Files
lingniu-vehicle-ingest/vehicle-data-platform/apps/api/internal/gzev/client_test.go
T
lingniu d6b957dfc8 feat: sync vehicle monitoring and accumulated platform updates
Add monitoring metrics, numeric sorting, report-time display, vehicle number labels, and map layout fixes. Include accumulated mileage, hydrogen, OneOS authentication, open platform, ingestion, deployment, and UI updates.

Exclude temporary files, generated reports, and credentials. Validate frontend 632 tests and production build, API packages, vehicle-map tests, and release installer tests. Gateway suite has one pre-existing date-sensitive identity throttling test failure reproduced on the parent commit.
2026-10-26 18:05:59 +08:00

148 lines
5.1 KiB
Go

package gzev
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestDecimalPreservesNullAndZero(t *testing.T) {
for _, tc := range []struct {
in string
valid bool
value string
}{{"null", false, ""}, {`"0.0"`, true, "0.0"}, {"203.125", true, "203.125"}} {
var d Decimal
if err := json.Unmarshal([]byte(tc.in), &d); err != nil || d.Valid != tc.valid || d.Value != tc.value {
t.Fatalf("%s: %+v %v", tc.in, d, err)
}
}
for _, bad := range []string{`""`, `"NaN"`, `-1`, `"1.2345"`, `"100000000000"`} {
var d Decimal
if json.Unmarshal([]byte(bad), &d) == nil {
t.Fatalf("accepted %s", bad)
}
}
}
func TestDateShanghaiBoundary(t *testing.T) {
now := time.Date(2026, 9, 27, 16, 0, 0, 0, time.UTC)
if ValidateDate("2026-09-27", now) != nil || ValidateDate("2026-09-28", now) == nil {
t.Fatal("Shanghai day cutoff incorrect")
}
}
func TestFetchPaginationAndCookie(t *testing.T) {
calls := 0
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
calls++
if r.Header.Get("Authorization") != "Bearer fake" {
t.Error("missing bearer")
}
cookie, e := r.Cookie("token")
if e != nil || cookie.Value != "fake" {
t.Error("missing token cookie")
}
if r.URL.Query().Get("queryBeginDate") != "2024-01-01" || r.URL.Query().Get("queryEndDate") != "2024-01-01" || r.URL.Query().Get("queryType") != "2" {
t.Error("wrong daily query")
}
fmt.Fprintf(w, `{"code":"0","data":{"pageNum":%d,"total":2,"list":[{"vin":"LNXNEGRR7SR31945%d","dateRange":"2024-01-01 - 2024-01-01","runMileage":"12.1","hyRunMileage":null,"chargeRunMileage":"0"}]}}`, calls, calls)
}))
defer srv.Close()
c := NewClient(Session{Authorization: "Bearer fake", Cookies: []SessionCookie{{"token", "fake"}}})
c.baseURL = srv.URL
c.PageSize = 1
c.Delay = 0
day, err := c.FetchDay(context.Background(), "2024-01-01")
if err != nil || len(day.Rows) != 2 || len(day.Pages) != 2 || calls != 2 {
t.Fatalf("pagination: %+v %v", day, err)
}
if day.Rows[0].Hydrogen.Valid || !day.Rows[0].Charge.Valid {
t.Fatal("null lost")
}
}
func TestRejectsIncompleteSource(t *testing.T) {
for name, body := range map[string]string{
"missing code": `{"data":{}}`,
"missing total": `{"code":"0","data":{"pageNum":1,"list":[]}}`,
"empty page": `{"code":"0","data":{"pageNum":1,"total":2,"list":[]}}`,
"wrong date": `{"code":"0","data":{"pageNum":1,"total":1,"list":[{"vin":"LNXNEGRR7SR319456","dateRange":"2024-01-01 - 2024-01-02"}]}}`,
} {
t.Run(name, func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, body) }))
defer srv.Close()
c := NewClient(Session{})
c.baseURL = srv.URL
if _, err := c.FetchDay(context.Background(), "2024-01-01"); err == nil {
t.Fatal("accepted incomplete day")
}
})
}
}
func TestAuthAndPermissionAreDifferent(t *testing.T) {
for _, tc := range []struct {
code string
auth bool
}{{"401", true}, {"00000004", false}, {"403", false}} {
calls := 0
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { calls++; fmt.Fprintf(w, `{"code":%q}`, tc.code) }))
c := NewClient(Session{})
c.baseURL = srv.URL
_, err := c.FetchDay(context.Background(), "2024-01-01")
srv.Close()
if err == nil || errors.Is(err, ErrAuth) != tc.auth || calls != 1 {
t.Fatalf("code %s: %v calls=%d", tc.code, err, calls)
}
}
}
func TestNoCredentialRedirect(t *testing.T) {
hit := false
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { hit = true }))
defer target.Close()
source := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, target.URL, 302) }))
defer source.Close()
c := NewClient(Session{Authorization: "Bearer fake"})
c.baseURL = source.URL
_, err := c.FetchDay(context.Background(), "2024-01-01")
if hit || !errors.Is(err, ErrAuth) {
t.Fatalf("redirect leaked credentials: %v", err)
}
}
func TestReadSessionPermissionsAndCookieAllowlist(t *testing.T) {
p := filepath.Join(t.TempDir(), "session.json")
body := `{"authorization":"Bearer fake","cookies":[{"name":"token","value":"fake"}]}`
os.WriteFile(p, []byte(body), 0644)
if _, err := ReadSession(p); err == nil {
t.Fatal("accepted world-readable session")
}
os.Chmod(p, 0600)
if _, err := ReadSession(p); err != nil {
t.Fatal(err)
}
os.WriteFile(p, []byte(strings.ReplaceAll(body, `"name":"token"`, `"name":"password"`)), 0600)
if _, err := ReadSession(p); err == nil {
t.Fatal("accepted password cookie")
}
}
func TestVerifyAccountRejectsOtherLogin(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/evdata-sso/api/base/getUserInfo" || r.URL.Query().Get("token") != "fake" {
t.Error("incorrect identity contract")
}
fmt.Fprint(w, `{"code":"0","data":{"loginname":"different-account"}}`)
}))
defer srv.Close()
c := NewClient(Session{Authorization: "Bearer fake"})
c.baseURL = srv.URL
if c.VerifyAccount(context.Background(), "guangdonglingniu") == nil {
t.Fatal("mixed account data")
}
}