@@ -197,6 +197,285 @@ void main() {
197
197
await client.shutdown ();
198
198
},
199
199
);
200
+
201
+ test.test ('launch_app tool fails when process exits early' , () async {
202
+ final mockProcessManager = MockProcessManager ();
203
+ mockProcessManager.addCommand (
204
+ Command (
205
+ [
206
+ Platform .isWindows
207
+ ? r'C:\path\to\flutter\sdk\bin\cache\dart-sdk\bin\dart.exe'
208
+ : '/path/to/flutter/sdk/bin/cache/dart-sdk/bin/dart' ,
209
+ 'language-server' ,
210
+ '--protocol' ,
211
+ 'lsp' ,
212
+ ],
213
+ stdout:
214
+ '''Content-Length: 145\r\n\r\n {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}},"workspaceSymbolProvider":true}}}''' ,
215
+ ),
216
+ );
217
+ mockProcessManager.addCommand (
218
+ Command (
219
+ [
220
+ Platform .isWindows
221
+ ? r'C:\path\to\flutter\sdk\bin\flutter.bat'
222
+ : '/path/to/flutter/sdk/bin/flutter' ,
223
+ 'run' ,
224
+ '--print-dtd' ,
225
+ '--device-id' ,
226
+ 'test-device' ,
227
+ ],
228
+ stderr: 'Something went wrong' ,
229
+ exitCode: Future .value (1 ),
230
+ ),
231
+ );
232
+ final serverAndClient = await createServerAndClient (
233
+ processManager: mockProcessManager,
234
+ fileSystem: fileSystem,
235
+ );
236
+ final server = serverAndClient.server;
237
+ final client = serverAndClient.client;
238
+
239
+ // Initialize
240
+ await client.initialize (
241
+ InitializeRequest (
242
+ protocolVersion: ProtocolVersion .latestSupported,
243
+ capabilities: ClientCapabilities (),
244
+ clientInfo: Implementation (name: 'test_client' , version: '1.0.0' ),
245
+ ),
246
+ );
247
+ client.notifyInitialized ();
248
+
249
+ // Call the tool
250
+ final result = await client.callTool (
251
+ CallToolRequest (
252
+ name: 'launch_app' ,
253
+ arguments: {'root' : projectRoot, 'device' : 'test-device' },
254
+ ),
255
+ );
256
+
257
+ test.expect (result.isError, true );
258
+ final textOutput = result.content as List <TextContent >;
259
+ test.expect (
260
+ textOutput.map ((context) => context.text).toList ().join ('\n ' ),
261
+ test.stringContainsInOrder ([
262
+ 'Flutter application exited with code 1 before the DTD URI was found' ,
263
+ 'with log output' ,
264
+ 'Something went wrong' ,
265
+ ]),
266
+ );
267
+ await server.shutdown ();
268
+ await client.shutdown ();
269
+ });
270
+
271
+ test.test ('stop_app tool stops a running app' , () async {
272
+ final dtdUri = 'ws://127.0.0.1:12345/abcdefg=' ;
273
+ final processPid = 54321 ;
274
+ final mockProcessManager = MockProcessManager ();
275
+ mockProcessManager.addCommand (
276
+ Command (
277
+ [
278
+ Platform .isWindows
279
+ ? r'C:\path\to\flutter\sdk\bin\cache\dart-sdk\bin\dart.exe'
280
+ : '/path/to/flutter/sdk/bin/cache/dart-sdk/bin/dart' ,
281
+ 'language-server' ,
282
+ '--protocol' ,
283
+ 'lsp' ,
284
+ ],
285
+ stdout:
286
+ '''Content-Length: 145\r\n\r\n {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}},"workspaceSymbolProvider":true}}}
287
+ ''' ,
288
+ ),
289
+ );
290
+ mockProcessManager.addCommand (
291
+ Command (
292
+ [
293
+ Platform .isWindows
294
+ ? r'C:\path\to\flutter\sdk\bin\flutter.bat'
295
+ : '/path/to/flutter/sdk/bin/flutter' ,
296
+ 'run' ,
297
+ '--print-dtd' ,
298
+ '--device-id' ,
299
+ 'test-device' ,
300
+ ],
301
+ stdout: 'The Dart Tooling Daemon is available at: $dtdUri \n ' ,
302
+ pid: processPid,
303
+ ),
304
+ );
305
+ final serverAndClient = await createServerAndClient (
306
+ processManager: mockProcessManager,
307
+ fileSystem: fileSystem,
308
+ );
309
+ final server = serverAndClient.server;
310
+ final client = serverAndClient.client;
311
+
312
+ // Initialize and launch the app
313
+ await client.initialize (
314
+ InitializeRequest (
315
+ protocolVersion: ProtocolVersion .latestSupported,
316
+ capabilities: ClientCapabilities (),
317
+ clientInfo: Implementation (name: 'test_client' , version: '1.0.0' ),
318
+ ),
319
+ );
320
+ client.notifyInitialized ();
321
+ await client.callTool (
322
+ CallToolRequest (
323
+ name: 'launch_app' ,
324
+ arguments: {'root' : projectRoot, 'device' : 'test-device' },
325
+ ),
326
+ );
327
+
328
+ // Stop the app
329
+ final result = await client.callTool (
330
+ CallToolRequest (name: 'stop_app' , arguments: {'pid' : processPid}),
331
+ );
332
+
333
+ test.expect (result.isError, test.isNot (true ));
334
+ test.expect (result.structuredContent, {'success' : true });
335
+ test.expect (mockProcessManager.killedPids, [processPid]);
336
+ await server.shutdown ();
337
+ await client.shutdown ();
338
+ });
339
+
340
+ test.test ('get_app_logs tool respects maxLines' , () async {
341
+ final dtdUri = 'ws://127.0.0.1:12345/abcdefg=' ;
342
+ final processPid = 54321 ;
343
+ final mockProcessManager = MockProcessManager ();
344
+ mockProcessManager.addCommand (
345
+ Command (
346
+ [
347
+ Platform .isWindows
348
+ ? r'C:\path\to\flutter\sdk\bin\cache\dart-sdk\bin\dart.exe'
349
+ : '/path/to/flutter/sdk/bin/cache/dart-sdk/bin/dart' ,
350
+ 'language-server' ,
351
+ '--protocol' ,
352
+ 'lsp' ,
353
+ ],
354
+ stdout:
355
+ '''Content-Length: 145\r\n\r\n {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}},"workspaceSymbolProvider":true}}}''' ,
356
+ ),
357
+ );
358
+ mockProcessManager.addCommand (
359
+ Command (
360
+ [
361
+ Platform .isWindows
362
+ ? r'C:\path\to\flutter\sdk\bin\flutter.bat'
363
+ : '/path/to/flutter/sdk/bin/flutter' ,
364
+ 'run' ,
365
+ '--print-dtd' ,
366
+ '--device-id' ,
367
+ 'test-device' ,
368
+ ],
369
+ stdout:
370
+ 'line 1\n line 2\n line 3\n '
371
+ 'The Dart Tooling Daemon is available at: $dtdUri \n ' ,
372
+ pid: processPid,
373
+ ),
374
+ );
375
+ final serverAndClient = await createServerAndClient (
376
+ processManager: mockProcessManager,
377
+ fileSystem: fileSystem,
378
+ );
379
+ final server = serverAndClient.server;
380
+ final client = serverAndClient.client;
381
+
382
+ // Initialize and launch the app
383
+ await client.initialize (
384
+ InitializeRequest (
385
+ protocolVersion: ProtocolVersion .latestSupported,
386
+ capabilities: ClientCapabilities (),
387
+ clientInfo: Implementation (name: 'test_client' , version: '1.0.0' ),
388
+ ),
389
+ );
390
+ client.notifyInitialized ();
391
+ await client.callTool (
392
+ CallToolRequest (
393
+ name: 'launch_app' ,
394
+ arguments: {'root' : projectRoot, 'device' : 'test-device' },
395
+ ),
396
+ );
397
+
398
+ // Get the logs
399
+ final result = await client.callTool (
400
+ CallToolRequest (
401
+ name: 'get_app_logs' ,
402
+ arguments: {'pid' : processPid, 'maxLines' : 2 },
403
+ ),
404
+ );
405
+
406
+ test.expect (result.isError, test.isNot (true ));
407
+ test.expect (result.structuredContent, {
408
+ 'logs' : [
409
+ '[skipping 2 log lines]...' ,
410
+ '[stdout] line 3' ,
411
+ '[stdout] The Dart Tooling Daemon is available at: ws://127.0.0.1:12345/abcdefg=' ,
412
+ ],
413
+ });
414
+ await server.shutdown ();
415
+ await client.shutdown ();
416
+ });
417
+
418
+ test.test ('list_devices tool returns available devices' , () async {
419
+ final mockProcessManager = MockProcessManager ();
420
+ mockProcessManager.addCommand (
421
+ Command (
422
+ [
423
+ Platform .isWindows
424
+ ? r'C:\path\to\flutter\sdk\bin\cache\dart-sdk\bin\dart.exe'
425
+ : '/path/to/flutter/sdk/bin/cache/dart-sdk/bin/dart' ,
426
+ 'language-server' ,
427
+ '--protocol' ,
428
+ 'lsp' ,
429
+ ],
430
+ stdout:
431
+ '''Content-Length: 145\r\n\r\n {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}},"workspaceSymbolProvider":true}}}
432
+ ''' ,
433
+ ),
434
+ );
435
+ mockProcessManager.addCommand (
436
+ Command (
437
+ [
438
+ Platform .isWindows
439
+ ? r'C:\path\to\flutter\sdk\bin\flutter.bat'
440
+ : '/path/to/flutter/sdk/bin/flutter' ,
441
+ 'devices' ,
442
+ '--machine' ,
443
+ ],
444
+ stdout: jsonEncode ([
445
+ {'id' : 'test-device-1' },
446
+ {'id' : 'test-device-2' },
447
+ ]),
448
+ ),
449
+ );
450
+ final serverAndClient = await createServerAndClient (
451
+ processManager: mockProcessManager,
452
+ fileSystem: fileSystem,
453
+ );
454
+ final server = serverAndClient.server;
455
+ final client = serverAndClient.client;
456
+
457
+ // Initialize
458
+ await client.initialize (
459
+ InitializeRequest (
460
+ protocolVersion: ProtocolVersion .latestSupported,
461
+ capabilities: ClientCapabilities (),
462
+ clientInfo: Implementation (name: 'test_client' , version: '1.0.0' ),
463
+ ),
464
+ );
465
+ client.notifyInitialized ();
466
+
467
+ // List devices
468
+ final result = await client.callTool (
469
+ CallToolRequest (name: 'list_devices' , arguments: {}),
470
+ );
471
+
472
+ test.expect (result.isError, test.isNot (true ));
473
+ test.expect (result.structuredContent, {
474
+ 'devices' : ['test-device-1' , 'test-device-2' ],
475
+ });
476
+ await server.shutdown ();
477
+ await client.shutdown ();
478
+ });
200
479
});
201
480
}
202
481
0 commit comments