diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2026-06-30 16:03:45 -0230 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2026-06-30 16:03:45 -0230 |
| commit | 7d0f3d56121feccfe84600a39c362ba8bfcaa042 (patch) | |
| tree | 0e412db49a133af1020ae13d6a0f3930fa04ee06 /callback_test.go | |
| download | xmrpayclnt-7d0f3d56121feccfe84600a39c362ba8bfcaa042.zip | |
init
Diffstat (limited to 'callback_test.go')
| -rw-r--r-- | callback_test.go | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/callback_test.go b/callback_test.go new file mode 100644 index 0000000..c9de48a --- /dev/null +++ b/callback_test.go @@ -0,0 +1,137 @@ +package xmrpayclnt + +import ( + "net/url" + "testing" + "testing/synctest" + "time" + + "github.com/stretchr/testify/require" + "gitlab.com/moneropay/moneropay/v2/pkg/model" +) + +func newTestCallback(t *testing.T) Callback { + id := newCallbackId() + base, err := url.Parse("http://localhost") + require.NoError(t, err) + url := callbackUrl(base, id) + done := make(chan callbackId) + go func() { + // signal to callback that it can close + id := <-done + done <- id + close(done) + }() + return newCallback(id, url, done) +} + +func TestCallbackRx(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + cb := newTestCallback(t) + defer cb.Close() + info := model.CallbackResponse{ + Description: "lorem ipsum", + CreatedAt: time.Now(), + } + cb.in <- info + synctest.Wait() + require.Equal(t, info, <-cb.C) + }) +} + +// Callback blocks until it receives another callback POST request. +func TestCallbackBlockUntilRx(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + cb := newTestCallback(t) + defer cb.Close() + info := model.CallbackResponse{ + Description: "lorem ipsum", + CreatedAt: time.Now(), + } + + for i := 0; i < 5; i++ { + requireBlockingf(t, cb.C, "callback not blocking") + cb.in <- info + synctest.Wait() + require.Equal(t, info, <-cb.C) + } + }) +} + +// C and Complete channels closed when transaction completes. +func TestCallbackComplete(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + cb := newTestCallback(t) + defer cb.Close() + + info := model.CallbackResponse{ + Description: "lorem ipsum", + CreatedAt: time.Now(), + } + cb.in <- info + require.Equal(t, info, <-cb.C) + requireOpenf(t, cb.Complete, "complete channel closed before transaction is complete") + + info.Complete = true + cb.in <- info + requireClosedf(t, cb.C, "channel not closed once transaction is finished") + requireClosedf(t, cb.Complete, "complete channel not closed once transaction finished") + }) +} + +// Channels closed when callback closed +func TestCallbackClose(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + cb := newTestCallback(t) + requireOpen(t, cb.C) + requireOpen(t, cb.Complete) + cb.Close() + requireClosed(t, cb.C) + requireClosed(t, cb.Complete) + }) +} + +func requireBlockingf[T any](t *testing.T, c <-chan T, msg string, args ...any) { + t.Helper() + synctest.Wait() + select { + case <-c: + t.Fatalf(msg, args...) + default: + } +} + +func requireOpen[T any](t *testing.T, c <-chan T) { + t.Helper() + requireOpenf(t, c, "channel not open") +} + +func requireOpenf[T any](t *testing.T, c <-chan T, msg string, args ...any) { + t.Helper() + synctest.Wait() + select { + case _, ok := <-c: + if !ok { + t.Fatalf(msg, args...) + } + default: + } +} + +func requireClosed[T any](t *testing.T, c <-chan T) { + t.Helper() + requireClosedf(t, c, "channel not closed") +} + +func requireClosedf[T any](t *testing.T, c <-chan T, msg string, args ...any) { + t.Helper() + synctest.Wait() + select { + case _, ok := <-c: + if ok { + t.Fatalf(msg, args...) + } + default: + t.Fatalf(msg, args...) + } +} |