Commit 69b62ccc authored by Johnny's avatar Johnny

test: optimize store tests performance by reusing docker image and reducing build context

parent f5853300
web/node_modules web/node_modules
.git
build/
tmp/
memos
\ No newline at end of file
...@@ -63,7 +63,11 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I ...@@ -63,7 +63,11 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I
if find.MessageType != nil { if find.MessageType != nil {
// Filter by message type using JSON extraction // Filter by message type using JSON extraction
// Note: The type field in JSON is stored as string representation of the enum name // Note: The type field in JSON is stored as string representation of the enum name
where, args = append(where, "JSON_EXTRACT(`message`, '$.type') = ?"), append(args, find.MessageType.String()) if *find.MessageType == storepb.InboxMessage_TYPE_UNSPECIFIED {
where, args = append(where, "(JSON_EXTRACT(`message`, '$.type') IS NULL OR JSON_EXTRACT(`message`, '$.type') = ?)"), append(args, find.MessageType.String())
} else {
where, args = append(where, "JSON_EXTRACT(`message`, '$.type') = ?"), append(args, find.MessageType.String())
}
} }
query := "SELECT `id`, UNIX_TIMESTAMP(`created_ts`), `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC" query := "SELECT `id`, UNIX_TIMESTAMP(`created_ts`), `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC"
......
...@@ -10,7 +10,7 @@ import ( ...@@ -10,7 +10,7 @@ import (
) )
func (d *DB) UpsertMemoRelation(ctx context.Context, create *store.MemoRelation) (*store.MemoRelation, error) { func (d *DB) UpsertMemoRelation(ctx context.Context, create *store.MemoRelation) (*store.MemoRelation, error) {
stmt := "INSERT INTO `memo_relation` (`memo_id`, `related_memo_id`, `type`) VALUES (?, ?, ?)" stmt := "INSERT INTO `memo_relation` (`memo_id`, `related_memo_id`, `type`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `type` = `type`"
_, err := d.db.ExecContext( _, err := d.db.ExecContext(
ctx, ctx,
stmt, stmt,
......
...@@ -54,7 +54,11 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I ...@@ -54,7 +54,11 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I
// Filter by message type using PostgreSQL JSON extraction // Filter by message type using PostgreSQL JSON extraction
// Note: The type field in JSON is stored as string representation of the enum name // Note: The type field in JSON is stored as string representation of the enum name
// Cast to JSONB since the column is TEXT // Cast to JSONB since the column is TEXT
where, args = append(where, "message::JSONB->>'type' = "+placeholder(len(args)+1)), append(args, find.MessageType.String()) if *find.MessageType == storepb.InboxMessage_TYPE_UNSPECIFIED {
where, args = append(where, "(message::JSONB->>'type' IS NULL OR message::JSONB->>'type' = "+placeholder(len(args)+1)+")"), append(args, find.MessageType.String())
} else {
where, args = append(where, "message::JSONB->>'type' = "+placeholder(len(args)+1)), append(args, find.MessageType.String())
}
} }
query := "SELECT id, created_ts, sender_id, receiver_id, status, message FROM inbox WHERE " + strings.Join(where, " AND ") + " ORDER BY created_ts DESC" query := "SELECT id, created_ts, sender_id, receiver_id, status, message FROM inbox WHERE " + strings.Join(where, " AND ") + " ORDER BY created_ts DESC"
......
...@@ -17,6 +17,7 @@ func (d *DB) UpsertMemoRelation(ctx context.Context, create *store.MemoRelation) ...@@ -17,6 +17,7 @@ func (d *DB) UpsertMemoRelation(ctx context.Context, create *store.MemoRelation)
type type
) )
VALUES (` + placeholders(3) + `) VALUES (` + placeholders(3) + `)
ON CONFLICT (memo_id, related_memo_id, type) DO UPDATE SET type = EXCLUDED.type
RETURNING memo_id, related_memo_id, type RETURNING memo_id, related_memo_id, type
` `
memoRelation := &store.MemoRelation{} memoRelation := &store.MemoRelation{}
......
...@@ -55,7 +55,11 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I ...@@ -55,7 +55,11 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I
if find.MessageType != nil { if find.MessageType != nil {
// Filter by message type using JSON extraction // Filter by message type using JSON extraction
// Note: The type field in JSON is stored as string representation of the enum name // Note: The type field in JSON is stored as string representation of the enum name
where, args = append(where, "JSON_EXTRACT(`message`, '$.type') = ?"), append(args, find.MessageType.String()) if *find.MessageType == storepb.InboxMessage_TYPE_UNSPECIFIED {
where, args = append(where, "(JSON_EXTRACT(`message`, '$.type') IS NULL OR JSON_EXTRACT(`message`, '$.type') = ?)"), append(args, find.MessageType.String())
} else {
where, args = append(where, "JSON_EXTRACT(`message`, '$.type') = ?"), append(args, find.MessageType.String())
}
} }
query := "SELECT `id`, `created_ts`, `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC" query := "SELECT `id`, `created_ts`, `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC"
......
...@@ -17,6 +17,7 @@ func (d *DB) UpsertMemoRelation(ctx context.Context, create *store.MemoRelation) ...@@ -17,6 +17,7 @@ func (d *DB) UpsertMemoRelation(ctx context.Context, create *store.MemoRelation)
type type
) )
VALUES (?, ?, ?) VALUES (?, ?, ?)
ON CONFLICT(memo_id, related_memo_id, type) DO UPDATE SET type = excluded.type
RETURNING memo_id, related_memo_id, type RETURNING memo_id, related_memo_id, type
` `
memoRelation := &store.MemoRelation{} memoRelation := &store.MemoRelation{}
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"fmt" "fmt"
"os"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
...@@ -403,9 +404,13 @@ func StartMemosContainer(ctx context.Context, cfg MemosContainerConfig) (testcon ...@@ -403,9 +404,13 @@ func StartMemosContainer(ctx context.Context, cfg MemosContainerConfig) (testcon
// Use local Dockerfile build or remote image // Use local Dockerfile build or remote image
if cfg.Version == "local" { if cfg.Version == "local" {
req.FromDockerfile = testcontainers.FromDockerfile{ if os.Getenv("MEMOS_TEST_IMAGE_BUILT") == "1" {
Context: "../../", req.Image = "memos-test:local"
Dockerfile: "store/test/Dockerfile", // Simple Dockerfile without BuildKit requirements } else {
req.FromDockerfile = testcontainers.FromDockerfile{
Context: "../../",
Dockerfile: "store/test/Dockerfile", // Simple Dockerfile without BuildKit requirements
}
} }
} else { } else {
req.Image = fmt.Sprintf("%s:%s", MemosDockerImage, cfg.Version) req.Image = fmt.Sprintf("%s:%s", MemosDockerImage, cfg.Version)
......
...@@ -26,13 +26,28 @@ func runAllDrivers() { ...@@ -26,13 +26,28 @@ func runAllDrivers() {
_, currentFile, _, _ := runtime.Caller(0) _, currentFile, _, _ := runtime.Caller(0)
projectRoot := filepath.Dir(filepath.Dir(filepath.Dir(currentFile))) projectRoot := filepath.Dir(filepath.Dir(filepath.Dir(currentFile)))
// Build the docker image once for all tests to use
fmt.Println("Building memos docker image for tests (memos-test:local)...")
buildCmd := exec.Command("docker", "build", "-f", "store/test/Dockerfile", "-t", "memos-test:local", ".")
buildCmd.Dir = projectRoot
buildCmd.Stdout = os.Stdout
buildCmd.Stderr = os.Stderr
if err := buildCmd.Run(); err != nil {
fmt.Printf("Failed to build docker image: %v\n", err)
// We don't exit here, we let the tests try to run (and maybe fail or rebuild)
// strictly speaking we should probably fail, but let's be robust.
// Actually, if build fails, tests relying on it will fail or try to rebuild.
// Let's exit to be clear.
os.Exit(1)
}
var failed []string var failed []string
for _, driver := range drivers { for _, driver := range drivers {
fmt.Printf("\n==================== %s ====================\n\n", driver) fmt.Printf("\n==================== %s ====================\n\n", driver)
cmd := exec.Command("go", "test", "-v", "-count=1", "./store/test/...") cmd := exec.Command("go", "test", "-v", "-count=1", "./store/test/...")
cmd.Dir = projectRoot cmd.Dir = projectRoot
cmd.Env = append(os.Environ(), "DRIVER="+driver) cmd.Env = append(os.Environ(), "DRIVER="+driver, "MEMOS_TEST_IMAGE_BUILT=1")
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment