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...) } }