storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/lock/lock_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2016 MinIO, Inc.
     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 lock
    18  
    19  import (
    20  	"io/ioutil"
    21  	"os"
    22  	"testing"
    23  	"time"
    24  )
    25  
    26  // Test lock fails.
    27  func TestLockFail(t *testing.T) {
    28  	f, err := ioutil.TempFile("", "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, 0600)
    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, err := ioutil.TempDir("", "lockDir")
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	defer func() {
    53  		err = os.Remove(d)
    54  		if err != nil {
    55  			t.Fatal(err)
    56  		}
    57  	}()
    58  
    59  	_, err = LockedOpenFile(d, os.O_APPEND, 0600)
    60  	if err == nil {
    61  		t.Fatal("Should fail here")
    62  	}
    63  }
    64  
    65  // Tests rwlock methods.
    66  func TestRWLockedFile(t *testing.T) {
    67  	f, err := ioutil.TempFile("", "lock")
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  	f.Close()
    72  	defer func() {
    73  		err = os.Remove(f.Name())
    74  		if err != nil {
    75  			t.Fatal(err)
    76  		}
    77  	}()
    78  
    79  	rlk, err := RLockedOpenFile(f.Name())
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	isClosed := rlk.IsClosed()
    84  	if isClosed {
    85  		t.Fatal("File ref count shouldn't be zero")
    86  	}
    87  
    88  	// Increase reference count to 2.
    89  	rlk.IncLockRef()
    90  
    91  	isClosed = rlk.IsClosed()
    92  	if isClosed {
    93  		t.Fatal("File ref count shouldn't be zero")
    94  	}
    95  
    96  	// Decrease reference count by 1.
    97  	if err = rlk.Close(); err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	isClosed = rlk.IsClosed()
   102  	if isClosed {
   103  		t.Fatal("File ref count shouldn't be zero")
   104  	}
   105  
   106  	// Decrease reference count by 1.
   107  	if err = rlk.Close(); err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	// Now file should be closed.
   112  	isClosed = rlk.IsClosed()
   113  	if !isClosed {
   114  		t.Fatal("File ref count should be zero")
   115  	}
   116  
   117  	// Closing a file again should result in invalid argument.
   118  	if err = rlk.Close(); err != os.ErrInvalid {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	_, err = newRLockedFile(nil)
   123  	if err != os.ErrInvalid {
   124  		t.Fatal("Unexpected error", err)
   125  	}
   126  }
   127  
   128  // Tests lock and unlock semantics.
   129  func TestLockAndUnlock(t *testing.T) {
   130  	f, err := ioutil.TempFile("", "lock")
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	f.Close()
   135  	defer func() {
   136  		err = os.Remove(f.Name())
   137  		if err != nil {
   138  			t.Fatal(err)
   139  		}
   140  	}()
   141  
   142  	// lock the file
   143  	l, err := LockedOpenFile(f.Name(), os.O_WRONLY, 0600)
   144  	if err != nil {
   145  		t.Fatal(err)
   146  	}
   147  
   148  	// unlock the file
   149  	if err = l.Close(); err != nil {
   150  		t.Fatal(err)
   151  	}
   152  
   153  	// try lock the unlocked file
   154  	dupl, err := LockedOpenFile(f.Name(), os.O_WRONLY|os.O_CREATE, 0600)
   155  	if err != nil {
   156  		t.Errorf("err = %v, want %v", err, nil)
   157  	}
   158  
   159  	// blocking on locked file
   160  	locked := make(chan struct{}, 1)
   161  	go func() {
   162  		bl, blerr := LockedOpenFile(f.Name(), os.O_WRONLY, 0600)
   163  		if blerr != nil {
   164  			t.Error(blerr)
   165  			return
   166  		}
   167  		locked <- struct{}{}
   168  		if blerr = bl.Close(); blerr != nil {
   169  			t.Error(blerr)
   170  			return
   171  		}
   172  	}()
   173  
   174  	select {
   175  	case <-locked:
   176  		t.Error("unexpected unblocking")
   177  	case <-time.After(100 * time.Millisecond):
   178  	}
   179  
   180  	// unlock
   181  	if err = dupl.Close(); err != nil {
   182  		t.Fatal(err)
   183  	}
   184  
   185  	// the previously blocked routine should be unblocked
   186  	select {
   187  	case <-locked:
   188  	case <-time.After(1 * time.Second):
   189  		t.Error("unexpected blocking")
   190  	}
   191  }