140 lines
5.3 KiB
Go
140 lines
5.3 KiB
Go
package upstream
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gogf/gf/v2/errors/gcode"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/os/gcfg"
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
|
)
|
|
|
|
func TestTestChannelPostsOneTenantBoundRequestToGateway(t *testing.T) {
|
|
const gatewayBody = `{"code":0,"message":"success","data":{"items":[{"key":"simStatus","name":"卡状态","status":"success"}]}}`
|
|
var requestBody model.UpstreamChannelTestRequest
|
|
requestCount := 0
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/internal/channel/test" || r.Method != http.MethodPost {
|
|
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
|
}
|
|
requestCount++
|
|
if r.Header.Get("X-Internal-Token") != "" {
|
|
t.Errorf("unexpected internal token header")
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, _ = w.Write([]byte(gatewayBody))
|
|
}))
|
|
defer server.Close()
|
|
|
|
oldAdapter := g.Cfg().GetAdapter()
|
|
adapter, err := gcfg.NewAdapterContent(`upstream:
|
|
gateway:
|
|
address: "` + strings.TrimPrefix(server.URL, "http://") + `"
|
|
timeout: 1s
|
|
`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
g.Cfg().SetAdapter(adapter)
|
|
t.Cleanup(func() { g.Cfg().SetAdapter(oldAdapter) })
|
|
|
|
output, err := NewUpstreamChan().TestChannel(context.Background(), &model.UpstreamChannelTestRequest{
|
|
ChannelID: 42, TenantID: "tenant-a", InputMode: "complete",
|
|
ICCID: "iccid", IMSI: "imsi", MSISDN: "msisdn", Items: []string{"simStatus"},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if requestCount != 1 {
|
|
t.Fatalf("request count=%d, want one", requestCount)
|
|
}
|
|
if requestBody.ChannelID != 42 || requestBody.TenantID != "tenant-a" || len(requestBody.Items) != 1 {
|
|
t.Fatalf("unexpected request body: %+v", requestBody)
|
|
}
|
|
if output == nil || len(output.Items) != 1 || output.Items[0].Status != "success" {
|
|
t.Fatalf("unexpected output: %+v", output)
|
|
}
|
|
if output.GatewayResponseRaw != gatewayBody {
|
|
t.Fatalf("raw response=%q, want %q", output.GatewayResponseRaw, gatewayBody)
|
|
}
|
|
}
|
|
|
|
func TestTestChannelPreservesGatewayErrorResponses(t *testing.T) {
|
|
responseBody := ""
|
|
responseStatus := http.StatusOK
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(responseStatus)
|
|
_, _ = w.Write([]byte(responseBody))
|
|
}))
|
|
defer server.Close()
|
|
|
|
oldAdapter := g.Cfg().GetAdapter()
|
|
adapter, err := gcfg.NewAdapterContent(`upstream:
|
|
gateway:
|
|
address: "` + strings.TrimPrefix(server.URL, "http://") + `"
|
|
timeout: 1s
|
|
`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
g.Cfg().SetAdapter(adapter)
|
|
t.Cleanup(func() { g.Cfg().SetAdapter(oldAdapter) })
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
body string
|
|
status int
|
|
wantMessage string
|
|
}{
|
|
{"business error", `{"code":13000,"message":"系统忙","data":{"items":[]}}`, http.StatusOK, "系统忙"},
|
|
{"completion error", `{"code":50,"message":"carrier did not return complete card identifiers","data":null}`, http.StatusOK, "carrier did not return complete card identifiers"},
|
|
{"empty message", `{"code":50,"message":"","data":null}`, http.StatusOK, "上游通道测试失败"},
|
|
{"HTTP error", `{"code":13000,"message":"网关故障"}`, http.StatusBadGateway, "网关故障"},
|
|
{"invalid JSON", `gateway unavailable`, http.StatusOK, "解析上游通道测试响应失败"},
|
|
{"schema mismatch", `{"code":0,"data":{"items":"invalid"}}`, http.StatusOK, "解析上游通道测试响应失败"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
responseBody = tc.body
|
|
responseStatus = tc.status
|
|
output, err := NewUpstreamChan().TestChannel(context.Background(), &model.UpstreamChannelTestRequest{
|
|
ChannelID: 42, TenantID: "tenant-a", InputMode: "complete",
|
|
ICCID: "iccid", IMSI: "imsi", MSISDN: "msisdn",
|
|
})
|
|
if err == nil || output != nil {
|
|
t.Fatalf("failure must remain an error: output=%+v err=%v", output, err)
|
|
}
|
|
var diagnostic *model.TSimChannelsTestError
|
|
if !errors.As(err, &diagnostic) || diagnostic.GatewayResponseRaw != tc.body {
|
|
t.Fatalf("missing raw error response: %+v", err)
|
|
}
|
|
if !strings.Contains(err.Error(), tc.wantMessage) || gerror.Code(err) != gcode.CodeNil {
|
|
t.Fatalf("original error changed: %v code=%v", err, gerror.Code(err))
|
|
}
|
|
if err.Error() != diagnostic.Err.Error() || !errors.Is(err, diagnostic.Err) {
|
|
t.Fatalf("original error chain changed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("individual failures remain results", func(t *testing.T) {
|
|
responseStatus = http.StatusOK
|
|
responseBody = `{"code":0,"message":"success","data":{"items":[{"key":"simStatus","status":"failed","errorCode":9999,"message":"carrier rejected"},{"key":"simSession","status":"timeout","message":"channel test item timed out"}]}}`
|
|
output, err := NewUpstreamChan().TestChannel(context.Background(), &model.UpstreamChannelTestRequest{ChannelID: 42, TenantID: "tenant-a"})
|
|
if err != nil || output == nil {
|
|
t.Fatalf("single-item failures must not fail the whole request: %v", err)
|
|
}
|
|
if output.GatewayResponseRaw != responseBody || len(output.Items) != 2 || output.Items[0].ErrorCode != 9999 || output.Items[0].Message != "carrier rejected" || output.Items[1].Status != "timeout" {
|
|
t.Fatalf("item results changed: %+v", output)
|
|
}
|
|
})
|
|
}
|