github.com/containerd/Containerd@v1.4.13/snapshots/devmapper/metadata_test.go (about) 1 // +build linux 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package devmapper 20 21 import ( 22 "context" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "strconv" 27 "testing" 28 29 "github.com/pkg/errors" 30 "go.etcd.io/bbolt" 31 "gotest.tools/v3/assert" 32 is "gotest.tools/v3/assert/cmp" 33 ) 34 35 var ( 36 testCtx = context.Background() 37 ) 38 39 func TestPoolMetadata_AddDevice(t *testing.T) { 40 tempDir, store := createStore(t) 41 defer cleanupStore(t, tempDir, store) 42 43 expected := &DeviceInfo{ 44 Name: "test2", 45 ParentName: "test1", 46 Size: 1, 47 State: Activated, 48 } 49 50 err := store.AddDevice(testCtx, expected) 51 assert.NilError(t, err) 52 53 result, err := store.GetDevice(testCtx, "test2") 54 assert.NilError(t, err) 55 56 assert.Equal(t, expected.Name, result.Name) 57 assert.Equal(t, expected.ParentName, result.ParentName) 58 assert.Equal(t, expected.Size, result.Size) 59 assert.Equal(t, expected.State, result.State) 60 assert.Assert(t, result.DeviceID != 0) 61 assert.Equal(t, expected.DeviceID, result.DeviceID) 62 } 63 64 func TestPoolMetadata_AddDeviceRollback(t *testing.T) { 65 tempDir, store := createStore(t) 66 defer cleanupStore(t, tempDir, store) 67 68 err := store.AddDevice(testCtx, &DeviceInfo{Name: ""}) 69 assert.Assert(t, err != nil) 70 71 _, err = store.GetDevice(testCtx, "") 72 assert.Equal(t, ErrNotFound, err) 73 } 74 75 func TestPoolMetadata_AddDeviceDuplicate(t *testing.T) { 76 tempDir, store := createStore(t) 77 defer cleanupStore(t, tempDir, store) 78 79 err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"}) 80 assert.NilError(t, err) 81 82 err = store.AddDevice(testCtx, &DeviceInfo{Name: "test"}) 83 assert.Assert(t, errors.Is(err, ErrAlreadyExists)) 84 } 85 86 func TestPoolMetadata_ReuseDeviceID(t *testing.T) { 87 tempDir, store := createStore(t) 88 defer cleanupStore(t, tempDir, store) 89 90 info1 := &DeviceInfo{Name: "test1"} 91 err := store.AddDevice(testCtx, info1) 92 assert.NilError(t, err) 93 94 info2 := &DeviceInfo{Name: "test2"} 95 err = store.AddDevice(testCtx, info2) 96 assert.NilError(t, err) 97 98 assert.Assert(t, info1.DeviceID != info2.DeviceID) 99 assert.Assert(t, info1.DeviceID != 0) 100 101 err = store.RemoveDevice(testCtx, info2.Name) 102 assert.NilError(t, err) 103 104 info3 := &DeviceInfo{Name: "test3"} 105 err = store.AddDevice(testCtx, info3) 106 assert.NilError(t, err) 107 108 assert.Equal(t, info2.DeviceID, info3.DeviceID) 109 } 110 111 func TestPoolMetadata_RemoveDevice(t *testing.T) { 112 tempDir, store := createStore(t) 113 defer cleanupStore(t, tempDir, store) 114 115 err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"}) 116 assert.NilError(t, err) 117 118 err = store.RemoveDevice(testCtx, "test") 119 assert.NilError(t, err) 120 121 _, err = store.GetDevice(testCtx, "test") 122 assert.Equal(t, ErrNotFound, err) 123 } 124 125 func TestPoolMetadata_UpdateDevice(t *testing.T) { 126 tempDir, store := createStore(t) 127 defer cleanupStore(t, tempDir, store) 128 129 oldInfo := &DeviceInfo{ 130 Name: "test1", 131 ParentName: "test2", 132 Size: 3, 133 State: Activated, 134 } 135 136 err := store.AddDevice(testCtx, oldInfo) 137 assert.NilError(t, err) 138 139 err = store.UpdateDevice(testCtx, oldInfo.Name, func(info *DeviceInfo) error { 140 info.ParentName = "test5" 141 info.Size = 6 142 info.State = Created 143 return nil 144 }) 145 146 assert.NilError(t, err) 147 148 newInfo, err := store.GetDevice(testCtx, "test1") 149 assert.NilError(t, err) 150 151 assert.Equal(t, "test1", newInfo.Name) 152 assert.Equal(t, "test5", newInfo.ParentName) 153 assert.Assert(t, newInfo.Size == 6) 154 assert.Equal(t, Created, newInfo.State) 155 } 156 157 func TestPoolMetadata_MarkFaulty(t *testing.T) { 158 tempDir, store := createStore(t) 159 defer cleanupStore(t, tempDir, store) 160 161 info := &DeviceInfo{Name: "test"} 162 err := store.AddDevice(testCtx, info) 163 assert.NilError(t, err) 164 165 err = store.MarkFaulty(testCtx, "test") 166 assert.NilError(t, err) 167 168 saved, err := store.GetDevice(testCtx, info.Name) 169 assert.NilError(t, err) 170 assert.Equal(t, saved.State, Faulty) 171 assert.Assert(t, saved.DeviceID > 0) 172 173 // Make sure a device ID marked as faulty as well 174 err = store.db.View(func(tx *bbolt.Tx) error { 175 bucket := tx.Bucket(deviceIDBucketName) 176 key := strconv.FormatUint(uint64(saved.DeviceID), 10) 177 value := bucket.Get([]byte(key)) 178 assert.Equal(t, value[0], byte(deviceFaulty)) 179 return nil 180 }) 181 assert.NilError(t, err) 182 } 183 184 func TestPoolMetadata_WalkDevices(t *testing.T) { 185 tempDir, store := createStore(t) 186 defer cleanupStore(t, tempDir, store) 187 188 err := store.AddDevice(testCtx, &DeviceInfo{Name: "device1", DeviceID: 1, State: Created}) 189 assert.NilError(t, err) 190 191 err = store.AddDevice(testCtx, &DeviceInfo{Name: "device2", DeviceID: 2, State: Faulty}) 192 assert.NilError(t, err) 193 194 called := 0 195 err = store.WalkDevices(testCtx, func(info *DeviceInfo) error { 196 called++ 197 switch called { 198 case 1: 199 assert.Equal(t, "device1", info.Name) 200 assert.Equal(t, uint32(1), info.DeviceID) 201 assert.Equal(t, Created, info.State) 202 case 2: 203 assert.Equal(t, "device2", info.Name) 204 assert.Equal(t, uint32(2), info.DeviceID) 205 assert.Equal(t, Faulty, info.State) 206 default: 207 t.Error("unexpected walk call") 208 } 209 210 return nil 211 }) 212 assert.NilError(t, err) 213 assert.Equal(t, called, 2) 214 } 215 216 func TestPoolMetadata_GetDeviceNames(t *testing.T) { 217 tempDir, store := createStore(t) 218 defer cleanupStore(t, tempDir, store) 219 220 err := store.AddDevice(testCtx, &DeviceInfo{Name: "test1"}) 221 assert.NilError(t, err) 222 223 err = store.AddDevice(testCtx, &DeviceInfo{Name: "test2"}) 224 assert.NilError(t, err) 225 226 names, err := store.GetDeviceNames(testCtx) 227 assert.NilError(t, err) 228 assert.Assert(t, is.Len(names, 2)) 229 230 assert.Equal(t, "test1", names[0]) 231 assert.Equal(t, "test2", names[1]) 232 } 233 234 func createStore(t *testing.T) (tempDir string, store *PoolMetadata) { 235 tempDir, err := ioutil.TempDir("", "pool-metadata-") 236 assert.NilError(t, err, "couldn't create temp directory for metadata tests") 237 238 path := filepath.Join(tempDir, "test.db") 239 metadata, err := NewPoolMetadata(path) 240 assert.NilError(t, err) 241 242 return tempDir, metadata 243 } 244 245 func cleanupStore(t *testing.T, tempDir string, store *PoolMetadata) { 246 err := store.Close() 247 assert.NilError(t, err, "failed to close metadata store") 248 249 err = os.RemoveAll(tempDir) 250 assert.NilError(t, err, "failed to cleanup temp directory") 251 }