Skip to content

Commit 93e268f

Browse files
committed
tests: Symlink volume tests
There was a known issue regarding how the symlink files mounted as volumes were being handled on Windows. This commit adds tests that will check against those issue to ensure there won't be any regressions. Signed-off-by: Claudiu Belu <[email protected]>
1 parent 308c7b3 commit 93e268f

2 files changed

Lines changed: 162 additions & 0 deletions

File tree

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package integration
18+
19+
import (
20+
"io/ioutil"
21+
"os"
22+
"path/filepath"
23+
"testing"
24+
"time"
25+
26+
"github.com/stretchr/testify/assert"
27+
"github.com/stretchr/testify/require"
28+
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
29+
)
30+
31+
func createRegularFile(basePath, content string) (string, error) {
32+
newFolder := filepath.Join(basePath, "regular")
33+
err := os.Mkdir(newFolder, 0755)
34+
if err != nil {
35+
return "", err
36+
}
37+
38+
newFile := filepath.Join(newFolder, "foo.txt")
39+
err = ioutil.WriteFile(newFile, []byte(content), 0644)
40+
return filepath.Join("regular", "foo.txt"), err
41+
}
42+
43+
func fileInSymlinkedFolder(basePath, targetFile string) (string, error) {
44+
symlinkFolder := filepath.Join(basePath, "symlink_folder")
45+
err := os.Symlink(filepath.Dir(targetFile), symlinkFolder)
46+
47+
return filepath.Join(symlinkFolder, filepath.Base(targetFile)), err
48+
}
49+
50+
func symlinkedFile(basePath, targetFile string) (string, error) {
51+
symlinkFile := filepath.Join(basePath, "symlink_file")
52+
err := os.Symlink(targetFile, symlinkFile)
53+
54+
return symlinkFile, err
55+
}
56+
57+
func symlinkedFileInSymlinkedFolder(basePath, targetFile string) (string, error) {
58+
symlinkFolderFile, err := fileInSymlinkedFolder(basePath, targetFile)
59+
if err != nil {
60+
return "", err
61+
}
62+
63+
return symlinkedFile(basePath, symlinkFolderFile)
64+
}
65+
66+
func TestContainerSymlinkVolumes(t *testing.T) {
67+
for name, testCase := range map[string]struct {
68+
createFileFn func(basePath, targetFile string) (string, error)
69+
}{
70+
// Create difference file / symlink scenarios:
71+
// - symlink_file -> regular_folder/regular_file
72+
// - symlink_folder/regular_file (symlink_folder -> regular_folder)
73+
// - symlink_file -> symlink_folder/regular_file (symlink_folder -> regular_folder)
74+
"file in symlinked folder": {
75+
createFileFn: fileInSymlinkedFolder,
76+
},
77+
"symlinked file": {
78+
createFileFn: symlinkedFile,
79+
},
80+
"symlinkedFileInSymlinkedFolder": {
81+
createFileFn: symlinkedFileInSymlinkedFolder,
82+
},
83+
} {
84+
testCase := testCase // capture range variable
85+
t.Run(name, func(t *testing.T) {
86+
testPodLogDir, err := ioutil.TempDir("", "symlink-test")
87+
require.NoError(t, err)
88+
defer os.RemoveAll(testPodLogDir)
89+
90+
testVolDir, err := ioutil.TempDir("", "symlink-test-vol")
91+
require.NoError(t, err)
92+
defer os.RemoveAll(testVolDir)
93+
94+
content := "hello there\n"
95+
regularFile, err := createRegularFile(testVolDir, content)
96+
require.NoError(t, err)
97+
98+
file, err := testCase.createFileFn(testVolDir, regularFile)
99+
require.NoError(t, err)
100+
101+
t.Log("Create test sandbox with log directory")
102+
sbConfig := PodSandboxConfig("sandbox", "test-symlink",
103+
WithPodLogDirectory(testPodLogDir),
104+
)
105+
sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler)
106+
require.NoError(t, err)
107+
defer func() {
108+
assert.NoError(t, runtimeService.StopPodSandbox(sb))
109+
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
110+
}()
111+
112+
var (
113+
testImage = GetImage(BusyBox)
114+
containerName = "test-container"
115+
)
116+
117+
EnsureImageExists(t, testImage)
118+
119+
t.Log("Create a container with a symlink volume mount")
120+
cnConfig := ContainerConfig(
121+
containerName,
122+
testImage,
123+
WithCommand("cat", "/mounted_file"),
124+
WithLogPath(containerName),
125+
WithVolumeMount(file, "/mounted_file"),
126+
)
127+
128+
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
129+
require.NoError(t, err)
130+
131+
t.Log("Start the container")
132+
require.NoError(t, runtimeService.StartContainer(cn))
133+
134+
t.Log("Wait for container to finish running")
135+
require.NoError(t, Eventually(func() (bool, error) {
136+
s, err := runtimeService.ContainerStatus(cn)
137+
if err != nil {
138+
return false, err
139+
}
140+
if s.GetState() == runtime.ContainerState_CONTAINER_EXITED {
141+
return true, nil
142+
}
143+
return false, nil
144+
}, time.Second, 30*time.Second))
145+
146+
output, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName))
147+
assert.NoError(t, err)
148+
149+
assert.Contains(t, string(output), content)
150+
})
151+
}
152+
}

integration/main_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"fmt"
2424
"os"
2525
"os/exec"
26+
"path/filepath"
2627
"strconv"
2728
"strings"
2829
"testing"
@@ -206,6 +207,15 @@ func WithResources(r *runtime.LinuxContainerResources) ContainerOpts { //nolint:
206207
}
207208
}
208209

210+
func WithVolumeMount(hostPath, containerPath string) ContainerOpts {
211+
return func(c *runtime.ContainerConfig) {
212+
hostPath, _ = filepath.Abs(hostPath)
213+
containerPath, _ = filepath.Abs(containerPath)
214+
mount := &runtime.Mount{HostPath: hostPath, ContainerPath: containerPath}
215+
c.Mounts = append(c.Mounts, mount)
216+
}
217+
}
218+
209219
// Add container command.
210220
func WithCommand(cmd string, args ...string) ContainerOpts {
211221
return func(c *runtime.ContainerConfig) {

0 commit comments

Comments
 (0)