oto/apps/runner/test/oto_agent_cli_test.dart
toki 86afabb3eb refactor(runner): 런타임 패키지를 앱 하위로 이동한다
독립 control plane 구성을 위해 기존 Dart CLI/runtime을 runner 앱 경계로 옮기고, 후속 client/core/root 작업을 같은 마일스톤 task group에 연결한다.
2026-06-05 06:34:45 +09:00

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>'));
});
}