Skip to content

Commit

Permalink
added some unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Bartek Rybak committed Feb 13, 2021
1 parent fe80cc7 commit a6c8dc6
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 46 deletions.
58 changes: 29 additions & 29 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ import (
)

const (
FLAG_ROOT = "root"
ENV_ROOT = "FMUTEX_ROOT"
FLAG_ID = "id"
FLAG_SILENT = "s"
FLAG_PULSE = "pulse"
FLAG_REFRESH = "refresh"
FLAG_LIMIT = "limit"
FLAG_TIMEOUT = "timeout"
FlagRoot = "root"
EnvRoot = "FMUTEX_ROOT"
FlagId = "id"
FlagSilent = "s"
FlagPulse = "pulse"
FlagRefresh = "refresh"
FlagLimit = "limit"
FlagTimeout = "timeout"
)

var cmn = struct { // Common flags
Root string
Id string
Silent bool
}{
Root: ifEmptyStr(os.Getenv(ENV_ROOT), os.TempDir()),
Root: ifEmptyStr(os.Getenv(EnvRoot), os.TempDir()),
Silent: false,
}

Expand All @@ -44,10 +44,10 @@ var lck = struct { // Lock flags
}

const (
CMD_LOCK = "lock"
CMD_RELEASE = "release"
CMD_UNLOCK = "unlock" // An alias to CMD_RELEASE
CMD_TEST = "test"
CmdLock = "lock"
CmdRelease = "release"
CmdUnlock = "unlock" // An alias to CmdRelease
CmdTest = "test"
)

var (
Expand All @@ -63,28 +63,28 @@ func init() {
log.SetPrefix(fmt.Sprintf("%s: ", getProg(os.Args)))

flag.Usage = usage
flag.StringVar(&cmn.Root, FLAG_ROOT, cmn.Root, "root directory for mutex(es)")
flag.StringVar(&cmn.Id, FLAG_ID, cmn.Id, "mutex id")
flag.BoolVar(&cmn.Silent, FLAG_SILENT, cmn.Silent, "silent execution")
flag.StringVar(&cmn.Root, FlagRoot, cmn.Root, "root directory for mutex(es)")
flag.StringVar(&cmn.Id, FlagId, cmn.Id, "mutex id")
flag.BoolVar(&cmn.Silent, FlagSilent, cmn.Silent, "silent execution")

cmdLock = flag.NewFlagSet(CMD_LOCK, flag.ExitOnError)
cmdLock.DurationVar(&lck.Pulse, FLAG_PULSE, lck.Pulse, "determines frequency of locking attempts")
cmdLock.DurationVar(&lck.Refresh, FLAG_REFRESH, lck.Refresh, "determines frequency of saving current timestamp in a locking file")
cmdLock.DurationVar(&lck.Limit, FLAG_LIMIT, lck.Limit, "determines how long takes to consider given mutex as \"dead\"")
cmdLock.DurationVar(&lck.Timeout, FLAG_TIMEOUT, lck.Timeout, "locking timeout (if > 0)")
cmdLock = flag.NewFlagSet(CmdLock, flag.ExitOnError)
cmdLock.DurationVar(&lck.Pulse, FlagPulse, lck.Pulse, "determines frequency of locking attempts")
cmdLock.DurationVar(&lck.Refresh, FlagRefresh, lck.Refresh, "determines frequency of saving current timestamp in a locking file")
cmdLock.DurationVar(&lck.Limit, FlagLimit, lck.Limit, "determines how long takes to consider given mutex as \"dead\"")
cmdLock.DurationVar(&lck.Timeout, FlagTimeout, lck.Timeout, "locking timeout (if > 0)")

cmdRelease = flag.NewFlagSet(CMD_RELEASE, flag.ExitOnError)
cmdTest = flag.NewFlagSet(CMD_TEST, flag.ExitOnError)
cmdRelease = flag.NewFlagSet(CmdRelease, flag.ExitOnError)
cmdTest = flag.NewFlagSet(CmdTest, flag.ExitOnError)

cmdAll, cmdNames = mkCommands(cmdLock, cmdRelease, cmdTest)

flag.Parse()
}

func main() {
flag.Parse()

if isEmptyStr(cmn.Id) {
log.Fatalf("Flag -%s is required.", FLAG_ID)
log.Fatalf("Flag -%s is required.", FlagId)
}

if flag.NArg() < 1 {
Expand All @@ -95,19 +95,19 @@ func main() {
log.SetOutput(ioutil.Discard)
}
switch flag.Arg(0) {
case CMD_LOCK:
case CmdLock:
cmdLock.Parse(flag.Args()[1:])
doLock()
if !cmn.Silent {
fmt.Println("LOCKED")
}
case CMD_RELEASE, CMD_UNLOCK:
case CmdRelease, CmdUnlock:
cmdRelease.Parse(flag.Args()[1:])
doUnlock()
if !cmn.Silent {
fmt.Println("RELEASED")
}
case CMD_TEST:
case CmdTest:
cmdTest.Parse(flag.Args()[1:])
os.Exit(doTest())

Expand Down Expand Up @@ -146,7 +146,7 @@ func doUnlock() {
func newMutex() *mutex.Mutex {
result, err := mutex.NewMutexExt(cmn.Root, cmn.Id, lck.Pulse, lck.Refresh, lck.Limit)
if err != nil {
log.Fatalf("Cannot create mutex \"%s\": %v", result.Id(), err)
log.Fatalf("Cannot create mutex \"%s\": %v", cmn.Id, err)
}
return result
}
Expand Down
97 changes: 97 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package main

import (
"fmt"
"os"
"path"
"testing"
)

func temporaryCatalog(t *testing.T) string {
tempDir, err := os.MkdirTemp("", "temp-*.dir")
if err != nil {
t.Fatalf("error creating temporary directory: %v", err)
}
t.Cleanup(func() {
if err := os.RemoveAll(tempDir); err != nil {
t.Errorf("error removing temporary directory: %v", err)
}
})
return tempDir
}

func TestIsEmptyStr(t *testing.T) {
cases := [][]string{
{"", " ", " \t "},
{"A", " a "},
}

for i, c := range cases {
expected := i == 0
for _, testCase := range c {
if got := isEmptyStr(testCase); got != expected {
t.Fatalf("wrong value of isEmpty(\"%s\") => %v instead of %v", testCase, got, expected)
}
}
}
}

func TestIfEmptyStr(t *testing.T) {
cases := []struct {
s string
r string
}{
{"", "abcd"},
{"xyz", "xyz"},
{" ", "abcd"},
}

for _, c := range cases {
expected := c.r
if got := ifEmptyStr(c.s, "abcd"); got != expected {
t.Fatalf("wrong value of ifEmpty(\"%s\", \"abcd\") => %v instead of \"%s\"", c.s, got, expected)
}
}
}

func lockName() string {
lockFile := fmt.Sprintf("%s-mutex.lck", cmn.Id)
return path.Join(cmn.Root, cmn.Id, lockFile)
}

func TestTest(t *testing.T) {
cmn.Root = temporaryCatalog(t)
cmn.Id = "test-test"
doLock()
expected := 0
if got := doTest(); got != expected {
t.Fatalf("wrong value of doTest() => %d instead of %d", got, expected)
}
doUnlock()
expected = 1
if got := doTest(); got != expected {
t.Fatalf("wrong value of doTest() => %d instead of %d", got, expected)
}
}

func TestLock(t *testing.T) {
cmn.Root = temporaryCatalog(t)
cmn.Id = "test-lock"
defer doUnlock()
doLock()
expected := lockName()
if _, err := os.Stat(expected); err != nil {
t.Fatalf("wrong result of doLock(): %v", err)
}
}

func TestUnlock(t *testing.T) {
cmn.Root = temporaryCatalog(t)
cmn.Id = "test-unlock"
doLock()
doUnlock()
lockFile := lockName()
if _, err := os.Stat(lockFile); err == nil {
t.Fatalf("wrong result of doUnlock(): lock file still exists: %s", lockFile)
}
}
1 change: 0 additions & 1 deletion mutex/mutex.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ func NewMutex(root string, lockId string) (*Mutex, error) {
func NewMutexExt(root string, lockId string, pulse time.Duration, refresh time.Duration, deadTimeout time.Duration) (*Mutex, error) {
if !filepath.IsAbs(root) {
var err error
//return nil, fmt.Errorf("root (%s) is NOT an absolute absolute path", root)
if root, err = filepath.Abs(root); err != nil {
return nil, err
}
Expand Down
101 changes: 85 additions & 16 deletions mutex/mutex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package mutex

import (
"fmt"
"log"
"os"
"path"
"path/filepath"
"sync"
"testing"
Expand All @@ -22,13 +24,18 @@ func temporaryCatalog(t *testing.T) string {
return tempDir
}

func newTestMutex(root string, id string) *Mutex {
result, err := NewMutex(root, id)
if err != nil {
log.Fatalf("Cannot create mutex \"%s\": %v", id, err)
}
return result
}

func TestSimpleMutex(t *testing.T) {
const mutexId = "simple-test-mutex"
mutexRoot := temporaryCatalog(t)
mx, err := NewMutex(mutexRoot, mutexId)
if err != nil {
t.Fatalf("cannot create the mutex: %v", err)
}
mx := newTestMutex(mutexRoot, mutexId)
value := 0
mx.Lock()
go func(v *int) {
Expand Down Expand Up @@ -84,10 +91,7 @@ func TestSimpleMutexN(t *testing.T) {
func TestLockPath(t *testing.T) {
const mutexId = "simple-test-mutex"
mutexRoot := temporaryCatalog(t)
mx, err := NewMutex(mutexRoot, mutexId)
if err != nil {
t.Fatalf("cannot create the mutex: %v", err)
}
mx := newTestMutex(mutexRoot, mutexId)
want := filepath.Join(mutexRoot, mutexId, fmt.Sprintf("%s-mutex.lck", mutexId))
got := mx.LockPath()

Expand All @@ -99,10 +103,7 @@ func TestLockPath(t *testing.T) {
func TestId(t *testing.T) {
const mutexId = "simple-test-mutex"
mutexRoot := temporaryCatalog(t)
mx, err := NewMutex(mutexRoot, mutexId)
if err != nil {
t.Fatalf("cannot create the mutex: %v", err)
}
mx := newTestMutex(mutexRoot, mutexId)
want := mutexId
got := mx.Id()

Expand All @@ -114,10 +115,7 @@ func TestId(t *testing.T) {
func TestWhen(t *testing.T) {
const mutexId = "simple-test-mutex"
mutexRoot := temporaryCatalog(t)
mx, err := NewMutex(mutexRoot, mutexId)
if err != nil {
t.Fatalf("cannot create the mutex: %v", err)
}
mx := newTestMutex(mutexRoot, mutexId)
mx.Lock()
defer mx.Unlock()
if file, err := os.Create(mx.LockPath()); err != nil {
Expand All @@ -133,3 +131,74 @@ func TestWhen(t *testing.T) {
}
}
}

func TestTry1(t *testing.T) {
const mutexId = "try1-test-mutex"
mutexRoot := temporaryCatalog(t)
mx1 := newTestMutex(mutexRoot, mutexId)
mx1.Lock()
go func() {
defer mx1.Unlock()
time.Sleep(3 * time.Second)
}()
mx2 := newTestMutex(mutexRoot, mutexId)
defer mx2.Unlock()
if err := mx2.TryLock(5 * time.Second); err != nil {
t.Fatalf("TryLock failed (%v), but should succeed.", err)
}
}

func TestTry2(t *testing.T) {
const mutexId = "try2-test-mutex"
mutexRoot := temporaryCatalog(t)
mx1 := newTestMutex(mutexRoot, mutexId)
mx1.Lock()
go func() {
defer mx1.Unlock()
time.Sleep(3 * time.Second)
}()
mx2 := newTestMutex(mutexRoot, mutexId)
defer mx2.Unlock()
if err := mx2.TryLock(1 * time.Second); err == nil {
t.Fatal("TryLock succeed but should failed.")
}
}

func TestMutexDefaults(t *testing.T) {
const mutexId = "mutex-defaults"
mutexRoot := temporaryCatalog(t)
zero := time.Duration(0)
if mx, err := NewMutexExt(mutexRoot, mutexId, zero, zero, zero); err != nil {
t.Fatal(err)
} else {
expected := DefaultPulse
if got := mx.pulse; got != expected {
t.Fatalf("Wrong pulse default: got: %v, expected: %v", got, expected)
}
expected = DefaultRefresh
if got := mx.refresh; got != expected {
t.Fatalf("Wrong pulse refresh: got: %v, expected: %v", got, expected)
}
}
}

func TestMutexRoot(t *testing.T) {
const mutexId = "mutex-root"
cwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
defer os.Chdir(cwd)
tmpdir := temporaryCatalog(t)
if err := os.Chdir(tmpdir); err != nil {
t.Fatal(err)
}
mutexRoot := "./here"
if mx, err := NewMutex(mutexRoot, mutexId); err != nil {
t.Fatal(err)
} else {
if !path.IsAbs(mx.directory) {
t.Fatalf("Wrong lock directory - should be absolute (%s)", mx.directory)
}
}
}

0 comments on commit a6c8dc6

Please sign in to comment.