244 lines
6.1 KiB
V
244 lines
6.1 KiB
V
module runner
|
|
|
|
import freeflowuniverse.herolib.core.redisclient
|
|
import freeflowuniverse.herolib.core.playbook {PlayBook}
|
|
import freeflowuniverse.herolib.baobab.engine { Engine, Context }
|
|
|
|
__global (
|
|
entries shared map[string]string
|
|
)
|
|
|
|
// Mock actor implementation for testing
|
|
struct TestActor implements Actor {
|
|
pub:
|
|
name string = 'test_actor'
|
|
pub mut:
|
|
redis_conn redisclient.Redis
|
|
}
|
|
|
|
// Implement the Actor interface
|
|
pub fn (mut actor TestActor) process_job(j job.Job) ! {
|
|
mut redis_conn := actor.redis_conn()!
|
|
// Update job status to started
|
|
job.update_status(mut redis_conn, j.id, .started) or {
|
|
return error('Failed to update job status to started: ${err}')
|
|
}
|
|
|
|
// Run the job using the engine
|
|
result := actor.engine.run_in_context(j.script,
|
|
db_path: actor.db_path
|
|
caller_id: j.caller_id
|
|
context_id: j.context_id
|
|
) or {
|
|
// Handle execution error
|
|
job.update_status(mut redis_conn, j.id, .error)!
|
|
job.set_error(mut redis_conn, j.id, '${err}')!
|
|
return err
|
|
}
|
|
|
|
// Update job status to finished and set result
|
|
job.update_status(mut redis_conn, j.id, .finished) or {
|
|
return error('Failed to update job status to finished: ${err}')
|
|
}
|
|
job.set_result(mut redis_conn, j.id, result) or {
|
|
return error('Failed to set job result: ${err}')
|
|
}
|
|
}
|
|
|
|
fn test_actor_interface_defaults() {
|
|
actor := TestActor{
|
|
name: 'test_actor'
|
|
}
|
|
|
|
// Test default values from interface
|
|
assert actor.name == 'test_actor'
|
|
}
|
|
|
|
fn test_actor_queue_key() {
|
|
actor := TestActor{
|
|
name: 'test_actor'
|
|
}
|
|
|
|
assert actor.queue_key()! == 'runner:test_actor'
|
|
}
|
|
|
|
// Mock player function for testing
|
|
fn mock_player(mut plbook PlayBook) ! {
|
|
// Simple test player that adds some content
|
|
action := plbook.get(filter:'entry.define')!
|
|
entries['entry'] = action.params.get!('entry')!
|
|
}
|
|
|
|
|
|
fn test_actor_run_job() {
|
|
mut e := Engine{
|
|
players: []
|
|
}
|
|
|
|
// Register a simple test player
|
|
e.register_player(mock_player) or { panic('Failed to register player: ${err}') }
|
|
|
|
actor := TestActor{
|
|
id: 'test_runner'
|
|
db_path: '/tmp/test_run.db'
|
|
engine: e
|
|
}
|
|
|
|
// Create a test job
|
|
test_job := job.new(
|
|
caller_id: 'test_caller',
|
|
context_id: 'test_context',
|
|
script: 'test script',
|
|
script_type: .v
|
|
)
|
|
|
|
// Run the job
|
|
result := actor.run_job(test_job) or { panic('Failed to run job: ${err}') }
|
|
|
|
assert result.len > 0
|
|
}
|
|
|
|
fn test_actor_run_job_with_context() {
|
|
mut engine := Engine{
|
|
players: []
|
|
}
|
|
|
|
// Register a player that uses context
|
|
engine.register_player(fn (mut plbook playbook.PlayBook) ! {
|
|
// This player might access context variables
|
|
plbook.add_result('Context-aware execution')
|
|
}) or { panic('Failed to register context player: ${err}') }
|
|
|
|
actor := TestActor{
|
|
id: 'context_actor'
|
|
db_path: '/tmp/context_test.db'
|
|
engine: engine
|
|
}
|
|
|
|
// Create a job with specific context
|
|
test_job := job.Job{
|
|
id: 'context_job_1'
|
|
caller_id: 'context_caller'
|
|
context_id: 'context_123'
|
|
script: 'context_script'
|
|
script_type: .osis
|
|
status: .dispatched
|
|
// ... other fields with defaults
|
|
}
|
|
|
|
result := actor.run_job(test_job) or { panic('Failed to run context job: ${err}') }
|
|
|
|
assert result.len > 0
|
|
}
|
|
|
|
fn test_actor_process_job_success() {
|
|
mut e := Engine{
|
|
players: []
|
|
}
|
|
|
|
// Register a successful player
|
|
e.register_player(fn (mut plbook playbook.PlayBook) ! {
|
|
plbook.add_result('Success!')
|
|
}) or { panic('Failed to register success player: ${err}') }
|
|
|
|
actor := TestActor{
|
|
id: 'success_actor'
|
|
engine: e
|
|
}
|
|
|
|
// Create test job
|
|
test_job := job.new_job('success_caller', 'success_context', 'success script', .v)
|
|
|
|
// Process the job
|
|
actor.process_job(test_job) or { panic('Failed to process job: ${err}') }
|
|
|
|
// Process the job
|
|
actor.process_job(test_job, mut mock_redis) or { panic('Failed to process job: ${err}') }
|
|
|
|
// Verify Redis operations were called
|
|
assert mock_redis.operations.len > 0
|
|
|
|
// Check that status was updated to started and then finished
|
|
job_key := 'hero:job:${test_job.id}'
|
|
assert mock_redis.job_status[job_key] == 'finished'
|
|
assert mock_redis.job_results[job_key].len > 0
|
|
}
|
|
|
|
fn test_actor_process_job_error() {
|
|
mut engine := Engine{
|
|
players: []
|
|
}
|
|
|
|
// Register a failing player
|
|
engine.register_player(fn (mut plbook playbook.PlayBook) ! {
|
|
return error('Test error')
|
|
}) or { panic('Failed to register failing player: ${err}') }
|
|
|
|
actor := TestActor{
|
|
id: 'error_actor'
|
|
engine: engine
|
|
}
|
|
|
|
// Create test job
|
|
test_job := job.new_job('error_caller', 'error_context', 'error script', .v)
|
|
|
|
// Mock Redis connection
|
|
mut mock_redis := MockRedisConn{
|
|
operations: []
|
|
job_status: map[string]string{}
|
|
job_results: map[string]string{}
|
|
job_errors: map[string]string{}
|
|
}
|
|
|
|
// Process the job (should handle error gracefully)
|
|
if result := actor.process_job(test_job, mut mock_redis) {
|
|
panic('Expected job processing to fail')
|
|
}
|
|
|
|
// Verify error was recorded
|
|
job_key := 'hero:job:${test_job.id}'
|
|
assert mock_redis.job_status[job_key] == 'error'
|
|
assert mock_redis.job_errors[job_key].len > 0
|
|
}
|
|
|
|
fn test_multiple_actors() {
|
|
mut engine1 := Engine{ players: [] }
|
|
mut engine2 := Engine{ players: [] }
|
|
|
|
engine1.register_player(fn (mut plbook playbook.PlayBook) ! {
|
|
plbook.add_result('Actor 1 result')
|
|
}) or { panic('Failed to register player 1: ${err}') }
|
|
|
|
engine2.register_player(fn (mut plbook playbook.PlayBook) ! {
|
|
plbook.add_result('Actor 2 result')
|
|
}) or { panic('Failed to register player 2: ${err}') }
|
|
|
|
actor1 := TestActor{
|
|
id: 'actor_1'
|
|
engine: engine1
|
|
}
|
|
|
|
actor2 := TestActor{
|
|
id: 'actor_2'
|
|
engine: engine2
|
|
}
|
|
|
|
// Test that actors have different queue keys
|
|
queue1 := actor1.queue_key() or { panic('Failed to get queue key 1: ${err}') }
|
|
queue2 := actor2.queue_key() or { panic('Failed to get queue key 2: ${err}') }
|
|
|
|
assert queue1 != queue2
|
|
assert queue1.contains('actor_1')
|
|
assert queue2.contains('actor_2')
|
|
|
|
// Test that actors can run jobs independently
|
|
job1 := job.new_job('caller1', 'context1', 'script1', .v)
|
|
job2 := job.new_job('caller2', 'context2', 'script2', .osis)
|
|
|
|
result1 := actor1.run_job(job1) or { panic('Failed to run job 1: ${err}') }
|
|
result2 := actor2.run_job(job2) or { panic('Failed to run job 2: ${err}') }
|
|
|
|
assert result1.len > 0
|
|
assert result2.len > 0
|
|
}
|