github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/lock/lock_test.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package lock 19 20 import ( 21 "os" 22 "testing" 23 "time" 24 ) 25 26 // Test lock fails. 27 func TestLockFail(t *testing.T) { 28 f, err := os.CreateTemp("", "lock") 29 if err != nil { 30 t.Fatal(err) 31 } 32 f.Close() 33 defer func() { 34 err = os.Remove(f.Name()) 35 if err != nil { 36 t.Fatal(err) 37 } 38 }() 39 40 _, err = LockedOpenFile(f.Name(), os.O_APPEND, 0o600) 41 if err == nil { 42 t.Fatal("Should fail here") 43 } 44 } 45 46 // Tests lock directory fail. 47 func TestLockDirFail(t *testing.T) { 48 d := t.TempDir() 49 50 _, err := LockedOpenFile(d, os.O_APPEND, 0o600) 51 if err == nil { 52 t.Fatal("Should fail here") 53 } 54 } 55 56 // Tests rwlock methods. 57 func TestRWLockedFile(t *testing.T) { 58 f, err := os.CreateTemp("", "lock") 59 if err != nil { 60 t.Fatal(err) 61 } 62 f.Close() 63 defer func() { 64 err = os.Remove(f.Name()) 65 if err != nil { 66 t.Fatal(err) 67 } 68 }() 69 70 rlk, err := RLockedOpenFile(f.Name()) 71 if err != nil { 72 t.Fatal(err) 73 } 74 isClosed := rlk.IsClosed() 75 if isClosed { 76 t.Fatal("File ref count shouldn't be zero") 77 } 78 79 // Increase reference count to 2. 80 rlk.IncLockRef() 81 82 isClosed = rlk.IsClosed() 83 if isClosed { 84 t.Fatal("File ref count shouldn't be zero") 85 } 86 87 // Decrease reference count by 1. 88 if err = rlk.Close(); err != nil { 89 t.Fatal(err) 90 } 91 92 isClosed = rlk.IsClosed() 93 if isClosed { 94 t.Fatal("File ref count shouldn't be zero") 95 } 96 97 // Decrease reference count by 1. 98 if err = rlk.Close(); err != nil { 99 t.Fatal(err) 100 } 101 102 // Now file should be closed. 103 isClosed = rlk.IsClosed() 104 if !isClosed { 105 t.Fatal("File ref count should be zero") 106 } 107 108 // Closing a file again should result in invalid argument. 109 if err = rlk.Close(); err != os.ErrInvalid { 110 t.Fatal(err) 111 } 112 113 _, err = newRLockedFile(nil) 114 if err != os.ErrInvalid { 115 t.Fatal("Unexpected error", err) 116 } 117 } 118 119 // Tests lock and unlock semantics. 120 func TestLockAndUnlock(t *testing.T) { 121 f, err := os.CreateTemp("", "lock") 122 if err != nil { 123 t.Fatal(err) 124 } 125 f.Close() 126 defer func() { 127 err = os.Remove(f.Name()) 128 if err != nil { 129 t.Fatal(err) 130 } 131 }() 132 133 // lock the file 134 l, err := LockedOpenFile(f.Name(), os.O_WRONLY, 0o600) 135 if err != nil { 136 t.Fatal(err) 137 } 138 139 // unlock the file 140 if err = l.Close(); err != nil { 141 t.Fatal(err) 142 } 143 144 // try lock the unlocked file 145 dupl, err := LockedOpenFile(f.Name(), os.O_WRONLY|os.O_CREATE, 0o600) 146 if err != nil { 147 t.Errorf("err = %v, want %v", err, nil) 148 } 149 150 // blocking on locked file 151 locked := make(chan struct{}, 1) 152 go func() { 153 bl, blerr := LockedOpenFile(f.Name(), os.O_WRONLY, 0o600) 154 if blerr != nil { 155 t.Error(blerr) 156 return 157 } 158 locked <- struct{}{} 159 if blerr = bl.Close(); blerr != nil { 160 t.Error(blerr) 161 return 162 } 163 }() 164 165 select { 166 case <-locked: 167 t.Error("unexpected unblocking") 168 case <-time.After(100 * time.Millisecond): 169 } 170 171 // unlock 172 if err = dupl.Close(); err != nil { 173 t.Fatal(err) 174 } 175 176 // the previously blocked routine should be unblocked 177 select { 178 case <-locked: 179 case <-time.After(1 * time.Second): 180 t.Error("unexpected blocking") 181 } 182 }