github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/hooks/monitor_test.go (about) 1 package hooks 2 3 import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "testing" 10 "time" 11 12 rspec "github.com/opencontainers/runtime-spec/specs-go" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 func TestMonitorOneDirGood(t *testing.T) { 17 ctx, cancel := context.WithCancel(context.Background()) 18 dir, err := ioutil.TempDir("", "hooks-test-") 19 if err != nil { 20 t.Fatal(err) 21 } 22 defer os.RemoveAll(dir) 23 24 manager, err := New(ctx, []string{dir}, []string{}) 25 if err != nil { 26 t.Fatal(err) 27 } 28 29 sync := make(chan error, 2) 30 go manager.Monitor(ctx, sync) 31 err = <-sync 32 if err != nil { 33 t.Fatal(err) 34 } 35 36 jsonPath := filepath.Join(dir, "a.json") 37 38 t.Run("good-addition", func(t *testing.T) { 39 err = ioutil.WriteFile(jsonPath, []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\", \"poststart\", \"poststop\"]}", path)), 0644) 40 if err != nil { 41 t.Fatal(err) 42 } 43 44 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 45 46 config := &rspec.Spec{} 47 _, err = manager.Hooks(config, map[string]string{}, false) 48 if err != nil { 49 t.Fatal(err) 50 } 51 52 assert.Equal(t, &rspec.Hooks{ 53 Prestart: []rspec.Hook{ 54 { 55 Path: path, 56 }, 57 }, 58 Poststart: []rspec.Hook{ 59 { 60 Path: path, 61 }, 62 }, 63 Poststop: []rspec.Hook{ 64 { 65 Path: path, 66 }, 67 }, 68 }, config.Hooks) 69 }) 70 71 t.Run("good-removal", func(t *testing.T) { 72 err = os.Remove(jsonPath) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 78 79 config := &rspec.Spec{} 80 expected := config.Hooks 81 _, err = manager.Hooks(config, map[string]string{}, false) 82 if err != nil { 83 t.Fatal(err) 84 } 85 assert.Equal(t, expected, config.Hooks) 86 }) 87 88 t.Run("bad-addition", func(t *testing.T) { 89 err = ioutil.WriteFile(jsonPath, []byte("{\"version\": \"-1\"}"), 0644) 90 if err != nil { 91 t.Fatal(err) 92 } 93 94 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 95 96 config := &rspec.Spec{} 97 expected := config.Hooks 98 _, err = manager.Hooks(config, map[string]string{}, false) 99 if err != nil { 100 t.Fatal(err) 101 } 102 assert.Equal(t, expected, config.Hooks) 103 104 err = os.Remove(jsonPath) 105 if err != nil { 106 t.Fatal(err) 107 } 108 }) 109 110 cancel() 111 err = <-sync 112 assert.Equal(t, context.Canceled, err) 113 } 114 115 func TestMonitorTwoDirGood(t *testing.T) { 116 ctx, cancel := context.WithCancel(context.Background()) 117 primaryDir, err := ioutil.TempDir("", "hooks-test-primary-") 118 if err != nil { 119 t.Fatal(err) 120 } 121 defer os.RemoveAll(primaryDir) 122 123 fallbackDir, err := ioutil.TempDir("", "hooks-test-fallback-") 124 if err != nil { 125 t.Fatal(err) 126 } 127 defer os.RemoveAll(fallbackDir) 128 129 manager, err := New(ctx, []string{fallbackDir, primaryDir}, []string{}) 130 if err != nil { 131 t.Fatal(err) 132 } 133 134 sync := make(chan error, 2) 135 go manager.Monitor(ctx, sync) 136 err = <-sync 137 if err != nil { 138 t.Fatal(err) 139 } 140 141 fallbackPath := filepath.Join(fallbackDir, "a.json") 142 fallbackJSON := []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path)) 143 fallbackInjected := &rspec.Hooks{ 144 Prestart: []rspec.Hook{ 145 { 146 Path: path, 147 }, 148 }, 149 } 150 151 t.Run("good-fallback-addition", func(t *testing.T) { 152 err = ioutil.WriteFile(fallbackPath, fallbackJSON, 0644) 153 if err != nil { 154 t.Fatal(err) 155 } 156 157 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 158 159 config := &rspec.Spec{} 160 _, err = manager.Hooks(config, map[string]string{}, false) 161 if err != nil { 162 t.Fatal(err) 163 } 164 165 assert.Equal(t, fallbackInjected, config.Hooks) 166 }) 167 168 primaryPath := filepath.Join(primaryDir, "a.json") 169 primaryJSON := []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\", \"timeout\": 1}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path)) 170 one := 1 171 primaryInjected := &rspec.Hooks{ 172 Prestart: []rspec.Hook{ 173 { 174 Path: path, 175 Timeout: &one, 176 }, 177 }, 178 } 179 180 t.Run("good-primary-override", func(t *testing.T) { 181 err = ioutil.WriteFile(primaryPath, primaryJSON, 0644) 182 if err != nil { 183 t.Fatal(err) 184 } 185 186 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 187 188 config := &rspec.Spec{} 189 _, err = manager.Hooks(config, map[string]string{}, false) 190 if err != nil { 191 t.Fatal(err) 192 } 193 194 assert.Equal(t, primaryInjected, config.Hooks) 195 }) 196 197 t.Run("good-fallback-removal", func(t *testing.T) { 198 err = os.Remove(fallbackPath) 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 204 205 config := &rspec.Spec{} 206 _, err = manager.Hooks(config, map[string]string{}, false) 207 if err != nil { 208 t.Fatal(err) 209 } 210 assert.Equal(t, primaryInjected, config.Hooks) // masked by primary 211 }) 212 213 t.Run("good-fallback-restore", func(t *testing.T) { 214 err = ioutil.WriteFile(fallbackPath, fallbackJSON, 0644) 215 if err != nil { 216 t.Fatal(err) 217 } 218 219 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 220 221 config := &rspec.Spec{} 222 _, err = manager.Hooks(config, map[string]string{}, false) 223 if err != nil { 224 t.Fatal(err) 225 } 226 assert.Equal(t, primaryInjected, config.Hooks) // masked by primary 227 }) 228 229 primaryPath2 := filepath.Join(primaryDir, "0a.json") //0a because it will be before a.json alphabetically 230 231 t.Run("bad-primary-new-addition", func(t *testing.T) { 232 err = ioutil.WriteFile(primaryPath2, []byte("{\"version\": \"-1\"}"), 0644) 233 if err != nil { 234 t.Fatal(err) 235 } 236 237 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 238 239 config := &rspec.Spec{} 240 fmt.Println("expected: ", config.Hooks) 241 expected := primaryInjected // 0a.json is bad, a.json is still good 242 _, err = manager.Hooks(config, map[string]string{}, false) 243 fmt.Println("actual: ", config.Hooks) 244 if err != nil { 245 t.Fatal(err) 246 } 247 assert.Equal(t, expected, config.Hooks) 248 }) 249 250 t.Run("bad-primary-same-addition", func(t *testing.T) { 251 err = ioutil.WriteFile(primaryPath, []byte("{\"version\": \"-1\"}"), 0644) 252 if err != nil { 253 t.Fatal(err) 254 } 255 256 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 257 258 config := &rspec.Spec{} 259 expected := fallbackInjected 260 _, err = manager.Hooks(config, map[string]string{}, false) 261 if err != nil { 262 t.Fatal(err) 263 } 264 assert.Equal(t, expected, config.Hooks) 265 }) 266 267 t.Run("good-primary-removal", func(t *testing.T) { 268 err = os.Remove(primaryPath) 269 if err != nil { 270 t.Fatal(err) 271 } 272 273 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 274 275 config := &rspec.Spec{} 276 _, err = manager.Hooks(config, map[string]string{}, false) 277 if err != nil { 278 t.Fatal(err) 279 } 280 assert.Equal(t, fallbackInjected, config.Hooks) 281 }) 282 283 t.Run("good-non-json-addition", func(t *testing.T) { 284 err = ioutil.WriteFile(filepath.Join(fallbackDir, "README"), []byte("Hello"), 0644) 285 if err != nil { 286 t.Fatal(err) 287 } 288 289 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 290 291 config := &rspec.Spec{} 292 _, err = manager.Hooks(config, map[string]string{}, false) 293 if err != nil { 294 t.Fatal(err) 295 } 296 297 assert.Equal(t, fallbackInjected, config.Hooks) 298 }) 299 300 t.Run("good-fallback-removal", func(t *testing.T) { 301 err = os.Remove(fallbackPath) 302 if err != nil { 303 t.Fatal(err) 304 } 305 306 time.Sleep(100 * time.Millisecond) // wait for monitor to notice 307 308 config := &rspec.Spec{} 309 expected := config.Hooks 310 _, err = manager.Hooks(config, map[string]string{}, false) 311 if err != nil { 312 t.Fatal(err) 313 } 314 assert.Equal(t, expected, config.Hooks) 315 }) 316 317 cancel() 318 err = <-sync 319 assert.Equal(t, context.Canceled, err) 320 } 321 322 func TestMonitorBadWatcher(t *testing.T) { 323 ctx := context.Background() 324 325 manager, err := New(ctx, []string{}, []string{}) 326 if err != nil { 327 t.Fatal(err) 328 } 329 manager.directories = []string{"/does/not/exist"} 330 331 sync := make(chan error, 2) 332 go manager.Monitor(ctx, sync) 333 err = <-sync 334 if !os.IsNotExist(err) { 335 t.Fatal("opaque wrapping for not-exist errors") 336 } 337 }