package osi import ( "context" "encoding/json" "net" "net/http" "net/http/httptest" "strings" "testing" "time" ) func TestTransportPostJSONSendsPayloadAndHeaders(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { t.Fatalf("method = %s, want POST", r.Method) } if r.Header.Get("Content-Type") != "application/json" { t.Fatalf("Content-Type = %q", r.Header.Get("Content-Type")) } if r.Header.Get("orgCode") != "org-001" { t.Fatalf("orgCode = %q", r.Header.Get("orgCode")) } for _, name := range []string{"Cookie", "Origin", "Referer", "X-Requested-With"} { if got := r.Header.Get(name); got != "" { t.Fatalf("unexpected browser/cookie header %s=%q", name, got) } } var payload map[string]any if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { t.Fatalf("decode payload: %v", err) } if payload["serviceId"] != "JKDA00002" { t.Fatalf("serviceId = %v", payload["serviceId"]) } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) _, _ = w.Write([]byte(`{"code":"01"}`)) })) defer server.Close() transport, err := NewTransport(TransportConfig{Timeout: time.Second}) if err != nil { t.Fatalf("NewTransport: %v", err) } status, raw, err := transport.PostJSON( context.Background(), server.URL, map[string]any{"serviceId": "JKDA00002"}, map[string]string{"Content-Type": "application/json", "orgCode": "org-001"}, ) if err != nil { t.Fatalf("PostJSON: %v", err) } if status != http.StatusAccepted { t.Fatalf("status = %d, want %d", status, http.StatusAccepted) } if string(raw) != `{"code":"01"}` { t.Fatalf("raw = %s", raw) } } func TestNewTransportKeepsTimeout(t *testing.T) { transport, err := NewTransport(TransportConfig{Timeout: 3 * time.Second}) if err != nil { t.Fatalf("NewTransport: %v", err) } if transport.timeout != 3*time.Second { t.Fatalf("timeout = %s, want 3s", transport.timeout) } } func TestNewTransportRejectsInvalidSOCKS5Proxy(t *testing.T) { if _, err := NewTransport(TransportConfig{Socks5Proxy: "missing-port"}); err == nil { t.Fatal("NewTransport accepted invalid SOCKS5 proxy") } } func TestTransportPreservesHeaderNameCasing(t *testing.T) { listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listen: %v", err) } defer listener.Close() received := make(chan string, 1) go func() { conn, err := listener.Accept() if err != nil { received <- "" return } defer conn.Close() buf := make([]byte, 4096) n, _ := conn.Read(buf) received <- string(buf[:n]) _, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\n{}")) }() transport, err := NewTransport(TransportConfig{Timeout: time.Second}) if err != nil { t.Fatalf("NewTransport: %v", err) } _, _, err = transport.PostJSON( context.Background(), "http://"+listener.Addr().String(), map[string]string{"serviceId": "JKDA00002"}, map[string]string{"orgCode": "org-001", "deviceSN": "", "userName": "dyytgw"}, ) if err != nil { t.Fatalf("PostJSON: %v", err) } raw := <-received for _, header := range []string{"orgCode:", "deviceSN:", "userName:"} { if !strings.Contains(raw, "\r\n"+header) { t.Fatalf("raw request missing exact header %q:\n%s", header, raw) } } } func TestTransportAddsRequestsCompatibleBaseHeaders(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("User-Agent") == "" { t.Fatal("missing User-Agent") } if r.Header.Get("Accept") != "*/*" { t.Fatalf("Accept = %q", r.Header.Get("Accept")) } if r.Header.Get("Connection") != "keep-alive" { t.Fatalf("Connection = %q", r.Header.Get("Connection")) } _, _ = w.Write([]byte(`{}`)) })) defer server.Close() transport, err := NewTransport(TransportConfig{Timeout: time.Second}) if err != nil { t.Fatalf("NewTransport: %v", err) } if _, _, err := transport.PostJSON(context.Background(), server.URL, map[string]string{"serviceId": "JKDA00002"}, nil); err != nil { t.Fatalf("PostJSON: %v", err) } } func TestTransportRequestsIdentityEncoding(t *testing.T) { listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listen: %v", err) } defer listener.Close() received := make(chan string, 1) go func() { conn, err := listener.Accept() if err != nil { received <- "" return } defer conn.Close() buf := make([]byte, 4096) n, _ := conn.Read(buf) received <- string(buf[:n]) _, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\n{}")) }() transport, err := NewTransport(TransportConfig{Timeout: time.Second}) if err != nil { t.Fatalf("NewTransport: %v", err) } _, _, err = transport.PostJSON(context.Background(), "http://"+listener.Addr().String(), map[string]string{"serviceId": "JKDA00002"}, nil) if err != nil { t.Fatalf("PostJSON: %v", err) } raw := <-received if !strings.Contains(raw, "\r\nAccept-Encoding: identity\r\n") { t.Fatalf("raw request missing identity Accept-Encoding:\n%s", raw) } }