1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2025-03-19 14:17:48 +02:00
pocketbase/apis/realtime_test.go

537 lines
17 KiB
Go
Raw Normal View History

2022-07-07 00:19:05 +03:00
package apis_test
import (
2024-09-29 19:23:19 +03:00
"context"
"errors"
"fmt"
2022-07-07 00:19:05 +03:00
"net/http"
"strings"
"testing"
"time"
2022-07-07 00:19:05 +03:00
"github.com/pocketbase/dbx"
2022-07-07 00:19:05 +03:00
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/subscriptions"
)
func TestRealtimeConnect(t *testing.T) {
scenarios := []tests.ApiScenario{
{
Method: http.MethodGet,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
Timeout: 100 * time.Millisecond,
2022-07-07 00:19:05 +03:00
ExpectedStatus: 200,
ExpectedContent: []string{
`id:`,
`event:PB_CONNECT`,
`data:{"clientId":`,
},
ExpectedEvents: map[string]int{
2024-09-29 19:23:19 +03:00
"*": 0,
"OnRealtimeConnectRequest": 1,
"OnRealtimeMessageSend": 1,
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if len(app.SubscriptionsBroker().Clients()) != 0 {
t.Errorf("Expected the subscribers to be removed after connection close, found %d", len(app.SubscriptionsBroker().Clients()))
}
},
},
{
Name: "PB_CONNECT interrupt",
Method: http.MethodGet,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
Timeout: 100 * time.Millisecond,
ExpectedStatus: 200,
ExpectedEvents: map[string]int{
2024-09-29 19:23:19 +03:00
"*": 0,
"OnRealtimeConnectRequest": 1,
"OnRealtimeMessageSend": 1,
},
2024-09-29 19:23:19 +03:00
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.OnRealtimeMessageSend().BindFunc(func(e *core.RealtimeMessageEvent) error {
if e.Message.Name == "PB_CONNECT" {
return errors.New("PB_CONNECT error")
}
2024-09-29 19:23:19 +03:00
return e.Next()
})
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if len(app.SubscriptionsBroker().Clients()) != 0 {
t.Errorf("Expected the subscribers to be removed after connection close, found %d", len(app.SubscriptionsBroker().Clients()))
}
},
},
{
Name: "Skipping/ignoring messages",
Method: http.MethodGet,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
Timeout: 100 * time.Millisecond,
ExpectedStatus: 200,
ExpectedEvents: map[string]int{
2024-09-29 19:23:19 +03:00
"*": 0,
"OnRealtimeConnectRequest": 1,
"OnRealtimeMessageSend": 1,
},
2024-09-29 19:23:19 +03:00
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.OnRealtimeMessageSend().BindFunc(func(e *core.RealtimeMessageEvent) error {
return nil
})
2022-07-07 00:19:05 +03:00
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
2022-07-07 00:19:05 +03:00
if len(app.SubscriptionsBroker().Clients()) != 0 {
t.Errorf("Expected the subscribers to be removed after connection close, found %d", len(app.SubscriptionsBroker().Clients()))
}
},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
func TestRealtimeSubscribe(t *testing.T) {
client := subscriptions.NewDefaultClient()
resetClient := func() {
client.Unsubscribe()
2024-09-29 19:23:19 +03:00
client.Set(apis.RealtimeClientAuthKey, nil)
2022-07-07 00:19:05 +03:00
}
validSubscriptionsLimit := make([]string, 1000)
for i := 0; i < len(validSubscriptionsLimit); i++ {
validSubscriptionsLimit[i] = fmt.Sprintf(`"%d"`, i)
}
invalidSubscriptionsLimit := make([]string, 1001)
for i := 0; i < len(invalidSubscriptionsLimit); i++ {
invalidSubscriptionsLimit[i] = fmt.Sprintf(`"%d"`, i)
}
2022-07-07 00:19:05 +03:00
scenarios := []tests.ApiScenario{
{
Name: "missing client",
Method: http.MethodPost,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
2022-07-07 00:19:05 +03:00
Body: strings.NewReader(`{"clientId":"missing","subscriptions":["test1", "test2"]}`),
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
2024-09-29 19:23:19 +03:00
ExpectedEvents: map[string]int{"*": 0},
2022-07-07 00:19:05 +03:00
},
{
Name: "empty data",
Method: http.MethodPost,
URL: "/api/realtime",
Body: strings.NewReader(`{}`),
ExpectedStatus: 400,
ExpectedContent: []string{
`"data":{`,
`"clientId":{"code":"validation_required`,
},
NotExpectedContent: []string{
`"subscriptions"`,
},
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "existing client with invalid subscriptions limit",
Method: http.MethodPost,
URL: "/api/realtime",
Body: strings.NewReader(`{
"clientId": "` + client.Id() + `",
"subscriptions": [` + strings.Join(invalidSubscriptionsLimit, ",") + `]
}`),
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
resetClient()
},
ExpectedStatus: 400,
ExpectedContent: []string{
`"data":{`,
`"subscriptions":{"code":"validation_length_too_long"`,
},
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "existing client with valid subscriptions limit",
Method: http.MethodPost,
URL: "/api/realtime",
Body: strings.NewReader(`{
"clientId": "` + client.Id() + `",
"subscriptions": [` + strings.Join(validSubscriptionsLimit, ",") + `]
}`),
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
"*": 0,
"OnRealtimeSubscribeRequest": 1,
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
client.Subscribe("test0") // should be replaced
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if len(client.Subscriptions()) != len(validSubscriptionsLimit) {
t.Errorf("Expected %d subscriptions, got %d", len(validSubscriptionsLimit), len(client.Subscriptions()))
}
if client.HasSubscription("test0") {
t.Errorf("Expected old subscriptions to be replaced")
}
resetClient()
},
},
2022-07-07 00:19:05 +03:00
{
Name: "existing client - empty subscriptions",
Method: http.MethodPost,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
2022-07-07 00:19:05 +03:00
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":[]}`),
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
2024-09-29 19:23:19 +03:00
"*": 0,
"OnRealtimeSubscribeRequest": 1,
2022-07-07 00:19:05 +03:00
},
2024-09-29 19:23:19 +03:00
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
2022-07-07 00:19:05 +03:00
client.Subscribe("test0")
app.SubscriptionsBroker().Register(client)
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
2022-07-07 00:19:05 +03:00
if len(client.Subscriptions()) != 0 {
t.Errorf("Expected no subscriptions, got %d", len(client.Subscriptions()))
2022-07-07 00:19:05 +03:00
}
resetClient()
},
},
{
Name: "existing client - 2 new subscriptions",
Method: http.MethodPost,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
2022-07-07 00:19:05 +03:00
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
2024-09-29 19:23:19 +03:00
"*": 0,
"OnRealtimeSubscribeRequest": 1,
2022-07-07 00:19:05 +03:00
},
2024-09-29 19:23:19 +03:00
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
2022-07-07 00:19:05 +03:00
client.Subscribe("test0")
app.SubscriptionsBroker().Register(client)
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
2022-07-07 00:19:05 +03:00
expectedSubs := []string{"test1", "test2"}
if len(expectedSubs) != len(client.Subscriptions()) {
t.Errorf("Expected subscriptions %v, got %v", expectedSubs, client.Subscriptions())
}
for _, s := range expectedSubs {
if !client.HasSubscription(s) {
t.Errorf("Cannot find %q subscription in %v", s, client.Subscriptions())
}
}
resetClient()
},
},
{
Name: "existing client - guest -> authorized superuser",
2022-07-07 00:19:05 +03:00
Method: http.MethodPost,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
2022-07-07 00:19:05 +03:00
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
2024-09-29 19:23:19 +03:00
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
2022-07-07 00:19:05 +03:00
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
2024-09-29 19:23:19 +03:00
"*": 0,
"OnRealtimeSubscribeRequest": 1,
2022-07-07 00:19:05 +03:00
},
2024-09-29 19:23:19 +03:00
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
2022-07-07 00:19:05 +03:00
app.SubscriptionsBroker().Register(client)
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
authRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
if authRecord == nil || !authRecord.IsSuperuser() {
t.Errorf("Expected superuser auth record, got %v", authRecord)
2022-07-07 00:19:05 +03:00
}
resetClient()
},
},
{
Name: "existing client - guest -> authorized regular auth record",
2022-07-07 00:19:05 +03:00
Method: http.MethodPost,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
2022-07-07 00:19:05 +03:00
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
2024-09-29 19:23:19 +03:00
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.ZT3F0Z3iM-xbGgSG3LEKiEzHrPHr8t8IuHLZGGNuxLo",
2022-07-07 00:19:05 +03:00
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
2024-09-29 19:23:19 +03:00
"*": 0,
"OnRealtimeSubscribeRequest": 1,
2022-07-07 00:19:05 +03:00
},
2024-09-29 19:23:19 +03:00
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
2022-07-07 00:19:05 +03:00
app.SubscriptionsBroker().Register(client)
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
authRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
2022-10-30 10:28:14 +02:00
if authRecord == nil {
2024-09-29 19:23:19 +03:00
t.Errorf("Expected regular user auth record, got %v", authRecord)
2022-07-07 00:19:05 +03:00
}
resetClient()
},
},
{
Name: "existing client - same auth",
Method: http.MethodPost,
URL: "/api/realtime",
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.ZT3F0Z3iM-xbGgSG3LEKiEzHrPHr8t8IuHLZGGNuxLo",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
"*": 0,
"OnRealtimeSubscribeRequest": 1,
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
// the same user as the auth token
user, err := app.FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
client.Set(apis.RealtimeClientAuthKey, user)
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
authRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
if authRecord == nil {
t.Errorf("Expected auth record model, got nil")
}
resetClient()
},
},
2022-07-07 00:19:05 +03:00
{
Name: "existing client - mismatched auth",
Method: http.MethodPost,
2024-09-29 19:23:19 +03:00
URL: "/api/realtime",
2022-07-07 00:19:05 +03:00
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
2024-09-29 19:23:19 +03:00
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.ZT3F0Z3iM-xbGgSG3LEKiEzHrPHr8t8IuHLZGGNuxLo",
},
ExpectedStatus: 403,
ExpectedContent: []string{`"data":{}`},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
user, err := app.FindAuthRecordByEmail("users", "test2@example.com")
if err != nil {
t.Fatal(err)
}
client.Set(apis.RealtimeClientAuthKey, user)
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
authRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
if authRecord == nil {
t.Errorf("Expected auth record model, got nil")
}
resetClient()
2022-07-07 00:19:05 +03:00
},
2024-09-29 19:23:19 +03:00
},
{
Name: "existing client - unauthorized client",
Method: http.MethodPost,
URL: "/api/realtime",
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
2022-07-07 00:19:05 +03:00
ExpectedStatus: 403,
ExpectedContent: []string{`"data":{}`},
2024-09-29 19:23:19 +03:00
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
user, err := app.FindAuthRecordByEmail("users", "test2@example.com")
if err != nil {
t.Fatal(err)
}
client.Set(apis.RealtimeClientAuthKey, user)
2022-07-07 00:19:05 +03:00
app.SubscriptionsBroker().Register(client)
},
2024-09-29 19:23:19 +03:00
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
authRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
2022-10-30 10:28:14 +02:00
if authRecord == nil {
t.Errorf("Expected auth record model, got nil")
2022-07-07 00:19:05 +03:00
}
resetClient()
},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
2022-10-30 10:28:14 +02:00
func TestRealtimeAuthRecordDeleteEvent(t *testing.T) {
2022-07-07 00:19:05 +03:00
testApp, _ := tests.NewTestApp()
defer testApp.Cleanup()
2024-09-29 19:23:19 +03:00
// init realtime handlers
apis.NewRouter(testApp)
2022-07-07 00:19:05 +03:00
2024-09-29 19:23:19 +03:00
authRecord, err := testApp.FindAuthRecordByEmail("users", "test@example.com")
2022-07-07 00:19:05 +03:00
if err != nil {
t.Fatal(err)
}
client := subscriptions.NewDefaultClient()
2024-09-29 19:23:19 +03:00
client.Set(apis.RealtimeClientAuthKey, authRecord)
2022-07-07 00:19:05 +03:00
testApp.SubscriptionsBroker().Register(client)
2024-09-29 19:23:19 +03:00
// mock delete event
e := new(core.ModelEvent)
2024-09-29 19:23:19 +03:00
e.App = testApp
e.Type = core.ModelEventTypeDelete
e.Context = context.Background()
e.Model = authRecord
2022-07-07 00:19:05 +03:00
2024-09-29 19:23:19 +03:00
testApp.OnModelAfterDeleteSuccess().Trigger(e)
if total := len(testApp.SubscriptionsBroker().Clients()); total != 0 {
t.Fatalf("Expected no subscription clients, found %d", total)
2022-07-07 00:19:05 +03:00
}
}
2022-10-30 10:28:14 +02:00
func TestRealtimeAuthRecordUpdateEvent(t *testing.T) {
2022-07-07 00:19:05 +03:00
testApp, _ := tests.NewTestApp()
defer testApp.Cleanup()
2024-09-29 19:23:19 +03:00
// init realtime handlers
apis.NewRouter(testApp)
2022-07-07 00:19:05 +03:00
2024-09-29 19:23:19 +03:00
authRecord1, err := testApp.FindAuthRecordByEmail("users", "test@example.com")
2022-07-07 00:19:05 +03:00
if err != nil {
t.Fatal(err)
}
client := subscriptions.NewDefaultClient()
2024-09-29 19:23:19 +03:00
client.Set(apis.RealtimeClientAuthKey, authRecord1)
2022-07-07 00:19:05 +03:00
testApp.SubscriptionsBroker().Register(client)
2022-10-30 10:28:14 +02:00
// refetch the authRecord and change its email
2024-09-29 19:23:19 +03:00
authRecord2, err := testApp.FindAuthRecordByEmail("users", "test@example.com")
2022-07-07 00:19:05 +03:00
if err != nil {
t.Fatal(err)
}
2022-10-30 10:28:14 +02:00
authRecord2.SetEmail("new@example.com")
2022-07-07 00:19:05 +03:00
2024-09-29 19:23:19 +03:00
// mock update event
e := new(core.ModelEvent)
2024-09-29 19:23:19 +03:00
e.App = testApp
e.Type = core.ModelEventTypeUpdate
e.Context = context.Background()
e.Model = authRecord2
2022-07-07 00:19:05 +03:00
2024-09-29 19:23:19 +03:00
testApp.OnModelAfterUpdateSuccess().Trigger(e)
clientAuthRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
2022-10-30 10:28:14 +02:00
if clientAuthRecord.Email() != authRecord2.Email() {
t.Fatalf("Expected authRecord with email %q, got %q", authRecord2.Email(), clientAuthRecord.Email())
2022-07-07 00:19:05 +03:00
}
}
// Custom auth record model struct
// -------------------------------------------------------------------
2024-09-29 19:23:19 +03:00
var _ core.Model = (*CustomUser)(nil)
type CustomUser struct {
2024-09-29 19:23:19 +03:00
core.BaseModel
Email string `db:"email" json:"email"`
}
func (m *CustomUser) TableName() string {
2024-09-29 19:23:19 +03:00
return "users"
}
2024-09-29 19:23:19 +03:00
func findCustomUserByEmail(app core.App, email string) (*CustomUser, error) {
model := &CustomUser{}
2024-09-29 19:23:19 +03:00
err := app.ModelQuery(model).
AndWhere(dbx.HashExp{"email": email}).
Limit(1).
One(model)
if err != nil {
return nil, err
}
return model, nil
}
func TestRealtimeCustomAuthModelDeleteEvent(t *testing.T) {
testApp, _ := tests.NewTestApp()
defer testApp.Cleanup()
2024-09-29 19:23:19 +03:00
// init realtime handlers
apis.NewRouter(testApp)
2024-09-29 19:23:19 +03:00
authRecord, err := testApp.FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
client := subscriptions.NewDefaultClient()
2024-09-29 19:23:19 +03:00
client.Set(apis.RealtimeClientAuthKey, authRecord)
testApp.SubscriptionsBroker().Register(client)
// refetch the authRecord as CustomUser
2024-09-29 19:23:19 +03:00
customUser, err := findCustomUserByEmail(testApp, "test@example.com")
if err != nil {
t.Fatal(err)
}
// delete the custom user (should unset the client auth record)
2024-09-29 19:23:19 +03:00
if err := testApp.Delete(customUser); err != nil {
t.Fatal(err)
}
2024-09-29 19:23:19 +03:00
if total := len(testApp.SubscriptionsBroker().Clients()); total != 0 {
t.Fatalf("Expected no subscription clients, found %d", total)
}
}
func TestRealtimeCustomAuthModelUpdateEvent(t *testing.T) {
testApp, _ := tests.NewTestApp()
defer testApp.Cleanup()
2024-09-29 19:23:19 +03:00
// init realtime handlers
apis.NewRouter(testApp)
2024-09-29 19:23:19 +03:00
authRecord, err := testApp.FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
client := subscriptions.NewDefaultClient()
2024-09-29 19:23:19 +03:00
client.Set(apis.RealtimeClientAuthKey, authRecord)
testApp.SubscriptionsBroker().Register(client)
// refetch the authRecord as CustomUser
2024-09-29 19:23:19 +03:00
customUser, err := findCustomUserByEmail(testApp, "test@example.com")
if err != nil {
t.Fatal(err)
}
// change its email
customUser.Email = "new@example.com"
2024-09-29 19:23:19 +03:00
if err := testApp.Save(customUser); err != nil {
t.Fatal(err)
}
2024-09-29 19:23:19 +03:00
clientAuthRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
if clientAuthRecord.Email() != customUser.Email {
t.Fatalf("Expected authRecord with email %q, got %q", customUser.Email, clientAuthRecord.Email())
}
}