diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52f4c9c..a1183f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,9 +87,11 @@ jobs: - name: 'Test on [linux] arch [arm64]' if: ${{ matrix.os == 'linux' && contains(fromJson('["arm64"]'), matrix.arch) }} - run: go test -coverpkg=./mock/... ./... + - name: 'Test on [darwin] arch [arm64]' + if: ${{ matrix.os == 'darwin' && contains(fromJson('["arm64"]'), matrix.arch) }} + run: go test -coverpkg=./mock/... ./... - name: 'Test on windows' if: ${{ matrix.os == 'windows' && contains(fromJson('["amd64"]'), matrix.arch) }} diff --git a/go.mod b/go.mod index 1904c8d..3873228 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.21 require ( github.com/ovechkin-dm/go-dyno v0.0.14 - github.com/timandy/routine v1.1.1 ) - +require github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc // indirect diff --git a/go.sum b/go.sum index 6df5f07..1ae61ec 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ovechkin-dm/go-dyno v0.0.14 h1:PqcZ1xWJCd6nWdkIRRdU4IyUdDlA5bjfJKSGXnM9seA= github.com/ovechkin-dm/go-dyno v0.0.14/go.mod h1:CcJNuo7AbePMoRNpM3i1jC1Rp9kHEMyWozNdWzR+0ys= +github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc h1:8bQZVK1X6BJR/6nYUPxQEP+ReTsceJTKizeuwjWOPUA= +github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= diff --git a/registry/registry.go b/registry/registry.go index e429c4c..7020e68 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -4,13 +4,14 @@ import ( "fmt" "github.com/ovechkin-dm/go-dyno/pkg/dyno" "github.com/ovechkin-dm/mockio/matchers" - "github.com/timandy/routine" + "github.com/ovechkin-dm/mockio/threadlocal" + "log" "reflect" "sync" ) -var instance = routine.NewThreadLocalWithInitial(newRegistry) +var instance = threadlocal.NewThreadLocal(newRegistry) var lock sync.Mutex type Registry struct { @@ -37,7 +38,7 @@ func SetUp(reporter matchers.ErrorReporter) { func TearDown() { reg := getInstance() - instance.Remove() + instance.Clear() if reg.mockContext.reporter == nil { reg.mockContext.reporter.Errorf("Cannot TearDown since SetUp function wasn't called") @@ -138,7 +139,7 @@ func withCheck[T any](f func() T) T { log.Println("Warning: reporter is not initialized. You can initialize it with `SetUp(*testing.T)`. Defaulting to the panic reporter. This could also happen when using mocks concurrently") } initRoutineID := getInstance().mockContext.routineID - if initRoutineID != routine.Goid() { + if initRoutineID != threadlocal.GoId() { rep.Fatalf("Call to mock api from a different goroutine. `When` or `Verify` can only be used from the initial goroutine.") } return f() diff --git a/registry/state.go b/registry/state.go index b20aaec..847f067 100644 --- a/registry/state.go +++ b/registry/state.go @@ -3,7 +3,7 @@ package registry import ( "github.com/ovechkin-dm/go-dyno/pkg/dyno" "github.com/ovechkin-dm/mockio/matchers" - "github.com/timandy/routine" + "github.com/ovechkin-dm/mockio/threadlocal" "reflect" "sync" "sync/atomic" @@ -20,7 +20,7 @@ type fiberState struct { } type mockContext struct { - state routine.ThreadLocal + state threadlocal.ThreadLocal[*fiberState] reporter *EnrichedReporter lock sync.Mutex routineID int64 @@ -92,12 +92,12 @@ type matcherWrapper struct { } func (ctx *mockContext) getState() *fiberState { - return ctx.state.Get().(*fiberState) + return ctx.state.Get() } func newMockContext(reporter *EnrichedReporter) *mockContext { return &mockContext{ - state: routine.NewThreadLocalWithInitial(func() any { + state: threadlocal.NewThreadLocal(func() *fiberState { return &fiberState{ matchers: make([]*matcherWrapper, 0), whenHandler: nil, @@ -108,7 +108,7 @@ func newMockContext(reporter *EnrichedReporter) *mockContext { }), reporter: reporter, lock: sync.Mutex{}, - routineID: routine.Goid(), + routineID: threadlocal.GoId(), } } diff --git a/threadlocal/threadlocal.go b/threadlocal/threadlocal.go new file mode 100644 index 0000000..3c63e4e --- /dev/null +++ b/threadlocal/threadlocal.go @@ -0,0 +1,49 @@ +package threadlocal + +import ( + "github.com/petermattis/goid" + "sync" +) + +type ThreadLocal[T any] interface { + Get() T + Set(t T) + Clear() +} + +type impl[T any] struct { + data sync.Map + init func() T +} + +func (i *impl[T]) Get() T { + id := goid.Get() + v, ok := i.data.Load(id) + if !ok { + nv := i.init() + i.data.Store(id, nv) + return nv + } + return v.(T) +} + +func (i *impl[T]) Set(t T) { + id := goid.Get() + i.data.Store(id, t) +} + +func (i *impl[T]) Clear() { + id := goid.Get() + i.data.Delete(id) +} + +func NewThreadLocal[T any](initFunc func() T) ThreadLocal[T] { + return &impl[T]{ + data: sync.Map{}, + init: initFunc, + } +} + +func GoId() int64 { + return goid.Get() +} \ No newline at end of file