Skip to content

Commit ad7c946

Browse files
committed
chore(integration): update GPU integration tests
1 parent 4ea87fc commit ad7c946

File tree

1 file changed

+80
-8
lines changed

1 file changed

+80
-8
lines changed

integration/gpu_test.go

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"testing"
1010
"time"
1111

12+
"github.com/stretchr/testify/assert"
1213
"github.com/stretchr/testify/require"
1314

1415
"github.com/coder/envbox/integration/integrationtest"
@@ -41,8 +42,7 @@ func TestDocker_Nvidia(t *testing.T) {
4142
)
4243

4344
// Assert that we can run nvidia-smi in the inner container.
44-
_, err := execContainerCmd(ctx, t, ctID, "docker", "exec", "workspace_cvm", "nvidia-smi")
45-
require.NoError(t, err, "failed to run nvidia-smi in the inner container")
45+
assertInnerNvidiaSMI(ctx, t, ctID)
4646
})
4747

4848
t.Run("Redhat", func(t *testing.T) {
@@ -52,16 +52,21 @@ func TestDocker_Nvidia(t *testing.T) {
5252

5353
// Start the envbox container.
5454
ctID := startEnvboxCmd(ctx, t, integrationtest.RedhatImage, "root",
55-
"-v", "/usr/lib/x86_64-linux-gnu:/var/coder/usr/lib64",
55+
"-v", "/usr/lib/x86_64-linux-gnu:/var/coder/usr/lib",
5656
"--env", "CODER_ADD_GPU=true",
57-
"--env", "CODER_USR_LIB_DIR=/var/coder/usr/lib64",
57+
"--env", "CODER_USR_LIB_DIR=/var/coder/usr/lib",
5858
"--runtime=nvidia",
5959
"--gpus=all",
6060
)
6161

6262
// Assert that we can run nvidia-smi in the inner container.
63-
_, err := execContainerCmd(ctx, t, ctID, "docker", "exec", "workspace_cvm", "nvidia-smi")
64-
require.NoError(t, err, "failed to run nvidia-smi in the inner container")
63+
assertInnerNvidiaSMI(ctx, t, ctID)
64+
65+
// Make sure dnf still works.
66+
out, err := execContainerCmd(ctx, t, ctID, "docker", "exec", "workspace_cvm", "dnf", "list")
67+
if !assert.NoError(t, err, "failed to run dnf in the inner container") {
68+
t.Logf("dnf output:\n%s", strings.TrimSpace(out))
69+
}
6570
})
6671

6772
t.Run("InnerUsrLibDirOverride", func(t *testing.T) {
@@ -79,11 +84,35 @@ func TestDocker_Nvidia(t *testing.T) {
7984
"--gpus=all",
8085
)
8186

82-
// Assert that the libraries end up in the expected location in the inner container.
83-
out, err := execContainerCmd(ctx, t, ctID, "docker", "exec", "workspace_cvm", "ls", "-l", "/usr/lib/coder")
87+
// Assert that the libraries end up in the expected location in the inner
88+
// container.
89+
out, err := execContainerCmd(ctx, t, ctID, "docker", "exec", "workspace_cvm", "ls", "-1", "/usr/lib/coder")
8490
require.NoError(t, err, "inner usr lib dir override failed")
8591
require.Regexp(t, `(?i)(libgl|nvidia|vulkan|cuda)`, out)
8692
})
93+
94+
t.Run("EmptyHostUsrLibDir", func(t *testing.T) {
95+
t.Parallel()
96+
ctx, cancel := context.WithCancel(context.Background())
97+
t.Cleanup(cancel)
98+
emptyUsrLibDir := t.TempDir()
99+
100+
// Start the envbox container.
101+
ctID := startEnvboxCmd(ctx, t, integrationtest.UbuntuImage, "root",
102+
"-v", emptyUsrLibDir+":/var/coder/usr/lib",
103+
"--env", "CODER_ADD_GPU=true",
104+
"--env", "CODER_USR_LIB_DIR=/var/coder/usr/lib",
105+
"--runtime=nvidia",
106+
"--gpus=all",
107+
)
108+
109+
ofs := outerFiles(ctx, t, ctID, "/usr/lib/x86_64-linux-gnu/libnv*")
110+
// Assert invariant: the outer container has the files we expect.
111+
require.NotEmpty(t, ofs, "failed to list outer container files")
112+
// Assert that expected files are available in the inner container.
113+
assertInnerFiles(ctx, t, ctID, "/usr/lib/x86_64-linux-gnu/libnv*", ofs...)
114+
assertInnerNvidiaSMI(ctx, t, ctID)
115+
})
87116
}
88117

89118
// dockerRuntimes returns the list of container runtimes available on the host.
@@ -101,6 +130,49 @@ func dockerRuntimes(t *testing.T) []string {
101130
return strings.Split(raw, "\n")
102131
}
103132

133+
// outerFiles returns the list of files in the outer container matching the
134+
// given pattern. It does this by running `ls -1` in the outer container.
135+
func outerFiles(ctx context.Context, t *testing.T, containerID, pattern string) []string {
136+
t.Helper()
137+
// We need to use /bin/sh -c to avoid the shell interpreting the glob.
138+
out, err := execContainerCmd(ctx, t, containerID, "/bin/sh", "-c", "ls -1 "+pattern)
139+
require.NoError(t, err, "failed to list outer container files")
140+
files := strings.Split(strings.TrimSpace(out), "\n")
141+
slices.Sort(files)
142+
return files
143+
}
144+
145+
// assertInnerFiles checks that all the files matching the given pattern exist in the
146+
// inner container.
147+
func assertInnerFiles(ctx context.Context, t *testing.T, containerID, pattern string, expected ...string) {
148+
t.Helper()
149+
150+
// Get the list of files in the inner container.
151+
// We need to use /bin/sh -c to avoid the shell interpreting the glob.
152+
out, err := execContainerCmd(ctx, t, containerID, "docker", "exec", "workspace_cvm", "/bin/sh", "-c", "ls -1 "+pattern)
153+
require.NoError(t, err, "failed to list inner container files")
154+
innerFiles := strings.Split(strings.TrimSpace(out), "\n")
155+
156+
// Check that the expected files exist in the inner container.
157+
missingFiles := make([]string, 0)
158+
for _, expectedFile := range expected {
159+
if !slices.Contains(innerFiles, expectedFile) {
160+
missingFiles = append(missingFiles, expectedFile)
161+
}
162+
}
163+
require.Empty(t, missingFiles, "missing files in inner container: %s", strings.Join(missingFiles, ", "))
164+
}
165+
166+
// assertInnerNvidiaSMI checks that nvidia-smi runs successfully in the inner
167+
// container.
168+
func assertInnerNvidiaSMI(ctx context.Context, t *testing.T, containerID string) {
169+
t.Helper()
170+
// Assert that we can run nvidia-smi in the inner container.
171+
out, err := execContainerCmd(ctx, t, containerID, "docker", "exec", "workspace_cvm", "nvidia-smi")
172+
require.NoError(t, err, "failed to run nvidia-smi in the inner container")
173+
require.Contains(t, out, "NVIDIA-SMI", "nvidia-smi output does not contain NVIDIA-SMI")
174+
}
175+
104176
// startEnvboxCmd starts the envbox container with the given arguments.
105177
// Ideally we would use ory/dockertest for this, but it doesn't support
106178
// specifying the runtime. We have alternatively used the docker client library,

0 commit comments

Comments
 (0)