Skip to content

Commit

Permalink
fixed race in Wait helper
Browse files Browse the repository at this point in the history
  • Loading branch information
hexdigest committed Jan 29, 2019
1 parent e9edfca commit bf7e7c7
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 3 deletions.
2 changes: 1 addition & 1 deletion mock_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var _ MockController = &Controller{}

//NewController returns an instance of Controller
func NewController(t Tester) *Controller {
return &Controller{Tester: t}
return &Controller{Tester: newSafeTester(t)}
}

//RegisterMocker puts mocker to the list of controller mockers
Expand Down
37 changes: 35 additions & 2 deletions mock_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

func TestNewController(t *testing.T) {
c := NewController(t)
assert.Equal(t, t, c.Tester)
assert.Equal(t, &safeTester{Tester: t}, c.Tester)
}

func TestController_RegisterMocker(t *testing.T) {
Expand All @@ -20,7 +20,6 @@ func TestController_RegisterMocker(t *testing.T) {
}

type dummyMocker struct {
Mocker
finishCounter int32
waitCounter int32
}
Expand Down Expand Up @@ -52,3 +51,37 @@ func TestController_Wait(t *testing.T) {
c.Wait(0)
assert.Equal(t, int32(2), atomic.LoadInt32(&dm.waitCounter))
}

func TestController_WaitConcurrent(t *testing.T) {
um1 := &unsafeMocker{}
um2 := &unsafeMocker{}

c := &Controller{
Tester: newSafeTester(&unsafeTester{}),
mockers: []Mocker{um1, um2},
}

um1.tester = c
um2.tester = c

c.Wait(0) //shouln't produce data races
}

type unsafeMocker struct {
Mocker
tester Tester
}

func (um *unsafeMocker) MinimockWait(time.Duration) {
um.tester.FailNow()
}

type unsafeTester struct {
Tester

finished bool
}

func (u *unsafeTester) FailNow() {
u.finished = true
}
52 changes: 52 additions & 0 deletions safe_tester.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package minimock

import "sync"

type safeTester struct {
Tester
m sync.Mutex
}

func newSafeTester(t Tester) *safeTester {
return &safeTester{Tester: t}
}

// Error implements Tester
func (st *safeTester) Error(args ...interface{}) {
st.m.Lock()
defer st.m.Unlock()

st.Tester.Error(args...)
}

// Errorf implements Tester
func (st *safeTester) Errorf(format string, args ...interface{}) {
st.m.Lock()
defer st.m.Unlock()

st.Tester.Fatalf(format, args...)
}

// Fatal implements Tester
func (st *safeTester) Fatal(args ...interface{}) {
st.m.Lock()
defer st.m.Unlock()

st.Tester.Fatal(args...)
}

// Fatalf implements Tester
func (st *safeTester) Fatalf(format string, args ...interface{}) {
st.m.Lock()
defer st.m.Unlock()

st.Tester.Fatalf(format, args...)
}

// FailNow implements Tester
func (st *safeTester) FailNow() {
st.m.Lock()
defer st.m.Unlock()

st.Tester.FailNow()
}

0 comments on commit bf7e7c7

Please sign in to comment.