github.com/cs3org/reva/v2@v2.27.7/pkg/storage/utils/decomposedfs/node/locks_test.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package node_test 20 21 import ( 22 "context" 23 "os" 24 25 "github.com/google/uuid" 26 . "github.com/onsi/ginkgo/v2" 27 . "github.com/onsi/gomega" 28 "google.golang.org/protobuf/testing/protocmp" 29 30 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 31 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 32 ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" 33 "github.com/cs3org/reva/v2/pkg/errtypes" 34 "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node" 35 helpers "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/testhelpers" 36 ) 37 38 var _ = Describe("Node locks", func() { 39 var ( 40 env *helpers.TestEnv 41 42 lockByUser *provider.Lock 43 wrongLockByUser *provider.Lock 44 lockByApp *provider.Lock 45 wrongLockByApp *provider.Lock 46 n *node.Node 47 n2 *node.Node 48 49 otherUser = &userpb.User{ 50 Id: &userpb.UserId{ 51 Idp: "idp", 52 OpaqueId: "otheruserid", 53 Type: userpb.UserType_USER_TYPE_PRIMARY, 54 }, 55 Username: "foo", 56 } 57 otherCtx = ctxpkg.ContextSetUser(context.Background(), otherUser) 58 ) 59 60 BeforeEach(func() { 61 var err error 62 env, err = helpers.NewTestEnv(nil) 63 Expect(err).ToNot(HaveOccurred()) 64 65 lockByUser = &provider.Lock{ 66 Type: provider.LockType_LOCK_TYPE_EXCL, 67 User: env.Owner.Id, 68 LockId: uuid.New().String(), 69 } 70 wrongLockByUser = &provider.Lock{ 71 Type: provider.LockType_LOCK_TYPE_EXCL, 72 User: env.Owner.Id, 73 LockId: uuid.New().String(), 74 } 75 lockByApp = &provider.Lock{ 76 Type: provider.LockType_LOCK_TYPE_WRITE, 77 AppName: "app1", 78 LockId: uuid.New().String(), 79 } 80 wrongLockByApp = &provider.Lock{ 81 Type: provider.LockType_LOCK_TYPE_WRITE, 82 AppName: "app2", 83 LockId: uuid.New().String(), 84 } 85 spaceResID, err := env.CreateTestStorageSpace("project", &provider.Quota{QuotaMaxBytes: 2000}) 86 Expect(err).ToNot(HaveOccurred()) 87 n, err = env.CreateTestFile("tobelockedid", "blob", spaceResID.OpaqueId, spaceResID.OpaqueId, 10) 88 Expect(err).ToNot(HaveOccurred()) 89 n2, err = env.CreateTestFile("neverlockedlockedid", "blob", spaceResID.OpaqueId, spaceResID.OpaqueId, 10) 90 Expect(err).ToNot(HaveOccurred()) 91 }) 92 93 AfterEach(func() { 94 if env != nil { 95 env.Cleanup() 96 } 97 }) 98 99 Describe("SetLock for a user", func() { 100 It("sets the lock", func() { 101 _, err := os.Stat(n.LockFilePath()) 102 Expect(err).To(HaveOccurred()) 103 104 err = n.SetLock(env.Ctx, lockByUser) 105 Expect(err).ToNot(HaveOccurred()) 106 107 _, err = os.Stat(n.LockFilePath()) 108 Expect(err).ToNot(HaveOccurred()) 109 }) 110 111 It("refuses to set a lock if already locked", func() { 112 err := n.SetLock(env.Ctx, lockByUser) 113 Expect(err).ToNot(HaveOccurred()) 114 115 err = n.SetLock(env.Ctx, lockByUser) 116 Expect(err).To(HaveOccurred()) 117 _, ok := err.(errtypes.PreconditionFailed) 118 Expect(ok).To(BeTrue()) 119 }) 120 }) 121 122 Describe("SetLock for an app", func() { 123 It("sets the lock", func() { 124 _, err := os.Stat(n.LockFilePath()) 125 Expect(err).To(HaveOccurred()) 126 127 err = n.SetLock(env.Ctx, lockByApp) 128 Expect(err).ToNot(HaveOccurred()) 129 130 _, err = os.Stat(n.LockFilePath()) 131 Expect(err).ToNot(HaveOccurred()) 132 }) 133 134 It("refuses to set a lock if already locked", func() { 135 err := n.SetLock(env.Ctx, lockByApp) 136 Expect(err).ToNot(HaveOccurred()) 137 138 err = n.SetLock(env.Ctx, lockByApp) 139 Expect(err).To(HaveOccurred()) 140 _, ok := err.(errtypes.PreconditionFailed) 141 Expect(ok).To(BeTrue()) 142 }) 143 144 }) 145 146 Context("with an existing lock for a user", func() { 147 BeforeEach(func() { 148 err := n.SetLock(env.Ctx, lockByUser) 149 Expect(err).ToNot(HaveOccurred()) 150 }) 151 152 Describe("ReadLock", func() { 153 It("returns the lock", func() { 154 l, err := n.ReadLock(env.Ctx, false) 155 Expect(err).ToNot(HaveOccurred()) 156 Expect(l).To(BeComparableTo(lockByUser, protocmp.Transform())) 157 }) 158 159 It("reports an error when the node wasn't locked", func() { 160 _, err := n2.ReadLock(env.Ctx, false) 161 Expect(err).To(HaveOccurred()) 162 Expect(err.Error()).To(ContainSubstring("no lock found")) 163 }) 164 }) 165 166 Describe("RefreshLock", func() { 167 var ( 168 newLock *provider.Lock 169 ) 170 171 JustBeforeEach(func() { 172 newLock = &provider.Lock{ 173 Type: provider.LockType_LOCK_TYPE_EXCL, 174 User: env.Owner.Id, 175 LockId: lockByUser.LockId, 176 } 177 }) 178 179 It("fails when the node is unlocked", func() { 180 err := n2.RefreshLock(env.Ctx, lockByUser, "") 181 Expect(err).To(HaveOccurred()) 182 Expect(err.Error()).To(ContainSubstring("precondition failed")) 183 }) 184 185 It("refuses to refresh the lock without holding the lock", func() { 186 newLock.LockId = "somethingsomething" 187 err := n.RefreshLock(env.Ctx, newLock, "") 188 Expect(err).To(HaveOccurred()) 189 Expect(err.Error()).To(ContainSubstring("mismatching")) 190 }) 191 192 It("refuses to refresh the lock for other users than the lock holder", func() { 193 err := n.RefreshLock(otherCtx, newLock, "") 194 Expect(err).To(HaveOccurred()) 195 Expect(err.Error()).To(ContainSubstring("permission denied")) 196 }) 197 198 It("refuses to change the lock holder", func() { 199 newLock.User = otherUser.Id 200 err := n.RefreshLock(env.Ctx, newLock, "") 201 Expect(err).To(HaveOccurred()) 202 Expect(err.Error()).To(ContainSubstring("permission denied")) 203 }) 204 205 It("refuses to change the lock when we do not send the correct lock id for the old lock", func() { 206 newLock.LockId = "somethingsomething" 207 err := n.RefreshLock(env.Ctx, newLock, "somethingdifferent") 208 Expect(err).To(HaveOccurred()) 209 Expect(err.Error()).To(ContainSubstring("mismatching")) 210 }) 211 212 It("refreshes the lock when we send a new lock and the correct lock id for the old lock", func() { 213 newLock.LockId = "somethingsomething" 214 err := n.RefreshLock(env.Ctx, newLock, lockByUser.LockId) 215 Expect(err).ToNot(HaveOccurred()) 216 }) 217 218 It("refreshes the lock", func() { 219 err := n.RefreshLock(env.Ctx, newLock, "") 220 Expect(err).ToNot(HaveOccurred()) 221 }) 222 223 It("refreshes the lock and unlocks with the new lock", func() { 224 err := n.RefreshLock(env.Ctx, newLock, lockByUser.LockId) 225 Expect(err).ToNot(HaveOccurred()) 226 err = n.Unlock(env.Ctx, newLock) 227 Expect(err).ToNot(HaveOccurred()) 228 }) 229 }) 230 231 Describe("Unlock", func() { 232 It("refuses to unlock without having a lock", func() { 233 err := n.Unlock(env.Ctx, nil) 234 Expect(err.Error()).To(ContainSubstring(lockByUser.LockId)) 235 }) 236 237 It("refuses to unlock without having the proper lock", func() { 238 err := n.Unlock(env.Ctx, nil) 239 Expect(err.Error()).To(ContainSubstring(lockByUser.LockId)) 240 241 err = n.Unlock(env.Ctx, wrongLockByUser) 242 Expect(err.Error()).To(ContainSubstring(lockByUser.LockId)) 243 }) 244 245 It("refuses to unlock for others even if they have the lock", func() { 246 err := n.Unlock(otherCtx, lockByUser) 247 Expect(err).To(HaveOccurred()) 248 Expect(err.Error()).To(ContainSubstring("mismatching")) 249 }) 250 251 It("unlocks when the owner uses the lock", func() { 252 err := n.Unlock(env.Ctx, lockByUser) 253 Expect(err).ToNot(HaveOccurred()) 254 255 _, err = os.Stat(n.LockFilePath()) 256 Expect(err).To(HaveOccurred()) 257 }) 258 259 It("fails to unlock an unlocked node", func() { 260 err := n.Unlock(env.Ctx, lockByUser) 261 Expect(err).ToNot(HaveOccurred()) 262 263 err = n.Unlock(env.Ctx, lockByUser) 264 Expect(err).To(HaveOccurred()) 265 Expect(err.Error()).To(ContainSubstring("lock does not exist")) 266 }) 267 }) 268 }) 269 270 Context("with an existing lock for an app", func() { 271 BeforeEach(func() { 272 err := n.SetLock(env.Ctx, lockByApp) 273 Expect(err).ToNot(HaveOccurred()) 274 }) 275 276 Describe("ReadLock", func() { 277 It("returns the lock", func() { 278 l, err := n.ReadLock(env.Ctx, false) 279 Expect(err).ToNot(HaveOccurred()) 280 Expect(l).To(Equal(lockByApp)) 281 }) 282 283 It("reports an error when the node wasn't locked", func() { 284 _, err := n2.ReadLock(env.Ctx, false) 285 Expect(err).To(HaveOccurred()) 286 Expect(err.Error()).To(ContainSubstring("no lock found")) 287 }) 288 }) 289 290 Describe("RefreshLock", func() { 291 var ( 292 newLock *provider.Lock 293 ) 294 295 JustBeforeEach(func() { 296 newLock = &provider.Lock{ 297 Type: provider.LockType_LOCK_TYPE_EXCL, 298 AppName: lockByApp.AppName, 299 LockId: lockByApp.LockId, 300 } 301 }) 302 303 It("fails when the node is unlocked", func() { 304 err := n2.RefreshLock(env.Ctx, lockByApp, "") 305 Expect(err).To(HaveOccurred()) 306 Expect(err.Error()).To(ContainSubstring("precondition failed")) 307 }) 308 309 It("refuses to refresh the lock without holding the lock", func() { 310 newLock.LockId = "somethingsomething" 311 err := n.RefreshLock(env.Ctx, newLock, "") 312 Expect(err).To(HaveOccurred()) 313 Expect(err.Error()).To(ContainSubstring("mismatching")) 314 }) 315 316 It("refreshes the lock for other users", func() { 317 err := n.RefreshLock(otherCtx, lockByApp, "") 318 Expect(err).ToNot(HaveOccurred()) 319 }) 320 321 It("refuses to change the lock holder", func() { 322 newLock.AppName = wrongLockByApp.AppName 323 err := n.RefreshLock(env.Ctx, newLock, "") 324 Expect(err).To(HaveOccurred()) 325 Expect(err.Error()).To(ContainSubstring("permission denied")) 326 }) 327 328 It("refuses to change the lock when we do not send the correct lock id for the old lock", func() { 329 newLock.LockId = "somethingsomething" 330 err := n.RefreshLock(env.Ctx, newLock, "somethingdifferent") 331 Expect(err).To(HaveOccurred()) 332 Expect(err.Error()).To(ContainSubstring("mismatching")) 333 }) 334 335 It("refreshes the lock when we send a new lock and the correct lock id for the old lock", func() { 336 newLock.LockId = "somethingsomething" 337 err := n.RefreshLock(env.Ctx, newLock, lockByApp.LockId) 338 Expect(err).ToNot(HaveOccurred()) 339 }) 340 341 It("refreshes the lock", func() { 342 err := n.RefreshLock(env.Ctx, newLock, "") 343 Expect(err).ToNot(HaveOccurred()) 344 }) 345 It("refreshes the lock and unlocks it with the new lock", func() { 346 newLock.LockId = "somethingnew" 347 err := n.RefreshLock(env.Ctx, newLock, lockByApp.LockId) 348 Expect(err).ToNot(HaveOccurred()) 349 err = n.Unlock(env.Ctx, newLock) 350 Expect(err).ToNot(HaveOccurred()) 351 }) 352 }) 353 354 Describe("Unlock", func() { 355 It("refuses to unlock without having a lock", func() { 356 err := n.Unlock(env.Ctx, nil) 357 Expect(err.Error()).To(ContainSubstring(lockByApp.LockId)) 358 }) 359 360 It("refuses to unlock without having the proper lock", func() { 361 err := n.Unlock(env.Ctx, nil) 362 Expect(err.Error()).To(ContainSubstring(lockByApp.LockId)) 363 364 err = n.Unlock(env.Ctx, wrongLockByUser) 365 Expect(err.Error()).To(ContainSubstring(lockByApp.LockId)) 366 }) 367 368 It("accepts to unlock for others if they have the lock", func() { 369 err := n.Unlock(otherCtx, lockByApp) 370 Expect(err).ToNot(HaveOccurred()) 371 }) 372 373 It("unlocks when the owner uses the lock", func() { 374 err := n.Unlock(env.Ctx, lockByApp) 375 Expect(err).ToNot(HaveOccurred()) 376 377 _, err = os.Stat(n.LockFilePath()) 378 Expect(err).To(HaveOccurred()) 379 }) 380 381 It("fails to unlock an unlocked node", func() { 382 err := n.Unlock(env.Ctx, lockByApp) 383 Expect(err).ToNot(HaveOccurred()) 384 385 err = n.Unlock(env.Ctx, lockByApp) 386 Expect(err).To(HaveOccurred()) 387 Expect(err.Error()).To(ContainSubstring("lock does not exist")) 388 }) 389 }) 390 }) 391 })