已完成用户APP首期功能开发
交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
This commit is contained in:
98
backend/api/internal/logic/client/user/address_test.go
Normal file
98
backend/api/internal/logic/client/user/address_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// 功能描述:验证地址坐标、所有权、事务回滚及创建幂等,不访问远程数据。
|
||||
// 版本:1.0.0。
|
||||
package user
|
||||
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/types"
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddressCoordinates(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
lon, lat string
|
||||
valid bool
|
||||
}{
|
||||
{"", "", true}, {"113.2", "23.4", true}, {"180", "-90", true}, {"181", "0", false},
|
||||
{"0", "91", false}, {"0", "", false}, {"NaN", "0", false}, {"Inf", "0", false},
|
||||
} {
|
||||
if validAddressCoordinates(tc.lon, tc.lat) != tc.valid {
|
||||
t.Errorf("坐标边界不正确:%q %q", tc.lon, tc.lat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// addressContext 构造当前用户鉴权,不依赖登录接口。
|
||||
func addressContext(body, identity string) (*gin.Context, *httptest.ResponseRecorder) {
|
||||
response := httptest.NewRecorder()
|
||||
ctx, _ := gin.CreateTestContext(response)
|
||||
ctx.Set("Auth", &types.JwtClaims{Client: "user_app", Identity: "alice"})
|
||||
ctx.Request = httptest.NewRequest("POST", "/addresses", strings.NewReader(body))
|
||||
ctx.Request.Header.Set("Content-Type", "application/json")
|
||||
ctx.Params = gin.Params{{Key: "identity", Value: identity}}
|
||||
return ctx, response
|
||||
}
|
||||
|
||||
func expectAddressAccount(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectQuery(`SELECT .* FROM "user_account"`).WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "name", "phone"}).AddRow(1, "alice", "测试用户", "13800000001"))
|
||||
}
|
||||
|
||||
func expectAddressLock(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectQuery(`SELECT "id" FROM "user_account".*FOR UPDATE`).WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
|
||||
}
|
||||
|
||||
func TestAddressMutationsRejectOtherOwner(t *testing.T) {
|
||||
for _, action := range []func(*gin.Context){SetDefaultAddress, DeleteAddress, UpdateAddress} {
|
||||
mock := primaryTestDB(t)
|
||||
expectAddressAccount(mock)
|
||||
expectAddressLock(mock)
|
||||
mock.ExpectQuery(`SELECT .* FROM "user_address".*identity = \$1 AND user_account_id = \$2`).WillReturnRows(sqlmock.NewRows([]string{"id"}))
|
||||
mock.ExpectRollback()
|
||||
ctx, response := addressContext(`{"address":"测试地址"}`, "other-address")
|
||||
action(ctx)
|
||||
if strings.Contains(response.Body.String(), `"code":0`) {
|
||||
t.Fatal("越权修改成功")
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddressCreateRetryDoesNotDuplicateOrResetDefault(t *testing.T) {
|
||||
mock := primaryTestDB(t)
|
||||
expectAddressAccount(mock)
|
||||
expectAddressLock(mock)
|
||||
mock.ExpectQuery(`SELECT .* FROM "user_address".*request_no`).WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "status", "address", "contact_name", "contact_phone"}).AddRow(5, "existing", 1, "测试地址", "测试用户", "13800000001"))
|
||||
mock.ExpectCommit()
|
||||
ctx, response := addressContext(`{"address":"测试地址","request_no":"same-request","is_default":true}`, "")
|
||||
SaveAddress(ctx)
|
||||
if !strings.Contains(response.Body.String(), `"identity":"existing"`) {
|
||||
t.Fatal(response.Body.String())
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddressDefaultUpdateFailureRollsBack(t *testing.T) {
|
||||
mock := primaryTestDB(t)
|
||||
expectAddressAccount(mock)
|
||||
expectAddressLock(mock)
|
||||
mock.ExpectQuery(`SELECT .* FROM "user_address"`).WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "status"}).AddRow(5, "owned", 1))
|
||||
mock.ExpectExec(`UPDATE "user_address" SET "is_default"`).WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
mock.ExpectExec(`UPDATE "user_address" SET "is_default"`).WillReturnError(sqlmock.ErrCancelled)
|
||||
mock.ExpectRollback()
|
||||
ctx, response := addressContext("", "owned")
|
||||
SetDefaultAddress(ctx)
|
||||
if strings.Contains(response.Body.String(), `"code":0`) {
|
||||
t.Fatal("失败写入被当作成功")
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user