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