Files
Pulse/internal/dockeragent/runtime_coverage_test.go
rcourtman 44fa50eed7 feat(dockeragent): improve test coverage and refactor registry dependencies
- Add comprehensive test coverage for agent report, flush buffer, and deps
- Expand flow, HTTP, CPU, and swarm test coverage
- Refactor registry access to use deps interface for better testability
- Add container update and self-update test scenarios
2025-12-29 09:57:45 +00:00

170 lines
4.9 KiB
Go

package dockeragent
import (
"context"
"errors"
"strings"
"testing"
systemtypes "github.com/docker/docker/api/types/system"
"github.com/docker/docker/client"
"github.com/rs/zerolog"
)
func TestTryRuntimeCandidate(t *testing.T) {
t.Run("new client error", func(t *testing.T) {
swap(t, &newDockerClientFn, func(_ ...client.Opt) (dockerClient, error) {
return nil, errors.New("dial failed")
})
if _, _, err := tryRuntimeCandidate(nil); err == nil {
t.Fatal("expected error")
}
})
t.Run("info error closes client", func(t *testing.T) {
closed := false
fake := &fakeDockerClient{
infoFunc: func(_ context.Context) (systemtypes.Info, error) {
return systemtypes.Info{}, errors.New("info failed")
},
closeFn: func() error {
closed = true
return nil
},
}
swap(t, &newDockerClientFn, func(_ ...client.Opt) (dockerClient, error) {
return fake, nil
})
if _, _, err := tryRuntimeCandidate(nil); err == nil {
t.Fatal("expected error")
}
if !closed {
t.Fatal("expected Close to be called on error")
}
})
t.Run("success", func(t *testing.T) {
fake := &fakeDockerClient{
infoFunc: func(_ context.Context) (systemtypes.Info, error) {
return systemtypes.Info{ServerVersion: "24.0.0"}, nil
},
}
swap(t, &newDockerClientFn, func(_ ...client.Opt) (dockerClient, error) {
return fake, nil
})
gotClient, info, err := tryRuntimeCandidate(nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gotClient != fake {
t.Fatal("expected returned client to match fake")
}
if info.ServerVersion != "24.0.0" {
t.Fatalf("expected info to be returned")
}
})
}
func TestConnectRuntime(t *testing.T) {
t.Run("no candidates", func(t *testing.T) {
swap(t, &buildRuntimeCandidatesFn, func(_ RuntimeKind) []runtimeCandidate {
return nil
})
if _, _, _, err := connectRuntime(RuntimeAuto, nil); err == nil {
t.Fatal("expected error with no candidates")
}
})
t.Run("candidate failure accumulates attempts", func(t *testing.T) {
swap(t, &buildRuntimeCandidatesFn, func(_ RuntimeKind) []runtimeCandidate {
return []runtimeCandidate{{label: "first"}}
})
swap(t, &tryRuntimeCandidateFn, func(_ []client.Opt) (dockerClient, systemtypes.Info, error) {
return nil, systemtypes.Info{}, errors.New("no socket")
})
if _, _, _, err := connectRuntime(RuntimeAuto, nil); err == nil {
t.Fatal("expected error")
}
})
t.Run("preference mismatch returns error", func(t *testing.T) {
fake := &fakeDockerClient{daemonHost: "unix:///run/podman/podman.sock"}
swap(t, &buildRuntimeCandidatesFn, func(_ RuntimeKind) []runtimeCandidate {
return []runtimeCandidate{{label: "podman"}}
})
swap(t, &tryRuntimeCandidateFn, func(_ []client.Opt) (dockerClient, systemtypes.Info, error) {
return fake, systemtypes.Info{ServerVersion: "4.6.1"}, nil
})
_, _, _, err := connectRuntime(RuntimeDocker, nil)
if err == nil {
t.Fatal("expected error")
}
if !strings.Contains(err.Error(), "detected podman runtime") {
t.Fatalf("expected mismatch error, got %v", err)
}
})
t.Run("success with logger", func(t *testing.T) {
fake := &fakeDockerClient{daemonHost: "unix:///var/run/docker.sock"}
swap(t, &buildRuntimeCandidatesFn, func(_ RuntimeKind) []runtimeCandidate {
return []runtimeCandidate{{label: "docker"}}
})
swap(t, &tryRuntimeCandidateFn, func(_ []client.Opt) (dockerClient, systemtypes.Info, error) {
return fake, systemtypes.Info{ServerVersion: "24.0.0"}, nil
})
logger := zerolog.Nop()
cli, info, runtimeKind, err := connectRuntime(RuntimeAuto, &logger)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cli != fake {
t.Fatalf("expected client to be returned")
}
if info.ServerVersion != "24.0.0" {
t.Fatalf("expected info to be returned")
}
if runtimeKind != RuntimeDocker {
t.Fatalf("expected runtime docker, got %v", runtimeKind)
}
})
t.Run("mismatch then success with host opts", func(t *testing.T) {
podman := &fakeDockerClient{daemonHost: "unix:///run/podman/podman.sock"}
docker := &fakeDockerClient{daemonHost: "unix:///var/run/docker.sock"}
swap(t, &buildRuntimeCandidatesFn, func(_ RuntimeKind) []runtimeCandidate {
return []runtimeCandidate{
{label: "podman", host: "unix:///run/podman/podman.sock", applyDockerEnv: true},
{label: "docker", host: "unix:///var/run/docker.sock"},
}
})
calls := 0
swap(t, &tryRuntimeCandidateFn, func(opts []client.Opt) (dockerClient, systemtypes.Info, error) {
calls++
if calls == 1 {
if len(opts) < 2 {
t.Fatalf("expected opts to include env and host")
}
return podman, systemtypes.Info{ServerVersion: "4.6.1"}, nil
}
return docker, systemtypes.Info{ServerVersion: "24.0.0"}, nil
})
cli, _, runtimeKind, err := connectRuntime(RuntimeDocker, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cli != docker || runtimeKind != RuntimeDocker {
t.Fatalf("expected docker runtime after mismatch")
}
})
}