| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- package integration
- import (
- "context"
- "encoding/json"
- "testing"
- "time"
- "vocat/internal/device"
- "vocat/internal/store"
- "vocat/internal/vowifi"
- )
- func testStore(t *testing.T) *store.Store {
- t.Helper()
- database, err := store.Open(context.Background(), ":memory:")
- if err != nil {
- t.Fatal(err)
- }
- t.Cleanup(func() { _ = database.Close() })
- return database
- }
- func TestProxyResolverUsesDeviceBinding(t *testing.T) {
- database := testStore(t)
- if err := database.UpsertDevice(context.Background(), store.Device{ID: "ec20", Name: "EC20"}); err != nil {
- t.Fatal(err)
- }
- if err := database.UpsertUpstreamProxy(context.Background(), store.UpstreamProxy{
- ID: "clash",
- Name: "Clash",
- Addr: "192.168.2.143:7897",
- Enabled: true,
- Password: "must-not-be-lost",
- Username: "proxy-user",
- }); err != nil {
- t.Fatal(err)
- }
- if err := database.UpsertDeviceProxyBinding(context.Background(), store.DeviceProxyBinding{
- DeviceID: "ec20",
- UpstreamProxyID: "clash",
- }); err != nil {
- t.Fatal(err)
- }
- route, err := (ProxyResolver{Store: database}).Resolve(
- context.Background(),
- vowifi.ProxyRequest{DeviceID: "ec20", HomeMCC: "234", HomeMNC: "15"},
- )
- if err != nil {
- t.Fatal(err)
- }
- if route.Mode != vowifi.ProxyModeSOCKS5 ||
- route.Address != "192.168.2.143:7897" ||
- route.Username != "proxy-user" ||
- route.Password != "must-not-be-lost" {
- t.Fatalf("route = %#v", route)
- }
- }
- func TestProxyResolverDoesNotUseCountryRuleWithoutDeviceBinding(t *testing.T) {
- database := testStore(t)
- if err := database.UpsertUpstreamProxy(context.Background(), store.UpstreamProxy{
- ID: "legacy", Name: "Legacy", Addr: "127.0.0.1:1080", Enabled: true,
- }); err != nil {
- t.Fatal(err)
- }
- if err := database.UpsertCountryRule(context.Background(), store.CountryRule{
- CountryCode: "GB", CountryName: "United Kingdom", UpstreamProxyID: "legacy", Enabled: true,
- }); err != nil {
- t.Fatal(err)
- }
- route, err := (ProxyResolver{Store: database}).Resolve(
- context.Background(),
- vowifi.ProxyRequest{DeviceID: "ec20", HomeMCC: "234"},
- )
- if err != nil {
- t.Fatal(err)
- }
- if route.Mode != vowifi.ProxyModeDirect {
- t.Fatalf("route = %#v, want direct", route)
- }
- }
- func TestPhoneStoreRejectsUntrustedSource(t *testing.T) {
- database := testStore(t)
- phones := PhoneStore{Store: database, DeviceID: "ec20"}
- record := vowifi.PhoneRecord{
- ICCID: "89441000400311061404",
- Number: "+447700900123",
- Source: "imsi_guess",
- UpdatedAt: time.Now(),
- }
- if err := phones.SaveAssociatedNumber(context.Background(), record); err == nil {
- t.Fatal("untrusted source was accepted")
- }
- record.Source = vowifi.PhoneSourcePAssociatedURI
- if err := phones.SaveAssociatedNumber(context.Background(), record); err != nil {
- t.Fatal(err)
- }
- got, err := database.PhoneAssociation(context.Background(), record.ICCID)
- if err != nil {
- t.Fatal(err)
- }
- if got.Number != record.Number || got.Source != record.Source {
- t.Fatalf("association = %#v", got)
- }
- }
- func TestStateProjectorRestoresVerifiedNumber(t *testing.T) {
- database := testStore(t)
- if err := database.UpsertDevice(context.Background(), store.Device{
- ID: "ec20",
- Name: "EC20",
- }); err != nil {
- t.Fatal(err)
- }
- if err := database.UpsertPhoneAssociation(context.Background(), store.PhoneAssociation{
- ICCID: "89441000400311061404",
- DeviceID: "ec20",
- Number: "+447700900123",
- Source: vowifi.PhoneSourcePAssociatedURI,
- }); err != nil {
- t.Fatal(err)
- }
- projector := StateProjector{
- Store: database,
- Devices: staticDeviceReader{
- iccid: "89441000400311061404",
- imsi: "234159598901845",
- },
- }
- if err := projector.Save(context.Background(), vowifi.State{
- DeviceID: "ec20",
- Phase: vowifi.PhaseIdle,
- UpdatedAt: time.Now().UTC(),
- }); err != nil {
- t.Fatal(err)
- }
- runtime, err := database.VoWiFiRuntime(context.Background(), "ec20")
- if err != nil {
- t.Fatal(err)
- }
- if runtime.LocalPhone != "+447700900123" ||
- runtime.PhoneNumberSource != vowifi.PhoneSourcePAssociatedURI {
- t.Fatalf("runtime phone = %q (%q)", runtime.LocalPhone, runtime.PhoneNumberSource)
- }
- var tunnel map[string]any
- if err := json.Unmarshal(runtime.Tunnel, &tunnel); err != nil {
- t.Fatal(err)
- }
- }
- func TestStateProjectorPreservesConcreteDataplaneMode(t *testing.T) {
- database := testStore(t)
- if err := database.UpsertDevice(context.Background(), store.Device{
- ID: "ec25",
- Name: "EC25",
- }); err != nil {
- t.Fatal(err)
- }
- projector := StateProjector{Store: database}
- if err := projector.Save(context.Background(), vowifi.State{
- DeviceID: "ec25",
- Phase: vowifi.PhaseIMSReady,
- TunnelReady: true,
- IMSReady: true,
- TunnelName: "vocat-swu-ec25",
- DataplaneMode: "userspace",
- UpdatedAt: time.Now().UTC(),
- }); err != nil {
- t.Fatal(err)
- }
- runtime, err := database.VoWiFiRuntime(context.Background(), "ec25")
- if err != nil {
- t.Fatal(err)
- }
- if runtime.DataplaneMode != "userspace" {
- t.Fatalf("dataplane mode = %q, want userspace", runtime.DataplaneMode)
- }
- var tunnel map[string]any
- if err := json.Unmarshal(runtime.Tunnel, &tunnel); err != nil {
- t.Fatal(err)
- }
- if tunnel["dataplane_mode"] != "userspace" {
- t.Fatalf("tunnel dataplane mode = %#v", tunnel["dataplane_mode"])
- }
- }
- type staticDeviceReader struct {
- iccid string
- imsi string
- }
- func (reader staticDeviceReader) Get(string) (device.Device, error) {
- return device.Device{
- Snapshot: &device.Snapshot{
- ICCID: reader.iccid,
- IMSI: reader.imsi,
- },
- }, nil
- }
|