import 'dart:convert'; import 'dart:io'; import 'live_ikar_smoke.dart' as live; Future main(List args) async { final label = args.isEmpty ? 'before' : args.first; final devices = []; final report = { 'timestamp': DateTime.now().toUtc().toIso8601String(), 'checks': {}, }; final checks = report['checks'] as Map; try { final stamp = DateTime.now().microsecondsSinceEpoch.toString(); for (var i = 0; i < 2; i++) { devices.add( await live.Device.create( Uri.parse('https://ikar.kusoft.xyz'), Platform.environment['IKAR_TEST_NODE'] ?? 'node', '+999$stamp$i', 'IKAR messaging regression', ), ); } final a = devices[0], b = devices[1]; Future> run( String name, int opcode, Map payload, ) async { final response = await a.transport.request(opcode, payload); checks[name] = { 'passed': response['cmd'] == 1, if (response['cmd'] != 1) 'error': response['payload'], }; return Map.from(response['payload'] as Map); } await run('savedHistoryBeforeFirstMessage', 49, {'chatId': 0, 'count': 40}); final saved = await run('savedText', 64, { 'chatId': 0, 'message': { 'text': 'IKAR saved regression', 'cid': DateTime.now().microsecondsSinceEpoch, }, }); final history = await run('savedHistoryAfterMessage', 49, { 'chatId': 0, 'count': 40, }); checks['savedMessagePersisted'] = { 'passed': saved['message'] != null && (history['messages'] as List? ?? []).any( (m) => m['id'] == saved['message']['id'], ), }; final sticker = await run('savedSticker', 64, { 'chatId': 0, 'message': { 'attaches': [ {'_type': 'STICKER', 'stickerId': 1}, ], }, }); checks['savedStickerPersisted'] = {'passed': sticker['message'] is Map}; await run('savedTyping', 59, {'chatId': 0, 'type': 'TEXT'}); await run('contactAdd', 34, { 'contactId': b.id, 'action': 'ADD', 'firstName': 'Regression contact', }); await run('contactUpdate', 34, { 'contactId': b.id, 'action': 'UPDATE', 'firstName': 'Renamed contact', }); await run('contactRemove', 34, {'contactId': b.id, 'action': 'REMOVE'}); final chatId = a.id ^ b.id; await run('directSubscribeBeforeFirstMessage', 75, { 'chatId': chatId, 'subscribe': true, }); final received = b.transport.events .firstWhere( (e) => e['opcode'] == 128 && e['payload']?['chatId'] == chatId, ) .timeout(const Duration(seconds: 15)); final message = await run('firstDirectMessage', 64, { 'chatId': chatId, 'message': { 'text': 'IKAR direct regression', 'cid': DateTime.now().microsecondsSinceEpoch, }, }); await received; final directHistory = await b.ok(49, {'chatId': chatId, 'count': 40}); checks['directDeliveryAndHistory'] = { 'passed': (directHistory['messages'] as List).any( (m) => m['id'] == message['message']['id'], ), }; await run('directUnsubscribe', 75, {'chatId': chatId, 'subscribe': false}); final afterUnsubscribe = await run('directHistoryAfterUnsubscribe', 49, { 'chatId': chatId, 'count': 40, }); checks['unsubscribeRetainsMembership'] = { 'passed': (afterUnsubscribe['messages'] as List? ?? []).any( (m) => m['id'] == message['message']['id'], ), }; final otherSaved = await b.transport.request(49, { 'chatId': 0, 'count': 40, }); checks['savedIsolation'] = { 'passed': otherSaved['cmd'] == 1 && (otherSaved['payload']['messages'] as List).every( (m) => m['text'] != 'IKAR saved regression', ), }; report['passed'] = checks.values.every( (value) => (value as Map)['passed'] == true, ); } finally { for (final device in devices) { try { await device.ok(199, {}); } finally { await device.close(); } } await File( 'artifacts/messaging-fix-$label.json', ).writeAsString(const JsonEncoder.withIndent(' ').convert(report)); stdout.writeln(jsonEncode(report)); } }