package jobresultspublisher_test import ( "context" "testing" "galaxy/rtmanager/internal/adapters/jobresultspublisher" "galaxy/rtmanager/internal/ports" "github.com/alicebob/miniredis/v2" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func newPublisher(t *testing.T) (*jobresultspublisher.Publisher, *redis.Client) { t.Helper() server := miniredis.RunT(t) client := redis.NewClient(&redis.Options{Addr: server.Addr()}) t.Cleanup(func() { _ = client.Close() }) publisher, err := jobresultspublisher.NewPublisher(jobresultspublisher.Config{ Client: client, Stream: "runtime:job_results", }) require.NoError(t, err) return publisher, client } func TestNewPublisherRejectsMissingCollaborators(t *testing.T) { _, err := jobresultspublisher.NewPublisher(jobresultspublisher.Config{}) require.Error(t, err) server := miniredis.RunT(t) client := redis.NewClient(&redis.Options{Addr: server.Addr()}) t.Cleanup(func() { _ = client.Close() }) _, err = jobresultspublisher.NewPublisher(jobresultspublisher.Config{Client: client}) require.Error(t, err) _, err = jobresultspublisher.NewPublisher(jobresultspublisher.Config{Client: client, Stream: " "}) require.Error(t, err) } func TestPublishRejectsInvalidResult(t *testing.T) { publisher, _ := newPublisher(t) require.Error(t, publisher.Publish(context.Background(), ports.JobResult{})) require.Error(t, publisher.Publish(context.Background(), ports.JobResult{ GameID: "game-1", Outcome: "weird", })) } func TestPublishStartSuccessXAddsAllRequiredFields(t *testing.T) { publisher, client := newPublisher(t) result := ports.JobResult{ GameID: "game-1", Outcome: ports.JobOutcomeSuccess, ContainerID: "c-1", EngineEndpoint: "http://galaxy-game-game-1:8080", ErrorCode: "", ErrorMessage: "", } require.NoError(t, publisher.Publish(context.Background(), result)) entries, err := client.XRange(context.Background(), "runtime:job_results", "-", "+").Result() require.NoError(t, err) require.Len(t, entries, 1) values := entries[0].Values assert.Equal(t, "game-1", values["game_id"]) assert.Equal(t, "success", values["outcome"]) assert.Equal(t, "c-1", values["container_id"]) assert.Equal(t, "http://galaxy-game-game-1:8080", values["engine_endpoint"]) assert.Equal(t, "", values["error_code"]) assert.Equal(t, "", values["error_message"]) } func TestPublishFailureXAddsEmptyContainerAndEndpoint(t *testing.T) { publisher, client := newPublisher(t) result := ports.JobResult{ GameID: "game-2", Outcome: ports.JobOutcomeFailure, ErrorCode: "image_pull_failed", ErrorMessage: "manifest unknown", } require.NoError(t, publisher.Publish(context.Background(), result)) entries, err := client.XRange(context.Background(), "runtime:job_results", "-", "+").Result() require.NoError(t, err) require.Len(t, entries, 1) values := entries[0].Values assert.Equal(t, "game-2", values["game_id"]) assert.Equal(t, "failure", values["outcome"]) assert.Equal(t, "", values["container_id"], "failure must publish empty container id") assert.Equal(t, "", values["engine_endpoint"], "failure must publish empty engine endpoint") assert.Equal(t, "image_pull_failed", values["error_code"]) assert.Equal(t, "manifest unknown", values["error_message"]) } func TestPublishReplayNoOpKeepsContainerAndEndpoint(t *testing.T) { publisher, client := newPublisher(t) result := ports.JobResult{ GameID: "game-3", Outcome: ports.JobOutcomeSuccess, ContainerID: "c-3", EngineEndpoint: "http://galaxy-game-game-3:8080", ErrorCode: "replay_no_op", } require.NoError(t, publisher.Publish(context.Background(), result)) entries, err := client.XRange(context.Background(), "runtime:job_results", "-", "+").Result() require.NoError(t, err) require.Len(t, entries, 1) values := entries[0].Values assert.Equal(t, "game-3", values["game_id"]) assert.Equal(t, "success", values["outcome"]) assert.Equal(t, "c-3", values["container_id"]) assert.Equal(t, "http://galaxy-game-game-3:8080", values["engine_endpoint"]) assert.Equal(t, "replay_no_op", values["error_code"]) assert.Equal(t, "", values["error_message"]) } func TestPublishFailsOnClosedClient(t *testing.T) { server := miniredis.RunT(t) client := redis.NewClient(&redis.Options{Addr: server.Addr()}) publisher, err := jobresultspublisher.NewPublisher(jobresultspublisher.Config{ Client: client, Stream: "runtime:job_results", }) require.NoError(t, err) require.NoError(t, client.Close()) err = publisher.Publish(context.Background(), ports.JobResult{ GameID: "game-4", Outcome: ports.JobOutcomeSuccess, }) require.Error(t, err) }