From 25cb3c4c53f90e12316b31d1da4d1620b41fb886 Mon Sep 17 00:00:00 2001 From: Amir Raminfar Date: Sat, 3 Feb 2024 09:06:05 -0800 Subject: [PATCH] chore: adds tests for store (#2751) --- internal/docker/container_store.go | 26 +++---- internal/docker/container_store_test.go | 92 +++++++++++++++++++++++++ internal/web/routes.go | 3 +- 3 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 internal/docker/container_store_test.go diff --git a/internal/docker/container_store.go b/internal/docker/container_store.go index f7f6b073..af3b4610 100644 --- a/internal/docker/container_store.go +++ b/internal/docker/container_store.go @@ -14,7 +14,7 @@ type ContainerStore struct { subscribers sync.Map } -func NewContainerStore(client Client) *ContainerStore { +func NewContainerStore(ctx context.Context, client Client) *ContainerStore { s := &ContainerStore{ containers: make(map[string]*Container), client: client, @@ -22,8 +22,18 @@ func NewContainerStore(client Client) *ContainerStore { statsCollector: NewStatsCollector(client), } - go s.init(context.Background()) - go s.statsCollector.StartCollecting(context.Background()) + containers, err := s.client.ListContainers() + if err != nil { + log.Fatalf("error while listing containers: %v", err) + } + + for _, c := range containers { + c := c // create a new variable to avoid capturing the loop variable + s.containers[c.ID] = &c + } + + go s.init(ctx) + go s.statsCollector.StartCollecting(ctx) return s } @@ -50,16 +60,6 @@ func (s *ContainerStore) SubscribeStats(ctx context.Context, stats chan Containe } func (s *ContainerStore) init(ctx context.Context) { - containers, err := s.client.ListContainers() - if err != nil { - log.Fatalf("error while listing containers: %v", err) - } - - for _, c := range containers { - c := c // create a new variable to avoid capturing the loop variable - s.containers[c.ID] = &c - } - events := make(chan ContainerEvent) s.client.Events(ctx, events) diff --git a/internal/docker/container_store_test.go b/internal/docker/container_store_test.go new file mode 100644 index 00000000..70fc9eee --- /dev/null +++ b/internal/docker/container_store_test.go @@ -0,0 +1,92 @@ +package docker + +import ( + "context" + "testing" + + "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/mock" +) + +type mockedClient struct { + mock.Mock + Client +} + +func (m *mockedClient) ListContainers() ([]Container, error) { + args := m.Called() + return args.Get(0).([]Container), args.Error(1) +} + +func (m *mockedClient) FindContainer(id string) (Container, error) { + args := m.Called(id) + return args.Get(0).(Container), args.Error(1) +} + +func (m *mockedClient) Events(ctx context.Context, events chan<- ContainerEvent) <-chan error { + args := m.Called(ctx, events) + return args.Get(0).(chan error) +} + +func (m *mockedClient) ContainerStats(ctx context.Context, id string, stats chan<- ContainerStat) error { + args := m.Called(ctx, id, stats) + return args.Error(0) +} + +func TestContainerStore_List(t *testing.T) { + + client := new(mockedClient) + client.On("ListContainers").Return([]Container{ + { + ID: "1234", + Name: "test", + }, + }, nil) + client.On("Events", mock.Anything, mock.AnythingOfType("chan<- docker.ContainerEvent")).Return(make(chan error)) + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + store := NewContainerStore(ctx, client) + containers := store.List() + + assert.Equal(t, containers[0].ID, "1234") +} + +func TestContainerStore_die(t *testing.T) { + client := new(mockedClient) + client.On("ListContainers").Return([]Container{ + { + ID: "1234", + Name: "test", + State: "running", + }, + }, nil) + + client.On("Events", mock.Anything, mock.AnythingOfType("chan<- docker.ContainerEvent")).Return(make(chan error)). + Run(func(args mock.Arguments) { + ctx := args.Get(0).(context.Context) + events := args.Get(1).(chan<- ContainerEvent) + go func() { + events <- ContainerEvent{ + Name: "die", + ActorID: "1234", + Host: "localhost", + } + <-ctx.Done() + }() + }) + + client.On("ContainerStats", mock.Anything, "1234", mock.AnythingOfType("chan<- docker.ContainerStat")).Return(nil) + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + store := NewContainerStore(ctx, client) + + // Wait until we get the event + events := make(chan ContainerEvent) + store.Subscribe(ctx, events) + <-events + + containers := store.List() + assert.Equal(t, containers[0].State, "exited") +} diff --git a/internal/web/routes.go b/internal/web/routes.go index db22ce33..87308c27 100644 --- a/internal/web/routes.go +++ b/internal/web/routes.go @@ -1,6 +1,7 @@ package web import ( + "context" "io/fs" "net/http" @@ -53,7 +54,7 @@ type handler struct { func CreateServer(clients map[string]docker.Client, content fs.FS, config Config) *http.Server { stores := make(map[string]*docker.ContainerStore) for host, client := range clients { - stores[host] = docker.NewContainerStore(client) + stores[host] = docker.NewContainerStore(context.Background(), client) } handler := &handler{