| package environment | |
| import ( | |
| "context" | |
| "testing" | |
| "github.com/docker/docker/api/types" | |
| "github.com/docker/docker/api/types/filters" | |
| "github.com/docker/docker/api/types/volume" | |
| "github.com/docker/docker/errdefs" | |
| "gotest.tools/v3/assert" | |
| ) | |
| var frozenImages = []string{"busybox:latest", "busybox:glibc", "hello-world:frozen", "debian:bullseye-slim"} | |
| type protectedElements struct { | |
| containers map[string]struct{} | |
| images map[string]struct{} | |
| networks map[string]struct{} | |
| plugins map[string]struct{} | |
| volumes map[string]struct{} | |
| } | |
| func newProtectedElements() protectedElements { | |
| return protectedElements{ | |
| containers: map[string]struct{}{}, | |
| images: map[string]struct{}{}, | |
| networks: map[string]struct{}{}, | |
| plugins: map[string]struct{}{}, | |
| volumes: map[string]struct{}{}, | |
| } | |
| } | |
| // ProtectAll protects the existing environment (containers, images, networks, | |
| // volumes, and, on Linux, plugins) from being cleaned up at the end of test | |
| // runs | |
| func ProtectAll(t testing.TB, testEnv *Execution) { | |
| t.Helper() | |
| ProtectContainers(t, testEnv) | |
| ProtectImages(t, testEnv) | |
| ProtectNetworks(t, testEnv) | |
| ProtectVolumes(t, testEnv) | |
| if testEnv.OSType == "linux" { | |
| ProtectPlugins(t, testEnv) | |
| } | |
| } | |
| // ProtectContainer adds the specified container(s) to be protected in case of | |
| // clean | |
| func (e *Execution) ProtectContainer(t testing.TB, containers ...string) { | |
| t.Helper() | |
| for _, container := range containers { | |
| e.protectedElements.containers[container] = struct{}{} | |
| } | |
| } | |
| // ProtectContainers protects existing containers from being cleaned up at the | |
| // end of test runs | |
| func ProtectContainers(t testing.TB, testEnv *Execution) { | |
| t.Helper() | |
| containers := getExistingContainers(t, testEnv) | |
| testEnv.ProtectContainer(t, containers...) | |
| } | |
| func getExistingContainers(t testing.TB, testEnv *Execution) []string { | |
| t.Helper() | |
| client := testEnv.APIClient() | |
| containerList, err := client.ContainerList(context.Background(), types.ContainerListOptions{ | |
| All: true, | |
| }) | |
| assert.NilError(t, err, "failed to list containers") | |
| var containers []string | |
| for _, container := range containerList { | |
| containers = append(containers, container.ID) | |
| } | |
| return containers | |
| } | |
| // ProtectImage adds the specified image(s) to be protected in case of clean | |
| func (e *Execution) ProtectImage(t testing.TB, images ...string) { | |
| t.Helper() | |
| for _, image := range images { | |
| e.protectedElements.images[image] = struct{}{} | |
| } | |
| } | |
| // ProtectImages protects existing images and on linux frozen images from being | |
| // cleaned up at the end of test runs | |
| func ProtectImages(t testing.TB, testEnv *Execution) { | |
| t.Helper() | |
| images := getExistingImages(t, testEnv) | |
| if testEnv.OSType == "linux" { | |
| images = append(images, frozenImages...) | |
| } | |
| testEnv.ProtectImage(t, images...) | |
| testEnv.ProtectImage(t, DanglingImageIdGraphDriver, DanglingImageIdSnapshotter) | |
| } | |
| func getExistingImages(t testing.TB, testEnv *Execution) []string { | |
| t.Helper() | |
| client := testEnv.APIClient() | |
| imageList, err := client.ImageList(context.Background(), types.ImageListOptions{ | |
| All: true, | |
| Filters: filters.NewArgs(filters.Arg("dangling", "false")), | |
| }) | |
| assert.NilError(t, err, "failed to list images") | |
| var images []string | |
| for _, image := range imageList { | |
| images = append(images, tagsFromImageSummary(image)...) | |
| } | |
| return images | |
| } | |
| func tagsFromImageSummary(image types.ImageSummary) []string { | |
| var result []string | |
| for _, tag := range image.RepoTags { | |
| // Starting from API 1.43 no longer outputs the hardcoded <none> | |
| // strings. But since the tests might be ran against a remote | |
| // daemon/pre 1.43 CLI we must still be able to handle it. | |
| if tag != "<none>:<none>" { | |
| result = append(result, tag) | |
| } | |
| } | |
| for _, digest := range image.RepoDigests { | |
| if digest != "<none>@<none>" { | |
| result = append(result, digest) | |
| } | |
| } | |
| return result | |
| } | |
| // ProtectNetwork adds the specified network(s) to be protected in case of | |
| // clean | |
| func (e *Execution) ProtectNetwork(t testing.TB, networks ...string) { | |
| t.Helper() | |
| for _, network := range networks { | |
| e.protectedElements.networks[network] = struct{}{} | |
| } | |
| } | |
| // ProtectNetworks protects existing networks from being cleaned up at the end | |
| // of test runs | |
| func ProtectNetworks(t testing.TB, testEnv *Execution) { | |
| t.Helper() | |
| networks := getExistingNetworks(t, testEnv) | |
| testEnv.ProtectNetwork(t, networks...) | |
| } | |
| func getExistingNetworks(t testing.TB, testEnv *Execution) []string { | |
| t.Helper() | |
| client := testEnv.APIClient() | |
| networkList, err := client.NetworkList(context.Background(), types.NetworkListOptions{}) | |
| assert.NilError(t, err, "failed to list networks") | |
| var networks []string | |
| for _, network := range networkList { | |
| networks = append(networks, network.ID) | |
| } | |
| return networks | |
| } | |
| // ProtectPlugin adds the specified plugin(s) to be protected in case of clean | |
| func (e *Execution) ProtectPlugin(t testing.TB, plugins ...string) { | |
| t.Helper() | |
| for _, plugin := range plugins { | |
| e.protectedElements.plugins[plugin] = struct{}{} | |
| } | |
| } | |
| // ProtectPlugins protects existing plugins from being cleaned up at the end of | |
| // test runs | |
| func ProtectPlugins(t testing.TB, testEnv *Execution) { | |
| t.Helper() | |
| plugins := getExistingPlugins(t, testEnv) | |
| testEnv.ProtectPlugin(t, plugins...) | |
| } | |
| func getExistingPlugins(t testing.TB, testEnv *Execution) []string { | |
| t.Helper() | |
| client := testEnv.APIClient() | |
| pluginList, err := client.PluginList(context.Background(), filters.Args{}) | |
| // Docker EE does not allow cluster-wide plugin management. | |
| if errdefs.IsNotImplemented(err) { | |
| return []string{} | |
| } | |
| assert.NilError(t, err, "failed to list plugins") | |
| var plugins []string | |
| for _, plugin := range pluginList { | |
| plugins = append(plugins, plugin.Name) | |
| } | |
| return plugins | |
| } | |
| // ProtectVolume adds the specified volume(s) to be protected in case of clean | |
| func (e *Execution) ProtectVolume(t testing.TB, volumes ...string) { | |
| t.Helper() | |
| for _, vol := range volumes { | |
| e.protectedElements.volumes[vol] = struct{}{} | |
| } | |
| } | |
| // ProtectVolumes protects existing volumes from being cleaned up at the end of | |
| // test runs | |
| func ProtectVolumes(t testing.TB, testEnv *Execution) { | |
| t.Helper() | |
| volumes := getExistingVolumes(t, testEnv) | |
| testEnv.ProtectVolume(t, volumes...) | |
| } | |
| func getExistingVolumes(t testing.TB, testEnv *Execution) []string { | |
| t.Helper() | |
| client := testEnv.APIClient() | |
| volumeList, err := client.VolumeList(context.Background(), volume.ListOptions{}) | |
| assert.NilError(t, err, "failed to list volumes") | |
| var volumes []string | |
| for _, vol := range volumeList.Volumes { | |
| volumes = append(volumes, vol.Name) | |
| } | |
| return volumes | |
| } |