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