173 lines
5.7 KiB
Go
173 lines
5.7 KiB
Go
package discovery_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/shcizo/package-updater/internal/discovery"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type fakeDockerClient struct {
|
|
containers []types.Container
|
|
err error
|
|
}
|
|
|
|
func (f *fakeDockerClient) ContainerList(_ context.Context, _ container.ListOptions) ([]types.Container, error) {
|
|
return f.containers, f.err
|
|
}
|
|
|
|
func (f *fakeDockerClient) Ping(_ context.Context) (types.Ping, error) {
|
|
return types.Ping{}, nil
|
|
}
|
|
|
|
func mkContainer(image string, labels map[string]string) types.Container {
|
|
return types.Container{Image: image, Labels: labels}
|
|
}
|
|
|
|
func mkComposeLabels(project, service, workingDir, configFile string, optIn bool) map[string]string {
|
|
m := map[string]string{
|
|
"com.docker.compose.project": project,
|
|
"com.docker.compose.service": service,
|
|
"com.docker.compose.project.working_dir": workingDir,
|
|
"com.docker.compose.project.config_files": configFile,
|
|
}
|
|
if optIn {
|
|
m["se.shcizo.auto-update"] = "true"
|
|
}
|
|
return m
|
|
}
|
|
|
|
func TestFindJobs_MatchAndOptIn(t *testing.T) {
|
|
fake := &fakeDockerClient{containers: []types.Container{
|
|
mkContainer("registry.example.com/myapp:v1", mkComposeLabels(
|
|
"myapp-prod", "web",
|
|
"/home/shcizo/self-hosted/myapp-prod",
|
|
"/home/shcizo/self-hosted/myapp-prod/docker-compose.yml",
|
|
true,
|
|
)),
|
|
mkContainer("registry.example.com/other:v1", mkComposeLabels(
|
|
"other", "web",
|
|
"/home/shcizo/self-hosted/other",
|
|
"/home/shcizo/self-hosted/other/docker-compose.yml",
|
|
true,
|
|
)),
|
|
}}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
jobs, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.NoError(t, err)
|
|
require.Len(t, jobs, 1)
|
|
require.Equal(t, "myapp-prod", jobs[0].Project)
|
|
require.Equal(t, "web", jobs[0].Service)
|
|
require.Equal(t, "/home/shcizo/self-hosted/myapp-prod", jobs[0].WorkingDir)
|
|
}
|
|
|
|
func TestFindJobs_SkipsWithoutOptIn(t *testing.T) {
|
|
fake := &fakeDockerClient{containers: []types.Container{
|
|
mkContainer("registry.example.com/myapp:v1", mkComposeLabels(
|
|
"myapp-prod", "web",
|
|
"/home/shcizo/self-hosted/myapp-prod",
|
|
"/home/shcizo/self-hosted/myapp-prod/docker-compose.yml",
|
|
false,
|
|
)),
|
|
}}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
jobs, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.NoError(t, err)
|
|
require.Empty(t, jobs)
|
|
}
|
|
|
|
func TestFindJobs_DedupReplicas(t *testing.T) {
|
|
labels := mkComposeLabels(
|
|
"myapp", "web",
|
|
"/home/shcizo/self-hosted/myapp",
|
|
"/home/shcizo/self-hosted/myapp/docker-compose.yml",
|
|
true,
|
|
)
|
|
fake := &fakeDockerClient{containers: []types.Container{
|
|
mkContainer("registry.example.com/myapp:v1", labels),
|
|
mkContainer("registry.example.com/myapp:v1", labels),
|
|
mkContainer("registry.example.com/myapp:v1", labels),
|
|
}}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
jobs, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.NoError(t, err)
|
|
require.Len(t, jobs, 1)
|
|
}
|
|
|
|
func TestFindJobs_OutsideRootProducesRefusedJob(t *testing.T) {
|
|
fake := &fakeDockerClient{containers: []types.Container{
|
|
mkContainer("registry.example.com/myapp:v1", mkComposeLabels(
|
|
"myapp", "web",
|
|
"/opt/elsewhere/myapp",
|
|
"/opt/elsewhere/myapp/docker-compose.yml",
|
|
true,
|
|
)),
|
|
}}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
jobs, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.NoError(t, err)
|
|
require.Len(t, jobs, 1)
|
|
require.True(t, jobs[0].Refused)
|
|
}
|
|
|
|
func TestFindJobs_MultipleStacksSameImage(t *testing.T) {
|
|
fake := &fakeDockerClient{containers: []types.Container{
|
|
mkContainer("registry.example.com/myapp:v1", mkComposeLabels(
|
|
"myapp-prod", "web",
|
|
"/home/shcizo/self-hosted/myapp-prod",
|
|
"/home/shcizo/self-hosted/myapp-prod/docker-compose.yml",
|
|
true,
|
|
)),
|
|
mkContainer("registry.example.com/myapp:v1", mkComposeLabels(
|
|
"myapp-staging", "web",
|
|
"/home/shcizo/self-hosted/myapp-staging",
|
|
"/home/shcizo/self-hosted/myapp-staging/docker-compose.yml",
|
|
true,
|
|
)),
|
|
}}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
jobs, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.NoError(t, err)
|
|
require.Len(t, jobs, 2)
|
|
}
|
|
|
|
func TestFindJobs_DockerError(t *testing.T) {
|
|
fake := &fakeDockerClient{err: errors.New("connection refused")}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
_, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFindJobs_NonComposeContainerIsSkipped(t *testing.T) {
|
|
fake := &fakeDockerClient{containers: []types.Container{
|
|
mkContainer("registry.example.com/myapp:v1", map[string]string{
|
|
"se.shcizo.auto-update": "true",
|
|
}),
|
|
}}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
jobs, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.NoError(t, err)
|
|
require.Empty(t, jobs)
|
|
}
|
|
|
|
func TestFindJobs_PopulatesImageField(t *testing.T) {
|
|
fake := &fakeDockerClient{containers: []types.Container{
|
|
mkContainer("registry.example.com/myapp:v1", mkComposeLabels(
|
|
"myapp-prod", "web",
|
|
"/home/shcizo/self-hosted/myapp-prod",
|
|
"/home/shcizo/self-hosted/myapp-prod/docker-compose.yml",
|
|
true,
|
|
)),
|
|
}}
|
|
d := discovery.New(fake, "/home/shcizo/self-hosted", "se.shcizo.auto-update")
|
|
jobs, err := d.FindJobs(context.Background(), "registry.example.com/myapp")
|
|
require.NoError(t, err)
|
|
require.Len(t, jobs, 1)
|
|
require.Equal(t, "registry.example.com/myapp", jobs[0].Image)
|
|
require.Empty(t, jobs[0].ServiceID)
|
|
}
|