github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/configs/config_test.go (about) 1 package configs_test 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "reflect" 8 "testing" 9 "time" 10 11 "github.com/opencontainers/runc/libcontainer/configs" 12 "github.com/opencontainers/runtime-spec/specs-go" 13 ) 14 15 func TestUnmarshalHooks(t *testing.T) { 16 timeout := time.Second 17 18 hookCmd := configs.NewCommandHook(configs.Command{ 19 Path: "/var/vcap/hooks/hook", 20 Args: []string{"--pid=123"}, 21 Env: []string{"FOO=BAR"}, 22 Dir: "/var/vcap", 23 Timeout: &timeout, 24 }) 25 26 hookJson, err := json.Marshal(hookCmd) 27 if err != nil { 28 t.Fatal(err) 29 } 30 31 for _, hookName := range configs.HookNameList { 32 hooks := configs.Hooks{} 33 err = hooks.UnmarshalJSON([]byte(fmt.Sprintf(`{"%s" :[%s]}`, hookName, hookJson))) 34 if err != nil { 35 t.Fatal(err) 36 } 37 38 if !reflect.DeepEqual(hooks[hookName], configs.HookList{hookCmd}) { 39 t.Errorf("Expected %s to equal %+v but it was %+v", hookName, hookCmd, hooks[hookName]) 40 } 41 } 42 } 43 44 func TestUnmarshalHooksWithInvalidData(t *testing.T) { 45 hook := configs.Hooks{} 46 err := hook.UnmarshalJSON([]byte(`{invalid-json}`)) 47 if err == nil { 48 t.Error("Expected error to occur but it was nil") 49 } 50 } 51 52 func TestMarshalHooks(t *testing.T) { 53 timeout := time.Second 54 55 hookCmd := configs.NewCommandHook(configs.Command{ 56 Path: "/var/vcap/hooks/hook", 57 Args: []string{"--pid=123"}, 58 Env: []string{"FOO=BAR"}, 59 Dir: "/var/vcap", 60 Timeout: &timeout, 61 }) 62 63 hook := configs.Hooks{ 64 configs.Prestart: configs.HookList{hookCmd}, 65 configs.CreateRuntime: configs.HookList{hookCmd}, 66 configs.CreateContainer: configs.HookList{hookCmd}, 67 configs.StartContainer: configs.HookList{hookCmd}, 68 configs.Poststart: configs.HookList{hookCmd}, 69 configs.Poststop: configs.HookList{hookCmd}, 70 } 71 hooks, err := hook.MarshalJSON() 72 if err != nil { 73 t.Fatal(err) 74 } 75 76 // Note Marshal seems to output fields in alphabetical order 77 hookCmdJson := `[{"path":"/var/vcap/hooks/hook","args":["--pid=123"],"env":["FOO=BAR"],"dir":"/var/vcap","timeout":1000000000}]` 78 h := fmt.Sprintf(`{"createContainer":%[1]s,"createRuntime":%[1]s,"poststart":%[1]s,"poststop":%[1]s,"prestart":%[1]s,"startContainer":%[1]s}`, hookCmdJson) 79 if string(hooks) != h { 80 t.Errorf("Expected hooks %s to equal %s", string(hooks), h) 81 } 82 } 83 84 func TestMarshalUnmarshalHooks(t *testing.T) { 85 timeout := time.Second 86 87 hookCmd := configs.NewCommandHook(configs.Command{ 88 Path: "/var/vcap/hooks/hook", 89 Args: []string{"--pid=123"}, 90 Env: []string{"FOO=BAR"}, 91 Dir: "/var/vcap", 92 Timeout: &timeout, 93 }) 94 95 hook := configs.Hooks{ 96 configs.Prestart: configs.HookList{hookCmd}, 97 configs.CreateRuntime: configs.HookList{hookCmd}, 98 configs.CreateContainer: configs.HookList{hookCmd}, 99 configs.StartContainer: configs.HookList{hookCmd}, 100 configs.Poststart: configs.HookList{hookCmd}, 101 configs.Poststop: configs.HookList{hookCmd}, 102 } 103 hooks, err := hook.MarshalJSON() 104 if err != nil { 105 t.Fatal(err) 106 } 107 108 umMhook := configs.Hooks{} 109 err = umMhook.UnmarshalJSON(hooks) 110 if err != nil { 111 t.Fatal(err) 112 } 113 if !reflect.DeepEqual(umMhook, hook) { 114 t.Errorf("Expected hooks to be equal after mashaling -> unmarshaling them: %+v, %+v", umMhook, hook) 115 } 116 } 117 118 func TestMarshalHooksWithUnexpectedType(t *testing.T) { 119 fHook := configs.NewFunctionHook(func(*specs.State) error { 120 return nil 121 }) 122 hook := configs.Hooks{ 123 configs.CreateRuntime: configs.HookList{fHook}, 124 } 125 hooks, err := hook.MarshalJSON() 126 if err != nil { 127 t.Fatal(err) 128 } 129 130 h := `{"createContainer":null,"createRuntime":null,"poststart":null,"poststop":null,"prestart":null,"startContainer":null}` 131 if string(hooks) != h { 132 t.Errorf("Expected hooks %s to equal %s", string(hooks), h) 133 } 134 } 135 136 func TestFuncHookRun(t *testing.T) { 137 state := &specs.State{ 138 Version: "1", 139 ID: "1", 140 Status: "created", 141 Pid: 1, 142 Bundle: "/bundle", 143 } 144 145 fHook := configs.NewFunctionHook(func(s *specs.State) error { 146 if !reflect.DeepEqual(state, s) { 147 return fmt.Errorf("expected state %+v to equal %+v", state, s) 148 } 149 return nil 150 }) 151 152 err := fHook.Run(state) 153 if err != nil { 154 t.Fatal(err) 155 } 156 } 157 158 func TestCommandHookRun(t *testing.T) { 159 state := &specs.State{ 160 Version: "1", 161 ID: "1", 162 Status: "created", 163 Pid: 1, 164 Bundle: "/bundle", 165 } 166 167 stateJson, err := json.Marshal(state) 168 if err != nil { 169 t.Fatal(err) 170 } 171 172 verifyCommandTemplate := `#!/bin/sh 173 if [ "$1" != "testarg" ]; then 174 echo "Bad value for $1. Expected 'testarg', found '$1'" 175 exit 1 176 fi 177 if [ -z "$FOO" ] || [ "$FOO" != BAR ]; then 178 echo "Bad value for FOO. Expected 'BAR', found '$FOO'" 179 exit 1 180 fi 181 expectedJson=%q 182 read JSON 183 if [ "$JSON" != "$expectedJson" ]; then 184 echo "Bad JSON received. Expected '$expectedJson', found '$JSON'" 185 exit 1 186 fi 187 exit 0 188 ` 189 verifyCommand := fmt.Sprintf(verifyCommandTemplate, stateJson) 190 filename := "/tmp/runc-hooktest.sh" 191 os.Remove(filename) 192 if err := os.WriteFile(filename, []byte(verifyCommand), 0o700); err != nil { 193 t.Fatalf("Failed to create tmp file: %v", err) 194 } 195 defer os.Remove(filename) 196 197 cmdHook := configs.NewCommandHook(configs.Command{ 198 Path: filename, 199 Args: []string{filename, "testarg"}, 200 Env: []string{"FOO=BAR"}, 201 Dir: "/", 202 }) 203 204 if err := cmdHook.Run(state); err != nil { 205 t.Errorf(fmt.Sprintf("Expected error to not occur but it was %+v", err)) 206 } 207 } 208 209 func TestCommandHookRunTimeout(t *testing.T) { 210 state := &specs.State{ 211 Version: "1", 212 ID: "1", 213 Status: "created", 214 Pid: 1, 215 Bundle: "/bundle", 216 } 217 timeout := 100 * time.Millisecond 218 219 cmdHook := configs.NewCommandHook(configs.Command{ 220 Path: "/bin/sleep", 221 Args: []string{"/bin/sleep", "1"}, 222 Timeout: &timeout, 223 }) 224 225 if err := cmdHook.Run(state); err == nil { 226 t.Error("Expected error to occur but it was nil") 227 } 228 }