diff --git a/apis/admin_test.go b/apis/admin_test.go index a750b1be..f7cf3a05 100644 --- a/apis/admin_test.go +++ b/apis/admin_test.go @@ -1,6 +1,7 @@ package apis_test import ( + "errors" "net/http" "strings" "testing" @@ -8,6 +9,7 @@ import ( "github.com/labstack/echo/v5" "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/daos" "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tests" @@ -89,6 +91,26 @@ func TestAdminAuthWithPassword(t *testing.T) { "OnAdminAuthRequest": 1, }, }, + { + Name: "OnAdminAfterAuthWithPasswordRequest error response", + Method: http.MethodPost, + Url: "/api/admins/auth-with-password", + Body: strings.NewReader(`{"identity":"test@example.com","password":"1234567890"}`), + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4MTYwMH0.han3_sG65zLddpcX2ic78qgy7FKecuPfOpFa8Dvi5Bg", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnAdminAfterAuthWithPasswordRequest().Add(func(e *core.AdminAuthWithPasswordEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnAdminBeforeAuthWithPasswordRequest": 1, + "OnAdminAfterAuthWithPasswordRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -224,6 +246,29 @@ func TestAdminConfirmPasswordReset(t *testing.T) { "OnAdminAfterConfirmPasswordResetRequest": 1, }, }, + { + Name: "OnAdminAfterConfirmPasswordResetRequest error response", + Method: http.MethodPost, + Url: "/api/admins/confirm-password-reset", + Body: strings.NewReader(`{ + "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImV4cCI6MjIwODk4MTYwMH0.kwFEler6KSMKJNstuaSDvE1QnNdCta5qSnjaIQ0hhhc", + "password":"1234567891", + "passwordConfirm":"1234567891" + }`), + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnAdminAfterConfirmPasswordResetRequest().Add(func(e *core.AdminConfirmPasswordResetEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelBeforeUpdate": 1, + "OnModelAfterUpdate": 1, + "OnAdminBeforeConfirmPasswordResetRequest": 1, + "OnAdminAfterConfirmPasswordResetRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -278,6 +323,25 @@ func TestAdminRefresh(t *testing.T) { "OnAdminAfterAuthRefreshRequest": 1, }, }, + { + Name: "OnAdminAfterAuthRefreshRequest error response", + Method: http.MethodPost, + Url: "/api/admins/auth-refresh", + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnAdminAfterAuthRefreshRequest().Add(func(e *core.AdminAuthRefreshEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnAdminBeforeAuthRefreshRequest": 1, + "OnAdminAfterAuthRefreshRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -510,6 +574,27 @@ func TestAdminDelete(t *testing.T) { "OnAdminBeforeDeleteRequest": 1, }, }, + { + Name: "OnAdminAfterDeleteRequest error response", + Method: http.MethodDelete, + Url: "/api/admins/sbmbsdb40jyxf7h", + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnAdminAfterDeleteRequest().Add(func(e *core.AdminDeleteEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelBeforeDelete": 1, + "OnModelAfterDelete": 1, + "OnAdminBeforeDeleteRequest": 1, + "OnAdminAfterDeleteRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -637,6 +722,33 @@ func TestAdminCreate(t *testing.T) { "OnAdminAfterCreateRequest": 1, }, }, + { + Name: "OnAdminAfterCreateRequest error response", + Method: http.MethodPost, + Url: "/api/admins", + Body: strings.NewReader(`{ + "email":"testnew@example.com", + "password":"1234567890", + "passwordConfirm":"1234567890", + "avatar":3 + }`), + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnAdminAfterCreateRequest().Add(func(e *core.AdminCreateEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelBeforeCreate": 1, + "OnModelAfterCreate": 1, + "OnAdminBeforeCreateRequest": 1, + "OnAdminAfterCreateRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -729,6 +841,7 @@ func TestAdminUpdate(t *testing.T) { }, }, { + Name: "authorized as admin + valid data", Method: http.MethodPatch, Url: "/api/admins/sbmbsdb40jyxf7h", Body: strings.NewReader(`{ @@ -759,6 +872,33 @@ func TestAdminUpdate(t *testing.T) { "OnAdminAfterUpdateRequest": 1, }, }, + { + Name: "OnAdminAfterUpdateRequest error response", + Method: http.MethodPatch, + Url: "/api/admins/sbmbsdb40jyxf7h", + Body: strings.NewReader(`{ + "email":"testnew@example.com", + "password":"1234567891", + "passwordConfirm":"1234567891", + "avatar":5 + }`), + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnAdminAfterUpdateRequest().Add(func(e *core.AdminUpdateEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelBeforeUpdate": 1, + "OnModelAfterUpdate": 1, + "OnAdminBeforeUpdateRequest": 1, + "OnAdminAfterUpdateRequest": 1, + }, + }, } for _, scenario := range scenarios { diff --git a/apis/collection_test.go b/apis/collection_test.go index 746fe7d4..84bfcae1 100644 --- a/apis/collection_test.go +++ b/apis/collection_test.go @@ -1,6 +1,7 @@ package apis_test import ( + "errors" "net/http" "os" "path/filepath" @@ -9,6 +10,7 @@ import ( "time" "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/models/schema" "github.com/pocketbase/pocketbase/tests" @@ -299,7 +301,6 @@ func TestCollectionDelete(t *testing.T) { RequestHeaders: map[string]string{ "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", }, - Delay: 100 * time.Millisecond, ExpectedStatus: 204, ExpectedEvents: map[string]int{ "OnModelBeforeDelete": 1, @@ -308,6 +309,27 @@ func TestCollectionDelete(t *testing.T) { "OnCollectionAfterDeleteRequest": 1, }, }, + { + Name: "OnCollectionAfterDeleteRequest error response", + Method: http.MethodDelete, + Url: "/api/collections/view2", + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnCollectionAfterDeleteRequest().Add(func(e *core.CollectionDeleteEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelBeforeDelete": 1, + "OnModelAfterDelete": 1, + "OnCollectionBeforeDeleteRequest": 1, + "OnCollectionAfterDeleteRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -536,6 +558,28 @@ func TestCollectionCreate(t *testing.T) { `"options":{"minPasswordLength":{"code":"validation_required"`, }, }, + { + Name: "OnCollectionAfterCreateRequest error response", + Method: http.MethodPost, + Url: "/api/collections", + Body: strings.NewReader(`{"name":"new","type":"base","schema":[{"type":"text","id":"12345789","name":"test"}]}`), + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnCollectionAfterCreateRequest().Add(func(e *core.CollectionCreateEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelBeforeCreate": 1, + "OnModelAfterCreate": 1, + "OnCollectionBeforeCreateRequest": 1, + "OnCollectionAfterCreateRequest": 1, + }, + }, // view // ----------------------------------------------------------- @@ -720,6 +764,28 @@ func TestCollectionUpdate(t *testing.T) { "OnModelBeforeUpdate": 1, }, }, + { + Name: "OnCollectionAfterUpdateRequest error response", + Method: http.MethodPatch, + Url: "/api/collections/demo1", + Body: strings.NewReader(`{}`), + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnCollectionAfterUpdateRequest().Add(func(e *core.CollectionUpdateEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnCollectionAfterUpdateRequest": 1, + "OnCollectionBeforeUpdateRequest": 1, + "OnModelAfterUpdate": 1, + "OnModelBeforeUpdate": 1, + }, + }, { Name: "authorized as admin + invalid data (eg. existing name)", Method: http.MethodPatch, @@ -1373,6 +1439,58 @@ func TestCollectionsImport(t *testing.T) { } }, }, + { + Name: "authorized as admin + successful collections save", + Method: http.MethodPut, + Url: "/api/collections/import", + Body: strings.NewReader(`{ + "collections":[ + { + "name": "import1", + "schema": [ + { + "id": "koih1lqx", + "name": "test", + "type": "text" + } + ] + }, + { + "name": "import2", + "schema": [ + { + "id": "koih1lqx", + "name": "test", + "type": "text" + } + ], + "indexes": [ + "create index idx_test on import2 (test)" + ] + }, + { + "name": "auth_without_schema", + "type": "auth" + } + ] + }`), + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnCollectionsAfterImportRequest().Add(func(e *core.CollectionsImportEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnCollectionsBeforeImportRequest": 1, + "OnCollectionsAfterImportRequest": 1, + "OnModelBeforeCreate": 3, + "OnModelAfterCreate": 3, + }, + }, } for _, scenario := range scenarios { diff --git a/apis/record_auth_test.go b/apis/record_auth_test.go index ca9f5527..cfc2484d 100644 --- a/apis/record_auth_test.go +++ b/apis/record_auth_test.go @@ -2,12 +2,14 @@ package apis_test import ( "context" + "errors" "net/http" "strings" "testing" "time" "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/daos" "github.com/pocketbase/pocketbase/tests" "github.com/pocketbase/pocketbase/tools/subscriptions" @@ -280,6 +282,28 @@ func TestRecordAuthWithPassword(t *testing.T) { "OnRecordAuthRequest": 1, }, }, + + // after hooks error checks + { + Name: "OnRecordAfterAuthWithPasswordRequest error response", + Method: http.MethodPost, + Url: "/api/collections/users/auth-with-password", + Body: strings.NewReader(`{ + "identity":"test2_username", + "password":"1234567890" + }`), + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterAuthWithPasswordRequest().Add(func(e *core.RecordAuthWithPasswordEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnRecordBeforeAuthWithPasswordRequest": 1, + "OnRecordAfterAuthWithPasswordRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -353,6 +377,25 @@ func TestRecordAuthRefresh(t *testing.T) { "OnRecordAfterAuthRefreshRequest": 1, }, }, + { + Name: "OnRecordAfterAuthRefreshRequest error response", + Method: http.MethodPost, + Url: "/api/collections/users/auth-refresh?expand=rel,missing", + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyMjA4OTg1MjYxfQ.UwD8JvkbQtXpymT09d7J6fdA0aP9g4FJ1GPh_ggEkzc", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterAuthRefreshRequest().Add(func(e *core.RecordAuthRefreshEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnRecordBeforeAuthRefreshRequest": 1, + "OnRecordAfterAuthRefreshRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -494,10 +537,8 @@ func TestRecordAuthConfirmPasswordReset(t *testing.T) { "password":"12345678", "passwordConfirm":"12345678" }`), - ExpectedStatus: 400, - ExpectedContent: []string{ - `"data":{}`, - }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, }, { Name: "different auth collection", @@ -530,6 +571,29 @@ func TestRecordAuthConfirmPasswordReset(t *testing.T) { "OnRecordAfterConfirmPasswordResetRequest": 1, }, }, + { + Name: "OnRecordAfterConfirmPasswordResetRequest error response", + Method: http.MethodPost, + Url: "/api/collections/users/confirm-password-reset", + Body: strings.NewReader(`{ + "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImNvbGxlY3Rpb25JZCI6Il9wYl91c2Vyc19hdXRoXyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiZXhwIjoyMjA4OTg1MjYxfQ.R_4FOSUHIuJQ5Crl3PpIPCXMsoHzuTaNlccpXg_3FOg", + "password":"12345678", + "passwordConfirm":"12345678" + }`), + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterConfirmPasswordResetRequest().Add(func(e *core.RecordConfirmPasswordResetEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelAfterUpdate": 1, + "OnModelBeforeUpdate": 1, + "OnRecordBeforeConfirmPasswordResetRequest": 1, + "OnRecordAfterConfirmPasswordResetRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -671,10 +735,8 @@ func TestRecordAuthConfirmVerification(t *testing.T) { Body: strings.NewReader(`{ "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImNvbGxlY3Rpb25JZCI6Il9wYl91c2Vyc19hdXRoXyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiZXhwIjoyMjA4OTg1MjYxfQ.R_4FOSUHIuJQ5Crl3PpIPCXMsoHzuTaNlccpXg_3FOg" }`), - ExpectedStatus: 400, - ExpectedContent: []string{ - `"data":{}`, - }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, }, { Name: "different auth collection", @@ -732,6 +794,27 @@ func TestRecordAuthConfirmVerification(t *testing.T) { "OnRecordAfterConfirmVerificationRequest": 1, }, }, + { + Name: "OnRecordAfterConfirmVerificationRequest error response", + Method: http.MethodPost, + Url: "/api/collections/users/confirm-verification", + Body: strings.NewReader(`{ + "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImNvbGxlY3Rpb25JZCI6Il9wYl91c2Vyc19hdXRoXyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiZXhwIjoyMjA4OTg1MjYxfQ.hL16TVmStHFdHLc4a860bRqJ3sFfzjv0_NRNzwsvsrc" + }`), + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterConfirmVerificationRequest().Add(func(e *core.RecordConfirmVerificationEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelAfterUpdate": 1, + "OnModelBeforeUpdate": 1, + "OnRecordBeforeConfirmVerificationRequest": 1, + "OnRecordAfterConfirmVerificationRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -932,6 +1015,28 @@ func TestRecordAuthConfirmEmailChange(t *testing.T) { `"token":{"code":"validation_token_collection_mismatch"`, }, }, + { + Name: "OnRecordAfterConfirmEmailChangeRequest error response", + Method: http.MethodPost, + Url: "/api/collections/users/confirm-email-change", + Body: strings.NewReader(`{ + "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsImNvbGxlY3Rpb25JZCI6Il9wYl91c2Vyc19hdXRoXyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwibmV3RW1haWwiOiJjaGFuZ2VAZXhhbXBsZS5jb20iLCJleHAiOjIyMDg5ODUyNjF9.1sG6cL708pRXXjiHRZhG-in0X5fnttSf5nNcadKoYRs", + "password":"1234567890" + }`), + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterConfirmEmailChangeRequest().Add(func(e *core.RecordConfirmEmailChangeEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelAfterUpdate": 1, + "OnModelBeforeUpdate": 1, + "OnRecordBeforeConfirmEmailChangeRequest": 1, + "OnRecordAfterConfirmEmailChangeRequest": 1, + }, + }, } for _, scenario := range scenarios { @@ -1140,6 +1245,27 @@ func TestRecordAuthUnlinkExternalsAuth(t *testing.T) { } }, }, + { + Name: "OnRecordBeforeUnlinkExternalAuthRequest error response", + Method: http.MethodDelete, + Url: "/api/collections/users/records/4q1xlclmfloku33/external-auths/google", + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterUnlinkExternalAuthRequest().Add(func(e *core.RecordUnlinkExternalAuthEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelAfterDelete": 1, + "OnModelBeforeDelete": 1, + "OnRecordAfterUnlinkExternalAuthRequest": 1, + "OnRecordBeforeUnlinkExternalAuthRequest": 1, + }, + }, } for _, scenario := range scenarios { diff --git a/apis/record_crud_test.go b/apis/record_crud_test.go index 1fa16b01..85d27adf 100644 --- a/apis/record_crud_test.go +++ b/apis/record_crud_test.go @@ -1,6 +1,7 @@ package apis_test import ( + "errors" "net/http" "net/url" "os" @@ -10,6 +11,7 @@ import ( "time" "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tests" ) @@ -836,6 +838,27 @@ func TestRecordCrudDelete(t *testing.T) { "OnRecordBeforeDeleteRequest": 1, }, }, + { + Name: "OnRecordAfterDeleteRequest error response", + Method: http.MethodDelete, + Url: "/api/collections/clients/records/o1y0dd0spd786md", + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterDeleteRequest().Add(func(e *core.RecordDeleteEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelAfterDelete": 1, + "OnModelBeforeDelete": 1, + "OnRecordAfterDeleteRequest": 1, + "OnRecordBeforeDeleteRequest": 1, + }, + }, { Name: "authenticated record that match the collection delete rule", Method: http.MethodDelete, @@ -1187,6 +1210,25 @@ func TestRecordCrudCreate(t *testing.T) { `"code":"validation_not_unique"`, }, }, + { + Name: "OnRecordAfterCreateRequest error response", + Method: http.MethodPost, + Url: "/api/collections/demo2/records", + Body: strings.NewReader(`{"title":"new"}`), + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterCreateRequest().Add(func(e *core.RecordCreateEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnRecordBeforeCreateRequest": 1, + "OnRecordAfterCreateRequest": 1, + "OnModelBeforeCreate": 1, + "OnModelAfterCreate": 1, + }, + }, // ID checks // ----------------------------------------------------------- @@ -1745,6 +1787,25 @@ func TestRecordCrudUpdate(t *testing.T) { "OnModelAfterUpdate": 1, }, }, + { + Name: "OnRecordAfterUpdateRequest error response", + Method: http.MethodPatch, + Url: "/api/collections/demo2/records/0yxhwia2amd8gec", + Body: strings.NewReader(`{"title":"new"}`), + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnRecordAfterUpdateRequest().Add(func(e *core.RecordUpdateEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnRecordBeforeUpdateRequest": 1, + "OnRecordAfterUpdateRequest": 1, + "OnModelBeforeUpdate": 1, + "OnModelAfterUpdate": 1, + }, + }, { Name: "try to change the id of an existing record", Method: http.MethodPatch, diff --git a/apis/settings_test.go b/apis/settings_test.go index 490f2701..5ec1f012 100644 --- a/apis/settings_test.go +++ b/apis/settings_test.go @@ -6,12 +6,14 @@ import ( "crypto/rand" "crypto/x509" "encoding/pem" + "errors" "fmt" "net/http" "strings" "testing" "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/tests" ) @@ -240,6 +242,28 @@ func TestSettingsSet(t *testing.T) { "OnSettingsAfterUpdateRequest": 1, }, }, + { + Name: "OnSettingsAfterUpdateRequest error response", + Method: http.MethodPatch, + Url: "/api/settings", + Body: strings.NewReader(validData), + RequestHeaders: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8", + }, + BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { + app.OnSettingsAfterUpdateRequest().Add(func(e *core.SettingsUpdateEvent) error { + return errors.New("error") + }) + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{ + "OnModelBeforeUpdate": 1, + "OnModelAfterUpdate": 1, + "OnSettingsBeforeUpdateRequest": 1, + "OnSettingsAfterUpdateRequest": 1, + }, + }, } for _, scenario := range scenarios {