package rabbitmq import ( "context" "fmt" "net/http" "net/http/httptest" "strings" "sync" "sync/atomic" "testing" "time" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gcfg" "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/model" ) func setChannelRefreshTestConfig(t *testing.T, gateway, proxy string) { t.Helper() oldAdapter := g.Cfg().GetAdapter() adapter, err := gcfg.NewAdapterContent(fmt.Sprintf(` upstream: gateway: address: %q timeout: 1s proxy: address: %q timeout: 1s `, gateway, proxy)) if err != nil { t.Fatal(err) } g.Cfg().SetAdapter(adapter) t.Cleanup(func() { g.Cfg().SetAdapter(oldAdapter) }) } func testServerAddress(server *httptest.Server) string { return strings.TrimPrefix(server.URL, "http://") } func TestRefreshChannelCallsGatewayAndProxy(t *testing.T) { var gatewayCalls atomic.Int32 var proxyCalls atomic.Int32 newServer := func(counter *atomic.Int32) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { counter.Add(1) if request.URL.Path != "/internal/channel/refresh" || request.URL.Query().Get("chanKey") != "channel-a" { t.Fatalf("unexpected request: %s", request.URL.String()) } _, _ = w.Write([]byte(`{"code":0,"message":"success"}`)) })) } gateway := newServer(&gatewayCalls) defer gateway.Close() proxy := newServer(&proxyCalls) defer proxy.Close() setChannelRefreshTestConfig(t, testServerAddress(gateway), testServerAddress(proxy)) if err := refreshChannel(context.Background(), "channel-a"); err != nil { t.Fatal(err) } if gatewayCalls.Load() != 1 || proxyCalls.Load() != 1 { t.Fatalf("gateway calls=%d proxy calls=%d", gatewayCalls.Load(), proxyCalls.Load()) } } func TestRenameChannelOnlyRebuildsRuntimeInstances(t *testing.T) { var ( mu sync.Mutex events []string ) newServer := func(target string) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { mu.Lock() events = append(events, target+":"+request.URL.Path+":"+request.URL.Query().Get("chanKey")) mu.Unlock() _, _ = w.Write([]byte(`{"code":0,"message":"success"}`)) })) } gateway := newServer("gateway") defer gateway.Close() proxy := newServer("proxy") defer proxy.Close() setChannelRefreshTestConfig(t, testServerAddress(gateway), testServerAddress(proxy)) if err := renameChannel(context.Background(), "channel-old", "channel-new"); err != nil { t.Fatal(err) } want := []string{ "gateway:/internal/channel/refresh:channel-new", "proxy:/internal/channel/refresh:channel-new", "gateway:/internal/channel/remove:channel-old", "proxy:/internal/channel/remove:channel-old", } if strings.Join(events, "\n") != strings.Join(want, "\n") { t.Fatalf("rename events = %q, want %q", events, want) } } func TestChannelControlErrorIncludesTargetStatusAndMessage(t *testing.T) { gateway := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusBadGateway) _, _ = w.Write([]byte(`{"code":50,"message":"carrier unavailable"}`)) })) defer gateway.Close() setChannelRefreshTestConfig(t, testServerAddress(gateway), "127.0.0.1:1") err := refreshChannelTarget(context.Background(), "upstream.gateway", "channel-a") if err == nil { t.Fatal("expected target error") } message := err.Error() for _, part := range []string{"target=upstream.gateway", "status=502", "carrier unavailable"} { if !strings.Contains(message, part) { t.Fatalf("error %q does not contain %q", message, part) } } } func TestHandleChannelRefreshReturnsError(t *testing.T) { gateway := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(`{"code":50,"message":"refresh rejected"}`)) })) defer gateway.Close() setChannelRefreshTestConfig(t, testServerAddress(gateway), "127.0.0.1:1") ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond) defer cancel() consumer := &Consumers{} if err := consumer.handleChannelRefresh(ctx, model.ChannelRefreshMessage{Type: "channel", ChanKey: "channel-a"}); err == nil { t.Fatal("refresh failure was acknowledged as success") } }