Files
IKAR/tool/live_bot_smoke.dart
T

137 lines
4.6 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import '../lib/core/transport/ikar_network.dart';
import 'live_ikar_smoke.dart' as live;
Future<void> main() async {
final peer = await live.Device.create(
Uri.parse('https://ikar.kusoft.xyz'),
Platform.environment['IKAR_TEST_NODE'] ?? 'node',
'+999${DateTime.now().microsecondsSinceEpoch}',
'IKAR bot test',
);
final http = IkarNetwork.client();
String? botGuid;
try {
Future<dynamic> request(String method, String path, [Object? body]) async {
final r = await http.openUrl(
method,
Uri.parse('https://ikar.kusoft.xyz$path'),
);
r.headers.set('Authorization', 'Bearer ${peer.transport.token}');
if (body != null) {
r.headers.contentType = ContentType.json;
r.write(jsonEncode(body));
}
final response = await r.close();
final text = await utf8.decodeStream(response);
live.check(
response.statusCode >= 200 && response.statusCode < 300,
'Bot HTTP $method rejected: ${response.statusCode}',
);
return text.isEmpty ? null : jsonDecode(text);
}
final creator =
(await peer.ok(60, {
'query': 'botfatherbot',
}))['result'][0]['contact']['id']
as int;
final creatorChat = creator ^ peer.id;
final reply = peer.transport.events
.firstWhere(
(e) =>
e['opcode'] == 128 &&
e['payload']?['message']?['sender'] == creator,
)
.timeout(const Duration(seconds: 20));
final name = 'ikar_test_${DateTime.now().millisecondsSinceEpoch}bot';
await peer.ok(64, {
'chatId': creatorChat,
'message': {'text': '/создать_бота IKAR smoke | $name | Test'},
});
final createdText = (await reply)['payload']['message']['text'] as String;
final botToken = RegExp(
r'ikarbot_[A-Za-z0-9_-]+',
).firstMatch(createdText)?.group(0);
live.check(botToken != null, 'Creator did not return a bot token');
final mine = await request('GET', '/api/bots/mine') as List;
final bot = mine.singleWhere((x) => x['username'] == name);
botGuid = bot['id'];
await request('PUT', '/api/bots/$botGuid/web-app', {
'url': 'https://example.com/ikar-test',
});
final contact = (await peer.ok(60, {
'query': name,
}))['result'][0]['contact'];
live.check(
(contact['options'] as List).contains('HAS_WEBAPP'),
'Mini-app was not advertised',
);
final botId = contact['id'] as int;
final launch = await peer.ok(160, {'botId': botId, 'startParam': 'test'});
live.check(
(launch['url'] as String).contains('ikarWebAppData'),
'Own launch signature missing',
);
final phone = await peer.ok(106, {'botId': botId});
live.check(
(phone['hash'] as String).length == 64,
'Phone share signature missing',
);
final botChat = peer.id ^ botId;
await peer.ok(64, {
'chatId': botChat,
'message': {'text': 'IKAR bot request'},
});
final updates = await request(
'GET',
'/api/bot/$botToken/getUpdates?timeoutSeconds=0',
);
final update = (updates['updates'] as List).singleWhere(
(x) => x['message']?['text'] == 'IKAR bot request',
);
final botReply = peer.transport.events
.firstWhere(
(e) =>
e['opcode'] == 128 &&
e['payload']?['message']?['sender'] == botId,
)
.timeout(const Duration(seconds: 20));
await request('POST', '/api/bot/$botToken/sendMessage', {
'chatId': update['message']['chatId'],
'text': 'IKAR bot response',
});
live.check(
(await botReply)['payload']['message']['text'] == 'IKAR bot response',
'Bot reply not delivered',
);
final report = {
'passed': true,
'checks': [
'bot creation through own chat',
'bot update queue and reply delivery',
'mini-app configuration and signed launch',
'separate signed phone share',
],
'timestamp': DateTime.now().toUtc().toIso8601String(),
};
await File(
'artifacts/live-bot-smoke.json',
).writeAsString(const JsonEncoder.withIndent(' ').convert(report));
stdout.writeln(jsonEncode(report));
} finally {
if (botGuid != null) {
final r = await http.deleteUrl(
Uri.parse('https://ikar.kusoft.xyz/api/bots/$botGuid'),
);
r.headers.set('Authorization', 'Bearer ${peer.transport.token}');
await (await r.close()).drain<void>();
}
http.close(force: true);
await peer.ok(199, {});
await peer.close();
}
}