ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/AnyEvent-MCP/t/13_vim_stdio.t
Revision: 1.1
Committed: Sat Oct 10 08:35:59 2026 UTC (7 days, 7 hours ago) by root
Content type: application/x-troff
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 use common::sense;
2     use Test::More;
3     use JSON::XS ();
4     use IPC::Open3 ();
5     use IO::Select ();
6     use IO::Socket::INET ();
7     use POSIX qw(WNOHANG);
8     use Time::HiRes ();
9     use File::Temp ();
10     use File::Path ();
11     use Symbol ();
12    
13     my $dir = File::Temp::tempdir (CLEANUP => 1);
14     File::Path::mkpath (["$dir/home", "$dir/config"], 0, 0700);
15     local $ENV{HOME} = "$dir/home";
16     local $ENV{XDG_CONFIG_HOME} = "$dir/config";
17    
18     sub free_port {
19     my $socket = IO::Socket::INET->new (
20     LocalAddr => "127.0.0.1", LocalPort => 0,
21     Proto => "tcp", Listen => 1,
22     ) or die "cannot allocate TCP test port: $!";
23     my $port = $socket->sockport;
24     close $socket;
25     $port
26     }
27    
28     sub start_child {
29     my ($use_env) = @_;
30     my $port = free_port;
31     local $ENV{PERL_ANYEVENT_MCP_MULTIBROKER_PROTOCOL} = $use_env ? "stdio" : "";
32     my $err = Symbol::gensym;
33     my $pid = IPC::Open3::open3 (my $in, my $out, $err,
34     $^X, "-Ilib", "bin/mcp-vim", "--host", "127.0.0.1",
35     "--port", "$port", ($use_env ? () : ("--stdio")));
36     my $old = select $in;
37     $| = 1;
38     select $old;
39     ($pid, $in, $out, $err, $port)
40     }
41    
42     sub rpc {
43     my ($in, $out, $id, $method, $params) = @_;
44     print {$in} JSON::XS::encode_json ({
45     jsonrpc => "2.0", id => $id, method => $method, params => $params,
46     }), "\n" or die "cannot send JSONL test request: $!";
47     return unless IO::Select->new ($out)->can_read (5);
48     my $line = <$out>;
49     return unless defined $line;
50     eval { JSON::XS::decode_json $line }
51     }
52    
53     sub wait_exit {
54     my ($pid) = @_;
55     for (1 .. 150) {
56     my $w = waitpid ($pid, WNOHANG);
57     return $? >> 8 if $w == $pid;
58     Time::HiRes::sleep (0.02);
59     }
60     kill TERM => $pid;
61     waitpid ($pid, 0);
62     -1
63     }
64    
65     for my $use_env (0, 1) {
66     my $kind = $use_env ? "multibroker environment" : "explicit --stdio";
67     my ($pid, $in, $out, $err, $port) = start_child ($use_env);
68    
69     my $init = rpc ($in, $out, 1, "initialize", {
70     protocolVersion => "2025-11-25",
71     capabilities => {}, clientInfo => { name => "stdio-test", version => "0" },
72     });
73    
74     is $init->{id}, 1, "$kind: JSONL initialize response";
75     ok !$init->{error} && $init->{result}{serverInfo},
76     "$kind: valid MCP server metadata";
77    
78     my $tools = rpc ($in, $out, 2, "tools/list", {});
79     is $tools->{id}, 2, "$kind: JSONL tools/list response";
80     ok !$tools->{error} && grep ($_->{name} eq "vim-targets", @{$tools->{result}{tools} || []}),
81     "$kind: exposes the shared Vim toolset";
82    
83     # The stdio transport must not prevent the normal Vim/browser TCP listener.
84     my $sock;
85     for (1 .. 25) {
86     $sock = IO::Socket::INET->new (
87     PeerAddr => "127.0.0.1", PeerPort => $port,
88     Proto => "tcp", Timeout => 1,
89     );
90     last if $sock;
91     Time::HiRes::sleep (0.02);
92     }
93     ok $sock, "$kind: TCP listener remains available";
94     if ($sock) {
95     $sock->autoflush (1);
96     print {$sock}
97     "POST / HTTP/1.1\r\nHost: localhost\r\n"
98     . "Content-Type: application/json\r\nContent-Length: 2\r\n\r\n{}";
99     my $response = IO::Select->new ($sock)->can_read (3) ? <$sock> : undef;
100     like $response, qr{\AHTTP/1\.1 401\b},
101     "$kind: TCP listener still serves authenticated MCP HTTP";
102     close $sock;
103     } else {
104     fail "$kind: HTTP listener response";
105     }
106    
107     close $in;
108     is wait_exit ($pid), 0, "$kind: stdin EOF stops the child cleanly";
109     my $extra = <$out>;
110     ok !defined $extra, "$kind: no extraneous stdout after final MCP response";
111     close $out;
112     close $err;
113     }
114    
115     done_testing;