147 lines
4.1 KiB
Go
147 lines
4.1 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"io"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
_ "modernc.org/sqlite"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func TestBindPhoneReassignsDuplicatePhoneToLatestOpenID(t *testing.T) {
|
|
svc, database, closeDB := newTestService(t)
|
|
defer closeDB()
|
|
|
|
ctx := context.Background()
|
|
first, err := svc.Login(ctx, "first")
|
|
if err != nil {
|
|
t.Fatalf("login first user: %v", err)
|
|
}
|
|
second, err := svc.Login(ctx, "second")
|
|
if err != nil {
|
|
t.Fatalf("login second user: %v", err)
|
|
}
|
|
|
|
if _, err := svc.BindPhone(ctx, first.User.Openid, "13900001111"); err != nil {
|
|
t.Fatalf("bind first phone: %v", err)
|
|
}
|
|
if _, err := svc.BindPhone(ctx, second.User.Openid, "13900001111"); err != nil {
|
|
t.Fatalf("bind second phone: %v", err)
|
|
}
|
|
|
|
var phoneOwners int
|
|
if err := database.QueryRowContext(ctx, `
|
|
SELECT COUNT(*)
|
|
FROM users
|
|
WHERE phone = ?`, "13900001111").Scan(&phoneOwners); err != nil {
|
|
t.Fatalf("count phone owners: %v", err)
|
|
}
|
|
if phoneOwners != 1 {
|
|
t.Fatalf("phone owner count = %d, want 1", phoneOwners)
|
|
}
|
|
|
|
firstUser, err := svc.Q.GetUserByOpenID(ctx, first.User.Openid)
|
|
if err != nil {
|
|
t.Fatalf("reload first user: %v", err)
|
|
}
|
|
if firstUser.Phone.Valid {
|
|
t.Fatalf("first user phone = %#v, want cleared", firstUser.Phone)
|
|
}
|
|
|
|
records, err := svc.AdminPhoneRecords(ctx)
|
|
if err != nil {
|
|
t.Fatalf("list admin phone records: %v", err)
|
|
}
|
|
if len(records) != 1 {
|
|
t.Fatalf("admin phone records = %d, want 1", len(records))
|
|
}
|
|
if records[0].OpenID != second.User.Openid || records[0].Phone != "13900001111" {
|
|
t.Fatalf("admin phone record = %#v, want latest openid with bound phone", records[0])
|
|
}
|
|
}
|
|
|
|
func TestCreatePriceInquiryUpdatesDuplicateSubmissionTimestamp(t *testing.T) {
|
|
svc, database, closeDB := newTestService(t)
|
|
defer closeDB()
|
|
|
|
ctx := context.Background()
|
|
session, err := svc.Login(ctx, "price_inquiry_duplicate")
|
|
if err != nil {
|
|
t.Fatalf("login user: %v", err)
|
|
}
|
|
if _, err := svc.BindPhone(ctx, session.User.Openid, "13900005555"); err != nil {
|
|
t.Fatalf("bind phone: %v", err)
|
|
}
|
|
|
|
req := CreatePriceInquiryRequest{
|
|
OpenID: session.User.Openid,
|
|
Province: "上海市",
|
|
City: "上海市",
|
|
District: "浦东新区",
|
|
ProjectName: "牙齿种植",
|
|
}
|
|
first, err := svc.CreatePriceInquiry(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("create first inquiry: %v", err)
|
|
}
|
|
if _, err := database.ExecContext(ctx, `
|
|
UPDATE price_inquiries
|
|
SET status = 'assigned', created_at = '2026-07-01 10:00:00', updated_at = '2026-07-01 10:00:00'
|
|
WHERE id = ?`, first.ID); err != nil {
|
|
t.Fatalf("set deterministic timestamps: %v", err)
|
|
}
|
|
|
|
second, err := svc.CreatePriceInquiry(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("create duplicate inquiry: %v", err)
|
|
}
|
|
if second.ID != first.ID {
|
|
t.Fatalf("duplicate inquiry id = %q, want existing id %q", second.ID, first.ID)
|
|
}
|
|
if second.CreatedAt != "2026-07-01 10:00:00" {
|
|
t.Fatalf("duplicate inquiry created_at = %q, want original created_at", second.CreatedAt)
|
|
}
|
|
if second.UpdatedAt == "" || second.UpdatedAt == "2026-07-01 10:00:00" {
|
|
t.Fatalf("duplicate inquiry updated_at = %q, want refreshed timestamp", second.UpdatedAt)
|
|
}
|
|
if second.Status != "assigned" {
|
|
t.Fatalf("duplicate inquiry status = %q, want assigned", second.Status)
|
|
}
|
|
|
|
var count int
|
|
if err := database.QueryRowContext(ctx, `
|
|
SELECT COUNT(*)
|
|
FROM price_inquiries
|
|
WHERE phone = ? AND province = ? AND city = ? AND district = ? AND project_name = ?`,
|
|
"13900005555", "上海市", "上海市", "浦东新区", "牙齿种植").Scan(&count); err != nil {
|
|
t.Fatalf("count price inquiries: %v", err)
|
|
}
|
|
if count != 1 {
|
|
t.Fatalf("price inquiry count = %d, want 1", count)
|
|
}
|
|
}
|
|
|
|
func newTestService(t *testing.T) (*Service, *sql.DB, func()) {
|
|
t.Helper()
|
|
|
|
database, err := sql.Open("sqlite", ":memory:")
|
|
if err != nil {
|
|
t.Fatalf("open sqlite: %v", err)
|
|
}
|
|
|
|
ctx := context.Background()
|
|
schemaPath := filepath.Join("..", "..", "migrations", "schema.sql")
|
|
if err := ApplySchema(ctx, database, schemaPath); err != nil {
|
|
database.Close()
|
|
t.Fatalf("apply schema: %v", err)
|
|
}
|
|
|
|
log := logrus.New()
|
|
log.SetOutput(io.Discard)
|
|
return New(database, log), database, func() { database.Close() }
|
|
}
|