gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/runsc/cmd/install_test.go (about) 1 // Copyright 2022 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "testing" 21 22 "github.com/google/go-cmp/cmp" 23 ) 24 25 type runtimeDef struct { 26 path string 27 runtimeArgs []string 28 } 29 30 func (r *runtimeDef) MarshalJSON() ([]byte, error) { 31 args, err := json.Marshal(r.runtimeArgs) 32 if err != nil { 33 return nil, err 34 } 35 str := fmt.Sprintf(`{"path": "%s", "runtimeArgs":%s}`, r.path, args) 36 return []byte(str), nil 37 } 38 39 func (r *runtimeDef) UnmarshalJSON(data []byte) error { 40 var dat map[string]any 41 if err := json.Unmarshal(data, &dat); err != nil { 42 return err 43 } 44 if p, ok := dat["path"]; ok { 45 r.path = p.(string) 46 } 47 if p, ok := dat["runtimeArgs"]; ok { 48 r.runtimeArgs = p.([]string) 49 } 50 return nil 51 } 52 53 var defaultInput = map[string]any{ 54 "runtimes": map[string]*runtimeDef{ 55 "runtime1": &runtimeDef{ 56 path: "runtime1_path", 57 runtimeArgs: []string{"some", "args"}, 58 }, 59 "other runtime": &runtimeDef{ 60 path: "other_runtime_path", 61 runtimeArgs: []string{"some", "other", "args"}, 62 }, 63 "myRuntime": &runtimeDef{ 64 path: "myRuntimePath", 65 runtimeArgs: []string{"super", "cool", "args"}, 66 }, 67 }, 68 "exec-opts": []string{"some-cgroup-driver=something", "native.cgroupdriver=init_driver"}, 69 } 70 71 func TestInstall(t *testing.T) { 72 73 for _, tc := range []struct { 74 name string 75 i *Install 76 input map[string]any 77 output map[string]any 78 }{ 79 { 80 name: "clobber", 81 i: &Install{ 82 Runtime: "myRuntime", 83 Experimental: true, 84 Clobber: true, 85 CgroupDriver: "my_driver", 86 executablePath: "some_runsc_path", 87 runtimeArgs: []string{"new", "cool", "args"}, 88 }, 89 input: defaultInput, 90 output: map[string]any{ 91 "runtimes": map[string]*runtimeDef{ 92 "runtime1": &runtimeDef{ 93 path: "runtime1_path", 94 runtimeArgs: []string{"some", "args"}, 95 }, 96 "other runtime": &runtimeDef{ 97 path: "other_runtime_path", 98 runtimeArgs: []string{"some", "other", "args"}, 99 }, 100 "myRuntime": &runtimeDef{ 101 path: "some_runsc_path", 102 runtimeArgs: []string{"new", "cool", "args"}, 103 }, 104 }, 105 "exec-opts": []string{"some-cgroup-driver=something", "native.cgroupdriver=my_driver"}, 106 "experimental": true, 107 }, 108 }, 109 { 110 name: "no clobber", 111 i: &Install{ 112 Runtime: "myRuntime", 113 Experimental: true, 114 Clobber: false, 115 CgroupDriver: "my_driver", 116 executablePath: "some_runsc_path", 117 runtimeArgs: []string{"new", "cool", "args"}, 118 }, 119 input: defaultInput, 120 output: map[string]any{ 121 "runtimes": map[string]*runtimeDef{ 122 "runtime1": &runtimeDef{ 123 path: "runtime1_path", 124 runtimeArgs: []string{"some", "args"}, 125 }, 126 "other runtime": &runtimeDef{ 127 path: "other_runtime_path", 128 runtimeArgs: []string{"some", "other", "args"}, 129 }, 130 "myRuntime": &runtimeDef{ 131 path: "myRuntimePath", 132 runtimeArgs: []string{"super", "cool", "args"}, 133 }, 134 }, 135 "exec-opts": []string{"some-cgroup-driver=something", "native.cgroupdriver=init_driver", "native.cgroupdriver=my_driver"}, 136 "experimental": true, 137 }, 138 }, 139 { 140 name: "new runtime", 141 i: &Install{ 142 Runtime: "newRuntime", 143 Experimental: true, 144 executablePath: "newPath", 145 runtimeArgs: []string{"new", "cool", "args"}, 146 }, 147 input: defaultInput, 148 output: map[string]any{ 149 "runtimes": map[string]*runtimeDef{ 150 "runtime1": &runtimeDef{ 151 path: "runtime1_path", 152 runtimeArgs: []string{"some", "args"}, 153 }, 154 "newRuntime": &runtimeDef{ 155 path: "newPath", 156 runtimeArgs: []string{"new", "cool", "args"}, 157 }, 158 "other runtime": &runtimeDef{ 159 path: "other_runtime_path", 160 runtimeArgs: []string{"some", "other", "args"}, 161 }, 162 "myRuntime": &runtimeDef{ 163 path: "myRuntimePath", 164 runtimeArgs: []string{"super", "cool", "args"}, 165 }, 166 }, 167 "exec-opts": []string{"some-cgroup-driver=something", "native.cgroupdriver=init_driver"}, 168 "experimental": true, 169 }, 170 }, 171 } { 172 t.Run(tc.name, func(t *testing.T) { 173 174 mockRead := func(_ string) ([]byte, error) { 175 return json.MarshalIndent(tc.input, "", " ") 176 } 177 178 got := []byte{} 179 mockWrite := func(c map[string]any, _ string) error { 180 res, err := json.MarshalIndent(c, "", " ") 181 if err != nil { 182 return err 183 } 184 got = res 185 return nil 186 } 187 188 rw := configReaderWriter{ 189 read: mockRead, 190 write: mockWrite, 191 } 192 193 if err := doInstallConfig(tc.i, rw); err != nil { 194 t.Fatalf("Error updating config: %v", err) 195 } 196 197 want, err := json.MarshalIndent(tc.output, "", " ") 198 if err != nil { 199 t.Fatalf("Failed to marshal output: %v", err) 200 } 201 202 if res := cmp.Diff(string(want), string(got)); res != "" { 203 t.Fatalf("Mismatch output (-want +got): %s", res) 204 } 205 }) 206 } 207 } 208 209 func TestUninstall(t *testing.T) { 210 for _, tc := range []struct { 211 name string 212 u *Uninstall 213 input map[string]any 214 output map[string]any 215 wantErr bool 216 }{ 217 { 218 name: "runtime found", 219 u: &Uninstall{ 220 Runtime: "other runtime", 221 }, 222 input: defaultInput, 223 output: map[string]any{ 224 "runtimes": map[string]*runtimeDef{ 225 "runtime1": &runtimeDef{ 226 path: "runtime1_path", 227 runtimeArgs: []string{"some", "args"}, 228 }, 229 "myRuntime": &runtimeDef{ 230 path: "myRuntimePath", 231 runtimeArgs: []string{"super", "cool", "args"}, 232 }, 233 }, 234 "exec-opts": []string{"some-cgroup-driver=something", "native.cgroupdriver=init_driver"}, 235 }, 236 }, 237 { 238 name: "runtime not found", 239 u: &Uninstall{ 240 Runtime: "not found runtime", 241 }, 242 input: defaultInput, 243 wantErr: true, 244 }, 245 } { 246 t.Run(tc.name, func(t *testing.T) { 247 mockRead := func(_ string) ([]byte, error) { 248 return json.MarshalIndent(tc.input, "", " ") 249 } 250 251 got := []byte{} 252 mockWrite := func(c map[string]any, _ string) error { 253 res, err := json.MarshalIndent(c, "", " ") 254 if err != nil { 255 return err 256 } 257 got = res 258 return nil 259 } 260 261 rw := configReaderWriter{ 262 read: mockRead, 263 write: mockWrite, 264 } 265 266 err := doUninstallConfig(tc.u, rw) 267 if tc.wantErr { 268 if err == nil { 269 t.Fatalf("Did not get an error when expected.") 270 } 271 return 272 } 273 if err != nil { 274 t.Fatalf("Error updating config: %v", err) 275 } 276 277 want, err := json.MarshalIndent(tc.output, "", " ") 278 if err != nil { 279 t.Fatalf("Failed to marshal output: %v", err) 280 } 281 if res := cmp.Diff(string(want), string(got)); res != "" { 282 t.Fatalf("Mismatch output (-want +got-): %s", res) 283 } 284 }) 285 } 286 }