ituoke/internal/mcpclient/mobile_test.go

128 lines
4.2 KiB
Go

package mcpclient
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
func TestMobilePresetPersistsAndHonorsDisabled(t *testing.T) {
s, _ := testService(t)
if err := s.ensureMobile(); err != nil {
t.Fatal(err)
}
if err := s.ensureMobile(); err != nil {
t.Fatal(err)
}
views, err := s.ListServers()
if err != nil || len(views) != 1 || views[0].Config.Transport != "mobile" {
t.Fatalf("preset: %+v %v", views, err)
}
if err := s.SetEnabled(mobileServerID, false); err != nil {
t.Fatal(err)
}
restored := newService(s.path, memorySecrets{})
if err := restored.ensureMobile(); err != nil {
t.Fatal(err)
}
views, err = restored.ListServers()
if err != nil || len(views) != 1 || views[0].Config.Enabled {
t.Fatalf("disabled preference lost: %+v %v", views, err)
}
if err := s.DeleteServer(mobileServerID); err == nil {
t.Fatal("deleted system preset")
}
c, err := normalize(ServerConfig{Name: "Mobile", Transport: "mobile", TimeoutSeconds: 30, Command: "unexpected", URL: "https://invalid.test", Args: []string{"bad"}})
if err != nil || c.Command != "" || c.URL != "" || len(c.Args) != 0 {
t.Fatalf("launch parameters persisted: %+v %v", c, err)
}
if err := validateSecrets(c, Secrets{Env: map[string]string{"NODE_OPTIONS": "--inspect"}}); err == nil {
t.Fatal("accepted builtin credentials")
}
}
func TestBuiltinMobileOnlyExposesLocalDriverTools(t *testing.T) {
c := ServerConfig{Transport: "mobile"}
for _, name := range []string{"mobile_login_to_cloud_provider", "mobile_list_remote_devices", "mobile_allocate_remote_device", "mobile_release_remote_device", "mobile_batch_commands", "mobile_get_foreground_app", "mobile_future_cloud_tool"} {
if supportedTool(c, name) {
t.Errorf("builtin exposes unsupported tool %s", name)
}
if !supportedTool(ServerConfig{Transport: "stdio"}, name) {
t.Errorf("custom server unexpectedly filtered: %s", name)
}
}
if got := toolDescription(c, "mobile_list_available_devices", "Use mobile_list_remote_devices"); strings.Contains(got, "mobile_list_remote_devices") {
t.Fatal("local discovery still recommends cloud devices")
}
}
func TestBundledMobile(t *testing.T) {
if os.Getenv("ITUOKE_TEST_MOBILE") != "1" {
t.Skip("stage official runtime and set ITUOKE_TEST_MOBILE=1")
}
t.Chdir(filepath.Join("..", ".."))
t.Setenv("PATH", t.TempDir())
t.Setenv("NODE_OPTIONS", "--invalid-parent-option")
s, _ := testService(t)
if err := s.ensureMobile(); err != nil {
t.Fatal(err)
}
views, err := s.ListServers()
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second)
defer cancel()
result := s.TestServer(ctx, ServerInput{Config: views[0].Config})
if !result.OK {
t.Fatal(result.Message)
}
names := map[string]bool{}
for _, tool := range result.Tools {
names[tool.Name] = true
if !supportedTool(views[0].Config, tool.Name) {
t.Fatalf("discovery exposes unsupported tool %s", tool.Name)
}
}
for _, name := range []string{"mobile_list_available_devices", "mobile_take_screenshot", "mobile_click_on_screen_at_coordinates", "mobile_swipe_on_screen", "mobile_type_keys"} {
if !names[name] {
t.Fatalf("missing tool %s", name)
}
}
if err := withSession(ctx, views[0].Config, Secrets{}, func(session *mcp.ClientSession) error {
result, err := session.CallTool(ctx, &mcp.CallToolParams{Name: "mobile_list_available_devices", Arguments: map[string]any{}})
if err != nil {
return err
}
if result.IsError {
t.Fatalf("device discovery failed: %+v", result.Content)
}
return nil
}); err != nil {
t.Fatal(err)
}
toolset, err := OpenTools(ctx, s, nil)
if err != nil {
t.Fatal(err)
}
defer toolset.Close()
if len(toolset.Tools()) < 5 {
t.Fatal("tools not available to Agent")
}
for _, tool := range toolset.Tools() {
if !supportedTool(views[0].Config, tool.Tool) {
t.Fatalf("Agent exposes unsupported tool %s", tool.Tool)
}
}
raw, _ := os.ReadFile(s.path)
if strings.Contains(string(raw), "node_modules") || strings.Contains(string(raw), "Applications") {
t.Fatal("machine-specific paths saved")
}
t.Logf("bundled Mobile Next: %d tools; device discovery succeeded without system Node/ADB", len(result.Tools))
}