Merge pull request #8398 from fuweid/chore-ut

pkg/cri/sbserver: sub-test uses array and capture range var
This commit is contained in:
Maksym Pavlenko 2023-04-18 12:35:30 +02:00 committed by GitHub
commit 290a800e83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 973 additions and 493 deletions

View File

@ -198,12 +198,14 @@ func TestContainerCapabilities(t *testing.T) {
testContainerName := "container-name" testContainerName := "container-name"
testPid := uint32(1234) testPid := uint32(1234)
allCaps := cap.Known() allCaps := cap.Known()
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
capability *runtime.Capability capability *runtime.Capability
includes []string includes []string
excludes []string excludes []string
}{ }{
"should be able to add/drop capabilities": { {
desc: "should be able to add/drop capabilities",
capability: &runtime.Capability{ capability: &runtime.Capability{
AddCapabilities: []string{"SYS_ADMIN"}, AddCapabilities: []string{"SYS_ADMIN"},
DropCapabilities: []string{"CHOWN"}, DropCapabilities: []string{"CHOWN"},
@ -211,19 +213,22 @@ func TestContainerCapabilities(t *testing.T) {
includes: []string{"CAP_SYS_ADMIN"}, includes: []string{"CAP_SYS_ADMIN"},
excludes: []string{"CAP_CHOWN"}, excludes: []string{"CAP_CHOWN"},
}, },
"should be able to add all capabilities": { {
desc: "should be able to add all capabilities",
capability: &runtime.Capability{ capability: &runtime.Capability{
AddCapabilities: []string{"ALL"}, AddCapabilities: []string{"ALL"},
}, },
includes: allCaps, includes: allCaps,
}, },
"should be able to drop all capabilities": { {
desc: "should be able to drop all capabilities",
capability: &runtime.Capability{ capability: &runtime.Capability{
DropCapabilities: []string{"ALL"}, DropCapabilities: []string{"ALL"},
}, },
excludes: allCaps, excludes: allCaps,
}, },
"should be able to drop capabilities with add all": { {
desc: "should be able to drop capabilities with add all",
capability: &runtime.Capability{ capability: &runtime.Capability{
AddCapabilities: []string{"ALL"}, AddCapabilities: []string{"ALL"},
DropCapabilities: []string{"CHOWN"}, DropCapabilities: []string{"CHOWN"},
@ -231,7 +236,8 @@ func TestContainerCapabilities(t *testing.T) {
includes: util.SubtractStringSlice(allCaps, "CAP_CHOWN"), includes: util.SubtractStringSlice(allCaps, "CAP_CHOWN"),
excludes: []string{"CAP_CHOWN"}, excludes: []string{"CAP_CHOWN"},
}, },
"should be able to add capabilities with drop all": { {
desc: "should be able to add capabilities with drop all",
capability: &runtime.Capability{ capability: &runtime.Capability{
AddCapabilities: []string{"SYS_ADMIN"}, AddCapabilities: []string{"SYS_ADMIN"},
DropCapabilities: []string{"ALL"}, DropCapabilities: []string{"ALL"},
@ -240,7 +246,8 @@ func TestContainerCapabilities(t *testing.T) {
excludes: util.SubtractStringSlice(allCaps, "CAP_SYS_ADMIN"), excludes: util.SubtractStringSlice(allCaps, "CAP_SYS_ADMIN"),
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
ociRuntime := config.Runtime{} ociRuntime := config.Runtime{}
c := newTestCRIService() c := newTestCRIService()
@ -390,33 +397,39 @@ func TestContainerAndSandboxPrivileged(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
ociRuntime := config.Runtime{} ociRuntime := config.Runtime{}
c := newTestCRIService() c := newTestCRIService()
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
containerPrivileged bool containerPrivileged bool
sandboxPrivileged bool sandboxPrivileged bool
expectError bool expectError bool
}{ }{
"privileged container in non-privileged sandbox should fail": { {
desc: "privileged container in non-privileged sandbox should fail",
containerPrivileged: true, containerPrivileged: true,
sandboxPrivileged: false, sandboxPrivileged: false,
expectError: true, expectError: true,
}, },
"privileged container in privileged sandbox should be fine": { {
desc: "privileged container in privileged sandbox should be fine",
containerPrivileged: true, containerPrivileged: true,
sandboxPrivileged: true, sandboxPrivileged: true,
expectError: false, expectError: false,
}, },
"non-privileged container in privileged sandbox should be fine": { {
desc: "non-privileged container in privileged sandbox should be fine",
containerPrivileged: false, containerPrivileged: false,
sandboxPrivileged: true, sandboxPrivileged: true,
expectError: false, expectError: false,
}, },
"non-privileged container in non-privileged sandbox should be fine": { {
desc: "non-privileged container in non-privileged sandbox should be fine",
containerPrivileged: false, containerPrivileged: false,
sandboxPrivileged: false, sandboxPrivileged: false,
expectError: false, expectError: false,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
containerConfig.Linux.SecurityContext.Privileged = test.containerPrivileged containerConfig.Linux.SecurityContext.Privileged = test.containerPrivileged
sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
Privileged: test.sandboxPrivileged, Privileged: test.sandboxPrivileged,
@ -439,22 +452,26 @@ func TestPrivilegedBindMount(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
ociRuntime := config.Runtime{} ociRuntime := config.Runtime{}
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
privileged bool privileged bool
expectedSysFSRO bool expectedSysFSRO bool
expectedCgroupFSRO bool expectedCgroupFSRO bool
}{ }{
"sysfs and cgroupfs should mount as 'ro' by default": { {
desc: "sysfs and cgroupfs should mount as 'ro' by default",
expectedSysFSRO: true, expectedSysFSRO: true,
expectedCgroupFSRO: true, expectedCgroupFSRO: true,
}, },
"sysfs and cgroupfs should not mount as 'ro' if privileged": { {
desc: "sysfs and cgroupfs should not mount as 'ro' if privileged",
privileged: true, privileged: true,
expectedSysFSRO: false, expectedSysFSRO: false,
expectedCgroupFSRO: false, expectedCgroupFSRO: false,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
containerConfig.Linux.SecurityContext.Privileged = test.privileged containerConfig.Linux.SecurityContext.Privileged = test.privileged
sandboxConfig.Linux.SecurityContext.Privileged = test.privileged sandboxConfig.Linux.SecurityContext.Privileged = test.privileged
@ -498,13 +515,15 @@ func TestMountPropagation(t *testing.T) {
}, nil }, nil
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
criMount *runtime.Mount criMount *runtime.Mount
fakeLookupMountFn func(string) (mount.Info, error) fakeLookupMountFn func(string) (mount.Info, error)
optionsCheck []string optionsCheck []string
expectErr bool expectErr bool
}{ }{
"HostPath should mount as 'rprivate' if propagation is MountPropagation_PROPAGATION_PRIVATE": { {
desc: "HostPath should mount as 'rprivate' if propagation is MountPropagation_PROPAGATION_PRIVATE",
criMount: &runtime.Mount{ criMount: &runtime.Mount{
ContainerPath: "container-path", ContainerPath: "container-path",
HostPath: "host-path", HostPath: "host-path",
@ -514,7 +533,8 @@ func TestMountPropagation(t *testing.T) {
optionsCheck: []string{"rbind", "rprivate"}, optionsCheck: []string{"rbind", "rprivate"},
expectErr: false, expectErr: false,
}, },
"HostPath should mount as 'rslave' if propagation is MountPropagation_PROPAGATION_HOST_TO_CONTAINER": { {
desc: "HostPath should mount as 'rslave' if propagation is MountPropagation_PROPAGATION_HOST_TO_CONTAINER",
criMount: &runtime.Mount{ criMount: &runtime.Mount{
ContainerPath: "container-path", ContainerPath: "container-path",
HostPath: "host-path", HostPath: "host-path",
@ -524,7 +544,8 @@ func TestMountPropagation(t *testing.T) {
optionsCheck: []string{"rbind", "rslave"}, optionsCheck: []string{"rbind", "rslave"},
expectErr: false, expectErr: false,
}, },
"HostPath should mount as 'rshared' if propagation is MountPropagation_PROPAGATION_BIDIRECTIONAL": { {
desc: "HostPath should mount as 'rshared' if propagation is MountPropagation_PROPAGATION_BIDIRECTIONAL",
criMount: &runtime.Mount{ criMount: &runtime.Mount{
ContainerPath: "container-path", ContainerPath: "container-path",
HostPath: "host-path", HostPath: "host-path",
@ -534,7 +555,8 @@ func TestMountPropagation(t *testing.T) {
optionsCheck: []string{"rbind", "rshared"}, optionsCheck: []string{"rbind", "rshared"},
expectErr: false, expectErr: false,
}, },
"HostPath should mount as 'rprivate' if propagation is illegal": { {
desc: "HostPath should mount as 'rprivate' if propagation is illegal",
criMount: &runtime.Mount{ criMount: &runtime.Mount{
ContainerPath: "container-path", ContainerPath: "container-path",
HostPath: "host-path", HostPath: "host-path",
@ -544,7 +566,8 @@ func TestMountPropagation(t *testing.T) {
optionsCheck: []string{"rbind", "rprivate"}, optionsCheck: []string{"rbind", "rprivate"},
expectErr: false, expectErr: false,
}, },
"Expect an error if HostPath isn't shared and mount propagation is MountPropagation_PROPAGATION_BIDIRECTIONAL": { {
desc: "Expect an error if HostPath isn't shared and mount propagation is MountPropagation_PROPAGATION_BIDIRECTIONAL",
criMount: &runtime.Mount{ criMount: &runtime.Mount{
ContainerPath: "container-path", ContainerPath: "container-path",
HostPath: "host-path", HostPath: "host-path",
@ -553,7 +576,8 @@ func TestMountPropagation(t *testing.T) {
fakeLookupMountFn: slaveLookupMountFn, fakeLookupMountFn: slaveLookupMountFn,
expectErr: true, expectErr: true,
}, },
"Expect an error if HostPath isn't slave or shared and mount propagation is MountPropagation_PROPAGATION_HOST_TO_CONTAINER": { {
desc: "Expect an error if HostPath isn't slave or shared and mount propagation is MountPropagation_PROPAGATION_HOST_TO_CONTAINER",
criMount: &runtime.Mount{ criMount: &runtime.Mount{
ContainerPath: "container-path", ContainerPath: "container-path",
HostPath: "host-path", HostPath: "host-path",
@ -563,7 +587,8 @@ func TestMountPropagation(t *testing.T) {
expectErr: true, expectErr: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
c.os.(*ostesting.FakeOS).LookupMountFn = test.fakeLookupMountFn c.os.(*ostesting.FakeOS).LookupMountFn = test.fakeLookupMountFn
config, _, _, _ := getCreateContainerTestData() config, _, _, _ := getCreateContainerTestData()
@ -590,24 +615,28 @@ func TestPidNamespace(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
ociRuntime := config.Runtime{} ociRuntime := config.Runtime{}
c := newTestCRIService() c := newTestCRIService()
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
pidNS runtime.NamespaceMode pidNS runtime.NamespaceMode
expected runtimespec.LinuxNamespace expected runtimespec.LinuxNamespace
}{ }{
"node namespace mode": { {
desc: "node namespace mode",
pidNS: runtime.NamespaceMode_NODE, pidNS: runtime.NamespaceMode_NODE,
expected: runtimespec.LinuxNamespace{ expected: runtimespec.LinuxNamespace{
Type: runtimespec.PIDNamespace, Type: runtimespec.PIDNamespace,
Path: opts.GetPIDNamespace(testPid), Path: opts.GetPIDNamespace(testPid),
}, },
}, },
"container namespace mode": { {
desc: "container namespace mode",
pidNS: runtime.NamespaceMode_CONTAINER, pidNS: runtime.NamespaceMode_CONTAINER,
expected: runtimespec.LinuxNamespace{ expected: runtimespec.LinuxNamespace{
Type: runtimespec.PIDNamespace, Type: runtimespec.PIDNamespace,
}, },
}, },
"pod namespace mode": { {
desc: "pod namespace mode",
pidNS: runtime.NamespaceMode_POD, pidNS: runtime.NamespaceMode_POD,
expected: runtimespec.LinuxNamespace{ expected: runtimespec.LinuxNamespace{
Type: runtimespec.PIDNamespace, Type: runtimespec.PIDNamespace,
@ -615,7 +644,8 @@ func TestPidNamespace(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
containerConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{Pid: test.pidNS} containerConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{Pid: test.pidNS}
spec, err := c.buildContainerSpec(currentPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) spec, err := c.buildContainerSpec(currentPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err) require.NoError(t, err)
@ -647,7 +677,9 @@ func TestUserNamespace(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
ociRuntime := config.Runtime{} ociRuntime := config.Runtime{}
c := newTestCRIService() c := newTestCRIService()
for desc, test := range map[string]struct {
for _, test := range []struct {
desc string
userNS *runtime.UserNamespace userNS *runtime.UserNamespace
sandboxUserNS *runtime.UserNamespace sandboxUserNS *runtime.UserNamespace
expNS *runtimespec.LinuxNamespace expNS *runtimespec.LinuxNamespace
@ -656,7 +688,8 @@ func TestUserNamespace(t *testing.T) {
expGIDMapping []runtimespec.LinuxIDMapping expGIDMapping []runtimespec.LinuxIDMapping
err bool err bool
}{ }{
"node namespace mode": { {
desc: "node namespace mode",
userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_NODE}, userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_NODE},
// Expect userns to NOT be present. // Expect userns to NOT be present.
expNotNS: &runtimespec.LinuxNamespace{ expNotNS: &runtimespec.LinuxNamespace{
@ -664,7 +697,8 @@ func TestUserNamespace(t *testing.T) {
Path: opts.GetUserNamespace(testPid), Path: opts.GetUserNamespace(testPid),
}, },
}, },
"node namespace mode with mappings": { {
desc: "node namespace mode with mappings",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_NODE, Mode: runtime.NamespaceMode_NODE,
Uids: []*runtime.IDMapping{&idMap}, Uids: []*runtime.IDMapping{&idMap},
@ -672,19 +706,23 @@ func TestUserNamespace(t *testing.T) {
}, },
err: true, err: true,
}, },
"container namespace mode": { {
desc: "container namespace mode",
userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_CONTAINER}, userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_CONTAINER},
err: true, err: true,
}, },
"target namespace mode": { {
desc: "target namespace mode",
userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_TARGET}, userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_TARGET},
err: true, err: true,
}, },
"unknown namespace mode": { {
desc: "unknown namespace mode",
userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode(100)}, userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode(100)},
err: true, err: true,
}, },
"pod namespace mode": { {
desc: "pod namespace mode",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_POD, Mode: runtime.NamespaceMode_POD,
Uids: []*runtime.IDMapping{&idMap}, Uids: []*runtime.IDMapping{&idMap},
@ -697,7 +735,8 @@ func TestUserNamespace(t *testing.T) {
expUIDMapping: []runtimespec.LinuxIDMapping{expIDMap}, expUIDMapping: []runtimespec.LinuxIDMapping{expIDMap},
expGIDMapping: []runtimespec.LinuxIDMapping{expIDMap}, expGIDMapping: []runtimespec.LinuxIDMapping{expIDMap},
}, },
"pod namespace mode with inconsistent sandbox config (different GIDs)": { {
desc: "pod namespace mode with inconsistent sandbox config (different GIDs)",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_POD, Mode: runtime.NamespaceMode_POD,
Uids: []*runtime.IDMapping{&idMap}, Uids: []*runtime.IDMapping{&idMap},
@ -710,7 +749,8 @@ func TestUserNamespace(t *testing.T) {
}, },
err: true, err: true,
}, },
"pod namespace mode with inconsistent sandbox config (different UIDs)": { {
desc: "pod namespace mode with inconsistent sandbox config (different UIDs)",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_POD, Mode: runtime.NamespaceMode_POD,
Uids: []*runtime.IDMapping{&idMap}, Uids: []*runtime.IDMapping{&idMap},
@ -723,7 +763,8 @@ func TestUserNamespace(t *testing.T) {
}, },
err: true, err: true,
}, },
"pod namespace mode with inconsistent sandbox config (different len)": { {
desc: "pod namespace mode with inconsistent sandbox config (different len)",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_POD, Mode: runtime.NamespaceMode_POD,
Uids: []*runtime.IDMapping{&idMap}, Uids: []*runtime.IDMapping{&idMap},
@ -736,7 +777,8 @@ func TestUserNamespace(t *testing.T) {
}, },
err: true, err: true,
}, },
"pod namespace mode with inconsistent sandbox config (different mode)": { {
desc: "pod namespace mode with inconsistent sandbox config (different mode)",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_POD, Mode: runtime.NamespaceMode_POD,
Uids: []*runtime.IDMapping{&idMap}, Uids: []*runtime.IDMapping{&idMap},
@ -749,7 +791,8 @@ func TestUserNamespace(t *testing.T) {
}, },
err: true, err: true,
}, },
"pod namespace mode with several mappings": { {
desc: "pod namespace mode with several mappings",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_POD, Mode: runtime.NamespaceMode_POD,
Uids: []*runtime.IDMapping{&idMap, &idMap}, Uids: []*runtime.IDMapping{&idMap, &idMap},
@ -757,7 +800,8 @@ func TestUserNamespace(t *testing.T) {
}, },
err: true, err: true,
}, },
"pod namespace mode with uneven mappings": { {
desc: "pod namespace mode with uneven mappings",
userNS: &runtime.UserNamespace{ userNS: &runtime.UserNamespace{
Mode: runtime.NamespaceMode_POD, Mode: runtime.NamespaceMode_POD,
Uids: []*runtime.IDMapping{&idMap, &idMap}, Uids: []*runtime.IDMapping{&idMap, &idMap},
@ -766,9 +810,8 @@ func TestUserNamespace(t *testing.T) {
err: true, err: true,
}, },
} { } {
desc := desc
test := test test := test
t.Run(desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
containerConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{UsernsOptions: test.userNS} containerConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{UsernsOptions: test.userNS}
// By default, set sandbox and container config to the same (this is // By default, set sandbox and container config to the same (this is
// required by containerSpec). However, if the test wants to test for what // required by containerSpec). However, if the test wants to test for what
@ -817,7 +860,8 @@ func TestNoDefaultRunMount(t *testing.T) {
} }
func TestGenerateSeccompSecurityProfileSpecOpts(t *testing.T) { func TestGenerateSeccompSecurityProfileSpecOpts(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
profile string profile string
privileged bool privileged bool
disable bool disable bool
@ -826,98 +870,119 @@ func TestGenerateSeccompSecurityProfileSpecOpts(t *testing.T) {
defaultProfile string defaultProfile string
sp *runtime.SecurityProfile sp *runtime.SecurityProfile
}{ }{
"should return error if seccomp is specified when seccomp is not supported": { {
desc: "should return error if seccomp is specified when seccomp is not supported",
profile: runtimeDefault, profile: runtimeDefault,
disable: true, disable: true,
expectErr: true, expectErr: true,
}, },
"should not return error if seccomp is not specified when seccomp is not supported": { {
desc: "should not return error if seccomp is not specified when seccomp is not supported",
profile: "", profile: "",
disable: true, disable: true,
}, },
"should not return error if seccomp is unconfined when seccomp is not supported": { {
desc: "should not return error if seccomp is unconfined when seccomp is not supported",
profile: unconfinedProfile, profile: unconfinedProfile,
disable: true, disable: true,
}, },
"should not set seccomp when privileged is true": { {
desc: "should not set seccomp when privileged is true",
profile: seccompDefaultProfile, profile: seccompDefaultProfile,
privileged: true, privileged: true,
}, },
"should not set seccomp when seccomp is unconfined": { {
desc: "should not set seccomp when seccomp is unconfined",
profile: unconfinedProfile, profile: unconfinedProfile,
}, },
"should not set seccomp when seccomp is not specified": { {
desc: "should not set seccomp when seccomp is not specified",
profile: "", profile: "",
}, },
"should set default seccomp when seccomp is runtime/default": { {
desc: "should set default seccomp when seccomp is runtime/default",
profile: runtimeDefault, profile: runtimeDefault,
specOpts: seccomp.WithDefaultProfile(), specOpts: seccomp.WithDefaultProfile(),
}, },
"should set default seccomp when seccomp is docker/default": { {
desc: "should set default seccomp when seccomp is docker/default",
profile: dockerDefault, profile: dockerDefault,
specOpts: seccomp.WithDefaultProfile(), specOpts: seccomp.WithDefaultProfile(),
}, },
"should set specified profile when local profile is specified": { {
desc: "should set specified profile when local profile is specified",
profile: profileNamePrefix + "test-profile", profile: profileNamePrefix + "test-profile",
specOpts: seccomp.WithProfile("test-profile"), specOpts: seccomp.WithProfile("test-profile"),
}, },
"should use default profile when seccomp is empty": { {
desc: "should use default profile when seccomp is empty",
defaultProfile: profileNamePrefix + "test-profile", defaultProfile: profileNamePrefix + "test-profile",
specOpts: seccomp.WithProfile("test-profile"), specOpts: seccomp.WithProfile("test-profile"),
}, },
"should fallback to docker/default when seccomp is empty and default is runtime/default": { {
desc: "should fallback to docker/default when seccomp is empty and default is runtime/default",
defaultProfile: runtimeDefault, defaultProfile: runtimeDefault,
specOpts: seccomp.WithDefaultProfile(), specOpts: seccomp.WithDefaultProfile(),
}, },
//----------------------------------------------- //-----------------------------------------------
// now buckets for the SecurityProfile variants // now buckets for the SecurityProfile variants
//----------------------------------------------- //-----------------------------------------------
"sp should return error if seccomp is specified when seccomp is not supported": { {
desc: "sp should return error if seccomp is specified when seccomp is not supported",
disable: true, disable: true,
expectErr: true, expectErr: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_RuntimeDefault, ProfileType: runtime.SecurityProfile_RuntimeDefault,
}, },
}, },
"sp should not return error if seccomp is unconfined when seccomp is not supported": { {
desc: "sp should not return error if seccomp is unconfined when seccomp is not supported",
disable: true, disable: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Unconfined, ProfileType: runtime.SecurityProfile_Unconfined,
}, },
}, },
"sp should not set seccomp when privileged is true": { {
desc: "sp should not set seccomp when privileged is true",
privileged: true, privileged: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_RuntimeDefault, ProfileType: runtime.SecurityProfile_RuntimeDefault,
}, },
}, },
"sp should not set seccomp when seccomp is unconfined": { {
desc: "sp should not set seccomp when seccomp is unconfined",
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Unconfined, ProfileType: runtime.SecurityProfile_Unconfined,
}, },
}, },
"sp should not set seccomp when seccomp is not specified": {}, {
"sp should set default seccomp when seccomp is runtime/default": { desc: "sp should not set seccomp when seccomp is not specified",
},
{
desc: "sp should set default seccomp when seccomp is runtime/default",
specOpts: seccomp.WithDefaultProfile(), specOpts: seccomp.WithDefaultProfile(),
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_RuntimeDefault, ProfileType: runtime.SecurityProfile_RuntimeDefault,
}, },
}, },
"sp should set specified profile when local profile is specified": { {
desc: "sp should set specified profile when local profile is specified",
specOpts: seccomp.WithProfile("test-profile"), specOpts: seccomp.WithProfile("test-profile"),
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Localhost, ProfileType: runtime.SecurityProfile_Localhost,
LocalhostRef: profileNamePrefix + "test-profile", LocalhostRef: profileNamePrefix + "test-profile",
}, },
}, },
"sp should set specified profile when local profile is specified even without prefix": { {
desc: "sp should set specified profile when local profile is specified even without prefix",
specOpts: seccomp.WithProfile("test-profile"), specOpts: seccomp.WithProfile("test-profile"),
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Localhost, ProfileType: runtime.SecurityProfile_Localhost,
LocalhostRef: "test-profile", LocalhostRef: "test-profile",
}, },
}, },
"sp should return error if specified profile is invalid": { {
desc: "sp should return error if specified profile is invalid",
expectErr: true, expectErr: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_RuntimeDefault, ProfileType: runtime.SecurityProfile_RuntimeDefault,
@ -925,7 +990,8 @@ func TestGenerateSeccompSecurityProfileSpecOpts(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
cri := &criService{} cri := &criService{}
cri.config.UnsetSeccompProfile = test.defaultProfile cri.config.UnsetSeccompProfile = test.defaultProfile
ssp := test.sp ssp := test.sp
@ -957,7 +1023,8 @@ func TestGenerateSeccompSecurityProfileSpecOpts(t *testing.T) {
} }
func TestGenerateApparmorSpecOpts(t *testing.T) { func TestGenerateApparmorSpecOpts(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
profile string profile string
privileged bool privileged bool
disable bool disable bool
@ -965,103 +1032,123 @@ func TestGenerateApparmorSpecOpts(t *testing.T) {
expectErr bool expectErr bool
sp *runtime.SecurityProfile sp *runtime.SecurityProfile
}{ }{
"should return error if apparmor is specified when apparmor is not supported": { {
desc: "should return error if apparmor is specified when apparmor is not supported",
profile: runtimeDefault, profile: runtimeDefault,
disable: true, disable: true,
expectErr: true, expectErr: true,
}, },
"should not return error if apparmor is not specified when apparmor is not supported": { {
desc: "should not return error if apparmor is not specified when apparmor is not supported",
profile: "", profile: "",
disable: true, disable: true,
}, },
"should set default apparmor when apparmor is not specified": { {
desc: "should set default apparmor when apparmor is not specified",
profile: "", profile: "",
specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName), specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName),
}, },
"should not apparmor when apparmor is not specified and privileged is true": { {
desc: "should not apparmor when apparmor is not specified and privileged is true",
profile: "", profile: "",
privileged: true, privileged: true,
}, },
"should not return error if apparmor is unconfined when apparmor is not supported": { {
desc: "should not return error if apparmor is unconfined when apparmor is not supported",
profile: unconfinedProfile, profile: unconfinedProfile,
disable: true, disable: true,
}, },
"should not apparmor when apparmor is unconfined": { {
desc: "should not apparmor when apparmor is unconfined",
profile: unconfinedProfile, profile: unconfinedProfile,
}, },
"should not apparmor when apparmor is unconfined and privileged is true": { {
desc: "should not apparmor when apparmor is unconfined and privileged is true",
profile: unconfinedProfile, profile: unconfinedProfile,
privileged: true, privileged: true,
}, },
"should set default apparmor when apparmor is runtime/default": { {
desc: "should set default apparmor when apparmor is runtime/default",
profile: runtimeDefault, profile: runtimeDefault,
specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName), specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName),
}, },
"should not apparmor when apparmor is default and privileged is true": { {
desc: "should not apparmor when apparmor is default and privileged is true",
profile: runtimeDefault, profile: runtimeDefault,
privileged: true, privileged: true,
}, },
// TODO (mikebrow) add success with existing defined profile tests // TODO (mikebrow) add success with existing defined profile tests
"should return error when undefined local profile is specified": { {
desc: "should return error when undefined local profile is specified",
profile: profileNamePrefix + "test-profile", profile: profileNamePrefix + "test-profile",
expectErr: true, expectErr: true,
}, },
"should return error when undefined local profile is specified and privileged is true": { {
desc: "should return error when undefined local profile is specified and privileged is true",
profile: profileNamePrefix + "test-profile", profile: profileNamePrefix + "test-profile",
privileged: true, privileged: true,
expectErr: true, expectErr: true,
}, },
"should return error if specified profile is invalid": { {
desc: "should return error if specified profile is invalid",
profile: "test-profile", profile: "test-profile",
expectErr: true, expectErr: true,
}, },
//-------------------------------------- //--------------------------------------
// buckets for SecurityProfile struct // buckets for SecurityProfile struct
//-------------------------------------- //--------------------------------------
"sp should return error if apparmor is specified when apparmor is not supported": { {
desc: "sp should return error if apparmor is specified when apparmor is not supported",
disable: true, disable: true,
expectErr: true, expectErr: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_RuntimeDefault, ProfileType: runtime.SecurityProfile_RuntimeDefault,
}, },
}, },
"sp should not return error if apparmor is unconfined when apparmor is not supported": { {
desc: "sp should not return error if apparmor is unconfined when apparmor is not supported",
disable: true, disable: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Unconfined, ProfileType: runtime.SecurityProfile_Unconfined,
}, },
}, },
"sp should not apparmor when apparmor is unconfined": { {
desc: "sp should not apparmor when apparmor is unconfined",
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Unconfined, ProfileType: runtime.SecurityProfile_Unconfined,
}, },
}, },
"sp should not apparmor when apparmor is unconfined and privileged is true": { {
desc: "sp should not apparmor when apparmor is unconfined and privileged is true",
privileged: true, privileged: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Unconfined, ProfileType: runtime.SecurityProfile_Unconfined,
}, },
}, },
"sp should set default apparmor when apparmor is runtime/default": { {
desc: "sp should set default apparmor when apparmor is runtime/default",
specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName), specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName),
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_RuntimeDefault, ProfileType: runtime.SecurityProfile_RuntimeDefault,
}, },
}, },
"sp should not apparmor when apparmor is default and privileged is true": { {
desc: "sp should not apparmor when apparmor is default and privileged is true",
privileged: true, privileged: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_RuntimeDefault, ProfileType: runtime.SecurityProfile_RuntimeDefault,
}, },
}, },
"sp should return error when undefined local profile is specified": { {
desc: "sp should return error when undefined local profile is specified",
expectErr: true, expectErr: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
ProfileType: runtime.SecurityProfile_Localhost, ProfileType: runtime.SecurityProfile_Localhost,
LocalhostRef: profileNamePrefix + "test-profile", LocalhostRef: profileNamePrefix + "test-profile",
}, },
}, },
"sp should return error when undefined local profile is specified even without prefix": { {
desc: "sp should return error when undefined local profile is specified even without prefix",
profile: profileNamePrefix + "test-profile", profile: profileNamePrefix + "test-profile",
expectErr: true, expectErr: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
@ -1069,7 +1156,8 @@ func TestGenerateApparmorSpecOpts(t *testing.T) {
LocalhostRef: "test-profile", LocalhostRef: "test-profile",
}, },
}, },
"sp should return error when undefined local profile is specified and privileged is true": { {
desc: "sp should return error when undefined local profile is specified and privileged is true",
privileged: true, privileged: true,
expectErr: true, expectErr: true,
sp: &runtime.SecurityProfile{ sp: &runtime.SecurityProfile{
@ -1078,7 +1166,8 @@ func TestGenerateApparmorSpecOpts(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
asp := test.sp asp := test.sp
csp, err := generateApparmorSecurityProfile(test.profile) csp, err := generateApparmorSecurityProfile(test.profile)
if err != nil { if err != nil {
@ -1117,7 +1206,8 @@ func TestMaskedAndReadonlyPaths(t *testing.T) {
defaultSpec, err := oci.GenerateSpec(ctrdutil.NamespacedContext(), nil, &containers.Container{ID: testID}) defaultSpec, err := oci.GenerateSpec(ctrdutil.NamespacedContext(), nil, &containers.Container{ID: testID})
require.NoError(t, err) require.NoError(t, err)
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
disableProcMount bool disableProcMount bool
masked []string masked []string
readonly []string readonly []string
@ -1125,7 +1215,8 @@ func TestMaskedAndReadonlyPaths(t *testing.T) {
expectedReadonly []string expectedReadonly []string
privileged bool privileged bool
}{ }{
"should apply default if not specified when disable_proc_mount = true": { {
desc: "should apply default if not specified when disable_proc_mount = true",
disableProcMount: true, disableProcMount: true,
masked: nil, masked: nil,
readonly: nil, readonly: nil,
@ -1133,7 +1224,8 @@ func TestMaskedAndReadonlyPaths(t *testing.T) {
expectedReadonly: defaultSpec.Linux.ReadonlyPaths, expectedReadonly: defaultSpec.Linux.ReadonlyPaths,
privileged: false, privileged: false,
}, },
"should apply default if not specified when disable_proc_mount = false": { {
desc: "should apply default if not specified when disable_proc_mount = false",
disableProcMount: false, disableProcMount: false,
masked: nil, masked: nil,
readonly: nil, readonly: nil,
@ -1141,33 +1233,38 @@ func TestMaskedAndReadonlyPaths(t *testing.T) {
expectedReadonly: []string{}, expectedReadonly: []string{},
privileged: false, privileged: false,
}, },
"should be able to specify empty paths": { {
desc: "should be able to specify empty paths",
masked: []string{}, masked: []string{},
readonly: []string{}, readonly: []string{},
expectedMasked: []string{}, expectedMasked: []string{},
expectedReadonly: []string{}, expectedReadonly: []string{},
privileged: false, privileged: false,
}, },
"should apply CRI specified paths": { {
desc: "should apply CRI specified paths",
masked: []string{"/proc"}, masked: []string{"/proc"},
readonly: []string{"/sys"}, readonly: []string{"/sys"},
expectedMasked: []string{"/proc"}, expectedMasked: []string{"/proc"},
expectedReadonly: []string{"/sys"}, expectedReadonly: []string{"/sys"},
privileged: false, privileged: false,
}, },
"default should be nil for privileged": { {
desc: "default should be nil for privileged",
expectedMasked: nil, expectedMasked: nil,
expectedReadonly: nil, expectedReadonly: nil,
privileged: true, privileged: true,
}, },
"should be able to specify empty paths, esp. if privileged": { {
desc: "should be able to specify empty paths, esp. if privileged",
masked: []string{}, masked: []string{},
readonly: []string{}, readonly: []string{},
expectedMasked: nil, expectedMasked: nil,
expectedReadonly: nil, expectedReadonly: nil,
privileged: true, privileged: true,
}, },
"should not apply CRI specified paths if privileged": { {
desc: "should not apply CRI specified paths if privileged",
masked: []string{"/proc"}, masked: []string{"/proc"},
readonly: []string{"/sys"}, readonly: []string{"/sys"},
expectedMasked: nil, expectedMasked: nil,
@ -1175,7 +1272,8 @@ func TestMaskedAndReadonlyPaths(t *testing.T) {
privileged: true, privileged: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c.config.DisableProcMount = test.disableProcMount c.config.DisableProcMount = test.disableProcMount
containerConfig.Linux.SecurityContext.MaskedPaths = test.masked containerConfig.Linux.SecurityContext.MaskedPaths = test.masked
containerConfig.Linux.SecurityContext.ReadonlyPaths = test.readonly containerConfig.Linux.SecurityContext.ReadonlyPaths = test.readonly
@ -1205,28 +1303,33 @@ func TestHostname(t *testing.T) {
c.os.(*ostesting.FakeOS).HostnameFn = func() (string, error) { c.os.(*ostesting.FakeOS).HostnameFn = func() (string, error) {
return "real-hostname", nil return "real-hostname", nil
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
hostname string hostname string
networkNs runtime.NamespaceMode networkNs runtime.NamespaceMode
expectedEnv string expectedEnv string
}{ }{
"should add HOSTNAME=sandbox.Hostname for pod network namespace": { {
desc: "should add HOSTNAME=sandbox.Hostname for pod network namespace",
hostname: "test-hostname", hostname: "test-hostname",
networkNs: runtime.NamespaceMode_POD, networkNs: runtime.NamespaceMode_POD,
expectedEnv: "HOSTNAME=test-hostname", expectedEnv: "HOSTNAME=test-hostname",
}, },
"should add HOSTNAME=sandbox.Hostname for host network namespace": { {
desc: "should add HOSTNAME=sandbox.Hostname for host network namespace",
hostname: "test-hostname", hostname: "test-hostname",
networkNs: runtime.NamespaceMode_NODE, networkNs: runtime.NamespaceMode_NODE,
expectedEnv: "HOSTNAME=test-hostname", expectedEnv: "HOSTNAME=test-hostname",
}, },
"should add HOSTNAME=os.Hostname for host network namespace if sandbox.Hostname is not set": { {
desc: "should add HOSTNAME=os.Hostname for host network namespace if sandbox.Hostname is not set",
hostname: "", hostname: "",
networkNs: runtime.NamespaceMode_NODE, networkNs: runtime.NamespaceMode_NODE,
expectedEnv: "HOSTNAME=real-hostname", expectedEnv: "HOSTNAME=real-hostname",
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
sandboxConfig.Hostname = test.hostname sandboxConfig.Hostname = test.hostname
sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
NamespaceOptions: &runtime.NamespaceOption{Network: test.networkNs}, NamespaceOptions: &runtime.NamespaceOption{Network: test.networkNs},
@ -1357,12 +1460,14 @@ additional-group-for-root:x:22222:root
os.WriteFile(filepath.Join(tempRootDir, "etc", "group"), []byte(etcGroup), 0644), os.WriteFile(filepath.Join(tempRootDir, "etc", "group"), []byte(etcGroup), 0644),
) )
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
imageConfigUser string imageConfigUser string
securityContext *runtime.LinuxContainerSecurityContext securityContext *runtime.LinuxContainerSecurityContext
expected runtimespec.User expected runtimespec.User
}{ }{
"Only SecurityContext was set, SecurityContext defines User": { {
desc: "Only SecurityContext was set, SecurityContext defines User",
securityContext: &runtime.LinuxContainerSecurityContext{ securityContext: &runtime.LinuxContainerSecurityContext{
RunAsUser: &runtime.Int64Value{Value: 1000}, RunAsUser: &runtime.Int64Value{Value: 1000},
RunAsGroup: &runtime.Int64Value{Value: 2000}, RunAsGroup: &runtime.Int64Value{Value: 2000},
@ -1370,12 +1475,14 @@ additional-group-for-root:x:22222:root
}, },
expected: runtimespec.User{UID: 1000, GID: 2000, AdditionalGids: []uint32{2000, 3333, 11111}}, expected: runtimespec.User{UID: 1000, GID: 2000, AdditionalGids: []uint32{2000, 3333, 11111}},
}, },
"Only imageConfig.User was set, imageConfig.User defines User": { {
desc: "Only imageConfig.User was set, imageConfig.User defines User",
imageConfigUser: "1000", imageConfigUser: "1000",
securityContext: nil, securityContext: nil,
expected: runtimespec.User{UID: 1000, GID: 1000, AdditionalGids: []uint32{1000, 11111}}, expected: runtimespec.User{UID: 1000, GID: 1000, AdditionalGids: []uint32{1000, 11111}},
}, },
"Both SecurityContext and ImageConfig.User was set, SecurityContext defines User": { {
desc: "Both SecurityContext and ImageConfig.User was set, SecurityContext defines User",
imageConfigUser: "0", imageConfigUser: "0",
securityContext: &runtime.LinuxContainerSecurityContext{ securityContext: &runtime.LinuxContainerSecurityContext{
RunAsUser: &runtime.Int64Value{Value: 1000}, RunAsUser: &runtime.Int64Value{Value: 1000},
@ -1384,12 +1491,13 @@ additional-group-for-root:x:22222:root
}, },
expected: runtimespec.User{UID: 1000, GID: 2000, AdditionalGids: []uint32{2000, 3333, 11111}}, expected: runtimespec.User{UID: 1000, GID: 2000, AdditionalGids: []uint32{2000, 3333, 11111}},
}, },
"No SecurityContext nor ImageConfig.User were set, runtime default defines User": { {
desc: "No SecurityContext nor ImageConfig.User were set, runtime default defines User",
expected: runtimespec.User{UID: 0, GID: 0, AdditionalGids: []uint32{0, 22222}}, expected: runtimespec.User{UID: 0, GID: 0, AdditionalGids: []uint32{0, 22222}},
}, },
} { } {
desc := desc test := test
t.Run(desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
containerConfig.Linux.SecurityContext = test.securityContext containerConfig.Linux.SecurityContext = test.securityContext
imageConfig.User = test.imageConfigUser imageConfig.User = test.imageConfigUser
@ -1419,32 +1527,37 @@ func TestNonRootUserAndDevices(t *testing.T) {
testDevice := hostDevicesRaw[0] testDevice := hostDevicesRaw[0]
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
uid, gid *runtime.Int64Value uid, gid *runtime.Int64Value
deviceOwnershipFromSecurityContext bool deviceOwnershipFromSecurityContext bool
expectedDeviceUID uint32 expectedDeviceUID uint32
expectedDeviceGID uint32 expectedDeviceGID uint32
}{ }{
"expect non-root container's Devices Uid/Gid to be the same as the device Uid/Gid on the host when deviceOwnershipFromSecurityContext is disabled": { {
desc: "expect non-root container's Devices Uid/Gid to be the same as the device Uid/Gid on the host when deviceOwnershipFromSecurityContext is disabled",
uid: &runtime.Int64Value{Value: 1}, uid: &runtime.Int64Value{Value: 1},
gid: &runtime.Int64Value{Value: 10}, gid: &runtime.Int64Value{Value: 10},
expectedDeviceUID: *testDevice.UID, expectedDeviceUID: *testDevice.UID,
expectedDeviceGID: *testDevice.GID, expectedDeviceGID: *testDevice.GID,
}, },
"expect root container's Devices Uid/Gid to be the same as the device Uid/Gid on the host when deviceOwnershipFromSecurityContext is disabled": { {
desc: "expect root container's Devices Uid/Gid to be the same as the device Uid/Gid on the host when deviceOwnershipFromSecurityContext is disabled",
uid: &runtime.Int64Value{Value: 0}, uid: &runtime.Int64Value{Value: 0},
gid: &runtime.Int64Value{Value: 0}, gid: &runtime.Int64Value{Value: 0},
expectedDeviceUID: *testDevice.UID, expectedDeviceUID: *testDevice.UID,
expectedDeviceGID: *testDevice.GID, expectedDeviceGID: *testDevice.GID,
}, },
"expect non-root container's Devices Uid/Gid to be the same as RunAsUser/RunAsGroup when deviceOwnershipFromSecurityContext is enabled": { {
desc: "expect non-root container's Devices Uid/Gid to be the same as RunAsUser/RunAsGroup when deviceOwnershipFromSecurityContext is enabled",
uid: &runtime.Int64Value{Value: 1}, uid: &runtime.Int64Value{Value: 1},
gid: &runtime.Int64Value{Value: 10}, gid: &runtime.Int64Value{Value: 10},
deviceOwnershipFromSecurityContext: true, deviceOwnershipFromSecurityContext: true,
expectedDeviceUID: 1, expectedDeviceUID: 1,
expectedDeviceGID: 10, expectedDeviceGID: 10,
}, },
"expect root container's Devices Uid/Gid to be the same as the device Uid/Gid on the host when deviceOwnershipFromSecurityContext is enabled": { {
desc: "expect root container's Devices Uid/Gid to be the same as the device Uid/Gid on the host when deviceOwnershipFromSecurityContext is enabled",
uid: &runtime.Int64Value{Value: 0}, uid: &runtime.Int64Value{Value: 0},
gid: &runtime.Int64Value{Value: 0}, gid: &runtime.Int64Value{Value: 0},
deviceOwnershipFromSecurityContext: true, deviceOwnershipFromSecurityContext: true,
@ -1452,7 +1565,8 @@ func TestNonRootUserAndDevices(t *testing.T) {
expectedDeviceGID: *testDevice.GID, expectedDeviceGID: *testDevice.GID,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c.config.DeviceOwnershipFromSecurityContext = test.deviceOwnershipFromSecurityContext c.config.DeviceOwnershipFromSecurityContext = test.deviceOwnershipFromSecurityContext
containerConfig.Linux.SecurityContext.RunAsUser = test.uid containerConfig.Linux.SecurityContext.RunAsUser = test.uid
containerConfig.Linux.SecurityContext.RunAsGroup = test.gid containerConfig.Linux.SecurityContext.RunAsGroup = test.gid
@ -1480,42 +1594,48 @@ func TestPrivilegedDevices(t *testing.T) {
testContainerName := "container-name" testContainerName := "container-name"
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
privileged bool privileged bool
privilegedWithoutHostDevices bool privilegedWithoutHostDevices bool
privilegedWithoutHostDevicesAllDevicesAllowed bool privilegedWithoutHostDevicesAllDevicesAllowed bool
expectHostDevices bool expectHostDevices bool
expectAllDevicesAllowed bool expectAllDevicesAllowed bool
}{ }{
"expect no host devices when privileged is false": { {
desc: "expect no host devices when privileged is false",
privileged: false, privileged: false,
privilegedWithoutHostDevices: false, privilegedWithoutHostDevices: false,
privilegedWithoutHostDevicesAllDevicesAllowed: false, privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: false, expectHostDevices: false,
expectAllDevicesAllowed: false, expectAllDevicesAllowed: false,
}, },
"expect no host devices when privileged is false and privilegedWithoutHostDevices is true": { {
desc: "expect no host devices when privileged is false and privilegedWithoutHostDevices is true",
privileged: false, privileged: false,
privilegedWithoutHostDevices: true, privilegedWithoutHostDevices: true,
privilegedWithoutHostDevicesAllDevicesAllowed: false, privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: false, expectHostDevices: false,
expectAllDevicesAllowed: false, expectAllDevicesAllowed: false,
}, },
"expect host devices and all device allowlist when privileged is true": { {
desc: "expect host devices and all device allowlist when privileged is true",
privileged: true, privileged: true,
privilegedWithoutHostDevices: false, privilegedWithoutHostDevices: false,
privilegedWithoutHostDevicesAllDevicesAllowed: false, privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: true, expectHostDevices: true,
expectAllDevicesAllowed: true, expectAllDevicesAllowed: true,
}, },
"expect no host devices when privileged is true and privilegedWithoutHostDevices is true": { {
desc: "expect no host devices when privileged is true and privilegedWithoutHostDevices is true",
privileged: true, privileged: true,
privilegedWithoutHostDevices: true, privilegedWithoutHostDevices: true,
privilegedWithoutHostDevicesAllDevicesAllowed: false, privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: false, expectHostDevices: false,
expectAllDevicesAllowed: false, expectAllDevicesAllowed: false,
}, },
"expect host devices and all devices allowlist when privileged is true and privilegedWithoutHostDevices is true and privilegedWithoutHostDevicesAllDevicesAllowed is true": { {
desc: "expect host devices and all devices allowlist when privileged is true and privilegedWithoutHostDevices is true and privilegedWithoutHostDevicesAllDevicesAllowed is true",
privileged: true, privileged: true,
privilegedWithoutHostDevices: true, privilegedWithoutHostDevices: true,
privilegedWithoutHostDevicesAllDevicesAllowed: true, privilegedWithoutHostDevicesAllDevicesAllowed: true,
@ -1523,7 +1643,8 @@ func TestPrivilegedDevices(t *testing.T) {
expectAllDevicesAllowed: true, expectAllDevicesAllowed: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
containerConfig.Linux.SecurityContext.Privileged = test.privileged containerConfig.Linux.SecurityContext.Privileged = test.privileged
sandboxConfig.Linux.SecurityContext.Privileged = test.privileged sandboxConfig.Linux.SecurityContext.Privileged = test.privileged

View File

@ -88,18 +88,21 @@ func TestPodAnnotationPassthroughContainerSpec(t *testing.T) {
testContainerName := "container-name" testContainerName := "container-name"
testPid := uint32(1234) testPid := uint32(1234)
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
podAnnotations []string podAnnotations []string
configChange func(*runtime.PodSandboxConfig) configChange func(*runtime.PodSandboxConfig)
specCheck func(*testing.T, *runtimespec.Spec) specCheck func(*testing.T, *runtimespec.Spec)
}{ }{
"a passthrough annotation should be passed as an OCI annotation": { {
desc: "a passthrough annotation should be passed as an OCI annotation",
podAnnotations: []string{"c"}, podAnnotations: []string{"c"},
specCheck: func(t *testing.T, spec *runtimespec.Spec) { specCheck: func(t *testing.T, spec *runtimespec.Spec) {
assert.Equal(t, spec.Annotations["c"], "d") assert.Equal(t, spec.Annotations["c"], "d")
}, },
}, },
"a non-passthrough annotation should not be passed as an OCI annotation": { {
desc: "a non-passthrough annotation should not be passed as an OCI annotation",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Annotations["d"] = "e" c.Annotations["d"] = "e"
}, },
@ -110,7 +113,8 @@ func TestPodAnnotationPassthroughContainerSpec(t *testing.T) {
assert.False(t, ok) assert.False(t, ok)
}, },
}, },
"passthrough annotations should support wildcard match": { {
desc: "passthrough annotations should support wildcard match",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Annotations["t.f"] = "j" c.Annotations["t.f"] = "j"
c.Annotations["z.g"] = "o" c.Annotations["z.g"] = "o"
@ -131,7 +135,8 @@ func TestPodAnnotationPassthroughContainerSpec(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
if test.configChange != nil { if test.configChange != nil {
@ -154,7 +159,8 @@ func TestPodAnnotationPassthroughContainerSpec(t *testing.T) {
} }
func TestContainerSpecCommand(t *testing.T) { func TestContainerSpecCommand(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
criEntrypoint []string criEntrypoint []string
criArgs []string criArgs []string
imageEntrypoint []string imageEntrypoint []string
@ -162,42 +168,49 @@ func TestContainerSpecCommand(t *testing.T) {
expected []string expected []string
expectErr bool expectErr bool
}{ }{
"should use cri entrypoint if it's specified": { {
desc: "should use cri entrypoint if it's specified",
criEntrypoint: []string{"a", "b"}, criEntrypoint: []string{"a", "b"},
imageEntrypoint: []string{"c", "d"}, imageEntrypoint: []string{"c", "d"},
imageArgs: []string{"e", "f"}, imageArgs: []string{"e", "f"},
expected: []string{"a", "b"}, expected: []string{"a", "b"},
}, },
"should use cri entrypoint if it's specified even if it's empty": { {
desc: "should use cri entrypoint if it's specified even if it's empty",
criEntrypoint: []string{}, criEntrypoint: []string{},
criArgs: []string{"a", "b"}, criArgs: []string{"a", "b"},
imageEntrypoint: []string{"c", "d"}, imageEntrypoint: []string{"c", "d"},
imageArgs: []string{"e", "f"}, imageArgs: []string{"e", "f"},
expected: []string{"a", "b"}, expected: []string{"a", "b"},
}, },
"should use cri entrypoint and args if they are specified": { {
desc: "should use cri entrypoint and args if they are specified",
criEntrypoint: []string{"a", "b"}, criEntrypoint: []string{"a", "b"},
criArgs: []string{"c", "d"}, criArgs: []string{"c", "d"},
imageEntrypoint: []string{"e", "f"}, imageEntrypoint: []string{"e", "f"},
imageArgs: []string{"g", "h"}, imageArgs: []string{"g", "h"},
expected: []string{"a", "b", "c", "d"}, expected: []string{"a", "b", "c", "d"},
}, },
"should use image entrypoint if cri entrypoint is not specified": { {
desc: "should use image entrypoint if cri entrypoint is not specified",
criArgs: []string{"a", "b"}, criArgs: []string{"a", "b"},
imageEntrypoint: []string{"c", "d"}, imageEntrypoint: []string{"c", "d"},
imageArgs: []string{"e", "f"}, imageArgs: []string{"e", "f"},
expected: []string{"c", "d", "a", "b"}, expected: []string{"c", "d", "a", "b"},
}, },
"should use image args if both cri entrypoint and args are not specified": { {
desc: "should use image args if both cri entrypoint and args are not specified",
imageEntrypoint: []string{"c", "d"}, imageEntrypoint: []string{"c", "d"},
imageArgs: []string{"e", "f"}, imageArgs: []string{"e", "f"},
expected: []string{"c", "d", "e", "f"}, expected: []string{"c", "d", "e", "f"},
}, },
"should return error if both entrypoint and args are empty": { {
desc: "should return error if both entrypoint and args are empty",
expectErr: true, expectErr: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
config, _, imageConfig, _ := getCreateContainerTestData() config, _, imageConfig, _ := getCreateContainerTestData()
config.Command = test.criEntrypoint config.Command = test.criEntrypoint
config.Args = test.criArgs config.Args = test.criArgs
@ -211,19 +224,21 @@ func TestContainerSpecCommand(t *testing.T) {
return return
} }
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, test.expected, spec.Process.Args, desc) assert.Equal(t, test.expected, spec.Process.Args, test.desc)
}) })
} }
} }
func TestVolumeMounts(t *testing.T) { func TestVolumeMounts(t *testing.T) {
testContainerRootDir := "test-container-root" testContainerRootDir := "test-container-root"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
criMounts []*runtime.Mount criMounts []*runtime.Mount
imageVolumes map[string]struct{} imageVolumes map[string]struct{}
expectedMountDest []string expectedMountDest []string
}{ }{
"should setup rw mount for image volumes": { {
desc: "should setup rw mount for image volumes",
imageVolumes: map[string]struct{}{ imageVolumes: map[string]struct{}{
"/test-volume-1": {}, "/test-volume-1": {},
"/test-volume-2": {}, "/test-volume-2": {},
@ -233,7 +248,8 @@ func TestVolumeMounts(t *testing.T) {
"/test-volume-2", "/test-volume-2",
}, },
}, },
"should skip image volumes if already mounted by CRI": { {
desc: "should skip image volumes if already mounted by CRI",
criMounts: []*runtime.Mount{ criMounts: []*runtime.Mount{
{ {
ContainerPath: "/test-volume-1", ContainerPath: "/test-volume-1",
@ -248,7 +264,8 @@ func TestVolumeMounts(t *testing.T) {
"/test-volume-2", "/test-volume-2",
}, },
}, },
"should compare and return cleanpath": { {
desc: "should compare and return cleanpath",
criMounts: []*runtime.Mount{ criMounts: []*runtime.Mount{
{ {
ContainerPath: "/test-volume-1", ContainerPath: "/test-volume-1",
@ -264,7 +281,8 @@ func TestVolumeMounts(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
config := &imagespec.ImageConfig{ config := &imagespec.ImageConfig{
Volumes: test.imageVolumes, Volumes: test.imageVolumes,
} }
@ -301,14 +319,16 @@ func TestContainerAnnotationPassthroughContainerSpec(t *testing.T) {
testContainerName := "container-name" testContainerName := "container-name"
testPid := uint32(1234) testPid := uint32(1234)
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
podAnnotations []string podAnnotations []string
containerAnnotations []string containerAnnotations []string
podConfigChange func(*runtime.PodSandboxConfig) podConfigChange func(*runtime.PodSandboxConfig)
configChange func(*runtime.ContainerConfig) configChange func(*runtime.ContainerConfig)
specCheck func(*testing.T, *runtimespec.Spec) specCheck func(*testing.T, *runtimespec.Spec)
}{ }{
"passthrough annotations from pod and container should be passed as an OCI annotation": { {
desc: "passthrough annotations from pod and container should be passed as an OCI annotation",
podConfigChange: func(p *runtime.PodSandboxConfig) { podConfigChange: func(p *runtime.PodSandboxConfig) {
p.Annotations["pod.annotation.1"] = "1" p.Annotations["pod.annotation.1"] = "1"
p.Annotations["pod.annotation.2"] = "2" p.Annotations["pod.annotation.2"] = "2"
@ -334,7 +354,8 @@ func TestContainerAnnotationPassthroughContainerSpec(t *testing.T) {
assert.False(t, ok) assert.False(t, ok)
}, },
}, },
"passthrough annotations from pod and container should support wildcard": { {
desc: "passthrough annotations from pod and container should support wildcard",
podConfigChange: func(p *runtime.PodSandboxConfig) { podConfigChange: func(p *runtime.PodSandboxConfig) {
p.Annotations["pod.annotation.1"] = "1" p.Annotations["pod.annotation.1"] = "1"
p.Annotations["pod.annotation.2"] = "2" p.Annotations["pod.annotation.2"] = "2"
@ -356,7 +377,8 @@ func TestContainerAnnotationPassthroughContainerSpec(t *testing.T) {
assert.Equal(t, "3", spec.Annotations["pod.annotation.3"]) assert.Equal(t, "3", spec.Annotations["pod.annotation.3"])
}, },
}, },
"annotations should not pass through if no passthrough annotations are configured": { {
desc: "annotations should not pass through if no passthrough annotations are configured",
podConfigChange: func(p *runtime.PodSandboxConfig) { podConfigChange: func(p *runtime.PodSandboxConfig) {
p.Annotations["pod.annotation.1"] = "1" p.Annotations["pod.annotation.1"] = "1"
p.Annotations["pod.annotation.2"] = "2" p.Annotations["pod.annotation.2"] = "2"
@ -385,7 +407,8 @@ func TestContainerAnnotationPassthroughContainerSpec(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
if test.configChange != nil { if test.configChange != nil {
@ -441,13 +464,15 @@ func TestBaseRuntimeSpec(t *testing.T) {
func TestLinuxContainerMounts(t *testing.T) { func TestLinuxContainerMounts(t *testing.T) {
const testSandboxID = "test-id" const testSandboxID = "test-id"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
statFn func(string) (os.FileInfo, error) statFn func(string) (os.FileInfo, error)
criMounts []*runtime.Mount criMounts []*runtime.Mount
securityContext *runtime.LinuxContainerSecurityContext securityContext *runtime.LinuxContainerSecurityContext
expectedMounts []*runtime.Mount expectedMounts []*runtime.Mount
}{ }{
"should setup ro mount when rootfs is read-only": { {
desc: "should setup ro mount when rootfs is read-only",
securityContext: &runtime.LinuxContainerSecurityContext{ securityContext: &runtime.LinuxContainerSecurityContext{
ReadonlyRootfs: true, ReadonlyRootfs: true,
}, },
@ -478,7 +503,8 @@ func TestLinuxContainerMounts(t *testing.T) {
}, },
}, },
}, },
"should setup rw mount when rootfs is read-write": { {
desc: "should setup rw mount when rootfs is read-write",
securityContext: &runtime.LinuxContainerSecurityContext{}, securityContext: &runtime.LinuxContainerSecurityContext{},
expectedMounts: []*runtime.Mount{ expectedMounts: []*runtime.Mount{
{ {
@ -507,7 +533,8 @@ func TestLinuxContainerMounts(t *testing.T) {
}, },
}, },
}, },
"should use host /dev/shm when host ipc is set": { {
desc: "should use host /dev/shm when host ipc is set",
securityContext: &runtime.LinuxContainerSecurityContext{ securityContext: &runtime.LinuxContainerSecurityContext{
NamespaceOptions: &runtime.NamespaceOption{Ipc: runtime.NamespaceMode_NODE}, NamespaceOptions: &runtime.NamespaceOption{Ipc: runtime.NamespaceMode_NODE},
}, },
@ -537,7 +564,8 @@ func TestLinuxContainerMounts(t *testing.T) {
}, },
}, },
}, },
"should skip container mounts if already mounted by CRI": { {
desc: "should skip container mounts if already mounted by CRI",
criMounts: []*runtime.Mount{ criMounts: []*runtime.Mount{
{ {
ContainerPath: "/etc/hostname", ContainerPath: "/etc/hostname",
@ -559,7 +587,8 @@ func TestLinuxContainerMounts(t *testing.T) {
securityContext: &runtime.LinuxContainerSecurityContext{}, securityContext: &runtime.LinuxContainerSecurityContext{},
expectedMounts: nil, expectedMounts: nil,
}, },
"should skip hostname mount if the old sandbox doesn't have hostname file": { {
desc: "should skip hostname mount if the old sandbox doesn't have hostname file",
statFn: func(path string) (os.FileInfo, error) { statFn: func(path string) (os.FileInfo, error) {
assert.Equal(t, filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"), path) assert.Equal(t, filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"), path)
return nil, errors.New("random error") return nil, errors.New("random error")
@ -587,7 +616,8 @@ func TestLinuxContainerMounts(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
config := &runtime.ContainerConfig{ config := &runtime.ContainerConfig{
Metadata: &runtime.ContainerMetadata{ Metadata: &runtime.ContainerMetadata{
Name: "test-name", Name: "test-name",
@ -601,7 +631,7 @@ func TestLinuxContainerMounts(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
c.os.(*ostesting.FakeOS).StatFn = test.statFn c.os.(*ostesting.FakeOS).StatFn = test.statFn
mounts := c.linuxContainerMounts(testSandboxID, config) mounts := c.linuxContainerMounts(testSandboxID, config)
assert.Equal(t, test.expectedMounts, mounts, desc) assert.Equal(t, test.expectedMounts, mounts, test.desc)
}) })
} }
} }

View File

@ -208,33 +208,39 @@ func TestHostProcessRequirements(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
ociRuntime := config.Runtime{} ociRuntime := config.Runtime{}
c := newTestCRIService() c := newTestCRIService()
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
containerHostProcess bool containerHostProcess bool
sandboxHostProcess bool sandboxHostProcess bool
expectError bool expectError bool
}{ }{
"hostprocess container in non-hostprocess sandbox should fail": { {
desc: "hostprocess container in non-hostprocess sandbox should fail",
containerHostProcess: true, containerHostProcess: true,
sandboxHostProcess: false, sandboxHostProcess: false,
expectError: true, expectError: true,
}, },
"hostprocess container in hostprocess sandbox should be fine": { {
desc: "hostprocess container in hostprocess sandbox should be fine",
containerHostProcess: true, containerHostProcess: true,
sandboxHostProcess: true, sandboxHostProcess: true,
expectError: false, expectError: false,
}, },
"non-hostprocess container in hostprocess sandbox should fail": { {
desc: "non-hostprocess container in hostprocess sandbox should fail",
containerHostProcess: false, containerHostProcess: false,
sandboxHostProcess: true, sandboxHostProcess: true,
expectError: true, expectError: true,
}, },
"non-hostprocess container in non-hostprocess sandbox should be fine": { {
desc: "non-hostprocess container in non-hostprocess sandbox should be fine",
containerHostProcess: false, containerHostProcess: false,
sandboxHostProcess: false, sandboxHostProcess: false,
expectError: false, expectError: false,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
containerConfig.Windows.SecurityContext.HostProcess = test.containerHostProcess containerConfig.Windows.SecurityContext.HostProcess = test.containerHostProcess
sandboxConfig.Windows.SecurityContext = &runtime.WindowsSandboxSecurityContext{ sandboxConfig.Windows.SecurityContext = &runtime.WindowsSandboxSecurityContext{
HostProcess: test.sandboxHostProcess, HostProcess: test.sandboxHostProcess,

View File

@ -101,18 +101,22 @@ func TestFilterContainers(t *testing.T) {
Labels: map[string]string{"c": "d"}, Labels: map[string]string{"c": "d"},
}, },
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
filter *runtime.ContainerFilter filter *runtime.ContainerFilter
expect []*runtime.Container expect []*runtime.Container
}{ }{
"no filter": { {
desc: "no filter",
expect: testContainers, expect: testContainers,
}, },
"id filter": { {
desc: "id filter",
filter: &runtime.ContainerFilter{Id: "2"}, filter: &runtime.ContainerFilter{Id: "2"},
expect: []*runtime.Container{testContainers[1]}, expect: []*runtime.Container{testContainers[1]},
}, },
"state filter": { {
desc: "state filter",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
State: &runtime.ContainerStateValue{ State: &runtime.ContainerStateValue{
State: runtime.ContainerState_CONTAINER_EXITED, State: runtime.ContainerState_CONTAINER_EXITED,
@ -120,17 +124,20 @@ func TestFilterContainers(t *testing.T) {
}, },
expect: []*runtime.Container{testContainers[1]}, expect: []*runtime.Container{testContainers[1]},
}, },
"label filter": { {
desc: "label filter",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
LabelSelector: map[string]string{"a": "b"}, LabelSelector: map[string]string{"a": "b"},
}, },
expect: []*runtime.Container{testContainers[1]}, expect: []*runtime.Container{testContainers[1]},
}, },
"sandbox id filter": { {
desc: "sandbox id filter",
filter: &runtime.ContainerFilter{PodSandboxId: "s-2"}, filter: &runtime.ContainerFilter{PodSandboxId: "s-2"},
expect: []*runtime.Container{testContainers[1], testContainers[2]}, expect: []*runtime.Container{testContainers[1], testContainers[2]},
}, },
"mixed filter not matched": { {
desc: "mixed filter not matched",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
Id: "1", Id: "1",
PodSandboxId: "s-2", PodSandboxId: "s-2",
@ -138,7 +145,8 @@ func TestFilterContainers(t *testing.T) {
}, },
expect: []*runtime.Container{}, expect: []*runtime.Container{},
}, },
"mixed filter matched": { {
desc: "mixed filter matched",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
PodSandboxId: "s-2", PodSandboxId: "s-2",
State: &runtime.ContainerStateValue{ State: &runtime.ContainerStateValue{
@ -149,9 +157,10 @@ func TestFilterContainers(t *testing.T) {
expect: []*runtime.Container{testContainers[2]}, expect: []*runtime.Container{testContainers[2]},
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
filtered := c.filterCRIContainers(testContainers, test.filter) filtered := c.filterCRIContainers(testContainers, test.filter)
assert.Equal(t, test.expect, filtered, desc) assert.Equal(t, test.expect, filtered, test.desc)
}) })
} }
} }
@ -287,46 +296,54 @@ func TestListContainers(t *testing.T) {
assert.NoError(t, c.containerStore.Add(container)) assert.NoError(t, c.containerStore.Add(container))
} }
for testdesc, testdata := range map[string]struct { for _, testdata := range []struct {
desc string
filter *runtime.ContainerFilter filter *runtime.ContainerFilter
expect []*runtime.Container expect []*runtime.Container
}{ }{
"test without filter": { {
desc: "test without filter",
filter: &runtime.ContainerFilter{}, filter: &runtime.ContainerFilter{},
expect: expectedContainers, expect: expectedContainers,
}, },
"test filter by sandboxid": { {
desc: "test filter by sandboxid",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
PodSandboxId: "s-1abcdef1234", PodSandboxId: "s-1abcdef1234",
}, },
expect: expectedContainers[:3], expect: expectedContainers[:3],
}, },
"test filter by truncated sandboxid": { {
desc: "test filter by truncated sandboxid",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
PodSandboxId: "s-1", PodSandboxId: "s-1",
}, },
expect: expectedContainers[:3], expect: expectedContainers[:3],
}, },
"test filter by containerid": { {
desc: "test filter by containerid",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
Id: "c-1container", Id: "c-1container",
}, },
expect: expectedContainers[:1], expect: expectedContainers[:1],
}, },
"test filter by truncated containerid": { {
desc: "test filter by truncated containerid",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
Id: "c-1", Id: "c-1",
}, },
expect: expectedContainers[:1], expect: expectedContainers[:1],
}, },
"test filter by containerid and sandboxid": { {
desc: "test filter by containerid and sandboxid",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
Id: "c-1container", Id: "c-1container",
PodSandboxId: "s-1abcdef1234", PodSandboxId: "s-1abcdef1234",
}, },
expect: expectedContainers[:1], expect: expectedContainers[:1],
}, },
"test filter by truncated containerid and truncated sandboxid": { {
desc: "test filter by truncated containerid and truncated sandboxid",
filter: &runtime.ContainerFilter{ filter: &runtime.ContainerFilter{
Id: "c-1", Id: "c-1",
PodSandboxId: "s-1", PodSandboxId: "s-1",
@ -334,7 +351,8 @@ func TestListContainers(t *testing.T) {
expect: expectedContainers[:1], expect: expectedContainers[:1],
}, },
} { } {
t.Run(testdesc, func(t *testing.T) { testdata := testdata
t.Run(testdata.desc, func(t *testing.T) {
resp, err := c.ListContainers(context.Background(), &runtime.ListContainersRequest{Filter: testdata.filter}) resp, err := c.ListContainers(context.Background(), &runtime.ListContainersRequest{Filter: testdata.filter})
assert.NoError(t, err) assert.NoError(t, err)
require.NotNil(t, resp) require.NotNil(t, resp)

View File

@ -29,25 +29,29 @@ import (
// state correctly. // state correctly.
func TestSetContainerRemoving(t *testing.T) { func TestSetContainerRemoving(t *testing.T) {
testID := "test-id" testID := "test-id"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
status containerstore.Status status containerstore.Status
expectErr bool expectErr bool
}{ }{
"should return error when container is in running state": { {
desc: "should return error when container is in running state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
}, },
expectErr: true, expectErr: true,
}, },
"should return error when container is in starting state": { {
desc: "should return error when container is in starting state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
Starting: true, Starting: true,
}, },
expectErr: true, expectErr: true,
}, },
"should return error when container is in removing state": { {
desc: "should return error when container is in removing state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
@ -56,7 +60,8 @@ func TestSetContainerRemoving(t *testing.T) {
}, },
expectErr: true, expectErr: true,
}, },
"should not return error when container is not running and removing": { {
desc: "should not return error when container is not running and removing",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
@ -65,7 +70,8 @@ func TestSetContainerRemoving(t *testing.T) {
expectErr: false, expectErr: false,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
container, err := containerstore.NewContainer( container, err := containerstore.NewContainer(
containerstore.Metadata{ID: testID}, containerstore.Metadata{ID: testID},
containerstore.WithFakeStatus(test.status), containerstore.WithFakeStatus(test.status),

View File

@ -29,25 +29,28 @@ import (
// state correctly. // state correctly.
func TestSetContainerStarting(t *testing.T) { func TestSetContainerStarting(t *testing.T) {
testID := "test-id" testID := "test-id"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
status containerstore.Status status containerstore.Status
expectErr bool expectErr bool
}{ }{
{
"should not return error when container is in created state": { desc: "should not return error when container is in created state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
}, },
expectErr: false, expectErr: false,
}, },
"should return error when container is in running state": { {
desc: "should return error when container is in running state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
}, },
expectErr: true, expectErr: true,
}, },
"should return error when container is in exited state": { {
desc: "should return error when container is in exited state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
@ -55,7 +58,8 @@ func TestSetContainerStarting(t *testing.T) {
}, },
expectErr: true, expectErr: true,
}, },
"should return error when container is in unknown state": { {
desc: "should return error when container is in unknown state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: 0, CreatedAt: 0,
StartedAt: 0, StartedAt: 0,
@ -63,14 +67,16 @@ func TestSetContainerStarting(t *testing.T) {
}, },
expectErr: true, expectErr: true,
}, },
"should return error when container is in starting state": { {
desc: "should return error when container is in starting state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
Starting: true, Starting: true,
}, },
expectErr: true, expectErr: true,
}, },
"should return error when container is in removing state": { {
desc: "should return error when container is in removing state",
status: containerstore.Status{ status: containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
Removing: true, Removing: true,
@ -78,7 +84,8 @@ func TestSetContainerStarting(t *testing.T) {
expectErr: true, expectErr: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
container, err := containerstore.NewContainer( container, err := containerstore.NewContainer(
containerstore.Metadata{ID: testID}, containerstore.Metadata{ID: testID},
containerstore.WithFakeStatus(test.status), containerstore.WithFakeStatus(test.status),

View File

@ -28,22 +28,26 @@ import (
) )
func TestGetWorkingSet(t *testing.T) { func TestGetWorkingSet(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
memory *v1.MemoryStat memory *v1.MemoryStat
expected uint64 expected uint64
}{ }{
"nil memory usage": { {
desc: "nil memory usage",
memory: &v1.MemoryStat{}, memory: &v1.MemoryStat{},
expected: 0, expected: 0,
}, },
"memory usage higher than inactive_total_file": { {
desc: "memory usage higher than inactive_total_file",
memory: &v1.MemoryStat{ memory: &v1.MemoryStat{
TotalInactiveFile: 1000, TotalInactiveFile: 1000,
Usage: &v1.MemoryEntry{Usage: 2000}, Usage: &v1.MemoryEntry{Usage: 2000},
}, },
expected: 1000, expected: 1000,
}, },
"memory usage lower than inactive_total_file": { {
desc: "memory usage lower than inactive_total_file",
memory: &v1.MemoryStat{ memory: &v1.MemoryStat{
TotalInactiveFile: 2000, TotalInactiveFile: 2000,
Usage: &v1.MemoryEntry{Usage: 1000}, Usage: &v1.MemoryEntry{Usage: 1000},
@ -51,7 +55,8 @@ func TestGetWorkingSet(t *testing.T) {
expected: 0, expected: 0,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
got := getWorkingSet(test.memory) got := getWorkingSet(test.memory)
assert.Equal(t, test.expected, got) assert.Equal(t, test.expected, got)
}) })
@ -59,22 +64,26 @@ func TestGetWorkingSet(t *testing.T) {
} }
func TestGetWorkingSetV2(t *testing.T) { func TestGetWorkingSetV2(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
memory *v2.MemoryStat memory *v2.MemoryStat
expected uint64 expected uint64
}{ }{
"nil memory usage": { {
desc: "nil memory usage",
memory: &v2.MemoryStat{}, memory: &v2.MemoryStat{},
expected: 0, expected: 0,
}, },
"memory usage higher than inactive_total_file": { {
desc: "memory usage higher than inactive_total_file",
memory: &v2.MemoryStat{ memory: &v2.MemoryStat{
InactiveFile: 1000, InactiveFile: 1000,
Usage: 2000, Usage: 2000,
}, },
expected: 1000, expected: 1000,
}, },
"memory usage lower than inactive_total_file": { {
desc: "memory usage lower than inactive_total_file",
memory: &v2.MemoryStat{ memory: &v2.MemoryStat{
InactiveFile: 2000, InactiveFile: 2000,
Usage: 1000, Usage: 1000,
@ -82,7 +91,8 @@ func TestGetWorkingSetV2(t *testing.T) {
expected: 0, expected: 0,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
got := getWorkingSetV2(test.memory) got := getWorkingSetV2(test.memory)
assert.Equal(t, test.expected, got) assert.Equal(t, test.expected, got)
}) })
@ -90,13 +100,14 @@ func TestGetWorkingSetV2(t *testing.T) {
} }
func TestGetAvailableBytes(t *testing.T) { func TestGetAvailableBytes(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
memory *v1.MemoryStat memory *v1.MemoryStat
workingSetBytes uint64 workingSetBytes uint64
expected uint64 expected uint64
}{ }{
{
"no limit": { desc: "no limit",
memory: &v1.MemoryStat{ memory: &v1.MemoryStat{
Usage: &v1.MemoryEntry{ Usage: &v1.MemoryEntry{
Limit: math.MaxUint64, // no limit Limit: math.MaxUint64, // no limit
@ -106,7 +117,8 @@ func TestGetAvailableBytes(t *testing.T) {
workingSetBytes: 500, workingSetBytes: 500,
expected: 0, expected: 0,
}, },
"with limit": { {
desc: "with limit",
memory: &v1.MemoryStat{ memory: &v1.MemoryStat{
Usage: &v1.MemoryEntry{ Usage: &v1.MemoryEntry{
Limit: 5000, Limit: 5000,
@ -117,7 +129,8 @@ func TestGetAvailableBytes(t *testing.T) {
expected: 5000 - 500, expected: 5000 - 500,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
got := getAvailableBytes(test.memory, test.workingSetBytes) got := getAvailableBytes(test.memory, test.workingSetBytes)
assert.Equal(t, test.expected, got) assert.Equal(t, test.expected, got)
}) })
@ -125,13 +138,14 @@ func TestGetAvailableBytes(t *testing.T) {
} }
func TestGetAvailableBytesV2(t *testing.T) { func TestGetAvailableBytesV2(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
memory *v2.MemoryStat memory *v2.MemoryStat
workingSetBytes uint64 workingSetBytes uint64
expected uint64 expected uint64
}{ }{
{
"no limit": { desc: "no limit",
memory: &v2.MemoryStat{ memory: &v2.MemoryStat{
UsageLimit: math.MaxUint64, // no limit UsageLimit: math.MaxUint64, // no limit
Usage: 1000, Usage: 1000,
@ -139,7 +153,8 @@ func TestGetAvailableBytesV2(t *testing.T) {
workingSetBytes: 500, workingSetBytes: 500,
expected: 0, expected: 0,
}, },
"with limit": { {
desc: "with limit",
memory: &v2.MemoryStat{ memory: &v2.MemoryStat{
UsageLimit: 5000, UsageLimit: 5000,
Usage: 1000, Usage: 1000,
@ -148,7 +163,8 @@ func TestGetAvailableBytesV2(t *testing.T) {
expected: 5000 - 500, expected: 5000 - 500,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
got := getAvailableBytesV2(test.memory, test.workingSetBytes) got := getAvailableBytesV2(test.memory, test.workingSetBytes)
assert.Equal(t, test.expected, got) assert.Equal(t, test.expected, got)
}) })
@ -159,11 +175,13 @@ func TestContainerMetricsMemory(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
timestamp := time.Now() timestamp := time.Now()
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
metrics interface{} metrics interface{}
expected *runtime.MemoryUsage expected *runtime.MemoryUsage
}{ }{
"v1 metrics - no memory limit": { {
desc: "v1 metrics - no memory limit",
metrics: &v1.Metrics{ metrics: &v1.Metrics{
Memory: &v1.MemoryStat{ Memory: &v1.MemoryStat{
Usage: &v1.MemoryEntry{ Usage: &v1.MemoryEntry{
@ -186,7 +204,8 @@ func TestContainerMetricsMemory(t *testing.T) {
MajorPageFaults: &runtime.UInt64Value{Value: 12}, MajorPageFaults: &runtime.UInt64Value{Value: 12},
}, },
}, },
"v1 metrics - memory limit": { {
desc: "v1 metrics - memory limit",
metrics: &v1.Metrics{ metrics: &v1.Metrics{
Memory: &v1.MemoryStat{ Memory: &v1.MemoryStat{
Usage: &v1.MemoryEntry{ Usage: &v1.MemoryEntry{
@ -209,7 +228,8 @@ func TestContainerMetricsMemory(t *testing.T) {
MajorPageFaults: &runtime.UInt64Value{Value: 12}, MajorPageFaults: &runtime.UInt64Value{Value: 12},
}, },
}, },
"v2 metrics - memory limit": { {
desc: "v2 metrics - memory limit",
metrics: &v2.Metrics{ metrics: &v2.Metrics{
Memory: &v2.MemoryStat{ Memory: &v2.MemoryStat{
Usage: 1000, Usage: 1000,
@ -229,7 +249,8 @@ func TestContainerMetricsMemory(t *testing.T) {
MajorPageFaults: &runtime.UInt64Value{Value: 12}, MajorPageFaults: &runtime.UInt64Value{Value: 12},
}, },
}, },
"v2 metrics - no memory limit": { {
desc: "v2 metrics - no memory limit",
metrics: &v2.Metrics{ metrics: &v2.Metrics{
Memory: &v2.MemoryStat{ Memory: &v2.MemoryStat{
Usage: 1000, Usage: 1000,
@ -250,7 +271,8 @@ func TestContainerMetricsMemory(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
got, err := c.memoryContainerStats("ID", test.metrics, timestamp) got, err := c.memoryContainerStats("ID", test.metrics, timestamp)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, test.expected, got) assert.Equal(t, test.expected, got)

View File

@ -30,20 +30,23 @@ func TestContainerMetricsCPUNanoCoreUsage(t *testing.T) {
secondAfterTimeStamp := timestamp.Add(time.Second) secondAfterTimeStamp := timestamp.Add(time.Second)
ID := "ID" ID := "ID"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
firstCPUValue uint64 firstCPUValue uint64
secondCPUValue uint64 secondCPUValue uint64
expectedNanoCoreUsageFirst uint64 expectedNanoCoreUsageFirst uint64
expectedNanoCoreUsageSecond uint64 expectedNanoCoreUsageSecond uint64
}{ }{
"metrics": { {
desc: "metrics",
firstCPUValue: 50, firstCPUValue: 50,
secondCPUValue: 500, secondCPUValue: 500,
expectedNanoCoreUsageFirst: 0, expectedNanoCoreUsageFirst: 0,
expectedNanoCoreUsageSecond: 450, expectedNanoCoreUsageSecond: 450,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
container, err := containerstore.NewContainer( container, err := containerstore.NewContainer(
containerstore.Metadata{ID: ID}, containerstore.Metadata{ID: ID},
) )

View File

@ -88,7 +88,8 @@ func getContainerStatusTestData() (*containerstore.Metadata, *containerstore.Sta
} }
func TestToCRIContainerStatus(t *testing.T) { func TestToCRIContainerStatus(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
startedAt int64 startedAt int64
finishedAt int64 finishedAt int64
exitCode int32 exitCode int32
@ -97,14 +98,17 @@ func TestToCRIContainerStatus(t *testing.T) {
expectedState runtime.ContainerState expectedState runtime.ContainerState
expectedReason string expectedReason string
}{ }{
"container created": { {
desc: "container created",
expectedState: runtime.ContainerState_CONTAINER_CREATED, expectedState: runtime.ContainerState_CONTAINER_CREATED,
}, },
"container running": { {
desc: "container running",
startedAt: time.Now().UnixNano(), startedAt: time.Now().UnixNano(),
expectedState: runtime.ContainerState_CONTAINER_RUNNING, expectedState: runtime.ContainerState_CONTAINER_RUNNING,
}, },
"container exited with reason": { {
desc: "container exited with reason",
startedAt: time.Now().UnixNano(), startedAt: time.Now().UnixNano(),
finishedAt: time.Now().UnixNano(), finishedAt: time.Now().UnixNano(),
exitCode: 1, exitCode: 1,
@ -113,7 +117,8 @@ func TestToCRIContainerStatus(t *testing.T) {
expectedState: runtime.ContainerState_CONTAINER_EXITED, expectedState: runtime.ContainerState_CONTAINER_EXITED,
expectedReason: "test-reason", expectedReason: "test-reason",
}, },
"container exited with exit code 0 without reason": { {
desc: "container exited with exit code 0 without reason",
startedAt: time.Now().UnixNano(), startedAt: time.Now().UnixNano(),
finishedAt: time.Now().UnixNano(), finishedAt: time.Now().UnixNano(),
exitCode: 0, exitCode: 0,
@ -121,7 +126,8 @@ func TestToCRIContainerStatus(t *testing.T) {
expectedState: runtime.ContainerState_CONTAINER_EXITED, expectedState: runtime.ContainerState_CONTAINER_EXITED,
expectedReason: completeExitReason, expectedReason: completeExitReason,
}, },
"container exited with non-zero exit code without reason": { {
desc: "container exited with non-zero exit code without reason",
startedAt: time.Now().UnixNano(), startedAt: time.Now().UnixNano(),
finishedAt: time.Now().UnixNano(), finishedAt: time.Now().UnixNano(),
exitCode: 1, exitCode: 1,
@ -130,7 +136,8 @@ func TestToCRIContainerStatus(t *testing.T) {
expectedReason: errorExitReason, expectedReason: errorExitReason,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
metadata, status, _, expected := getContainerStatusTestData() metadata, status, _, expected := getContainerStatusTestData()
// Update status with test case. // Update status with test case.
@ -154,7 +161,7 @@ func TestToCRIContainerStatus(t *testing.T) {
containerStatus := toCRIContainerStatus(container, containerStatus := toCRIContainerStatus(container,
expected.Image, expected.Image,
expected.ImageRef) expected.ImageRef)
assert.Equal(t, expected, containerStatus, desc) assert.Equal(t, expected, containerStatus, test.desc)
}) })
} }
} }
@ -176,7 +183,8 @@ func TestToCRIContainerInfo(t *testing.T) {
} }
func TestContainerStatus(t *testing.T) { func TestContainerStatus(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
exist bool exist bool
imageExist bool imageExist bool
startedAt int64 startedAt int64
@ -185,18 +193,21 @@ func TestContainerStatus(t *testing.T) {
expectedState runtime.ContainerState expectedState runtime.ContainerState
expectErr bool expectErr bool
}{ }{
"container created": { {
desc: "container created",
exist: true, exist: true,
imageExist: true, imageExist: true,
expectedState: runtime.ContainerState_CONTAINER_CREATED, expectedState: runtime.ContainerState_CONTAINER_CREATED,
}, },
"container running": { {
desc: "container running",
exist: true, exist: true,
imageExist: true, imageExist: true,
startedAt: time.Now().UnixNano(), startedAt: time.Now().UnixNano(),
expectedState: runtime.ContainerState_CONTAINER_RUNNING, expectedState: runtime.ContainerState_CONTAINER_RUNNING,
}, },
"container exited": { {
desc: "container exited",
exist: true, exist: true,
imageExist: true, imageExist: true,
startedAt: time.Now().UnixNano(), startedAt: time.Now().UnixNano(),
@ -204,18 +215,21 @@ func TestContainerStatus(t *testing.T) {
reason: "test-reason", reason: "test-reason",
expectedState: runtime.ContainerState_CONTAINER_EXITED, expectedState: runtime.ContainerState_CONTAINER_EXITED,
}, },
"container not exist": { {
desc: "container not exist",
exist: false, exist: false,
imageExist: true, imageExist: true,
expectErr: true, expectErr: true,
}, },
"image not exist": { {
desc: "image not exist",
exist: false, exist: false,
imageExist: false, imageExist: false,
expectErr: true, expectErr: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
metadata, status, image, expected := getContainerStatusTestData() metadata, status, image, expected := getContainerStatusTestData()
// Update status with test case. // Update status with test case.

View File

@ -28,13 +28,15 @@ import (
func TestWaitContainerStop(t *testing.T) { func TestWaitContainerStop(t *testing.T) {
id := "test-id" id := "test-id"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
status *containerstore.Status status *containerstore.Status
cancel bool cancel bool
timeout time.Duration timeout time.Duration
expectErr bool expectErr bool
}{ }{
"should return error if timeout exceeds": { {
desc: "should return error if timeout exceeds",
status: &containerstore.Status{ status: &containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
@ -42,7 +44,8 @@ func TestWaitContainerStop(t *testing.T) {
timeout: 200 * time.Millisecond, timeout: 200 * time.Millisecond,
expectErr: true, expectErr: true,
}, },
"should return error if context is cancelled": { {
desc: "should return error if context is cancelled",
status: &containerstore.Status{ status: &containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
@ -51,7 +54,8 @@ func TestWaitContainerStop(t *testing.T) {
cancel: true, cancel: true,
expectErr: true, expectErr: true,
}, },
"should not return error if container is stopped before timeout": { {
desc: "should not return error if container is stopped before timeout",
status: &containerstore.Status{ status: &containerstore.Status{
CreatedAt: time.Now().UnixNano(), CreatedAt: time.Now().UnixNano(),
StartedAt: time.Now().UnixNano(), StartedAt: time.Now().UnixNano(),
@ -61,7 +65,8 @@ func TestWaitContainerStop(t *testing.T) {
expectErr: false, expectErr: false,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
container, err := containerstore.NewContainer( container, err := containerstore.NewContainer(
containerstore.Metadata{ID: id}, containerstore.Metadata{ID: id},
@ -81,7 +86,7 @@ func TestWaitContainerStop(t *testing.T) {
ctx = timeoutCtx ctx = timeoutCtx
} }
err = c.waitContainerStop(ctx, container) err = c.waitContainerStop(ctx, container)
assert.Equal(t, test.expectErr, err != nil, desc) assert.Equal(t, test.expectErr, err != nil, test.desc)
}) })
} }
} }

View File

@ -38,13 +38,16 @@ func TestUpdateOCILinuxResource(t *testing.T) {
} }
return nil return nil
} }
for desc, test := range map[string]struct {
for _, test := range []struct {
desc string
spec *runtimespec.Spec spec *runtimespec.Spec
request *runtime.UpdateContainerResourcesRequest request *runtime.UpdateContainerResourcesRequest
expected *runtimespec.Spec expected *runtimespec.Spec
expectErr bool expectErr bool
}{ }{
"should be able to update each resource": { {
desc: "should be able to update each resource",
spec: &runtimespec.Spec{ spec: &runtimespec.Spec{
Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj},
Linux: &runtimespec.Linux{ Linux: &runtimespec.Linux{
@ -93,7 +96,8 @@ func TestUpdateOCILinuxResource(t *testing.T) {
}, },
}, },
}, },
"should skip empty fields": { {
desc: "should skip empty fields",
spec: &runtimespec.Spec{ spec: &runtimespec.Spec{
Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj},
Linux: &runtimespec.Linux{ Linux: &runtimespec.Linux{
@ -139,7 +143,8 @@ func TestUpdateOCILinuxResource(t *testing.T) {
}, },
}, },
}, },
"should be able to fill empty fields": { {
desc: "should be able to fill empty fields",
spec: &runtimespec.Spec{ spec: &runtimespec.Spec{
Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj},
Linux: &runtimespec.Linux{ Linux: &runtimespec.Linux{
@ -180,7 +185,8 @@ func TestUpdateOCILinuxResource(t *testing.T) {
}, },
}, },
}, },
"should be able to patch the unified map": { {
desc: "should be able to patch the unified map",
spec: &runtimespec.Spec{ spec: &runtimespec.Spec{
Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj},
Linux: &runtimespec.Linux{ Linux: &runtimespec.Linux{
@ -230,7 +236,8 @@ func TestUpdateOCILinuxResource(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
config := criconfig.Config{ config := criconfig.Config{
PluginConfig: criconfig.PluginConfig{ PluginConfig: criconfig.PluginConfig{
TolerateMissingHugetlbController: true, TolerateMissingHugetlbController: true,

View File

@ -44,36 +44,44 @@ import (
// TestGetUserFromImage tests the logic of getting image uid or user name of image user. // TestGetUserFromImage tests the logic of getting image uid or user name of image user.
func TestGetUserFromImage(t *testing.T) { func TestGetUserFromImage(t *testing.T) {
newI64 := func(i int64) *int64 { return &i } newI64 := func(i int64) *int64 { return &i }
for c, test := range map[string]struct { for _, test := range []struct {
desc string
user string user string
uid *int64 uid *int64
name string name string
}{ }{
"no gid": { {
desc: "no gid",
user: "0", user: "0",
uid: newI64(0), uid: newI64(0),
}, },
"uid/gid": { {
desc: "uid/gid",
user: "0:1", user: "0:1",
uid: newI64(0), uid: newI64(0),
}, },
"empty user": { {
desc: "empty user",
user: "", user: "",
}, },
"multiple separators": { {
desc: "multiple separators",
user: "1:2:3", user: "1:2:3",
uid: newI64(1), uid: newI64(1),
}, },
"root username": { {
desc: "root username",
user: "root:root", user: "root:root",
name: "root", name: "root",
}, },
"username": { {
desc: "username",
user: "test:test", user: "test:test",
name: "test", name: "test",
}, },
} { } {
t.Run(c, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
actualUID, actualName := getUserFromImage(test.user) actualUID, actualName := getUserFromImage(test.user)
assert.Equal(t, test.uid, actualUID) assert.Equal(t, test.uid, actualUID)
assert.Equal(t, test.name, actualName) assert.Equal(t, test.name, actualName)
@ -145,17 +153,20 @@ systemd_cgroup = true
require.NoError(t, err) require.NoError(t, err)
require.Len(t, nonNilOptsConfig.Runtimes, 3) require.Len(t, nonNilOptsConfig.Runtimes, 3)
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
r criconfig.Runtime r criconfig.Runtime
c criconfig.Config c criconfig.Config
expectedOptions interface{} expectedOptions interface{}
}{ }{
"when options is nil, should return nil option for io.containerd.runc.v2": { {
desc: "when options is nil, should return nil option for io.containerd.runc.v2",
r: nilOptsConfig.Runtimes["runcv2"], r: nilOptsConfig.Runtimes["runcv2"],
c: nilOptsConfig, c: nilOptsConfig,
expectedOptions: nil, expectedOptions: nil,
}, },
"when options is not nil, should be able to decode for io.containerd.runc.v2": { {
desc: "when options is not nil, should be able to decode for io.containerd.runc.v2",
r: nonNilOptsConfig.Runtimes["runcv2"], r: nonNilOptsConfig.Runtimes["runcv2"],
c: nonNilOptsConfig, c: nonNilOptsConfig,
expectedOptions: &runcoptions.Options{ expectedOptions: &runcoptions.Options{
@ -165,7 +176,8 @@ systemd_cgroup = true
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
opts, err := generateRuntimeOptions(test.r, test.c) opts, err := generateRuntimeOptions(test.r, test.c)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, test.expectedOptions, opts) assert.Equal(t, test.expectedOptions, opts)
@ -174,18 +186,21 @@ systemd_cgroup = true
} }
func TestEnvDeduplication(t *testing.T) { func TestEnvDeduplication(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
existing []string existing []string
kv [][2]string kv [][2]string
expected []string expected []string
}{ }{
"single env": { {
desc: "single env",
kv: [][2]string{ kv: [][2]string{
{"a", "b"}, {"a", "b"},
}, },
expected: []string{"a=b"}, expected: []string{"a=b"},
}, },
"multiple envs": { {
desc: "multiple envs",
kv: [][2]string{ kv: [][2]string{
{"a", "b"}, {"a", "b"},
{"c", "d"}, {"c", "d"},
@ -197,7 +212,8 @@ func TestEnvDeduplication(t *testing.T) {
"e=f", "e=f",
}, },
}, },
"env override": { {
desc: "env override",
kv: [][2]string{ kv: [][2]string{
{"k1", "v1"}, {"k1", "v1"},
{"k2", "v2"}, {"k2", "v2"},
@ -213,7 +229,8 @@ func TestEnvDeduplication(t *testing.T) {
"k4=v6", "k4=v6",
}, },
}, },
"existing env": { {
desc: "existing env",
existing: []string{ existing: []string{
"k1=v1", "k1=v1",
"k2=v2", "k2=v2",
@ -232,7 +249,8 @@ func TestEnvDeduplication(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
var spec runtimespec.Spec var spec runtimespec.Spec
if len(test.existing) > 0 { if len(test.existing) > 0 {
spec.Process = &runtimespec.Process{ spec.Process = &runtimespec.Process{
@ -248,17 +266,20 @@ func TestEnvDeduplication(t *testing.T) {
} }
func TestPassThroughAnnotationsFilter(t *testing.T) { func TestPassThroughAnnotationsFilter(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
podAnnotations map[string]string podAnnotations map[string]string
runtimePodAnnotations []string runtimePodAnnotations []string
passthroughAnnotations map[string]string passthroughAnnotations map[string]string
}{ }{
"should support direct match": { {
desc: "should support direct match",
podAnnotations: map[string]string{"c": "d", "d": "e"}, podAnnotations: map[string]string{"c": "d", "d": "e"},
runtimePodAnnotations: []string{"c"}, runtimePodAnnotations: []string{"c"},
passthroughAnnotations: map[string]string{"c": "d"}, passthroughAnnotations: map[string]string{"c": "d"},
}, },
"should support wildcard match": { {
desc: "should support wildcard match",
podAnnotations: map[string]string{ podAnnotations: map[string]string{
"t.f": "j", "t.f": "j",
"z.g": "o", "z.g": "o",
@ -273,7 +294,8 @@ func TestPassThroughAnnotationsFilter(t *testing.T) {
"y.ca": "b", "y.ca": "b",
}, },
}, },
"should support wildcard match all": { {
desc: "should support wildcard match all",
podAnnotations: map[string]string{ podAnnotations: map[string]string{
"t.f": "j", "t.f": "j",
"z.g": "o", "z.g": "o",
@ -290,7 +312,8 @@ func TestPassThroughAnnotationsFilter(t *testing.T) {
"y": "b", "y": "b",
}, },
}, },
"should support match including path separator": { {
desc: "should support match including path separator",
podAnnotations: map[string]string{ podAnnotations: map[string]string{
"matchend.com/end": "1", "matchend.com/end": "1",
"matchend.com/end1": "2", "matchend.com/end1": "2",
@ -349,7 +372,8 @@ func TestPassThroughAnnotationsFilter(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
passthroughAnnotations := getPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations) passthroughAnnotations := getPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations)
assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations) assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations)
}) })
@ -437,28 +461,34 @@ func TestValidateTargetContainer(t *testing.T) {
err = addContainer(c, testOtherContainerID, testOtherContainerSandboxID, testOtherContainerPID, createdAt, startedAt, 0) err = addContainer(c, testOtherContainerID, testOtherContainerSandboxID, testOtherContainerPID, createdAt, startedAt, 0)
require.NoError(t, err, "error creating test container in other pod") require.NoError(t, err, "error creating test container in other pod")
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
targetContainerID string targetContainerID string
expectError bool expectError bool
}{ }{
"target container in pod": { {
desc: "target container in pod",
targetContainerID: testTargetContainerID, targetContainerID: testTargetContainerID,
expectError: false, expectError: false,
}, },
"target stopped container in pod": { {
desc: "target stopped container in pod",
targetContainerID: testStoppedContainerID, targetContainerID: testStoppedContainerID,
expectError: true, expectError: true,
}, },
"target container does not exist": { {
desc: "target container does not exist",
targetContainerID: "no-container-with-this-id", targetContainerID: "no-container-with-this-id",
expectError: true, expectError: true,
}, },
"target container in other pod": { {
desc: "target container in other pod",
targetContainerID: testOtherContainerID, targetContainerID: testOtherContainerID,
expectError: true, expectError: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
targetContainer, err := c.validateTargetContainer(testSandboxID, test.targetContainerID) targetContainer, err := c.validateTargetContainer(testSandboxID, test.targetContainerID)
if test.expectError { if test.expectError {
require.Error(t, err, "target should have been invalid but no error") require.Error(t, err, "target should have been invalid but no error")
@ -520,6 +550,8 @@ func TestHostNetwork(t *testing.T) {
if goruntime.GOOS != "linux" { if goruntime.GOOS != "linux" {
t.Skip() t.Skip()
} }
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if hostNetwork(tt.c) != tt.expected { if hostNetwork(tt.c) != tt.expected {
t.Errorf("failed hostNetwork got %t expected %t", hostNetwork(tt.c), tt.expected) t.Errorf("failed hostNetwork got %t expected %t", hostNetwork(tt.c), tt.expected)

View File

@ -39,23 +39,29 @@ func TestParseAuth(t *testing.T) {
base64.StdEncoding.Encode(testAuth, []byte(testUser+":"+testPasswd)) base64.StdEncoding.Encode(testAuth, []byte(testUser+":"+testPasswd))
invalidAuth := make([]byte, testAuthLen) invalidAuth := make([]byte, testAuthLen)
base64.StdEncoding.Encode(invalidAuth, []byte(testUser+"@"+testPasswd)) base64.StdEncoding.Encode(invalidAuth, []byte(testUser+"@"+testPasswd))
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
auth *runtime.AuthConfig auth *runtime.AuthConfig
host string host string
expectedUser string expectedUser string
expectedSecret string expectedSecret string
expectErr bool expectErr bool
}{ }{
"should not return error if auth config is nil": {}, {
"should not return error if empty auth is provided for access to anonymous registry": { desc: "should not return error if auth config is nil",
},
{
desc: "should not return error if empty auth is provided for access to anonymous registry",
auth: &runtime.AuthConfig{}, auth: &runtime.AuthConfig{},
expectErr: false, expectErr: false,
}, },
"should support identity token": { {
desc: "should support identity token",
auth: &runtime.AuthConfig{IdentityToken: "abcd"}, auth: &runtime.AuthConfig{IdentityToken: "abcd"},
expectedSecret: "abcd", expectedSecret: "abcd",
}, },
"should support username and password": { {
desc: "should support username and password",
auth: &runtime.AuthConfig{ auth: &runtime.AuthConfig{
Username: testUser, Username: testUser,
Password: testPasswd, Password: testPasswd,
@ -63,16 +69,19 @@ func TestParseAuth(t *testing.T) {
expectedUser: testUser, expectedUser: testUser,
expectedSecret: testPasswd, expectedSecret: testPasswd,
}, },
"should support auth": { {
desc: "should support auth",
auth: &runtime.AuthConfig{Auth: string(testAuth)}, auth: &runtime.AuthConfig{Auth: string(testAuth)},
expectedUser: testUser, expectedUser: testUser,
expectedSecret: testPasswd, expectedSecret: testPasswd,
}, },
"should return error for invalid auth": { {
desc: "should return error for invalid auth",
auth: &runtime.AuthConfig{Auth: string(invalidAuth)}, auth: &runtime.AuthConfig{Auth: string(invalidAuth)},
expectErr: true, expectErr: true,
}, },
"should return empty auth if server address doesn't match": { {
desc: "should return empty auth if server address doesn't match",
auth: &runtime.AuthConfig{ auth: &runtime.AuthConfig{
Username: testUser, Username: testUser,
Password: testPasswd, Password: testPasswd,
@ -82,7 +91,8 @@ func TestParseAuth(t *testing.T) {
expectedUser: "", expectedUser: "",
expectedSecret: "", expectedSecret: "",
}, },
"should return auth if server address matches": { {
desc: "should return auth if server address matches",
auth: &runtime.AuthConfig{ auth: &runtime.AuthConfig{
Username: testUser, Username: testUser,
Password: testPasswd, Password: testPasswd,
@ -92,7 +102,8 @@ func TestParseAuth(t *testing.T) {
expectedUser: testUser, expectedUser: testUser,
expectedSecret: testPasswd, expectedSecret: testPasswd,
}, },
"should return auth if server address is not specified": { {
desc: "should return auth if server address is not specified",
auth: &runtime.AuthConfig{ auth: &runtime.AuthConfig{
Username: testUser, Username: testUser,
Password: testPasswd, Password: testPasswd,
@ -102,7 +113,8 @@ func TestParseAuth(t *testing.T) {
expectedSecret: testPasswd, expectedSecret: testPasswd,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
u, s, err := ParseAuth(test.auth, test.host) u, s, err := ParseAuth(test.auth, test.host)
assert.Equal(t, test.expectErr, err != nil) assert.Equal(t, test.expectErr, err != nil)
assert.Equal(t, test.expectedUser, u) assert.Equal(t, test.expectedUser, u)
@ -112,12 +124,14 @@ func TestParseAuth(t *testing.T) {
} }
func TestRegistryEndpoints(t *testing.T) { func TestRegistryEndpoints(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
mirrors map[string]criconfig.Mirror mirrors map[string]criconfig.Mirror
host string host string
expected []string expected []string
}{ }{
"no mirror configured": { {
desc: "no mirror configured",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"registry-1.io": { "registry-1.io": {
Endpoints: []string{ Endpoints: []string{
@ -131,7 +145,8 @@ func TestRegistryEndpoints(t *testing.T) {
"https://registry-3.io", "https://registry-3.io",
}, },
}, },
"mirror configured": { {
desc: "mirror configured",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"registry-3.io": { "registry-3.io": {
Endpoints: []string{ Endpoints: []string{
@ -147,7 +162,8 @@ func TestRegistryEndpoints(t *testing.T) {
"https://registry-3.io", "https://registry-3.io",
}, },
}, },
"wildcard mirror configured": { {
desc: "wildcard mirror configured",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"*": { "*": {
Endpoints: []string{ Endpoints: []string{
@ -163,7 +179,8 @@ func TestRegistryEndpoints(t *testing.T) {
"https://registry-3.io", "https://registry-3.io",
}, },
}, },
"host should take precedence if both host and wildcard mirrors are configured": { {
desc: "host should take precedence if both host and wildcard mirrors are configured",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"*": { "*": {
Endpoints: []string{ Endpoints: []string{
@ -182,7 +199,8 @@ func TestRegistryEndpoints(t *testing.T) {
"https://registry-3.io", "https://registry-3.io",
}, },
}, },
"default endpoint in list with http": { {
desc: "default endpoint in list with http",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"registry-3.io": { "registry-3.io": {
Endpoints: []string{ Endpoints: []string{
@ -199,7 +217,8 @@ func TestRegistryEndpoints(t *testing.T) {
"http://registry-3.io", "http://registry-3.io",
}, },
}, },
"default endpoint in list with https": { {
desc: "default endpoint in list with https",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"registry-3.io": { "registry-3.io": {
Endpoints: []string{ Endpoints: []string{
@ -216,7 +235,8 @@ func TestRegistryEndpoints(t *testing.T) {
"https://registry-3.io", "https://registry-3.io",
}, },
}, },
"default endpoint in list with path": { {
desc: "default endpoint in list with path",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"registry-3.io": { "registry-3.io": {
Endpoints: []string{ Endpoints: []string{
@ -233,7 +253,8 @@ func TestRegistryEndpoints(t *testing.T) {
"https://registry-3.io/path", "https://registry-3.io/path",
}, },
}, },
"miss scheme endpoint in list with path": { {
desc: "miss scheme endpoint in list with path",
mirrors: map[string]criconfig.Mirror{ mirrors: map[string]criconfig.Mirror{
"registry-3.io": { "registry-3.io": {
Endpoints: []string{ Endpoints: []string{
@ -251,7 +272,8 @@ func TestRegistryEndpoints(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
c.config.Registry.Mirrors = test.mirrors c.config.Registry.Mirrors = test.mirrors
got, err := c.registryEndpoints(test.host) got, err := c.registryEndpoints(test.host)
@ -262,52 +284,64 @@ func TestRegistryEndpoints(t *testing.T) {
} }
func TestDefaultScheme(t *testing.T) { func TestDefaultScheme(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
host string host string
expected string expected string
}{ }{
"should use http by default for localhost": { {
desc: "should use http by default for localhost",
host: "localhost", host: "localhost",
expected: "http", expected: "http",
}, },
"should use http by default for localhost with port": { {
desc: "should use http by default for localhost with port",
host: "localhost:8080", host: "localhost:8080",
expected: "http", expected: "http",
}, },
"should use http by default for 127.0.0.1": { {
desc: "should use http by default for 127.0.0.1",
host: "127.0.0.1", host: "127.0.0.1",
expected: "http", expected: "http",
}, },
"should use http by default for 127.0.0.1 with port": { {
desc: "should use http by default for 127.0.0.1 with port",
host: "127.0.0.1:8080", host: "127.0.0.1:8080",
expected: "http", expected: "http",
}, },
"should use http by default for ::1": { {
desc: "should use http by default for ::1",
host: "::1", host: "::1",
expected: "http", expected: "http",
}, },
"should use http by default for ::1 with port": { {
desc: "should use http by default for ::1 with port",
host: "[::1]:8080", host: "[::1]:8080",
expected: "http", expected: "http",
}, },
"should use https by default for remote host": { {
desc: "should use https by default for remote host",
host: "remote", host: "remote",
expected: "https", expected: "https",
}, },
"should use https by default for remote host with port": { {
desc: "should use https by default for remote host with port",
host: "remote:8080", host: "remote:8080",
expected: "https", expected: "https",
}, },
"should use https by default for remote ip": { {
desc: "should use https by default for remote ip",
host: "8.8.8.8", host: "8.8.8.8",
expected: "https", expected: "https",
}, },
"should use https by default for remote ip with port": { {
desc: "should use https by default for remote ip with port",
host: "8.8.8.8:8080", host: "8.8.8.8:8080",
expected: "https", expected: "https",
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
got := defaultScheme(test.host) got := defaultScheme(test.host)
assert.Equal(t, test.expected, got) assert.Equal(t, test.expected, got)
}) })
@ -315,20 +349,24 @@ func TestDefaultScheme(t *testing.T) {
} }
func TestEncryptedImagePullOpts(t *testing.T) { func TestEncryptedImagePullOpts(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
keyModel string keyModel string
expectedOpts int expectedOpts int
}{ }{
"node key model should return one unpack opt": { {
desc: "node key model should return one unpack opt",
keyModel: criconfig.KeyModelNode, keyModel: criconfig.KeyModelNode,
expectedOpts: 1, expectedOpts: 1,
}, },
"no key model selected should default to node key model": { {
desc: "no key model selected should default to node key model",
keyModel: "", keyModel: "",
expectedOpts: 0, expectedOpts: 0,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
c.config.ImageDecryption.KeyModel = test.keyModel c.config.ImageDecryption.KeyModel = test.keyModel
got := len(c.encryptedImagesPullOpts()) got := len(c.encryptedImagesPullOpts())
@ -400,35 +438,41 @@ func TestSnapshotterFromPodSandboxConfig(t *testing.T) {
func TestGetRepoDigestAndTag(t *testing.T) { func TestGetRepoDigestAndTag(t *testing.T) {
digest := digest.Digest("sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582") digest := digest.Digest("sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582")
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
ref string ref string
schema1 bool schema1 bool
expectedRepoDigest string expectedRepoDigest string
expectedRepoTag string expectedRepoTag string
}{ }{
"repo tag should be empty if original ref has no tag": { {
desc: "repo tag should be empty if original ref has no tag",
ref: "gcr.io/library/busybox@" + digest.String(), ref: "gcr.io/library/busybox@" + digest.String(),
expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(), expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(),
}, },
"repo tag should not be empty if original ref has tag": { {
desc: "repo tag should not be empty if original ref has tag",
ref: "gcr.io/library/busybox:latest", ref: "gcr.io/library/busybox:latest",
expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(), expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(),
expectedRepoTag: "gcr.io/library/busybox:latest", expectedRepoTag: "gcr.io/library/busybox:latest",
}, },
"repo digest should be empty if original ref is schema1 and has no digest": { {
desc: "repo digest should be empty if original ref is schema1 and has no digest",
ref: "gcr.io/library/busybox:latest", ref: "gcr.io/library/busybox:latest",
schema1: true, schema1: true,
expectedRepoDigest: "", expectedRepoDigest: "",
expectedRepoTag: "gcr.io/library/busybox:latest", expectedRepoTag: "gcr.io/library/busybox:latest",
}, },
"repo digest should not be empty if original ref is schema1 but has digest": { {
desc: "repo digest should not be empty if original ref is schema1 but has digest",
ref: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594", ref: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594",
schema1: true, schema1: true,
expectedRepoDigest: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594", expectedRepoDigest: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594",
expectedRepoTag: "", expectedRepoTag: "",
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
named, err := docker.ParseDockerRef(test.ref) named, err := docker.ParseDockerRef(test.ref)
assert.NoError(t, err) assert.NoError(t, err)
repoDigest, repoTag := getRepoDigestAndTag(named, digest, test.schema1) repoDigest, repoTag := getRepoDigestAndTag(named, digest, test.schema1)

View File

@ -92,36 +92,44 @@ func TestParseImageReferences(t *testing.T) {
// TestGetUserFromImage tests the logic of getting image uid or user name of image user. // TestGetUserFromImage tests the logic of getting image uid or user name of image user.
func TestGetUserFromImage(t *testing.T) { func TestGetUserFromImage(t *testing.T) {
newI64 := func(i int64) *int64 { return &i } newI64 := func(i int64) *int64 { return &i }
for c, test := range map[string]struct { for _, test := range []struct {
desc string
user string user string
uid *int64 uid *int64
name string name string
}{ }{
"no gid": { {
desc: "no gid",
user: "0", user: "0",
uid: newI64(0), uid: newI64(0),
}, },
"uid/gid": { {
desc: "uid/gid",
user: "0:1", user: "0:1",
uid: newI64(0), uid: newI64(0),
}, },
"empty user": { {
desc: "empty user",
user: "", user: "",
}, },
"multiple separators": { {
desc: "multiple separators",
user: "1:2:3", user: "1:2:3",
uid: newI64(1), uid: newI64(1),
}, },
"root username": { {
desc: "root username",
user: "root:root", user: "root:root",
name: "root", name: "root",
}, },
"username": { {
desc: "username",
user: "test:test", user: "test:test",
name: "test", name: "test",
}, },
} { } {
t.Run(c, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
actualUID, actualName := getUserFromImage(test.user) actualUID, actualName := getUserFromImage(test.user)
assert.Equal(t, test.uid, actualUID) assert.Equal(t, test.uid, actualUID)
assert.Equal(t, test.name, actualName) assert.Equal(t, test.name, actualName)

View File

@ -104,20 +104,24 @@ func TestRuntimeSnapshotter(t *testing.T) {
Snapshotter: "devmapper", Snapshotter: "devmapper",
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
runtime criconfig.Runtime runtime criconfig.Runtime
expectSnapshotter string expectSnapshotter string
}{ }{
"should return default snapshotter when runtime.Snapshotter is not set": { {
desc: "should return default snapshotter when runtime.Snapshotter is not set",
runtime: defaultRuntime, runtime: defaultRuntime,
expectSnapshotter: criconfig.DefaultConfig().Snapshotter, expectSnapshotter: criconfig.DefaultConfig().Snapshotter,
}, },
"should return overridden snapshotter when runtime.Snapshotter is set": { {
desc: "should return overridden snapshotter when runtime.Snapshotter is set",
runtime: fooRuntime, runtime: fooRuntime,
expectSnapshotter: "devmapper", expectSnapshotter: "devmapper",
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
cri := newTestCRIService() cri := newTestCRIService()
cri.config = criconfig.Config{ cri.config = criconfig.Config{
PluginConfig: criconfig.DefaultConfig(), PluginConfig: criconfig.DefaultConfig(),

View File

@ -29,32 +29,39 @@ import (
func TestGetCgroupsPath(t *testing.T) { func TestGetCgroupsPath(t *testing.T) {
testID := "test-id" testID := "test-id"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
cgroupsParent string cgroupsParent string
expected string expected string
}{ }{
"should support regular cgroup path": { {
desc: "should support regular cgroup path",
cgroupsParent: "/a/b", cgroupsParent: "/a/b",
expected: "/a/b/test-id", expected: "/a/b/test-id",
}, },
"should support systemd cgroup path": { {
desc: "should support systemd cgroup path",
cgroupsParent: "/a.slice/b.slice", cgroupsParent: "/a.slice/b.slice",
expected: "b.slice:cri-containerd:test-id", expected: "b.slice:cri-containerd:test-id",
}, },
"should support tailing slash for regular cgroup path": { {
desc: "should support tailing slash for regular cgroup path",
cgroupsParent: "/a/b/", cgroupsParent: "/a/b/",
expected: "/a/b/test-id", expected: "/a/b/test-id",
}, },
"should support tailing slash for systemd cgroup path": { {
desc: "should support tailing slash for systemd cgroup path",
cgroupsParent: "/a.slice/b.slice/", cgroupsParent: "/a.slice/b.slice/",
expected: "b.slice:cri-containerd:test-id", expected: "b.slice:cri-containerd:test-id",
}, },
"should treat root cgroup as regular cgroup path": { {
desc: "should treat root cgroup as regular cgroup path",
cgroupsParent: "/", cgroupsParent: "/",
expected: "/test-id", expected: "/test-id",
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
got := getCgroupsPath(test.cgroupsParent, testID) got := getCgroupsPath(test.cgroupsParent, testID)
assert.Equal(t, test.expected, got) assert.Equal(t, test.expected, got)
}) })

View File

@ -29,18 +29,21 @@ func TestInitSelinuxOpts(t *testing.T) {
t.Skip("selinux is not enabled") t.Skip("selinux is not enabled")
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
selinuxOpt *runtime.SELinuxOption selinuxOpt *runtime.SELinuxOption
processLabel string processLabel string
mountLabel string mountLabel string
expectErr bool expectErr bool
}{ }{
"Should return empty strings for processLabel and mountLabel when selinuxOpt is nil": { {
desc: "Should return empty strings for processLabel and mountLabel when selinuxOpt is nil",
selinuxOpt: nil, selinuxOpt: nil,
processLabel: ".*:c[0-9]{1,3},c[0-9]{1,3}", processLabel: ".*:c[0-9]{1,3},c[0-9]{1,3}",
mountLabel: ".*:c[0-9]{1,3},c[0-9]{1,3}", mountLabel: ".*:c[0-9]{1,3},c[0-9]{1,3}",
}, },
"Should overlay fields on processLabel when selinuxOpt has been initialized partially": { {
desc: "Should overlay fields on processLabel when selinuxOpt has been initialized partially",
selinuxOpt: &runtime.SELinuxOption{ selinuxOpt: &runtime.SELinuxOption{
User: "", User: "",
Role: "user_r", Role: "user_r",
@ -50,7 +53,8 @@ func TestInitSelinuxOpts(t *testing.T) {
processLabel: "system_u:user_r:(container_file_t|svirt_lxc_net_t):s0:c1,c2", processLabel: "system_u:user_r:(container_file_t|svirt_lxc_net_t):s0:c1,c2",
mountLabel: "system_u:object_r:(container_file_t|svirt_sandbox_file_t):s0:c1,c2", mountLabel: "system_u:object_r:(container_file_t|svirt_sandbox_file_t):s0:c1,c2",
}, },
"Should be resolved correctly when selinuxOpt has been initialized completely": { {
desc: "Should be resolved correctly when selinuxOpt has been initialized completely",
selinuxOpt: &runtime.SELinuxOption{ selinuxOpt: &runtime.SELinuxOption{
User: "user_u", User: "user_u",
Role: "user_r", Role: "user_r",
@ -60,7 +64,8 @@ func TestInitSelinuxOpts(t *testing.T) {
processLabel: "user_u:user_r:user_t:s0:c1,c2", processLabel: "user_u:user_r:user_t:s0:c1,c2",
mountLabel: "user_u:object_r:(container_file_t|svirt_sandbox_file_t):s0:c1,c2", mountLabel: "user_u:object_r:(container_file_t|svirt_sandbox_file_t):s0:c1,c2",
}, },
"Should be resolved correctly when selinuxOpt has been initialized with level=''": { {
desc: "Should be resolved correctly when selinuxOpt has been initialized with level=''",
selinuxOpt: &runtime.SELinuxOption{ selinuxOpt: &runtime.SELinuxOption{
User: "user_u", User: "user_u",
Role: "user_r", Role: "user_r",
@ -70,7 +75,8 @@ func TestInitSelinuxOpts(t *testing.T) {
processLabel: "user_u:user_r:user_t:s0:c[0-9]{1,3},c[0-9]{1,3}", processLabel: "user_u:user_r:user_t:s0:c[0-9]{1,3},c[0-9]{1,3}",
mountLabel: "user_u:object_r:(container_file_t|svirt_sandbox_file_t):s0", mountLabel: "user_u:object_r:(container_file_t|svirt_sandbox_file_t):s0",
}, },
"Should return error when the format of 'level' is not correct": { {
desc: "Should return error when the format of 'level' is not correct",
selinuxOpt: &runtime.SELinuxOption{ selinuxOpt: &runtime.SELinuxOption{
User: "user_u", User: "user_u",
Role: "user_r", Role: "user_r",
@ -80,7 +86,8 @@ func TestInitSelinuxOpts(t *testing.T) {
expectErr: true, expectErr: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
processLabel, mountLabel, err := initLabelsFromOpt(test.selinuxOpt) processLabel, mountLabel, err := initLabelsFromOpt(test.selinuxOpt)
if test.expectErr { if test.expectErr {
assert.Error(t, err) assert.Error(t, err)
@ -93,59 +100,75 @@ func TestInitSelinuxOpts(t *testing.T) {
} }
func TestCheckSelinuxLevel(t *testing.T) { func TestCheckSelinuxLevel(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
level string level string
expectNoMatch bool expectNoMatch bool
}{ }{
"s0": { {
desc: "s0",
level: "s0", level: "s0",
}, },
"s0-s0": { {
desc: "s0-s0",
level: "s0-s0", level: "s0-s0",
}, },
"s0:c0": { {
desc: "s0:c0",
level: "s0:c0", level: "s0:c0",
}, },
"s0:c0.c3": { {
desc: "s0:c0.c3",
level: "s0:c0.c3", level: "s0:c0.c3",
}, },
"s0:c0,c3": { {
desc: "s0:c0,c3",
level: "s0:c0,c3", level: "s0:c0,c3",
}, },
"s0-s0:c0,c3": { {
desc: "s0-s0:c0,c3",
level: "s0-s0:c0,c3", level: "s0-s0:c0,c3",
}, },
"s0-s0:c0,c3.c6": { {
desc: "s0-s0:c0,c3.c6",
level: "s0-s0:c0,c3.c6", level: "s0-s0:c0,c3.c6",
}, },
"s0-s0:c0,c3.c6,c8.c10": { {
desc: "s0-s0:c0,c3.c6,c8.c10",
level: "s0-s0:c0,c3.c6,c8.c10", level: "s0-s0:c0,c3.c6,c8.c10",
}, },
"s0-s0:c0,c3.c6,c8,c10": { {
desc: "s0-s0:c0,c3.c6,c8,c10",
level: "s0-s0:c0,c3.c6", level: "s0-s0:c0,c3.c6",
}, },
"s0,c0,c3": { {
desc: "s0,c0,c3",
level: "s0,c0,c3", level: "s0,c0,c3",
expectNoMatch: true, expectNoMatch: true,
}, },
"s0:c0.c3.c6": { {
desc: "s0:c0.c3.c6",
level: "s0:c0.c3.c6", level: "s0:c0.c3.c6",
expectNoMatch: true, expectNoMatch: true,
}, },
"s0-s0,c0,c3": { {
desc: "s0-s0,c0,c3",
level: "s0-s0,c0,c3", level: "s0-s0,c0,c3",
expectNoMatch: true, expectNoMatch: true,
}, },
"s0-s0:c0.c3.c6": { {
desc: "s0-s0:c0.c3.c6",
level: "s0-s0:c0.c3.c6", level: "s0-s0:c0.c3.c6",
expectNoMatch: true, expectNoMatch: true,
}, },
"s0-s0:c0,c3.c6.c8": { {
desc: "s0-s0:c0,c3.c6.c8",
level: "s0-s0:c0,c3.c6.c8", level: "s0-s0:c0,c3.c6.c8",
expectNoMatch: true, expectNoMatch: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
err := checkSelinuxLevel(test.level) err := checkSelinuxLevel(test.level)
if test.expectNoMatch { if test.expectNoMatch {
assert.Error(t, err) assert.Error(t, err)

View File

@ -31,35 +31,41 @@ import (
func TestGetRepoDigestAndTag(t *testing.T) { func TestGetRepoDigestAndTag(t *testing.T) {
digest := imagedigest.Digest("sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582") digest := imagedigest.Digest("sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582")
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
ref string ref string
schema1 bool schema1 bool
expectedRepoDigest string expectedRepoDigest string
expectedRepoTag string expectedRepoTag string
}{ }{
"repo tag should be empty if original ref has no tag": { {
desc: "repo tag should be empty if original ref has no tag",
ref: "gcr.io/library/busybox@" + digest.String(), ref: "gcr.io/library/busybox@" + digest.String(),
expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(), expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(),
}, },
"repo tag should not be empty if original ref has tag": { {
desc: "repo tag should not be empty if original ref has tag",
ref: "gcr.io/library/busybox:latest", ref: "gcr.io/library/busybox:latest",
expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(), expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(),
expectedRepoTag: "gcr.io/library/busybox:latest", expectedRepoTag: "gcr.io/library/busybox:latest",
}, },
"repo digest should be empty if original ref is schema1 and has no digest": { {
desc: "repo digest should be empty if original ref is schema1 and has no digest",
ref: "gcr.io/library/busybox:latest", ref: "gcr.io/library/busybox:latest",
schema1: true, schema1: true,
expectedRepoDigest: "", expectedRepoDigest: "",
expectedRepoTag: "gcr.io/library/busybox:latest", expectedRepoTag: "gcr.io/library/busybox:latest",
}, },
"repo digest should not be empty if original ref is schema1 but has digest": { {
desc: "repo digest should not be empty if original ref is schema1 but has digest",
ref: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594", ref: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594",
schema1: true, schema1: true,
expectedRepoDigest: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594", expectedRepoDigest: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594",
expectedRepoTag: "", expectedRepoTag: "",
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
named, err := docker.ParseDockerRef(test.ref) named, err := docker.ParseDockerRef(test.ref)
assert.NoError(t, err) assert.NoError(t, err)
repoDigest, repoTag := getRepoDigestAndTag(named, digest, test.schema1) repoDigest, repoTag := getRepoDigestAndTag(named, digest, test.schema1)
@ -109,18 +115,21 @@ func TestParseImageReferences(t *testing.T) {
} }
func TestEnvDeduplication(t *testing.T) { func TestEnvDeduplication(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
existing []string existing []string
kv [][2]string kv [][2]string
expected []string expected []string
}{ }{
"single env": { {
desc: "single env",
kv: [][2]string{ kv: [][2]string{
{"a", "b"}, {"a", "b"},
}, },
expected: []string{"a=b"}, expected: []string{"a=b"},
}, },
"multiple envs": { {
desc: "multiple envs",
kv: [][2]string{ kv: [][2]string{
{"a", "b"}, {"a", "b"},
{"c", "d"}, {"c", "d"},
@ -132,7 +141,8 @@ func TestEnvDeduplication(t *testing.T) {
"e=f", "e=f",
}, },
}, },
"env override": { {
desc: "env override",
kv: [][2]string{ kv: [][2]string{
{"k1", "v1"}, {"k1", "v1"},
{"k2", "v2"}, {"k2", "v2"},
@ -148,7 +158,8 @@ func TestEnvDeduplication(t *testing.T) {
"k4=v6", "k4=v6",
}, },
}, },
"existing env": { {
desc: "existing env",
existing: []string{ existing: []string{
"k1=v1", "k1=v1",
"k2=v2", "k2=v2",
@ -167,7 +178,8 @@ func TestEnvDeduplication(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
var spec runtimespec.Spec var spec runtimespec.Spec
if len(test.existing) > 0 { if len(test.existing) > 0 {
spec.Process = &runtimespec.Process{ spec.Process = &runtimespec.Process{
@ -183,17 +195,20 @@ func TestEnvDeduplication(t *testing.T) {
} }
func TestPassThroughAnnotationsFilter(t *testing.T) { func TestPassThroughAnnotationsFilter(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
podAnnotations map[string]string podAnnotations map[string]string
runtimePodAnnotations []string runtimePodAnnotations []string
passthroughAnnotations map[string]string passthroughAnnotations map[string]string
}{ }{
"should support direct match": { {
desc: "should support direct match",
podAnnotations: map[string]string{"c": "d", "d": "e"}, podAnnotations: map[string]string{"c": "d", "d": "e"},
runtimePodAnnotations: []string{"c"}, runtimePodAnnotations: []string{"c"},
passthroughAnnotations: map[string]string{"c": "d"}, passthroughAnnotations: map[string]string{"c": "d"},
}, },
"should support wildcard match": { {
desc: "should support wildcard match",
podAnnotations: map[string]string{ podAnnotations: map[string]string{
"t.f": "j", "t.f": "j",
"z.g": "o", "z.g": "o",
@ -208,7 +223,8 @@ func TestPassThroughAnnotationsFilter(t *testing.T) {
"y.ca": "b", "y.ca": "b",
}, },
}, },
"should support wildcard match all": { {
desc: "should support wildcard match all",
podAnnotations: map[string]string{ podAnnotations: map[string]string{
"t.f": "j", "t.f": "j",
"z.g": "o", "z.g": "o",
@ -225,7 +241,8 @@ func TestPassThroughAnnotationsFilter(t *testing.T) {
"y": "b", "y": "b",
}, },
}, },
"should support match including path separator": { {
desc: "should support match including path separator",
podAnnotations: map[string]string{ podAnnotations: map[string]string{
"matchend.com/end": "1", "matchend.com/end": "1",
"matchend.com/end1": "2", "matchend.com/end1": "2",
@ -284,7 +301,8 @@ func TestPassThroughAnnotationsFilter(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
passthroughAnnotations := getPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations) passthroughAnnotations := getPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations)
assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations) assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations)
}) })

View File

@ -106,12 +106,14 @@ func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConf
func TestLinuxSandboxContainerSpec(t *testing.T) { func TestLinuxSandboxContainerSpec(t *testing.T) {
testID := "test-id" testID := "test-id"
nsPath := "test-cni" nsPath := "test-cni"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
configChange func(*runtime.PodSandboxConfig) configChange func(*runtime.PodSandboxConfig)
specCheck func(*testing.T, *runtimespec.Spec) specCheck func(*testing.T, *runtimespec.Spec)
expectErr bool expectErr bool
}{ }{
"spec should reflect original config": { {
desc: "spec should reflect original config",
specCheck: func(t *testing.T, spec *runtimespec.Spec) { specCheck: func(t *testing.T, spec *runtimespec.Spec) {
// runtime spec should have expected namespaces enabled by default. // runtime spec should have expected namespaces enabled by default.
require.NotNil(t, spec.Linux) require.NotNil(t, spec.Linux)
@ -132,7 +134,8 @@ func TestLinuxSandboxContainerSpec(t *testing.T) {
assert.Contains(t, spec.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647") assert.Contains(t, spec.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647")
}, },
}, },
"host namespace": { {
desc: "host namespace",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
NamespaceOptions: &runtime.NamespaceOption{ NamespaceOptions: &runtime.NamespaceOption{
@ -161,7 +164,8 @@ func TestLinuxSandboxContainerSpec(t *testing.T) {
assert.NotContains(t, spec.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647") assert.NotContains(t, spec.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647")
}, },
}, },
"should set supplemental groups correctly": { {
desc: "should set supplemental groups correctly",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
SupplementalGroups: []int64{1111, 2222}, SupplementalGroups: []int64{1111, 2222},
@ -173,7 +177,8 @@ func TestLinuxSandboxContainerSpec(t *testing.T) {
assert.Contains(t, spec.Process.User.AdditionalGids, uint32(2222)) assert.Contains(t, spec.Process.User.AdditionalGids, uint32(2222))
}, },
}, },
"should overwrite default sysctls": { {
desc: "should overwrite default sysctls",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Linux.Sysctls = map[string]string{ c.Linux.Sysctls = map[string]string{
"net.ipv4.ip_unprivileged_port_start": "500", "net.ipv4.ip_unprivileged_port_start": "500",
@ -186,7 +191,8 @@ func TestLinuxSandboxContainerSpec(t *testing.T) {
assert.Contains(t, spec.Linux.Sysctl["net.ipv4.ping_group_range"], "1 1000") assert.Contains(t, spec.Linux.Sysctl["net.ipv4.ping_group_range"], "1 1000")
}, },
}, },
"sandbox sizing annotations should be set if LinuxContainerResources were provided": { {
desc: "sandbox sizing annotations should be set if LinuxContainerResources were provided",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Linux.Resources = &v1.LinuxContainerResources{ c.Linux.Resources = &v1.LinuxContainerResources{
CpuPeriod: 100, CpuPeriod: 100,
@ -214,7 +220,8 @@ func TestLinuxSandboxContainerSpec(t *testing.T) {
assert.EqualValues(t, "1024", value) assert.EqualValues(t, "1024", value)
}, },
}, },
"sandbox sizing annotations should not be set if LinuxContainerResources were not provided": { {
desc: "sandbox sizing annotations should not be set if LinuxContainerResources were not provided",
specCheck: func(t *testing.T, spec *runtimespec.Spec) { specCheck: func(t *testing.T, spec *runtimespec.Spec) {
_, ok := spec.Annotations[annotations.SandboxCPUPeriod] _, ok := spec.Annotations[annotations.SandboxCPUPeriod]
assert.False(t, ok) assert.False(t, ok)
@ -226,7 +233,8 @@ func TestLinuxSandboxContainerSpec(t *testing.T) {
assert.False(t, ok) assert.False(t, ok)
}, },
}, },
"sandbox sizing annotations are zero if the resources are set to 0": { {
desc: "sandbox sizing annotations are zero if the resources are set to 0",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Linux.Resources = &v1.LinuxContainerResources{} c.Linux.Resources = &v1.LinuxContainerResources{}
}, },
@ -246,7 +254,8 @@ func TestLinuxSandboxContainerSpec(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newControllerService() c := newControllerService()
c.config.EnableUnprivilegedICMP = true c.config.EnableUnprivilegedICMP = true
c.config.EnableUnprivilegedPorts = true c.config.EnableUnprivilegedPorts = true
@ -275,13 +284,15 @@ func TestSetupSandboxFiles(t *testing.T) {
testID = "test-id" testID = "test-id"
realhostname = "test-real-hostname" realhostname = "test-real-hostname"
) )
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
dnsConfig *runtime.DNSConfig dnsConfig *runtime.DNSConfig
hostname string hostname string
ipcMode runtime.NamespaceMode ipcMode runtime.NamespaceMode
expectedCalls []ostesting.CalledDetail expectedCalls []ostesting.CalledDetail
}{ }{
"should check host /dev/shm existence when ipc mode is NODE": { {
desc: "should check host /dev/shm existence when ipc mode is NODE",
ipcMode: runtime.NamespaceMode_NODE, ipcMode: runtime.NamespaceMode_NODE,
expectedCalls: []ostesting.CalledDetail{ expectedCalls: []ostesting.CalledDetail{
{ {
@ -317,7 +328,8 @@ func TestSetupSandboxFiles(t *testing.T) {
}, },
}, },
}, },
"should create new /etc/resolv.conf if DNSOptions is set": { {
desc: "should create new /etc/resolv.conf if DNSOptions is set",
dnsConfig: &runtime.DNSConfig{ dnsConfig: &runtime.DNSConfig{
Servers: []string{"8.8.8.8"}, Servers: []string{"8.8.8.8"},
Searches: []string{"114.114.114.114"}, Searches: []string{"114.114.114.114"},
@ -360,7 +372,8 @@ options timeout:1
}, },
}, },
}, },
"should create sandbox shm when ipc namespace mode is not NODE": { {
desc: "should create sandbox shm when ipc namespace mode is not NODE",
ipcMode: runtime.NamespaceMode_POD, ipcMode: runtime.NamespaceMode_POD,
expectedCalls: []ostesting.CalledDetail{ expectedCalls: []ostesting.CalledDetail{
{ {
@ -403,7 +416,8 @@ options timeout:1
}, },
}, },
}, },
"should create /etc/hostname when hostname is set": { {
desc: "should create /etc/hostname when hostname is set",
hostname: "test-hostname", hostname: "test-hostname",
ipcMode: runtime.NamespaceMode_NODE, ipcMode: runtime.NamespaceMode_NODE,
expectedCalls: []ostesting.CalledDetail{ expectedCalls: []ostesting.CalledDetail{
@ -438,7 +452,8 @@ options timeout:1
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newControllerService() c := newControllerService()
c.os.(*ostesting.FakeOS).HostnameFn = func() (string, error) { c.os.(*ostesting.FakeOS).HostnameFn = func() (string, error) {
return realhostname, nil return realhostname, nil
@ -469,15 +484,19 @@ options timeout:1
} }
func TestParseDNSOption(t *testing.T) { func TestParseDNSOption(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
servers []string servers []string
searches []string searches []string
options []string options []string
expectedContent string expectedContent string
expectErr bool expectErr bool
}{ }{
"empty dns options should return empty content": {}, {
"non-empty dns options should return correct content": { desc: "empty dns options should return empty content",
},
{
desc: "non-empty dns options should return correct content",
servers: []string{"8.8.8.8", "server.google.com"}, servers: []string{"8.8.8.8", "server.google.com"},
searches: []string{"114.114.114.114"}, searches: []string{"114.114.114.114"},
options: []string{"timeout:1"}, options: []string{"timeout:1"},
@ -487,7 +506,8 @@ nameserver server.google.com
options timeout:1 options timeout:1
`, `,
}, },
"expanded dns config should return correct content on modern libc (e.g. glibc 2.26 and above)": { {
desc: "expanded dns config should return correct content on modern libc (e.g. glibc 2.26 and above)",
servers: []string{"8.8.8.8", "server.google.com"}, servers: []string{"8.8.8.8", "server.google.com"},
searches: []string{ searches: []string{
"server0.google.com", "server0.google.com",
@ -506,7 +526,8 @@ options timeout:1
`, `,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
resolvContent, err := parseDNSOptions(test.servers, test.searches, test.options) resolvContent, err := parseDNSOptions(test.servers, test.searches, test.options)
if test.expectErr { if test.expectErr {
assert.Error(t, err) assert.Error(t, err)

View File

@ -38,27 +38,31 @@ func TestSandboxContainerSpec(t *testing.T) {
} }
testID := "test-id" testID := "test-id"
nsPath := "test-cni" nsPath := "test-cni"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
configChange func(*runtime.PodSandboxConfig) configChange func(*runtime.PodSandboxConfig)
podAnnotations []string podAnnotations []string
imageConfigChange func(*imagespec.ImageConfig) imageConfigChange func(*imagespec.ImageConfig)
specCheck func(*testing.T, *runtimespec.Spec) specCheck func(*testing.T, *runtimespec.Spec)
expectErr bool expectErr bool
}{ }{
"should return error when entrypoint and cmd are empty": { {
desc: "should return error when entrypoint and cmd are empty",
imageConfigChange: func(c *imagespec.ImageConfig) { imageConfigChange: func(c *imagespec.ImageConfig) {
c.Entrypoint = nil c.Entrypoint = nil
c.Cmd = nil c.Cmd = nil
}, },
expectErr: true, expectErr: true,
}, },
"a passthrough annotation should be passed as an OCI annotation": { {
desc: "a passthrough annotation should be passed as an OCI annotation",
podAnnotations: []string{"c"}, podAnnotations: []string{"c"},
specCheck: func(t *testing.T, spec *runtimespec.Spec) { specCheck: func(t *testing.T, spec *runtimespec.Spec) {
assert.Equal(t, spec.Annotations["c"], "d") assert.Equal(t, spec.Annotations["c"], "d")
}, },
}, },
"a non-passthrough annotation should not be passed as an OCI annotation": { {
desc: "a non-passthrough annotation should not be passed as an OCI annotation",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Annotations["d"] = "e" c.Annotations["d"] = "e"
}, },
@ -69,7 +73,8 @@ func TestSandboxContainerSpec(t *testing.T) {
assert.False(t, ok) assert.False(t, ok)
}, },
}, },
"passthrough annotations should support wildcard match": { {
desc: "passthrough annotations should support wildcard match",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
c.Annotations["t.f"] = "j" c.Annotations["t.f"] = "j"
c.Annotations["z.g"] = "o" c.Annotations["z.g"] = "o"
@ -89,7 +94,8 @@ func TestSandboxContainerSpec(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newControllerService() c := newControllerService()
config, imageConfig, specCheck := getRunPodSandboxTestData() config, imageConfig, specCheck := getRunPodSandboxTestData()
if test.configChange != nil { if test.configChange != nil {
@ -117,11 +123,15 @@ func TestSandboxContainerSpec(t *testing.T) {
} }
func TestTypeurlMarshalUnmarshalSandboxMeta(t *testing.T) { func TestTypeurlMarshalUnmarshalSandboxMeta(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
configChange func(*runtime.PodSandboxConfig) configChange func(*runtime.PodSandboxConfig)
}{ }{
"should marshal original config": {}, {
"should marshal Linux": { desc: "should marshal original config",
},
{
desc: "should marshal Linux",
configChange: func(c *runtime.PodSandboxConfig) { configChange: func(c *runtime.PodSandboxConfig) {
if c.Linux == nil { if c.Linux == nil {
c.Linux = &runtime.LinuxPodSandboxConfig{} c.Linux = &runtime.LinuxPodSandboxConfig{}
@ -137,7 +147,8 @@ func TestTypeurlMarshalUnmarshalSandboxMeta(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
meta := &sandboxstore.Metadata{ meta := &sandboxstore.Metadata{
ID: "1", ID: "1",
Name: "sandbox_1", Name: "sandbox_1",
@ -198,6 +209,7 @@ func TestHostAccessingSandbox(t *testing.T) {
{"Security Context namespace host access", hostNamespace, true}, {"Security Context namespace host access", hostNamespace, true},
} }
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if got := hostAccessingSandbox(tt.config); got != tt.want { if got := hostAccessingSandbox(tt.config); got != tt.want {
t.Errorf("hostAccessingSandbox() = %v, want %v", got, tt.want) t.Errorf("hostAccessingSandbox() = %v, want %v", got, tt.want)

View File

@ -53,31 +53,36 @@ func TestToCRISandbox(t *testing.T) {
Annotations: config.GetAnnotations(), Annotations: config.GetAnnotations(),
RuntimeHandler: "test-runtime-handler", RuntimeHandler: "test-runtime-handler",
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
state sandboxstore.State state sandboxstore.State
expectedState runtime.PodSandboxState expectedState runtime.PodSandboxState
}{ }{
"sandbox state ready": { {
desc: "sandbox state ready",
state: sandboxstore.StateReady, state: sandboxstore.StateReady,
expectedState: runtime.PodSandboxState_SANDBOX_READY, expectedState: runtime.PodSandboxState_SANDBOX_READY,
}, },
"sandbox state not ready": { {
desc: "sandbox state not ready",
state: sandboxstore.StateNotReady, state: sandboxstore.StateNotReady,
expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY,
}, },
"sandbox state unknown": { {
desc: "sandbox state unknown",
state: sandboxstore.StateUnknown, state: sandboxstore.StateUnknown,
expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
status := sandboxstore.Status{ status := sandboxstore.Status{
CreatedAt: createdAt, CreatedAt: createdAt,
State: test.state, State: test.state,
} }
expect.State = test.expectedState expect.State = test.expectedState
s := toCRISandbox(meta, status) s := toCRISandbox(meta, status)
assert.Equal(t, expect, s, desc) assert.Equal(t, expect, s, test.desc)
}) })
} }
} }
@ -157,22 +162,27 @@ func TestFilterSandboxes(t *testing.T) {
assert.NoError(t, c.sandboxStore.Add(sb)) assert.NoError(t, c.sandboxStore.Add(sb))
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
filter *runtime.PodSandboxFilter filter *runtime.PodSandboxFilter
expect []*runtime.PodSandbox expect []*runtime.PodSandbox
}{ }{
"no filter": { {
desc: "no filter",
expect: testSandboxes, expect: testSandboxes,
}, },
"id filter": { {
desc: "id filter",
filter: &runtime.PodSandboxFilter{Id: "2abcdef"}, filter: &runtime.PodSandboxFilter{Id: "2abcdef"},
expect: []*runtime.PodSandbox{testSandboxes[1]}, expect: []*runtime.PodSandbox{testSandboxes[1]},
}, },
"truncid filter": { {
desc: "truncid filter",
filter: &runtime.PodSandboxFilter{Id: "2"}, filter: &runtime.PodSandboxFilter{Id: "2"},
expect: []*runtime.PodSandbox{testSandboxes[1]}, expect: []*runtime.PodSandbox{testSandboxes[1]},
}, },
"state filter": { {
desc: "state filter",
filter: &runtime.PodSandboxFilter{ filter: &runtime.PodSandboxFilter{
State: &runtime.PodSandboxStateValue{ State: &runtime.PodSandboxStateValue{
State: runtime.PodSandboxState_SANDBOX_READY, State: runtime.PodSandboxState_SANDBOX_READY,
@ -180,20 +190,23 @@ func TestFilterSandboxes(t *testing.T) {
}, },
expect: []*runtime.PodSandbox{testSandboxes[0], testSandboxes[2]}, expect: []*runtime.PodSandbox{testSandboxes[0], testSandboxes[2]},
}, },
"label filter": { {
desc: "label filter",
filter: &runtime.PodSandboxFilter{ filter: &runtime.PodSandboxFilter{
LabelSelector: map[string]string{"a": "b"}, LabelSelector: map[string]string{"a": "b"},
}, },
expect: []*runtime.PodSandbox{testSandboxes[1]}, expect: []*runtime.PodSandbox{testSandboxes[1]},
}, },
"mixed filter not matched": { {
desc: "mixed filter not matched",
filter: &runtime.PodSandboxFilter{ filter: &runtime.PodSandboxFilter{
Id: "1", Id: "1",
LabelSelector: map[string]string{"a": "b"}, LabelSelector: map[string]string{"a": "b"},
}, },
expect: []*runtime.PodSandbox{}, expect: []*runtime.PodSandbox{},
}, },
"mixed filter matched": { {
desc: "mixed filter matched",
filter: &runtime.PodSandboxFilter{ filter: &runtime.PodSandboxFilter{
State: &runtime.PodSandboxStateValue{ State: &runtime.PodSandboxStateValue{
State: runtime.PodSandboxState_SANDBOX_READY, State: runtime.PodSandboxState_SANDBOX_READY,
@ -203,9 +216,10 @@ func TestFilterSandboxes(t *testing.T) {
expect: []*runtime.PodSandbox{testSandboxes[2]}, expect: []*runtime.PodSandbox{testSandboxes[2]},
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
filtered := c.filterCRISandboxes(testSandboxes, test.filter) filtered := c.filterCRISandboxes(testSandboxes, test.filter)
assert.Equal(t, test.expect, filtered, desc) assert.Equal(t, test.expect, filtered, test.desc)
}) })
} }
} }

View File

@ -27,12 +27,16 @@ import (
) )
func TestToCNIPortMappings(t *testing.T) { func TestToCNIPortMappings(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
criPortMappings []*runtime.PortMapping criPortMappings []*runtime.PortMapping
cniPortMappings []cni.PortMapping cniPortMappings []cni.PortMapping
}{ }{
"empty CRI port mapping should map to empty CNI port mapping": {}, {
"CRI port mapping should be converted to CNI port mapping properly": { desc: "empty CRI port mapping should map to empty CNI port mapping",
},
{
desc: "CRI port mapping should be converted to CNI port mapping properly",
criPortMappings: []*runtime.PortMapping{ criPortMappings: []*runtime.PortMapping{
{ {
Protocol: runtime.Protocol_UDP, Protocol: runtime.Protocol_UDP,
@ -74,7 +78,8 @@ func TestToCNIPortMappings(t *testing.T) {
}, },
}, },
}, },
"CRI port mapping without host port should be skipped": { {
desc: "CRI port mapping without host port should be skipped",
criPortMappings: []*runtime.PortMapping{ criPortMappings: []*runtime.PortMapping{
{ {
Protocol: runtime.Protocol_UDP, Protocol: runtime.Protocol_UDP,
@ -97,7 +102,8 @@ func TestToCNIPortMappings(t *testing.T) {
}, },
}, },
}, },
"CRI port mapping with unsupported protocol should be skipped": { {
desc: "CRI port mapping with unsupported protocol should be skipped",
criPortMappings: []*runtime.PortMapping{ criPortMappings: []*runtime.PortMapping{
{ {
Protocol: runtime.Protocol_TCP, Protocol: runtime.Protocol_TCP,
@ -116,54 +122,62 @@ func TestToCNIPortMappings(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
assert.Equal(t, test.cniPortMappings, toCNIPortMappings(test.criPortMappings)) assert.Equal(t, test.cniPortMappings, toCNIPortMappings(test.criPortMappings))
}) })
} }
} }
func TestSelectPodIP(t *testing.T) { func TestSelectPodIP(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
ips []string ips []string
expectedIP string expectedIP string
expectedAdditionalIPs []string expectedAdditionalIPs []string
pref string pref string
}{ }{
"ipv4 should be picked even if ipv6 comes first": { {
desc: "ipv4 should be picked even if ipv6 comes first",
ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"}, ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"},
expectedIP: "192.168.17.43", expectedIP: "192.168.17.43",
expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334"}, expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334"},
}, },
"ipv6 should be picked even if ipv4 comes first": { {
desc: "ipv6 should be picked even if ipv4 comes first",
ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"}, ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"},
expectedIP: "2001:db8:85a3::8a2e:370:7334", expectedIP: "2001:db8:85a3::8a2e:370:7334",
expectedAdditionalIPs: []string{"192.168.17.43"}, expectedAdditionalIPs: []string{"192.168.17.43"},
pref: "ipv6", pref: "ipv6",
}, },
"order should reflect ip selection": { {
desc: "order should reflect ip selection",
ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"}, ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"},
expectedIP: "2001:db8:85a3::8a2e:370:7334", expectedIP: "2001:db8:85a3::8a2e:370:7334",
expectedAdditionalIPs: []string{"192.168.17.43"}, expectedAdditionalIPs: []string{"192.168.17.43"},
pref: "cni", pref: "cni",
}, },
{
"ipv4 should be picked when there is only ipv4": { desc: "ipv4 should be picked when there is only ipv4",
ips: []string{"192.168.17.43"}, ips: []string{"192.168.17.43"},
expectedIP: "192.168.17.43", expectedIP: "192.168.17.43",
expectedAdditionalIPs: nil, expectedAdditionalIPs: nil,
}, },
"ipv6 should be picked when there is no ipv4": { {
desc: "ipv6 should be picked when there is no ipv4",
ips: []string{"2001:db8:85a3::8a2e:370:7334"}, ips: []string{"2001:db8:85a3::8a2e:370:7334"},
expectedIP: "2001:db8:85a3::8a2e:370:7334", expectedIP: "2001:db8:85a3::8a2e:370:7334",
expectedAdditionalIPs: nil, expectedAdditionalIPs: nil,
}, },
"the first ipv4 should be picked when there are multiple ipv4": { // unlikely to happen {
desc: "the first ipv4 should be picked when there are multiple ipv4", // unlikely to happen
ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43", "2001:db8:85a3::8a2e:370:7335", "192.168.17.45"}, ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43", "2001:db8:85a3::8a2e:370:7335", "192.168.17.45"},
expectedIP: "192.168.17.43", expectedIP: "192.168.17.43",
expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334", "2001:db8:85a3::8a2e:370:7335", "192.168.17.45"}, expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334", "2001:db8:85a3::8a2e:370:7335", "192.168.17.45"},
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
var ipConfigs []*cni.IPConfig var ipConfigs []*cni.IPConfig
for _, ip := range test.ips { for _, ip := range test.ips {
ipConfigs = append(ipConfigs, &cni.IPConfig{ ipConfigs = append(ipConfigs, &cni.IPConfig{

View File

@ -33,20 +33,23 @@ func TestGetUsageNanoCores(t *testing.T) {
secondAfterTimeStamp := timestamp.Add(time.Second) secondAfterTimeStamp := timestamp.Add(time.Second)
ID := "ID" ID := "ID"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
firstCPUValue uint64 firstCPUValue uint64
secondCPUValue uint64 secondCPUValue uint64
expectedNanoCoreUsageFirst uint64 expectedNanoCoreUsageFirst uint64
expectedNanoCoreUsageSecond uint64 expectedNanoCoreUsageSecond uint64
}{ }{
"metrics": { {
desc: "metrics",
firstCPUValue: 50, firstCPUValue: 50,
secondCPUValue: 500, secondCPUValue: 500,
expectedNanoCoreUsageFirst: 0, expectedNanoCoreUsageFirst: 0,
expectedNanoCoreUsageSecond: 450, expectedNanoCoreUsageSecond: 450,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
container, err := containerstore.NewContainer( container, err := containerstore.NewContainer(
containerstore.Metadata{ID: ID}, containerstore.Metadata{ID: ID},
) )
@ -85,7 +88,8 @@ func Test_criService_podSandboxStats(t *testing.T) {
UsageNanoCores uint64 UsageNanoCores uint64
WorkingSetBytes uint64 WorkingSetBytes uint64
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
metrics map[string]*wstats.Statistics metrics map[string]*wstats.Statistics
sandbox sandboxstore.Sandbox sandbox sandboxstore.Sandbox
containers []containerstore.Container containers []containerstore.Container
@ -93,7 +97,8 @@ func Test_criService_podSandboxStats(t *testing.T) {
expectedContainerStats []expectedStats expectedContainerStats []expectedStats
expectError bool expectError bool
}{ }{
"no metrics found should return error": { {
desc: "no metrics found should return error",
metrics: map[string]*wstats.Statistics{}, metrics: map[string]*wstats.Statistics{},
sandbox: sandboxstore.Sandbox{}, sandbox: sandboxstore.Sandbox{},
containers: []containerstore.Container{}, containers: []containerstore.Container{},
@ -101,7 +106,8 @@ func Test_criService_podSandboxStats(t *testing.T) {
expectedContainerStats: []expectedStats{}, expectedContainerStats: []expectedStats{},
expectError: true, expectError: true,
}, },
"pod stats will include the container stats": { {
desc: "pod stats will include the container stats",
metrics: map[string]*wstats.Statistics{ metrics: map[string]*wstats.Statistics{
"c1": { "c1": {
Container: windowsStat(currentStatsTimestamp, 200, 20), Container: windowsStat(currentStatsTimestamp, 200, 20),
@ -128,7 +134,8 @@ func Test_criService_podSandboxStats(t *testing.T) {
}, },
expectError: false, expectError: false,
}, },
"pod with existing stats will have usagenanocores totalled across pods and containers": { {
desc: "pod with existing stats will have usagenanocores totalled across pods and containers",
metrics: map[string]*wstats.Statistics{ metrics: map[string]*wstats.Statistics{
"c1": { "c1": {
Container: windowsStat(currentStatsTimestamp, 400, 20), Container: windowsStat(currentStatsTimestamp, 400, 20),
@ -161,7 +168,8 @@ func Test_criService_podSandboxStats(t *testing.T) {
}, },
expectError: false, expectError: false,
}, },
"pod sandbox with nil stats still works (hostprocess container scenario)": { {
desc: "pod sandbox with nil stats still works (hostprocess container scenario)",
metrics: map[string]*wstats.Statistics{ metrics: map[string]*wstats.Statistics{
"c1": { "c1": {
Container: windowsStat(currentStatsTimestamp, 400, 20), Container: windowsStat(currentStatsTimestamp, 400, 20),
@ -193,7 +201,8 @@ func Test_criService_podSandboxStats(t *testing.T) {
expectError: false, expectError: false,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
actualPodStats, actualContainerStats, err := c.toPodSandboxStats(test.sandbox, test.metrics, test.containers, currentStatsTimestamp) actualPodStats, actualContainerStats, err := c.toPodSandboxStats(test.sandbox, test.metrics, test.containers, currentStatsTimestamp)
if test.expectError { if test.expectError {
assert.NotNil(t, err) assert.NotNil(t, err)
@ -240,25 +249,29 @@ func Test_criService_saveSandBoxMetrics(t *testing.T) {
timestamp := time.Now() timestamp := time.Now()
containerID := "c1" containerID := "c1"
sandboxID := "s1" sandboxID := "s1"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
sandboxStats *runtime.PodSandboxStats sandboxStats *runtime.PodSandboxStats
expectError bool expectError bool
expectedSandboxvalue *stats.ContainerStats expectedSandboxvalue *stats.ContainerStats
expectedContainervalue *stats.ContainerStats expectedContainervalue *stats.ContainerStats
}{ }{
"if sandboxstats is nil then skip ": { {
desc: "if sandboxstats is nil then skip ",
sandboxStats: nil, sandboxStats: nil,
expectError: false, expectError: false,
expectedSandboxvalue: nil, expectedSandboxvalue: nil,
}, },
"if sandboxstats.windows is nil then skip": { {
desc: "if sandboxstats.windows is nil then skip",
sandboxStats: &runtime.PodSandboxStats{ sandboxStats: &runtime.PodSandboxStats{
Windows: nil, Windows: nil,
}, },
expectError: false, expectError: false,
expectedSandboxvalue: nil, expectedSandboxvalue: nil,
}, },
"if sandboxstats.windows.cpu is nil then skip": { {
desc: "if sandboxstats.windows.cpu is nil then skip",
sandboxStats: &runtime.PodSandboxStats{ sandboxStats: &runtime.PodSandboxStats{
Windows: &runtime.WindowsPodSandboxStats{ Windows: &runtime.WindowsPodSandboxStats{
Cpu: nil, Cpu: nil,
@ -267,7 +280,8 @@ func Test_criService_saveSandBoxMetrics(t *testing.T) {
expectError: false, expectError: false,
expectedSandboxvalue: nil, expectedSandboxvalue: nil,
}, },
"if sandboxstats.windows.cpu.UsageCoreNanoSeconds is nil then skip": { {
desc: "if sandboxstats.windows.cpu.UsageCoreNanoSeconds is nil then skip",
sandboxStats: &runtime.PodSandboxStats{ sandboxStats: &runtime.PodSandboxStats{
Windows: &runtime.WindowsPodSandboxStats{ Windows: &runtime.WindowsPodSandboxStats{
Cpu: &runtime.WindowsCpuUsage{ Cpu: &runtime.WindowsCpuUsage{
@ -278,7 +292,8 @@ func Test_criService_saveSandBoxMetrics(t *testing.T) {
expectError: false, expectError: false,
expectedSandboxvalue: nil, expectedSandboxvalue: nil,
}, },
"Stats for containers that have cpu nil are skipped": { {
desc: "Stats for containers that have cpu nil are skipped",
sandboxStats: &runtime.PodSandboxStats{ sandboxStats: &runtime.PodSandboxStats{
Windows: &runtime.WindowsPodSandboxStats{ Windows: &runtime.WindowsPodSandboxStats{
Cpu: &runtime.WindowsCpuUsage{ Cpu: &runtime.WindowsCpuUsage{
@ -300,7 +315,8 @@ func Test_criService_saveSandBoxMetrics(t *testing.T) {
}, },
expectedContainervalue: nil, expectedContainervalue: nil,
}, },
"Stats for containers that have UsageCoreNanoSeconds nil are skipped": { {
desc: "Stats for containers that have UsageCoreNanoSeconds nil are skipped",
sandboxStats: &runtime.PodSandboxStats{ sandboxStats: &runtime.PodSandboxStats{
Windows: &runtime.WindowsPodSandboxStats{ Windows: &runtime.WindowsPodSandboxStats{
Cpu: &runtime.WindowsCpuUsage{ Cpu: &runtime.WindowsCpuUsage{
@ -324,7 +340,8 @@ func Test_criService_saveSandBoxMetrics(t *testing.T) {
}, },
expectedContainervalue: nil, expectedContainervalue: nil,
}, },
"Stats are updated for sandbox and containers": { {
desc: "Stats are updated for sandbox and containers",
sandboxStats: &runtime.PodSandboxStats{ sandboxStats: &runtime.PodSandboxStats{
Windows: &runtime.WindowsPodSandboxStats{ Windows: &runtime.WindowsPodSandboxStats{
Cpu: &runtime.WindowsCpuUsage{ Cpu: &runtime.WindowsCpuUsage{
@ -353,7 +370,8 @@ func Test_criService_saveSandBoxMetrics(t *testing.T) {
}, },
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
c.sandboxStore.Add(sandboxstore.Sandbox{ c.sandboxStore.Add(sandboxstore.Sandbox{
Metadata: sandboxstore.Metadata{ID: sandboxID}, Metadata: sandboxstore.Metadata{ID: sandboxID},

View File

@ -87,24 +87,29 @@ func TestPodSandboxStatus(t *testing.T) {
Annotations: config.GetAnnotations(), Annotations: config.GetAnnotations(),
RuntimeHandler: "test-runtime-handler", RuntimeHandler: "test-runtime-handler",
} }
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
state string state string
expectedState runtime.PodSandboxState expectedState runtime.PodSandboxState
}{ }{
"sandbox state ready": { {
desc: "sandbox state ready",
state: sandboxstore.StateReady.String(), state: sandboxstore.StateReady.String(),
expectedState: runtime.PodSandboxState_SANDBOX_READY, expectedState: runtime.PodSandboxState_SANDBOX_READY,
}, },
"sandbox state not ready": { {
desc: "sandbox state not ready",
state: sandboxstore.StateNotReady.String(), state: sandboxstore.StateNotReady.String(),
expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY,
}, },
"sandbox state unknown": { {
desc: "sandbox state unknown",
state: sandboxstore.StateUnknown.String(), state: sandboxstore.StateUnknown.String(),
expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
expected.State = test.expectedState expected.State = test.expectedState
got := toCRISandboxStatus(metadata, test.state, createdAt, ip, additionalIPs) got := toCRISandboxStatus(metadata, test.state, createdAt, ip, additionalIPs)
assert.Equal(t, expected, got) assert.Equal(t, expected, got)

View File

@ -28,30 +28,35 @@ import (
func TestWaitSandboxStop(t *testing.T) { func TestWaitSandboxStop(t *testing.T) {
id := "test-id" id := "test-id"
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
state sandboxstore.State state sandboxstore.State
cancel bool cancel bool
timeout time.Duration timeout time.Duration
expectErr bool expectErr bool
}{ }{
"should return error if timeout exceeds": { {
desc: "should return error if timeout exceeds",
state: sandboxstore.StateReady, state: sandboxstore.StateReady,
timeout: 200 * time.Millisecond, timeout: 200 * time.Millisecond,
expectErr: true, expectErr: true,
}, },
"should return error if context is cancelled": { {
desc: "should return error if context is cancelled",
state: sandboxstore.StateReady, state: sandboxstore.StateReady,
timeout: time.Hour, timeout: time.Hour,
cancel: true, cancel: true,
expectErr: true, expectErr: true,
}, },
"should not return error if sandbox is stopped before timeout": { {
desc: "should not return error if sandbox is stopped before timeout",
state: sandboxstore.StateNotReady, state: sandboxstore.StateNotReady,
timeout: time.Hour, timeout: time.Hour,
expectErr: false, expectErr: false,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
c := newTestCRIService() c := newTestCRIService()
sandbox := sandboxstore.NewSandbox( sandbox := sandboxstore.NewSandbox(
sandboxstore.Metadata{ID: id}, sandboxstore.Metadata{ID: id},
@ -69,7 +74,7 @@ func TestWaitSandboxStop(t *testing.T) {
ctx = timeoutCtx ctx = timeoutCtx
} }
err := c.waitSandboxStop(ctx, sandbox) err := c.waitSandboxStop(ctx, sandbox)
assert.Equal(t, test.expectErr, err != nil, desc) assert.Equal(t, test.expectErr, err != nil, test.desc)
}) })
} }
} }

View File

@ -24,12 +24,14 @@ import (
) )
func TestValidateStreamServer(t *testing.T) { func TestValidateStreamServer(t *testing.T) {
for desc, test := range map[string]struct { for _, test := range []struct {
desc string
*criService *criService
tlsMode streamListenerMode tlsMode streamListenerMode
expectErr bool expectErr bool
}{ }{
"should pass with default withoutTLS": { {
desc: "should pass with default withoutTLS",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.DefaultConfig(), PluginConfig: config.DefaultConfig(),
@ -38,7 +40,8 @@ func TestValidateStreamServer(t *testing.T) {
tlsMode: withoutTLS, tlsMode: withoutTLS,
expectErr: false, expectErr: false,
}, },
"should pass with x509KeyPairTLS": { {
desc: "should pass with x509KeyPairTLS",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.PluginConfig{ PluginConfig: config.PluginConfig{
@ -53,7 +56,8 @@ func TestValidateStreamServer(t *testing.T) {
tlsMode: x509KeyPairTLS, tlsMode: x509KeyPairTLS,
expectErr: false, expectErr: false,
}, },
"should pass with selfSign": { {
desc: "should pass with selfSign",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.PluginConfig{ PluginConfig: config.PluginConfig{
@ -64,7 +68,8 @@ func TestValidateStreamServer(t *testing.T) {
tlsMode: selfSignTLS, tlsMode: selfSignTLS,
expectErr: false, expectErr: false,
}, },
"should return error with X509 keypair but not EnableTLSStreaming": { {
desc: "should return error with X509 keypair but not EnableTLSStreaming",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.PluginConfig{ PluginConfig: config.PluginConfig{
@ -79,7 +84,8 @@ func TestValidateStreamServer(t *testing.T) {
tlsMode: -1, tlsMode: -1,
expectErr: true, expectErr: true,
}, },
"should return error with X509 TLSCertFile empty": { {
desc: "should return error with X509 TLSCertFile empty",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.PluginConfig{ PluginConfig: config.PluginConfig{
@ -94,7 +100,8 @@ func TestValidateStreamServer(t *testing.T) {
tlsMode: -1, tlsMode: -1,
expectErr: true, expectErr: true,
}, },
"should return error with X509 TLSKeyFile empty": { {
desc: "should return error with X509 TLSKeyFile empty",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.PluginConfig{ PluginConfig: config.PluginConfig{
@ -109,7 +116,8 @@ func TestValidateStreamServer(t *testing.T) {
tlsMode: -1, tlsMode: -1,
expectErr: true, expectErr: true,
}, },
"should return error without EnableTLSStreaming and only TLSCertFile set": { {
desc: "should return error without EnableTLSStreaming and only TLSCertFile set",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.PluginConfig{ PluginConfig: config.PluginConfig{
@ -124,7 +132,8 @@ func TestValidateStreamServer(t *testing.T) {
tlsMode: -1, tlsMode: -1,
expectErr: true, expectErr: true,
}, },
"should return error without EnableTLSStreaming and only TLSKeyFile set": { {
desc: "should return error without EnableTLSStreaming and only TLSKeyFile set",
criService: &criService{ criService: &criService{
config: config.Config{ config: config.Config{
PluginConfig: config.PluginConfig{ PluginConfig: config.PluginConfig{
@ -140,7 +149,8 @@ func TestValidateStreamServer(t *testing.T) {
expectErr: true, expectErr: true,
}, },
} { } {
t.Run(desc, func(t *testing.T) { test := test
t.Run(test.desc, func(t *testing.T) {
tlsMode, err := getStreamListenerMode(test.criService) tlsMode, err := getStreamListenerMode(test.criService)
if test.expectErr { if test.expectErr {
assert.Error(t, err) assert.Error(t, err)

View File

@ -70,29 +70,35 @@ func TestUpdateRuntimeConfig(t *testing.T) {
}` }`
) )
for name, test := range map[string]struct { for _, test := range []struct {
name string
noTemplate bool noTemplate bool
emptyCIDR bool emptyCIDR bool
networkReady bool networkReady bool
expectCNIConfig bool expectCNIConfig bool
}{ }{
"should not generate cni config if cidr is empty": { {
name: "should not generate cni config if cidr is empty",
emptyCIDR: true, emptyCIDR: true,
expectCNIConfig: false, expectCNIConfig: false,
}, },
"should not generate cni config if template file is not specified": { {
name: "should not generate cni config if template file is not specified",
noTemplate: true, noTemplate: true,
expectCNIConfig: false, expectCNIConfig: false,
}, },
"should not generate cni config if network is ready": { {
name: "should not generate cni config if network is ready",
networkReady: true, networkReady: true,
expectCNIConfig: false, expectCNIConfig: false,
}, },
"should generate cni config if template is specified and cidr is provided": { {
name: "should generate cni config if template is specified and cidr is provided",
expectCNIConfig: true, expectCNIConfig: true,
}, },
} { } {
t.Run(name, func(t *testing.T) { test := test
t.Run(test.name, func(t *testing.T) {
testDir := t.TempDir() testDir := t.TempDir()
templateName := filepath.Join(testDir, "template") templateName := filepath.Join(testDir, "template")
err := os.WriteFile(templateName, []byte(testTemplate), 0666) err := os.WriteFile(templateName, []byte(testTemplate), 0666)