//go:build linux package modem import ( "context" "fmt" "os" "path/filepath" "strconv" "testing" ) func TestSysFSDiscoverySelectsInterface04AndNeverInterface02(t *testing.T) { root := t.TempDir() sysRoot := filepath.Join(root, "sys") devRoot := filepath.Join(root, "dev") usbRoot := filepath.Join(sysRoot, "bus", "usb", "devices") mustWrite(t, filepath.Join(usbRoot, "1-6", "idVendor"), "2c7c\n") mustWrite(t, filepath.Join(usbRoot, "1-6", "idProduct"), "0125\n") mustWrite(t, filepath.Join(usbRoot, "1-6", "manufacturer"), "Android\n") mustWrite(t, filepath.Join(usbRoot, "1-6", "product"), "Android\n") mustWrite(t, filepath.Join(usbRoot, "1-6", "serial"), "Android\n") for _, item := range []struct { interfaceName string interfaceNumber string tty string }{ {"1-6:1.2", "02", "ttyUSB0"}, {"1-6:1.3", "03", "ttyUSB1"}, {"1-6:1.4", "04", "ttyUSB2"}, {"1-6:1.5", "05", "ttyUSB3"}, } { mustWrite( t, filepath.Join(usbRoot, item.interfaceName, "bInterfaceNumber"), item.interfaceNumber+"\n", ) mustMkdir(t, filepath.Join( usbRoot, item.interfaceName, item.tty, "tty", item.tty, )) } mustMkdir(t, filepath.Join(usbRoot, "1-6:1.0", "net", "enx001122334455")) mustMkdir(t, filepath.Join(usbRoot, "1-6:1.4", "usbmisc", "cdc-wdm0")) discoverer := NewSysFSDiscoverer(sysRoot, devRoot) candidates, err := discoverer.Discover(context.Background()) if err != nil { t.Fatalf("Discover: %v", err) } if len(candidates) != 1 { t.Fatalf("got %d candidates, want 1", len(candidates)) } candidate := candidates[0] if candidate.ID != "quectel-0125-1-6" { t.Fatalf("ID = %q", candidate.ID) } if candidate.ATPort.Name != "ttyUSB2" { t.Fatalf("AT port = %#v, want ttyUSB2", candidate.ATPort) } if candidate.ATPort.InterfaceNumber != 0x04 { t.Fatalf("AT interface = %d, want 4", candidate.ATPort.InterfaceNumber) } if candidate.Ports[0].Role != PortRoleDiagnostic { t.Fatalf("interface 02 role = %q", candidate.Ports[0].Role) } if candidate.QMIControl != filepath.Join(devRoot, "cdc-wdm0") { t.Fatalf("QMI control = %q", candidate.QMIControl) } if candidate.NetworkInterface != "enx001122334455" { t.Fatalf("network interface = %q", candidate.NetworkInterface) } } func TestSysFSDiscoverySelectsTTYUSB2InQMIInterface00Layout(t *testing.T) { root := t.TempDir() sysRoot := filepath.Join(root, "sys") devRoot := filepath.Join(root, "dev") usbRoot := filepath.Join(sysRoot, "bus", "usb", "devices") mustWrite(t, filepath.Join(usbRoot, "1-6", "idVendor"), "2c7c\n") mustWrite(t, filepath.Join(usbRoot, "1-6", "idProduct"), "0125\n") for number, tty := range []string{"ttyUSB0", "ttyUSB1", "ttyUSB2", "ttyUSB3"} { interfaceName := "1-6:1." + strconv.Itoa(number) mustWrite( t, filepath.Join(usbRoot, interfaceName, "bInterfaceNumber"), fmt.Sprintf("%02x\n", number), ) mustMkdir(t, filepath.Join(usbRoot, interfaceName, tty, "tty", tty)) } mustWrite( t, filepath.Join(usbRoot, "1-6:1.4", "bInterfaceNumber"), "04\n", ) mustMkdir(t, filepath.Join(usbRoot, "1-6:1.4", "usbmisc", "cdc-wdm0")) mustMkdir(t, filepath.Join(usbRoot, "1-6:1.4", "net", "wwp0s20f0u6i4")) candidates, err := NewSysFSDiscoverer(sysRoot, devRoot).Discover(context.Background()) if err != nil { t.Fatalf("Discover: %v", err) } if len(candidates) != 1 { t.Fatalf("got %d candidates, want 1", len(candidates)) } candidate := candidates[0] if candidate.ATPort.Name != "ttyUSB2" || candidate.ATPort.InterfaceNumber != 0x02 || candidate.ATPort.Role != PortRoleAT { t.Fatalf("AT port = %#v, want ttyUSB2 on interface 02", candidate.ATPort) } if candidate.QMIControl != filepath.Join(devRoot, "cdc-wdm0") { t.Fatalf("QMI control = %q", candidate.QMIControl) } if candidate.NetworkInterface != "wwp0s20f0u6i4" { t.Fatalf("network interface = %q", candidate.NetworkInterface) } } func TestSysFSDiscoveryIgnoresNonQuectelUSB(t *testing.T) { root := t.TempDir() usbRoot := filepath.Join(root, "sys", "bus", "usb", "devices") mustWrite(t, filepath.Join(usbRoot, "2-1", "idVendor"), "0403\n") mustWrite(t, filepath.Join(usbRoot, "2-1:1.0", "bInterfaceNumber"), "00\n") mustMkdir(t, filepath.Join(usbRoot, "2-1:1.0", "ttyUSB9")) candidates, err := NewSysFSDiscoverer( filepath.Join(root, "sys"), filepath.Join(root, "dev"), ).Discover(context.Background()) if err != nil { t.Fatalf("Discover: %v", err) } if len(candidates) != 0 { t.Fatalf("got %#v, want no candidates", candidates) } } func mustWrite(t *testing.T, path, value string) { t.Helper() mustMkdir(t, filepath.Dir(path)) if err := os.WriteFile(path, []byte(value), 0o600); err != nil { t.Fatal(err) } } func mustMkdir(t *testing.T, path string) { t.Helper() if err := os.MkdirAll(path, 0o700); err != nil { t.Fatal(err) } }