diff --git a/.gitignore b/.gitignore index 48954fa..46c663e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ tmp # Frontend asset web/dist +web-r + # build folder build diff --git a/store/db/db.go b/store/db/db.go index 0d3c6ff..e9f60bd 100644 --- a/store/db/db.go +++ b/store/db/db.go @@ -19,9 +19,6 @@ import ( //go:embed migration var migrationFS embed.FS -//go:embed seed -var seedFS embed.FS - type DB struct { profile *profile.Profile // sqlite db connection instance @@ -122,9 +119,6 @@ func (db *DB) Open(ctx context.Context) (err error) { if err := db.applyLatestSchema(ctx); err != nil { return fmt.Errorf("failed to apply latest schema: %w", err) } - if err := db.seed(ctx); err != nil { - return fmt.Errorf("failed to seed: %w", err) - } } } @@ -191,28 +185,6 @@ func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion st return tx.Commit() } -func (db *DB) seed(ctx context.Context) error { - filenames, err := fs.Glob(seedFS, fmt.Sprintf("%s/*.sql", "seed")) - if err != nil { - return fmt.Errorf("failed to read seed files, err: %w", err) - } - - sort.Strings(filenames) - - // Loop over all seed files and execute them in order. - for _, filename := range filenames { - buf, err := seedFS.ReadFile(filename) - if err != nil { - return fmt.Errorf("failed to read seed file, filename=%s err=%w", filename, err) - } - stmt := string(buf) - if err := db.execute(ctx, stmt); err != nil { - return fmt.Errorf("seed error: statement:%s err=%w", stmt, err) - } - } - return nil -} - // execute runs a single SQL statement within a transaction. func (db *DB) execute(ctx context.Context, stmt string) error { tx, err := db.DBInstance.Begin() diff --git a/store/db/seed/10000__reset.sql b/store/db/seed/10000__reset.sql deleted file mode 100644 index f99cf0d..0000000 --- a/store/db/seed/10000__reset.sql +++ /dev/null @@ -1,11 +0,0 @@ -DELETE FROM shortcut; - -DELETE FROM workspace_user; - -DELETE FROM user_setting; - -DELETE FROM user; - -DELETE FROM workspace_setting; - -DELETE FROM workspace; diff --git a/store/db/seed/10001__user.sql b/store/db/seed/10001__user.sql deleted file mode 100644 index ec93eb9..0000000 --- a/store/db/seed/10001__user.sql +++ /dev/null @@ -1,35 +0,0 @@ -INSERT INTO - user ( - `id`, - `username`, - `nickname`, - `email`, - `password_hash` - ) -VALUES - ( - 11, - 'frank', - 'Frank', - 'frank@shortify.demo', - -- raw password: secret - '$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK' - ); - -INSERT INTO - user ( - `id`, - `username`, - `nickname`, - `email`, - `password_hash` - ) -VALUES - ( - 12, - 'bob', - 'Bob', - 'bob@shortify.demo', - -- raw password: secret - '$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK' - ); diff --git a/store/db/seed/10002__workspace.sql b/store/db/seed/10002__workspace.sql deleted file mode 100644 index 57147c9..0000000 --- a/store/db/seed/10002__workspace.sql +++ /dev/null @@ -1,14 +0,0 @@ -INSERT INTO - workspace ( - `id`, - `name`, - `title`, - `description` - ) -VALUES - ( - 1, - 'minecraft', - 'minecraft', - '' - ); diff --git a/store/db/seed/10003__workspace_user.sql b/store/db/seed/10003__workspace_user.sql deleted file mode 100644 index 2ee1a8e..0000000 --- a/store/db/seed/10003__workspace_user.sql +++ /dev/null @@ -1,25 +0,0 @@ -INSERT INTO - workspace_user ( - `workspace_id`, - `user_id`, - `role` - ) -VALUES - ( - 1, - 11, - 'ADMIN' - ); - -INSERT INTO - workspace_user ( - `workspace_id`, - `user_id`, - `role` - ) -VALUES - ( - 1, - 12, - 'USER' - ); diff --git a/store/db/seed/10004__shortcut.sql b/store/db/seed/10004__shortcut.sql deleted file mode 100644 index 45b422e..0000000 --- a/store/db/seed/10004__shortcut.sql +++ /dev/null @@ -1,56 +0,0 @@ -INSERT INTO - shortcut ( - `creator_id`, - `workspace_id`, - `name`, - `link`, - `description`, - `visibility` - ) -VALUES - ( - 11, - 1, - 'baidu', - 'https://baidu.com', - '百度搜索', - 'WORKSPACE' - ); - -INSERT INTO - shortcut ( - `creator_id`, - `workspace_id`, - `name`, - `link`, - `description`, - `visibility` - ) -VALUES - ( - 12, - 1, - 'bl', - 'https://bilibili.com', - 'B站', - 'PUBLIC' - ); - -INSERT INTO - shortcut ( - `creator_id`, - `workspace_id`, - `name`, - `link`, - `description`, - `visibility` - ) -VALUES - ( - 11, - 1, - 'ph', - 'https://producthunt.com', - 'PH', - 'PRIVATE' - ); diff --git a/test/store/store.go b/test/store/store.go new file mode 100644 index 0000000..aefc738 --- /dev/null +++ b/test/store/store.go @@ -0,0 +1,25 @@ +package teststore + +import ( + "context" + "fmt" + "testing" + + "github.com/boojack/shortify/store" + "github.com/boojack/shortify/store/db" + test "github.com/boojack/shortify/test" + + // sqlite driver. + _ "modernc.org/sqlite" +) + +func NewTestingStore(ctx context.Context, t *testing.T) *store.Store { + profile := test.GetTestingProfile(t) + db := db.NewDB(profile) + if err := db.Open(ctx); err != nil { + fmt.Printf("failed to open db, error: %+v\n", err) + } + + store := store.New(db.DBInstance, profile) + return store +} diff --git a/test/store/user_test.go b/test/store/user_test.go new file mode 100644 index 0000000..4c56893 --- /dev/null +++ b/test/store/user_test.go @@ -0,0 +1,54 @@ +package teststore + +import ( + "context" + "testing" + + "github.com/boojack/shortify/store" + + "github.com/stretchr/testify/require" + "golang.org/x/crypto/bcrypt" +) + +func TestUserStore(t *testing.T) { + ctx := context.Background() + ts := NewTestingStore(ctx, t) + user, err := createTestingAdminUser(ctx, ts) + require.NoError(t, err) + users, err := ts.ListUsers(ctx, &store.FindUser{}) + require.NoError(t, err) + require.Equal(t, 1, len(users)) + require.Equal(t, store.RoleAdmin, users[0].Role) + require.Equal(t, user, users[0]) + userPatchNickname := "test_nickname_2" + user, err = ts.UpdateUser(ctx, &store.UpdateUser{ + ID: user.ID, + Nickname: &userPatchNickname, + }) + require.NoError(t, err) + require.Equal(t, userPatchNickname, user.Nickname) + err = ts.DeleteUser(ctx, &store.DeleteUser{ + ID: user.ID, + }) + require.NoError(t, err) + users, err = ts.ListUsers(ctx, &store.FindUser{}) + require.NoError(t, err) + require.Equal(t, 0, len(users)) +} + +// createTestingAdminUser creates a testing admin user. +func createTestingAdminUser(ctx context.Context, ts *store.Store) (*store.User, error) { + userCreate := &store.User{ + Role: store.RoleAdmin, + Username: "test", + Nickname: "test_nickname", + Email: "test@test.com", + } + passwordHash, err := bcrypt.GenerateFromPassword([]byte("test-password"), bcrypt.DefaultCost) + if err != nil { + return nil, err + } + userCreate.PasswordHash = string(passwordHash) + user, err := ts.CreateUser(ctx, userCreate) + return user, err +} diff --git a/test/test.go b/test/test.go new file mode 100644 index 0000000..746ecd5 --- /dev/null +++ b/test/test.go @@ -0,0 +1,37 @@ +package tests + +import ( + "fmt" + "net" + "testing" + + "github.com/boojack/shortify/server/profile" + "github.com/boojack/shortify/server/version" +) + +func getUnusedPort() int { + // Get a random unused port + listener, err := net.Listen("tcp", "localhost:0") + if err != nil { + panic(err) + } + defer listener.Close() + + // Get the port number + port := listener.Addr().(*net.TCPAddr).Port + return port +} + +func GetTestingProfile(t *testing.T) *profile.Profile { + // Get a temporary directory for the test data. + dir := t.TempDir() + mode := "dev" + port := getUnusedPort() + return &profile.Profile{ + Mode: mode, + Port: port, + Data: dir, + DSN: fmt.Sprintf("%s/shortify_%s.db", dir, mode), + Version: version.GetCurrentVersion(mode), + } +}