mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-13 19:33:42 +08:00
- Increment schema version from 11 to 12. - Modify ProxyResolver to use ICCID for device proxy binding resolution. - Update tests to reflect changes in proxy binding logic using ICCID. - Enhance DeviceBindingsDialog to manage eSIM profile bindings instead of device bindings. - Update UI components and translations to reflect the new profile binding terminology. - Implement pagination for automatic task runs in AutomaticTasksPage. - Create a new Pagination component for better navigation in lists.
96 lines
4.0 KiB
Go
96 lines
4.0 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"vocat/internal/store"
|
|
"vocat/internal/vowifi"
|
|
)
|
|
|
|
const testProfileICCID = "89441000400128014257"
|
|
|
|
func newProfileBindingTestServer(t *testing.T) (*Server, *store.Store, *fakeVoWiFiController) {
|
|
t.Helper()
|
|
database, err := store.Open(context.Background(), ":memory:")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = database.Close() })
|
|
if err := database.UpsertDevice(context.Background(), store.Device{ID: "ec20", Name: "EC20", VoWiFiEnabled: true}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, upstream := range []store.UpstreamProxy{
|
|
{ID: "route-1", Name: "Route 1", Addr: "127.0.0.1:1080", Enabled: true},
|
|
{ID: "route-2", Name: "Route 2", Addr: "127.0.0.1:1081", Enabled: true},
|
|
} {
|
|
if err := database.UpsertUpstreamProxy(context.Background(), upstream); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
controller := &fakeVoWiFiController{state: vowifi.State{DeviceID: "ec20", ICCID: testProfileICCID, Enabled: true}}
|
|
return &Server{store: database, vowifi: controller, logger: slog.New(slog.NewTextHandler(io.Discard, nil)), maxRequestBodyBytes: 16 << 10}, database, controller
|
|
}
|
|
|
|
func profileBindingRequest(t *testing.T, server *Server, method, body string) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
request := httptest.NewRequest(method, "/api/upstream-proxy-profile-bindings", bytes.NewBufferString(body))
|
|
request.Header.Set("Content-Type", "application/json")
|
|
response := httptest.NewRecorder()
|
|
server.handleProfileProxyBindings(response, request)
|
|
return response
|
|
}
|
|
|
|
func TestProfileProxyBindingPersistsAndReconnectsOnlyCurrentICCID(t *testing.T) {
|
|
server, database, controller := newProfileBindingTestServer(t)
|
|
response := profileBindingRequest(t, server, http.MethodPost, `{
|
|
"upstream_proxy_id":"route-1",
|
|
"bindings":[
|
|
{"device_id":"ec20","iccid":"89441000400128014257","profile_name":"Vodafone UK","state_text":"Enabled"},
|
|
{"device_id":"ec20","iccid":"89104100000028106378","profile_name":"TIM"}
|
|
]
|
|
}`)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("POST status = %d, body = %s", response.Code, response.Body.String())
|
|
}
|
|
binding, err := database.DeviceProxyBinding(context.Background(), testProfileICCID)
|
|
if err != nil || binding.UpstreamProxyID != "route-1" || binding.ProfileName != "Vodafone UK" {
|
|
t.Fatalf("binding = %+v, %v", binding, err)
|
|
}
|
|
if controller.reconnects != 1 {
|
|
t.Fatalf("reconnects = %d, want only the current ICCID to reconnect", controller.reconnects)
|
|
}
|
|
|
|
response = profileBindingRequest(t, server, http.MethodDelete, `{"upstream_proxy_id":"route-1","iccids":["89441000400128014257","89104100000028106378"]}`)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("DELETE status = %d, body = %s", response.Code, response.Body.String())
|
|
}
|
|
if _, err := database.DeviceProxyBinding(context.Background(), testProfileICCID); err != store.ErrNotFound {
|
|
t.Fatalf("binding after delete error = %v, want ErrNotFound", err)
|
|
}
|
|
if controller.reconnects != 2 {
|
|
t.Fatalf("reconnects after delete = %d, want 2", controller.reconnects)
|
|
}
|
|
}
|
|
|
|
func TestProfileProxyBindingRejectsSameICCIDOnDifferentProxy(t *testing.T) {
|
|
server, database, _ := newProfileBindingTestServer(t)
|
|
first := profileBindingRequest(t, server, http.MethodPost, `{"upstream_proxy_id":"route-1","bindings":[{"device_id":"ec20","iccid":"89441000400128014257","profile_name":"Profile"}]}`)
|
|
if first.Code != http.StatusOK {
|
|
t.Fatalf("initial bind status = %d, body = %s", first.Code, first.Body.String())
|
|
}
|
|
second := profileBindingRequest(t, server, http.MethodPost, `{"upstream_proxy_id":"route-2","bindings":[{"device_id":"ec20","iccid":"89441000400128014257","profile_name":"Profile"}]}`)
|
|
if second.Code != http.StatusConflict {
|
|
t.Fatalf("rebind status = %d, want 409, body = %s", second.Code, second.Body.String())
|
|
}
|
|
binding, err := database.DeviceProxyBinding(context.Background(), testProfileICCID)
|
|
if err != nil || binding.UpstreamProxyID != "route-1" {
|
|
t.Fatalf("binding after rejected rebind = %+v, %v", binding, err)
|
|
}
|
|
}
|