test: optimize store tests performance by reusing docker image and reducing build context
This commit is contained in:
parent
f58533003b
commit
69b62cccdb
9 changed files with 46 additions and 8 deletions
|
|
@ -1 +1,5 @@
|
||||||
web/node_modules
|
web/node_modules
|
||||||
|
.git
|
||||||
|
build/
|
||||||
|
tmp/
|
||||||
|
memos
|
||||||
|
|
@ -63,8 +63,12 @@ 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
|
||||||
|
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())
|
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"
|
||||||
if find.Limit != nil {
|
if find.Limit != nil {
|
||||||
|
|
|
||||||
|
|
@ -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,8 +54,12 @@ 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
|
||||||
|
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())
|
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"
|
||||||
if find.Limit != nil {
|
if find.Limit != nil {
|
||||||
|
|
|
||||||
|
|
@ -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,8 +55,12 @@ 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
|
||||||
|
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())
|
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"
|
||||||
if find.Limit != nil {
|
if find.Limit != nil {
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
@ -403,10 +404,14 @@ 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" {
|
||||||
|
if os.Getenv("MEMOS_TEST_IMAGE_BUILT") == "1" {
|
||||||
|
req.Image = "memos-test:local"
|
||||||
|
} else {
|
||||||
req.FromDockerfile = testcontainers.FromDockerfile{
|
req.FromDockerfile = testcontainers.FromDockerfile{
|
||||||
Context: "../../",
|
Context: "../../",
|
||||||
Dockerfile: "store/test/Dockerfile", // Simple Dockerfile without BuildKit requirements
|
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() {
|
||||||
_, 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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue