github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/metadata/leases_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package metadata 18 19 import ( 20 _ "crypto/sha256" 21 "testing" 22 23 "github.com/containerd/containerd/errdefs" 24 "github.com/containerd/containerd/leases" 25 "github.com/pkg/errors" 26 bolt "go.etcd.io/bbolt" 27 ) 28 29 func TestLeases(t *testing.T) { 30 ctx, db, cancel := testEnv(t) 31 defer cancel() 32 33 lm := NewLeaseManager(NewDB(db, nil, nil)) 34 35 testCases := []struct { 36 ID string 37 CreateErr error 38 DeleteErr error 39 }{ 40 { 41 ID: "tx1", 42 }, 43 { 44 ID: "tx1", 45 CreateErr: errdefs.ErrAlreadyExists, 46 DeleteErr: errdefs.ErrNotFound, 47 }, 48 { 49 ID: "tx2", 50 }, 51 } 52 53 var ll []leases.Lease 54 55 for _, tc := range testCases { 56 if err := db.Update(func(tx *bolt.Tx) error { 57 lease, err := lm.Create(WithTransactionContext(ctx, tx), leases.WithID(tc.ID)) 58 if err != nil { 59 if tc.CreateErr != nil && errors.Is(err, tc.CreateErr) { 60 return nil 61 } 62 return err 63 } 64 ll = append(ll, lease) 65 return nil 66 }); err != nil { 67 t.Fatal(err) 68 } 69 } 70 71 listed, err := lm.List(ctx) 72 if err != nil { 73 t.Fatal(err) 74 } 75 76 if len(listed) != len(ll) { 77 t.Fatalf("Expected %d lease, got %d", len(ll), len(listed)) 78 } 79 for i := range listed { 80 if listed[i].ID != ll[i].ID { 81 t.Fatalf("Expected lease ID %s, got %s", ll[i].ID, listed[i].ID) 82 } 83 if listed[i].CreatedAt != ll[i].CreatedAt { 84 t.Fatalf("Expected lease created at time %s, got %s", ll[i].CreatedAt, listed[i].CreatedAt) 85 } 86 } 87 88 for _, tc := range testCases { 89 if err := lm.Delete(ctx, leases.Lease{ 90 ID: tc.ID, 91 }); err != nil { 92 if tc.DeleteErr == nil && !errors.Is(err, tc.DeleteErr) { 93 t.Fatal(err) 94 } 95 96 } 97 } 98 99 listed, err = lm.List(ctx) 100 if err != nil { 101 t.Fatal(err) 102 } 103 104 if len(listed) > 0 { 105 t.Fatalf("Expected no leases, found %d: %v", len(listed), listed) 106 } 107 } 108 109 func TestLeasesList(t *testing.T) { 110 ctx, db, cancel := testEnv(t) 111 defer cancel() 112 113 lm := NewLeaseManager(NewDB(db, nil, nil)) 114 115 testset := [][]leases.Opt{ 116 { 117 leases.WithID("lease1"), 118 leases.WithLabels(map[string]string{ 119 "label1": "value1", 120 "label3": "other", 121 }), 122 }, 123 { 124 leases.WithID("lease2"), 125 leases.WithLabels(map[string]string{ 126 "label1": "value1", 127 "label2": "", 128 "label3": "other", 129 }), 130 }, 131 { 132 leases.WithID("lease3"), 133 leases.WithLabels(map[string]string{ 134 "label1": "value2", 135 "label2": "something", 136 }), 137 }, 138 } 139 140 // Insert all 141 if err := db.Update(func(tx *bolt.Tx) error { 142 for _, opts := range testset { 143 _, err := lm.Create(WithTransactionContext(ctx, tx), opts...) 144 if err != nil { 145 return err 146 } 147 } 148 return nil 149 }); err != nil { 150 t.Fatal(err) 151 } 152 153 for _, testcase := range []struct { 154 name string 155 filters []string 156 expected []string 157 }{ 158 { 159 name: "All", 160 filters: []string{}, 161 expected: []string{"lease1", "lease2", "lease3"}, 162 }, 163 { 164 name: "ID", 165 filters: []string{"id==lease1"}, 166 expected: []string{"lease1"}, 167 }, 168 { 169 name: "IDx2", 170 filters: []string{"id==lease1", "id==lease2"}, 171 expected: []string{"lease1", "lease2"}, 172 }, 173 { 174 name: "Label1", 175 filters: []string{"labels.label1"}, 176 expected: []string{"lease1", "lease2", "lease3"}, 177 }, 178 179 { 180 name: "Label1value1", 181 filters: []string{"labels.label1==value1"}, 182 expected: []string{"lease1", "lease2"}, 183 }, 184 { 185 name: "Label1value2", 186 filters: []string{"labels.label1==value2"}, 187 expected: []string{"lease3"}, 188 }, 189 { 190 name: "Label2", 191 filters: []string{"labels.label2"}, 192 expected: []string{"lease3"}, 193 }, 194 { 195 name: "Label3", 196 filters: []string{"labels.label2", "labels.label3"}, 197 expected: []string{"lease1", "lease2", "lease3"}, 198 }, 199 } { 200 t.Run(testcase.name, func(t *testing.T) { 201 results, err := lm.List(ctx, testcase.filters...) 202 if err != nil { 203 t.Fatal(err) 204 } 205 206 if len(results) != len(testcase.expected) { 207 t.Errorf("length of result does not match expected: %v != %v", len(results), len(testcase.expected)) 208 } 209 210 expectedMap := map[string]struct{}{} 211 for _, expected := range testcase.expected { 212 expectedMap[expected] = struct{}{} 213 } 214 215 for _, result := range results { 216 if _, ok := expectedMap[result.ID]; !ok { 217 t.Errorf("unexpected match: %v", result.ID) 218 } else { 219 delete(expectedMap, result.ID) 220 } 221 } 222 if len(expectedMap) > 0 { 223 for match := range expectedMap { 224 t.Errorf("missing match: %v", match) 225 } 226 } 227 228 }) 229 } 230 231 // delete everything to test it 232 for _, opts := range testset { 233 var lease leases.Lease 234 for _, opt := range opts { 235 if err := opt(&lease); err != nil { 236 t.Fatal(err) 237 } 238 } 239 240 if err := lm.Delete(ctx, lease); err != nil { 241 t.Fatal(err) 242 } 243 244 // try it again, get not found 245 if err := lm.Delete(ctx, lease); err == nil { 246 t.Fatalf("expected error deleting non-existent lease") 247 } else if !errdefs.IsNotFound(err) { 248 t.Fatalf("unexpected error: %s", err) 249 } 250 } 251 } 252 253 func TestLeaseResource(t *testing.T) { 254 ctx, db, cancel := testEnv(t) 255 defer cancel() 256 257 lm := NewLeaseManager(NewDB(db, nil, nil)) 258 259 var ( 260 leaseID = "l1" 261 262 lease = leases.Lease{ 263 ID: leaseID, 264 } 265 266 snapshotterKey = "RstMI3X8vguKoPFkmIStZ5fQFI7F1L0o" 267 ) 268 269 // prepare lease 270 if _, err := lm.Create(ctx, leases.WithID(leaseID)); err != nil { 271 t.Fatal(err) 272 } 273 274 testCases := []struct { 275 lease leases.Lease 276 resource leases.Resource 277 err error 278 }{ 279 { 280 lease: lease, 281 resource: leases.Resource{ 282 ID: "sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912", 283 Type: "content", 284 }, 285 }, 286 { 287 lease: lease, 288 resource: leases.Resource{ 289 ID: "d2UdcINOwrBTQG9kS8rySAM3eMNBSojH", 290 Type: "ingests", 291 }, 292 }, 293 { 294 // allow to add resource which exists 295 lease: lease, 296 resource: leases.Resource{ 297 ID: "d2UdcINOwrBTQG9kS8rySAM3eMNBSojH", 298 Type: "ingests", 299 }, 300 }, 301 { 302 // not allow to reference to lease 303 lease: lease, 304 resource: leases.Resource{ 305 ID: "xCAV3F6PddlXitbtby0Vo23Qof6RTWpG", 306 Type: "leases", 307 }, 308 err: errdefs.ErrNotImplemented, 309 }, 310 { 311 // not allow to reference to container 312 lease: lease, 313 resource: leases.Resource{ 314 ID: "05O9ljptPu5Qq9kZGOacEfymBwQFM8ZH", 315 Type: "containers", 316 }, 317 err: errdefs.ErrNotImplemented, 318 }, 319 { 320 // not allow to reference to image 321 lease: lease, 322 resource: leases.Resource{ 323 ID: "qBUHpWBn03YaCt9cL3PPGKWoxBqTlLfu", 324 Type: "image", 325 }, 326 err: errdefs.ErrNotImplemented, 327 }, 328 { 329 lease: lease, 330 resource: leases.Resource{ 331 ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2", 332 Type: "snapshots", 333 }, 334 err: errdefs.ErrInvalidArgument, 335 }, 336 { 337 lease: lease, 338 resource: leases.Resource{ 339 ID: snapshotterKey, 340 Type: "snapshots/overlayfs", 341 }, 342 }, 343 { 344 lease: lease, 345 resource: leases.Resource{ 346 ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2", 347 Type: "snapshots/overlayfs/type1", 348 }, 349 err: errdefs.ErrInvalidArgument, 350 }, 351 { 352 lease: leases.Lease{ 353 ID: "non-found", 354 }, 355 resource: leases.Resource{ 356 ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2", 357 Type: "snapshots/overlayfs", 358 }, 359 err: errdefs.ErrNotFound, 360 }, 361 } 362 363 idxList := make(map[leases.Resource]bool) 364 for i, tc := range testCases { 365 if err := db.Update(func(tx *bolt.Tx) error { 366 err0 := lm.AddResource(WithTransactionContext(ctx, tx), tc.lease, tc.resource) 367 if !errors.Is(err0, tc.err) { 368 return errors.Errorf("expect error (%v), but got (%v)", tc.err, err0) 369 } 370 371 if err0 == nil { 372 // not visited yet 373 idxList[tc.resource] = false 374 } 375 return nil 376 }); err != nil { 377 t.Fatalf("failed to run case %d with resource: %v", i, err) 378 } 379 } 380 381 // check list function 382 var gotList []leases.Resource 383 gotList, err := lm.ListResources(ctx, lease) 384 if err != nil { 385 t.Fatal(err) 386 } 387 388 if len(gotList) != len(idxList) { 389 t.Fatalf("expected (%d) resources, but got (%d)", len(idxList), len(gotList)) 390 } 391 392 for _, r := range gotList { 393 visited, ok := idxList[r] 394 if !ok { 395 t.Fatalf("unexpected resource(%v)", r) 396 } 397 if visited { 398 t.Fatalf("duplicate resource(%v)", r) 399 } 400 idxList[r] = true 401 } 402 403 // remove snapshots 404 if err := lm.DeleteResource(ctx, lease, leases.Resource{ 405 ID: snapshotterKey, 406 Type: "snapshots/overlayfs", 407 }); err != nil { 408 t.Fatal(err) 409 } 410 411 // check list number 412 gotList, err = lm.ListResources(ctx, lease) 413 if err != nil { 414 t.Fatal(err) 415 } 416 417 if len(gotList)+1 != len(idxList) { 418 t.Fatalf("expected (%d) resources, but got (%d)", len(idxList)-1, len(gotList)) 419 } 420 }