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  }