// InMemoryRepository(agent)的單元測試(WP-B B2)。 // // 無 build tag:預設 `go test ./...` 即涵蓋(不需 Docker)。PG 側對齊測試見 // postgres_repository_db_test.go(-tags=dbtest)。 package agent import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestInMemory_GetOrCreate_CreatesWhenAbsent(t *testing.T) { ctx := context.Background() r := NewInMemoryRepository() owner := "owner-1" paired := time.Now().UTC() a, err := r.GetOrCreateAgentTx(ctx, nil, owner, "", "", "", paired) require.NoError(t, err) require.NotNil(t, a) assert.NotEmpty(t, a.ID) assert.Equal(t, owner, a.OwnerUserID) assert.Equal(t, "local-agent", a.Name, "name 空時應用預設 local-agent") require.NotNil(t, a.LastPairedAt) assert.True(t, paired.Equal(*a.LastPairedAt)) } func TestInMemory_GetOrCreate_ReusesExisting(t *testing.T) { ctx := context.Background() r := NewInMemoryRepository() owner := "owner-2" first, err := r.GetOrCreateAgentTx(ctx, nil, owner, "local-agent", "darwin", "1.0", time.Now().UTC()) require.NoError(t, err) time.Sleep(2 * time.Millisecond) later := time.Now().UTC() second, err := r.GetOrCreateAgentTx(ctx, nil, owner, "", "", "", later) require.NoError(t, err) assert.Equal(t, first.ID, second.ID, "同 owner 應復用同一 agent") assert.Equal(t, "darwin", second.Platform, "空上報值不應覆寫既有 platform") assert.Equal(t, "1.0", second.AgentVersion, "空上報值不應覆寫既有 agent_version") require.NotNil(t, second.LastPairedAt) assert.True(t, later.Equal(*second.LastPairedAt), "last_paired_at 應更新") } func TestInMemory_GetOrCreate_UpdatesNonEmptyFieldsOnReuse(t *testing.T) { ctx := context.Background() r := NewInMemoryRepository() owner := "owner-3" _, err := r.GetOrCreateAgentTx(ctx, nil, owner, "local-agent", "darwin", "1.0", time.Now().UTC()) require.NoError(t, err) updated, err := r.GetOrCreateAgentTx(ctx, nil, owner, "renamed", "linux", "2.0", time.Now().UTC()) require.NoError(t, err) assert.Equal(t, "renamed", updated.Name) assert.Equal(t, "linux", updated.Platform) assert.Equal(t, "2.0", updated.AgentVersion) } func TestInMemory_GetOrCreate_DistinctOwners(t *testing.T) { ctx := context.Background() r := NewInMemoryRepository() a1, err := r.GetOrCreateAgentTx(ctx, nil, "owner-A", "", "", "", time.Now().UTC()) require.NoError(t, err) a2, err := r.GetOrCreateAgentTx(ctx, nil, "owner-B", "", "", "", time.Now().UTC()) require.NoError(t, err) assert.NotEqual(t, a1.ID, a2.ID, "不同 owner 應各自建 agent") } func TestInMemory_GetOrCreate_RequiresOwner(t *testing.T) { r := NewInMemoryRepository() _, err := r.GetOrCreateAgentTx(context.Background(), nil, "", "", "", "", time.Now().UTC()) assert.Error(t, err) } func TestInMemory_GetByOwner(t *testing.T) { ctx := context.Background() r := NewInMemoryRepository() owner := "owner-4" _, err := r.GetByOwnerTx(ctx, nil, owner) assert.ErrorIs(t, err, ErrNotFound, "無 agent 時應回 ErrNotFound") created, err := r.GetOrCreateAgentTx(ctx, nil, owner, "", "", "", time.Now().UTC()) require.NoError(t, err) got, err := r.GetByOwnerTx(ctx, nil, owner) require.NoError(t, err) assert.Equal(t, created.ID, got.ID) }