github.com/jfrog/jfrog-cli-core/v2@v2.51.0/utils/lock/lock_test.go (about)

     1  package lock
     2  
     3  import (
     4  	"math"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
    11  	"github.com/jfrog/jfrog-cli-core/v2/utils/log"
    12  	"github.com/jfrog/jfrog-cli-core/v2/utils/tests"
    13  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  var testLockDirPath string
    18  
    19  func init() {
    20  	log.SetDefaultLogger()
    21  	locksDirPath, err := coreutils.GetJfrogLocksDir()
    22  	if err != nil {
    23  		return
    24  	}
    25  	testLockDirPath = filepath.Join(locksDirPath, "test")
    26  }
    27  
    28  // The lock mechanism prefers earlier lock requests. If two locks requests have same time stamps, it'll take the one with the smaller PID first.
    29  // Here we test the functionality of a real process with a real PID and a dummy process with MaxInt pid.
    30  func TestLockSmallerPid(t *testing.T) {
    31  	// First creating the first lock object with special pid number that doesn't exist.
    32  	firstLock := getLock(math.MaxInt32, t)
    33  	// Creating a second lock object with the running PID
    34  	secondLock := getLock(os.Getpid(), t)
    35  
    36  	// Confirming that only two locks are located in the lock directory
    37  	files, err := fileutils.ListFiles(testLockDirPath, false)
    38  	assert.NoError(t, err)
    39  	assert.Len(t, files, 2)
    40  
    41  	// Performing lock. This should work since the first lock PID is not running. The lock() will remove it.
    42  	assert.NoError(t, secondLock.lock())
    43  
    44  	// Unlocking to remove the lock file.
    45  	assert.NoError(t, secondLock.Unlock())
    46  
    47  	// If timestamp equals, secondLock.lock() is not expected to delete first lock's file, since os.Getpid() < math.MaxInt32.
    48  	if firstLock.currentTime == secondLock.currentTime {
    49  		assert.NoError(t, firstLock.Unlock())
    50  	}
    51  
    52  	// Confirming that no locks are located in the lock directory
    53  	files, err = fileutils.ListFiles(testLockDirPath, false)
    54  	assert.NoError(t, err)
    55  	assert.Empty(t, files)
    56  }
    57  
    58  // The lock mechanism prefers earlier lock requests. If two locks requests have same time stamps, it'll take the one with the smaller PID first.
    59  // Here we test the functionality of a real process with a real PID and a dummy process with -1 pid.
    60  func TestLockBiggerPid(t *testing.T) {
    61  	// First creating the first lock object with special pid number that doesn't exist.
    62  	getLock(-1, t)
    63  	// Creating a second lock object with the running PID
    64  	secondLock := getLock(os.Getpid(), t)
    65  
    66  	// Confirming that only two locks are located in the lock directory
    67  	files, err := fileutils.ListFiles(testLockDirPath, false)
    68  	assert.NoError(t, err)
    69  	assert.Len(t, files, 2)
    70  
    71  	// Performing lock. This should work since the first lock PID is not running. The lock() will remove it.
    72  	assert.NoError(t, secondLock.lock())
    73  
    74  	// Unlocking to remove the lock file.
    75  	assert.NoError(t, secondLock.Unlock())
    76  
    77  	// Confirming that no locks are located in the lock directory
    78  	files, err = fileutils.ListFiles(testLockDirPath, false)
    79  	assert.NoError(t, err)
    80  	assert.Empty(t, files)
    81  }
    82  
    83  func TestUnlock(t *testing.T) {
    84  	lock := new(Lock)
    85  	assert.NotZero(t, testLockDirPath, "An error occurred while initializing testLockDirPath")
    86  	err := lock.createNewLockFile(testLockDirPath)
    87  	assert.NoError(t, err)
    88  
    89  	exists, err := fileutils.IsFileExists(lock.fileName, false)
    90  	assert.NoError(t, err)
    91  	assert.Truef(t, exists, "File %s is missing", lock.fileName)
    92  
    93  	assert.NoError(t, lock.Unlock())
    94  	exists, err = fileutils.IsFileExists(lock.fileName, false)
    95  	assert.NoError(t, err)
    96  	assert.Falsef(t, exists, "File %s exists, but it should have been removed by Unlock", lock.fileName)
    97  }
    98  
    99  func TestCreateFile(t *testing.T) {
   100  	pid := os.Getpid()
   101  	lock := getLock(pid, t)
   102  
   103  	exists, err := fileutils.IsFileExists(lock.fileName, false)
   104  	assert.NoError(t, err)
   105  	assert.True(t, exists, "Lock wan't created.")
   106  
   107  	files, err := fileutils.ListFiles(testLockDirPath, false)
   108  	assert.NoError(t, err)
   109  	assert.Lenf(t, files, 1, "Expected one file, got %d.", len(files))
   110  	assert.Equalf(t, lock.fileName, files[0], "Expected filename %s, got %s", lock.fileName, files[0])
   111  
   112  	// Removing the created lock file
   113  	assert.NoError(t, lock.Unlock())
   114  }
   115  
   116  func TestGetLastLockTimestamp(t *testing.T) {
   117  	// Create an empty dir and make sure we get zero timestamp
   118  	tmpDir, createTempDirCallback := tests.CreateTempDirWithCallbackAndAssert(t)
   119  	defer createTempDirCallback()
   120  	timestamp, err := GetLastLockTimestamp(tmpDir)
   121  	assert.NoError(t, err)
   122  	assert.Zero(t, timestamp)
   123  
   124  	// Create a lock and make sure the timestamps are equal
   125  	lock := getLock(os.Getpid(), t)
   126  	timestamp, err = GetLastLockTimestamp(testLockDirPath)
   127  	assert.NoError(t, err)
   128  	assert.Equal(t, lock.currentTime, timestamp)
   129  
   130  	// Removing the created lock file
   131  	assert.NoError(t, lock.Unlock())
   132  }
   133  
   134  func TestGetLastLockNotRunningTimestamp(t *testing.T) {
   135  	// Create an empty dir and make sure we get zero timestamp
   136  	tmpDir, createTempDirCallback := tests.CreateTempDirWithCallbackAndAssert(t)
   137  	defer createTempDirCallback()
   138  	timestamp, err := GetLastLockTimestamp(tmpDir)
   139  	assert.NoError(t, err)
   140  	assert.Zero(t, timestamp)
   141  
   142  	// Create a lock for a non-running process and make sure the timestamp is zero
   143  	lock := getLock(math.MaxInt-1, t)
   144  	timestamp, err = GetLastLockTimestamp(testLockDirPath)
   145  	assert.NoError(t, err)
   146  	assert.Zero(t, timestamp)
   147  
   148  	// Removing the created lock file
   149  	assert.NoError(t, lock.Unlock())
   150  }
   151  
   152  func getLock(pid int, t *testing.T) Lock {
   153  	lock := Lock{pid: pid, currentTime: time.Now().UnixNano()}
   154  	assert.NotZero(t, testLockDirPath, "An error occurred while initializing testLockDirPath")
   155  	assert.NoError(t, fileutils.CreateDirIfNotExist(testLockDirPath))
   156  	assert.NoError(t, lock.createFile(testLockDirPath))
   157  	return lock
   158  }