package ocpp import ( "bytes" "context" "net/http" "net/http/httptest" "strings" "testing" "time" ) func TestAcceptKey(t *testing.T) { // RFC 6455 §1.3 worked example. if got := acceptKey("dGhlIHNhbXBsZSBub25jZQ=="); got != "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" { t.Fatalf("acceptKey = %q, want s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", got) } } // echoServer upgrades and echoes every message back, exercising the framing + // masking round trip in both directions across a range of payload sizes. func TestFramingRoundTrip(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { conn, err := Upgrade(w, r) if err != nil { t.Errorf("upgrade: %v", err) return } for { msg, err := conn.ReadMessage() if err != nil { return } if err := conn.WriteMessage(msg); err != nil { return } } })) defer srv.Close() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() conn, err := Dial(ctx, wsURL(srv.URL, "/"), []string{"ocpp1.6"}, nil) if err != nil { t.Fatalf("dial: %v", err) } defer conn.Close() // Small (<126), medium (2-byte length), large (8-byte length) — all masked // client→server, unmasked on the way back. for _, size := range []int{5, 200, 70000} { want := bytes.Repeat([]byte("x"), size) if err := conn.WriteMessage(want); err != nil { t.Fatalf("write size %d: %v", size, err) } got, err := conn.ReadMessage() if err != nil { t.Fatalf("read size %d: %v", size, err) } if !bytes.Equal(got, want) { t.Fatalf("size %d: echoed %d bytes, want %d", size, len(got), len(want)) } } } func TestUpgradeRejectsNonWebSocket(t *testing.T) { rec := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/ocpp/CP1", nil) if _, err := Upgrade(rec, req); err == nil { t.Fatal("expected error upgrading a plain GET") } } func TestDialRejectsBadScheme(t *testing.T) { if _, err := Dial(context.Background(), "ftp://example/x", nil, nil); err == nil || !strings.Contains(err.Error(), "unsupported scheme") { t.Fatalf("want unsupported scheme error, got %v", err) } }