package websocket import ( "context" "encoding/json" "fmt" "net" "net/http" "net/http/httptest" "strings" "testing" "time" m "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/httpclient" "github.com/fiskerinc/cloud-services/pkg/httpclient/mock" kafka "github.com/fiskerinc/cloud-services/pkg/kafka/mock" "github.com/fiskerinc/cloud-services/pkg/testhelper" "github.com/gobwas/httphead" "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" ) func createMockWebsocketClient(url, userAgent string) net.Conn { u := "ws" + strings.TrimPrefix(url, "http") header := make(http.Header) header.Add("User-Agent", userAgent) header.Add("X-ICCID", "12345678912345678923456789") header.Add("Ssl-Client-Subject-Dn", "CN=1F15K3R45N1234567") dialer := ws.Dialer{ Header: ws.HandshakeHeaderHTTP(header), Extensions: []httphead.Option{httphead.NewOption("permessage-deflate", map[string]string{})}, } ctx := context.Background() ws, _, _, err := dialer.Dial(ctx, u) if err != nil { return nil } return ws } func TestSecureSessionTRex(t *testing.T) { userAgent := "Fisker Ocean T.Rex 1.2.3.4 abc123" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewSecureSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionTRex", nil, err) } defer s.Close() if fmt.Sprintf("%T", s) != "*websocket.SessionTRex" { t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionTRex", "*websocket.SessionTRex", fmt.Sprintf("%T", s)) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() } func TestSecureSessionHMI(t *testing.T) { userAgent := "HMI 2.0.0.0" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewSecureSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionHMI", nil, err) } defer s.Close() if fmt.Sprintf("%T", s) != "*websocket.SessionHMI" { t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionHMI", "*websocket.SessionHMI", fmt.Sprintf("%T", s)) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() } func TestInsecureSessionMobile(t *testing.T) { userAgent := "Mobile 1.2.3.4" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewInsecureSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionMobile", nil, err) } defer s.Close() if fmt.Sprintf("%T", s) != "*websocket.SessionMobile" { t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionMobile", "*websocket.SessionMobile", fmt.Sprintf("%T", s)) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() } func TestSession(t *testing.T) { ws, _ := net.Pipe() s := &Session{ Websocket: ws, } if fmt.Sprintf("%T", s) != "*websocket.Session" { t.Errorf(testhelper.TestErrorTemplate, "TestSession", "*websocket.Session", fmt.Sprintf("%T", s)) } } func TestNewSession(t *testing.T) { userAgent := "" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestNewSession", nil, err) } defer s.Close() if fmt.Sprintf("%T", s) != "*websocket.Session" { t.Errorf(testhelper.TestErrorTemplate, "TestNewSession", "*websocket.Session", fmt.Sprintf("%T", s)) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() } func TestSessionAuthenticate(t *testing.T) { c := mock.Client{ DoFunc: func(*http.Request) (*http.Response, error) { return &http.Response{StatusCode: 200}, nil }, } httpclient.Client = &c userAgent := "" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionAuthenticate", nil, err) } defer s.Close() err = s.Authenticate() if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionAuthenticate", nil, err) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() ae := AuthEvent{ Topic: "auth_service", Key: "FISKER123", Payload: AuthPayload{ Handler: "verify", Data: AuthData{ Token: "validtoken", }, }, } msg, err := json.Marshal(ae) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionAuthenticate", nil, err) } wsutil.WriteClientMessage(conn, ws.OpText, msg) } func TestSessionKey(t *testing.T) { ws, _ := net.Pipe() s := &Session{ Websocket: ws, Type: m.TRex, ID: "FISKER123", } key := s.Key() if key != "1:FISKER123" { t.Errorf(testhelper.TestErrorTemplate, "TestSessionKey", "1:FISKER123", key) } } func TestSessionKeyUnknown(t *testing.T) { ws, _ := net.Pipe() s := &Session{ Websocket: ws, Type: m.Unknown, ID: "FISKER123", } key := s.Key() if key != "FISKER123" { t.Errorf(testhelper.TestErrorTemplate, "TestSessionKeyUnknown", "FISKER123", key) } } func TestSessionReceive(t *testing.T) { userAgent := "" payload := "hello fisker!" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionReceive", nil, err) } defer s.Close() data, _, err := s.Receive() if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionReceive", nil, err) } msg := string(data) if msg != payload { t.Errorf(testhelper.TestErrorTemplate, "TestSessionReceive", payload, msg) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() err := wsutil.WriteClientMessage(conn, ws.OpText, []byte(payload)) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionReceive", nil, err) } } func TestSessionListen(t *testing.T) { userAgent := "" payload := "hello fisker!" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionListen", nil, err) } defer s.Close() ctx := context.Background() err = s.Listen(ctx, kafka.GetKafkaMock(nil)) if err.Error() != "EOF" { t.Errorf(testhelper.TestErrorTemplate, "TestSessionListen", nil, err) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() err := wsutil.WriteClientMessage(conn, ws.OpText, []byte(payload)) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionListen", nil, err) } } func TestSessionSend(t *testing.T) { userAgent := "" payload := "hello fisker!" createNewSession := func(w http.ResponseWriter, r *http.Request) { s, err := NewSession(w, r) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionSend", nil, err) } defer s.Close() data, _, err := s.Receive() if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionSend", nil, err) } msg := string(data) if msg != payload { t.Errorf(testhelper.TestErrorTemplate, "TestSessionSend", payload, msg) } err = s.SendMsgToClient(data) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionSend", nil, err) } } server := httptest.NewServer(http.HandlerFunc(createNewSession)) defer server.Close() conn := createMockWebsocketClient(server.URL, userAgent) defer conn.Close() err := wsutil.WriteClientMessage(conn, ws.OpText, []byte(payload)) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionSend", nil, err) } echo, _, err := wsutil.ReadServerData(conn) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionSend", nil, err) } message := string(echo) if message != payload { t.Errorf(testhelper.TestErrorTemplate, "TestSessionSend", payload, message) } } func TestSessionLoad(t *testing.T) { ws, _ := net.Pipe() s := &Session{ Websocket: ws, Type: m.TRex, ID: "FISKER123", } err := s.Load(kafka.GetKafkaMock(nil)) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionLoad", nil, err) } } func TestSessionTeardown(t *testing.T) { ws, _ := net.Pipe() s := &Session{ Websocket: ws, Type: m.TRex, ID: "FISKER123", } err := s.Load(kafka.GetKafkaMock(nil)) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionLoad", nil, err) } err = s.Teardown(kafka.GetKafkaMock(nil)) if err != nil { t.Errorf(testhelper.TestErrorTemplate, "TestSessionLoad", nil, err) } } func TestSessionGetUUID(t *testing.T) { ws, _ := net.Pipe() currentNanoSeconds := time.Now().UnixNano() s := &Session{ Websocket: ws, Type: m.TRex, ID: "FISKER123", epoch: currentNanoSeconds, } uuid := s.GetUUID() if uuid != currentNanoSeconds { t.Errorf(testhelper.TestErrorTemplate, "TestSessionLoad", currentNanoSeconds, uuid) } } type SessionGetVINTestCase struct { Name string Session *Session VIN string ExpectedErrorMsg string } func TestSessionGetVIN(t *testing.T) { ws, _ := net.Pipe() tests := []SessionGetVINTestCase{ { Name: "Parsable", Session: &Session{ Websocket: ws, Type: m.TRex, ID: "VCF1EBU22PG001732", }, VIN: "VCF1EBU22PG001732", }, { Name: "Not Parsable", Session: &Session{ Websocket: ws, Type: m.TRex, ID: "FISKER123", }, VIN: "FISKER123", ExpectedErrorMsg: "could not get VIN from session", }, } for _, tt := range tests { vin := tt.Session.GetID() if vin != tt.VIN { t.Errorf(testhelper.TestErrorTemplate, "TestSessionGetVIN", tt.VIN, vin) } } }