128 lines
4.2 KiB
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))
|
|
}
|