chore: 初始开源发布
iotlcm-app:小程序端 + 用户端服务。 - app/:uni-app 小程序前端(基于 unibest,MIT) - 微信 AppID → YOUR_WX_APPID,uni-app AppID → __UNI__YOURAPPID - 内网后端地址 → admin.iotlcm.example.com - 应用标题与 unibest 模板 README 重写(保留上游致谢与 MIT 声明) - server/:GoFrame 用户端服务(基于 XiuAdmin,Apache-2.0) - module xiuadmin → git.5iot.com/iotlcm-public/iotlcm-app(360 文件) - 支付回调地址 → app.iotlcm.example.com,商户名与应用名泛化 - 真实手机号 → 合法 11 位编造号(保留号段前 3 位 + 后 4 位) - 依赖号码尾部的断言同步更新 - 补 server/LICENSE(Apache-2.0) - 移除内部资产:CI 触发器 - 补根 README,LF 行尾 + .gitattributes 已知:TestSysDept_RefreshDeptAncestors 在源仓同一提交上同样失败,属既有缺陷。
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
)
|
||||
|
||||
func TestQueryDiagnosisFlowByCardRejectsUnsupportedPeriod(t *testing.T) {
|
||||
_, err := NewAppDiagnosis().queryDiagnosisFlowByCard(nil, nil, "12M")
|
||||
if err == nil || !strings.Contains(err.Error(), "3M") {
|
||||
t.Fatalf("unsupported period error = %v, want query type hint", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppCachedDiagnosisRegionModuleTreatsCachedDataAsSuccess(t *testing.T) {
|
||||
raw, err := json.Marshal(map[string]string{
|
||||
"regionLimitStatus": "1",
|
||||
"orderStatus": "0",
|
||||
"limitStatus": "1",
|
||||
"limitType": "province",
|
||||
"limitArea": "山东",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal region data: %v", err)
|
||||
}
|
||||
item := &appUpstreamSimQueryItem{
|
||||
Code: 1001,
|
||||
Message: "上游一小时内限制重复查询",
|
||||
ResData: raw,
|
||||
}
|
||||
|
||||
status, message := appCachedDiagnosisRegionModule(item)
|
||||
if status != "cached" {
|
||||
t.Fatalf("status = %q, want cached", status)
|
||||
}
|
||||
if !strings.Contains(message, "区域限制结果来自缓存") {
|
||||
t.Fatalf("message = %q, want cache hint", message)
|
||||
}
|
||||
|
||||
res := &model.AppDiagnosisInfoModel{Info: &model.AppDiagnosisInfoItem{}}
|
||||
appDiagnosisApplyRegionLimit(res, item)
|
||||
if res.Info.RegionLimitStatus == nil || *res.Info.RegionLimitStatus != "1" {
|
||||
t.Fatalf("RegionLimitStatus = %#v, want 1", res.Info.RegionLimitStatus)
|
||||
}
|
||||
if res.Info.RegionLimitArea == nil || *res.Info.RegionLimitArea != "山东" {
|
||||
t.Fatalf("RegionLimitArea = %#v, want 山东", res.Info.RegionLimitArea)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppCachedDiagnosisRegionModuleFailsEmptyCacheData(t *testing.T) {
|
||||
status, _ := appCachedDiagnosisRegionModule(&appUpstreamSimQueryItem{Code: 0})
|
||||
if status != "error" {
|
||||
t.Fatalf("status = %q, want error", status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppDiagnosisApplyRateLimitIncludesApnDetails(t *testing.T) {
|
||||
inner, err := json.Marshal(map[string]any{
|
||||
"rateLimitStatus": "0",
|
||||
"rateLimitReason": "套餐达量",
|
||||
"rateLimitDetail": "APN触发限速",
|
||||
"apnDetails": []map[string]any{
|
||||
{
|
||||
"apnName": "cmiot",
|
||||
"apnStatus": "0",
|
||||
"modifyTime": "2026-08-28 10:00:00",
|
||||
"overUseDetails": "流量超额",
|
||||
"apnServiceUsageState": "超额",
|
||||
"pccDetails": []map[string]any{
|
||||
{
|
||||
"pccServiceCode": "PCC001",
|
||||
"pccName": "白名单",
|
||||
"pccPolicyStatus": "1",
|
||||
"pccServiceUsageState": "正常",
|
||||
"modifyTime": "2026-08-28 10:01:00",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal rate limit data: %v", err)
|
||||
}
|
||||
raw, err := json.Marshal(map[string]any{"resData": json.RawMessage(inner)})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal wrapped rate limit data: %v", err)
|
||||
}
|
||||
|
||||
res := &model.AppDiagnosisInfoModel{Info: &model.AppDiagnosisInfoItem{}}
|
||||
appDiagnosisApplyRateLimit(res, &appUpstreamSimQueryItem{Code: 0, ResData: raw})
|
||||
if res.Info.RateLimitStatus == nil || *res.Info.RateLimitStatus != "0" {
|
||||
t.Fatalf("RateLimitStatus = %#v, want 0", res.Info.RateLimitStatus)
|
||||
}
|
||||
if len(res.Info.RateLimitApnDetails) != 1 {
|
||||
t.Fatalf("RateLimitApnDetails length = %d, want 1", len(res.Info.RateLimitApnDetails))
|
||||
}
|
||||
apn := res.Info.RateLimitApnDetails[0]
|
||||
if apn.ApnName != "cmiot" || len(apn.PccDetails) != 1 || apn.PccDetails[0].PccServiceCode != "PCC001" {
|
||||
t.Fatalf("unexpected APN detail: %#v", apn)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizeOpenDiagnosisInfoMasksIdentifiersAndRemovesNetworkData(t *testing.T) {
|
||||
res := &model.AppDiagnosisInfoModel{
|
||||
Info: &model.AppDiagnosisInfoItem{
|
||||
Iccid: appDiagnosisStringPtr("8986001234567890123"),
|
||||
Imsi: appDiagnosisStringPtr("460001234567890"),
|
||||
Msisdn: appDiagnosisStringPtr("13800008000"),
|
||||
RateLimitApnDetails: []model.AppDiagnosisRateLimitApnItem{
|
||||
{ApnName: "cmiot"},
|
||||
},
|
||||
},
|
||||
Session: &model.AppDiagnosisSessionItem{
|
||||
ApnId: appDiagnosisStringPtr("internet"),
|
||||
Imei: appDiagnosisStringPtr("860123456789012"),
|
||||
Ipv4: appDiagnosisStringPtr("10.0.0.1"),
|
||||
Ipv6: appDiagnosisStringPtr("2001:db8::1"),
|
||||
},
|
||||
Card: &model.AppCardModel{
|
||||
Iccid: "8986001234567890123",
|
||||
Msisdn: "13800008000",
|
||||
Imsi: "460001234567890",
|
||||
Imei: "860123456789012",
|
||||
Ipv4: "10.0.0.1",
|
||||
},
|
||||
}
|
||||
|
||||
sanitizeOpenDiagnosisInfo(res)
|
||||
if got := *res.Info.Iccid; got != "8986****0123" {
|
||||
t.Fatalf("masked ICCID = %q", got)
|
||||
}
|
||||
if got := *res.Info.Msisdn; got != "1380****8000" {
|
||||
t.Fatalf("masked MSISDN = %q", got)
|
||||
}
|
||||
if res.Info.Imsi != nil || len(res.Info.RateLimitApnDetails) != 0 || res.Session.ApnId != nil || res.Session.Imei != nil || res.Session.Ipv4 != nil {
|
||||
t.Fatal("sensitive diagnosis fields were not removed")
|
||||
}
|
||||
if res.Card.Imsi != "" || res.Card.Imei != "" || res.Card.Ipv4 != "" {
|
||||
t.Fatal("sensitive card fields were not removed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDiagnosisInfoKeepsSessionImeiBeforeOpenSanitization(t *testing.T) {
|
||||
res := &model.AppDiagnosisInfoModel{
|
||||
Session: &model.AppDiagnosisSessionItem{Imei: appDiagnosisStringPtr("860123456789012")},
|
||||
}
|
||||
if res.Session.Imei == nil || *res.Session.Imei != "860123456789012" {
|
||||
t.Fatal("authenticated diagnosis should keep session IMEI")
|
||||
}
|
||||
sanitizeOpenDiagnosisInfo(res)
|
||||
if res.Session.Imei != nil {
|
||||
t.Fatal("open diagnosis should remove session IMEI")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppDiagnosisStatusMappingsMatchConsoleContract(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
mapper func(string) *string
|
||||
}{
|
||||
{name: "imei separated", input: "0", want: "0", mapper: appDiagnosisImeiStatus},
|
||||
{name: "imei bound", input: "1", want: "1", mapper: appDiagnosisImeiStatus},
|
||||
{name: "imei unknown", input: "2", want: "2", mapper: appDiagnosisImeiStatus},
|
||||
{name: "online", input: "0", want: "1", mapper: appDiagnosisOnlineStatus},
|
||||
{name: "offline", input: "-1", want: "0", mapper: appDiagnosisOnlineStatus},
|
||||
{name: "unknown", input: "-2", want: "2", mapper: appDiagnosisOnlineStatus},
|
||||
{name: "human limited", input: "1", want: "0", mapper: appDiagnosisHumanLimitStatus},
|
||||
{name: "human normal", input: "0", want: "1", mapper: appDiagnosisHumanLimitStatus},
|
||||
{name: "human unknown", input: "2", want: "2", mapper: appDiagnosisHumanLimitStatus},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
got := test.mapper(test.input)
|
||||
if got == nil || *got != test.want {
|
||||
t.Fatalf("mapping %q = %#v, want %q", test.input, got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppDiagnosisBindStatusSupportsTelecomCardBindingType(t *testing.T) {
|
||||
tests := []struct {
|
||||
bindStatus string
|
||||
cardBindingType string
|
||||
want string
|
||||
}{
|
||||
{bindStatus: "0", cardBindingType: "1", want: "0"},
|
||||
{bindStatus: "1", cardBindingType: "2", want: "1"},
|
||||
{bindStatus: "2", cardBindingType: "1", want: "2"},
|
||||
{cardBindingType: "1", want: "1"},
|
||||
{cardBindingType: "5", want: "1"},
|
||||
{cardBindingType: "-1", want: "2"},
|
||||
{cardBindingType: "unknown", want: "2"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if got := appDiagnosisBindStatus(test.bindStatus, test.cardBindingType); got != test.want {
|
||||
t.Fatalf("bindStatus=%q cardBindingType=%q => %q, want %q", test.bindStatus, test.cardBindingType, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppDiagnosisSessionStatusNormalizesUpstreamValues(t *testing.T) {
|
||||
tests := map[string]string{
|
||||
"0": "0",
|
||||
"01": "0",
|
||||
"ONLINE": "0",
|
||||
"-1": "-1",
|
||||
"00": "-1",
|
||||
"OFFLINE": "-1",
|
||||
"-2": "-2",
|
||||
"02": "-2",
|
||||
"2": "-2",
|
||||
"": "-2",
|
||||
}
|
||||
|
||||
for input, want := range tests {
|
||||
if got := appDiagnosisSessionStatus(input); got != want {
|
||||
t.Fatalf("session status %q => %q, want %q", input, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user