mirror of
https://github.com/hanzoai/base.git
synced 2026-10-21 03:41:50 +00:00
Remove all _hz_ prefixes from collection IDs, internal markers, and test fixtures. The default users collection is now _users_auth_ instead of _hz_users_auth_. Internal SQL parser tokens renamed from __hz_join__/__hz_discard__ to __join__/__discard__. Backup prefix changed from @auto_hz_backup_ to @auto_backup_. Test database updated with correct collection IDs and indexes. JWT tokens in test files regenerated with new collection IDs. Add LogoURL field to MetaConfig so the admin UI logo is configurable via app settings instead of hardcoded. FullPage.svelte and App.svelte sidebar now read logo and app name from the settings store, falling back to defaults when not configured.
370 lines
11 KiB
Go
370 lines
11 KiB
Go
package apis_test
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hanzoai/base/core"
|
|
"github.com/hanzoai/base/tests"
|
|
)
|
|
|
|
func TestCollectionsImport(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
totalCollections := 16
|
|
|
|
scenarios := []tests.ApiScenario{
|
|
{
|
|
Name: "unauthorized",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
ExpectedStatus: 401,
|
|
ExpectedContent: []string{`"data":{}`},
|
|
ExpectedEvents: map[string]int{"*": 0},
|
|
},
|
|
{
|
|
Name: "authorized as regular user",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
Headers: map[string]string{
|
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfdXNlcnNfYXV0aF8iLCJleHAiOjI1MjQ2MDQ0NjEsImlkIjoiNHExeGxjbG1mbG9rdTMzIiwicmVmcmVzaGFibGUiOnRydWUsInR5cGUiOiJhdXRoIn0.AuFTIzCsdLEy-5adFzpjZzbqAdTP6Iu9B1wPBAxLBgo",
|
|
},
|
|
ExpectedStatus: 403,
|
|
ExpectedContent: []string{`"data":{}`},
|
|
ExpectedEvents: map[string]int{"*": 0},
|
|
},
|
|
{
|
|
Name: "authorized as superuser + empty collections",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
Body: strings.NewReader(`{"collections":[]}`),
|
|
Headers: map[string]string{
|
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJoYmNfMzE0MjYzNTgyMyIsImV4cCI6MjUyNDYwNDQ2MSwiaWQiOiJzeXdiaGVjbmg0NnJobTAiLCJyZWZyZXNoYWJsZSI6dHJ1ZSwidHlwZSI6ImF1dGgifQ.CXBf8BazmUeg2RnJW8OEs1UFYF41rbCMOa6YZa4wZio",
|
|
},
|
|
ExpectedStatus: 400,
|
|
ExpectedContent: []string{
|
|
`"data":{`,
|
|
`"collections":{"code":"validation_required"`,
|
|
},
|
|
ExpectedEvents: map[string]int{"*": 0},
|
|
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
|
|
collections := []*core.Collection{}
|
|
if err := app.CollectionQuery().All(&collections); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expected := totalCollections
|
|
if len(collections) != expected {
|
|
t.Fatalf("Expected %d collections, got %d", expected, len(collections))
|
|
}
|
|
},
|
|
},
|
|
{
|
|
Name: "authorized as superuser + collections validator failure",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
Body: strings.NewReader(`{
|
|
"collections":[
|
|
{"name": "import1"},
|
|
{
|
|
"name": "import2",
|
|
"fields": [
|
|
{
|
|
"id": "koih1lqx",
|
|
"name": "expand",
|
|
"type": "text"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}`),
|
|
Headers: map[string]string{
|
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJoYmNfMzE0MjYzNTgyMyIsImV4cCI6MjUyNDYwNDQ2MSwiaWQiOiJzeXdiaGVjbmg0NnJobTAiLCJyZWZyZXNoYWJsZSI6dHJ1ZSwidHlwZSI6ImF1dGgifQ.CXBf8BazmUeg2RnJW8OEs1UFYF41rbCMOa6YZa4wZio",
|
|
},
|
|
ExpectedStatus: 400,
|
|
ExpectedContent: []string{
|
|
`"data":{`,
|
|
`"collections":{"code":"validation_collections_import_failure"`,
|
|
`import2`,
|
|
`fields`,
|
|
},
|
|
NotExpectedContent: []string{"Raw error:"},
|
|
ExpectedEvents: map[string]int{
|
|
"*": 0,
|
|
"OnCollectionsImportRequest": 1,
|
|
"OnCollectionCreate": 2,
|
|
"OnCollectionCreateExecute": 2,
|
|
"OnCollectionAfterCreateError": 2,
|
|
"OnModelCreate": 2,
|
|
"OnModelCreateExecute": 2,
|
|
"OnModelAfterCreateError": 2,
|
|
},
|
|
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
|
|
collections := []*core.Collection{}
|
|
if err := app.CollectionQuery().All(&collections); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expected := totalCollections
|
|
if len(collections) != expected {
|
|
t.Fatalf("Expected %d collections, got %d", expected, len(collections))
|
|
}
|
|
},
|
|
},
|
|
{
|
|
Name: "authorized as superuser + non-validator failure",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
Body: strings.NewReader(`{
|
|
"collections":[
|
|
{
|
|
"name": "import1",
|
|
"fields": [
|
|
{
|
|
"id": "koih1lqx",
|
|
"name": "test",
|
|
"type": "text"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "import2",
|
|
"fields": [
|
|
{
|
|
"id": "koih1lqx",
|
|
"name": "test",
|
|
"type": "text"
|
|
}
|
|
],
|
|
"indexes": [
|
|
"create index idx_test on import2 (test)"
|
|
]
|
|
}
|
|
]
|
|
}`),
|
|
Headers: map[string]string{
|
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJoYmNfMzE0MjYzNTgyMyIsImV4cCI6MjUyNDYwNDQ2MSwiaWQiOiJzeXdiaGVjbmg0NnJobTAiLCJyZWZyZXNoYWJsZSI6dHJ1ZSwidHlwZSI6ImF1dGgifQ.CXBf8BazmUeg2RnJW8OEs1UFYF41rbCMOa6YZa4wZio",
|
|
},
|
|
ExpectedStatus: 400,
|
|
ExpectedContent: []string{
|
|
`"data":{`,
|
|
`"collections":{"code":"validation_collections_import_failure"`,
|
|
`Raw error:`,
|
|
`custom_error`,
|
|
},
|
|
ExpectedEvents: map[string]int{
|
|
"*": 0,
|
|
"OnCollectionsImportRequest": 1,
|
|
"OnCollectionCreate": 1,
|
|
"OnCollectionAfterCreateError": 1,
|
|
"OnModelCreate": 1,
|
|
"OnModelAfterCreateError": 1,
|
|
},
|
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
|
app.OnCollectionCreate().BindFunc(func(e *core.CollectionEvent) error {
|
|
return errors.New("custom_error")
|
|
})
|
|
},
|
|
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
|
|
collections := []*core.Collection{}
|
|
if err := app.CollectionQuery().All(&collections); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expected := totalCollections
|
|
if len(collections) != expected {
|
|
t.Fatalf("Expected %d collections, got %d", expected, len(collections))
|
|
}
|
|
},
|
|
},
|
|
{
|
|
Name: "authorized as superuser + successful collections create",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
Body: strings.NewReader(`{
|
|
"collections":[
|
|
{
|
|
"name": "import1",
|
|
"fields": [
|
|
{
|
|
"id": "koih1lqx",
|
|
"name": "test",
|
|
"type": "text"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "import2",
|
|
"fields": [
|
|
{
|
|
"id": "koih1lqx",
|
|
"name": "test",
|
|
"type": "text"
|
|
}
|
|
],
|
|
"indexes": [
|
|
"create index idx_test on import2 (test)"
|
|
]
|
|
},
|
|
{
|
|
"name": "auth_without_fields",
|
|
"type": "auth"
|
|
}
|
|
]
|
|
}`),
|
|
Headers: map[string]string{
|
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJoYmNfMzE0MjYzNTgyMyIsImV4cCI6MjUyNDYwNDQ2MSwiaWQiOiJzeXdiaGVjbmg0NnJobTAiLCJyZWZyZXNoYWJsZSI6dHJ1ZSwidHlwZSI6ImF1dGgifQ.CXBf8BazmUeg2RnJW8OEs1UFYF41rbCMOa6YZa4wZio",
|
|
},
|
|
ExpectedStatus: 204,
|
|
ExpectedEvents: map[string]int{
|
|
"*": 0,
|
|
"OnCollectionsImportRequest": 1,
|
|
"OnCollectionCreate": 3,
|
|
"OnCollectionCreateExecute": 3,
|
|
"OnCollectionAfterCreateSuccess": 3,
|
|
"OnModelCreate": 3,
|
|
"OnModelCreateExecute": 3,
|
|
"OnModelAfterCreateSuccess": 3,
|
|
},
|
|
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
|
|
collections := []*core.Collection{}
|
|
if err := app.CollectionQuery().All(&collections); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := totalCollections + 3
|
|
if len(collections) != expected {
|
|
t.Fatalf("Expected %d collections, got %d", expected, len(collections))
|
|
}
|
|
|
|
indexes, err := app.TableIndexes("import2")
|
|
if err != nil || indexes["idx_test"] == "" {
|
|
t.Fatalf("Missing index %s (%v)", "idx_test", err)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
Name: "authorized as superuser + create/update/delete",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
Body: strings.NewReader(`{
|
|
"deleteMissing": true,
|
|
"collections":[
|
|
{"name": "test123"},
|
|
{
|
|
"id":"wsmn24bux7wo113",
|
|
"name":"demo1",
|
|
"fields":[
|
|
{
|
|
"id":"_2hlxbmp",
|
|
"name":"title",
|
|
"type":"text",
|
|
"required":true
|
|
}
|
|
],
|
|
"indexes": []
|
|
}
|
|
]
|
|
}`),
|
|
Headers: map[string]string{
|
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJoYmNfMzE0MjYzNTgyMyIsImV4cCI6MjUyNDYwNDQ2MSwiaWQiOiJzeXdiaGVjbmg0NnJobTAiLCJyZWZyZXNoYWJsZSI6dHJ1ZSwidHlwZSI6ImF1dGgifQ.CXBf8BazmUeg2RnJW8OEs1UFYF41rbCMOa6YZa4wZio",
|
|
},
|
|
ExpectedStatus: 204,
|
|
ExpectedEvents: map[string]int{
|
|
"*": 0,
|
|
"OnCollectionsImportRequest": 1,
|
|
// ---
|
|
"OnModelCreate": 1,
|
|
"OnModelCreateExecute": 1,
|
|
"OnModelAfterCreateSuccess": 1,
|
|
"OnCollectionCreate": 1,
|
|
"OnCollectionCreateExecute": 1,
|
|
"OnCollectionAfterCreateSuccess": 1,
|
|
// ---
|
|
"OnModelUpdate": 1,
|
|
"OnModelUpdateExecute": 1,
|
|
"OnModelAfterUpdateSuccess": 1,
|
|
"OnCollectionUpdate": 1,
|
|
"OnCollectionUpdateExecute": 1,
|
|
"OnCollectionAfterUpdateSuccess": 1,
|
|
// ---
|
|
"OnModelDelete": 14,
|
|
"OnModelAfterDeleteSuccess": 14,
|
|
"OnModelDeleteExecute": 14,
|
|
"OnCollectionDelete": 9,
|
|
"OnCollectionDeleteExecute": 9,
|
|
"OnCollectionAfterDeleteSuccess": 9,
|
|
"OnRecordAfterDeleteSuccess": 5,
|
|
"OnRecordDelete": 5,
|
|
"OnRecordDeleteExecute": 5,
|
|
},
|
|
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
|
|
collections := []*core.Collection{}
|
|
if err := app.CollectionQuery().All(&collections); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
systemCollections := 0
|
|
for _, c := range collections {
|
|
if c.System {
|
|
systemCollections++
|
|
}
|
|
}
|
|
|
|
expected := systemCollections + 2
|
|
if len(collections) != expected {
|
|
t.Fatalf("Expected %d collections, got %d", expected, len(collections))
|
|
}
|
|
},
|
|
},
|
|
{
|
|
Name: "OnCollectionsImportRequest tx body write check",
|
|
Method: http.MethodPut,
|
|
URL: "/api/collections/import",
|
|
Body: strings.NewReader(`{
|
|
"deleteMissing": true,
|
|
"collections":[
|
|
{"name": "test123"},
|
|
{
|
|
"id":"wsmn24bux7wo113",
|
|
"name":"demo1",
|
|
"fields":[
|
|
{
|
|
"id":"_2hlxbmp",
|
|
"name":"title",
|
|
"type":"text",
|
|
"required":true
|
|
}
|
|
],
|
|
"indexes": []
|
|
}
|
|
]
|
|
}`),
|
|
Headers: map[string]string{
|
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJoYmNfMzE0MjYzNTgyMyIsImV4cCI6MjUyNDYwNDQ2MSwiaWQiOiJzeXdiaGVjbmg0NnJobTAiLCJyZWZyZXNoYWJsZSI6dHJ1ZSwidHlwZSI6ImF1dGgifQ.CXBf8BazmUeg2RnJW8OEs1UFYF41rbCMOa6YZa4wZio",
|
|
},
|
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
|
app.OnCollectionsImportRequest().BindFunc(func(e *core.CollectionsImportRequestEvent) error {
|
|
original := e.App
|
|
return e.App.RunInTransaction(func(txApp core.App) error {
|
|
e.App = txApp
|
|
defer func() { e.App = original }()
|
|
|
|
if err := e.Next(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return e.BadRequestError("TX_ERROR", nil)
|
|
})
|
|
})
|
|
},
|
|
ExpectedStatus: 400,
|
|
ExpectedEvents: map[string]int{"OnCollectionsImportRequest": 1},
|
|
ExpectedContent: []string{"TX_ERROR"},
|
|
},
|
|
}
|
|
|
|
for _, scenario := range scenarios {
|
|
scenario.Test(t)
|
|
}
|
|
}
|