- Add agent CLI command and agent runner module - Implement edge registration client - Add agent config and registration tests - Update roadmap and milestones - Update pubspec.yaml and main.dart for agent support - Update analysis_options.yaml
165 lines
4.6 KiB
Dart
165 lines
4.6 KiB
Dart
import 'dart:io';
|
|
import 'package:test/test.dart';
|
|
import 'package:oto/cli/cli.dart';
|
|
import 'package:oto/cli/commands/command_agent.dart';
|
|
import 'package:oto/oto/agent/agent_config.dart';
|
|
import 'package:oto/oto/agent/agent_runner.dart';
|
|
|
|
class FakeAgentRunner implements AgentRunner {
|
|
AgentConfig? lastConfig;
|
|
int callCount = 0;
|
|
Future<void> Function(AgentConfig)? onRun;
|
|
|
|
@override
|
|
Future<void> run(AgentConfig config) async {
|
|
lastConfig = config;
|
|
callCount++;
|
|
if (onRun != null) {
|
|
await onRun!(config);
|
|
}
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
const validBootstrapYaml = '''
|
|
agent:
|
|
id: "agent-abc"
|
|
alias: "my-agent"
|
|
enrollment_token: "token-123"
|
|
edge:
|
|
url: "https://edge.toki-labs.com:8443"
|
|
runtime:
|
|
install_dir: "/usr/bin"
|
|
workspace_root: "/var/oto"
|
|
log_dir: "/var/log/oto"
|
|
''';
|
|
|
|
late File tempFile;
|
|
|
|
setUp(() {
|
|
tempFile = File('${Directory.systemTemp.path}/agent_config_cli_test.yaml');
|
|
tempFile.writeAsStringSync(validBootstrapYaml);
|
|
CLI.logFunc = (msg) {};
|
|
CLI.initialize('oto', [], []);
|
|
});
|
|
|
|
tearDown(() {
|
|
if (tempFile.existsSync()) {
|
|
tempFile.deleteSync();
|
|
}
|
|
});
|
|
|
|
test('CommandAgent parses run config and calls runner', () async {
|
|
final runner = FakeAgentRunner();
|
|
final command = CommandAgent(runner: runner);
|
|
|
|
await command.execute(['run', '--config', tempFile.path]);
|
|
|
|
expect(runner.callCount, 1);
|
|
expect(runner.lastConfig, isNotNull);
|
|
expect(runner.lastConfig!.agent.id, 'agent-abc');
|
|
expect(runner.lastConfig!.edge.url, 'https://edge.toki-labs.com:8443');
|
|
expect(runner.lastConfig!.runtime.installDir, '/usr/bin');
|
|
});
|
|
|
|
test('CommandAgent parses run config with equals option and calls runner',
|
|
() async {
|
|
final runner = FakeAgentRunner();
|
|
final command = CommandAgent(runner: runner);
|
|
|
|
await command.execute(['run', '--config=${tempFile.path}']);
|
|
|
|
expect(runner.callCount, 1);
|
|
expect(runner.lastConfig!.agent.id, 'agent-abc');
|
|
});
|
|
|
|
test('CommandAgent rejects unknown subcommand', () async {
|
|
final runner = FakeAgentRunner();
|
|
final command = CommandAgent(runner: runner);
|
|
|
|
await command.execute(['unknown_sub']);
|
|
expect(runner.callCount, 0);
|
|
});
|
|
|
|
test('CommandAgent rejects missing config parameter', () async {
|
|
final runner = FakeAgentRunner();
|
|
final command = CommandAgent(runner: runner);
|
|
|
|
await command.execute(['run']);
|
|
expect(runner.callCount, 0);
|
|
});
|
|
|
|
test('CommandAgent sets exit code zero on accepted registration', () async {
|
|
final runner = FakeAgentRunner();
|
|
runner.onRun = (config) async {
|
|
// success
|
|
};
|
|
final command = CommandAgent(runner: runner);
|
|
|
|
final initialExitCode = exitCode;
|
|
exitCode = 0;
|
|
|
|
await command.execute(['run', '--config', tempFile.path]);
|
|
|
|
expect(runner.callCount, 1);
|
|
expect(exitCode, 0);
|
|
|
|
exitCode = initialExitCode;
|
|
});
|
|
|
|
test('CommandAgent sets exit code ten on rejected registration', () async {
|
|
final runner = FakeAgentRunner();
|
|
runner.onRun = (config) async {
|
|
throw RegistrationException('Rejected by server');
|
|
};
|
|
final command = CommandAgent(runner: runner);
|
|
|
|
final initialExitCode = exitCode;
|
|
exitCode = 0;
|
|
|
|
await command.execute(['run', '--config', tempFile.path]);
|
|
|
|
expect(runner.callCount, 1);
|
|
expect(exitCode, 10);
|
|
|
|
exitCode = initialExitCode;
|
|
});
|
|
|
|
// Integration tests calling actual binary
|
|
test('actual bin agent help lists run usage', () async {
|
|
final result = await Process.run(
|
|
'dart',
|
|
['run', 'bin/main.dart', 'agent', '-h'],
|
|
);
|
|
|
|
expect(result.exitCode, 0, reason: result.stderr.toString());
|
|
final stdoutStr = result.stdout.toString();
|
|
expect(stdoutStr, contains('agent'));
|
|
expect(stdoutStr, contains('run --config <path>'));
|
|
expect(stdoutStr, contains('Manage the OTO agent'));
|
|
});
|
|
|
|
test('actual bin agent run help works', () async {
|
|
final result = await Process.run(
|
|
'dart',
|
|
['run', 'bin/main.dart', 'agent', 'run', '-h'],
|
|
);
|
|
|
|
expect(result.exitCode, 0, reason: result.stderr.toString());
|
|
final stdoutStr = result.stdout.toString();
|
|
expect(stdoutStr, contains('agent run --config <path>'));
|
|
expect(stdoutStr, contains('Run the OTO agent daemon'));
|
|
});
|
|
|
|
test('actual bin agent with no parameters shows root help', () async {
|
|
final result = await Process.run(
|
|
'dart',
|
|
['run', 'bin/main.dart', 'agent'],
|
|
);
|
|
|
|
expect(result.exitCode, 0, reason: result.stderr.toString());
|
|
final stdoutStr = result.stdout.toString();
|
|
expect(stdoutStr, contains('Usage:'));
|
|
expect(stdoutStr, contains('agent run --config <path>'));
|
|
});
|
|
}
|