diff --git a/ci/test.sh b/ci/test.sh index a918ed36..7890f2e3 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -11,8 +11,8 @@ flutter analyze echo "==> dart format (whole tree)" dart format --set-exit-if-changed . -echo "==> dart test (forkpty — incompatible with flutter test runner)" -dart test --tags forkpty test/pty/session_test.dart test/panes/registry_test.dart +echo "==> dart test (pty — unreliable under the flutter test runner)" +dart test --tags pty test/pty/session_test.dart test/panes/registry_test.dart echo "==> flutter test --coverage (unit + widget + golden)" -flutter test --coverage --exclude-tags forkpty +flutter test --coverage --exclude-tags pty diff --git a/dart_test.yaml b/dart_test.yaml index a86d63ae..df577599 100644 --- a/dart_test.yaml +++ b/dart_test.yaml @@ -3,8 +3,10 @@ # both honor them. Undeclared tags are ignored by the runners, which # silently breaks selective excludes. tags: - # Tests that call `forkpty()` via Dart FFI. Must run under `dart test`, - # not `flutter test` — the latter's runner hosts a multi-threaded - # Flutter engine in which forkpty produces a master fd that never - # delivers output. See `test/pty/session_test.dart`. - forkpty: + # Native-PTY tests (posix_openpt + posix_spawn via Dart FFI). Must run + # under `dart test`, not `flutter test`: the flutter-test runner hosts a + # multi-threaded engine in which the PTY master fd doesn't reliably + # deliver output, so these flake there (verified). They are reliable + # under `dart test`. (Tag was historically named `forkpty`, before + # T-96 replaced forkpty with posix_spawn.) See `test/pty/session_test.dart`. + pty: diff --git a/test/panes/registry_test.dart b/test/panes/registry_test.dart index 83a5a458..b6a46c70 100644 --- a/test/panes/registry_test.dart +++ b/test/panes/registry_test.dart @@ -1,7 +1,7 @@ /// Unit tests for [PaneRegistry]. /// /// Exercises spawn / list / write / resize / close against the real -/// NativePty (forkpty via FFI). Events are captured via +/// NativePty (posix_spawn via FFI). Events are captured via /// [RecordingEventSink]. library; @@ -41,7 +41,7 @@ void main() { expect(evt.data['id'], pane.id); }); - test('output events base64-encode the child bytes', tags: ['forkpty'], retry: 2, () async { + test('output events base64-encode the child bytes', tags: ['pty'], retry: 2, () async { // Subscribe to the sink stream BEFORE spawn so we don't miss // any pane.output events that arrive between spawn and listen. final buf = StringBuffer(); diff --git a/test/pty/env_test.dart b/test/pty/env_test.dart index c92bc8f6..c037b7aa 100644 --- a/test/pty/env_test.dart +++ b/test/pty/env_test.dart @@ -11,8 +11,8 @@ import 'package:test/test.dart'; void main() { group('PtyException', () { test('toString includes the op + message', () { - const e = PtyException('forkpty', 'kaboom'); - expect(e.toString(), contains('forkpty')); + const e = PtyException('posix_spawn', 'kaboom'); + expect(e.toString(), contains('posix_spawn')); expect(e.toString(), contains('kaboom')); expect(e.toString(), isNot(contains('errno='))); }); diff --git a/test/pty/session_test.dart b/test/pty/session_test.dart index 253328bb..80994a36 100644 --- a/test/pty/session_test.dart +++ b/test/pty/session_test.dart @@ -3,7 +3,7 @@ /// Exercises posix_spawn() end-to-end: spawn → child output through the /// reader isolate. Linux + macOS only; skipped elsewhere. /// -/// Per-test `tags: ['forkpty']` marks the tests that depend on the +/// Per-test `tags: ['pty']` marks the tests that depend on the /// reader isolate delivering output from the master fd — reads from a /// pty master under the flutter test runner are unstable when other /// suites run in parallel (intermittently empty). Only the @@ -24,7 +24,7 @@ void main() { if (!Platform.isLinux && !Platform.isMacOS) return; group('NativePty', () { - test('spawns shell -c echo and reads output', tags: ['forkpty'], retry: 2, () async { + test('spawns shell -c echo and reads output', tags: ['pty'], retry: 2, () async { final s = NativePty.start( executable: '/bin/sh', arguments: ['-c', 'echo hello-pty'], @@ -42,7 +42,7 @@ void main() { expect(got, contains('hello-pty')); }); - test('write sends keystrokes to child', tags: ['forkpty'], retry: 2, () async { + test('write sends keystrokes to child', tags: ['pty'], retry: 2, () async { final s = NativePty.start( executable: '/bin/sh', arguments: [], @@ -77,7 +77,7 @@ void main() { expect(result, contains('write-test-ok')); }); - test('close kills child and closes output', tags: ['forkpty'], retry: 2, () async { + test('close kills child and closes output', tags: ['pty'], retry: 2, () async { final s = NativePty.start( executable: '/bin/sh', arguments: [], @@ -101,7 +101,7 @@ void main() { expect(s.isClosed, isTrue); }); - test('bare command name resolves via the PATH env var', tags: ['forkpty'], retry: 2, () async { + test('bare command name resolves via the PATH env var', tags: ['pty'], retry: 2, () async { // 'sh' is a bare command; without resolution, execve would fail. final s = NativePty.start( executable: 'sh', @@ -163,7 +163,7 @@ void main() { test('start with a bare command name resolves it via PATH (no read)', () async { // Resolves "cat" to /bin/cat (or wherever it lives on PATH). // Doesn't read the master fd — that path is exercised by the - // forkpty-tagged version of this test under `dart test`. + // pty-tagged version of this test under `dart test`. final s = NativePty.start( executable: 'cat', arguments: const [],