137 lines
5.1 KiB
Go
137 lines
5.1 KiB
Go
package processor
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"apskel-pos-be/internal/repository"
|
|
)
|
|
|
|
// customerDeviceRepoFake keeps devices the way the table does: one row per customer
|
|
// and device, and a token belongs to one row only.
|
|
type customerDeviceRepoFake struct{ devices []repository.CustomerDevice }
|
|
|
|
func (f *customerDeviceRepoFake) Register(_ context.Context, d repository.CustomerDevice, _ time.Time) error {
|
|
kept := f.devices[:0]
|
|
for _, existing := range f.devices {
|
|
sameRow := existing.CustomerID == d.CustomerID && existing.DeviceID == d.DeviceID
|
|
if !sameRow && existing.FCMToken != d.FCMToken {
|
|
kept = append(kept, existing)
|
|
}
|
|
}
|
|
f.devices = append(kept, d)
|
|
return nil
|
|
}
|
|
|
|
func (f *customerDeviceRepoFake) Unregister(_ context.Context, customerID uuid.UUID, deviceID string) error {
|
|
kept := f.devices[:0]
|
|
for _, d := range f.devices {
|
|
if d.CustomerID != customerID || d.DeviceID != deviceID {
|
|
kept = append(kept, d)
|
|
}
|
|
}
|
|
f.devices = kept
|
|
return nil
|
|
}
|
|
|
|
func (f *customerDeviceRepoFake) ListTokens(_ context.Context, customerID uuid.UUID) ([]string, error) {
|
|
var tokens []string
|
|
for _, d := range f.devices {
|
|
if d.CustomerID == customerID {
|
|
tokens = append(tokens, d.FCMToken)
|
|
}
|
|
}
|
|
return tokens, nil
|
|
}
|
|
|
|
type fcmFake struct {
|
|
tokens [][]string
|
|
title string
|
|
body string
|
|
data map[string]string
|
|
err error
|
|
}
|
|
|
|
func (f *fcmFake) SendMulticastNotification(_ context.Context, tokens []string, title, body string, data map[string]string) error {
|
|
f.tokens = append(f.tokens, tokens)
|
|
f.title, f.body, f.data = title, body, data
|
|
return f.err
|
|
}
|
|
|
|
func TestCustomerDevice_NotifiesEveryDeviceOfTheCustomer(t *testing.T) {
|
|
repo, fcm := &customerDeviceRepoFake{}, &fcmFake{}
|
|
p := NewCustomerDeviceProcessor(repo, fcm)
|
|
ctx := context.Background()
|
|
budi, anita := uuid.New(), uuid.New()
|
|
|
|
require.NoError(t, p.Register(ctx, repository.CustomerDevice{CustomerID: budi, DeviceID: "phone", FCMToken: "t1", Platform: ptr("Android")}))
|
|
require.NoError(t, p.Register(ctx, repository.CustomerDevice{CustomerID: budi, DeviceID: "tablet", FCMToken: "t2"}))
|
|
// A refreshed token replaces the old one of the same device.
|
|
require.NoError(t, p.Register(ctx, repository.CustomerDevice{CustomerID: budi, DeviceID: "phone", FCMToken: "t1b"}))
|
|
require.NoError(t, p.Register(ctx, repository.CustomerDevice{CustomerID: anita, DeviceID: "phone", FCMToken: "t3"}))
|
|
|
|
require.NoError(t, p.Notify(ctx, budi, "EnakPoint masuk", "Kamu menerima 10 EnakPoint", map[string]string{"type": "X"}))
|
|
assert.Equal(t, [][]string{{"t2", "t1b"}}, fcm.tokens)
|
|
assert.Equal(t, "EnakPoint masuk", fcm.title)
|
|
assert.Equal(t, map[string]string{"type": "X"}, fcm.data)
|
|
}
|
|
|
|
func TestCustomerDevice_TokenMovesToWhoeverLogsInOnThePhone(t *testing.T) {
|
|
repo, fcm := &customerDeviceRepoFake{}, &fcmFake{}
|
|
p := NewCustomerDeviceProcessor(repo, fcm)
|
|
ctx := context.Background()
|
|
budi, anita := uuid.New(), uuid.New()
|
|
|
|
require.NoError(t, p.Register(ctx, repository.CustomerDevice{CustomerID: budi, DeviceID: "phone", FCMToken: "shared"}))
|
|
require.NoError(t, p.Register(ctx, repository.CustomerDevice{CustomerID: anita, DeviceID: "phone", FCMToken: "shared"}))
|
|
|
|
// Budi's notifications no longer reach the phone Anita is now logged in on.
|
|
require.NoError(t, p.Notify(ctx, budi, "t", "b", nil))
|
|
require.NoError(t, p.Notify(ctx, anita, "t", "b", nil))
|
|
assert.Equal(t, [][]string{{"shared"}}, fcm.tokens)
|
|
}
|
|
|
|
func TestCustomerDevice_NothingToSend(t *testing.T) {
|
|
repo, fcm := &customerDeviceRepoFake{}, &fcmFake{}
|
|
ctx := context.Background()
|
|
customer := uuid.New()
|
|
|
|
// No device registered, or logged out: nothing is sent and nothing fails.
|
|
require.NoError(t, NewCustomerDeviceProcessor(repo, fcm).Notify(ctx, customer, "t", "b", nil))
|
|
require.NoError(t, NewCustomerDeviceProcessor(repo, fcm).Register(ctx, repository.CustomerDevice{CustomerID: customer, DeviceID: "phone", FCMToken: "t1"}))
|
|
require.NoError(t, NewCustomerDeviceProcessor(repo, fcm).Unregister(ctx, customer, "phone"))
|
|
require.NoError(t, NewCustomerDeviceProcessor(repo, fcm).Notify(ctx, customer, "t", "b", nil))
|
|
assert.Empty(t, fcm.tokens)
|
|
|
|
// FCM not configured.
|
|
require.NoError(t, NewCustomerDeviceProcessor(repo, nil).Notify(ctx, customer, "t", "b", nil))
|
|
}
|
|
|
|
func TestCustomerDevice_FCMFailureIsReported(t *testing.T) {
|
|
repo, fcm := &customerDeviceRepoFake{}, &fcmFake{err: errors.New("unavailable")}
|
|
p := NewCustomerDeviceProcessor(repo, fcm)
|
|
ctx := context.Background()
|
|
customer := uuid.New()
|
|
require.NoError(t, p.Register(ctx, repository.CustomerDevice{CustomerID: customer, DeviceID: "phone", FCMToken: "t1"}))
|
|
|
|
assert.Error(t, p.Notify(ctx, customer, "t", "b", nil))
|
|
}
|
|
|
|
func TestCustomerDevice_RejectsIncompleteRegistrations(t *testing.T) {
|
|
p := NewCustomerDeviceProcessor(&customerDeviceRepoFake{}, nil)
|
|
ctx := context.Background()
|
|
for name, d := range map[string]repository.CustomerDevice{
|
|
"no device": {FCMToken: "t"},
|
|
"no token": {DeviceID: "phone", FCMToken: " "},
|
|
"bad platform": {DeviceID: "phone", FCMToken: "t", Platform: ptr("symbian")},
|
|
} {
|
|
assert.ErrorIs(t, p.Register(ctx, d), ErrInvalidCustomerDevice, name)
|
|
}
|
|
}
|