refactor(protocol): isolate binary wire encoding (#228)
* refactor(protocol): isolate binary wire encoding * docs(architecture): record wire module ownership * docs(architecture): correct wire layer map
- commit
- f791584fd55cd239e4484d7ada11e6b587ec64ec
- author
- bnema · · 2026-08-28 13:03 UTC
- committer
- GitHub · · 2026-08-28 13:03 UTC
- parent
- b21386d
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
137 files · +1868 -1790
M AGENTS.md +4 -2
| @@ -37,7 +37,9 @@ Hexagonal boundaries are enforced by `boundary_test.go`. | |||||
| 37 | Layer map: | 37 | Layer map: | ||
| 38 | 38 | ||||
| 39 | - `main.go` → `internal/app`: CLI parsing, wiring, daemon startup, hidden subcommands. | 39 | - `main.go` → `internal/app`: CLI parsing, wiring, daemon startup, hidden subcommands. | ||
| 40 | - | - `internal/ports`: interfaces and wire protocol. | 40 | + | - `internal/ports`: application and raw carriage interfaces. |
| 41 | + | - `internal/protocol`: typed transport-neutral messages and negotiated session policy. | |||
| 42 | + | - `internal/protocol/wire`: message IDs, frames, strict binary codecs, compression, and encoded bounds. | |||
| 41 | - `internal/usecase/daemon`: sessions, tabs, panes, VT screens, renderer shadows, daemon features. | 43 | - `internal/usecase/daemon`: sessions, tabs, panes, VT screens, renderer shadows, daemon features. | ||
| 42 | - `internal/usecase/client`: raw-mode thin client; writes output bytes verbatim and interprets nothing. | 44 | - `internal/usecase/client`: raw-mode thin client; writes output bytes verbatim and interprets nothing. | ||
| 43 | - `internal/adapters`: IPC, SSH stdio, PTY, terminal, and clock implementations. | 45 | - `internal/adapters`: IPC, SSH stdio, PTY, terminal, and clock implementations. | ||
| @@ -61,7 +63,7 @@ Before touching daemon teardown paths, read the lock-ordering notes at the top o | |||||
| 61 | 63 | ||||
| 62 | ## Wire protocol | 64 | ## Wire protocol | ||
| 63 | 65 | ||||
| 64 | - | Semantic presentation, route, and session-control values live in `internal/protocol`. Frame IDs and codecs live in `internal/ports/frame.go`, `internal/ports/wire.go`, `internal/ports/routes_wire.go`, and `internal/ports/wire_command.go`. Connection framing lives in `internal/adapters/ipc/transport.go`. | 66 | + | Typed messages and negotiated version live in `internal/protocol`. Message IDs, frames, strict codecs, compression, and encoded bounds live in `internal/protocol/wire`; raw carriage interfaces remain in `internal/ports`. Connection framing lives in concrete carriage adapters such as `internal/adapters/ipc`. |
| 65 | 67 | ||||
| 66 | - IPC frames on a connection are 4-byte big-endian length, 1 type byte, then payload. | 68 | - IPC frames on a connection are 4-byte big-endian length, 1 type byte, then payload. | ||
| 67 | - Client message types occupy `1–13`, `15`, `32–33`, and `35` (`MsgParkedRouteRequest`); server types occupy `16–23`, `25–31`, `34`, and `36` (`MsgParkedRouteResponse`). Types `14` and `24` remain reserved. | 69 | - Client message types occupy `1–13`, `15`, `32–33`, and `35` (`MsgParkedRouteRequest`); server types occupy `16–23`, `25–31`, `34`, and `36` (`MsgParkedRouteResponse`). Types `14` and `24` remain reserved. | ||
M internal/adapters/dgram/control_plane_test.go +5 -4
| @@ -10,6 +10,7 @@ import ( | |||||
| 10 | "time" | 10 | "time" | ||
| 11 | 11 | ||||
| 12 | "github.com/bnema/vev/internal/ports" | 12 | "github.com/bnema/vev/internal/ports" | ||
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | pdgram "github.com/bnema/vev/pkg/dgram" | 14 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 14 | ) | 15 | ) | ||
| 15 | 16 | ||||
| @@ -81,7 +82,7 @@ func TestReadLoopDoesNotWriteACKSynchronously(t *testing.T) { | |||||
| 81 | a.diagnosticCh = make(chan Diagnostic, 1) | 82 | a.diagnosticCh = make(chan Diagnostic, 1) | ||
| 82 | a.mu.Unlock() | 83 | a.mu.Unlock() | ||
| 83 | 84 | ||||
| 84 | - | if err := b.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | 85 | + | if err := b.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { |
| 85 | t.Fatal(err) | 86 | t.Fatal(err) | ||
| 86 | } | 87 | } | ||
| 87 | awaitSignal(t, contacts, "first authenticated record") | 88 | awaitSignal(t, contacts, "first authenticated record") | ||
| @@ -92,7 +93,7 @@ func TestReadLoopDoesNotWriteACKSynchronously(t *testing.T) { | |||||
| 92 | awaitSignal(t, ackStarted, "blocked ACK") | 93 | awaitSignal(t, ackStarted, "blocked ACK") | ||
| 93 | 94 | ||||
| 94 | clk.advance(time.Second) | 95 | clk.advance(time.Second) | ||
| 95 | - | if err := b.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}); err != nil { | 96 | + | if err := b.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}); err != nil { |
| 96 | t.Fatal(err) | 97 | t.Fatal(err) | ||
| 97 | } | 98 | } | ||
| 98 | awaitSignal(t, contacts, "second authenticated record while ACK write is blocked") | 99 | awaitSignal(t, contacts, "second authenticated record while ACK write is blocked") | ||
| @@ -471,7 +472,7 @@ func TestHeartbeatContinuesDuringRetransmitStorm(t *testing.T) { | |||||
| 471 | a.mu.Lock() | 472 | a.mu.Lock() | ||
| 472 | for seq := uint64(1); seq <= 64; seq++ { | 473 | for seq := uint64(1); seq <= 64; seq++ { | ||
| 473 | a.pending[seq] = &pending{ | 474 | a.pending[seq] = &pending{ | ||
| 474 | - | frame: ports.Frame{Type: ports.MsgInput, Payload: make([]byte, 24*a.mtu)}, | 475 | + | frame: wire.Frame{Type: wire.MsgInput, Payload: make([]byte, 24*a.mtu)}, |
| 475 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | 476 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | ||
| 476 | } | 477 | } | ||
| 477 | } | 478 | } | ||
| @@ -515,7 +516,7 @@ func TestHealthChecksContinueDuringRetransmitStorm(t *testing.T) { | |||||
| 515 | now := clk.Now() | 516 | now := clk.Now() | ||
| 516 | a.mu.Lock() | 517 | a.mu.Lock() | ||
| 517 | a.pending[1] = &pending{ | 518 | a.pending[1] = &pending{ | ||
| 518 | - | frame: ports.Frame{Type: ports.MsgInput, Payload: make([]byte, 24*a.mtu)}, | 519 | + | frame: wire.Frame{Type: wire.MsgInput, Payload: make([]byte, 24*a.mtu)}, |
| 519 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | 520 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | ||
| 520 | } | 521 | } | ||
| 521 | a.mu.Unlock() | 522 | a.mu.Unlock() | ||
M internal/adapters/dgram/diagnostics_test.go +3 -2
| @@ -6,6 +6,7 @@ import ( | |||||
| 6 | "time" | 6 | "time" | ||
| 7 | 7 | ||||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 9 | ) | 10 | ) | ||
| 10 | 11 | ||||
| 11 | func TestDiagnosticSnapshotSeparatesProgressAges(t *testing.T) { | 12 | func TestDiagnosticSnapshotSeparatesProgressAges(t *testing.T) { | ||
| @@ -20,8 +21,8 @@ func TestDiagnosticSnapshotSeparatesProgressAges(t *testing.T) { | |||||
| 20 | retransmits: 64, | 21 | retransmits: 64, | ||
| 21 | reassemblyInflight: 2, | 22 | reassemblyInflight: 2, | ||
| 22 | pending: map[uint64]*pending{ | 23 | pending: map[uint64]*pending{ | ||
| 23 | - | 1: {frame: ports.Frame{Payload: make([]byte, 7)}}, | 24 | + | 1: {frame: wire.Frame{Payload: make([]byte, 7)}}, |
| 24 | - | 2: {frame: ports.Frame{Payload: make([]byte, 11)}}, | 25 | + | 2: {frame: wire.Frame{Payload: make([]byte, 11)}}, |
| 25 | }, | 26 | }, | ||
| 26 | diagnosticCh: make(chan Diagnostic, diagnosticBufferSize), | 27 | diagnosticCh: make(chan Diagnostic, diagnosticBufferSize), | ||
| 27 | done: make(chan struct{}), | 28 | done: make(chan struct{}), | ||
M internal/adapters/dgram/network_sim_test.go +7 -6
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | "github.com/bnema/vev/internal/domain" | 12 | "github.com/bnema/vev/internal/domain" | ||
| 13 | "github.com/bnema/vev/internal/ports" | 13 | "github.com/bnema/vev/internal/ports" | ||
| 14 | "github.com/bnema/vev/internal/protocol" | 14 | "github.com/bnema/vev/internal/protocol" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 15 | pdgram "github.com/bnema/vev/pkg/dgram" | 16 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 16 | ) | 17 | ) | ||
| 17 | 18 | ||||
| @@ -454,7 +455,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||||
| 454 | } | 455 | } | ||
| 455 | b.mu.Unlock() | 456 | b.mu.Unlock() | ||
| 456 | primer := mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("primer")}) | 457 | primer := mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("primer")}) | ||
| 457 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: primer}); err != nil { | 458 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: primer}); err != nil { |
| 458 | t.Fatal(err) | 459 | t.Fatal(err) | ||
| 459 | } | 460 | } | ||
| 460 | awaitSignal(t, primerWritten, "primer write") | 461 | awaitSignal(t, primerWritten, "primer write") | ||
| @@ -537,7 +538,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||||
| 537 | Size: domain.Size{Cols: 1, Rows: 1}, | 538 | Size: domain.Size{Cols: 1, Rows: 1}, | ||
| 538 | Data: bytes.Repeat([]byte{byte(state + 1)}, outputDataBytes), | 539 | Data: bytes.Repeat([]byte{byte(state + 1)}, outputDataBytes), | ||
| 539 | }) | 540 | }) | ||
| 540 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | 541 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: payload}); err != nil { |
| 541 | t.Fatal(err) | 542 | t.Fatal(err) | ||
| 542 | } | 543 | } | ||
| 543 | } | 544 | } | ||
| @@ -631,7 +632,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||||
| 631 | for { | 632 | for { | ||
| 632 | select { | 633 | select { | ||
| 633 | case frame := <-b.in: | 634 | case frame := <-b.in: | ||
| 634 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 635 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 635 | if err != nil { | 636 | if err != nil { | ||
| 636 | t.Fatal(err) | 637 | t.Fatal(err) | ||
| 637 | } | 638 | } | ||
| @@ -795,7 +796,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||||
| 795 | // A fresh record queues behind the sole data sender while control traffic | 796 | // A fresh record queues behind the sole data sender while control traffic | ||
| 796 | // remains independent of congestion tokens and the blocked data write. | 797 | // remains independent of congestion tokens and the blocked data write. | ||
| 797 | go func() { | 798 | go func() { | ||
| 798 | - | freshReturned <- a.Send(ports.Frame{Type: ports.MsgOutput, Payload: floodOutputPayload(floodRecordCount, 128)}) | 799 | + | freshReturned <- a.Send(wire.Frame{Type: wire.MsgOutput, Payload: floodOutputPayload(floodRecordCount, 128)}) |
| 799 | }() | 800 | }() | ||
| 800 | select { | 801 | select { | ||
| 801 | case err := <-freshReturned: | 802 | case err := <-freshReturned: | ||
| @@ -869,7 +870,7 @@ func TestFloodOutputPayloadIsIncrementalStateBearingOutput(t *testing.T) { | |||||
| 869 | const mtu = 128 | 870 | const mtu = 128 | ||
| 870 | for state := range floodRecordCount { | 871 | for state := range floodRecordCount { | ||
| 871 | payload := floodOutputPayload(state, mtu) | 872 | payload := floodOutputPayload(state, mtu) | ||
| 872 | - | output, err := ports.UnmarshalOutput(payload) | 873 | + | output, err := wire.UnmarshalOutput(payload) |
| 873 | if err != nil { | 874 | if err != nil { | ||
| 874 | t.Fatalf("state %d: %v", state, err) | 875 | t.Fatalf("state %d: %v", state, err) | ||
| 875 | } | 876 | } | ||
| @@ -889,7 +890,7 @@ func TestFloodOutputPayloadIsIncrementalStateBearingOutput(t *testing.T) { | |||||
| 889 | func sendFloodOutputs(t *testing.T, sender *Transport, count, mtu int) { | 890 | func sendFloodOutputs(t *testing.T, sender *Transport, count, mtu int) { | ||
| 890 | t.Helper() | 891 | t.Helper() | ||
| 891 | for state := range count { | 892 | for state := range count { | ||
| 892 | - | if err := sender.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: floodOutputPayload(state, mtu)}); err != nil { | 893 | + | if err := sender.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: floodOutputPayload(state, mtu)}); err != nil { |
| 893 | t.Fatal(err) | 894 | t.Fatal(err) | ||
| 894 | } | 895 | } | ||
| 895 | } | 896 | } | ||
M internal/adapters/dgram/output_pacer.go +4 -4
| @@ -1,11 +1,11 @@ | |||||
| 1 | package dgram | 1 | package dgram | ||
| 2 | 2 | ||||
| 3 | - | import "github.com/bnema/vev/internal/ports" | 3 | + | import "github.com/bnema/vev/internal/protocol/wire" |
| 4 | 4 | ||||
| 5 | type dataSendJob struct { | 5 | type dataSendJob struct { | ||
| 6 | seq uint64 | 6 | seq uint64 | ||
| 7 | reliable bool | 7 | reliable bool | ||
| 8 | - | frame ports.Frame | 8 | + | frame wire.Frame |
| 9 | done chan error | 9 | done chan error | ||
| 10 | } | 10 | } | ||
| 11 | 11 | ||||
| @@ -52,8 +52,8 @@ func (t *Transport) notifyOutputPacerLocked() { | |||||
| 52 | t.outputWake = make(chan struct{}) | 52 | t.outputWake = make(chan struct{}) | ||
| 53 | } | 53 | } | ||
| 54 | 54 | ||||
| 55 | - | func shouldPaceOutput(f ports.Frame) bool { | 55 | + | func shouldPaceOutput(f wire.Frame) bool { |
| 56 | - | return f.Type == ports.MsgOutput | 56 | + | return f.Type == wire.MsgOutput |
| 57 | } | 57 | } | ||
| 58 | 58 | ||||
| 59 | func (t *Transport) markPendingSent(seq uint64, reliable bool) { | 59 | func (t *Transport) markPendingSent(seq uint64, reliable bool) { | ||
M internal/adapters/dgram/proxy.go +6 -5
| @@ -8,6 +8,7 @@ import ( | |||||
| 8 | "time" | 8 | "time" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/ports" | 10 | "github.com/bnema/vev/internal/ports" | ||
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 11 | ) | 12 | ) | ||
| 12 | 13 | ||||
| 13 | const ( | 14 | const ( | ||
| @@ -50,7 +51,7 @@ type proxyCopyDirection struct { | |||||
| 50 | dst ports.Transport | 51 | dst ports.Transport | ||
| 51 | recvKind proxyCopyErrKind | 52 | recvKind proxyCopyErrKind | ||
| 52 | sendKind proxyCopyErrKind | 53 | sendKind proxyCopyErrKind | ||
| 53 | - | transform func(ports.Frame) ports.Frame | 54 | + | transform func(wire.Frame) wire.Frame |
| 54 | retryRecoverable bool | 55 | retryRecoverable bool | ||
| 55 | } | 56 | } | ||
| 56 | 57 | ||||
| @@ -211,15 +212,15 @@ func recoverableClientLink(t ports.Transport, err error) bool { | |||||
| 211 | // clampDatagramHelloOutputWindow enforces the datagram-safe state window at | 212 | // clampDatagramHelloOutputWindow enforces the datagram-safe state window at | ||
| 212 | // the adapter boundary. Invalid Hello payloads pass through unchanged so the | 213 | // the adapter boundary. Invalid Hello payloads pass through unchanged so the | ||
| 213 | // daemon remains the single authority for strict decoding and version checks. | 214 | // daemon remains the single authority for strict decoding and version checks. | ||
| 214 | - | func clampDatagramHelloOutputWindow(f ports.Frame) ports.Frame { | 215 | + | func clampDatagramHelloOutputWindow(f wire.Frame) wire.Frame { |
| 215 | - | if f.Type != ports.MsgHello { | 216 | + | if f.Type != wire.MsgHello { |
| 216 | return f | 217 | return f | ||
| 217 | } | 218 | } | ||
| 218 | - | hello, err := ports.UnmarshalHello(f.Payload) | 219 | + | hello, err := wire.UnmarshalHello(f.Payload) |
| 219 | if err != nil { | 220 | if err != nil { | ||
| 220 | return f | 221 | return f | ||
| 221 | } | 222 | } | ||
| 222 | hello.MaxOutputInFlight = 1 | 223 | hello.MaxOutputInFlight = 1 | ||
| 223 | - | f.Payload = ports.MarshalHello(hello) | 224 | + | f.Payload = wire.MarshalHello(hello) |
| 224 | return f | 225 | return f | ||
| 225 | } | 226 | } | ||
M internal/adapters/dgram/proxy_test.go +28 -27
| @@ -13,11 +13,12 @@ import ( | |||||
| 13 | "github.com/bnema/vev/internal/domain" | 13 | "github.com/bnema/vev/internal/domain" | ||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | "github.com/bnema/vev/internal/protocol" | 15 | "github.com/bnema/vev/internal/protocol" | ||
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | ) | 17 | ) | ||
| 17 | 18 | ||||
| 18 | type fakeTransport struct { | 19 | type fakeTransport struct { | ||
| 19 | recv chan recvResult | 20 | recv chan recvResult | ||
| 20 | - | sent chan ports.Frame | 21 | + | sent chan wire.Frame |
| 21 | sendErr chan error | 22 | sendErr chan error | ||
| 22 | linkState ports.LinkState | 23 | linkState ports.LinkState | ||
| 23 | linkEvents chan ports.LinkEvent | 24 | linkEvents chan ports.LinkEvent | ||
| @@ -26,14 +27,14 @@ type fakeTransport struct { | |||||
| 26 | } | 27 | } | ||
| 27 | 28 | ||||
| 28 | type recvResult struct { | 29 | type recvResult struct { | ||
| 29 | - | frame ports.Frame | 30 | + | frame wire.Frame |
| 30 | err error | 31 | err error | ||
| 31 | } | 32 | } | ||
| 32 | 33 | ||||
| 33 | func newFakeTransport() *fakeTransport { | 34 | func newFakeTransport() *fakeTransport { | ||
| 34 | - | return &fakeTransport{recv: make(chan recvResult, 4), sent: make(chan ports.Frame, 4), sendErr: make(chan error, 4), linkEvents: make(chan ports.LinkEvent, 4), linkState: ports.LinkStateConnected, closed: make(chan struct{})} | 35 | + | return &fakeTransport{recv: make(chan recvResult, 4), sent: make(chan wire.Frame, 4), sendErr: make(chan error, 4), linkEvents: make(chan ports.LinkEvent, 4), linkState: ports.LinkStateConnected, closed: make(chan struct{})} |
| 35 | } | 36 | } | ||
| 36 | - | func (f *fakeTransport) Send(fr ports.Frame) error { | 37 | + | func (f *fakeTransport) Send(fr wire.Frame) error { |
| 37 | select { | 38 | select { | ||
| 38 | case err := <-f.sendErr: | 39 | case err := <-f.sendErr: | ||
| 39 | return err | 40 | return err | ||
| @@ -42,12 +43,12 @@ func (f *fakeTransport) Send(fr ports.Frame) error { | |||||
| 42 | f.sent <- fr | 43 | f.sent <- fr | ||
| 43 | return nil | 44 | return nil | ||
| 44 | } | 45 | } | ||
| 45 | - | func (f *fakeTransport) Recv() (ports.Frame, error) { | 46 | + | func (f *fakeTransport) Recv() (wire.Frame, error) { |
| 46 | select { | 47 | select { | ||
| 47 | case r := <-f.recv: | 48 | case r := <-f.recv: | ||
| 48 | return r.frame, r.err | 49 | return r.frame, r.err | ||
| 49 | case <-f.closed: | 50 | case <-f.closed: | ||
| 50 | - | return ports.Frame{}, io.EOF | 51 | + | return wire.Frame{}, io.EOF |
| 51 | } | 52 | } | ||
| 52 | } | 53 | } | ||
| 53 | func (f *fakeTransport) Close() error { | 54 | func (f *fakeTransport) Close() error { | ||
| @@ -62,10 +63,10 @@ func TestProxyRuntimeCopiesFramesAndDaemonEOFIsTerminal(t *testing.T) { | |||||
| 62 | daemon := newFakeTransport() | 63 | daemon := newFakeTransport() | ||
| 63 | errCh := make(chan error, 1) | 64 | errCh := make(chan error, 1) | ||
| 64 | go func() { errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour}.Run(t.Context()) }() | 65 | go func() { errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour}.Run(t.Context()) }() | ||
| 65 | - | client.recv <- recvResult{frame: ports.Frame{Type: ports.MsgInput, Payload: []byte("x")}} | 66 | + | client.recv <- recvResult{frame: wire.Frame{Type: wire.MsgInput, Payload: []byte("x")}} |
| 66 | select { | 67 | select { | ||
| 67 | case got := <-daemon.sent: | 68 | case got := <-daemon.sent: | ||
| 68 | - | if got.Type != ports.MsgInput { | 69 | + | if got.Type != wire.MsgInput { |
| 69 | t.Fatalf("daemon got type %v", got.Type) | 70 | t.Fatalf("daemon got type %v", got.Type) | ||
| 70 | } | 71 | } | ||
| 71 | case <-time.After(time.Second): | 72 | case <-time.After(time.Second): | ||
| @@ -90,11 +91,11 @@ func TestProxyRuntimeClampsDatagramHelloOutputWindowAndPreservesControl(t *testi | |||||
| 90 | errCh := make(chan error, 1) | 91 | errCh := make(chan error, 1) | ||
| 91 | go func() { errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour}.Run(t.Context()) }() | 92 | go func() { errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour}.Run(t.Context()) }() | ||
| 92 | hello := protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: requested} | 93 | hello := protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: requested} | ||
| 93 | - | client.recv <- recvResult{frame: ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}} | 94 | + | client.recv <- recvResult{frame: wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}} |
| 94 | 95 | ||||
| 95 | select { | 96 | select { | ||
| 96 | case frame := <-daemon.sent: | 97 | case frame := <-daemon.sent: | ||
| 97 | - | got, err := ports.UnmarshalHello(frame.Payload) | 98 | + | got, err := wire.UnmarshalHello(frame.Payload) |
| 98 | if err != nil { | 99 | if err != nil { | ||
| 99 | t.Fatal(err) | 100 | t.Fatal(err) | ||
| 100 | } | 101 | } | ||
| @@ -105,11 +106,11 @@ func TestProxyRuntimeClampsDatagramHelloOutputWindowAndPreservesControl(t *testi | |||||
| 105 | t.Fatal("timeout waiting for proxied Hello") | 106 | t.Fatal("timeout waiting for proxied Hello") | ||
| 106 | } | 107 | } | ||
| 107 | 108 | ||||
| 108 | - | input := ports.Frame{Type: ports.MsgInput, Payload: []byte("still flowing")} | 109 | + | input := wire.Frame{Type: wire.MsgInput, Payload: []byte("still flowing")} |
| 109 | - | ack := ports.Frame{Type: ports.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 7})} | 110 | + | ack := wire.Frame{Type: wire.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 7})} |
| 110 | client.recv <- recvResult{frame: input} | 111 | client.recv <- recvResult{frame: input} | ||
| 111 | client.recv <- recvResult{frame: ack} | 112 | client.recv <- recvResult{frame: ack} | ||
| 112 | - | for _, want := range []ports.Frame{input, ack} { | 113 | + | for _, want := range []wire.Frame{input, ack} { |
| 113 | select { | 114 | select { | ||
| 114 | case got := <-daemon.sent: | 115 | case got := <-daemon.sent: | ||
| 115 | if !reflect.DeepEqual(got, want) { | 116 | if !reflect.DeepEqual(got, want) { | ||
| @@ -149,10 +150,10 @@ func TestProxyRuntimeRetriesRecoverableClientSendWithoutDroppingFrame(t *testing | |||||
| 149 | errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour, RetryBackoff: time.Nanosecond}.Run(t.Context()) | 150 | errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour, RetryBackoff: time.Nanosecond}.Run(t.Context()) | ||
| 150 | }() | 151 | }() | ||
| 151 | client.sendErr <- tt.err | 152 | client.sendErr <- tt.err | ||
| 152 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("preserved during outage")}} | 153 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("preserved during outage")}} |
| 153 | select { | 154 | select { | ||
| 154 | case got := <-client.sent: | 155 | case got := <-client.sent: | ||
| 155 | - | if got.Type != ports.MsgOutput || string(got.Payload) != "preserved during outage" { | 156 | + | if got.Type != wire.MsgOutput || string(got.Payload) != "preserved during outage" { |
| 156 | t.Fatalf("client got %+v, want retried output", got) | 157 | t.Fatalf("client got %+v, want retried output", got) | ||
| 157 | } | 158 | } | ||
| 158 | case <-time.After(time.Second): | 159 | case <-time.After(time.Second): | ||
| @@ -187,10 +188,10 @@ func TestProxyRuntimeSurvivesPendingFullAndPreservesOrder(t *testing.T) { | |||||
| 187 | const frames = 4 | 188 | const frames = 4 | ||
| 188 | for i := range frames { | 189 | for i := range frames { | ||
| 189 | client.sendErr <- ErrPendingFull | 190 | client.sendErr <- ErrPendingFull | ||
| 190 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}} | 191 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}} |
| 191 | select { | 192 | select { | ||
| 192 | case got := <-client.sent: | 193 | case got := <-client.sent: | ||
| 193 | - | if got.Type != ports.MsgOutput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { | 194 | + | if got.Type != wire.MsgOutput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { |
| 194 | t.Fatalf("frame %d delivered out of order or dropped: %+v", i, got) | 195 | t.Fatalf("frame %d delivered out of order or dropped: %+v", i, got) | ||
| 195 | } | 196 | } | ||
| 196 | case <-time.After(time.Second): | 197 | case <-time.After(time.Second): | ||
| @@ -378,7 +379,7 @@ func TestProxyRuntimeClientSendDeadWaitsForIdleTTL(t *testing.T) { | |||||
| 378 | }() | 379 | }() | ||
| 379 | 380 | ||||
| 380 | client.sendErr <- ErrLinkDead | 381 | client.sendErr <- ErrLinkDead | ||
| 381 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("client is gone")}} | 382 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("client is gone")}} |
| 382 | waitForProxyManualTimers(t, clk, 1) | 383 | waitForProxyManualTimers(t, clk, 1) | ||
| 383 | select { | 384 | select { | ||
| 384 | case err := <-errCh: | 385 | case err := <-errCh: | ||
| @@ -443,14 +444,14 @@ func newRetryingOfflineTransport() *retryingOfflineTransport { | |||||
| 443 | return &retryingOfflineTransport{closed: make(chan struct{}), firstSend: make(chan struct{})} | 444 | return &retryingOfflineTransport{closed: make(chan struct{}), firstSend: make(chan struct{})} | ||
| 444 | } | 445 | } | ||
| 445 | 446 | ||||
| 446 | - | func (t *retryingOfflineTransport) Send(ports.Frame) error { | 447 | + | func (t *retryingOfflineTransport) Send(wire.Frame) error { |
| 447 | t.firstSendOnce.Do(func() { close(t.firstSend) }) | 448 | t.firstSendOnce.Do(func() { close(t.firstSend) }) | ||
| 448 | return errors.New("offline") | 449 | return errors.New("offline") | ||
| 449 | } | 450 | } | ||
| 450 | 451 | ||||
| 451 | - | func (t *retryingOfflineTransport) Recv() (ports.Frame, error) { | 452 | + | func (t *retryingOfflineTransport) Recv() (wire.Frame, error) { |
| 452 | <-t.closed | 453 | <-t.closed | ||
| 453 | - | return ports.Frame{}, io.EOF | 454 | + | return wire.Frame{}, io.EOF |
| 454 | } | 455 | } | ||
| 455 | 456 | ||||
| 456 | func (t *retryingOfflineTransport) Close() error { | 457 | func (t *retryingOfflineTransport) Close() error { | ||
| @@ -474,7 +475,7 @@ func TestProxyCopierStopsRetryingWhenContextCanceled(t *testing.T) { | |||||
| 474 | close(done) | 475 | close(done) | ||
| 475 | }() | 476 | }() | ||
| 476 | 477 | ||||
| 477 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("retry until cancel")}} | 478 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("retry until cancel")}} |
| 478 | select { | 479 | select { | ||
| 479 | case <-client.firstSend: | 480 | case <-client.firstSend: | ||
| 480 | case <-time.After(time.Second): | 481 | case <-time.After(time.Second): | ||
| @@ -490,23 +491,23 @@ func TestProxyCopierStopsRetryingWhenContextCanceled(t *testing.T) { | |||||
| 490 | 491 | ||||
| 491 | func TestClampDatagramHelloOutputWindowPreservesProtocolValidation(t *testing.T) { | 492 | func TestClampDatagramHelloOutputWindowPreservesProtocolValidation(t *testing.T) { | ||
| 492 | t.Run("malformed payload remains malformed", func(t *testing.T) { | 493 | t.Run("malformed payload remains malformed", func(t *testing.T) { | ||
| 493 | - | payload := append(ports.MarshalHello(protocol.Hello{Version: protocol.Version, Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: 8}), 0xff) | 494 | + | payload := append(wire.MarshalHello(protocol.Hello{Version: protocol.Version, Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: 8}), 0xff) |
| 494 | - | frame := ports.Frame{Type: ports.MsgHello, Payload: payload} | 495 | + | frame := wire.Frame{Type: wire.MsgHello, Payload: payload} |
| 495 | got := clampDatagramHelloOutputWindow(frame) | 496 | got := clampDatagramHelloOutputWindow(frame) | ||
| 496 | if !reflect.DeepEqual(got, frame) { | 497 | if !reflect.DeepEqual(got, frame) { | ||
| 497 | t.Fatalf("malformed Hello changed: got %#v, want %#v", got, frame) | 498 | t.Fatalf("malformed Hello changed: got %#v, want %#v", got, frame) | ||
| 498 | } | 499 | } | ||
| 499 | - | if _, err := ports.UnmarshalHello(got.Payload); err == nil { | 500 | + | if _, err := wire.UnmarshalHello(got.Payload); err == nil { |
| 500 | t.Fatal("malformed Hello became decodable") | 501 | t.Fatal("malformed Hello became decodable") | ||
| 501 | } | 502 | } | ||
| 502 | }) | 503 | }) | ||
| 503 | 504 | ||||
| 504 | t.Run("mismatched version remains mismatched", func(t *testing.T) { | 505 | t.Run("mismatched version remains mismatched", func(t *testing.T) { | ||
| 505 | wantVersion := protocol.Version + 1 | 506 | wantVersion := protocol.Version + 1 | ||
| 506 | - | frame := ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | 507 | + | frame := wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ |
| 507 | Version: wantVersion, Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: 8, | 508 | Version: wantVersion, Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: 8, | ||
| 508 | })} | 509 | })} | ||
| 509 | - | got, err := ports.UnmarshalHello(clampDatagramHelloOutputWindow(frame).Payload) | 510 | + | got, err := wire.UnmarshalHello(clampDatagramHelloOutputWindow(frame).Payload) |
| 510 | if err != nil { | 511 | if err != nil { | ||
| 511 | t.Fatal(err) | 512 | t.Fatal(err) | ||
| 512 | } | 513 | } | ||
M internal/adapters/dgram/transport.go +5 -4
| @@ -9,6 +9,7 @@ import ( | |||||
| 9 | "time" | 9 | "time" | ||
| 10 | 10 | ||||
| 11 | "github.com/bnema/vev/internal/ports" | 11 | "github.com/bnema/vev/internal/ports" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | pdgram "github.com/bnema/vev/pkg/dgram" | 13 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 13 | ) | 14 | ) | ||
| 14 | 15 | ||||
| @@ -221,7 +222,7 @@ type Transport struct { | |||||
| 221 | recvMu sync.Mutex | 222 | recvMu sync.Mutex | ||
| 222 | replay *pdgram.ReplayWindow | 223 | replay *pdgram.ReplayWindow | ||
| 223 | reasm *pdgram.Reassembler | 224 | reasm *pdgram.Reassembler | ||
| 224 | - | in chan ports.Frame | 225 | + | in chan wire.Frame |
| 225 | done chan struct{} | 226 | done chan struct{} | ||
| 226 | 227 | ||||
| 227 | // Connection replacement takes writeMu, controlConnMu, then mu. Data writes | 228 | // Connection replacement takes writeMu, controlConnMu, then mu. Data writes | ||
| @@ -257,11 +258,11 @@ type Transport struct { | |||||
| 257 | deliverMu sync.Mutex | 258 | deliverMu sync.Mutex | ||
| 258 | deliverCond *sync.Cond | 259 | deliverCond *sync.Cond | ||
| 259 | nextRecvSeq uint64 | 260 | nextRecvSeq uint64 | ||
| 260 | - | recvBuf map[uint64]ports.Frame | 261 | + | recvBuf map[uint64]wire.Frame |
| 261 | } | 262 | } | ||
| 262 | 263 | ||||
| 263 | type pending struct { | 264 | type pending struct { | ||
| 264 | - | frame ports.Frame | 265 | + | frame wire.Frame |
| 265 | enqueued time.Time | 266 | enqueued time.Time | ||
| 266 | first time.Time | 267 | first time.Time | ||
| 267 | last time.Time | 268 | last time.Time | ||
| @@ -273,7 +274,7 @@ type pending struct { | |||||
| 273 | 274 | ||||
| 274 | type retransmitRecord struct { | 275 | type retransmitRecord struct { | ||
| 275 | seq uint64 | 276 | seq uint64 | ||
| 276 | - | f ports.Frame | 277 | + | f wire.Frame |
| 277 | } | 278 | } | ||
| 278 | 279 | ||||
| 279 | type writeDeadlineState struct { | 280 | type writeDeadlineState struct { | ||
M internal/adapters/dgram/transport_health_test.go +11 -10
| @@ -10,6 +10,7 @@ import ( | |||||
| 10 | "time" | 10 | "time" | ||
| 11 | 11 | ||||
| 12 | "github.com/bnema/vev/internal/ports" | 12 | "github.com/bnema/vev/internal/ports" | ||
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | pdgram "github.com/bnema/vev/pkg/dgram" | 14 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 14 | ) | 15 | ) | ||
| 15 | 16 | ||||
| @@ -32,7 +33,7 @@ func TestPortHopPreservesPendingReliableMessages(t *testing.T) { | |||||
| 32 | defer func() { _ = a.Close() }() | 33 | defer func() { _ = a.Close() }() | ||
| 33 | defer func() { _ = b.Close() }() | 34 | defer func() { _ = b.Close() }() | ||
| 34 | 35 | ||||
| 35 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("survive")}); err != nil { | 36 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("survive")}); err != nil { |
| 36 | t.Fatal(err) | 37 | t.Fatal(err) | ||
| 37 | } | 38 | } | ||
| 38 | a.mu.Lock() | 39 | a.mu.Lock() | ||
| @@ -44,7 +45,7 @@ func TestPortHopPreservesPendingReliableMessages(t *testing.T) { | |||||
| 44 | } | 45 | } | ||
| 45 | aPC.drop = nil | 46 | aPC.drop = nil | ||
| 46 | got := recvWithin(t, b, time.Second) | 47 | got := recvWithin(t, b, time.Second) | ||
| 47 | - | if got.Type != ports.MsgInput || string(got.Payload) != "survive" { | 48 | + | if got.Type != wire.MsgInput || string(got.Payload) != "survive" { |
| 48 | t.Fatalf("got=%+v, want pending reliable message", got) | 49 | t.Fatalf("got=%+v, want pending reliable message", got) | ||
| 49 | } | 50 | } | ||
| 50 | select { | 51 | select { | ||
| @@ -151,8 +152,8 @@ func TestRecvUnblocksWhenPeerDeadAfter(t *testing.T) { | |||||
| 151 | func TestPendingAttemptsResetWhenLinkRecovers(t *testing.T) { | 152 | func TestPendingAttemptsResetWhenLinkRecovers(t *testing.T) { | ||
| 152 | tr, _ := newResendTestTransport(t, 10) | 153 | tr, _ := newResendTestTransport(t, 10) | ||
| 153 | tr.linkState = ports.LinkStateDegraded | 154 | tr.linkState = ports.LinkStateDegraded | ||
| 154 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("stale")}, attempts: 4} | 155 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("stale")}, attempts: 4} |
| 155 | - | tr.pending[2] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("stale")}, attempts: 7} | 156 | + | tr.pending[2] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("stale")}, attempts: 7} |
| 156 | 157 | ||||
| 157 | tr.setLinkState(ports.LinkStateConnected, nil) | 158 | tr.setLinkState(ports.LinkStateConnected, nil) | ||
| 158 | 159 | ||||
| @@ -200,12 +201,12 @@ func TestPendingReliableQueueReturnsWhenLinkDegrades(t *testing.T) { | |||||
| 200 | defer func() { _ = a.Close() }() | 201 | defer func() { _ = a.Close() }() | ||
| 201 | defer func() { _ = b.Close() }() | 202 | defer func() { _ = b.Close() }() | ||
| 202 | 203 | ||||
| 203 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | 204 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { |
| 204 | t.Fatal(err) | 205 | t.Fatal(err) | ||
| 205 | } | 206 | } | ||
| 206 | done := make(chan error, 2) | 207 | done := make(chan error, 2) | ||
| 207 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}) }() | 208 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}) }() |
| 208 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("third")}) }() | 209 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("third")}) }() |
| 209 | waitForManualTimers(t, clk, 2) | 210 | waitForManualTimers(t, clk, 2) | ||
| 210 | a.setLinkState(ports.LinkStateDegraded, nil) | 211 | a.setLinkState(ports.LinkStateDegraded, nil) | ||
| 211 | for i := range 2 { | 212 | for i := range 2 { | ||
| @@ -313,7 +314,7 @@ func TestLinkHealthPendingStallWithFreshContactProbesOnceWithoutDying(t *testing | |||||
| 313 | now := time.Now() | 314 | now := time.Now() | ||
| 314 | a.mu.Lock() | 315 | a.mu.Lock() | ||
| 315 | a.health = healthTracker{lastPacket: now, lastRecord: now.Add(-time.Minute), lastProgress: now.Add(-time.Minute)} | 316 | a.health = healthTracker{lastPacket: now, lastRecord: now.Add(-time.Minute), lastProgress: now.Add(-time.Minute)} | ||
| 316 | - | a.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, enqueued: now.Add(-time.Minute), attempts: 3} | 317 | + | a.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, enqueued: now.Add(-time.Minute), attempts: 3} |
| 317 | a.mu.Unlock() | 318 | a.mu.Unlock() | ||
| 318 | 319 | ||||
| 319 | a.checkSilence() | 320 | a.checkSilence() | ||
| @@ -347,7 +348,7 @@ func TestLinkHealthHeartbeatControlCannotMaskPendingACKStall(t *testing.T) { | |||||
| 347 | } | 348 | } | ||
| 348 | defer func() { _ = tr.Close() }() | 349 | defer func() { _ = tr.Close() }() | ||
| 349 | defer func() { _ = bPC.Close() }() | 350 | defer func() { _ = bPC.Close() }() | ||
| 350 | - | if err := tr.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("unacked")}); err != nil { | 351 | + | if err := tr.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("unacked")}); err != nil { |
| 351 | t.Fatal(err) | 352 | t.Fatal(err) | ||
| 352 | } | 353 | } | ||
| 353 | 354 | ||||
| @@ -417,7 +418,7 @@ func TestLinkHealthOnlyAckProgressThatRemovesPendingRestoresConnected(t *testing | |||||
| 417 | now := tr.clock.Now() | 418 | now := tr.clock.Now() | ||
| 418 | tr.linkState = ports.LinkStateDegraded | 419 | tr.linkState = ports.LinkStateDegraded | ||
| 419 | tr.health = healthTracker{lastPacket: now, lastRecord: now.Add(-time.Minute), lastProgress: now.Add(-time.Minute)} | 420 | tr.health = healthTracker{lastPacket: now, lastRecord: now.Add(-time.Minute), lastProgress: now.Add(-time.Minute)} | ||
| 420 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: now, last: now} | 421 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: now, last: now} |
| 421 | 422 | ||||
| 422 | tr.handleRecord(ackRecord(1)) | 423 | tr.handleRecord(ackRecord(1)) | ||
| 423 | if got := tr.LinkState(); got != ports.LinkStateConnected { | 424 | if got := tr.LinkState(); got != ports.LinkStateConnected { | ||
M internal/adapters/dgram/transport_lifecycle.go +6 -5
| @@ -6,6 +6,7 @@ import ( | |||||
| 6 | "sync" | 6 | "sync" | ||
| 7 | 7 | ||||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 9 | pdgram "github.com/bnema/vev/pkg/dgram" | 10 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 10 | ) | 11 | ) | ||
| 11 | 12 | ||||
| @@ -29,7 +30,7 @@ func NewTransportWithOptions(pc net.PacketConn, peer net.Addr, key []byte, sendD | |||||
| 29 | pending: make(map[uint64]*pending), | 30 | pending: make(map[uint64]*pending), | ||
| 30 | replay: pdgram.NewReplayWindow(), | 31 | replay: pdgram.NewReplayWindow(), | ||
| 31 | reasm: pdgram.NewReassembler(), | 32 | reasm: pdgram.NewReassembler(), | ||
| 32 | - | in: make(chan ports.Frame, 32), | 33 | + | in: make(chan wire.Frame, 32), |
| 33 | done: make(chan struct{}), | 34 | done: make(chan struct{}), | ||
| 34 | health: newHealthTracker(opts.Clock.Now()), | 35 | health: newHealthTracker(opts.Clock.Now()), | ||
| 35 | lastAuthenticatedPacket: opts.Clock.Now(), | 36 | lastAuthenticatedPacket: opts.Clock.Now(), | ||
| @@ -56,7 +57,7 @@ func NewTransportWithOptions(pc net.PacketConn, peer net.Addr, key []byte, sendD | |||||
| 56 | probeWait: make(map[uint64]chan struct{}), | 57 | probeWait: make(map[uint64]chan struct{}), | ||
| 57 | rebind: opts.RebindPacketConn, | 58 | rebind: opts.RebindPacketConn, | ||
| 58 | nextRecvSeq: 1, | 59 | nextRecvSeq: 1, | ||
| 59 | - | recvBuf: make(map[uint64]ports.Frame), | 60 | + | recvBuf: make(map[uint64]wire.Frame), |
| 60 | } | 61 | } | ||
| 61 | for _, opt := range runtimeOpts { | 62 | for _, opt := range runtimeOpts { | ||
| 62 | if opt != nil { | 63 | if opt != nil { | ||
| @@ -90,7 +91,7 @@ func NewTransportWithOptions(pc net.PacketConn, peer net.Addr, key []byte, sendD | |||||
| 90 | return t, nil | 91 | return t, nil | ||
| 91 | } | 92 | } | ||
| 92 | 93 | ||||
| 93 | - | func (t *Transport) Recv() (ports.Frame, error) { | 94 | + | func (t *Transport) Recv() (wire.Frame, error) { |
| 94 | end := t.beginRuntimeOperation(ports.RuntimeAdapterReceiveStart, 0) | 95 | end := t.beginRuntimeOperation(ports.RuntimeAdapterReceiveStart, 0) | ||
| 95 | select { | 96 | select { | ||
| 96 | case f := <-t.in: | 97 | case f := <-t.in: | ||
| @@ -102,11 +103,11 @@ func (t *Transport) Recv() (ports.Frame, error) { | |||||
| 102 | t.mu.Unlock() | 103 | t.mu.Unlock() | ||
| 103 | if err != nil { | 104 | if err != nil { | ||
| 104 | end(false) | 105 | end(false) | ||
| 105 | - | return ports.Frame{}, err | 106 | + | return wire.Frame{}, err |
| 106 | } | 107 | } | ||
| 107 | err = errors.New("dgram: closed") | 108 | err = errors.New("dgram: closed") | ||
| 108 | end(false) | 109 | end(false) | ||
| 109 | - | return ports.Frame{}, err | 110 | + | return wire.Frame{}, err |
| 110 | } | 111 | } | ||
| 111 | } | 112 | } | ||
| 112 | 113 | ||||
M internal/adapters/dgram/transport_observability_test.go +4 -3
| @@ -13,6 +13,7 @@ import ( | |||||
| 13 | 13 | ||||
| 14 | "github.com/bnema/vev/internal/adapters/observability" | 14 | "github.com/bnema/vev/internal/adapters/observability" | ||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | ) | 17 | ) | ||
| 17 | 18 | ||||
| 18 | func TestTransportObservabilityDgramFailedCloseEndsReceiveAndSend(t *testing.T) { | 19 | func TestTransportObservabilityDgramFailedCloseEndsReceiveAndSend(t *testing.T) { | ||
| @@ -33,7 +34,7 @@ func TestTransportObservabilityDgramFailedCloseEndsReceiveAndSend(t *testing.T) | |||||
| 33 | if err != nil { | 34 | if err != nil { | ||
| 34 | t.Fatalf("NewTransportWithOptions() error = %v", err) | 35 | t.Fatalf("NewTransportWithOptions() error = %v", err) | ||
| 35 | } | 36 | } | ||
| 36 | - | if err := transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("write failure")}); err == nil { | 37 | + | if err := transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("write failure")}); err == nil { |
| 37 | t.Fatal("Send() error = nil on packet write failure") | 38 | t.Fatal("Send() error = nil on packet write failure") | ||
| 38 | } | 39 | } | ||
| 39 | recvDone := make(chan error, 1) | 40 | recvDone := make(chan error, 1) | ||
| @@ -155,11 +156,11 @@ func TestTransportObservabilityDgramKeepsBehaviorClockSeparate(t *testing.T) { | |||||
| 155 | } | 156 | } | ||
| 156 | defer func() { _ = b.Close() }() | 157 | defer func() { _ = b.Close() }() | ||
| 157 | 158 | ||||
| 158 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: []byte("datagram carriage remains exact")} | 159 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: []byte("datagram carriage remains exact")} |
| 159 | if err := a.Send(want); err != nil { | 160 | if err := a.Send(want); err != nil { | ||
| 160 | t.Fatalf("Send() error = %v", err) | 161 | t.Fatalf("Send() error = %v", err) | ||
| 161 | } | 162 | } | ||
| 162 | - | gotCh := make(chan ports.Frame, 1) | 163 | + | gotCh := make(chan wire.Frame, 1) |
| 163 | errCh := make(chan error, 1) | 164 | errCh := make(chan error, 1) | ||
| 164 | go func() { | 165 | go func() { | ||
| 165 | frame, recvErr := b.Recv() | 166 | frame, recvErr := b.Recv() | ||
M internal/adapters/dgram/transport_receive.go +8 -7
| @@ -5,6 +5,7 @@ import ( | |||||
| 5 | "net" | 5 | "net" | ||
| 6 | 6 | ||||
| 7 | "github.com/bnema/vev/internal/ports" | 7 | "github.com/bnema/vev/internal/ports" | ||
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 8 | pdgram "github.com/bnema/vev/pkg/dgram" | 9 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 9 | ) | 10 | ) | ||
| 10 | 11 | ||||
| @@ -176,7 +177,7 @@ func (t *Transport) handleRecord(p []byte) { | |||||
| 176 | } | 177 | } | ||
| 177 | } | 178 | } | ||
| 178 | 179 | ||||
| 179 | - | func (t *Transport) enqueueReliable(seq uint64, f ports.Frame) (ackSeq uint64, ack bool, queued bool) { | 180 | + | func (t *Transport) enqueueReliable(seq uint64, f wire.Frame) (ackSeq uint64, ack bool, queued bool) { |
| 180 | t.deliverMu.Lock() | 181 | t.deliverMu.Lock() | ||
| 181 | defer t.deliverMu.Unlock() | 182 | defer t.deliverMu.Unlock() | ||
| 182 | if seq < t.nextRecvSeq { | 183 | if seq < t.nextRecvSeq { | ||
| @@ -235,14 +236,14 @@ func (t *Transport) isClosed() bool { | |||||
| 235 | return t.closed | 236 | return t.closed | ||
| 236 | } | 237 | } | ||
| 237 | 238 | ||||
| 238 | - | func (t *Transport) deliver(f ports.Frame) { | 239 | + | func (t *Transport) deliver(f wire.Frame) { |
| 239 | select { | 240 | select { | ||
| 240 | case t.in <- f: | 241 | case t.in <- f: | ||
| 241 | case <-t.done: | 242 | case <-t.done: | ||
| 242 | } | 243 | } | ||
| 243 | } | 244 | } | ||
| 244 | 245 | ||||
| 245 | - | func encodeData(seq uint64, reliable bool, f ports.Frame) []byte { | 246 | + | func encodeData(seq uint64, reliable bool, f wire.Frame) []byte { |
| 246 | b := make([]byte, dataRecordHeaderSize+len(f.Payload)) | 247 | b := make([]byte, dataRecordHeaderSize+len(f.Payload)) | ||
| 247 | b[0] = recData | 248 | b[0] = recData | ||
| 248 | binary.BigEndian.PutUint64(b[1:9], seq) | 249 | binary.BigEndian.PutUint64(b[1:9], seq) | ||
| @@ -253,12 +254,12 @@ func encodeData(seq uint64, reliable bool, f ports.Frame) []byte { | |||||
| 253 | copy(b[dataRecordHeaderSize:], f.Payload) | 254 | copy(b[dataRecordHeaderSize:], f.Payload) | ||
| 254 | return b | 255 | return b | ||
| 255 | } | 256 | } | ||
| 256 | - | func decodeData(b []byte) (uint64, bool, ports.Frame, bool) { | 257 | + | func decodeData(b []byte) (uint64, bool, wire.Frame, bool) { |
| 257 | if len(b) < dataRecordHeaderSize || b[0] != recData { | 258 | if len(b) < dataRecordHeaderSize || b[0] != recData { | ||
| 258 | - | return 0, false, ports.Frame{}, false | 259 | + | return 0, false, wire.Frame{}, false |
| 259 | } | 260 | } | ||
| 260 | if b[11] != 0 { | 261 | if b[11] != 0 { | ||
| 261 | - | return 0, false, ports.Frame{}, false | 262 | + | return 0, false, wire.Frame{}, false |
| 262 | } | 263 | } | ||
| 263 | - | return binary.BigEndian.Uint64(b[1:9]), b[9] == 1, ports.Frame{Type: ports.MsgType(b[10]), Payload: append([]byte(nil), b[dataRecordHeaderSize:]...)}, true | 264 | + | return binary.BigEndian.Uint64(b[1:9]), b[9] == 1, wire.Frame{Type: wire.MsgType(b[10]), Payload: append([]byte(nil), b[dataRecordHeaderSize:]...)}, true |
| 264 | } | 265 | } | ||
M internal/adapters/dgram/transport_receive_test.go +18 -17
| @@ -8,6 +8,7 @@ import ( | |||||
| 8 | "time" | 8 | "time" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/ports" | 10 | "github.com/bnema/vev/internal/ports" | ||
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 11 | pdgram "github.com/bnema/vev/pkg/dgram" | 12 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 12 | ) | 13 | ) | ||
| 13 | 14 | ||||
| @@ -35,11 +36,11 @@ func TestReliableDuplicateAckedButNotDeliveredTwice(t *testing.T) { | |||||
| 35 | t.Errorf("close b: %v", err) | 36 | t.Errorf("close b: %v", err) | ||
| 36 | } | 37 | } | ||
| 37 | }() | 38 | }() | ||
| 38 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}); err != nil { | 39 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}); err != nil { |
| 39 | t.Fatal(err) | 40 | t.Fatal(err) | ||
| 40 | } | 41 | } | ||
| 41 | got := recvWithin(t, b, time.Second) | 42 | got := recvWithin(t, b, time.Second) | ||
| 42 | - | if got.Type != ports.MsgInput || string(got.Payload) != "typed" { | 43 | + | if got.Type != wire.MsgInput || string(got.Payload) != "typed" { |
| 43 | t.Fatalf("got=%+v", got) | 44 | t.Fatalf("got=%+v", got) | ||
| 44 | } | 45 | } | ||
| 45 | eventually(t, time.Second, droppedAck.Load) | 46 | eventually(t, time.Second, droppedAck.Load) | ||
| @@ -70,7 +71,7 @@ func TestAuthenticatedPeerChangeUpdatesPeerAndEmitsConnected(t *testing.T) { | |||||
| 70 | t.Fatalf("unauthenticated packet changed peer to %v", a.Peer()) | 71 | t.Fatalf("unauthenticated packet changed peer to %v", a.Peer()) | ||
| 71 | } | 72 | } | ||
| 72 | c, _ := pdgram.NewCodec(key()) | 73 | c, _ := pdgram.NewCodec(key()) | ||
| 73 | - | rec := encodeData(7, true, ports.Frame{Type: ports.MsgPing}) | 74 | + | rec := encodeData(7, true, wire.Frame{Type: wire.MsgPing}) |
| 74 | frags, _ := pdgram.FragmentPayload(9, rec, pdgram.DefaultMTU) | 75 | frags, _ := pdgram.FragmentPayload(9, rec, pdgram.DefaultMTU) | ||
| 75 | raw, _ := pdgram.MarshalFragment(frags[0]) | 76 | raw, _ := pdgram.MarshalFragment(frags[0]) | ||
| 76 | aPC.in <- packet{c.Seal(2, 99, raw, nil), testAddr("evil")} | 77 | aPC.in <- packet{c.Seal(2, 99, raw, nil), testAddr("evil")} | ||
| @@ -214,12 +215,12 @@ func TestAuthenticatedFragmentSeparatesContactProgressAndPeerEligibility(t *test | |||||
| 214 | } | 215 | } | ||
| 215 | 216 | ||||
| 216 | func TestReliableReceiveBufferDoesNotDropAckedFutureFrame(t *testing.T) { | 217 | func TestReliableReceiveBufferDoesNotDropAckedFutureFrame(t *testing.T) { | ||
| 217 | - | tr := &Transport{maxRecvBuffer: 1, nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame)} | 218 | + | tr := &Transport{maxRecvBuffer: 1, nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame)} |
| 218 | - | _, ack, queued := tr.enqueueReliable(2, ports.Frame{Type: ports.MsgOutput, Payload: []byte("future")}) | 219 | + | _, ack, queued := tr.enqueueReliable(2, wire.Frame{Type: wire.MsgOutput, Payload: []byte("future")}) |
| 219 | if !ack || !queued { | 220 | if !ack || !queued { | ||
| 220 | t.Fatalf("future enqueue ack=%v queued=%v, want true/true", ack, queued) | 221 | t.Fatalf("future enqueue ack=%v queued=%v, want true/true", ack, queued) | ||
| 221 | } | 222 | } | ||
| 222 | - | _, ack, queued = tr.enqueueReliable(1, ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")}) | 223 | + | _, ack, queued = tr.enqueueReliable(1, wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")}) |
| 223 | if !ack || !queued { | 224 | if !ack || !queued { | ||
| 224 | t.Fatalf("next enqueue ack=%v queued=%v, want true/true", ack, queued) | 225 | t.Fatalf("next enqueue ack=%v queued=%v, want true/true", ack, queued) | ||
| 225 | } | 226 | } | ||
| @@ -229,19 +230,19 @@ func TestReliableReceiveBufferDoesNotDropAckedFutureFrame(t *testing.T) { | |||||
| 229 | } | 230 | } | ||
| 230 | 231 | ||||
| 231 | func TestDataRecordWireEncoding(t *testing.T) { | 232 | func TestDataRecordWireEncoding(t *testing.T) { | ||
| 232 | - | got := encodeData(5, true, ports.Frame{Type: ports.MsgOutput, Payload: []byte("x")}) | 233 | + | got := encodeData(5, true, wire.Frame{Type: wire.MsgOutput, Payload: []byte("x")}) |
| 233 | - | want := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(ports.MsgOutput), 0, 'x'} | 234 | + | want := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(wire.MsgOutput), 0, 'x'} |
| 234 | if !bytes.Equal(got, want) { | 235 | if !bytes.Equal(got, want) { | ||
| 235 | t.Fatalf("encoded data=%v, want %v", got, want) | 236 | t.Fatalf("encoded data=%v, want %v", got, want) | ||
| 236 | } | 237 | } | ||
| 237 | seq, reliable, frame, ok := decodeData(got) | 238 | seq, reliable, frame, ok := decodeData(got) | ||
| 238 | - | if !ok || seq != 5 || !reliable || frame.Type != ports.MsgOutput || string(frame.Payload) != "x" { | 239 | + | if !ok || seq != 5 || !reliable || frame.Type != wire.MsgOutput || string(frame.Payload) != "x" { |
| 239 | t.Fatalf("decoded seq=%d reliable=%v frame=%+v ok=%v", seq, reliable, frame, ok) | 240 | t.Fatalf("decoded seq=%d reliable=%v frame=%+v ok=%v", seq, reliable, frame, ok) | ||
| 240 | } | 241 | } | ||
| 241 | } | 242 | } | ||
| 242 | 243 | ||||
| 243 | func TestDataRecordWireDecodeRejectsUnknownFlags(t *testing.T) { | 244 | func TestDataRecordWireDecodeRejectsUnknownFlags(t *testing.T) { | ||
| 244 | - | withTrailingGarbage := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(ports.MsgOutput), 1, 'x'} | 245 | + | withTrailingGarbage := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(wire.MsgOutput), 1, 'x'} |
| 245 | if _, _, _, ok := decodeData(withTrailingGarbage); ok { | 246 | if _, _, _, ok := decodeData(withTrailingGarbage); ok { | ||
| 246 | t.Fatal("decodeData accepted unknown data-record flags with trailing garbage") | 247 | t.Fatal("decodeData accepted unknown data-record flags with trailing garbage") | ||
| 247 | } | 248 | } | ||
| @@ -255,13 +256,13 @@ func TestReliableDeliveryPreservesInputSequenceOrder(t *testing.T) { | |||||
| 255 | defer func() { _ = b.Close() }() | 256 | defer func() { _ = b.Close() }() | ||
| 256 | 257 | ||||
| 257 | for i := range 100 { | 258 | for i := range 100 { | ||
| 258 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte{byte(i)}}); err != nil { | 259 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte{byte(i)}}); err != nil { |
| 259 | t.Fatal(err) | 260 | t.Fatal(err) | ||
| 260 | } | 261 | } | ||
| 261 | } | 262 | } | ||
| 262 | for i := range 100 { | 263 | for i := range 100 { | ||
| 263 | got := recvWithin(t, b, time.Second) | 264 | got := recvWithin(t, b, time.Second) | ||
| 264 | - | if got.Type != ports.MsgInput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { | 265 | + | if got.Type != wire.MsgInput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { |
| 265 | t.Fatalf("frame %d delivered out of order: %+v", i, got) | 266 | t.Fatalf("frame %d delivered out of order: %+v", i, got) | ||
| 266 | } | 267 | } | ||
| 267 | } | 268 | } | ||
| @@ -275,7 +276,7 @@ func TestAckProcessingContinuesWhenConsumerBackpressured(t *testing.T) { | |||||
| 275 | defer func() { _ = b.Close() }() | 276 | defer func() { _ = b.Close() }() | ||
| 276 | 277 | ||||
| 277 | for i := range cap(b.in) + 20 { | 278 | for i := range cap(b.in) + 20 { | ||
| 278 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | 279 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}); err != nil { |
| 279 | t.Fatal(err) | 280 | t.Fatal(err) | ||
| 280 | } | 281 | } | ||
| 281 | } | 282 | } | ||
| @@ -296,9 +297,9 @@ func TestAckProcessingContinuesWhenConsumerBackpressured(t *testing.T) { | |||||
| 296 | } | 297 | } | ||
| 297 | 298 | ||||
| 298 | func TestReliableReceiverAcksOnlyHighestContiguousSequence(t *testing.T) { | 299 | func TestReliableReceiverAcksOnlyHighestContiguousSequence(t *testing.T) { | ||
| 299 | - | tr := &Transport{maxRecvBuffer: maxRecvBuffer, nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame)} | 300 | + | tr := &Transport{maxRecvBuffer: maxRecvBuffer, nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame)} |
| 300 | 301 | ||||
| 301 | - | ackSeq, ack, queued := tr.enqueueReliable(3, ports.Frame{Type: ports.MsgOutput, Payload: []byte("third")}) | 302 | + | ackSeq, ack, queued := tr.enqueueReliable(3, wire.Frame{Type: wire.MsgOutput, Payload: []byte("third")}) |
| 302 | if !ack || !queued { | 303 | if !ack || !queued { | ||
| 303 | t.Fatalf("out-of-order enqueue ack=%v queued=%v, want true/true", ack, queued) | 304 | t.Fatalf("out-of-order enqueue ack=%v queued=%v, want true/true", ack, queued) | ||
| 304 | } | 305 | } | ||
| @@ -306,7 +307,7 @@ func TestReliableReceiverAcksOnlyHighestContiguousSequence(t *testing.T) { | |||||
| 306 | t.Fatalf("out-of-order ack=%d, want highest contiguous %d", got, want) | 307 | t.Fatalf("out-of-order ack=%d, want highest contiguous %d", got, want) | ||
| 307 | } | 308 | } | ||
| 308 | 309 | ||||
| 309 | - | ackSeq, ack, queued = tr.enqueueReliable(1, ports.Frame{Type: ports.MsgOutput, Payload: []byte("first")}) | 310 | + | ackSeq, ack, queued = tr.enqueueReliable(1, wire.Frame{Type: wire.MsgOutput, Payload: []byte("first")}) |
| 310 | if !ack || !queued { | 311 | if !ack || !queued { | ||
| 311 | t.Fatalf("first enqueue ack=%v queued=%v, want true/true", ack, queued) | 312 | t.Fatalf("first enqueue ack=%v queued=%v, want true/true", ack, queued) | ||
| 312 | } | 313 | } | ||
| @@ -314,7 +315,7 @@ func TestReliableReceiverAcksOnlyHighestContiguousSequence(t *testing.T) { | |||||
| 314 | t.Fatalf("first contiguous ack=%d, want %d", got, want) | 315 | t.Fatalf("first contiguous ack=%d, want %d", got, want) | ||
| 315 | } | 316 | } | ||
| 316 | 317 | ||||
| 317 | - | ackSeq, ack, queued = tr.enqueueReliable(2, ports.Frame{Type: ports.MsgOutput, Payload: []byte("second")}) | 318 | + | ackSeq, ack, queued = tr.enqueueReliable(2, wire.Frame{Type: wire.MsgOutput, Payload: []byte("second")}) |
| 318 | if !ack || !queued { | 319 | if !ack || !queued { | ||
| 319 | t.Fatalf("gap fill enqueue ack=%v queued=%v, want true/true", ack, queued) | 320 | t.Fatalf("gap fill enqueue ack=%v queued=%v, want true/true", ack, queued) | ||
| 320 | } | 321 | } | ||
M internal/adapters/dgram/transport_replay_test.go +3 -3
| @@ -3,13 +3,13 @@ package dgram | |||||
| 3 | import ( | 3 | import ( | ||
| 4 | "testing" | 4 | "testing" | ||
| 5 | 5 | ||||
| 6 | - | "github.com/bnema/vev/internal/ports" | 6 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 7 | "github.com/bnema/vev/internal/testutil/replaytest" | 7 | "github.com/bnema/vev/internal/testutil/replaytest" | ||
| 8 | "github.com/stretchr/testify/require" | 8 | "github.com/stretchr/testify/require" | ||
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| 11 | func TestTransportReplay(t *testing.T) { | 11 | func TestTransportReplay(t *testing.T) { | ||
| 12 | - | replaytest.Run(t, func(t *testing.T, frames []ports.Frame) []ports.Frame { | 12 | + | replaytest.Run(t, func(t *testing.T, frames []wire.Frame) []wire.Frame { |
| 13 | link := newSimulatedLink(fixedClock{}, packetPolicy{}) | 13 | link := newSimulatedLink(fixedClock{}, packetPolicy{}) | ||
| 14 | leftPC, rightPC := newPairWithCapacity(link, 32) | 14 | leftPC, rightPC := newPairWithCapacity(link, 32) | ||
| 15 | left, err := NewTransport(leftPC, testAddr("b"), key(), 1, 2) | 15 | left, err := NewTransport(leftPC, testAddr("b"), key(), 1, 2) | ||
| @@ -18,7 +18,7 @@ func TestTransportReplay(t *testing.T) { | |||||
| 18 | require.NoError(t, err) | 18 | require.NoError(t, err) | ||
| 19 | t.Cleanup(func() { _ = left.Close(); _ = right.Close() }) | 19 | t.Cleanup(func() { _ = left.Close(); _ = right.Close() }) | ||
| 20 | 20 | ||||
| 21 | - | got := make([]ports.Frame, 0, len(frames)) | 21 | + | got := make([]wire.Frame, 0, len(frames)) |
| 22 | for _, frame := range frames { | 22 | for _, frame := range frames { | ||
| 23 | require.NoError(t, left.Send(frame)) | 23 | require.NoError(t, left.Send(frame)) | ||
| 24 | link.flush(rightPC) | 24 | link.flush(rightPC) | ||
M internal/adapters/dgram/transport_retransmit_test.go +21 -20
| @@ -7,11 +7,12 @@ import ( | |||||
| 7 | "time" | 7 | "time" | ||
| 8 | 8 | ||||
| 9 | "github.com/bnema/vev/internal/ports" | 9 | "github.com/bnema/vev/internal/ports" | ||
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 10 | ) | 11 | ) | ||
| 11 | 12 | ||||
| 12 | func TestResendSkipsQueuedOutputBeforeFirstWireAttempt(t *testing.T) { | 13 | func TestResendSkipsQueuedOutputBeforeFirstWireAttempt(t *testing.T) { | ||
| 13 | tr, writes := newResendTestTransport(t, 10) | 14 | tr, writes := newResendTestTransport(t, 10) | ||
| 14 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued")}} | 15 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued")}} |
| 15 | 16 | ||||
| 16 | tr.resendPending() | 17 | tr.resendPending() | ||
| 17 | 18 | ||||
| @@ -27,7 +28,7 @@ func TestResendSkipsOutputDuringFirstWireAttempt(t *testing.T) { | |||||
| 27 | tr, writes := newResendTestTransport(t, 10) | 28 | tr, writes := newResendTestTransport(t, 10) | ||
| 28 | now := tr.clock.Now() | 29 | now := tr.clock.Now() | ||
| 29 | tr.pending[1] = &pending{ | 30 | tr.pending[1] = &pending{ | ||
| 30 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("sending")}, | 31 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("sending")}, |
| 31 | first: now.Add(-time.Second), | 32 | first: now.Add(-time.Second), | ||
| 32 | last: now.Add(-time.Second), | 33 | last: now.Add(-time.Second), | ||
| 33 | initialInFlight: true, | 34 | initialInFlight: true, | ||
| @@ -68,11 +69,11 @@ func TestReliableInputRetransmitsUntilAck(t *testing.T) { | |||||
| 68 | t.Errorf("close b: %v", err) | 69 | t.Errorf("close b: %v", err) | ||
| 69 | } | 70 | } | ||
| 70 | }() | 71 | }() | ||
| 71 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}); err != nil { | 72 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}); err != nil { |
| 72 | t.Fatal(err) | 73 | t.Fatal(err) | ||
| 73 | } | 74 | } | ||
| 74 | got := recvWithin(t, b, time.Second) | 75 | got := recvWithin(t, b, time.Second) | ||
| 75 | - | if got.Type != ports.MsgInput || string(got.Payload) != "typed" || !dropped.Load() { | 76 | + | if got.Type != wire.MsgInput || string(got.Payload) != "typed" || !dropped.Load() { |
| 76 | t.Fatalf("got=%+v dropped=%v", got, dropped.Load()) | 77 | t.Fatalf("got=%+v dropped=%v", got, dropped.Load()) | ||
| 77 | } | 78 | } | ||
| 78 | } | 79 | } | ||
| @@ -95,11 +96,11 @@ func TestOutputRetransmitsUntilAck(t *testing.T) { | |||||
| 95 | t.Errorf("close b: %v", err) | 96 | t.Errorf("close b: %v", err) | ||
| 96 | } | 97 | } | ||
| 97 | }() | 98 | }() | ||
| 98 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("state1")}); err != nil { | 99 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("state1")}); err != nil { |
| 99 | t.Fatal(err) | 100 | t.Fatal(err) | ||
| 100 | } | 101 | } | ||
| 101 | got := recvWithin(t, b, time.Second) | 102 | got := recvWithin(t, b, time.Second) | ||
| 102 | - | if got.Type != ports.MsgOutput || string(got.Payload) != "state1" || !dropped.Load() { | 103 | + | if got.Type != wire.MsgOutput || string(got.Payload) != "state1" || !dropped.Load() { |
| 103 | t.Fatalf("got=%+v dropped=%v", got, dropped.Load()) | 104 | t.Fatalf("got=%+v dropped=%v", got, dropped.Load()) | ||
| 104 | } | 105 | } | ||
| 105 | } | 106 | } | ||
| @@ -124,7 +125,7 @@ func TestImmediateLoopbackAckSamplesStampedFinalWrite(t *testing.T) { | |||||
| 124 | t.Error("ACK did not retire pending frame before WriteTo returned") | 125 | t.Error("ACK did not retire pending frame before WriteTo returned") | ||
| 125 | } | 126 | } | ||
| 126 | 127 | ||||
| 127 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("state")}); err != nil { | 128 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("state")}); err != nil { |
| 128 | t.Fatal(err) | 129 | t.Fatal(err) | ||
| 129 | } | 130 | } | ||
| 130 | eventually(t, time.Second, func() bool { | 131 | eventually(t, time.Second, func() bool { | ||
| @@ -155,14 +156,14 @@ func TestOutputDependencyChainRetransmitsDroppedPredecessors(t *testing.T) { | |||||
| 155 | defer func() { _ = b.Close() }() | 156 | defer func() { _ = b.Close() }() | ||
| 156 | 157 | ||||
| 157 | for _, payload := range []string{"state1", "state2", "state3"} { | 158 | for _, payload := range []string{"state1", "state2", "state3"} { | ||
| 158 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte(payload)}); err != nil { | 159 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte(payload)}); err != nil { |
| 159 | t.Fatal(err) | 160 | t.Fatal(err) | ||
| 160 | } | 161 | } | ||
| 161 | } | 162 | } | ||
| 162 | 163 | ||||
| 163 | for _, want := range []string{"state1", "state2", "state3"} { | 164 | for _, want := range []string{"state1", "state2", "state3"} { | ||
| 164 | got := recvWithin(t, b, time.Second) | 165 | got := recvWithin(t, b, time.Second) | ||
| 165 | - | if got.Type != ports.MsgOutput || string(got.Payload) != want { | 166 | + | if got.Type != wire.MsgOutput || string(got.Payload) != want { |
| 166 | t.Fatalf("got=%+v, want ordered prerequisite output %q", got, want) | 167 | t.Fatalf("got=%+v, want ordered prerequisite output %q", got, want) | ||
| 167 | } | 168 | } | ||
| 168 | } | 169 | } | ||
| @@ -175,7 +176,7 @@ func TestResendPendingCapsBurst(t *testing.T) { | |||||
| 175 | tr, writes := newResendTestTransport(t, 2) | 176 | tr, writes := newResendTestTransport(t, 2) | ||
| 176 | now := tr.clock.Now() | 177 | now := tr.clock.Now() | ||
| 177 | for i := range 5 { | 178 | for i := range 5 { | ||
| 178 | - | tr.pending[uint64(i+1)] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}, last: now.Add(-time.Second)} | 179 | + | tr.pending[uint64(i+1)] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}, last: now.Add(-time.Second)} |
| 179 | } | 180 | } | ||
| 180 | 181 | ||||
| 181 | tr.resendPending() | 182 | tr.resendPending() | ||
| @@ -189,7 +190,7 @@ func TestRetransmitBatchReducesCongestionWindowOnce(t *testing.T) { | |||||
| 189 | now := tr.clock.Now() | 190 | now := tr.clock.Now() | ||
| 190 | for seq := uint64(1); seq <= 3; seq++ { | 191 | for seq := uint64(1); seq <= 3; seq++ { | ||
| 191 | tr.pending[seq] = &pending{ | 192 | tr.pending[seq] = &pending{ | ||
| 192 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(seq)}}, | 193 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(seq)}}, |
| 193 | last: now.Add(-time.Second), | 194 | last: now.Add(-time.Second), | ||
| 194 | } | 195 | } | ||
| 195 | } | 196 | } | ||
| @@ -209,7 +210,7 @@ func TestACKBeforeQueuedRetransmitDoesNotReduceCongestionWindow(t *testing.T) { | |||||
| 209 | tr, writes := newResendTestTransport(t, 1) | 210 | tr, writes := newResendTestTransport(t, 1) | ||
| 210 | now := tr.clock.Now() | 211 | now := tr.clock.Now() | ||
| 211 | tr.pending[1] = &pending{ | 212 | tr.pending[1] = &pending{ | ||
| 212 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("acked")}, | 213 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("acked")}, |
| 213 | first: now.Add(-time.Second), | 214 | first: now.Add(-time.Second), | ||
| 214 | last: now.Add(-time.Second), | 215 | last: now.Add(-time.Second), | ||
| 215 | wireBytes: tr.mtu, | 216 | wireBytes: tr.mtu, | ||
| @@ -244,7 +245,7 @@ func TestOversizedRetransmitHonorsPacketBudget(t *testing.T) { | |||||
| 244 | tr.clock = clk | 245 | tr.clock = clk | ||
| 245 | tr.done = make(chan struct{}) | 246 | tr.done = make(chan struct{}) | ||
| 246 | tr.pending[1] = &pending{ | 247 | tr.pending[1] = &pending{ | ||
| 247 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 24*tr.mtu)}, | 248 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 24*tr.mtu)}, |
| 248 | last: clk.now.Add(-time.Second), | 249 | last: clk.now.Add(-time.Second), | ||
| 249 | } | 250 | } | ||
| 250 | done := make(chan struct{}) | 251 | done := make(chan struct{}) | ||
| @@ -274,9 +275,9 @@ func TestOversizedRetransmitHonorsPacketBudget(t *testing.T) { | |||||
| 274 | func TestResendPendingUsesExponentialBackoffAndMaxDelay(t *testing.T) { | 275 | func TestResendPendingUsesExponentialBackoffAndMaxDelay(t *testing.T) { | ||
| 275 | tr, writes := newResendTestTransport(t, 10) | 276 | tr, writes := newResendTestTransport(t, 10) | ||
| 276 | now := tr.clock.Now() | 277 | now := tr.clock.Now() | ||
| 277 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("too-soon")}, last: now.Add(-150 * time.Millisecond), attempts: 1} | 278 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("too-soon")}, last: now.Add(-150 * time.Millisecond), attempts: 1} |
| 278 | - | tr.pending[2] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("ready")}, last: now.Add(-250 * time.Millisecond), attempts: 1} | 279 | + | tr.pending[2] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("ready")}, last: now.Add(-250 * time.Millisecond), attempts: 1} |
| 279 | - | tr.pending[3] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("capped")}, last: now.Add(-time.Second), attempts: 10} | 280 | + | tr.pending[3] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("capped")}, last: now.Add(-time.Second), attempts: 10} |
| 280 | 281 | ||||
| 281 | tr.resendPending() | 282 | tr.resendPending() | ||
| 282 | if got := writes.Load(); got != 2 { | 283 | if got := writes.Load(); got != 2 { | ||
| @@ -297,7 +298,7 @@ func TestCumulativeAckReleasesAllEarlierPendingFrames(t *testing.T) { | |||||
| 297 | tr, _ := newResendTestTransport(t, 10) | 298 | tr, _ := newResendTestTransport(t, 10) | ||
| 298 | now := tr.clock.Now() | 299 | now := tr.clock.Now() | ||
| 299 | for seq := uint64(1); seq <= 3; seq++ { | 300 | for seq := uint64(1); seq <= 3; seq++ { | ||
| 300 | - | tr.pending[seq] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(seq)}}, first: now, last: now} | 301 | + | tr.pending[seq] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(seq)}}, first: now, last: now} |
| 301 | } | 302 | } | ||
| 302 | 303 | ||||
| 303 | tr.handleRecord(ackRecord(3)) | 304 | tr.handleRecord(ackRecord(3)) | ||
| @@ -314,14 +315,14 @@ func TestRTTEstimatorUpdatesRTOFromAckSample(t *testing.T) { | |||||
| 314 | tr.resendAfter = 100 * time.Millisecond | 315 | tr.resendAfter = 100 * time.Millisecond | ||
| 315 | tr.maxResendAfter = time.Second | 316 | tr.maxResendAfter = time.Second | ||
| 316 | tr.rto = tr.resendAfter | 317 | tr.rto = tr.resendAfter | ||
| 317 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-200 * time.Millisecond)} | 318 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-200 * time.Millisecond)} |
| 318 | 319 | ||||
| 319 | tr.handleRecord(ackRecord(1)) | 320 | tr.handleRecord(ackRecord(1)) | ||
| 320 | 321 | ||||
| 321 | if tr.rto <= tr.resendAfter { | 322 | if tr.rto <= tr.resendAfter { | ||
| 322 | t.Fatalf("rto=%v, want above initial resend after RTT sample", tr.rto) | 323 | t.Fatalf("rto=%v, want above initial resend after RTT sample", tr.rto) | ||
| 323 | } | 324 | } | ||
| 324 | - | tr.pending[2] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: clk.now, last: clk.now.Add(-(tr.rto - time.Millisecond))} | 325 | + | tr.pending[2] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: clk.now, last: clk.now.Add(-(tr.rto - time.Millisecond))} |
| 325 | tr.resendPending() | 326 | tr.resendPending() | ||
| 326 | if got := writes.Load(); got != 0 { | 327 | if got := writes.Load(); got != 0 { | ||
| 327 | t.Fatalf("writes before rto=%d, want 0", got) | 328 | t.Fatalf("writes before rto=%d, want 0", got) | ||
| @@ -340,7 +341,7 @@ func TestRTTEstimatorIgnoresRetransmittedFramesAfterRecovery(t *testing.T) { | |||||
| 340 | tr.resendAfter = 100 * time.Millisecond | 341 | tr.resendAfter = 100 * time.Millisecond | ||
| 341 | tr.maxResendAfter = time.Second | 342 | tr.maxResendAfter = time.Second | ||
| 342 | tr.rto = tr.resendAfter | 343 | tr.rto = tr.resendAfter | ||
| 343 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-tr.resendAfter)} | 344 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-tr.resendAfter)} |
| 344 | tr.resendPending() | 345 | tr.resendPending() | ||
| 345 | tr.linkState = ports.LinkStateOffline | 346 | tr.linkState = ports.LinkStateOffline | ||
| 346 | 347 | ||||
M internal/adapters/dgram/transport_send.go +5 -4
| @@ -6,16 +6,17 @@ import ( | |||||
| 6 | "time" | 6 | "time" | ||
| 7 | 7 | ||||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 9 | ) | 10 | ) | ||
| 10 | 11 | ||||
| 11 | - | func (t *Transport) Send(f ports.Frame) error { | 12 | + | func (t *Transport) Send(f wire.Frame) error { |
| 12 | end := t.beginRuntimeOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | 13 | end := t.beginRuntimeOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | ||
| 13 | err := t.send(f, false) | 14 | err := t.send(f, false) | ||
| 14 | end(err == nil) | 15 | end(err == nil) | ||
| 15 | return err | 16 | return err | ||
| 16 | } | 17 | } | ||
| 17 | 18 | ||||
| 18 | - | func (t *Transport) SendAsync(f ports.Frame) error { | 19 | + | func (t *Transport) SendAsync(f wire.Frame) error { |
| 19 | end := t.beginRuntimeOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | 20 | end := t.beginRuntimeOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | ||
| 20 | err := t.send(f, true) | 21 | err := t.send(f, true) | ||
| 21 | end(err == nil) | 22 | end(err == nil) | ||
| @@ -24,9 +25,9 @@ func (t *Transport) SendAsync(f ports.Frame) error { | |||||
| 24 | 25 | ||||
| 25 | // SendSynchronous owns queue reservation, fragment pacing, per-write deadlines, | 26 | // SendSynchronous owns queue reservation, fragment pacing, per-write deadlines, | ||
| 26 | // and close cancellation. Callers must not layer a shorter preflight timer over it. | 27 | // and close cancellation. Callers must not layer a shorter preflight timer over it. | ||
| 27 | - | func (t *Transport) SendSynchronous(f ports.Frame) error { return t.Send(f) } | 28 | + | func (t *Transport) SendSynchronous(f wire.Frame) error { return t.Send(f) } |
| 28 | 29 | ||||
| 29 | - | func (t *Transport) send(f ports.Frame, async bool) error { | 30 | + | func (t *Transport) send(f wire.Frame, async bool) error { |
| 30 | reliable := true | 31 | reliable := true | ||
| 31 | if err := t.lockOutboundSlot(reliable); err != nil { | 32 | if err := t.lockOutboundSlot(reliable); err != nil { | ||
| 32 | return err | 33 | return err | ||
M internal/adapters/dgram/transport_send_test.go +31 -31
| @@ -8,8 +8,8 @@ import ( | |||||
| 8 | "time" | 8 | "time" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | - | "github.com/bnema/vev/internal/ports" | |||
| 12 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | pdgram "github.com/bnema/vev/pkg/dgram" | 13 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 14 | "github.com/stretchr/testify/require" | 14 | "github.com/stretchr/testify/require" | ||
| 15 | ) | 15 | ) | ||
| @@ -26,7 +26,7 @@ func TestPendingWireBytesMatchSealedDatagrams(t *testing.T) { | |||||
| 26 | defer func() { _ = a.Close() }() | 26 | defer func() { _ = a.Close() }() | ||
| 27 | 27 | ||||
| 28 | maxFragmentData := mtu - pdgram.HeaderSize - a.codec.Overhead() - 16 | 28 | maxFragmentData := mtu - pdgram.HeaderSize - a.codec.Overhead() - 16 | ||
| 29 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, maxFragmentData-dataRecordHeaderSize+1)} | 29 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, maxFragmentData-dataRecordHeaderSize+1)} |
| 30 | if err := a.Send(frame); err != nil { | 30 | if err := a.Send(frame); err != nil { | ||
| 31 | t.Fatal(err) | 31 | t.Fatal(err) | ||
| 32 | } | 32 | } | ||
| @@ -69,7 +69,7 @@ func TestSendAsyncTransfersFragmentedRecordToBytePacedSender(t *testing.T) { | |||||
| 69 | defer func() { _ = a.Close() }() | 69 | defer func() { _ = a.Close() }() | ||
| 70 | 70 | ||||
| 71 | maxFragmentData := mtu - pdgram.HeaderSize - a.codec.Overhead() | 71 | maxFragmentData := mtu - pdgram.HeaderSize - a.codec.Overhead() | ||
| 72 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 2*maxFragmentData)} | 72 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 2*maxFragmentData)} |
| 73 | if err := a.SendAsync(frame); err != nil { | 73 | if err := a.SendAsync(frame); err != nil { | ||
| 74 | t.Fatal(err) | 74 | t.Fatal(err) | ||
| 75 | } | 75 | } | ||
| @@ -92,12 +92,12 @@ func TestSmallOutputsShareInitialByteBurst(t *testing.T) { | |||||
| 92 | defer func() { _ = a.Close() }() | 92 | defer func() { _ = a.Close() }() | ||
| 93 | 93 | ||||
| 94 | for i := range 3 { | 94 | for i := range 3 { | ||
| 95 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | 95 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}); err != nil { |
| 96 | t.Fatal(err) | 96 | t.Fatal(err) | ||
| 97 | } | 97 | } | ||
| 98 | } | 98 | } | ||
| 99 | eventuallyPacketCount(t, bPC, 3) | 99 | eventuallyPacketCount(t, bPC, 3) | ||
| 100 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")}); err != nil { | 100 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")}); err != nil { |
| 101 | t.Fatal(err) | 101 | t.Fatal(err) | ||
| 102 | } | 102 | } | ||
| 103 | eventuallyPacketCount(t, bPC, 4) | 103 | eventuallyPacketCount(t, bPC, 4) | ||
| @@ -112,12 +112,12 @@ func TestOutputPacingSendsAtMostOneOversizedFramePerTick(t *testing.T) { | |||||
| 112 | } | 112 | } | ||
| 113 | defer func() { _ = a.Close() }() | 113 | defer func() { _ = a.Close() }() | ||
| 114 | 114 | ||||
| 115 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("prime")}); err != nil { | 115 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("prime")}); err != nil { |
| 116 | t.Fatal(err) | 116 | t.Fatal(err) | ||
| 117 | } | 117 | } | ||
| 118 | large := mustMarshalOutput(protocol.Output{Epoch: 1, Base: 1, New: 2, Size: domain.Size{Cols: 1, Rows: 1}, Data: make([]byte, 24*a.mtu)}) | 118 | large := mustMarshalOutput(protocol.Output{Epoch: 1, Base: 1, New: 2, Size: domain.Size{Cols: 1, Rows: 1}, Data: make([]byte, 24*a.mtu)}) | ||
| 119 | for range 2 { | 119 | for range 2 { | ||
| 120 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: large}); err != nil { | 120 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: large}); err != nil { |
| 121 | t.Fatal(err) | 121 | t.Fatal(err) | ||
| 122 | } | 122 | } | ||
| 123 | } | 123 | } | ||
| @@ -152,7 +152,7 @@ func TestPacedInitialSendTimestampsFinalFragmentCompletion(t *testing.T) { | |||||
| 152 | t.Fatal(err) | 152 | t.Fatal(err) | ||
| 153 | } | 153 | } | ||
| 154 | defer func() { _ = a.Close() }() | 154 | defer func() { _ = a.Close() }() | ||
| 155 | - | large := ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 24*a.mtu)} | 155 | + | large := wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 24*a.mtu)} |
| 156 | done := make(chan error, 1) | 156 | done := make(chan error, 1) | ||
| 157 | go func() { done <- a.Send(large) }() | 157 | go func() { done <- a.Send(large) }() | ||
| 158 | start := clk.Now() | 158 | start := clk.Now() | ||
| @@ -209,7 +209,7 @@ func TestOwnedSynchronousMaxSideEffectCompletesThroughConcurrentPacedWork(t *tes | |||||
| 209 | a.srtt = 500 * time.Millisecond | 209 | a.srtt = 500 * time.Millisecond | ||
| 210 | a.mu.Unlock() | 210 | a.mu.Unlock() | ||
| 211 | for i := range 8 { | 211 | for i := range 8 { | ||
| 212 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | 212 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}); err != nil { |
| 213 | t.Fatal(err) | 213 | t.Fatal(err) | ||
| 214 | } | 214 | } | ||
| 215 | } | 215 | } | ||
| @@ -217,13 +217,13 @@ func TestOwnedSynchronousMaxSideEffectCompletesThroughConcurrentPacedWork(t *tes | |||||
| 217 | a.mu.Lock() | 217 | a.mu.Lock() | ||
| 218 | for _, seq := range []uint64{100, 101} { | 218 | for _, seq := range []uint64{100, 101} { | ||
| 219 | a.pending[seq] = &pending{ | 219 | a.pending[seq] = &pending{ | ||
| 220 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 20*a.mtu)}, | 220 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 20*a.mtu)}, |
| 221 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | 221 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | ||
| 222 | } | 222 | } | ||
| 223 | } | 223 | } | ||
| 224 | a.mu.Unlock() | 224 | a.mu.Unlock() | ||
| 225 | go a.resendPending() | 225 | go a.resendPending() | ||
| 226 | - | sideEffect := ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: make([]byte, 100*1024)})} | 226 | + | sideEffect := wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: make([]byte, 100*1024)})} |
| 227 | done := make(chan error, 1) | 227 | done := make(chan error, 1) | ||
| 228 | go func() { done <- a.SendSynchronous(sideEffect) }() | 228 | go func() { done <- a.SendSynchronous(sideEffect) }() | ||
| 229 | 229 | ||||
| @@ -256,12 +256,12 @@ func TestInputWaitsForDequeuedOutputBatch(t *testing.T) { | |||||
| 256 | 256 | ||||
| 257 | a.writeMu.Lock() | 257 | a.writeMu.Lock() | ||
| 258 | for _, payload := range []string{"first", "queued"} { | 258 | for _, payload := range []string{"first", "queued"} { | ||
| 259 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte(payload)}); err != nil { | 259 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte(payload)}); err != nil { |
| 260 | t.Fatal(err) | 260 | t.Fatal(err) | ||
| 261 | } | 261 | } | ||
| 262 | } | 262 | } | ||
| 263 | done := make(chan error, 1) | 263 | done := make(chan error, 1) | ||
| 264 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}) }() | 264 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}) }() |
| 265 | select { | 265 | select { | ||
| 266 | case err := <-done: | 266 | case err := <-done: | ||
| 267 | a.writeMu.Unlock() | 267 | a.writeMu.Unlock() | ||
| @@ -295,7 +295,7 @@ func TestPacedControlQueueFailureClosesTransport(t *testing.T) { | |||||
| 295 | t.Fatal(err) | 295 | t.Fatal(err) | ||
| 296 | } | 296 | } | ||
| 297 | inputDone := make(chan error, 1) | 297 | inputDone := make(chan error, 1) | ||
| 298 | - | go func() { inputDone <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}) }() | 298 | + | go func() { inputDone <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}) }() |
| 299 | if err := <-inputDone; err == nil { | 299 | if err := <-inputDone; err == nil { | ||
| 300 | t.Fatal("data send succeeded after paced wire failure") | 300 | t.Fatal("data send succeeded after paced wire failure") | ||
| 301 | } | 301 | } | ||
| @@ -328,10 +328,10 @@ func TestRemoveQueuedPendingResolvesSynchronousWaiters(t *testing.T) { | |||||
| 328 | func TestCloseUnblocksQueuedSynchronousFrames(t *testing.T) { | 328 | func TestCloseUnblocksQueuedSynchronousFrames(t *testing.T) { | ||
| 329 | frames := []struct { | 329 | frames := []struct { | ||
| 330 | name string | 330 | name string | ||
| 331 | - | frame ports.Frame | 331 | + | frame wire.Frame |
| 332 | }{ | 332 | }{ | ||
| 333 | - | {name: "control", frame: ports.Frame{Type: ports.MsgPing}}, | 333 | + | {name: "control", frame: wire.Frame{Type: wire.MsgPing}}, |
| 334 | - | {name: "terminal side effect", frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("osc")})}}, | 334 | + | {name: "terminal side effect", frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("osc")})}}, |
| 335 | } | 335 | } | ||
| 336 | for _, tt := range frames { | 336 | for _, tt := range frames { | ||
| 337 | t.Run(tt.name, func(t *testing.T) { | 337 | t.Run(tt.name, func(t *testing.T) { | ||
| @@ -341,7 +341,7 @@ func TestCloseUnblocksQueuedSynchronousFrames(t *testing.T) { | |||||
| 341 | if err != nil { | 341 | if err != nil { | ||
| 342 | t.Fatal(err) | 342 | t.Fatal(err) | ||
| 343 | } | 343 | } | ||
| 344 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 3*a.mtu)}); err != nil { | 344 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 3*a.mtu)}); err != nil { |
| 345 | t.Fatal(err) | 345 | t.Fatal(err) | ||
| 346 | } | 346 | } | ||
| 347 | done := make(chan error, 1) | 347 | done := make(chan error, 1) | ||
| @@ -371,7 +371,7 @@ func TestOutputPaceFailureClosesTransportWithWriteError(t *testing.T) { | |||||
| 371 | if err := bPC.Close(); err != nil { | 371 | if err := bPC.Close(); err != nil { | ||
| 372 | t.Fatal(err) | 372 | t.Fatal(err) | ||
| 373 | } | 373 | } | ||
| 374 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("fails")}); err != nil { | 374 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("fails")}); err != nil { |
| 375 | t.Fatal(err) | 375 | t.Fatal(err) | ||
| 376 | } | 376 | } | ||
| 377 | 377 | ||||
| @@ -380,7 +380,7 @@ func TestOutputPaceFailureClosesTransportWithWriteError(t *testing.T) { | |||||
| 380 | case <-time.After(time.Second): | 380 | case <-time.After(time.Second): | ||
| 381 | t.Fatal("transport remained open after paced output write failed") | 381 | t.Fatal("transport remained open after paced output write failed") | ||
| 382 | } | 382 | } | ||
| 383 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput}); err == nil || err.Error() != "peer closed" { | 383 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput}); err == nil || err.Error() != "peer closed" { |
| 384 | t.Fatalf("send after paced write failure err=%v, want peer closed", err) | 384 | t.Fatalf("send after paced write failure err=%v, want peer closed", err) | ||
| 385 | } | 385 | } | ||
| 386 | } | 386 | } | ||
| @@ -394,24 +394,24 @@ func TestInputAndControlRemainOrderedInBoundedPacedQueue(t *testing.T) { | |||||
| 394 | } | 394 | } | ||
| 395 | defer func() { _ = a.Close() }() | 395 | defer func() { _ = a.Close() }() | ||
| 396 | 396 | ||||
| 397 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("output")}); err != nil { | 397 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("output")}); err != nil { |
| 398 | t.Fatal(err) | 398 | t.Fatal(err) | ||
| 399 | } | 399 | } | ||
| 400 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued")}); err != nil { | 400 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued")}); err != nil { |
| 401 | t.Fatal(err) | 401 | t.Fatal(err) | ||
| 402 | } | 402 | } | ||
| 403 | eventuallyPacketCount(t, bPC, 2) | 403 | eventuallyPacketCount(t, bPC, 2) | ||
| 404 | inputDone := make(chan error, 1) | 404 | inputDone := make(chan error, 1) | ||
| 405 | - | go func() { inputDone <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}) }() | 405 | + | go func() { inputDone <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}) }() |
| 406 | eventuallyPacketCount(t, bPC, 3) | 406 | eventuallyPacketCount(t, bPC, 3) | ||
| 407 | if err := <-inputDone; err != nil { | 407 | if err := <-inputDone; err != nil { | ||
| 408 | t.Fatal(err) | 408 | t.Fatal(err) | ||
| 409 | } | 409 | } | ||
| 410 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued-before-control")}); err != nil { | 410 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued-before-control")}); err != nil { |
| 411 | t.Fatal(err) | 411 | t.Fatal(err) | ||
| 412 | } | 412 | } | ||
| 413 | controlDone := make(chan error, 1) | 413 | controlDone := make(chan error, 1) | ||
| 414 | - | go func() { controlDone <- a.Send(ports.Frame{Type: ports.MsgPing}) }() | 414 | + | go func() { controlDone <- a.Send(wire.Frame{Type: wire.MsgPing}) }() |
| 415 | eventuallyPacketCount(t, bPC, 5) | 415 | eventuallyPacketCount(t, bPC, 5) | ||
| 416 | if err := <-controlDone; err != nil { | 416 | if err := <-controlDone; err != nil { | ||
| 417 | t.Fatal(err) | 417 | t.Fatal(err) | ||
| @@ -431,7 +431,7 @@ func TestSendWriteTimeoutBoundsBlockedPacketConn(t *testing.T) { | |||||
| 431 | defer func() { _ = tr.Close() }() | 431 | defer func() { _ = tr.Close() }() | ||
| 432 | 432 | ||||
| 433 | done := make(chan error, 1) | 433 | done := make(chan error, 1) | ||
| 434 | - | go func() { done <- tr.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("blocked")}) }() | 434 | + | go func() { done <- tr.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("blocked")}) }() |
| 435 | select { | 435 | select { | ||
| 436 | case err := <-done: | 436 | case err := <-done: | ||
| 437 | if err == nil { | 437 | if err == nil { | ||
| @@ -460,11 +460,11 @@ func TestPendingReliableQueueBackpressuresUntilAck(t *testing.T) { | |||||
| 460 | defer func() { _ = a.Close() }() | 460 | defer func() { _ = a.Close() }() | ||
| 461 | defer func() { _ = b.Close() }() | 461 | defer func() { _ = b.Close() }() | ||
| 462 | 462 | ||||
| 463 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | 463 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { |
| 464 | t.Fatal(err) | 464 | t.Fatal(err) | ||
| 465 | } | 465 | } | ||
| 466 | done := make(chan error, 1) | 466 | done := make(chan error, 1) | ||
| 467 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}) }() | 467 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}) }() |
| 468 | 468 | ||||
| 469 | select { | 469 | select { | ||
| 470 | case err := <-done: | 470 | case err := <-done: | ||
| @@ -498,11 +498,11 @@ func TestPendingReliableQueueReturnsErrPendingFullWhileConnected(t *testing.T) { | |||||
| 498 | defer func() { _ = a.Close() }() | 498 | defer func() { _ = a.Close() }() | ||
| 499 | defer func() { _ = b.Close() }() | 499 | defer func() { _ = b.Close() }() | ||
| 500 | 500 | ||||
| 501 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | 501 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { |
| 502 | t.Fatal(err) | 502 | t.Fatal(err) | ||
| 503 | } | 503 | } | ||
| 504 | done := make(chan error, 1) | 504 | done := make(chan error, 1) | ||
| 505 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}) }() | 505 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}) }() |
| 506 | waitForManualTimers(t, clk, 4) | 506 | waitForManualTimers(t, clk, 4) | ||
| 507 | 507 | ||||
| 508 | clk.advance(50 * time.Millisecond) | 508 | clk.advance(50 * time.Millisecond) | ||
| @@ -530,7 +530,7 @@ func TestWritePacketDeadlineUsesTransportClock(t *testing.T) { | |||||
| 530 | } | 530 | } | ||
| 531 | defer func() { _ = tr.Close() }() | 531 | defer func() { _ = tr.Close() }() | ||
| 532 | 532 | ||||
| 533 | - | if err := tr.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("deadline")}); err != nil { | 533 | + | if err := tr.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("deadline")}); err != nil { |
| 534 | t.Fatal(err) | 534 | t.Fatal(err) | ||
| 535 | } | 535 | } | ||
| 536 | got, _ := pc.deadline.Load().(time.Time) | 536 | got, _ := pc.deadline.Load().(time.Time) | ||
M internal/adapters/dgram/transport_test_helpers_test.go +19 -18
| @@ -10,6 +10,7 @@ import ( | |||||
| 10 | "time" | 10 | "time" | ||
| 11 | 11 | ||||
| 12 | "github.com/bnema/vev/internal/ports" | 12 | "github.com/bnema/vev/internal/ports" | ||
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | pdgram "github.com/bnema/vev/pkg/dgram" | 14 | pdgram "github.com/bnema/vev/pkg/dgram" | ||
| 14 | ) | 15 | ) | ||
| 15 | 16 | ||||
| @@ -309,15 +310,15 @@ func probeRecord(kind byte, id uint64) []byte { | |||||
| 309 | } | 310 | } | ||
| 310 | 311 | ||||
| 311 | func TestReliableRecvBufferBoundedForFarFutureSequences(t *testing.T) { | 312 | func TestReliableRecvBufferBoundedForFarFutureSequences(t *testing.T) { | ||
| 312 | - | tr := &Transport{nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame), maxRecvBuffer: maxRecvBuffer, done: make(chan struct{})} | 313 | + | tr := &Transport{nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame), maxRecvBuffer: maxRecvBuffer, done: make(chan struct{})} |
| 313 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | 314 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | ||
| 314 | for i := range maxRecvBuffer + 100 { | 315 | for i := range maxRecvBuffer + 100 { | ||
| 315 | - | tr.enqueueReliable(uint64(1000+i), ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}) | 316 | + | tr.enqueueReliable(uint64(1000+i), wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}) |
| 316 | } | 317 | } | ||
| 317 | if got := len(tr.recvBuf); got != maxRecvBuffer { | 318 | if got := len(tr.recvBuf); got != maxRecvBuffer { | ||
| 318 | t.Fatalf("recvBuf len=%d, want %d", got, maxRecvBuffer) | 319 | t.Fatalf("recvBuf len=%d, want %d", got, maxRecvBuffer) | ||
| 319 | } | 320 | } | ||
| 320 | - | tr.enqueueReliable(1, ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")}) | 321 | + | tr.enqueueReliable(1, wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")}) |
| 321 | if _, ok := tr.recvBuf[1]; !ok { | 322 | if _, ok := tr.recvBuf[1]; !ok { | ||
| 322 | t.Fatalf("next expected sequence was dropped when far-future buffer was full") | 323 | t.Fatalf("next expected sequence was dropped when far-future buffer was full") | ||
| 323 | } | 324 | } | ||
| @@ -329,13 +330,13 @@ func TestReliableRecvBufferBoundedForFarFutureSequences(t *testing.T) { | |||||
| 329 | func TestOutputPrerequisitesRemainInFullReceiveBuffer(t *testing.T) { | 330 | func TestOutputPrerequisitesRemainInFullReceiveBuffer(t *testing.T) { | ||
| 330 | tr := &Transport{ | 331 | tr := &Transport{ | ||
| 331 | nextRecvSeq: 1, | 332 | nextRecvSeq: 1, | ||
| 332 | - | recvBuf: map[uint64]ports.Frame{2: {Type: ports.MsgOutput, Payload: []byte("stale")}}, | 333 | + | recvBuf: map[uint64]wire.Frame{2: {Type: wire.MsgOutput, Payload: []byte("stale")}}, |
| 333 | maxRecvBuffer: 1, | 334 | maxRecvBuffer: 1, | ||
| 334 | done: make(chan struct{}), | 335 | done: make(chan struct{}), | ||
| 335 | } | 336 | } | ||
| 336 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | 337 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | ||
| 337 | 338 | ||||
| 338 | - | ackSeq, ack, queued := tr.enqueueReliable(3, ports.Frame{Type: ports.MsgOutput, Payload: []byte("replacement")}) | 339 | + | ackSeq, ack, queued := tr.enqueueReliable(3, wire.Frame{Type: wire.MsgOutput, Payload: []byte("replacement")}) |
| 339 | if ack || queued || ackSeq != 0 { | 340 | if ack || queued || ackSeq != 0 { | ||
| 340 | t.Fatalf("replacement ackSeq=%d ack=%v queued=%v, want output rejected while prerequisite buffer is full", ackSeq, ack, queued) | 341 | t.Fatalf("replacement ackSeq=%d ack=%v queued=%v, want output rejected while prerequisite buffer is full", ackSeq, ack, queued) | ||
| 341 | } | 342 | } | ||
| @@ -353,22 +354,22 @@ func TestReliableFullRecvBufferDoesNotAckDroppedFarFutureFrame(t *testing.T) { | |||||
| 353 | if err != nil { | 354 | if err != nil { | ||
| 354 | t.Fatal(err) | 355 | t.Fatal(err) | ||
| 355 | } | 356 | } | ||
| 356 | - | tr := &Transport{pc: aPC, peer: testAddr("b"), codec: codec, sendDir: 1, mtu: pdgram.DefaultMTU, nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame), maxRecvBuffer: maxRecvBuffer, clock: realClock{}, done: make(chan struct{})} | 357 | + | tr := &Transport{pc: aPC, peer: testAddr("b"), codec: codec, sendDir: 1, mtu: pdgram.DefaultMTU, nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame), maxRecvBuffer: maxRecvBuffer, clock: realClock{}, done: make(chan struct{})} |
| 357 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | 358 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | ||
| 358 | defer func() { _ = aPC.Close() }() | 359 | defer func() { _ = aPC.Close() }() | ||
| 359 | defer func() { _ = bPC.Close() }() | 360 | defer func() { _ = bPC.Close() }() | ||
| 360 | 361 | ||||
| 361 | for i := range maxRecvBuffer { | 362 | for i := range maxRecvBuffer { | ||
| 362 | - | tr.recvBuf[uint64(1000+i)] = ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}} | 363 | + | tr.recvBuf[uint64(1000+i)] = wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}} |
| 363 | } | 364 | } | ||
| 364 | - | tr.handleRecord(encodeData(9999, true, ports.Frame{Type: ports.MsgOutput, Payload: []byte("dropped")})) | 365 | + | tr.handleRecord(encodeData(9999, true, wire.Frame{Type: wire.MsgOutput, Payload: []byte("dropped")})) |
| 365 | select { | 366 | select { | ||
| 366 | case pkt := <-bPC.in: | 367 | case pkt := <-bPC.in: | ||
| 367 | t.Fatalf("unexpected ACK packet for dropped frame: %x", pkt.b) | 368 | t.Fatalf("unexpected ACK packet for dropped frame: %x", pkt.b) | ||
| 368 | case <-time.After(25 * time.Millisecond): | 369 | case <-time.After(25 * time.Millisecond): | ||
| 369 | } | 370 | } | ||
| 370 | 371 | ||||
| 371 | - | tr.handleRecord(encodeData(1, true, ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")})) | 372 | + | tr.handleRecord(encodeData(1, true, wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")})) |
| 372 | select { | 373 | select { | ||
| 373 | case <-bPC.in: | 374 | case <-bPC.in: | ||
| 374 | case <-time.After(time.Second): | 375 | case <-time.After(time.Second): | ||
| @@ -376,27 +377,27 @@ func TestReliableFullRecvBufferDoesNotAckDroppedFarFutureFrame(t *testing.T) { | |||||
| 376 | } | 377 | } | ||
| 377 | } | 378 | } | ||
| 378 | 379 | ||||
| 379 | - | func recvMaybe(tr *Transport, d time.Duration) (ports.Frame, bool) { | 380 | + | func recvMaybe(tr *Transport, d time.Duration) (wire.Frame, bool) { |
| 380 | - | ch := make(chan ports.Frame, 1) | 381 | + | ch := make(chan wire.Frame, 1) |
| 381 | go func() { f, _ := tr.Recv(); ch <- f }() | 382 | go func() { f, _ := tr.Recv(); ch <- f }() | ||
| 382 | select { | 383 | select { | ||
| 383 | case f := <-ch: | 384 | case f := <-ch: | ||
| 384 | return f, true | 385 | return f, true | ||
| 385 | case <-time.After(d): | 386 | case <-time.After(d): | ||
| 386 | - | return ports.Frame{}, false | 387 | + | return wire.Frame{}, false |
| 387 | } | 388 | } | ||
| 388 | } | 389 | } | ||
| 389 | 390 | ||||
| 390 | - | func recvWithin(t *testing.T, tr *Transport, d time.Duration) ports.Frame { | 391 | + | func recvWithin(t *testing.T, tr *Transport, d time.Duration) wire.Frame { |
| 391 | t.Helper() | 392 | t.Helper() | ||
| 392 | - | ch := make(chan ports.Frame, 1) | 393 | + | ch := make(chan wire.Frame, 1) |
| 393 | go func() { f, _ := tr.Recv(); ch <- f }() | 394 | go func() { f, _ := tr.Recv(); ch <- f }() | ||
| 394 | select { | 395 | select { | ||
| 395 | case f := <-ch: | 396 | case f := <-ch: | ||
| 396 | return f | 397 | return f | ||
| 397 | case <-time.After(d): | 398 | case <-time.After(d): | ||
| 398 | t.Fatal("timeout") | 399 | t.Fatal("timeout") | ||
| 399 | - | return ports.Frame{} | 400 | + | return wire.Frame{} |
| 400 | } | 401 | } | ||
| 401 | } | 402 | } | ||
| 402 | 403 | ||||
| @@ -412,10 +413,10 @@ func waitPeer(t *testing.T, tr *Transport, want string) { | |||||
| 412 | t.Fatalf("peer=%v, want %s", tr.Peer(), want) | 413 | t.Fatalf("peer=%v, want %s", tr.Peer(), want) | ||
| 413 | } | 414 | } | ||
| 414 | 415 | ||||
| 415 | - | func recvErrWithin(t *testing.T, tr *Transport, d time.Duration) (ports.Frame, error) { | 416 | + | func recvErrWithin(t *testing.T, tr *Transport, d time.Duration) (wire.Frame, error) { |
| 416 | t.Helper() | 417 | t.Helper() | ||
| 417 | type result struct { | 418 | type result struct { | ||
| 418 | - | f ports.Frame | 419 | + | f wire.Frame |
| 419 | err error | 420 | err error | ||
| 420 | } | 421 | } | ||
| 421 | ch := make(chan result, 1) | 422 | ch := make(chan result, 1) | ||
| @@ -428,6 +429,6 @@ func recvErrWithin(t *testing.T, tr *Transport, d time.Duration) (ports.Frame, e | |||||
| 428 | return r.f, r.err | 429 | return r.f, r.err | ||
| 429 | case <-time.After(d): | 430 | case <-time.After(d): | ||
| 430 | t.Fatal("timeout") | 431 | t.Fatal("timeout") | ||
| 431 | - | return ports.Frame{}, nil | 432 | + | return wire.Frame{}, nil |
| 432 | } | 433 | } | ||
| 433 | } | 434 | } | ||
M internal/adapters/dgram/wire_test_helpers_test.go +3 -3
| @@ -1,12 +1,12 @@ | |||||
| 1 | package dgram | 1 | package dgram | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | - | "github.com/bnema/vev/internal/ports" | |||
| 5 | "github.com/bnema/vev/internal/protocol" | 4 | "github.com/bnema/vev/internal/protocol" | ||
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 6 | ) | 6 | ) | ||
| 7 | 7 | ||||
| 8 | func mustMarshalOutput(m protocol.Output) []byte { | 8 | func mustMarshalOutput(m protocol.Output) []byte { | ||
| 9 | - | payload, err := ports.MarshalOutput(m) | 9 | + | payload, err := wire.MarshalOutput(m) |
| 10 | if err != nil { | 10 | if err != nil { | ||
| 11 | panic(err) | 11 | panic(err) | ||
| 12 | } | 12 | } | ||
| @@ -14,7 +14,7 @@ func mustMarshalOutput(m protocol.Output) []byte { | |||||
| 14 | } | 14 | } | ||
| 15 | 15 | ||||
| 16 | func mustMarshalAck(m protocol.Ack) []byte { | 16 | func mustMarshalAck(m protocol.Ack) []byte { | ||
| 17 | - | payload, err := ports.MarshalAck(m) | 17 | + | payload, err := wire.MarshalAck(m) |
| 18 | if err != nil { | 18 | if err != nil { | ||
| 19 | panic(err) | 19 | panic(err) | ||
| 20 | } | 20 | } | ||
M internal/adapters/ipc/listener_test.go +3 -3
| @@ -9,7 +9,7 @@ import ( | |||||
| 9 | "strings" | 9 | "strings" | ||
| 10 | "testing" | 10 | "testing" | ||
| 11 | 11 | ||||
| 12 | - | "github.com/bnema/vev/internal/ports" | 12 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | func TestListenAcceptRoundTrip(t *testing.T) { | 15 | func TestListenAcceptRoundTrip(t *testing.T) { | ||
| @@ -43,7 +43,7 @@ func TestListenAcceptRoundTrip(t *testing.T) { | |||||
| 43 | } | 43 | } | ||
| 44 | defer func() { _ = conn.Close() }() | 44 | defer func() { _ = conn.Close() }() | ||
| 45 | client := NewTransport(conn) | 45 | client := NewTransport(conn) | ||
| 46 | - | errCh <- client.Send(ports.Frame{Type: ports.MsgPing}) | 46 | + | errCh <- client.Send(wire.Frame{Type: wire.MsgPing}) |
| 47 | }() | 47 | }() | ||
| 48 | 48 | ||||
| 49 | transport, err := ln.Accept() | 49 | transport, err := ln.Accept() | ||
| @@ -56,7 +56,7 @@ func TestListenAcceptRoundTrip(t *testing.T) { | |||||
| 56 | if err != nil { | 56 | if err != nil { | ||
| 57 | t.Fatalf("Recv() error = %v", err) | 57 | t.Fatalf("Recv() error = %v", err) | ||
| 58 | } | 58 | } | ||
| 59 | - | if got.Type != ports.MsgPing { | 59 | + | if got.Type != wire.MsgPing { |
| 60 | t.Fatalf("Recv() type = %v, want MsgPing", got.Type) | 60 | t.Fatalf("Recv() type = %v, want MsgPing", got.Type) | ||
| 61 | } | 61 | } | ||
| 62 | if err := <-errCh; err != nil { | 62 | if err := <-errCh; err != nil { | ||
M internal/adapters/ipc/transport.go +13 -12
| @@ -8,6 +8,7 @@ import ( | |||||
| 8 | "sync" | 8 | "sync" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/ports" | 10 | "github.com/bnema/vev/internal/ports" | ||
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 11 | ) | 12 | ) | ||
| 12 | 13 | ||||
| 13 | // frameHeaderLen is the size, in bytes, of the length prefix that precedes | 14 | // frameHeaderLen is the size, in bytes, of the length prefix that precedes | ||
| @@ -19,7 +20,7 @@ const frameHeaderLen = 4 | |||||
| 19 | var ErrZeroLengthFrame = errors.New("ipc: zero-length frame") | 20 | var ErrZeroLengthFrame = errors.New("ipc: zero-length frame") | ||
| 20 | 21 | ||||
| 21 | // ErrFrameTooLarge is returned by Recv when a frame's length field exceeds | 22 | // ErrFrameTooLarge is returned by Recv when a frame's length field exceeds | ||
| 22 | - | // ports.MaxFrameLen, and by Send when a payload is too large to encode. | 23 | + | // wire.MaxFrameLen, and by Send when a payload is too large to encode. |
| 23 | var ErrFrameTooLarge = errors.New("ipc: frame exceeds maximum length") | 24 | var ErrFrameTooLarge = errors.New("ipc: frame exceeds maximum length") | ||
| 24 | 25 | ||||
| 25 | // ErrBackpressure means the bounded IPC egress queue is full. Callers using | 26 | // ErrBackpressure means the bounded IPC egress queue is full. Callers using | ||
| @@ -103,7 +104,7 @@ type sendRequest struct { | |||||
| 103 | } | 104 | } | ||
| 104 | 105 | ||||
| 105 | // Send queues f for the sole writer and waits for its wire attempt. | 106 | // Send queues f for the sole writer and waits for its wire attempt. | ||
| 106 | - | func (t *unixTransport) Send(f ports.Frame) error { | 107 | + | func (t *unixTransport) Send(f wire.Frame) error { |
| 107 | data, err := marshalFrame(f) | 108 | data, err := marshalFrame(f) | ||
| 108 | if err != nil { | 109 | if err != nil { | ||
| 109 | return err | 110 | return err | ||
| @@ -124,7 +125,7 @@ func (t *unixTransport) Send(f ports.Frame) error { | |||||
| 124 | 125 | ||||
| 125 | // SendAsync accepts f for ordered background transmission without waiting for | 126 | // SendAsync accepts f for ordered background transmission without waiting for | ||
| 126 | // a socket write. The queue is bounded and ownership includes a payload copy. | 127 | // a socket write. The queue is bounded and ownership includes a payload copy. | ||
| 127 | - | func (t *unixTransport) SendAsync(f ports.Frame) error { | 128 | + | func (t *unixTransport) SendAsync(f wire.Frame) error { |
| 128 | data, err := marshalFrame(f) | 129 | data, err := marshalFrame(f) | ||
| 129 | if err != nil { | 130 | if err != nil { | ||
| 130 | return err | 131 | return err | ||
| @@ -137,9 +138,9 @@ func (t *unixTransport) SendAsync(f ports.Frame) error { | |||||
| 137 | return nil | 138 | return nil | ||
| 138 | } | 139 | } | ||
| 139 | 140 | ||||
| 140 | - | func marshalFrame(f ports.Frame) ([]byte, error) { | 141 | + | func marshalFrame(f wire.Frame) ([]byte, error) { |
| 141 | n := 1 + len(f.Payload) // type + payload | 142 | n := 1 + len(f.Payload) // type + payload | ||
| 142 | - | if n > ports.MaxFrameLen { | 143 | + | if n > wire.MaxFrameLen { |
| 143 | return nil, ErrFrameTooLarge | 144 | return nil, ErrFrameTooLarge | ||
| 144 | } | 145 | } | ||
| 145 | buf := make([]byte, frameHeaderLen+n) | 146 | buf := make([]byte, frameHeaderLen+n) | ||
| @@ -256,22 +257,22 @@ func writeAll(w io.Writer, data []byte) error { | |||||
| 256 | // Recv reads one frame: a 4-byte length, then a body of that many bytes | 257 | // Recv reads one frame: a 4-byte length, then a body of that many bytes | ||
| 257 | // (type byte + payload). It blocks until a full frame arrives, the | 258 | // (type byte + payload). It blocks until a full frame arrives, the | ||
| 258 | // connection is closed (io.EOF), or an error occurs. | 259 | // connection is closed (io.EOF), or an error occurs. | ||
| 259 | - | func (t *unixTransport) Recv() (ports.Frame, error) { | 260 | + | func (t *unixTransport) Recv() (wire.Frame, error) { |
| 260 | end := t.beginOperation(ports.RuntimeAdapterReceiveStart, 0) | 261 | end := t.beginOperation(ports.RuntimeAdapterReceiveStart, 0) | ||
| 261 | var hdr [frameHeaderLen]byte | 262 | var hdr [frameHeaderLen]byte | ||
| 262 | if _, err := io.ReadFull(t.conn, hdr[:]); err != nil { | 263 | if _, err := io.ReadFull(t.conn, hdr[:]); err != nil { | ||
| 263 | end(false) | 264 | end(false) | ||
| 264 | - | return ports.Frame{}, err | 265 | + | return wire.Frame{}, err |
| 265 | } | 266 | } | ||
| 266 | 267 | ||||
| 267 | n := binary.BigEndian.Uint32(hdr[:]) | 268 | n := binary.BigEndian.Uint32(hdr[:]) | ||
| 268 | if n == 0 { | 269 | if n == 0 { | ||
| 269 | end(false) | 270 | end(false) | ||
| 270 | - | return ports.Frame{}, ErrZeroLengthFrame | 271 | + | return wire.Frame{}, ErrZeroLengthFrame |
| 271 | } | 272 | } | ||
| 272 | - | if n > ports.MaxFrameLen { | 273 | + | if n > wire.MaxFrameLen { |
| 273 | end(false) | 274 | end(false) | ||
| 274 | - | return ports.Frame{}, ErrFrameTooLarge | 275 | + | return wire.Frame{}, ErrFrameTooLarge |
| 275 | } | 276 | } | ||
| 276 | 277 | ||||
| 277 | if cap(t.readBuf) < int(n) { | 278 | if cap(t.readBuf) < int(n) { | ||
| @@ -281,7 +282,7 @@ func (t *unixTransport) Recv() (ports.Frame, error) { | |||||
| 281 | } | 282 | } | ||
| 282 | if _, err := io.ReadFull(t.conn, t.readBuf); err != nil { | 283 | if _, err := io.ReadFull(t.conn, t.readBuf); err != nil { | ||
| 283 | end(false) | 284 | end(false) | ||
| 284 | - | return ports.Frame{}, err | 285 | + | return wire.Frame{}, err |
| 285 | } | 286 | } | ||
| 286 | 287 | ||||
| 287 | var payload []byte | 288 | var payload []byte | ||
| @@ -290,7 +291,7 @@ func (t *unixTransport) Recv() (ports.Frame, error) { | |||||
| 290 | copy(payload, t.readBuf[1:]) | 291 | copy(payload, t.readBuf[1:]) | ||
| 291 | } | 292 | } | ||
| 292 | end(true) | 293 | end(true) | ||
| 293 | - | return ports.Frame{Type: ports.MsgType(t.readBuf[0]), Payload: payload}, nil | 294 | + | return wire.Frame{Type: wire.MsgType(t.readBuf[0]), Payload: payload}, nil |
| 294 | } | 295 | } | ||
| 295 | 296 | ||||
| 296 | func (t *unixTransport) beginOperation(start ports.RuntimeMarkKind, bytes uint64) func(bool) { | 297 | func (t *unixTransport) beginOperation(start ports.RuntimeMarkKind, bytes uint64) func(bool) { | ||
M internal/adapters/ipc/transport_benchmark_test.go +4 -4
| @@ -7,14 +7,14 @@ import ( | |||||
| 7 | "testing" | 7 | "testing" | ||
| 8 | "time" | 8 | "time" | ||
| 9 | 9 | ||||
| 10 | - | "github.com/bnema/vev/internal/ports" | 10 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 11 | ) | 11 | ) | ||
| 12 | 12 | ||||
| 13 | func BenchmarkTransportSend(b *testing.B) { | 13 | func BenchmarkTransportSend(b *testing.B) { | ||
| 14 | conn := discardConn{} | 14 | conn := discardConn{} | ||
| 15 | tr := NewTransport(conn) | 15 | tr := NewTransport(conn) | ||
| 16 | payload := []byte("payload payload payload") | 16 | payload := []byte("payload payload payload") | ||
| 17 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: payload} | 17 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: payload} |
| 18 | 18 | ||||
| 19 | b.ReportAllocs() | 19 | b.ReportAllocs() | ||
| 20 | for b.Loop() { | 20 | for b.Loop() { | ||
| @@ -26,7 +26,7 @@ func BenchmarkTransportSend(b *testing.B) { | |||||
| 26 | 26 | ||||
| 27 | func BenchmarkTransportRecvReuse(b *testing.B) { | 27 | func BenchmarkTransportRecvReuse(b *testing.B) { | ||
| 28 | payload := []byte("payload payload payload") | 28 | payload := []byte("payload payload payload") | ||
| 29 | - | encoded := encodeBenchmarkFrame(ports.Frame{Type: ports.MsgOutput, Payload: payload}) | 29 | + | encoded := encodeBenchmarkFrame(wire.Frame{Type: wire.MsgOutput, Payload: payload}) |
| 30 | recv := &unixTransport{conn: &loopingReaderConn{data: encoded}} | 30 | recv := &unixTransport{conn: &loopingReaderConn{data: encoded}} | ||
| 31 | 31 | ||||
| 32 | b.ReportAllocs() | 32 | b.ReportAllocs() | ||
| @@ -37,7 +37,7 @@ func BenchmarkTransportRecvReuse(b *testing.B) { | |||||
| 37 | } | 37 | } | ||
| 38 | } | 38 | } | ||
| 39 | 39 | ||||
| 40 | - | func encodeBenchmarkFrame(f ports.Frame) []byte { | 40 | + | func encodeBenchmarkFrame(f wire.Frame) []byte { |
| 41 | n := 1 + len(f.Payload) | 41 | n := 1 + len(f.Payload) | ||
| 42 | buf := make([]byte, frameHeaderLen+n) | 42 | buf := make([]byte, frameHeaderLen+n) | ||
| 43 | binary.BigEndian.PutUint32(buf[:frameHeaderLen], uint32(n)) | 43 | binary.BigEndian.PutUint32(buf[:frameHeaderLen], uint32(n)) | ||
M internal/adapters/ipc/transport_observability_test.go +3 -2
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | 12 | ||||
| 13 | "github.com/bnema/vev/internal/adapters/observability" | 13 | "github.com/bnema/vev/internal/adapters/observability" | ||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 15 | ) | 16 | ) | ||
| 16 | 17 | ||||
| 17 | func TestTransportObservabilityIPCEOFAndCloseEndFailedSpans(t *testing.T) { | 18 | func TestTransportObservabilityIPCEOFAndCloseEndFailedSpans(t *testing.T) { | ||
| @@ -55,7 +56,7 @@ func TestTransportObservabilityIPCEOFAndCloseEndFailedSpans(t *testing.T) { | |||||
| 55 | left, right := net.Pipe() | 56 | left, right := net.Pipe() | ||
| 56 | transport := NewTransport(left, WithRuntimeObserver(reporter)) | 57 | transport := NewTransport(left, WithRuntimeObserver(reporter)) | ||
| 57 | _ = right.Close() | 58 | _ = right.Close() | ||
| 58 | - | if err := transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("failed")}); err == nil { | 59 | + | if err := transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("failed")}); err == nil { |
| 59 | t.Fatal("Send() error = nil after peer close") | 60 | t.Fatal("Send() error = nil after peer close") | ||
| 60 | } | 61 | } | ||
| 61 | _ = transport.Close() | 62 | _ = transport.Close() | ||
| @@ -152,7 +153,7 @@ func TestTransportObservabilityIPCMarksCarriageWithoutChangingBytes(t *testing.T | |||||
| 152 | defer func() { _ = right.Close() }() | 153 | defer func() { _ = right.Close() }() | ||
| 153 | client := NewTransport(left, WithRuntimeObserver(reporter)) | 154 | client := NewTransport(left, WithRuntimeObserver(reporter)) | ||
| 154 | server := NewTransport(right, WithRuntimeObserver(reporter)) | 155 | server := NewTransport(right, WithRuntimeObserver(reporter)) | ||
| 155 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: []byte("wire bytes stay exact")} | 156 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: []byte("wire bytes stay exact")} |
| 156 | 157 | ||||
| 157 | var wg sync.WaitGroup | 158 | var wg sync.WaitGroup | ||
| 158 | wg.Go(func() { | 159 | wg.Go(func() { | ||
M internal/adapters/ipc/transport_replay_test.go +3 -3
| @@ -5,12 +5,12 @@ import ( | |||||
| 5 | "sync" | 5 | "sync" | ||
| 6 | "testing" | 6 | "testing" | ||
| 7 | 7 | ||||
| 8 | - | "github.com/bnema/vev/internal/ports" | 8 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 9 | "github.com/bnema/vev/internal/testutil/replaytest" | 9 | "github.com/bnema/vev/internal/testutil/replaytest" | ||
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| 12 | func TestTransportReplay(t *testing.T) { | 12 | func TestTransportReplay(t *testing.T) { | ||
| 13 | - | replaytest.Run(t, func(t *testing.T, frames []ports.Frame) []ports.Frame { | 13 | + | replaytest.Run(t, func(t *testing.T, frames []wire.Frame) []wire.Frame { |
| 14 | left, right := net.Pipe() | 14 | left, right := net.Pipe() | ||
| 15 | t.Cleanup(func() { _ = left.Close(); _ = right.Close() }) | 15 | t.Cleanup(func() { _ = left.Close(); _ = right.Close() }) | ||
| 16 | sender, receiver := NewTransport(left), NewTransport(right) | 16 | sender, receiver := NewTransport(left), NewTransport(right) | ||
| @@ -24,7 +24,7 @@ func TestTransportReplay(t *testing.T) { | |||||
| 24 | } | 24 | } | ||
| 25 | } | 25 | } | ||
| 26 | }) | 26 | }) | ||
| 27 | - | got := make([]ports.Frame, 0, len(frames)) | 27 | + | got := make([]wire.Frame, 0, len(frames)) |
| 28 | for range frames { | 28 | for range frames { | ||
| 29 | frame, err := receiver.Recv() | 29 | frame, err := receiver.Recv() | ||
| 30 | if err != nil { | 30 | if err != nil { | ||
M internal/adapters/ipc/transport_test.go +27 -26
| @@ -14,6 +14,7 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/domain" | 14 | "github.com/bnema/vev/internal/domain" | ||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | "github.com/bnema/vev/internal/protocol" | 16 | "github.com/bnema/vev/internal/protocol" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 17 | ) | 18 | ) | ||
| 18 | 19 | ||||
| 19 | func TestTransportSendRecvBothDirections(t *testing.T) { | 20 | func TestTransportSendRecvBothDirections(t *testing.T) { | ||
| @@ -24,8 +25,8 @@ func TestTransportSendRecvBothDirections(t *testing.T) { | |||||
| 24 | client := NewTransport(c1) | 25 | client := NewTransport(c1) | ||
| 25 | server := NewTransport(c2) | 26 | server := NewTransport(c2) | ||
| 26 | 27 | ||||
| 27 | - | clientToServer := ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{Version: 1, Intent: protocol.IntentNew, Name: "w0"})} | 28 | + | clientToServer := wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{Version: 1, Intent: protocol.IntentNew, Name: "w0"})} |
| 28 | - | serverToClient := ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"})} | 29 | + | serverToClient := wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"})} |
| 29 | 30 | ||||
| 30 | var wg sync.WaitGroup | 31 | var wg sync.WaitGroup | ||
| 31 | wg.Go(func() { | 32 | wg.Go(func() { | ||
| @@ -97,12 +98,12 @@ func TestTransportLargeFrameNearCap(t *testing.T) { | |||||
| 97 | server := NewTransport(c2) | 98 | server := NewTransport(c2) | ||
| 98 | 99 | ||||
| 99 | // Largest payload whose frame length (1 + len(payload)) still fits | 100 | // Largest payload whose frame length (1 + len(payload)) still fits | ||
| 100 | - | // exactly at ports.MaxFrameLen. | 101 | + | // exactly at wire.MaxFrameLen. |
| 101 | - | payload := make([]byte, ports.MaxFrameLen-1) | 102 | + | payload := make([]byte, wire.MaxFrameLen-1) |
| 102 | for i := range payload { | 103 | for i := range payload { | ||
| 103 | payload[i] = byte(i) | 104 | payload[i] = byte(i) | ||
| 104 | } | 105 | } | ||
| 105 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: payload} | 106 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: payload} |
| 106 | 107 | ||||
| 107 | var wg sync.WaitGroup | 108 | var wg sync.WaitGroup | ||
| 108 | wg.Go(func() { | 109 | wg.Go(func() { | ||
| @@ -135,13 +136,13 @@ func TestTransportManySmallFramesBackToBack(t *testing.T) { | |||||
| 135 | server := NewTransport(c2) | 136 | server := NewTransport(c2) | ||
| 136 | 137 | ||||
| 137 | const count = 200 | 138 | const count = 200 | ||
| 138 | - | frames := make([]ports.Frame, count) | 139 | + | frames := make([]wire.Frame, count) |
| 139 | for i := range frames { | 140 | for i := range frames { | ||
| 140 | - | frames[i] = ports.Frame{Type: ports.MsgPing, Payload: nil} | 141 | + | frames[i] = wire.Frame{Type: wire.MsgPing, Payload: nil} |
| 141 | } | 142 | } | ||
| 142 | // Vary a couple to prove ordering and content are both preserved. | 143 | // Vary a couple to prove ordering and content are both preserved. | ||
| 143 | - | frames[7] = ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("hop")})} | 144 | + | frames[7] = wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("hop")})} |
| 144 | - | frames[150] = ports.Frame{Type: ports.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 5, Rows: 6}})} | 145 | + | frames[150] = wire.Frame{Type: wire.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 5, Rows: 6}})} |
| 145 | 146 | ||||
| 146 | var wg sync.WaitGroup | 147 | var wg sync.WaitGroup | ||
| 147 | wg.Go(func() { | 148 | wg.Go(func() { | ||
| @@ -178,7 +179,7 @@ func TestTransportRecvOversizeFrame(t *testing.T) { | |||||
| 178 | 179 | ||||
| 179 | go func() { | 180 | go func() { | ||
| 180 | var hdr [4]byte | 181 | var hdr [4]byte | ||
| 181 | - | binary.BigEndian.PutUint32(hdr[:], ports.MaxFrameLen+1) | 182 | + | binary.BigEndian.PutUint32(hdr[:], wire.MaxFrameLen+1) |
| 182 | _, _ = c1.Write(hdr[:]) | 183 | _, _ = c1.Write(hdr[:]) | ||
| 183 | }() | 184 | }() | ||
| 184 | 185 | ||||
| @@ -228,8 +229,8 @@ func TestTransportSendOversizePayloadRejected(t *testing.T) { | |||||
| 228 | defer func() { _ = c2.Close() }() | 229 | defer func() { _ = c2.Close() }() | ||
| 229 | 230 | ||||
| 230 | client := NewTransport(c1) | 231 | client := NewTransport(c1) | ||
| 231 | - | payload := make([]byte, ports.MaxFrameLen) // +1 byte type => exceeds max | 232 | + | payload := make([]byte, wire.MaxFrameLen) // +1 byte type => exceeds max |
| 232 | - | err := client.Send(ports.Frame{Type: ports.MsgOutput, Payload: payload}) | 233 | + | err := client.Send(wire.Frame{Type: wire.MsgOutput, Payload: payload}) |
| 233 | if !errors.Is(err, ErrFrameTooLarge) { | 234 | if !errors.Is(err, ErrFrameTooLarge) { | ||
| 234 | t.Fatalf("client.Send() error = %v, want ErrFrameTooLarge", err) | 235 | t.Fatalf("client.Send() error = %v, want ErrFrameTooLarge", err) | ||
| 235 | } | 236 | } | ||
| @@ -257,7 +258,7 @@ func TestTransportAsyncEgressPreservesWelcomeBeforeOutput(t *testing.T) { | |||||
| 257 | t.Fatal("IPC transport does not implement AsyncTransport") | 258 | t.Fatal("IPC transport does not implement AsyncTransport") | ||
| 258 | } | 259 | } | ||
| 259 | 260 | ||||
| 260 | - | welcome := ports.Frame{Type: ports.MsgWelcome, Payload: []byte("welcome")} | 261 | + | welcome := wire.Frame{Type: wire.MsgWelcome, Payload: []byte("welcome")} |
| 261 | sent := make(chan error, 1) | 262 | sent := make(chan error, 1) | ||
| 262 | go func() { sent <- server.Send(welcome) }() | 263 | go func() { sent <- server.Send(welcome) }() | ||
| 263 | got, err := client.Recv() | 264 | got, err := client.Recv() | ||
| @@ -277,16 +278,16 @@ func TestTransportAsyncEgressPreservesWelcomeBeforeOutput(t *testing.T) { | |||||
| 277 | } | 278 | } | ||
| 278 | 279 | ||||
| 279 | payload := []byte("first") | 280 | payload := []byte("first") | ||
| 280 | - | if err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | 281 | + | if err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: payload}); err != nil { |
| 281 | t.Fatalf("SendAsync first output: %v", err) | 282 | t.Fatalf("SendAsync first output: %v", err) | ||
| 282 | } | 283 | } | ||
| 283 | payload[0] = 'X' // async ownership must not retain caller memory. | 284 | payload[0] = 'X' // async ownership must not retain caller memory. | ||
| 284 | - | if err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("second")}); err != nil { | 285 | + | if err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("second")}); err != nil { |
| 285 | t.Fatalf("SendAsync second output: %v", err) | 286 | t.Fatalf("SendAsync second output: %v", err) | ||
| 286 | } | 287 | } | ||
| 287 | - | for _, want := range []ports.Frame{ | 288 | + | for _, want := range []wire.Frame{ |
| 288 | - | {Type: ports.MsgOutput, Payload: []byte("first")}, | 289 | + | {Type: wire.MsgOutput, Payload: []byte("first")}, |
| 289 | - | {Type: ports.MsgOutput, Payload: []byte("second")}, | 290 | + | {Type: wire.MsgOutput, Payload: []byte("second")}, |
| 290 | } { | 291 | } { | ||
| 291 | got, err := client.Recv() | 292 | got, err := client.Recv() | ||
| 292 | if err != nil { | 293 | if err != nil { | ||
| @@ -322,7 +323,7 @@ func TestTransportSendWaitsForEgressCapacity(t *testing.T) { | |||||
| 322 | } | 323 | } | ||
| 323 | 324 | ||||
| 324 | queued := fillAsyncEgress(t, transport, async, timeout) | 325 | queued := fillAsyncEgress(t, transport, async, timeout) | ||
| 325 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: []byte("synchronous")} | 326 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: []byte("synchronous")} |
| 326 | sent := make(chan error, 1) | 327 | sent := make(chan error, 1) | ||
| 327 | go func() { sent <- server.Send(want) }() | 328 | go func() { sent <- server.Send(want) }() | ||
| 328 | waitForEgressSender(t, transport, timeout) | 329 | waitForEgressSender(t, transport, timeout) | ||
| @@ -371,7 +372,7 @@ func TestTransportCloseInterruptsSendWaitingForEgressCapacity(t *testing.T) { | |||||
| 371 | fillAsyncEgress(t, transport, async, timeout) | 372 | fillAsyncEgress(t, transport, async, timeout) | ||
| 372 | 373 | ||||
| 373 | sent := make(chan error, 1) | 374 | sent := make(chan error, 1) | ||
| 374 | - | go func() { sent <- server.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("synchronous")}) }() | 375 | + | go func() { sent <- server.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("synchronous")}) }() |
| 375 | waitForEgressSender(t, transport, timeout) | 376 | waitForEgressSender(t, transport, timeout) | ||
| 376 | 377 | ||||
| 377 | closeTransport(t, server) | 378 | closeTransport(t, server) | ||
| @@ -421,18 +422,18 @@ func closeTransport(t *testing.T, transport ports.Transport) { | |||||
| 421 | } | 422 | } | ||
| 422 | } | 423 | } | ||
| 423 | 424 | ||||
| 424 | - | func fillAsyncEgress(t *testing.T, transport *unixTransport, async ports.AsyncTransport, timeout time.Duration) []ports.Frame { | 425 | + | func fillAsyncEgress(t *testing.T, transport *unixTransport, async ports.AsyncTransport, timeout time.Duration) []wire.Frame { |
| 425 | t.Helper() | 426 | t.Helper() | ||
| 426 | 427 | ||||
| 427 | - | first := ports.Frame{Type: ports.MsgOutput, Payload: []byte{0}} | 428 | + | first := wire.Frame{Type: wire.MsgOutput, Payload: []byte{0}} |
| 428 | if err := async.SendAsync(first); err != nil { | 429 | if err := async.SendAsync(first); err != nil { | ||
| 429 | t.Fatalf("SendAsync blocked frame: %v", err) | 430 | t.Fatalf("SendAsync blocked frame: %v", err) | ||
| 430 | } | 431 | } | ||
| 431 | waitForEgressDequeue(t, transport, timeout) | 432 | waitForEgressDequeue(t, transport, timeout) | ||
| 432 | 433 | ||||
| 433 | - | queued := []ports.Frame{first} | 434 | + | queued := []wire.Frame{first} |
| 434 | for i := 1; ; i++ { | 435 | for i := 1; ; i++ { | ||
| 435 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}} | 436 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}} |
| 436 | err := async.SendAsync(frame) | 437 | err := async.SendAsync(frame) | ||
| 437 | switch { | 438 | switch { | ||
| 438 | case err == nil: | 439 | case err == nil: | ||
| @@ -479,12 +480,12 @@ func TestTransportAsyncEgressIsBoundedAndCloseInterruptsWorkers(t *testing.T) { | |||||
| 479 | } | 480 | } | ||
| 480 | 481 | ||||
| 481 | // The first write blocks in net.Pipe because the peer never drains it. | 482 | // The first write blocks in net.Pipe because the peer never drains it. | ||
| 482 | - | if err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("blocked")}); err != nil { | 483 | + | if err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("blocked")}); err != nil { |
| 483 | t.Fatalf("SendAsync blocked frame: %v", err) | 484 | t.Fatalf("SendAsync blocked frame: %v", err) | ||
| 484 | } | 485 | } | ||
| 485 | var backpressure error | 486 | var backpressure error | ||
| 486 | for range sendQueueCapacity + 2 { | 487 | for range sendQueueCapacity + 2 { | ||
| 487 | - | err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued")}) | 488 | + | err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued")}) |
| 488 | if errors.Is(err, ErrBackpressure) { | 489 | if errors.Is(err, ErrBackpressure) { | ||
| 489 | backpressure = err | 490 | backpressure = err | ||
| 490 | break | 491 | break | ||
M internal/adapters/ipc/wire_test_helpers_test.go +2 -2
| @@ -1,12 +1,12 @@ | |||||
| 1 | package ipc | 1 | package ipc | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | - | "github.com/bnema/vev/internal/ports" | |||
| 5 | "github.com/bnema/vev/internal/protocol" | 4 | "github.com/bnema/vev/internal/protocol" | ||
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 6 | ) | 6 | ) | ||
| 7 | 7 | ||||
| 8 | func mustMarshalResize(m protocol.Resize) []byte { | 8 | func mustMarshalResize(m protocol.Resize) []byte { | ||
| 9 | - | payload, err := ports.MarshalResize(m) | 9 | + | payload, err := wire.MarshalResize(m) |
| 10 | if err != nil { | 10 | if err != nil { | ||
| 11 | panic(err) | 11 | panic(err) | ||
| 12 | } | 12 | } | ||
M internal/adapters/remote/preview.go +3 -2
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | "github.com/bnema/vev/internal/domain" | 12 | "github.com/bnema/vev/internal/domain" | ||
| 13 | "github.com/bnema/vev/internal/ports" | 13 | "github.com/bnema/vev/internal/ports" | ||
| 14 | "github.com/bnema/vev/internal/protocol" | 14 | "github.com/bnema/vev/internal/protocol" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 15 | ) | 16 | ) | ||
| 16 | 17 | ||||
| 17 | const ( | 18 | const ( | ||
| @@ -42,7 +43,7 @@ func NewPreviewClient() ports.RemotePreviewClient { | |||||
| 42 | 43 | ||||
| 43 | func (c *PreviewClient) Preview(ctx context.Context, target domain.RemoteSessionTarget, width, height uint16) (protocol.RemotePreview, error) { | 44 | func (c *PreviewClient) Preview(ctx context.Context, target domain.RemoteSessionTarget, width, height uint16) (protocol.RemotePreview, error) { | ||
| 44 | request := protocol.RemotePreviewRequest{Version: protocol.RemotePreviewSchemaVersion, Target: target, Width: width, Height: height} | 45 | request := protocol.RemotePreviewRequest{Version: protocol.RemotePreviewSchemaVersion, Target: target, Width: width, Height: height} | ||
| 45 | - | payload := ports.MarshalRemotePreviewRequest(request) | 46 | + | payload := wire.MarshalRemotePreviewRequest(request) |
| 46 | if payload == nil { | 47 | if payload == nil { | ||
| 47 | return protocol.RemotePreview{}, protocol.ErrInvalidRemotePreviewRequest | 48 | return protocol.RemotePreview{}, protocol.ErrInvalidRemotePreviewRequest | ||
| 48 | } | 49 | } | ||
| @@ -78,7 +79,7 @@ func (c *PreviewClient) Preview(ctx context.Context, target domain.RemoteSession | |||||
| 78 | if stdout.overflow || stderr.overflow { | 79 | if stdout.overflow || stderr.overflow { | ||
| 79 | return protocol.RemotePreview{}, errRemotePreviewTooLarge | 80 | return protocol.RemotePreview{}, errRemotePreviewTooLarge | ||
| 80 | } | 81 | } | ||
| 81 | - | preview, err := ports.UnmarshalRemotePreview(stdout.Bytes()) | 82 | + | preview, err := wire.UnmarshalRemotePreview(stdout.Bytes()) |
| 82 | if err != nil { | 83 | if err != nil { | ||
| 83 | return protocol.RemotePreview{}, err | 84 | return protocol.RemotePreview{}, err | ||
| 84 | } | 85 | } | ||
M internal/adapters/remote/preview_test.go +4 -4
| @@ -15,8 +15,8 @@ import ( | |||||
| 15 | renderer "github.com/bnema/vev-vt" | 15 | renderer "github.com/bnema/vev-vt" | ||
| 16 | "github.com/bnema/vev/internal/adapters/sshstdio" | 16 | "github.com/bnema/vev/internal/adapters/sshstdio" | ||
| 17 | "github.com/bnema/vev/internal/domain" | 17 | "github.com/bnema/vev/internal/domain" | ||
| 18 | - | "github.com/bnema/vev/internal/ports" | |||
| 19 | "github.com/bnema/vev/internal/protocol" | 18 | "github.com/bnema/vev/internal/protocol" | ||
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 20 | ) | 20 | ) | ||
| 21 | 21 | ||||
| 22 | func previewClientTargetForTest() domain.RemoteSessionTarget { | 22 | func previewClientTargetForTest() domain.RemoteSessionTarget { | ||
| @@ -37,7 +37,7 @@ func TestRemotePreviewClientBuildsExactSSHCommandAndDecodesResponse(t *testing.T | |||||
| 37 | LifecycleID: lifecycle, TabID: target.LiveTabID, Revision: 7, Width: 1, Height: 1, | 37 | LifecycleID: lifecycle, TabID: target.LiveTabID, Revision: 7, Width: 1, Height: 1, | ||
| 38 | Cells: []renderer.Cell{{Rune: 'x', Style: renderer.DefaultStyle()}}, | 38 | Cells: []renderer.Cell{{Rune: 'x', Style: renderer.DefaultStyle()}}, | ||
| 39 | } | 39 | } | ||
| 40 | - | payload := ports.MarshalRemotePreview(want) | 40 | + | payload := wire.MarshalRemotePreview(want) |
| 41 | require.NotNil(t, payload) | 41 | require.NotNil(t, payload) | ||
| 42 | 42 | ||||
| 43 | var gotPath string | 43 | var gotPath string | ||
| @@ -57,7 +57,7 @@ func TestRemotePreviewClientBuildsExactSSHCommandAndDecodesResponse(t *testing.T | |||||
| 57 | if err != nil { | 57 | if err != nil { | ||
| 58 | t.Fatalf("decode request: %v", err) | 58 | t.Fatalf("decode request: %v", err) | ||
| 59 | } | 59 | } | ||
| 60 | - | request, err := ports.UnmarshalRemotePreviewRequest(requestPayload) | 60 | + | request, err := wire.UnmarshalRemotePreviewRequest(requestPayload) |
| 61 | if err != nil { | 61 | if err != nil { | ||
| 62 | t.Fatalf("decode request payload: %v", err) | 62 | t.Fatalf("decode request payload: %v", err) | ||
| 63 | } | 63 | } | ||
| @@ -96,7 +96,7 @@ func TestRemotePreviewClientRejectsMismatchedResponseIdentity(t *testing.T) { | |||||
| 96 | t.Run(tt.name, func(t *testing.T) { | 96 | t.Run(tt.name, func(t *testing.T) { | ||
| 97 | preview := valid | 97 | preview := valid | ||
| 98 | tt.mutate(&preview) | 98 | tt.mutate(&preview) | ||
| 99 | - | payload := ports.MarshalRemotePreview(preview) | 99 | + | payload := wire.MarshalRemotePreview(preview) |
| 100 | require.NotNil(t, payload) | 100 | require.NotNil(t, payload) | ||
| 101 | 101 | ||||
| 102 | client := &PreviewClient{command: func(ctx context.Context, _ string, _ ...string) *exec.Cmd { | 102 | client := &PreviewClient{command: func(ctx context.Context, _ string, _ ...string) *exec.Cmd { | ||
M internal/adapters/sshstdio/transport.go +9 -8
| @@ -19,10 +19,11 @@ import ( | |||||
| 19 | "time" | 19 | "time" | ||
| 20 | 20 | ||||
| 21 | "github.com/bnema/vev/internal/ports" | 21 | "github.com/bnema/vev/internal/ports" | ||
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 22 | ) | 23 | ) | ||
| 23 | 24 | ||||
| 24 | const ( | 25 | const ( | ||
| 25 | - | maxFrameLen = ports.MaxFrameLen | 26 | + | maxFrameLen = wire.MaxFrameLen |
| 26 | frameHeaderLen = 4 | 27 | frameHeaderLen = 4 | ||
| 27 | sshCloseTimeout = 3 * time.Second | 28 | sshCloseTimeout = 3 * time.Second | ||
| 28 | ) | 29 | ) | ||
| @@ -260,7 +261,7 @@ func (r processStdinReader) Read(dst []byte) (int, error) { | |||||
| 260 | return r.pump.read(r.done, dst) | 261 | return r.pump.read(r.done, dst) | ||
| 261 | } | 262 | } | ||
| 262 | 263 | ||||
| 263 | - | func (t *transport) Send(f ports.Frame) error { | 264 | + | func (t *transport) Send(f wire.Frame) error { |
| 264 | end := t.beginOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | 265 | end := t.beginOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | ||
| 265 | n := 1 + len(f.Payload) | 266 | n := 1 + len(f.Payload) | ||
| 266 | if n > maxFrameLen { | 267 | if n > maxFrameLen { | ||
| @@ -280,23 +281,23 @@ func (t *transport) Send(f ports.Frame) error { | |||||
| 280 | return err | 281 | return err | ||
| 281 | } | 282 | } | ||
| 282 | 283 | ||||
| 283 | - | func (t *transport) Recv() (ports.Frame, error) { | 284 | + | func (t *transport) Recv() (wire.Frame, error) { |
| 284 | end := t.beginOperation(ports.RuntimeAdapterReceiveStart, 0) | 285 | end := t.beginOperation(ports.RuntimeAdapterReceiveStart, 0) | ||
| 285 | var hdr [frameHeaderLen]byte | 286 | var hdr [frameHeaderLen]byte | ||
| 286 | if _, err := io.ReadFull(t.r, hdr[:]); err != nil { | 287 | if _, err := io.ReadFull(t.r, hdr[:]); err != nil { | ||
| 287 | err = t.mapEOFError(err) | 288 | err = t.mapEOFError(err) | ||
| 288 | end(false) | 289 | end(false) | ||
| 289 | - | return ports.Frame{}, err | 290 | + | return wire.Frame{}, err |
| 290 | } | 291 | } | ||
| 291 | 292 | ||||
| 292 | n := binary.BigEndian.Uint32(hdr[:]) | 293 | n := binary.BigEndian.Uint32(hdr[:]) | ||
| 293 | if n == 0 { | 294 | if n == 0 { | ||
| 294 | end(false) | 295 | end(false) | ||
| 295 | - | return ports.Frame{}, ErrZeroLengthFrame | 296 | + | return wire.Frame{}, ErrZeroLengthFrame |
| 296 | } | 297 | } | ||
| 297 | if n > maxFrameLen { | 298 | if n > maxFrameLen { | ||
| 298 | end(false) | 299 | end(false) | ||
| 299 | - | return ports.Frame{}, ErrFrameTooLarge | 300 | + | return wire.Frame{}, ErrFrameTooLarge |
| 300 | } | 301 | } | ||
| 301 | 302 | ||||
| 302 | if cap(t.readBuf) < int(n) { | 303 | if cap(t.readBuf) < int(n) { | ||
| @@ -307,12 +308,12 @@ func (t *transport) Recv() (ports.Frame, error) { | |||||
| 307 | if _, err := io.ReadFull(t.r, t.readBuf); err != nil { | 308 | if _, err := io.ReadFull(t.r, t.readBuf); err != nil { | ||
| 308 | err = t.mapEOFError(err) | 309 | err = t.mapEOFError(err) | ||
| 309 | end(false) | 310 | end(false) | ||
| 310 | - | return ports.Frame{}, err | 311 | + | return wire.Frame{}, err |
| 311 | } | 312 | } | ||
| 312 | 313 | ||||
| 313 | payload := append([]byte(nil), t.readBuf[1:]...) | 314 | payload := append([]byte(nil), t.readBuf[1:]...) | ||
| 314 | end(true) | 315 | end(true) | ||
| 315 | - | return ports.Frame{Type: ports.MsgType(t.readBuf[0]), Payload: payload}, nil | 316 | + | return wire.Frame{Type: wire.MsgType(t.readBuf[0]), Payload: payload}, nil |
| 316 | } | 317 | } | ||
| 317 | 318 | ||||
| 318 | func (t *transport) beginOperation(start ports.RuntimeMarkKind, bytes uint64) func(bool) { | 319 | func (t *transport) beginOperation(start ports.RuntimeMarkKind, bytes uint64) func(bool) { | ||
M internal/adapters/sshstdio/transport_observability_test.go +2 -1
| @@ -13,6 +13,7 @@ import ( | |||||
| 13 | 13 | ||||
| 14 | "github.com/bnema/vev/internal/adapters/observability" | 14 | "github.com/bnema/vev/internal/adapters/observability" | ||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | ) | 17 | ) | ||
| 17 | 18 | ||||
| 18 | func TestTransportObservabilitySSHStdioEOFEndsReceive(t *testing.T) { | 19 | func TestTransportObservabilitySSHStdioEOFEndsReceive(t *testing.T) { | ||
| @@ -212,7 +213,7 @@ func TestTransportObservabilitySSHStdioPreservesCarriage(t *testing.T) { | |||||
| 212 | reporter := ports.NewSerializedRuntimeObserver(observer, 64) | 213 | reporter := ports.NewSerializedRuntimeObserver(observer, 64) | ||
| 213 | defer reporter.Close() | 214 | defer reporter.Close() | ||
| 214 | 215 | ||||
| 215 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: []byte("stdio bytes stay exact")} | 216 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: []byte("stdio bytes stay exact")} |
| 216 | var observed, baseline bytes.Buffer | 217 | var observed, baseline bytes.Buffer | ||
| 217 | if err := NewTransport(bytes.NewReader(nil), &observed, nil, WithRuntimeObserver(reporter)).Send(frame); err != nil { | 218 | if err := NewTransport(bytes.NewReader(nil), &observed, nil, WithRuntimeObserver(reporter)).Send(frame); err != nil { | ||
| 218 | t.Fatalf("observed Send() error = %v", err) | 219 | t.Fatalf("observed Send() error = %v", err) | ||
M internal/adapters/sshstdio/transport_replay_test.go +3 -3
| @@ -5,12 +5,12 @@ import ( | |||||
| 5 | "sync" | 5 | "sync" | ||
| 6 | "testing" | 6 | "testing" | ||
| 7 | 7 | ||||
| 8 | - | "github.com/bnema/vev/internal/ports" | 8 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 9 | "github.com/bnema/vev/internal/testutil/replaytest" | 9 | "github.com/bnema/vev/internal/testutil/replaytest" | ||
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| 12 | func TestTransportReplay(t *testing.T) { | 12 | func TestTransportReplay(t *testing.T) { | ||
| 13 | - | replaytest.Run(t, func(t *testing.T, frames []ports.Frame) []ports.Frame { | 13 | + | replaytest.Run(t, func(t *testing.T, frames []wire.Frame) []wire.Frame { |
| 14 | clientRead, serverWrite := io.Pipe() | 14 | clientRead, serverWrite := io.Pipe() | ||
| 15 | serverRead, clientWrite := io.Pipe() | 15 | serverRead, clientWrite := io.Pipe() | ||
| 16 | sender := NewTransport(clientRead, clientWrite, func() error { return clientWrite.Close() }) | 16 | sender := NewTransport(clientRead, clientWrite, func() error { return clientWrite.Close() }) | ||
| @@ -26,7 +26,7 @@ func TestTransportReplay(t *testing.T) { | |||||
| 26 | } | 26 | } | ||
| 27 | } | 27 | } | ||
| 28 | }) | 28 | }) | ||
| 29 | - | got := make([]ports.Frame, 0, len(frames)) | 29 | + | got := make([]wire.Frame, 0, len(frames)) |
| 30 | for range frames { | 30 | for range frames { | ||
| 31 | frame, err := receiver.Recv() | 31 | frame, err := receiver.Recv() | ||
| 32 | if err != nil { | 32 | if err != nil { | ||
M internal/adapters/sshstdio/transport_test.go +15 -15
| @@ -14,8 +14,8 @@ import ( | |||||
| 14 | "time" | 14 | "time" | ||
| 15 | 15 | ||||
| 16 | "github.com/bnema/vev/internal/domain" | 16 | "github.com/bnema/vev/internal/domain" | ||
| 17 | - | "github.com/bnema/vev/internal/ports" | |||
| 18 | "github.com/bnema/vev/internal/protocol" | 17 | "github.com/bnema/vev/internal/protocol" | ||
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 19 | ) | 19 | ) | ||
| 20 | 20 | ||||
| 21 | func TestBuildCommandUsesExecArgs(t *testing.T) { | 21 | func TestBuildCommandUsesExecArgs(t *testing.T) { | ||
| @@ -114,7 +114,7 @@ func TestCloseInterruptsBlockedSend(t *testing.T) { | |||||
| 114 | transport := NewTransport(nil, writer, nil) | 114 | transport := NewTransport(nil, writer, nil) | ||
| 115 | 115 | ||||
| 116 | sendDone := make(chan error, 1) | 116 | sendDone := make(chan error, 1) | ||
| 117 | - | go func() { sendDone <- transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("blocked")}) }() | 117 | + | go func() { sendDone <- transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("blocked")}) }() |
| 118 | <-writer.started | 118 | <-writer.started | ||
| 119 | if err := transport.Close(); err != nil { | 119 | if err := transport.Close(); err != nil { | ||
| 120 | t.Fatalf("Close() error = %v", err) | 120 | t.Fatalf("Close() error = %v", err) | ||
| @@ -166,7 +166,7 @@ func TestTransportRoundTripAndVersionMismatchFrame(t *testing.T) { | |||||
| 166 | t.Errorf("server Recv: %v", err) | 166 | t.Errorf("server Recv: %v", err) | ||
| 167 | return | 167 | return | ||
| 168 | } | 168 | } | ||
| 169 | - | got, err := ports.UnmarshalHello(f.Payload) | 169 | + | got, err := wire.UnmarshalHello(f.Payload) |
| 170 | if err != nil { | 170 | if err != nil { | ||
| 171 | t.Errorf("UnmarshalHello: %v", err) | 171 | t.Errorf("UnmarshalHello: %v", err) | ||
| 172 | return | 172 | return | ||
| @@ -174,20 +174,20 @@ func TestTransportRoundTripAndVersionMismatchFrame(t *testing.T) { | |||||
| 174 | if got.Version == protocol.Version { | 174 | if got.Version == protocol.Version { | ||
| 175 | t.Errorf("test did not send a mismatched version") | 175 | t.Errorf("test did not send a mismatched version") | ||
| 176 | } | 176 | } | ||
| 177 | - | _ = server.Send(ports.Frame{Type: ports.MsgError, Payload: ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "protocol version mismatch"})}) | 177 | + | _ = server.Send(wire.Frame{Type: wire.MsgError, Payload: wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "protocol version mismatch"})}) |
| 178 | }() | 178 | }() | ||
| 179 | 179 | ||||
| 180 | - | if err := client.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}); err != nil { | 180 | + | if err := client.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}); err != nil { |
| 181 | t.Fatalf("client Send: %v", err) | 181 | t.Fatalf("client Send: %v", err) | ||
| 182 | } | 182 | } | ||
| 183 | reply, err := client.Recv() | 183 | reply, err := client.Recv() | ||
| 184 | if err != nil { | 184 | if err != nil { | ||
| 185 | t.Fatalf("client Recv: %v", err) | 185 | t.Fatalf("client Recv: %v", err) | ||
| 186 | } | 186 | } | ||
| 187 | - | if reply.Type != ports.MsgError { | 187 | + | if reply.Type != wire.MsgError { |
| 188 | t.Fatalf("reply type = %d, want MsgError", reply.Type) | 188 | t.Fatalf("reply type = %d, want MsgError", reply.Type) | ||
| 189 | } | 189 | } | ||
| 190 | - | em, err := ports.UnmarshalErrorMsg(reply.Payload) | 190 | + | em, err := wire.UnmarshalErrorMsg(reply.Payload) |
| 191 | if err != nil { | 191 | if err != nil { | ||
| 192 | t.Fatalf("UnmarshalErrorMsg: %v", err) | 192 | t.Fatalf("UnmarshalErrorMsg: %v", err) | ||
| 193 | } | 193 | } | ||
| @@ -205,35 +205,35 @@ func TestTransportRejectsZeroLengthFrame(t *testing.T) { | |||||
| 205 | } | 205 | } | ||
| 206 | 206 | ||||
| 207 | func TestTransportUsesCanonicalFrameMaximum(t *testing.T) { | 207 | func TestTransportUsesCanonicalFrameMaximum(t *testing.T) { | ||
| 208 | - | boundaryPayload := make([]byte, ports.MaxFrameLen-1) | 208 | + | boundaryPayload := make([]byte, wire.MaxFrameLen-1) |
| 209 | boundaryWire := &bytes.Buffer{} | 209 | boundaryWire := &bytes.Buffer{} | ||
| 210 | boundarySend := NewTransport(nil, boundaryWire, nil) | 210 | boundarySend := NewTransport(nil, boundaryWire, nil) | ||
| 211 | - | if err := boundarySend.Send(ports.Frame{Type: ports.MsgOutput, Payload: boundaryPayload}); err != nil { | 211 | + | if err := boundarySend.Send(wire.Frame{Type: wire.MsgOutput, Payload: boundaryPayload}); err != nil { |
| 212 | t.Fatalf("boundary Send error = %v", err) | 212 | t.Fatalf("boundary Send error = %v", err) | ||
| 213 | } | 213 | } | ||
| 214 | - | if got := binary.BigEndian.Uint32(boundaryWire.Bytes()[:frameHeaderLen]); got != ports.MaxFrameLen { | 214 | + | if got := binary.BigEndian.Uint32(boundaryWire.Bytes()[:frameHeaderLen]); got != wire.MaxFrameLen { |
| 215 | - | t.Fatalf("boundary frame length = %d, want %d", got, ports.MaxFrameLen) | 215 | + | t.Fatalf("boundary frame length = %d, want %d", got, wire.MaxFrameLen) |
| 216 | } | 216 | } | ||
| 217 | boundaryRecv := NewTransport(bytes.NewReader(boundaryWire.Bytes()), io.Discard, nil) | 217 | boundaryRecv := NewTransport(bytes.NewReader(boundaryWire.Bytes()), io.Discard, nil) | ||
| 218 | boundaryFrame, err := boundaryRecv.Recv() | 218 | boundaryFrame, err := boundaryRecv.Recv() | ||
| 219 | if err != nil { | 219 | if err != nil { | ||
| 220 | t.Fatalf("boundary Recv error = %v", err) | 220 | t.Fatalf("boundary Recv error = %v", err) | ||
| 221 | } | 221 | } | ||
| 222 | - | if boundaryFrame.Type != ports.MsgOutput || len(boundaryFrame.Payload) != len(boundaryPayload) { | 222 | + | if boundaryFrame.Type != wire.MsgOutput || len(boundaryFrame.Payload) != len(boundaryPayload) { |
| 223 | - | t.Fatalf("boundary frame = type %d, payload %d bytes; want type %d, payload %d bytes", boundaryFrame.Type, len(boundaryFrame.Payload), ports.MsgOutput, len(boundaryPayload)) | 223 | + | t.Fatalf("boundary frame = type %d, payload %d bytes; want type %d, payload %d bytes", boundaryFrame.Type, len(boundaryFrame.Payload), wire.MsgOutput, len(boundaryPayload)) |
| 224 | } | 224 | } | ||
| 225 | if !bytes.Equal(boundaryFrame.Payload, boundaryPayload) { | 225 | if !bytes.Equal(boundaryFrame.Payload, boundaryPayload) { | ||
| 226 | t.Fatal("boundary payload was corrupted") | 226 | t.Fatal("boundary payload was corrupted") | ||
| 227 | } | 227 | } | ||
| 228 | 228 | ||||
| 229 | send := NewTransport(nil, io.Discard, nil) | 229 | send := NewTransport(nil, io.Discard, nil) | ||
| 230 | - | err = send.Send(ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, ports.MaxFrameLen)}) | 230 | + | err = send.Send(wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, wire.MaxFrameLen)}) |
| 231 | if !errors.Is(err, ErrFrameTooLarge) { | 231 | if !errors.Is(err, ErrFrameTooLarge) { | ||
| 232 | t.Fatalf("Send error = %v, want ErrFrameTooLarge", err) | 232 | t.Fatalf("Send error = %v, want ErrFrameTooLarge", err) | ||
| 233 | } | 233 | } | ||
| 234 | 234 | ||||
| 235 | var header [frameHeaderLen]byte | 235 | var header [frameHeaderLen]byte | ||
| 236 | - | binary.BigEndian.PutUint32(header[:], ports.MaxFrameLen+1) | 236 | + | binary.BigEndian.PutUint32(header[:], wire.MaxFrameLen+1) |
| 237 | recv := NewTransport(bytes.NewReader(header[:]), io.Discard, nil) | 237 | recv := NewTransport(bytes.NewReader(header[:]), io.Discard, nil) | ||
| 238 | _, err = recv.Recv() | 238 | _, err = recv.Recv() | ||
| 239 | if !errors.Is(err, ErrFrameTooLarge) { | 239 | if !errors.Is(err, ErrFrameTooLarge) { | ||
M internal/app/cmd.go +6 -5
| @@ -14,6 +14,7 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/adapters/ipc" | 14 | "github.com/bnema/vev/internal/adapters/ipc" | ||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | "github.com/bnema/vev/internal/protocol" | 16 | "github.com/bnema/vev/internal/protocol" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 17 | commandusecase "github.com/bnema/vev/internal/usecase/command" | 18 | commandusecase "github.com/bnema/vev/internal/usecase/command" | ||
| 18 | "github.com/bnema/vev/internal/usecase/daemon" | 19 | "github.com/bnema/vev/internal/usecase/daemon" | ||
| 19 | ) | 20 | ) | ||
| @@ -170,7 +171,7 @@ func runCmdWithDeps(ctx context.Context, invocation cmdInvocation, deps cmdDeps) | |||||
| 170 | return usagef("--self requires running inside a vev pane") | 171 | return usagef("--self requires running inside a vev pane") | ||
| 171 | } | 172 | } | ||
| 172 | 173 | ||||
| 173 | - | if _, err := ports.MarshalCommandRequest(request); errors.Is(err, ports.ErrTooManyCommandArgs) { | 174 | + | if _, err := wire.MarshalCommandRequest(request); errors.Is(err, wire.ErrTooManyCommandArgs) { |
| 174 | return usagef("too many command arguments") | 175 | return usagef("too many command arguments") | ||
| 175 | } else if err != nil { | 176 | } else if err != nil { | ||
| 176 | return fmt.Errorf("encoding command: %w", err) | 177 | return fmt.Errorf("encoding command: %w", err) | ||
| @@ -190,12 +191,12 @@ func runCmdWithDeps(ctx context.Context, invocation cmdInvocation, deps cmdDeps) | |||||
| 190 | const generation = uint64(1) | 191 | const generation = uint64(1) | ||
| 191 | requestID, outcome := tracker.Publish(generation) | 192 | requestID, outcome := tracker.Publish(generation) | ||
| 192 | request.RequestID = requestID | 193 | request.RequestID = requestID | ||
| 193 | - | payload, err := ports.MarshalCommandRequest(request) | 194 | + | payload, err := wire.MarshalCommandRequest(request) |
| 194 | if err != nil { | 195 | if err != nil { | ||
| 195 | tracker.Remove(requestID, generation) | 196 | tracker.Remove(requestID, generation) | ||
| 196 | return fmt.Errorf("encoding command: %w", err) | 197 | return fmt.Errorf("encoding command: %w", err) | ||
| 197 | } | 198 | } | ||
| 198 | - | if err := transport.Send(ports.Frame{Type: ports.MsgCommand, Payload: payload}); err != nil { | 199 | + | if err := transport.Send(wire.Frame{Type: wire.MsgCommand, Payload: payload}); err != nil { |
| 199 | tracker.Remove(requestID, generation) | 200 | tracker.Remove(requestID, generation) | ||
| 200 | return &exitCoded{code: 3, err: fmt.Errorf("sending command: %w", err)} | 201 | return &exitCoded{code: 3, err: fmt.Errorf("sending command: %w", err)} | ||
| 201 | } | 202 | } | ||
| @@ -205,11 +206,11 @@ func runCmdWithDeps(ctx context.Context, invocation cmdInvocation, deps cmdDeps) | |||||
| 205 | tracker.Fail(requestID, generation, fmt.Errorf("reading command reply: %w", recvErr)) | 206 | tracker.Fail(requestID, generation, fmt.Errorf("reading command reply: %w", recvErr)) | ||
| 206 | return | 207 | return | ||
| 207 | } | 208 | } | ||
| 208 | - | if reply.Type != ports.MsgCommandResult { | 209 | + | if reply.Type != wire.MsgCommandResult { |
| 209 | tracker.Fail(requestID, generation, fmt.Errorf("unexpected command reply type %d", reply.Type)) | 210 | tracker.Fail(requestID, generation, fmt.Errorf("unexpected command reply type %d", reply.Type)) | ||
| 210 | return | 211 | return | ||
| 211 | } | 212 | } | ||
| 212 | - | result, decodeErr := ports.UnmarshalCommandResult(reply.Payload) | 213 | + | result, decodeErr := wire.UnmarshalCommandResult(reply.Payload) |
| 213 | if decodeErr != nil { | 214 | if decodeErr != nil { | ||
| 214 | tracker.Fail(requestID, generation, fmt.Errorf("decoding command reply: %w", decodeErr)) | 215 | tracker.Fail(requestID, generation, fmt.Errorf("decoding command reply: %w", decodeErr)) | ||
| 215 | return | 216 | return | ||
M internal/app/cmd_test.go +21 -20
| @@ -14,6 +14,7 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 16 | "github.com/bnema/vev/internal/protocol" | 16 | "github.com/bnema/vev/internal/protocol" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 17 | "github.com/bnema/vev/internal/usecase/daemon" | 18 | "github.com/bnema/vev/internal/usecase/daemon" | ||
| 18 | "github.com/stretchr/testify/mock" | 19 | "github.com/stretchr/testify/mock" | ||
| 19 | "github.com/stretchr/testify/require" | 20 | "github.com/stretchr/testify/require" | ||
| @@ -141,14 +142,14 @@ func TestMoveCmdPreservesPositionalArguments(t *testing.T) { | |||||
| 141 | t.Run(tt.slug, func(t *testing.T) { | 142 | t.Run(tt.slug, func(t *testing.T) { | ||
| 142 | parsed, err := parseArgs(append([]string{"cmd", tt.slug}, tt.args...)) | 143 | parsed, err := parseArgs(append([]string{"cmd", tt.slug}, tt.args...)) | ||
| 143 | require.NoError(t, err) | 144 | require.NoError(t, err) | ||
| 144 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | 145 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} |
| 145 | require.NoError(t, runCmdWithDeps(context.Background(), parsed.cmd, cmdDeps{ | 146 | require.NoError(t, runCmdWithDeps(context.Background(), parsed.cmd, cmdDeps{ | ||
| 146 | stdout: io.Discard, | 147 | stdout: io.Discard, | ||
| 147 | getenv: func(string) string { return "" }, | 148 | getenv: func(string) string { return "" }, | ||
| 148 | dial: func(context.Context, string) (ports.Transport, error) { return transport, nil }, | 149 | dial: func(context.Context, string) (ports.Transport, error) { return transport, nil }, | ||
| 149 | })) | 150 | })) | ||
| 150 | require.Len(t, transport.sent, 1) | 151 | require.Len(t, transport.sent, 1) | ||
| 151 | - | request, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | 152 | + | request, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) |
| 152 | require.NoError(t, err) | 153 | require.NoError(t, err) | ||
| 153 | require.Equal(t, tt.slug, request.Slug) | 154 | require.Equal(t, tt.slug, request.Slug) | ||
| 154 | require.Equal(t, tt.args, request.Args) | 155 | require.Equal(t, tt.args, request.Args) | ||
| @@ -158,7 +159,7 @@ func TestMoveCmdPreservesPositionalArguments(t *testing.T) { | |||||
| 158 | } | 159 | } | ||
| 159 | 160 | ||||
| 160 | func TestRemoteCatalogCommandEnsuresDaemon(t *testing.T) { | 161 | func TestRemoteCatalogCommandEnsuresDaemon(t *testing.T) { | ||
| 161 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | 162 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} |
| 162 | ensureCalls := 0 | 163 | ensureCalls := 0 | ||
| 163 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "remote-catalog", jsonOut: true}, cmdDeps{ | 164 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "remote-catalog", jsonOut: true}, cmdDeps{ | ||
| 164 | stdout: io.Discard, | 165 | stdout: io.Discard, | ||
| @@ -184,7 +185,7 @@ func TestMoveCmdInvalidArgumentResultExitsTwo(t *testing.T) { | |||||
| 184 | {slug: "move-tab", args: []string{"work", "extra"}}, | 185 | {slug: "move-tab", args: []string{"work", "extra"}}, | ||
| 185 | } { | 186 | } { | ||
| 186 | t.Run(invocation.slug+"/"+strconv.Itoa(len(invocation.args)), func(t *testing.T) { | 187 | t.Run(invocation.slug+"/"+strconv.Itoa(len(invocation.args)), func(t *testing.T) { | ||
| 187 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{ | 188 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{ |
| 188 | Code: protocol.ErrInvalidCommandArgs, Text: "invalid command arguments", | 189 | Code: protocol.ErrInvalidCommandArgs, Text: "invalid command arguments", | ||
| 189 | })}} | 190 | })}} | ||
| 190 | err := runCmdWithDeps(context.Background(), invocation, cmdDeps{ | 191 | err := runCmdWithDeps(context.Background(), invocation, cmdDeps{ | ||
| @@ -207,14 +208,14 @@ func TestTargetPaneCmdsParseAndUseSelfTarget(t *testing.T) { | |||||
| 207 | t.Run(slug, func(t *testing.T) { | 208 | t.Run(slug, func(t *testing.T) { | ||
| 208 | invocation, err := parseArgs([]string{"cmd", "--self", slug}) | 209 | invocation, err := parseArgs([]string{"cmd", "--self", slug}) | ||
| 209 | require.NoError(t, err) | 210 | require.NoError(t, err) | ||
| 210 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | 211 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} |
| 211 | require.NoError(t, runCmdWithDeps(context.Background(), invocation.cmd, cmdDeps{ | 212 | require.NoError(t, runCmdWithDeps(context.Background(), invocation.cmd, cmdDeps{ | ||
| 212 | stdout: io.Discard, | 213 | stdout: io.Discard, | ||
| 213 | getenv: func(string) string { return "session=work,tab=t_abc,pane=p_def" }, | 214 | getenv: func(string) string { return "session=work,tab=t_abc,pane=p_def" }, | ||
| 214 | dial: func(context.Context, string) (ports.Transport, error) { return transport, nil }, | 215 | dial: func(context.Context, string) (ports.Transport, error) { return transport, nil }, | ||
| 215 | })) | 216 | })) | ||
| 216 | require.Len(t, transport.sent, 1) | 217 | require.Len(t, transport.sent, 1) | ||
| 217 | - | request, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | 218 | + | request, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) |
| 218 | require.NoError(t, err) | 219 | require.NoError(t, err) | ||
| 219 | require.Equal(t, slug, request.Slug) | 220 | require.Equal(t, slug, request.Slug) | ||
| 220 | require.True(t, request.Self) | 221 | require.True(t, request.Self) | ||
| @@ -226,7 +227,7 @@ func TestTargetPaneCmdsParseAndUseSelfTarget(t *testing.T) { | |||||
| 226 | } | 227 | } | ||
| 227 | 228 | ||||
| 228 | func TestRunCmdBuildsOneShotTargetedRequest(t *testing.T) { | 229 | func TestRunCmdBuildsOneShotTargetedRequest(t *testing.T) { | ||
| 229 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true, Output: "done"})}} | 230 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true, Output: "done"})}} |
| 230 | out := new(strings.Builder) | 231 | out := new(strings.Builder) | ||
| 231 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right", self: true}, cmdDeps{ | 232 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right", self: true}, cmdDeps{ | ||
| 232 | stdout: out, | 233 | stdout: out, | ||
| @@ -239,11 +240,11 @@ func TestRunCmdBuildsOneShotTargetedRequest(t *testing.T) { | |||||
| 239 | if len(transport.sent) != 1 || transport.recvCalls != 1 || transport.closeCalls != 1 { | 240 | if len(transport.sent) != 1 || transport.recvCalls != 1 || transport.closeCalls != 1 { | ||
| 240 | t.Fatalf("transport calls: sent=%d recv=%d close=%d", len(transport.sent), transport.recvCalls, transport.closeCalls) | 241 | t.Fatalf("transport calls: sent=%d recv=%d close=%d", len(transport.sent), transport.recvCalls, transport.closeCalls) | ||
| 241 | } | 242 | } | ||
| 242 | - | req, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | 243 | + | req, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) |
| 243 | if err != nil { | 244 | if err != nil { | ||
| 244 | t.Fatalf("decode request: %v", err) | 245 | t.Fatalf("decode request: %v", err) | ||
| 245 | } | 246 | } | ||
| 246 | - | if transport.sent[0].Type != ports.MsgCommand || req.Slug != "split-right" || !req.Self || req.TargetSession != "old" || req.TargetTab != "t_abc" || req.TargetPane != "p_def" { | 247 | + | if transport.sent[0].Type != wire.MsgCommand || req.Slug != "split-right" || !req.Self || req.TargetSession != "old" || req.TargetTab != "t_abc" || req.TargetPane != "p_def" { |
| 247 | t.Fatalf("request = type %d %+v", transport.sent[0].Type, req) | 248 | t.Fatalf("request = type %d %+v", transport.sent[0].Type, req) | ||
| 248 | } | 249 | } | ||
| 249 | if out.String() != "done\n" { | 250 | if out.String() != "done\n" { | ||
| @@ -252,7 +253,7 @@ func TestRunCmdBuildsOneShotTargetedRequest(t *testing.T) { | |||||
| 252 | } | 253 | } | ||
| 253 | 254 | ||||
| 254 | func TestRunCmdVEVWithoutSelfUsesIDsOnlyAsSessionLocator(t *testing.T) { | 255 | func TestRunCmdVEVWithoutSelfUsesIDsOnlyAsSessionLocator(t *testing.T) { | ||
| 255 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | 256 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} |
| 256 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | 257 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | ||
| 257 | stdout: io.Discard, | 258 | stdout: io.Discard, | ||
| 258 | getenv: func(string) string { return "session=old,tab=t_abc,pane=p_def" }, | 259 | getenv: func(string) string { return "session=old,tab=t_abc,pane=p_def" }, | ||
| @@ -261,7 +262,7 @@ func TestRunCmdVEVWithoutSelfUsesIDsOnlyAsSessionLocator(t *testing.T) { | |||||
| 261 | if err != nil { | 262 | if err != nil { | ||
| 262 | t.Fatalf("runCmdWithDeps: %v", err) | 263 | t.Fatalf("runCmdWithDeps: %v", err) | ||
| 263 | } | 264 | } | ||
| 264 | - | req, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | 265 | + | req, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) |
| 265 | if err != nil { | 266 | if err != nil { | ||
| 266 | t.Fatalf("decode request: %v", err) | 267 | t.Fatalf("decode request: %v", err) | ||
| 267 | } | 268 | } | ||
| @@ -271,7 +272,7 @@ func TestRunCmdVEVWithoutSelfUsesIDsOnlyAsSessionLocator(t *testing.T) { | |||||
| 271 | } | 272 | } | ||
| 272 | 273 | ||||
| 273 | func TestRunCmdExplicitSessionDoesNotUseEnvIDsWithoutSelf(t *testing.T) { | 274 | func TestRunCmdExplicitSessionDoesNotUseEnvIDsWithoutSelf(t *testing.T) { | ||
| 274 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | 275 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} |
| 275 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "new-tab", session: "current"}, cmdDeps{ | 276 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "new-tab", session: "current"}, cmdDeps{ | ||
| 276 | stdout: io.Discard, | 277 | stdout: io.Discard, | ||
| 277 | getenv: func(string) string { return "session=old,tab=t_abc,pane=p_def" }, | 278 | getenv: func(string) string { return "session=old,tab=t_abc,pane=p_def" }, | ||
| @@ -280,7 +281,7 @@ func TestRunCmdExplicitSessionDoesNotUseEnvIDsWithoutSelf(t *testing.T) { | |||||
| 280 | if err != nil { | 281 | if err != nil { | ||
| 281 | t.Fatalf("runCmdWithDeps: %v", err) | 282 | t.Fatalf("runCmdWithDeps: %v", err) | ||
| 282 | } | 283 | } | ||
| 283 | - | req, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | 284 | + | req, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) |
| 284 | if err != nil { | 285 | if err != nil { | ||
| 285 | t.Fatalf("decode request: %v", err) | 286 | t.Fatalf("decode request: %v", err) | ||
| 286 | } | 287 | } | ||
| @@ -343,7 +344,7 @@ func TestRunCmdTimesOutPendingRequest(t *testing.T) { | |||||
| 343 | if ExitCode(err) != 3 || !errors.Is(err, daemon.ErrCommandRequestTimeout) { | 344 | if ExitCode(err) != 3 || !errors.Is(err, daemon.ErrCommandRequestTimeout) { | ||
| 344 | t.Fatalf("timeout error=%v code=%d", err, ExitCode(err)) | 345 | t.Fatalf("timeout error=%v code=%d", err, ExitCode(err)) | ||
| 345 | } | 346 | } | ||
| 346 | - | request, decodeErr := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | 347 | + | request, decodeErr := wire.UnmarshalCommandRequest(transport.sent[0].Payload) |
| 347 | if decodeErr != nil || request.RequestID == 0 { | 348 | if decodeErr != nil || request.RequestID == 0 { | ||
| 348 | t.Fatalf("request=%+v decode=%v, want non-zero request ID", request, decodeErr) | 349 | t.Fatalf("request=%+v decode=%v, want non-zero request ID", request, decodeErr) | ||
| 349 | } | 350 | } | ||
| @@ -351,7 +352,7 @@ func TestRunCmdTimesOutPendingRequest(t *testing.T) { | |||||
| 351 | 352 | ||||
| 352 | func TestRunCmdZeroRequestIDReplyReturnsDaemonError(t *testing.T) { | 353 | func TestRunCmdZeroRequestIDReplyReturnsDaemonError(t *testing.T) { | ||
| 353 | const want = "daemon error" | 354 | const want = "daemon error" | ||
| 354 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{ | 355 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{ |
| 355 | Code: protocol.ErrInternal, Text: want, | 356 | Code: protocol.ErrInternal, Text: want, | ||
| 356 | })}} | 357 | })}} | ||
| 357 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | 358 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | ||
| @@ -415,7 +416,7 @@ func TestRunCmdClassifiesDaemonCommandErrors(t *testing.T) { | |||||
| 415 | } | 416 | } | ||
| 416 | for _, tt := range tests { | 417 | for _, tt := range tests { | ||
| 417 | t.Run(tt.name, func(t *testing.T) { | 418 | t.Run(tt.name, func(t *testing.T) { | ||
| 418 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(tt.result)}} | 419 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(tt.result)}} |
| 419 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | 420 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | ||
| 420 | stdout: io.Discard, | 421 | stdout: io.Discard, | ||
| 421 | getenv: func(string) string { return "" }, | 422 | getenv: func(string) string { return "" }, | ||
| @@ -429,8 +430,8 @@ func TestRunCmdClassifiesDaemonCommandErrors(t *testing.T) { | |||||
| 429 | } | 430 | } | ||
| 430 | 431 | ||||
| 431 | type cmdTestTransport struct { | 432 | type cmdTestTransport struct { | ||
| 432 | - | sent []ports.Frame | 433 | + | sent []wire.Frame |
| 433 | - | recv ports.Frame | 434 | + | recv wire.Frame |
| 434 | recvErr error | 435 | recvErr error | ||
| 435 | recvCalls int | 436 | recvCalls int | ||
| 436 | closeCalls int | 437 | closeCalls int | ||
| @@ -438,12 +439,12 @@ type cmdTestTransport struct { | |||||
| 438 | recvGate <-chan struct{} | 439 | recvGate <-chan struct{} | ||
| 439 | } | 440 | } | ||
| 440 | 441 | ||||
| 441 | - | func (t *cmdTestTransport) Send(frame ports.Frame) error { | 442 | + | func (t *cmdTestTransport) Send(frame wire.Frame) error { |
| 442 | t.sent = append(t.sent, frame) | 443 | t.sent = append(t.sent, frame) | ||
| 443 | return nil | 444 | return nil | ||
| 444 | } | 445 | } | ||
| 445 | 446 | ||||
| 446 | - | func (t *cmdTestTransport) Recv() (ports.Frame, error) { | 447 | + | func (t *cmdTestTransport) Recv() (wire.Frame, error) { |
| 447 | t.recvCalls++ | 448 | t.recvCalls++ | ||
| 448 | if t.recvStarted != nil { | 449 | if t.recvStarted != nil { | ||
| 449 | close(t.recvStarted) | 450 | close(t.recvStarted) | ||
M internal/app/daemon_integration_test.go +38 -37
| @@ -29,6 +29,7 @@ import ( | |||||
| 29 | "github.com/bnema/vev/internal/persist" | 29 | "github.com/bnema/vev/internal/persist" | ||
| 30 | "github.com/bnema/vev/internal/ports" | 30 | "github.com/bnema/vev/internal/ports" | ||
| 31 | "github.com/bnema/vev/internal/protocol" | 31 | "github.com/bnema/vev/internal/protocol" | ||
| 32 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 32 | "github.com/bnema/vev/internal/usecase/daemon" | 33 | "github.com/bnema/vev/internal/usecase/daemon" | ||
| 33 | "github.com/bnema/vev/internal/usecase/recovery" | 34 | "github.com/bnema/vev/internal/usecase/recovery" | ||
| 34 | ) | 35 | ) | ||
| @@ -64,10 +65,10 @@ func startDaemonInDir(t *testing.T, dir string, opts ...daemon.Option) (string, | |||||
| 64 | 65 | ||||
| 65 | // pump wires a background Recv pump to a transport so tests can await frames | 66 | // pump wires a background Recv pump to a transport so tests can await frames | ||
| 66 | // with a timeout (ports.Transport has no read deadline). | 67 | // with a timeout (ports.Transport has no read deadline). | ||
| 67 | - | type pump struct{ ch chan ports.Frame } | 68 | + | type pump struct{ ch chan wire.Frame } |
| 68 | 69 | ||||
| 69 | func recvPump(tr ports.Transport) *pump { | 70 | func recvPump(tr ports.Transport) *pump { | ||
| 70 | - | p := &pump{ch: make(chan ports.Frame, 128)} | 71 | + | p := &pump{ch: make(chan wire.Frame, 128)} |
| 71 | go func() { | 72 | go func() { | ||
| 72 | for { | 73 | for { | ||
| 73 | f, err := tr.Recv() | 74 | f, err := tr.Recv() | ||
| @@ -92,12 +93,12 @@ func attachWithEnvironment(t *testing.T, dir string, intent uint8, name string, | |||||
| 92 | tr, err := ipc.DialContext(context.Background(), dir) | 93 | tr, err := ipc.DialContext(context.Background(), dir) | ||
| 93 | require.NoError(t, err) | 94 | require.NoError(t, err) | ||
| 94 | hello := protocol.Hello{Version: protocol.Version, Intent: intent, Name: name, Size: sz, TermEnv: "xterm-256color", TrueColor: true, Env: env} | 95 | hello := protocol.Hello{Version: protocol.Version, Intent: intent, Name: name, Size: sz, TermEnv: "xterm-256color", TrueColor: true, Env: env} | ||
| 95 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)})) | 96 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)})) |
| 96 | p := recvPump(tr) | 97 | p := recvPump(tr) | ||
| 97 | select { | 98 | select { | ||
| 98 | case f, ok := <-p.ch: | 99 | case f, ok := <-p.ch: | ||
| 99 | require.True(t, ok, "connection closed before welcome") | 100 | require.True(t, ok, "connection closed before welcome") | ||
| 100 | - | require.Equal(t, ports.MsgWelcome, f.Type) | 101 | + | require.Equal(t, wire.MsgWelcome, f.Type) |
| 101 | case <-time.After(3 * time.Second): | 102 | case <-time.After(3 * time.Second): | ||
| 102 | t.Fatal("timed out waiting for welcome") | 103 | t.Fatal("timed out waiting for welcome") | ||
| 103 | } | 104 | } | ||
| @@ -109,11 +110,11 @@ func listRemoteSessions(t *testing.T, dir string) protocol.Sessions { | |||||
| 109 | tr, err := ipc.DialContext(context.Background(), dir) | 110 | tr, err := ipc.DialContext(context.Background(), dir) | ||
| 110 | require.NoError(t, err) | 111 | require.NoError(t, err) | ||
| 111 | defer func() { _ = tr.Close() }() | 112 | defer func() { _ = tr.Close() }() | ||
| 112 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})})) | 113 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})})) |
| 113 | f, err := tr.Recv() | 114 | f, err := tr.Recv() | ||
| 114 | require.NoError(t, err) | 115 | require.NoError(t, err) | ||
| 115 | - | require.Equal(t, ports.MsgSessions, f.Type) | 116 | + | require.Equal(t, wire.MsgSessions, f.Type) |
| 116 | - | sessions, err := ports.UnmarshalSessions(f.Payload) | 117 | + | sessions, err := wire.UnmarshalSessions(f.Payload) |
| 117 | require.NoError(t, err) | 118 | require.NoError(t, err) | ||
| 118 | return sessions | 119 | return sessions | ||
| 119 | } | 120 | } | ||
| @@ -124,7 +125,7 @@ func killAll(dir string) error { | |||||
| 124 | return err | 125 | return err | ||
| 125 | } | 126 | } | ||
| 126 | defer func() { _ = tr.Close() }() | 127 | defer func() { _ = tr.Close() }() | ||
| 127 | - | if err := tr.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})}); err != nil { | 128 | + | if err := tr.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})}); err != nil { |
| 128 | return err | 129 | return err | ||
| 129 | } | 130 | } | ||
| 130 | _, err = tr.Recv() | 131 | _, err = tr.Recv() | ||
| @@ -153,8 +154,8 @@ func awaitScreenText(t *testing.T, p *pump, sz domain.Size, want string) string | |||||
| 153 | if !ok { | 154 | if !ok { | ||
| 154 | t.Fatalf("connection closed before %q appeared; screen=%q", want, screenText(screen)) | 155 | t.Fatalf("connection closed before %q appeared; screen=%q", want, screenText(screen)) | ||
| 155 | } | 156 | } | ||
| 156 | - | if f.Type == ports.MsgOutput { | 157 | + | if f.Type == wire.MsgOutput { |
| 157 | - | o, err := ports.UnmarshalOutput(f.Payload) | 158 | + | o, err := wire.UnmarshalOutput(f.Payload) |
| 158 | require.NoError(t, err) | 159 | require.NoError(t, err) | ||
| 159 | screen.Write(o.Data) | 160 | screen.Write(o.Data) | ||
| 160 | text := screenText(screen) | 161 | text := screenText(screen) | ||
| @@ -178,8 +179,8 @@ func assertNoTextAfterInput(t *testing.T, p *pump, sz domain.Size, absent string | |||||
| 178 | if !ok { | 179 | if !ok { | ||
| 179 | return | 180 | return | ||
| 180 | } | 181 | } | ||
| 181 | - | if f.Type == ports.MsgOutput { | 182 | + | if f.Type == wire.MsgOutput { |
| 182 | - | o, err := ports.UnmarshalOutput(f.Payload) | 183 | + | o, err := wire.UnmarshalOutput(f.Payload) |
| 183 | require.NoError(t, err) | 184 | require.NoError(t, err) | ||
| 184 | screen.Write(o.Data) | 185 | screen.Write(o.Data) | ||
| 185 | require.NotContains(t, screenText(screen), absent) | 186 | require.NotContains(t, screenText(screen), absent) | ||
| @@ -214,7 +215,7 @@ func shellFixture(t *testing.T, label string) string { | |||||
| 214 | func assertChildEnvironment(t *testing.T, tr ports.Transport, p *pump, sz domain.Size, wantTestEnv, wantShell, wantRuntimeDir, wantWayland string) { | 215 | func assertChildEnvironment(t *testing.T, tr ports.Transport, p *pump, sz domain.Size, wantTestEnv, wantShell, wantRuntimeDir, wantWayland string) { | ||
| 215 | t.Helper() | 216 | t.Helper() | ||
| 216 | command := "printf '\\033[2J\\033[H'; printf 'VEV_TEST_ENV=%s SHELL=%s XDG_RUNTIME_DIR=%s WAYLAND_DISPLAY=%s TERM=%s COLORTERM=%s TERM_PROGRAM=%s VEV_PREFIX=%.24s\\n' \"$VEV_TEST_ENV\" \"${SHELL##*/}\" \"$XDG_RUNTIME_DIR\" \"$WAYLAND_DISPLAY\" \"$TERM\" \"$COLORTERM\" \"$TERM_PROGRAM\" \"$VEV\"\n" | 217 | command := "printf '\\033[2J\\033[H'; printf 'VEV_TEST_ENV=%s SHELL=%s XDG_RUNTIME_DIR=%s WAYLAND_DISPLAY=%s TERM=%s COLORTERM=%s TERM_PROGRAM=%s VEV_PREFIX=%.24s\\n' \"$VEV_TEST_ENV\" \"${SHELL##*/}\" \"$XDG_RUNTIME_DIR\" \"$WAYLAND_DISPLAY\" \"$TERM\" \"$COLORTERM\" \"$TERM_PROGRAM\" \"$VEV\"\n" | ||
| 217 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(command)})})) | 218 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(command)})})) |
| 218 | text := awaitScreenText(t, p, sz, "TERM_PROGRAM=vev") | 219 | text := awaitScreenText(t, p, sz, "TERM_PROGRAM=vev") | ||
| 219 | for _, want := range []string{ | 220 | for _, want := range []string{ | ||
| 220 | "VEV_TEST_ENV=" + wantTestEnv, | 221 | "VEV_TEST_ENV=" + wantTestEnv, | ||
| @@ -255,9 +256,9 @@ func TestIntegration_AttachEnvironmentRefreshesFuturePTYChildren(t *testing.T) { | |||||
| 255 | // The first shell was already running, so it retains its original environment. | 256 | // The first shell was already running, so it retains its original environment. | ||
| 256 | assertChildEnvironment(t, tr2, p2, sz, "first", firstShell, "/run/first", "wayland-first") | 257 | assertChildEnvironment(t, tr2, p2, sz, "first", firstShell, "/run/first", "wayland-first") | ||
| 257 | 258 | ||||
| 258 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | 259 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) |
| 259 | awaitText(t, p2, sz, "Commands") | 260 | awaitText(t, p2, sz, "Commands") | ||
| 260 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | 261 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) |
| 261 | awaitText(t, p2, sz, "SHELL_COMMAND=second") | 262 | awaitText(t, p2, sz, "SHELL_COMMAND=second") | ||
| 262 | assertChildEnvironment(t, tr2, p2, sz, "second", secondShell, "/run/second", "wayland-second") | 263 | assertChildEnvironment(t, tr2, p2, sz, "second", secondShell, "/run/second", "wayland-second") | ||
| 263 | } | 264 | } | ||
| @@ -288,17 +289,17 @@ func TestIntegration_TwoAttachmentsReceiveSharedMutationPTYOutput(t *testing.T) | |||||
| 288 | 289 | ||||
| 289 | // The second attachment mutates shared tab state. Its newly opened PTY must | 290 | // The second attachment mutates shared tab state. Its newly opened PTY must | ||
| 290 | // also be rendered to that attachment, not only to the coordinator primary. | 291 | // also be rendered to that attachment, not only to the coordinator primary. | ||
| 291 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | 292 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) |
| 292 | awaitText(t, p2, sz, "Commands") | 293 | awaitText(t, p2, sz, "Commands") | ||
| 293 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | 294 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) |
| 294 | awaitText(t, p2, sz, "SHELL_COMMAND=second") | 295 | awaitText(t, p2, sz, "SHELL_COMMAND=second") | ||
| 295 | 296 | ||||
| 296 | // Each attachment owns its selected tab. Move the first attachment to the | 297 | // Each attachment owns its selected tab. Move the first attachment to the | ||
| 297 | // new PTY before releasing its gate, so the fresh PTY output must reach both | 298 | // new PTY before releasing its gate, so the fresh PTY output must reach both | ||
| 298 | // views rather than only being recovered by a later first paint. | 299 | // views rather than only being recovered by a later first paint. | ||
| 299 | - | require.NoError(t, tr1.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b2")})})) | 300 | + | require.NoError(t, tr1.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b2")})})) |
| 300 | awaitText(t, p1, sz, "SHELL_COMMAND=second") | 301 | awaitText(t, p1, sz, "SHELL_COMMAND=second") | ||
| 301 | - | require.NoError(t, tr1.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("go\n")})})) | 302 | + | require.NoError(t, tr1.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("go\n")})})) |
| 302 | awaitText(t, p2, sz, sharedOutput) | 303 | awaitText(t, p2, sz, sharedOutput) | ||
| 303 | awaitText(t, p1, sz, sharedOutput) | 304 | awaitText(t, p1, sz, sharedOutput) | ||
| 304 | } | 305 | } | ||
| @@ -320,7 +321,7 @@ func TestIntegration_InputRoundtrip(t *testing.T) { | |||||
| 320 | tr, p := attach(t, dir, protocol.IntentEphemeral, "", sz) | 321 | tr, p := attach(t, dir, protocol.IntentEphemeral, "", sz) | ||
| 321 | defer func() { _ = tr.Close() }() | 322 | defer func() { _ = tr.Close() }() | ||
| 322 | 323 | ||||
| 323 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("PINGPONG\n")})})) | 324 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("PINGPONG\n")})})) |
| 324 | awaitText(t, p, sz, "PINGPONG") | 325 | awaitText(t, p, sz, "PINGPONG") | ||
| 325 | } | 326 | } | ||
| 326 | 327 | ||||
| @@ -332,10 +333,10 @@ func TestIntegration_CommandPaletteCreatesTab(t *testing.T) { | |||||
| 332 | defer func() { _ = tr.Close() }() | 333 | defer func() { _ = tr.Close() }() | ||
| 333 | awaitText(t, p, sz, "READY") | 334 | awaitText(t, p, sz, "READY") | ||
| 334 | 335 | ||||
| 335 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | 336 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) |
| 336 | awaitText(t, p, sz, "Commands") | 337 | awaitText(t, p, sz, "Commands") | ||
| 337 | 338 | ||||
| 338 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | 339 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) |
| 339 | // Tab labels are enriched with the focused pane's title; with no process | 340 | // Tab labels are enriched with the focused pane's title; with no process | ||
| 340 | // inspector wired in this test, that title falls back to the shell's | 341 | // inspector wired in this test, that title falls back to the shell's | ||
| 341 | // basename ("sh"). | 342 | // basename ("sh"). | ||
| @@ -352,24 +353,24 @@ func TestIntegration_CommandPaletteRenamesEphemeralSession(t *testing.T) { | |||||
| 352 | text := awaitScreenText(t, p, sz, "READY") | 353 | text := awaitScreenText(t, p, sz, "READY") | ||
| 353 | require.Contains(t, text, " 0* ") | 354 | require.Contains(t, text, " 0* ") | ||
| 354 | 355 | ||||
| 355 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | 356 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) |
| 356 | awaitText(t, p, sz, "Commands") | 357 | awaitText(t, p, sz, "Commands") | ||
| 357 | 358 | ||||
| 358 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("RNS\r")})})) | 359 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("RNS\r")})})) |
| 359 | awaitText(t, p, sz, "Rename session") | 360 | awaitText(t, p, sz, "Rename session") | ||
| 360 | 361 | ||||
| 361 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x7fwork\r")})})) | 362 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x7fwork\r")})})) |
| 362 | text = awaitScreenText(t, p, sz, " work ") | 363 | text = awaitScreenText(t, p, sz, " work ") | ||
| 363 | require.NotContains(t, text, "work*") | 364 | require.NotContains(t, text, "work*") | ||
| 364 | 365 | ||||
| 365 | listTr, err := ipc.DialContext(context.Background(), dir) | 366 | listTr, err := ipc.DialContext(context.Background(), dir) | ||
| 366 | require.NoError(t, err) | 367 | require.NoError(t, err) | ||
| 367 | defer func() { _ = listTr.Close() }() | 368 | defer func() { _ = listTr.Close() }() | ||
| 368 | - | require.NoError(t, listTr.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})})) | 369 | + | require.NoError(t, listTr.Send(wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})})) |
| 369 | f, err := listTr.Recv() | 370 | f, err := listTr.Recv() | ||
| 370 | require.NoError(t, err) | 371 | require.NoError(t, err) | ||
| 371 | - | require.Equal(t, ports.MsgSessions, f.Type) | 372 | + | require.Equal(t, wire.MsgSessions, f.Type) |
| 372 | - | sessions, err := ports.UnmarshalSessions(f.Payload) | 373 | + | sessions, err := wire.UnmarshalSessions(f.Payload) |
| 373 | require.NoError(t, err) | 374 | require.NoError(t, err) | ||
| 374 | require.NotEmpty(t, sessions.Sessions) | 375 | require.NotEmpty(t, sessions.Sessions) | ||
| 375 | require.Equal(t, "work", sessions.Sessions[0].Name) | 376 | require.Equal(t, "work", sessions.Sessions[0].Name) | ||
| @@ -385,7 +386,7 @@ func TestIntegration_AltCWithoutPaletteDoesNotCreateTab(t *testing.T) { | |||||
| 385 | text := awaitScreenText(t, p, sz, "READY") | 386 | text := awaitScreenText(t, p, sz, "READY") | ||
| 386 | require.NotContains(t, text, " 1 2 ") | 387 | require.NotContains(t, text, " 1 2 ") | ||
| 387 | 388 | ||||
| 388 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1bc")})})) | 389 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1bc")})})) |
| 389 | assertNoTextAfterInput(t, p, sz, " 1 2 ") | 390 | assertNoTextAfterInput(t, p, sz, " 1 2 ") | ||
| 390 | } | 391 | } | ||
| 391 | 392 | ||||
| @@ -802,7 +803,7 @@ func publishRestorableCheckpoint(t *testing.T, stateDir string, repository *snap | |||||
| 802 | go func() { served <- d.Serve(ctx, listener) }() | 803 | go func() { served <- d.Serve(ctx, listener) }() | ||
| 803 | 804 | ||||
| 804 | tr, _ := attach(t, runtimeDir, protocol.IntentNew, name, domain.Size{Cols: 80, Rows: 24}) | 805 | tr, _ := attach(t, runtimeDir, protocol.IntentNew, name, domain.Size{Cols: 80, Rows: 24}) | ||
| 805 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("checkpoint me\n")})})) | 806 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("checkpoint me\n")})})) |
| 806 | require.Eventually(t, func() bool { | 807 | require.Eventually(t, func() bool { | ||
| 807 | record, ok, _ := opened.Catalogue.Record(name) | 808 | record, ok, _ := opened.Catalogue.Record(name) | ||
| 808 | return ok && record.Committed != nil && record.DegradedReason == "" | 809 | return ok && record.Committed != nil && record.DegradedReason == "" | ||
| @@ -888,7 +889,7 @@ func runBlockedSnapshotWriterShutdown(t *testing.T) blockedSnapshotWriterShutdow | |||||
| 888 | 889 | ||||
| 889 | awaitLifecycleStage(t, listenerReady, "daemon listener") | 890 | awaitLifecycleStage(t, listenerReady, "daemon listener") | ||
| 890 | tr, _ := attach(t, runtimeDir, protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24}) | 891 | tr, _ := attach(t, runtimeDir, protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24}) | ||
| 891 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("dirty state\n")})})) | 892 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("dirty state\n")})})) |
| 892 | awaitLifecycleStage(t, repository.entered, "snapshot publication") | 893 | awaitLifecycleStage(t, repository.entered, "snapshot publication") | ||
| 893 | require.NoError(t, tr.Close()) | 894 | require.NoError(t, tr.Close()) | ||
| 894 | require.Eventually(t, func() bool { | 895 | require.Eventually(t, func() bool { | ||
| @@ -1240,11 +1241,11 @@ func (c *lifecycleControlledCatalogue) Close() error { | |||||
| 1240 | 1241 | ||||
| 1241 | type integrationTransport struct{} | 1242 | type integrationTransport struct{} | ||
| 1242 | 1243 | ||||
| 1243 | - | func (*integrationTransport) Send(ports.Frame) error { return nil } | 1244 | + | func (*integrationTransport) Send(wire.Frame) error { return nil } |
| 1244 | - | func (*integrationTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 1245 | + | func (*integrationTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 1245 | - | func (*integrationTransport) Close() error { return nil } | 1246 | + | func (*integrationTransport) Close() error { return nil } |
| 1246 | - | func (*integrationTransport) LocalAddr() net.Addr { return nil } | 1247 | + | func (*integrationTransport) LocalAddr() net.Addr { return nil } |
| 1247 | - | func (*integrationTransport) RemoteAddr() net.Addr { return nil } | 1248 | + | func (*integrationTransport) RemoteAddr() net.Addr { return nil } |
| 1248 | 1249 | ||||
| 1249 | func TestIntegration_KillAllShutsDownDaemon(t *testing.T) { | 1250 | func TestIntegration_KillAllShutsDownDaemon(t *testing.T) { | ||
| 1250 | sz := domain.Size{Cols: 80, Rows: 24} | 1251 | sz := domain.Size{Cols: 80, Rows: 24} | ||
| @@ -1258,7 +1259,7 @@ func TestIntegration_KillAllShutsDownDaemon(t *testing.T) { | |||||
| 1258 | killTr, err := ipc.DialContext(context.Background(), dir) | 1259 | killTr, err := ipc.DialContext(context.Background(), dir) | ||
| 1259 | require.NoError(t, err) | 1260 | require.NoError(t, err) | ||
| 1260 | defer func() { _ = killTr.Close() }() | 1261 | defer func() { _ = killTr.Close() }() | ||
| 1261 | - | require.NoError(t, killTr.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})})) | 1262 | + | require.NoError(t, killTr.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})})) |
| 1262 | 1263 | ||||
| 1263 | _, err = killTr.Recv() | 1264 | _, err = killTr.Recv() | ||
| 1264 | require.ErrorIs(t, err, io.EOF) | 1265 | require.ErrorIs(t, err, io.EOF) | ||
M internal/app/final_acceptance_test.go +17 -16
| @@ -9,16 +9,17 @@ import ( | |||||
| 9 | "github.com/bnema/vev/internal/domain" | 9 | "github.com/bnema/vev/internal/domain" | ||
| 10 | "github.com/bnema/vev/internal/ports" | 10 | "github.com/bnema/vev/internal/ports" | ||
| 11 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | "github.com/bnema/vev/internal/usecase/daemon" | 13 | "github.com/bnema/vev/internal/usecase/daemon" | ||
| 13 | "github.com/stretchr/testify/require" | 14 | "github.com/stretchr/testify/require" | ||
| 14 | ) | 15 | ) | ||
| 15 | 16 | ||||
| 16 | func sendAcceptanceInput(t *testing.T, tr ports.Transport, data string) { | 17 | func sendAcceptanceInput(t *testing.T, tr ports.Transport, data string) { | ||
| 17 | t.Helper() | 18 | t.Helper() | ||
| 18 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(data)})})) | 19 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(data)})})) |
| 19 | } | 20 | } | ||
| 20 | 21 | ||||
| 21 | - | func awaitAcceptanceFrame(t *testing.T, p *pump, typ ports.MsgType, predicate func(ports.Frame) bool) ports.Frame { | 22 | + | func awaitAcceptanceFrame(t *testing.T, p *pump, typ wire.MsgType, predicate func(wire.Frame) bool) wire.Frame { |
| 22 | t.Helper() | 23 | t.Helper() | ||
| 23 | deadline := time.NewTimer(5 * time.Second) | 24 | deadline := time.NewTimer(5 * time.Second) | ||
| 24 | defer deadline.Stop() | 25 | defer deadline.Stop() | ||
| @@ -37,35 +38,35 @@ func awaitAcceptanceFrame(t *testing.T, p *pump, typ ports.MsgType, predicate fu | |||||
| 37 | 38 | ||||
| 38 | func awaitAcceptanceCommand(t *testing.T, p *pump, requestID uint64) protocol.CommandResult { | 39 | func awaitAcceptanceCommand(t *testing.T, p *pump, requestID uint64) protocol.CommandResult { | ||
| 39 | t.Helper() | 40 | t.Helper() | ||
| 40 | - | frame := awaitAcceptanceFrame(t, p, ports.MsgCommandResult, func(frame ports.Frame) bool { | 41 | + | frame := awaitAcceptanceFrame(t, p, wire.MsgCommandResult, func(frame wire.Frame) bool { |
| 41 | - | result, err := ports.UnmarshalCommandResult(frame.Payload) | 42 | + | result, err := wire.UnmarshalCommandResult(frame.Payload) |
| 42 | require.NoError(t, err) | 43 | require.NoError(t, err) | ||
| 43 | return result.RequestID == requestID | 44 | return result.RequestID == requestID | ||
| 44 | }) | 45 | }) | ||
| 45 | - | result, err := ports.UnmarshalCommandResult(frame.Payload) | 46 | + | result, err := wire.UnmarshalCommandResult(frame.Payload) |
| 46 | require.NoError(t, err) | 47 | require.NoError(t, err) | ||
| 47 | return result | 48 | return result | ||
| 48 | } | 49 | } | ||
| 49 | 50 | ||||
| 50 | func awaitAcceptanceOutput(t *testing.T, p *pump, predicate func(protocol.Output) bool) protocol.Output { | 51 | func awaitAcceptanceOutput(t *testing.T, p *pump, predicate func(protocol.Output) bool) protocol.Output { | ||
| 51 | t.Helper() | 52 | t.Helper() | ||
| 52 | - | frame := awaitAcceptanceFrame(t, p, ports.MsgOutput, func(frame ports.Frame) bool { | 53 | + | frame := awaitAcceptanceFrame(t, p, wire.MsgOutput, func(frame wire.Frame) bool { |
| 53 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 54 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 54 | require.NoError(t, err) | 55 | require.NoError(t, err) | ||
| 55 | return predicate(output) | 56 | return predicate(output) | ||
| 56 | }) | 57 | }) | ||
| 57 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 58 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 58 | require.NoError(t, err) | 59 | require.NoError(t, err) | ||
| 59 | return output | 60 | return output | ||
| 60 | } | 61 | } | ||
| 61 | 62 | ||||
| 62 | func awaitAcceptanceCommandResult(t *testing.T, tr ports.Transport, p *pump, requestID uint64, slug string) protocol.CommandResult { | 63 | func awaitAcceptanceCommandResult(t *testing.T, tr ports.Transport, p *pump, requestID uint64, slug string) protocol.CommandResult { | ||
| 63 | t.Helper() | 64 | t.Helper() | ||
| 64 | - | payload, err := ports.MarshalCommandRequest(protocol.CommandRequest{ | 65 | + | payload, err := wire.MarshalCommandRequest(protocol.CommandRequest{ |
| 65 | Version: protocol.Version, RequestID: requestID, Attached: true, Slug: slug, | 66 | Version: protocol.Version, RequestID: requestID, Attached: true, Slug: slug, | ||
| 66 | }) | 67 | }) | ||
| 67 | require.NoError(t, err) | 68 | require.NoError(t, err) | ||
| 68 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgCommand, Payload: payload})) | 69 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgCommand, Payload: payload})) |
| 69 | return awaitAcceptanceCommand(t, p, requestID) | 70 | return awaitAcceptanceCommand(t, p, requestID) | ||
| 70 | } | 71 | } | ||
| 71 | 72 | ||||
| @@ -114,25 +115,25 @@ func TestAcceptanceTwoLocalAttachmentsKeepViewsOverTransports(t *testing.T) { | |||||
| 114 | // The resize keeps its attachment-local output stream while recalculating | 115 | // The resize keeps its attachment-local output stream while recalculating | ||
| 115 | // shared PTY/content geometry from the latest valid attachment claim; the | 116 | // shared PTY/content geometry from the latest valid attachment claim; the | ||
| 116 | // peer stream remains independent. | 117 | // peer stream remains independent. | ||
| 117 | - | resizePayload, err := ports.MarshalResize(protocol.Resize{Size: domain.Size{Cols: 100, Rows: 30}}) | 118 | + | resizePayload, err := wire.MarshalResize(protocol.Resize{Size: domain.Size{Cols: 100, Rows: 30}}) |
| 118 | require.NoError(t, err) | 119 | require.NoError(t, err) | ||
| 119 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgResize, Payload: resizePayload})) | 120 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgResize, Payload: resizePayload})) |
| 120 | resized := awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Size == (domain.Size{Cols: 100, Rows: 30}) }) | 121 | resized := awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Size == (domain.Size{Cols: 100, Rows: 30}) }) | ||
| 121 | require.Equal(t, domain.Size{Cols: 100, Rows: 30}, resized.Size) | 122 | require.Equal(t, domain.Size{Cols: 100, Rows: 30}, resized.Size) | ||
| 122 | assertNoTextAfterInput(t, secondPump, size, "FIRST_PANE_INPUT") | 123 | assertNoTextAfterInput(t, secondPump, size, "FIRST_PANE_INPUT") | ||
| 123 | 124 | ||||
| 124 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) | 125 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) |
| 125 | reset := awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Base == 0 && output.Full }) | 126 | reset := awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Base == 0 && output.Full }) | ||
| 126 | require.True(t, reset.Full) | 127 | require.True(t, reset.Full) | ||
| 127 | assertNoTextAfterInput(t, secondPump, size, "FIRST_PANE_INPUT") | 128 | assertNoTextAfterInput(t, secondPump, size, "FIRST_PANE_INPUT") | ||
| 128 | 129 | ||||
| 129 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})})) | 130 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})})) |
| 130 | deadline := time.NewTimer(5 * time.Second) | 131 | deadline := time.NewTimer(5 * time.Second) | ||
| 131 | defer deadline.Stop() | 132 | defer deadline.Stop() | ||
| 132 | for { | 133 | for { | ||
| 133 | select { | 134 | select { | ||
| 134 | case frame := <-firstPump.ch: | 135 | case frame := <-firstPump.ch: | ||
| 135 | - | if frame.Type == ports.MsgDetached { | 136 | + | if frame.Type == wire.MsgDetached { |
| 136 | goto detached | 137 | goto detached | ||
| 137 | } | 138 | } | ||
| 138 | case <-deadline.C: | 139 | case <-deadline.C: | ||
| @@ -173,7 +174,7 @@ func TestAcceptanceAttachedCommandUsesItsConnectionOnly(t *testing.T) { | |||||
| 173 | } | 174 | } | ||
| 174 | 175 | ||||
| 175 | drained: | 176 | drained: | ||
| 176 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) | 177 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) |
| 177 | awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Full && output.Base == 0 }) | 178 | awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Full && output.Base == 0 }) | ||
| 178 | assertNoTextAfterInput(t, secondPump, size, "Commands") | 179 | assertNoTextAfterInput(t, secondPump, size, "Commands") | ||
| 179 | } | 180 | } | ||
M internal/app/remote_final_acceptance_test.go +12 -11
| @@ -16,6 +16,7 @@ import ( | |||||
| 16 | "github.com/bnema/vev/internal/ports" | 16 | "github.com/bnema/vev/internal/ports" | ||
| 17 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 17 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 18 | "github.com/bnema/vev/internal/protocol" | 18 | "github.com/bnema/vev/internal/protocol" | ||
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 19 | "github.com/bnema/vev/internal/usecase/client" | 20 | "github.com/bnema/vev/internal/usecase/client" | ||
| 20 | "github.com/stretchr/testify/require" | 21 | "github.com/stretchr/testify/require" | ||
| 21 | ) | 22 | ) | ||
| @@ -58,17 +59,17 @@ func serveAcceptanceRemote(tr ports.Transport, target string, handoff protocol.A | |||||
| 58 | return | 59 | return | ||
| 59 | } | 60 | } | ||
| 60 | if !welcomed { | 61 | if !welcomed { | ||
| 61 | - | if frame.Type != ports.MsgHello { | 62 | + | if frame.Type != wire.MsgHello { |
| 62 | continue | 63 | continue | ||
| 63 | } | 64 | } | ||
| 64 | - | if err := tr.Send(ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: target})}); err != nil { | 65 | + | if err := tr.Send(wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: target})}); err != nil { |
| 65 | return | 66 | return | ||
| 66 | } | 67 | } | ||
| 67 | welcomed = true | 68 | welcomed = true | ||
| 68 | continue | 69 | continue | ||
| 69 | } | 70 | } | ||
| 70 | if handoff.Endpoint != "" { | 71 | if handoff.Endpoint != "" { | ||
| 71 | - | _ = tr.Send(ports.Frame{Type: ports.MsgAttachTarget, Payload: ports.MarshalAttachTarget(handoff)}) | 72 | + | _ = tr.Send(wire.Frame{Type: wire.MsgAttachTarget, Payload: wire.MarshalAttachTarget(handoff)}) |
| 72 | for { | 73 | for { | ||
| 73 | if _, err := tr.Recv(); err != nil { | 74 | if _, err := tr.Recv(); err != nil { | ||
| 74 | return | 75 | return | ||
| @@ -79,16 +80,16 @@ func serveAcceptanceRemote(tr ports.Transport, target string, handoff protocol.A | |||||
| 79 | if outputs != nil { | 80 | if outputs != nil { | ||
| 80 | outputs <- string(data) | 81 | outputs <- string(data) | ||
| 81 | } | 82 | } | ||
| 82 | - | payload, err := ports.MarshalOutput(protocol.Output{ | 83 | + | payload, err := wire.MarshalOutput(protocol.Output{ |
| 83 | Epoch: 1, New: 1, Full: true, Size: domain.Size{Cols: 80, Rows: 24}, Data: data, | 84 | Epoch: 1, New: 1, Full: true, Size: domain.Size{Cols: 80, Rows: 24}, Data: data, | ||
| 84 | }) | 85 | }) | ||
| 85 | if err != nil { | 86 | if err != nil { | ||
| 86 | return | 87 | return | ||
| 87 | } | 88 | } | ||
| 88 | - | if err := tr.Send(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | 89 | + | if err := tr.Send(wire.Frame{Type: wire.MsgOutput, Payload: payload}); err != nil { |
| 89 | return | 90 | return | ||
| 90 | } | 91 | } | ||
| 91 | - | _ = tr.Send(ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}) | 92 | + | _ = tr.Send(wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}) |
| 92 | for { | 93 | for { | ||
| 93 | if _, err := tr.Recv(); err != nil { | 94 | if _, err := tr.Recv(); err != nil { | ||
| 94 | return | 95 | return | ||
| @@ -150,18 +151,18 @@ func TestAcceptanceRemoteDirectAndPickerUseOnlyRemoteTransports(t *testing.T) { | |||||
| 150 | handoff: protocol.AttachTarget{Endpoint: "picked.example", Session: "picked", Intent: protocol.IntentAttach}, | 151 | handoff: protocol.AttachTarget{Endpoint: "picked.example", Session: "picked", Intent: protocol.IntentAttach}, | ||
| 151 | }).Dial(context.Background()) | 152 | }).Dial(context.Background()) | ||
| 152 | require.NoError(t, err) | 153 | require.NoError(t, err) | ||
| 153 | - | require.NoError(t, wireTransport.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | 154 | + | require.NoError(t, wireTransport.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ |
| 154 | Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, | 155 | Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, | ||
| 155 | })})) | 156 | })})) | ||
| 156 | welcome, err := wireTransport.Recv() | 157 | welcome, err := wireTransport.Recv() | ||
| 157 | require.NoError(t, err) | 158 | require.NoError(t, err) | ||
| 158 | - | require.Equal(t, ports.MsgWelcome, welcome.Type) | 159 | + | require.Equal(t, wire.MsgWelcome, welcome.Type) |
| 159 | - | require.NoError(t, wireTransport.Send(ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(protocol.Theme{})})) | 160 | + | require.NoError(t, wireTransport.Send(wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(protocol.Theme{})})) |
| 160 | attachTarget, err := wireTransport.Recv() | 161 | attachTarget, err := wireTransport.Recv() | ||
| 161 | require.NoError(t, err) | 162 | require.NoError(t, err) | ||
| 162 | - | target, err := ports.UnmarshalAttachTarget(attachTarget.Payload) | 163 | + | target, err := wire.UnmarshalAttachTarget(attachTarget.Payload) |
| 163 | require.NoError(t, err) | 164 | require.NoError(t, err) | ||
| 164 | - | require.Equal(t, ports.MsgAttachTarget, attachTarget.Type) | 165 | + | require.Equal(t, wire.MsgAttachTarget, attachTarget.Type) |
| 165 | require.Equal(t, "picked.example", target.Endpoint) | 166 | require.Equal(t, "picked.example", target.Endpoint) | ||
| 166 | require.NoError(t, wireTransport.Close()) | 167 | require.NoError(t, wireTransport.Close()) | ||
| 167 | 168 | ||||
M internal/app/remote_preview.go +8 -8
| @@ -8,8 +8,8 @@ import ( | |||||
| 8 | "os" | 8 | "os" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/adapters/ipc" | 10 | "github.com/bnema/vev/internal/adapters/ipc" | ||
| 11 | - | "github.com/bnema/vev/internal/ports" | |||
| 12 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | // runRemotePreview is the hidden SSH-side carriage. The request is encoded in | 15 | // runRemotePreview is the hidden SSH-side carriage. The request is encoded in | ||
| @@ -20,7 +20,7 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||||
| 20 | if err != nil { | 20 | if err != nil { | ||
| 21 | return fmt.Errorf("vev: invalid remote preview request: %w", err) | 21 | return fmt.Errorf("vev: invalid remote preview request: %w", err) | ||
| 22 | } | 22 | } | ||
| 23 | - | if _, err := ports.UnmarshalRemotePreviewRequest(request); err != nil { | 23 | + | if _, err := wire.UnmarshalRemotePreviewRequest(request); err != nil { |
| 24 | return fmt.Errorf("vev: invalid remote preview request: %w", err) | 24 | return fmt.Errorf("vev: invalid remote preview request: %w", err) | ||
| 25 | } | 25 | } | ||
| 26 | transport, err := ipc.DialContext(ctx, ipc.SocketDir()) | 26 | transport, err := ipc.DialContext(ctx, ipc.SocketDir()) | ||
| @@ -31,17 +31,17 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||||
| 31 | return writeRemotePreviewStatus(protocol.RemotePreviewUnavailable) | 31 | return writeRemotePreviewStatus(protocol.RemotePreviewUnavailable) | ||
| 32 | } | 32 | } | ||
| 33 | defer func() { _ = transport.Close() }() | 33 | defer func() { _ = transport.Close() }() | ||
| 34 | - | if err := transport.Send(ports.Frame{Type: ports.MsgRemotePreviewRequest, Payload: request}); err != nil { | 34 | + | if err := transport.Send(wire.Frame{Type: wire.MsgRemotePreviewRequest, Payload: request}); err != nil { |
| 35 | return fmt.Errorf("vev: sending remote preview request: %w", err) | 35 | return fmt.Errorf("vev: sending remote preview request: %w", err) | ||
| 36 | } | 36 | } | ||
| 37 | frameCh := make(chan struct { | 37 | frameCh := make(chan struct { | ||
| 38 | - | frame ports.Frame | 38 | + | frame wire.Frame |
| 39 | err error | 39 | err error | ||
| 40 | }, 1) | 40 | }, 1) | ||
| 41 | go func() { | 41 | go func() { | ||
| 42 | frame, err := transport.Recv() | 42 | frame, err := transport.Recv() | ||
| 43 | frameCh <- struct { | 43 | frameCh <- struct { | ||
| 44 | - | frame ports.Frame | 44 | + | frame wire.Frame |
| 45 | err error | 45 | err error | ||
| 46 | }{frame: frame, err: err} | 46 | }{frame: frame, err: err} | ||
| 47 | }() | 47 | }() | ||
| @@ -53,10 +53,10 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||||
| 53 | if result.err != nil { | 53 | if result.err != nil { | ||
| 54 | return fmt.Errorf("vev: receiving remote preview: %w", result.err) | 54 | return fmt.Errorf("vev: receiving remote preview: %w", result.err) | ||
| 55 | } | 55 | } | ||
| 56 | - | if result.frame.Type != ports.MsgRemotePreviewResponse { | 56 | + | if result.frame.Type != wire.MsgRemotePreviewResponse { |
| 57 | return fmt.Errorf("vev: unexpected remote preview response %d", result.frame.Type) | 57 | return fmt.Errorf("vev: unexpected remote preview response %d", result.frame.Type) | ||
| 58 | } | 58 | } | ||
| 59 | - | if _, err := ports.UnmarshalRemotePreview(result.frame.Payload); err != nil { | 59 | + | if _, err := wire.UnmarshalRemotePreview(result.frame.Payload); err != nil { |
| 60 | return fmt.Errorf("vev: malformed remote preview response: %w", err) | 60 | return fmt.Errorf("vev: malformed remote preview response: %w", err) | ||
| 61 | } | 61 | } | ||
| 62 | _, err := os.Stdout.Write(result.frame.Payload) | 62 | _, err := os.Stdout.Write(result.frame.Payload) | ||
| @@ -65,7 +65,7 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||||
| 65 | } | 65 | } | ||
| 66 | 66 | ||||
| 67 | func writeRemotePreviewStatus(status protocol.RemotePreviewStatus) error { | 67 | func writeRemotePreviewStatus(status protocol.RemotePreviewStatus) error { | ||
| 68 | - | payload := ports.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: status}) | 68 | + | payload := wire.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: status}) |
| 69 | if payload == nil { | 69 | if payload == nil { | ||
| 70 | return errors.New("vev: failed to encode remote preview status") | 70 | return errors.New("vev: failed to encode remote preview status") | ||
| 71 | } | 71 | } | ||
M internal/app/remote_test.go +5 -4
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | "github.com/bnema/vev/internal/ports" | 12 | "github.com/bnema/vev/internal/ports" | ||
| 13 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 13 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 14 | "github.com/bnema/vev/internal/protocol" | 14 | "github.com/bnema/vev/internal/protocol" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 15 | "github.com/bnema/vev/internal/usecase/client" | 16 | "github.com/bnema/vev/internal/usecase/client" | ||
| 16 | "github.com/stretchr/testify/mock" | 17 | "github.com/stretchr/testify/mock" | ||
| 17 | "github.com/stretchr/testify/require" | 18 | "github.com/stretchr/testify/require" | ||
| @@ -56,15 +57,15 @@ func TestRemoteHostDepsDefaultsStore(t *testing.T) { | |||||
| 56 | 57 | ||||
| 57 | func TestDecodeSessionListErrorReply(t *testing.T) { | 58 | func TestDecodeSessionListErrorReply(t *testing.T) { | ||
| 58 | t.Run("valid", func(t *testing.T) { | 59 | t.Run("valid", func(t *testing.T) { | ||
| 59 | - | _, err := decodeSessionListReply(ports.Frame{ | 60 | + | _, err := decodeSessionListReply(wire.Frame{ |
| 60 | - | Type: ports.MsgError, | 61 | + | Type: wire.MsgError, |
| 61 | - | Payload: ports.MarshalErrorMsg(protocol.ErrorMsg{Text: "denied"}), | 62 | + | Payload: wire.MarshalErrorMsg(protocol.ErrorMsg{Text: "denied"}), |
| 62 | }) | 63 | }) | ||
| 63 | require.EqualError(t, err, "vev: denied") | 64 | require.EqualError(t, err, "vev: denied") | ||
| 64 | }) | 65 | }) | ||
| 65 | 66 | ||||
| 66 | t.Run("malformed", func(t *testing.T) { | 67 | t.Run("malformed", func(t *testing.T) { | ||
| 67 | - | _, err := decodeSessionListReply(ports.Frame{Type: ports.MsgError, Payload: []byte{0}}) | 68 | + | _, err := decodeSessionListReply(wire.Frame{Type: wire.MsgError, Payload: []byte{0}}) |
| 68 | require.ErrorContains(t, err, "vev: decoding error reply") | 69 | require.ErrorContains(t, err, "vev: decoding error reply") | ||
| 69 | }) | 70 | }) | ||
| 70 | } | 71 | } | ||
M internal/app/run.go +16 -15
| @@ -47,6 +47,7 @@ import ( | |||||
| 47 | "github.com/bnema/vev/internal/platform" | 47 | "github.com/bnema/vev/internal/platform" | ||
| 48 | "github.com/bnema/vev/internal/ports" | 48 | "github.com/bnema/vev/internal/ports" | ||
| 49 | "github.com/bnema/vev/internal/protocol" | 49 | "github.com/bnema/vev/internal/protocol" | ||
| 50 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 50 | "github.com/bnema/vev/internal/usecase/client" | 51 | "github.com/bnema/vev/internal/usecase/client" | ||
| 51 | "github.com/bnema/vev/internal/usecase/daemon" | 52 | "github.com/bnema/vev/internal/usecase/daemon" | ||
| 52 | "github.com/bnema/vev/internal/usecase/recovery" | 53 | "github.com/bnema/vev/internal/usecase/recovery" | ||
| @@ -1077,12 +1078,12 @@ func createDetachedLocalSession(ctx context.Context, name string) error { | |||||
| 1077 | cwd = "" | 1078 | cwd = "" | ||
| 1078 | } | 1079 | } | ||
| 1079 | hello := detachedLocalHello(name, cwd) | 1080 | hello := detachedLocalHello(name, cwd) | ||
| 1080 | - | if err := transport.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}); err != nil { | 1081 | + | if err := transport.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}); err != nil { |
| 1081 | return fmt.Errorf("vev: creating detached session: %w", err) | 1082 | return fmt.Errorf("vev: creating detached session: %w", err) | ||
| 1082 | } | 1083 | } | ||
| 1083 | 1084 | ||||
| 1084 | type detachedReply struct { | 1085 | type detachedReply struct { | ||
| 1085 | - | frame ports.Frame | 1086 | + | frame wire.Frame |
| 1086 | err error | 1087 | err error | ||
| 1087 | } | 1088 | } | ||
| 1088 | replyCh := make(chan detachedReply, 1) | 1089 | replyCh := make(chan detachedReply, 1) | ||
| @@ -1100,10 +1101,10 @@ func createDetachedLocalSession(ctx context.Context, name string) error { | |||||
| 1100 | return fmt.Errorf("vev: awaiting detached session creation: %w", reply.err) | 1101 | return fmt.Errorf("vev: awaiting detached session creation: %w", reply.err) | ||
| 1101 | } | 1102 | } | ||
| 1102 | switch reply.frame.Type { | 1103 | switch reply.frame.Type { | ||
| 1103 | - | case ports.MsgWelcome: | 1104 | + | case wire.MsgWelcome: |
| 1104 | return nil | 1105 | return nil | ||
| 1105 | - | case ports.MsgError: | 1106 | + | case wire.MsgError: |
| 1106 | - | em, derr := ports.UnmarshalErrorMsg(reply.frame.Payload) | 1107 | + | em, derr := wire.UnmarshalErrorMsg(reply.frame.Payload) |
| 1107 | if derr != nil { | 1108 | if derr != nil { | ||
| 1108 | return fmt.Errorf("vev: decoding error reply: %w", derr) | 1109 | return fmt.Errorf("vev: decoding error reply: %w", derr) | ||
| 1109 | } | 1110 | } | ||
| @@ -1126,7 +1127,7 @@ func requestDaemonStop(ctx context.Context) error { | |||||
| 1126 | return errors.Join(errors.New("vev: no daemon running"), owner.Release()) | 1127 | return errors.Join(errors.New("vev: no daemon running"), owner.Release()) | ||
| 1127 | } | 1128 | } | ||
| 1128 | defer func() { _ = transport.Close() }() | 1129 | defer func() { _ = transport.Close() }() | ||
| 1129 | - | if err := transport.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})}); err != nil { | 1130 | + | if err := transport.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})}); err != nil { |
| 1130 | return fmt.Errorf("vev: requesting daemon stop: %w", err) | 1131 | return fmt.Errorf("vev: requesting daemon stop: %w", err) | ||
| 1131 | } | 1132 | } | ||
| 1132 | if _, err := transport.Recv(); err != nil && !errors.Is(err, io.EOF) { | 1133 | if _, err := transport.Recv(); err != nil && !errors.Is(err, io.EOF) { | ||
| @@ -1482,7 +1483,7 @@ func listLocalSessions(ctx context.Context) (_ []protocol.SessionInfo, retErr er | |||||
| 1482 | } | 1483 | } | ||
| 1483 | defer func() { _ = transport.Close() }() | 1484 | defer func() { _ = transport.Close() }() | ||
| 1484 | 1485 | ||||
| 1485 | - | if err := transport.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})}); err != nil { | 1486 | + | if err := transport.Send(wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})}); err != nil { |
| 1486 | return nil, fmt.Errorf("vev: requesting session list: %w", err) | 1487 | return nil, fmt.Errorf("vev: requesting session list: %w", err) | ||
| 1487 | } | 1488 | } | ||
| 1488 | reply, err := transport.Recv() | 1489 | reply, err := transport.Recv() | ||
| @@ -1492,18 +1493,18 @@ func listLocalSessions(ctx context.Context) (_ []protocol.SessionInfo, retErr er | |||||
| 1492 | return decodeSessionListReply(reply) | 1493 | return decodeSessionListReply(reply) | ||
| 1493 | } | 1494 | } | ||
| 1494 | 1495 | ||||
| 1495 | - | func decodeSessionListReply(reply ports.Frame) ([]protocol.SessionInfo, error) { | 1496 | + | func decodeSessionListReply(reply wire.Frame) ([]protocol.SessionInfo, error) { |
| 1496 | - | if reply.Type == ports.MsgError { | 1497 | + | if reply.Type == wire.MsgError { |
| 1497 | - | em, err := ports.UnmarshalErrorMsg(reply.Payload) | 1498 | + | em, err := wire.UnmarshalErrorMsg(reply.Payload) |
| 1498 | if err != nil { | 1499 | if err != nil { | ||
| 1499 | return nil, fmt.Errorf("vev: decoding error reply: %w", err) | 1500 | return nil, fmt.Errorf("vev: decoding error reply: %w", err) | ||
| 1500 | } | 1501 | } | ||
| 1501 | return nil, fmt.Errorf("vev: %s", em.Text) | 1502 | return nil, fmt.Errorf("vev: %s", em.Text) | ||
| 1502 | } | 1503 | } | ||
| 1503 | - | if reply.Type != ports.MsgSessions { | 1504 | + | if reply.Type != wire.MsgSessions { |
| 1504 | return nil, fmt.Errorf("vev: unexpected reply type %d to list", reply.Type) | 1505 | return nil, fmt.Errorf("vev: unexpected reply type %d to list", reply.Type) | ||
| 1505 | } | 1506 | } | ||
| 1506 | - | sessions, err := ports.UnmarshalSessions(reply.Payload) | 1507 | + | sessions, err := wire.UnmarshalSessions(reply.Payload) |
| 1507 | if err != nil { | 1508 | if err != nil { | ||
| 1508 | return nil, fmt.Errorf("vev: decoding session list: %w", err) | 1509 | return nil, fmt.Errorf("vev: decoding session list: %w", err) | ||
| 1509 | } | 1510 | } | ||
| @@ -1596,7 +1597,7 @@ func runKill(ctx context.Context, name string, all, daemon bool) (retErr error) | |||||
| 1596 | } | 1597 | } | ||
| 1597 | defer func() { _ = transport.Close() }() | 1598 | defer func() { _ = transport.Close() }() | ||
| 1598 | 1599 | ||||
| 1599 | - | if err := transport.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{Name: name, All: all || daemon})}); err != nil { | 1600 | + | if err := transport.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{Name: name, All: all || daemon})}); err != nil { |
| 1600 | return fmt.Errorf("vev: requesting kill: %w", err) | 1601 | return fmt.Errorf("vev: requesting kill: %w", err) | ||
| 1601 | } | 1602 | } | ||
| 1602 | reply, err := transport.Recv() | 1603 | reply, err := transport.Recv() | ||
| @@ -1609,8 +1610,8 @@ func runKill(ctx context.Context, name string, all, daemon bool) (retErr error) | |||||
| 1609 | } | 1610 | } | ||
| 1610 | return fmt.Errorf("vev: reading kill reply: %w", err) | 1611 | return fmt.Errorf("vev: reading kill reply: %w", err) | ||
| 1611 | } | 1612 | } | ||
| 1612 | - | if reply.Type == ports.MsgError { | 1613 | + | if reply.Type == wire.MsgError { |
| 1613 | - | em, _ := ports.UnmarshalErrorMsg(reply.Payload) | 1614 | + | em, _ := wire.UnmarshalErrorMsg(reply.Payload) |
| 1614 | return fmt.Errorf("vev: %s", em.Text) | 1615 | return fmt.Errorf("vev: %s", em.Text) | ||
| 1615 | } | 1616 | } | ||
| 1616 | printKillSuccess(name, all, daemon) | 1617 | printKillSuccess(name, all, daemon) | ||
M internal/ports/mocks/transport_mock.go +43 -42
| @@ -8,6 +8,7 @@ import ( | |||||
| 8 | "context" | 8 | "context" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/ports" | 10 | "github.com/bnema/vev/internal/ports" | ||
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 11 | mock "github.com/stretchr/testify/mock" | 12 | mock "github.com/stretchr/testify/mock" | ||
| 12 | ) | 13 | ) | ||
| 13 | 14 | ||||
| @@ -83,22 +84,22 @@ func (_c *MockTransport_Close_Call) RunAndReturn(run func() error) *MockTranspor | |||||
| 83 | } | 84 | } | ||
| 84 | 85 | ||||
| 85 | // Recv provides a mock function for the type MockTransport | 86 | // Recv provides a mock function for the type MockTransport | ||
| 86 | - | func (_mock *MockTransport) Recv() (ports.Frame, error) { | 87 | + | func (_mock *MockTransport) Recv() (wire.Frame, error) { |
| 87 | ret := _mock.Called() | 88 | ret := _mock.Called() | ||
| 88 | 89 | ||||
| 89 | if len(ret) == 0 { | 90 | if len(ret) == 0 { | ||
| 90 | panic("no return value specified for Recv") | 91 | panic("no return value specified for Recv") | ||
| 91 | } | 92 | } | ||
| 92 | 93 | ||||
| 93 | - | var r0 ports.Frame | 94 | + | var r0 wire.Frame |
| 94 | var r1 error | 95 | var r1 error | ||
| 95 | - | if returnFunc, ok := ret.Get(0).(func() (ports.Frame, error)); ok { | 96 | + | if returnFunc, ok := ret.Get(0).(func() (wire.Frame, error)); ok { |
| 96 | return returnFunc() | 97 | return returnFunc() | ||
| 97 | } | 98 | } | ||
| 98 | - | if returnFunc, ok := ret.Get(0).(func() ports.Frame); ok { | 99 | + | if returnFunc, ok := ret.Get(0).(func() wire.Frame); ok { |
| 99 | r0 = returnFunc() | 100 | r0 = returnFunc() | ||
| 100 | } else { | 101 | } else { | ||
| 101 | - | r0 = ret.Get(0).(ports.Frame) | 102 | + | r0 = ret.Get(0).(wire.Frame) |
| 102 | } | 103 | } | ||
| 103 | if returnFunc, ok := ret.Get(1).(func() error); ok { | 104 | if returnFunc, ok := ret.Get(1).(func() error); ok { | ||
| 104 | r1 = returnFunc() | 105 | r1 = returnFunc() | ||
| @@ -125,18 +126,18 @@ func (_c *MockTransport_Recv_Call) Run(run func()) *MockTransport_Recv_Call { | |||||
| 125 | return _c | 126 | return _c | ||
| 126 | } | 127 | } | ||
| 127 | 128 | ||||
| 128 | - | func (_c *MockTransport_Recv_Call) Return(frame ports.Frame, err error) *MockTransport_Recv_Call { | 129 | + | func (_c *MockTransport_Recv_Call) Return(frame wire.Frame, err error) *MockTransport_Recv_Call { |
| 129 | _c.Call.Return(frame, err) | 130 | _c.Call.Return(frame, err) | ||
| 130 | return _c | 131 | return _c | ||
| 131 | } | 132 | } | ||
| 132 | 133 | ||||
| 133 | - | func (_c *MockTransport_Recv_Call) RunAndReturn(run func() (ports.Frame, error)) *MockTransport_Recv_Call { | 134 | + | func (_c *MockTransport_Recv_Call) RunAndReturn(run func() (wire.Frame, error)) *MockTransport_Recv_Call { |
| 134 | _c.Call.Return(run) | 135 | _c.Call.Return(run) | ||
| 135 | return _c | 136 | return _c | ||
| 136 | } | 137 | } | ||
| 137 | 138 | ||||
| 138 | // Send provides a mock function for the type MockTransport | 139 | // Send provides a mock function for the type MockTransport | ||
| 139 | - | func (_mock *MockTransport) Send(frame ports.Frame) error { | 140 | + | func (_mock *MockTransport) Send(frame wire.Frame) error { |
| 140 | ret := _mock.Called(frame) | 141 | ret := _mock.Called(frame) | ||
| 141 | 142 | ||||
| 142 | if len(ret) == 0 { | 143 | if len(ret) == 0 { | ||
| @@ -144,7 +145,7 @@ func (_mock *MockTransport) Send(frame ports.Frame) error { | |||||
| 144 | } | 145 | } | ||
| 145 | 146 | ||||
| 146 | var r0 error | 147 | var r0 error | ||
| 147 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | 148 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { |
| 148 | r0 = returnFunc(frame) | 149 | r0 = returnFunc(frame) | ||
| 149 | } else { | 150 | } else { | ||
| 150 | r0 = ret.Error(0) | 151 | r0 = ret.Error(0) | ||
| @@ -158,16 +159,16 @@ type MockTransport_Send_Call struct { | |||||
| 158 | } | 159 | } | ||
| 159 | 160 | ||||
| 160 | // Send is a helper method to define mock.On call | 161 | // Send is a helper method to define mock.On call | ||
| 161 | - | // - frame ports.Frame | 162 | + | // - frame wire.Frame |
| 162 | func (_e *MockTransport_Expecter) Send(frame any) *MockTransport_Send_Call { | 163 | func (_e *MockTransport_Expecter) Send(frame any) *MockTransport_Send_Call { | ||
| 163 | return &MockTransport_Send_Call{Call: _e.mock.On("Send", frame)} | 164 | return &MockTransport_Send_Call{Call: _e.mock.On("Send", frame)} | ||
| 164 | } | 165 | } | ||
| 165 | 166 | ||||
| 166 | - | func (_c *MockTransport_Send_Call) Run(run func(frame ports.Frame)) *MockTransport_Send_Call { | 167 | + | func (_c *MockTransport_Send_Call) Run(run func(frame wire.Frame)) *MockTransport_Send_Call { |
| 167 | _c.Call.Run(func(args mock.Arguments) { | 168 | _c.Call.Run(func(args mock.Arguments) { | ||
| 168 | - | var arg0 ports.Frame | 169 | + | var arg0 wire.Frame |
| 169 | if args[0] != nil { | 170 | if args[0] != nil { | ||
| 170 | - | arg0 = args[0].(ports.Frame) | 171 | + | arg0 = args[0].(wire.Frame) |
| 171 | } | 172 | } | ||
| 172 | run( | 173 | run( | ||
| 173 | arg0, | 174 | arg0, | ||
| @@ -181,7 +182,7 @@ func (_c *MockTransport_Send_Call) Return(err error) *MockTransport_Send_Call { | |||||
| 181 | return _c | 182 | return _c | ||
| 182 | } | 183 | } | ||
| 183 | 184 | ||||
| 184 | - | func (_c *MockTransport_Send_Call) RunAndReturn(run func(frame ports.Frame) error) *MockTransport_Send_Call { | 185 | + | func (_c *MockTransport_Send_Call) RunAndReturn(run func(frame wire.Frame) error) *MockTransport_Send_Call { |
| 185 | _c.Call.Return(run) | 186 | _c.Call.Return(run) | ||
| 186 | return _c | 187 | return _c | ||
| 187 | } | 188 | } | ||
| @@ -291,22 +292,22 @@ func (_c *MockDatagramTransport_DatagramTransport_Call) RunAndReturn(run func()) | |||||
| 291 | } | 292 | } | ||
| 292 | 293 | ||||
| 293 | // Recv provides a mock function for the type MockDatagramTransport | 294 | // Recv provides a mock function for the type MockDatagramTransport | ||
| 294 | - | func (_mock *MockDatagramTransport) Recv() (ports.Frame, error) { | 295 | + | func (_mock *MockDatagramTransport) Recv() (wire.Frame, error) { |
| 295 | ret := _mock.Called() | 296 | ret := _mock.Called() | ||
| 296 | 297 | ||||
| 297 | if len(ret) == 0 { | 298 | if len(ret) == 0 { | ||
| 298 | panic("no return value specified for Recv") | 299 | panic("no return value specified for Recv") | ||
| 299 | } | 300 | } | ||
| 300 | 301 | ||||
| 301 | - | var r0 ports.Frame | 302 | + | var r0 wire.Frame |
| 302 | var r1 error | 303 | var r1 error | ||
| 303 | - | if returnFunc, ok := ret.Get(0).(func() (ports.Frame, error)); ok { | 304 | + | if returnFunc, ok := ret.Get(0).(func() (wire.Frame, error)); ok { |
| 304 | return returnFunc() | 305 | return returnFunc() | ||
| 305 | } | 306 | } | ||
| 306 | - | if returnFunc, ok := ret.Get(0).(func() ports.Frame); ok { | 307 | + | if returnFunc, ok := ret.Get(0).(func() wire.Frame); ok { |
| 307 | r0 = returnFunc() | 308 | r0 = returnFunc() | ||
| 308 | } else { | 309 | } else { | ||
| 309 | - | r0 = ret.Get(0).(ports.Frame) | 310 | + | r0 = ret.Get(0).(wire.Frame) |
| 310 | } | 311 | } | ||
| 311 | if returnFunc, ok := ret.Get(1).(func() error); ok { | 312 | if returnFunc, ok := ret.Get(1).(func() error); ok { | ||
| 312 | r1 = returnFunc() | 313 | r1 = returnFunc() | ||
| @@ -333,18 +334,18 @@ func (_c *MockDatagramTransport_Recv_Call) Run(run func()) *MockDatagramTranspor | |||||
| 333 | return _c | 334 | return _c | ||
| 334 | } | 335 | } | ||
| 335 | 336 | ||||
| 336 | - | func (_c *MockDatagramTransport_Recv_Call) Return(frame ports.Frame, err error) *MockDatagramTransport_Recv_Call { | 337 | + | func (_c *MockDatagramTransport_Recv_Call) Return(frame wire.Frame, err error) *MockDatagramTransport_Recv_Call { |
| 337 | _c.Call.Return(frame, err) | 338 | _c.Call.Return(frame, err) | ||
| 338 | return _c | 339 | return _c | ||
| 339 | } | 340 | } | ||
| 340 | 341 | ||||
| 341 | - | func (_c *MockDatagramTransport_Recv_Call) RunAndReturn(run func() (ports.Frame, error)) *MockDatagramTransport_Recv_Call { | 342 | + | func (_c *MockDatagramTransport_Recv_Call) RunAndReturn(run func() (wire.Frame, error)) *MockDatagramTransport_Recv_Call { |
| 342 | _c.Call.Return(run) | 343 | _c.Call.Return(run) | ||
| 343 | return _c | 344 | return _c | ||
| 344 | } | 345 | } | ||
| 345 | 346 | ||||
| 346 | // Send provides a mock function for the type MockDatagramTransport | 347 | // Send provides a mock function for the type MockDatagramTransport | ||
| 347 | - | func (_mock *MockDatagramTransport) Send(frame ports.Frame) error { | 348 | + | func (_mock *MockDatagramTransport) Send(frame wire.Frame) error { |
| 348 | ret := _mock.Called(frame) | 349 | ret := _mock.Called(frame) | ||
| 349 | 350 | ||||
| 350 | if len(ret) == 0 { | 351 | if len(ret) == 0 { | ||
| @@ -352,7 +353,7 @@ func (_mock *MockDatagramTransport) Send(frame ports.Frame) error { | |||||
| 352 | } | 353 | } | ||
| 353 | 354 | ||||
| 354 | var r0 error | 355 | var r0 error | ||
| 355 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | 356 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { |
| 356 | r0 = returnFunc(frame) | 357 | r0 = returnFunc(frame) | ||
| 357 | } else { | 358 | } else { | ||
| 358 | r0 = ret.Error(0) | 359 | r0 = ret.Error(0) | ||
| @@ -366,16 +367,16 @@ type MockDatagramTransport_Send_Call struct { | |||||
| 366 | } | 367 | } | ||
| 367 | 368 | ||||
| 368 | // Send is a helper method to define mock.On call | 369 | // Send is a helper method to define mock.On call | ||
| 369 | - | // - frame ports.Frame | 370 | + | // - frame wire.Frame |
| 370 | func (_e *MockDatagramTransport_Expecter) Send(frame any) *MockDatagramTransport_Send_Call { | 371 | func (_e *MockDatagramTransport_Expecter) Send(frame any) *MockDatagramTransport_Send_Call { | ||
| 371 | return &MockDatagramTransport_Send_Call{Call: _e.mock.On("Send", frame)} | 372 | return &MockDatagramTransport_Send_Call{Call: _e.mock.On("Send", frame)} | ||
| 372 | } | 373 | } | ||
| 373 | 374 | ||||
| 374 | - | func (_c *MockDatagramTransport_Send_Call) Run(run func(frame ports.Frame)) *MockDatagramTransport_Send_Call { | 375 | + | func (_c *MockDatagramTransport_Send_Call) Run(run func(frame wire.Frame)) *MockDatagramTransport_Send_Call { |
| 375 | _c.Call.Run(func(args mock.Arguments) { | 376 | _c.Call.Run(func(args mock.Arguments) { | ||
| 376 | - | var arg0 ports.Frame | 377 | + | var arg0 wire.Frame |
| 377 | if args[0] != nil { | 378 | if args[0] != nil { | ||
| 378 | - | arg0 = args[0].(ports.Frame) | 379 | + | arg0 = args[0].(wire.Frame) |
| 379 | } | 380 | } | ||
| 380 | run( | 381 | run( | ||
| 381 | arg0, | 382 | arg0, | ||
| @@ -389,7 +390,7 @@ func (_c *MockDatagramTransport_Send_Call) Return(err error) *MockDatagramTransp | |||||
| 389 | return _c | 390 | return _c | ||
| 390 | } | 391 | } | ||
| 391 | 392 | ||||
| 392 | - | func (_c *MockDatagramTransport_Send_Call) RunAndReturn(run func(frame ports.Frame) error) *MockDatagramTransport_Send_Call { | 393 | + | func (_c *MockDatagramTransport_Send_Call) RunAndReturn(run func(frame wire.Frame) error) *MockDatagramTransport_Send_Call { |
| 393 | _c.Call.Return(run) | 394 | _c.Call.Return(run) | ||
| 394 | return _c | 395 | return _c | ||
| 395 | } | 396 | } | ||
| @@ -422,7 +423,7 @@ func (_m *MockAsyncTransport) EXPECT() *MockAsyncTransport_Expecter { | |||||
| 422 | } | 423 | } | ||
| 423 | 424 | ||||
| 424 | // SendAsync provides a mock function for the type MockAsyncTransport | 425 | // SendAsync provides a mock function for the type MockAsyncTransport | ||
| 425 | - | func (_mock *MockAsyncTransport) SendAsync(frame ports.Frame) error { | 426 | + | func (_mock *MockAsyncTransport) SendAsync(frame wire.Frame) error { |
| 426 | ret := _mock.Called(frame) | 427 | ret := _mock.Called(frame) | ||
| 427 | 428 | ||||
| 428 | if len(ret) == 0 { | 429 | if len(ret) == 0 { | ||
| @@ -430,7 +431,7 @@ func (_mock *MockAsyncTransport) SendAsync(frame ports.Frame) error { | |||||
| 430 | } | 431 | } | ||
| 431 | 432 | ||||
| 432 | var r0 error | 433 | var r0 error | ||
| 433 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | 434 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { |
| 434 | r0 = returnFunc(frame) | 435 | r0 = returnFunc(frame) | ||
| 435 | } else { | 436 | } else { | ||
| 436 | r0 = ret.Error(0) | 437 | r0 = ret.Error(0) | ||
| @@ -444,16 +445,16 @@ type MockAsyncTransport_SendAsync_Call struct { | |||||
| 444 | } | 445 | } | ||
| 445 | 446 | ||||
| 446 | // SendAsync is a helper method to define mock.On call | 447 | // SendAsync is a helper method to define mock.On call | ||
| 447 | - | // - frame ports.Frame | 448 | + | // - frame wire.Frame |
| 448 | func (_e *MockAsyncTransport_Expecter) SendAsync(frame any) *MockAsyncTransport_SendAsync_Call { | 449 | func (_e *MockAsyncTransport_Expecter) SendAsync(frame any) *MockAsyncTransport_SendAsync_Call { | ||
| 449 | return &MockAsyncTransport_SendAsync_Call{Call: _e.mock.On("SendAsync", frame)} | 450 | return &MockAsyncTransport_SendAsync_Call{Call: _e.mock.On("SendAsync", frame)} | ||
| 450 | } | 451 | } | ||
| 451 | 452 | ||||
| 452 | - | func (_c *MockAsyncTransport_SendAsync_Call) Run(run func(frame ports.Frame)) *MockAsyncTransport_SendAsync_Call { | 453 | + | func (_c *MockAsyncTransport_SendAsync_Call) Run(run func(frame wire.Frame)) *MockAsyncTransport_SendAsync_Call { |
| 453 | _c.Call.Run(func(args mock.Arguments) { | 454 | _c.Call.Run(func(args mock.Arguments) { | ||
| 454 | - | var arg0 ports.Frame | 455 | + | var arg0 wire.Frame |
| 455 | if args[0] != nil { | 456 | if args[0] != nil { | ||
| 456 | - | arg0 = args[0].(ports.Frame) | 457 | + | arg0 = args[0].(wire.Frame) |
| 457 | } | 458 | } | ||
| 458 | run( | 459 | run( | ||
| 459 | arg0, | 460 | arg0, | ||
| @@ -467,7 +468,7 @@ func (_c *MockAsyncTransport_SendAsync_Call) Return(err error) *MockAsyncTranspo | |||||
| 467 | return _c | 468 | return _c | ||
| 468 | } | 469 | } | ||
| 469 | 470 | ||||
| 470 | - | func (_c *MockAsyncTransport_SendAsync_Call) RunAndReturn(run func(frame ports.Frame) error) *MockAsyncTransport_SendAsync_Call { | 471 | + | func (_c *MockAsyncTransport_SendAsync_Call) RunAndReturn(run func(frame wire.Frame) error) *MockAsyncTransport_SendAsync_Call { |
| 471 | _c.Call.Return(run) | 472 | _c.Call.Return(run) | ||
| 472 | return _c | 473 | return _c | ||
| 473 | } | 474 | } | ||
| @@ -500,7 +501,7 @@ func (_m *MockOwnedSynchronousTransport) EXPECT() *MockOwnedSynchronousTransport | |||||
| 500 | } | 501 | } | ||
| 501 | 502 | ||||
| 502 | // SendSynchronous provides a mock function for the type MockOwnedSynchronousTransport | 503 | // SendSynchronous provides a mock function for the type MockOwnedSynchronousTransport | ||
| 503 | - | func (_mock *MockOwnedSynchronousTransport) SendSynchronous(frame ports.Frame) error { | 504 | + | func (_mock *MockOwnedSynchronousTransport) SendSynchronous(frame wire.Frame) error { |
| 504 | ret := _mock.Called(frame) | 505 | ret := _mock.Called(frame) | ||
| 505 | 506 | ||||
| 506 | if len(ret) == 0 { | 507 | if len(ret) == 0 { | ||
| @@ -508,7 +509,7 @@ func (_mock *MockOwnedSynchronousTransport) SendSynchronous(frame ports.Frame) e | |||||
| 508 | } | 509 | } | ||
| 509 | 510 | ||||
| 510 | var r0 error | 511 | var r0 error | ||
| 511 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | 512 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { |
| 512 | r0 = returnFunc(frame) | 513 | r0 = returnFunc(frame) | ||
| 513 | } else { | 514 | } else { | ||
| 514 | r0 = ret.Error(0) | 515 | r0 = ret.Error(0) | ||
| @@ -522,16 +523,16 @@ type MockOwnedSynchronousTransport_SendSynchronous_Call struct { | |||||
| 522 | } | 523 | } | ||
| 523 | 524 | ||||
| 524 | // SendSynchronous is a helper method to define mock.On call | 525 | // SendSynchronous is a helper method to define mock.On call | ||
| 525 | - | // - frame ports.Frame | 526 | + | // - frame wire.Frame |
| 526 | func (_e *MockOwnedSynchronousTransport_Expecter) SendSynchronous(frame any) *MockOwnedSynchronousTransport_SendSynchronous_Call { | 527 | func (_e *MockOwnedSynchronousTransport_Expecter) SendSynchronous(frame any) *MockOwnedSynchronousTransport_SendSynchronous_Call { | ||
| 527 | return &MockOwnedSynchronousTransport_SendSynchronous_Call{Call: _e.mock.On("SendSynchronous", frame)} | 528 | return &MockOwnedSynchronousTransport_SendSynchronous_Call{Call: _e.mock.On("SendSynchronous", frame)} | ||
| 528 | } | 529 | } | ||
| 529 | 530 | ||||
| 530 | - | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) Run(run func(frame ports.Frame)) *MockOwnedSynchronousTransport_SendSynchronous_Call { | 531 | + | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) Run(run func(frame wire.Frame)) *MockOwnedSynchronousTransport_SendSynchronous_Call { |
| 531 | _c.Call.Run(func(args mock.Arguments) { | 532 | _c.Call.Run(func(args mock.Arguments) { | ||
| 532 | - | var arg0 ports.Frame | 533 | + | var arg0 wire.Frame |
| 533 | if args[0] != nil { | 534 | if args[0] != nil { | ||
| 534 | - | arg0 = args[0].(ports.Frame) | 535 | + | arg0 = args[0].(wire.Frame) |
| 535 | } | 536 | } | ||
| 536 | run( | 537 | run( | ||
| 537 | arg0, | 538 | arg0, | ||
| @@ -545,7 +546,7 @@ func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) Return(err error) | |||||
| 545 | return _c | 546 | return _c | ||
| 546 | } | 547 | } | ||
| 547 | 548 | ||||
| 548 | - | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) RunAndReturn(run func(frame ports.Frame) error) *MockOwnedSynchronousTransport_SendSynchronous_Call { | 549 | + | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) RunAndReturn(run func(frame wire.Frame) error) *MockOwnedSynchronousTransport_SendSynchronous_Call { |
| 549 | _c.Call.Return(run) | 550 | _c.Call.Return(run) | ||
| 550 | return _c | 551 | return _c | ||
| 551 | } | 552 | } | ||
M internal/ports/transport.go +9 -5
| @@ -1,13 +1,17 @@ | |||||
| 1 | package ports | 1 | package ports | ||
| 2 | 2 | ||||
| 3 | - | import "context" | 3 | + | import ( |
| 4 | + | "context" | |||
| 5 | + | ||||
| 6 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 7 | + | ) | |||
| 4 | 8 | ||||
| 5 | // Transport is a framed message channel over a single connection. Close must | 9 | // Transport is a framed message channel over a single connection. Close must | ||
| 6 | // be safe to call concurrently with Send and Recv, and must unblock active | 10 | // be safe to call concurrently with Send and Recv, and must unblock active | ||
| 7 | // Send and Recv calls. | 11 | // Send and Recv calls. | ||
| 8 | type Transport interface { | 12 | type Transport interface { | ||
| 9 | - | Send(Frame) error | 13 | + | Send(wire.Frame) error |
| 10 | - | Recv() (Frame, error) // blocking; io.EOF on close | 14 | + | Recv() (wire.Frame, error) // blocking; io.EOF on close |
| 11 | Close() error | 15 | Close() error | ||
| 12 | } | 16 | } | ||
| 13 | 17 | ||||
| @@ -22,13 +26,13 @@ type DatagramTransport interface { | |||||
| 22 | // returns once the adapter owns the frame; Send retains its synchronous wire- | 26 | // returns once the adapter owns the frame; Send retains its synchronous wire- | ||
| 23 | // attempt contract. Daemon paint output may use this capability to pipeline. | 27 | // attempt contract. Daemon paint output may use this capability to pipeline. | ||
| 24 | type AsyncTransport interface { | 28 | type AsyncTransport interface { | ||
| 25 | - | SendAsync(Frame) error | 29 | + | SendAsync(wire.Frame) error |
| 26 | } | 30 | } | ||
| 27 | 31 | ||||
| 28 | // OwnedSynchronousTransport owns the complete bounded synchronous operation, | 32 | // OwnedSynchronousTransport owns the complete bounded synchronous operation, | ||
| 29 | // including adapter queues, pacing, write deadlines, and close cancellation. | 33 | // including adapter queues, pacing, write deadlines, and close cancellation. | ||
| 30 | type OwnedSynchronousTransport interface { | 34 | type OwnedSynchronousTransport interface { | ||
| 31 | - | SendSynchronous(Frame) error | 35 | + | SendSynchronous(wire.Frame) error |
| 32 | } | 36 | } | ||
| 33 | 37 | ||||
| 34 | // Dialer establishes outbound Transport connections. | 38 | // Dialer establishes outbound Transport connections. | ||
R internal/ports/frame.go → internal/protocol/wire/frame.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | // MaxFrameLen is the largest permitted frame length, including the type byte | 3 | // MaxFrameLen is the largest permitted frame length, including the type byte | ||
| 4 | // and excluding the four-byte length prefix. | 4 | // and excluding the four-byte length prefix. | ||
R internal/ports/frame_test.go → internal/protocol/wire/frame_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "testing" | 4 | "testing" | ||
R internal/ports/navigation_test.go → internal/protocol/wire/navigation_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "encoding/hex" | 4 | "encoding/hex" | ||
R internal/ports/output_compression_test.go → internal/protocol/wire/output_compression_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "bytes" | 4 | "bytes" | ||
R internal/ports/remote_preview_hardening_test.go → internal/protocol/wire/remote_preview_hardening_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "bytes" | 4 | "bytes" | ||
R internal/ports/remote_preview_test.go → internal/protocol/wire/remote_preview_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "testing" | 4 | "testing" | ||
R internal/ports/remote_target_wire_test.go → internal/protocol/wire/remote_target_wire_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "bytes" | 4 | "bytes" | ||
R internal/ports/routes_test.go → internal/protocol/wire/routes_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "encoding/hex" | 4 | "encoding/hex" | ||
R internal/ports/routes_wire.go → internal/protocol/wire/routes_wire.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "fmt" | 4 | "fmt" | ||
R internal/ports/same_peer_switch_test.go → internal/protocol/wire/same_peer_switch_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "bytes" | 4 | "bytes" | ||
R internal/ports/wire.go → internal/protocol/wire/wire.go +3 -6 renamed, 99% similar
| @@ -1,10 +1,7 @@ | |||||
| 1 | - | // Wire codecs for vev's IPC message payloads. They live in ports (alongside | 1 | + | // Package wire owns vev's binary frame representation and strict payload |
| 2 | - | // Frame and the MsgType constants) because wire encoding is protocol | 2 | + | // codecs. It performs no I/O; carriage adapters transport Frame values. |
| 3 | - | // surface, not I/O: everything here is pure, stdlib-only byte marshalling. | |||
| 4 | - | // Adapters keep what actually performs I/O (framing over a connection, | |||
| 5 | - | // listening on a socket) and import these types for the payloads they carry. | |||
| 6 | 3 | ||||
| 7 | - | package ports | 4 | + | package wire |
| 8 | 5 | ||||
| 9 | import ( | 6 | import ( | ||
| 10 | "bytes" | 7 | "bytes" | ||
R internal/ports/wire_command.go → internal/protocol/wire/wire_command.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "encoding/binary" | 4 | "encoding/binary" | ||
R internal/ports/wire_final_test.go → internal/protocol/wire/wire_final_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "bytes" | 4 | "bytes" | ||
R internal/ports/wire_test.go → internal/protocol/wire/wire_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | package ports | 1 | + | package wire |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "bytes" | 4 | "bytes" | ||
M internal/testutil/replaytest/replay.go +12 -12
| @@ -8,31 +8,31 @@ import ( | |||||
| 8 | "testing" | 8 | "testing" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | - | "github.com/bnema/vev/internal/ports" | |||
| 12 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | func mustMarshalOutput(m protocol.Output) []byte { | 15 | func mustMarshalOutput(m protocol.Output) []byte { | ||
| 16 | - | payload, err := ports.MarshalOutput(m) | 16 | + | payload, err := wire.MarshalOutput(m) |
| 17 | if err != nil { | 17 | if err != nil { | ||
| 18 | panic(err) | 18 | panic(err) | ||
| 19 | } | 19 | } | ||
| 20 | return payload | 20 | return payload | ||
| 21 | } | 21 | } | ||
| 22 | 22 | ||||
| 23 | - | var transcript = []ports.Frame{ | 23 | + | var transcript = []wire.Frame{ |
| 24 | - | {Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("\x1b[2J\x1b[Hone\r\ntwo")})}, | 24 | + | {Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("\x1b[2J\x1b[Hone\r\ntwo")})}, |
| 25 | - | {Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 1, New: 2, Echo: 7, Size: domain.Size{Cols: 80, Rows: 24}, Data: []byte("\x1b[2;1HTWO")})}, | 25 | + | {Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 1, New: 2, Echo: 7, Size: domain.Size{Cols: 80, Rows: 24}, Data: []byte("\x1b[2;1HTWO")})}, |
| 26 | } | 26 | } | ||
| 27 | 27 | ||||
| 28 | // Transcript returns a deep copy of the canonical replay transcript so an | 28 | // Transcript returns a deep copy of the canonical replay transcript so an | ||
| 29 | // adapter cannot mutate the fixture observed by another adapter. | 29 | // adapter cannot mutate the fixture observed by another adapter. | ||
| 30 | - | func Transcript() []ports.Frame { | 30 | + | func Transcript() []wire.Frame { |
| 31 | return cloneFrames(transcript) | 31 | return cloneFrames(transcript) | ||
| 32 | } | 32 | } | ||
| 33 | 33 | ||||
| 34 | // Exchange carries already-composed frames through one transport adapter. | 34 | // Exchange carries already-composed frames through one transport adapter. | ||
| 35 | - | type Exchange func(t *testing.T, frames []ports.Frame) []ports.Frame | 35 | + | type Exchange func(t *testing.T, frames []wire.Frame) []wire.Frame |
| 36 | 36 | ||||
| 37 | // Run verifies that an adapter preserves the canonical transcript exactly. | 37 | // Run verifies that an adapter preserves the canonical transcript exactly. | ||
| 38 | func Run(t *testing.T, exchange Exchange) { | 38 | func Run(t *testing.T, exchange Exchange) { | ||
| @@ -50,12 +50,12 @@ func Run(t *testing.T, exchange Exchange) { | |||||
| 50 | t.Errorf("frame %d payload = %x, want byte-for-byte %x", i, got[i].Payload, want[i].Payload) | 50 | t.Errorf("frame %d payload = %x, want byte-for-byte %x", i, got[i].Payload, want[i].Payload) | ||
| 51 | continue | 51 | continue | ||
| 52 | } | 52 | } | ||
| 53 | - | gotOutput, err := ports.UnmarshalOutput(got[i].Payload) | 53 | + | gotOutput, err := wire.UnmarshalOutput(got[i].Payload) |
| 54 | if err != nil { | 54 | if err != nil { | ||
| 55 | t.Errorf("frame %d output decode: %v", i, err) | 55 | t.Errorf("frame %d output decode: %v", i, err) | ||
| 56 | continue | 56 | continue | ||
| 57 | } | 57 | } | ||
| 58 | - | wantOutput, err := ports.UnmarshalOutput(want[i].Payload) | 58 | + | wantOutput, err := wire.UnmarshalOutput(want[i].Payload) |
| 59 | if err != nil { | 59 | if err != nil { | ||
| 60 | t.Fatalf("canonical frame %d output decode: %v", i, err) | 60 | t.Fatalf("canonical frame %d output decode: %v", i, err) | ||
| 61 | } | 61 | } | ||
| @@ -65,10 +65,10 @@ func Run(t *testing.T, exchange Exchange) { | |||||
| 65 | } | 65 | } | ||
| 66 | } | 66 | } | ||
| 67 | 67 | ||||
| 68 | - | func cloneFrames(frames []ports.Frame) []ports.Frame { | 68 | + | func cloneFrames(frames []wire.Frame) []wire.Frame { |
| 69 | - | cloned := make([]ports.Frame, len(frames)) | 69 | + | cloned := make([]wire.Frame, len(frames)) |
| 70 | for i, frame := range frames { | 70 | for i, frame := range frames { | ||
| 71 | - | cloned[i] = ports.Frame{Type: frame.Type, Payload: append([]byte(nil), frame.Payload...)} | 71 | + | cloned[i] = wire.Frame{Type: frame.Type, Payload: append([]byte(nil), frame.Payload...)} |
| 72 | } | 72 | } | ||
| 73 | return cloned | 73 | return cloned | ||
| 74 | } | 74 | } | ||
M internal/usecase/client/ack_queue_test.go +26 -26
| @@ -7,20 +7,20 @@ import ( | |||||
| 7 | "testing" | 7 | "testing" | ||
| 8 | "time" | 8 | "time" | ||
| 9 | 9 | ||||
| 10 | - | "github.com/bnema/vev/internal/ports" | 10 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 11 | "github.com/stretchr/testify/require" | 11 | "github.com/stretchr/testify/require" | ||
| 12 | ) | 12 | ) | ||
| 13 | 13 | ||||
| 14 | - | type ackRecordingTransport struct{ sent chan ports.Frame } | 14 | + | type ackRecordingTransport struct{ sent chan wire.Frame } |
| 15 | 15 | ||||
| 16 | - | func (t *ackRecordingTransport) Send(f ports.Frame) error { t.sent <- f; return nil } | 16 | + | func (t *ackRecordingTransport) Send(f wire.Frame) error { t.sent <- f; return nil } |
| 17 | - | func (t *ackRecordingTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 17 | + | func (t *ackRecordingTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 18 | - | func (t *ackRecordingTransport) Close() error { return nil } | 18 | + | func (t *ackRecordingTransport) Close() error { return nil } |
| 19 | 19 | ||||
| 20 | func TestCumulativeAckBypassesFullNormalSendQueue(t *testing.T) { | 20 | func TestCumulativeAckBypassesFullNormalSendQueue(t *testing.T) { | ||
| 21 | - | normal := make(chan ports.Frame, sendQueueDepth) | 21 | + | normal := make(chan wire.Frame, sendQueueDepth) |
| 22 | for range cap(normal) { | 22 | for range cap(normal) { | ||
| 23 | - | normal <- ports.Frame{Type: ports.MsgInput} | 23 | + | normal <- wire.Frame{Type: wire.MsgInput} |
| 24 | } | 24 | } | ||
| 25 | const epoch = 7 | 25 | const epoch = 7 | ||
| 26 | acks := newCumulativeAckQueue() | 26 | acks := newCumulativeAckQueue() | ||
| @@ -30,13 +30,13 @@ func TestCumulativeAckBypassesFullNormalSendQueue(t *testing.T) { | |||||
| 30 | 30 | ||||
| 31 | ctx, cancel := context.WithCancel(context.Background()) | 31 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 32 | defer cancel() | 32 | defer cancel() | ||
| 33 | - | tr := &ackRecordingTransport{sent: make(chan ports.Frame, sendQueueDepth+1)} | 33 | + | tr := &ackRecordingTransport{sent: make(chan wire.Frame, sendQueueDepth+1)} |
| 34 | errCh := make(chan error, 1) | 34 | errCh := make(chan error, 1) | ||
| 35 | go runSender(ctx, cancel, tr, nil, nil, normal, nil, acks, errCh, slog.Default()) | 35 | go runSender(ctx, cancel, tr, nil, nil, normal, nil, acks, errCh, slog.Default()) | ||
| 36 | 36 | ||||
| 37 | first := <-tr.sent | 37 | first := <-tr.sent | ||
| 38 | - | require.Equal(t, ports.MsgAck, first.Type) | 38 | + | require.Equal(t, wire.MsgAck, first.Type) |
| 39 | - | ack, err := ports.UnmarshalAck(first.Payload) | 39 | + | ack, err := wire.UnmarshalAck(first.Payload) |
| 40 | require.NoError(t, err) | 40 | require.NoError(t, err) | ||
| 41 | require.Equal(t, uint64(epoch), ack.Epoch) | 41 | require.Equal(t, uint64(epoch), ack.Epoch) | ||
| 42 | require.Equal(t, uint64(maxUnackedOutputStatesForTest), ack.State) | 42 | require.Equal(t, uint64(maxUnackedOutputStatesForTest), ack.State) | ||
| @@ -45,21 +45,21 @@ func TestCumulativeAckBypassesFullNormalSendQueue(t *testing.T) { | |||||
| 45 | func TestSamePeerSwitchControlBypassesHeldInput(t *testing.T) { | 45 | func TestSamePeerSwitchControlBypassesHeldInput(t *testing.T) { | ||
| 46 | ctx, cancel := context.WithCancel(context.Background()) | 46 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 47 | defer cancel() | 47 | defer cancel() | ||
| 48 | - | normal := make(chan ports.Frame, 1) | 48 | + | normal := make(chan wire.Frame, 1) |
| 49 | - | control := make(chan ports.Frame, 1) | 49 | + | control := make(chan wire.Frame, 1) |
| 50 | gate := newSamePeerInputGate() | 50 | gate := newSamePeerInputGate() | ||
| 51 | gate.setPaused(true) | 51 | gate.setPaused(true) | ||
| 52 | held := make(chan struct{}) | 52 | held := make(chan struct{}) | ||
| 53 | gate.afterInputHeld = func() { close(held) } | 53 | gate.afterInputHeld = func() { close(held) } | ||
| 54 | - | transport := &ackRecordingTransport{sent: make(chan ports.Frame, 2)} | 54 | + | transport := &ackRecordingTransport{sent: make(chan wire.Frame, 2)} |
| 55 | acks := newCumulativeAckQueue() | 55 | acks := newCumulativeAckQueue() | ||
| 56 | errs := make(chan error, 1) | 56 | errs := make(chan error, 1) | ||
| 57 | go runSender(ctx, cancel, transport, control, nil, normal, gate, acks, errs, slog.Default()) | 57 | go runSender(ctx, cancel, transport, control, nil, normal, gate, acks, errs, slog.Default()) | ||
| 58 | 58 | ||||
| 59 | - | normal <- ports.Frame{Type: ports.MsgInput, Payload: []byte("held")} | 59 | + | normal <- wire.Frame{Type: wire.MsgInput, Payload: []byte("held")} |
| 60 | awaitSenderSignal(t, held) | 60 | awaitSenderSignal(t, held) | ||
| 61 | - | control <- ports.Frame{Type: ports.MsgSamePeerSwitchRequest, Payload: []byte("switch")} | 61 | + | control <- wire.Frame{Type: wire.MsgSamePeerSwitchRequest, Payload: []byte("switch")} |
| 62 | - | if got := awaitSenderFrame(t, transport.sent); got.Type != ports.MsgSamePeerSwitchRequest { | 62 | + | if got := awaitSenderFrame(t, transport.sent); got.Type != wire.MsgSamePeerSwitchRequest { |
| 63 | t.Fatalf("first frame = %d, want same-peer switch request", got.Type) | 63 | t.Fatalf("first frame = %d, want same-peer switch request", got.Type) | ||
| 64 | } | 64 | } | ||
| 65 | select { | 65 | select { | ||
| @@ -68,7 +68,7 @@ func TestSamePeerSwitchControlBypassesHeldInput(t *testing.T) { | |||||
| 68 | default: | 68 | default: | ||
| 69 | } | 69 | } | ||
| 70 | gate.setPaused(false) | 70 | gate.setPaused(false) | ||
| 71 | - | if got := awaitSenderFrame(t, transport.sent); got.Type != ports.MsgInput { | 71 | + | if got := awaitSenderFrame(t, transport.sent); got.Type != wire.MsgInput { |
| 72 | t.Fatalf("released frame = %d, want input", got.Type) | 72 | t.Fatalf("released frame = %d, want input", got.Type) | ||
| 73 | } | 73 | } | ||
| 74 | } | 74 | } | ||
| @@ -76,14 +76,14 @@ func TestSamePeerSwitchControlBypassesHeldInput(t *testing.T) { | |||||
| 76 | func TestSenderBarrierLeavesPausedInputQueued(t *testing.T) { | 76 | func TestSenderBarrierLeavesPausedInputQueued(t *testing.T) { | ||
| 77 | ctx, cancel := context.WithCancel(context.Background()) | 77 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 78 | defer cancel() | 78 | defer cancel() | ||
| 79 | - | normal := make(chan ports.Frame, 1) | 79 | + | normal := make(chan wire.Frame, 1) |
| 80 | barriers := make(chan chan struct{}) | 80 | barriers := make(chan chan struct{}) | ||
| 81 | gate := newSamePeerInputGate() | 81 | gate := newSamePeerInputGate() | ||
| 82 | gate.setPaused(true) | 82 | gate.setPaused(true) | ||
| 83 | - | transport := &ackRecordingTransport{sent: make(chan ports.Frame, 1)} | 83 | + | transport := &ackRecordingTransport{sent: make(chan wire.Frame, 1)} |
| 84 | go runSender(ctx, cancel, transport, nil, barriers, normal, gate, newCumulativeAckQueue(), make(chan error, 1), slog.Default()) | 84 | go runSender(ctx, cancel, transport, nil, barriers, normal, gate, newCumulativeAckQueue(), make(chan error, 1), slog.Default()) | ||
| 85 | 85 | ||||
| 86 | - | normal <- ports.Frame{Type: ports.MsgInput, Payload: []byte("held")} | 86 | + | normal <- wire.Frame{Type: wire.MsgInput, Payload: []byte("held")} |
| 87 | barrierDone := make(chan struct{}) | 87 | barrierDone := make(chan struct{}) | ||
| 88 | barriers <- barrierDone | 88 | barriers <- barrierDone | ||
| 89 | awaitSenderSignal(t, barrierDone) | 89 | awaitSenderSignal(t, barrierDone) | ||
| @@ -94,7 +94,7 @@ func TestSenderBarrierLeavesPausedInputQueued(t *testing.T) { | |||||
| 94 | } | 94 | } | ||
| 95 | 95 | ||||
| 96 | gate.setPaused(false) | 96 | gate.setPaused(false) | ||
| 97 | - | if got := awaitSenderFrame(t, transport.sent); got.Type != ports.MsgInput { | 97 | + | if got := awaitSenderFrame(t, transport.sent); got.Type != wire.MsgInput { |
| 98 | t.Fatalf("released frame = %d, want input", got.Type) | 98 | t.Fatalf("released frame = %d, want input", got.Type) | ||
| 99 | } | 99 | } | ||
| 100 | } | 100 | } | ||
| @@ -104,14 +104,14 @@ func TestSenderBarrierFlushesPendingAck(t *testing.T) { | |||||
| 104 | defer cancel() | 104 | defer cancel() | ||
| 105 | acks := newCumulativeAckQueue() | 105 | acks := newCumulativeAckQueue() | ||
| 106 | acks.offer(3, 9) | 106 | acks.offer(3, 9) | ||
| 107 | - | transport := &ackRecordingTransport{sent: make(chan ports.Frame, 1)} | 107 | + | transport := &ackRecordingTransport{sent: make(chan wire.Frame, 1)} |
| 108 | barriers := make(chan chan struct{}) | 108 | barriers := make(chan chan struct{}) | ||
| 109 | - | go runSender(ctx, cancel, transport, nil, barriers, make(chan ports.Frame, 1), newSamePeerInputGate(), acks, make(chan error, 1), slog.Default()) | 109 | + | go runSender(ctx, cancel, transport, nil, barriers, make(chan wire.Frame, 1), newSamePeerInputGate(), acks, make(chan error, 1), slog.Default()) |
| 110 | 110 | ||||
| 111 | done := make(chan struct{}) | 111 | done := make(chan struct{}) | ||
| 112 | barriers <- done | 112 | barriers <- done | ||
| 113 | frame := awaitSenderFrame(t, transport.sent) | 113 | frame := awaitSenderFrame(t, transport.sent) | ||
| 114 | - | require.Equal(t, ports.MsgAck, frame.Type) | 114 | + | require.Equal(t, wire.MsgAck, frame.Type) |
| 115 | awaitSenderSignal(t, done) | 115 | awaitSenderSignal(t, done) | ||
| 116 | } | 116 | } | ||
| 117 | 117 | ||||
| @@ -124,14 +124,14 @@ func awaitSenderSignal(t *testing.T, signal <-chan struct{}) { | |||||
| 124 | } | 124 | } | ||
| 125 | } | 125 | } | ||
| 126 | 126 | ||||
| 127 | - | func awaitSenderFrame(t *testing.T, frames <-chan ports.Frame) ports.Frame { | 127 | + | func awaitSenderFrame(t *testing.T, frames <-chan wire.Frame) wire.Frame { |
| 128 | t.Helper() | 128 | t.Helper() | ||
| 129 | select { | 129 | select { | ||
| 130 | case frame := <-frames: | 130 | case frame := <-frames: | ||
| 131 | return frame | 131 | return frame | ||
| 132 | case <-time.After(time.Second): | 132 | case <-time.After(time.Second): | ||
| 133 | t.Fatal("sender did not emit frame") | 133 | t.Fatal("sender did not emit frame") | ||
| 134 | - | return ports.Frame{} | 134 | + | return wire.Frame{} |
| 135 | } | 135 | } | ||
| 136 | } | 136 | } | ||
| 137 | 137 | ||||
M internal/usecase/client/client.go +74 -73
| @@ -24,6 +24,7 @@ import ( | |||||
| 24 | "github.com/bnema/vev/internal/domain" | 24 | "github.com/bnema/vev/internal/domain" | ||
| 25 | "github.com/bnema/vev/internal/ports" | 25 | "github.com/bnema/vev/internal/ports" | ||
| 26 | "github.com/bnema/vev/internal/protocol" | 26 | "github.com/bnema/vev/internal/protocol" | ||
| 27 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 27 | "github.com/bnema/vev/internal/usecase/theme" | 28 | "github.com/bnema/vev/internal/usecase/theme" | ||
| 28 | ) | 29 | ) | ||
| 29 | 30 | ||||
| @@ -1243,14 +1244,14 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1243 | Remote: remote, | 1244 | Remote: remote, | ||
| 1244 | } | 1245 | } | ||
| 1245 | if err := sendHandshake(func() error { | 1246 | if err := sendHandshake(func() error { | ||
| 1246 | - | return transport.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}) | 1247 | + | return transport.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}) |
| 1247 | }); err != nil { | 1248 | }); err != nil { | ||
| 1248 | return handshakeFailure("sending hello", err) | 1249 | return handshakeFailure("sending hello", err) | ||
| 1249 | } | 1250 | } | ||
| 1250 | ms.helloSent = true | 1251 | ms.helloSent = true | ||
| 1251 | 1252 | ||||
| 1252 | // 2. Await Welcome or a typed rejection. | 1253 | // 2. Await Welcome or a typed rejection. | ||
| 1253 | - | var reply ports.Frame | 1254 | + | var reply wire.Frame |
| 1254 | if err := boundedHandshakeOperationWithTransition(handshakeCtx, transport, func() error { | 1255 | if err := boundedHandshakeOperationWithTransition(handshakeCtx, transport, func() error { | ||
| 1255 | var recvErr error | 1256 | var recvErr error | ||
| 1256 | reply, recvErr = transport.Recv() | 1257 | reply, recvErr = transport.Recv() | ||
| @@ -1271,8 +1272,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1271 | } | 1272 | } | ||
| 1272 | } | 1273 | } | ||
| 1273 | switch reply.Type { | 1274 | switch reply.Type { | ||
| 1274 | - | case ports.MsgWelcome: | 1275 | + | case wire.MsgWelcome: |
| 1275 | - | welcome, derr := ports.UnmarshalWelcome(reply.Payload) | 1276 | + | welcome, derr := wire.UnmarshalWelcome(reply.Payload) |
| 1276 | if derr != nil { | 1277 | if derr != nil { | ||
| 1277 | return result(false, fmt.Errorf("vev: decoding welcome: %w", derr)) | 1278 | return result(false, fmt.Errorf("vev: decoding welcome: %w", derr)) | ||
| 1278 | } | 1279 | } | ||
| @@ -1286,8 +1287,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1286 | remember() | 1287 | remember() | ||
| 1287 | } | 1288 | } | ||
| 1288 | } | 1289 | } | ||
| 1289 | - | case ports.MsgError: | 1290 | + | case wire.MsgError: |
| 1290 | - | em, derr := ports.UnmarshalErrorMsg(reply.Payload) | 1291 | + | em, derr := wire.UnmarshalErrorMsg(reply.Payload) |
| 1291 | if derr != nil { | 1292 | if derr != nil { | ||
| 1292 | return result(false, fmt.Errorf("vev: decoding error reply: %w", derr)) | 1293 | return result(false, fmt.Errorf("vev: decoding error reply: %w", derr)) | ||
| 1293 | } | 1294 | } | ||
| @@ -1319,30 +1320,30 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1319 | return welcomedResult(fmt.Errorf("vev: committing route identity: %w", commitErr)) | 1320 | return welcomedResult(fmt.Errorf("vev: committing route identity: %w", commitErr)) | ||
| 1320 | } | 1321 | } | ||
| 1321 | } | 1322 | } | ||
| 1322 | - | snapshotPayload, err := ports.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) | 1323 | + | snapshotPayload, err := wire.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) |
| 1323 | if err != nil { | 1324 | if err != nil { | ||
| 1324 | return welcomedResult(fmt.Errorf("vev: encoding route snapshot: %w", err)) | 1325 | return welcomedResult(fmt.Errorf("vev: encoding route snapshot: %w", err)) | ||
| 1325 | } | 1326 | } | ||
| 1326 | - | attentionPayload, err := ports.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) | 1327 | + | attentionPayload, err := wire.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) |
| 1327 | if err != nil { | 1328 | if err != nil { | ||
| 1328 | return welcomedResult(fmt.Errorf("vev: encoding route attention subscription: %w", err)) | 1329 | return welcomedResult(fmt.Errorf("vev: encoding route attention subscription: %w", err)) | ||
| 1329 | } | 1330 | } | ||
| 1330 | if err := sendHandshake(func() error { | 1331 | if err := sendHandshake(func() error { | ||
| 1331 | - | if err := transport.Send(ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: snapshotPayload}); err != nil { | 1332 | + | if err := transport.Send(wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: snapshotPayload}); err != nil { |
| 1332 | return err | 1333 | return err | ||
| 1333 | } | 1334 | } | ||
| 1334 | - | return transport.Send(ports.Frame{Type: ports.MsgRouteAttentionSubscription, Payload: attentionPayload}) | 1335 | + | return transport.Send(wire.Frame{Type: wire.MsgRouteAttentionSubscription, Payload: attentionPayload}) |
| 1335 | }); err != nil { | 1336 | }); err != nil { | ||
| 1336 | return welcomedResult(fmt.Errorf("vev: publishing route snapshot: %w", err)) | 1337 | return welcomedResult(fmt.Errorf("vev: publishing route snapshot: %w", err)) | ||
| 1337 | } | 1338 | } | ||
| 1338 | } | 1339 | } | ||
| 1339 | if a.runner.routeFailure != nil { | 1340 | if a.runner.routeFailure != nil { | ||
| 1340 | - | payload, err := ports.MarshalRouteNavigationFailure(*a.runner.routeFailure) | 1341 | + | payload, err := wire.MarshalRouteNavigationFailure(*a.runner.routeFailure) |
| 1341 | if err != nil { | 1342 | if err != nil { | ||
| 1342 | return welcomedResult(fmt.Errorf("vev: encoding route navigation failure: %w", err)) | 1343 | return welcomedResult(fmt.Errorf("vev: encoding route navigation failure: %w", err)) | ||
| 1343 | } | 1344 | } | ||
| 1344 | if err := sendHandshake(func() error { | 1345 | if err := sendHandshake(func() error { | ||
| 1345 | - | return transport.Send(ports.Frame{Type: ports.MsgRouteNavigationFailure, Payload: payload}) | 1346 | + | return transport.Send(wire.Frame{Type: wire.MsgRouteNavigationFailure, Payload: payload}) |
| 1346 | }); err != nil { | 1347 | }); err != nil { | ||
| 1347 | return welcomedResult(fmt.Errorf("vev: publishing route navigation failure: %w", err)) | 1348 | return welcomedResult(fmt.Errorf("vev: publishing route navigation failure: %w", err)) | ||
| 1348 | } | 1349 | } | ||
| @@ -1369,8 +1370,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1369 | input.start() | 1370 | input.start() | ||
| 1370 | defer input.stop() | 1371 | defer input.stop() | ||
| 1371 | } | 1372 | } | ||
| 1372 | - | sendCh := make(chan ports.Frame, sendQueueDepth) | 1373 | + | sendCh := make(chan wire.Frame, sendQueueDepth) |
| 1373 | - | controlCh := make(chan ports.Frame, 1) | 1374 | + | controlCh := make(chan wire.Frame, 1) |
| 1374 | barrierCh := make(chan chan struct{}) | 1375 | barrierCh := make(chan chan struct{}) | ||
| 1375 | inputGate := newSamePeerInputGate() | 1376 | inputGate := newSamePeerInputGate() | ||
| 1376 | ackQueue := newCumulativeAckQueue() | 1377 | ackQueue := newCumulativeAckQueue() | ||
| @@ -1393,7 +1394,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1393 | } | 1394 | } | ||
| 1394 | } | 1395 | } | ||
| 1395 | publish := func(snapshot protocol.Theme) error { | 1396 | publish := func(snapshot protocol.Theme) error { | ||
| 1396 | - | frame := ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(snapshot)} | 1397 | + | frame := wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(snapshot)} |
| 1397 | // The initial cleared snapshot is sent before the sender exists. This | 1398 | // The initial cleared snapshot is sent before the sender exists. This | ||
| 1398 | // keeps the generation publication ordered before the first query and | 1399 | // keeps the generation publication ordered before the first query and | ||
| 1399 | // avoids leaving a queued Theme behind an immediate detach. | 1400 | // avoids leaving a queued Theme behind an immediate detach. | ||
| @@ -1503,11 +1504,11 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1503 | // Before the asynchronous sender starts, preserve transport ordering by | 1504 | // Before the asynchronous sender starts, preserve transport ordering by | ||
| 1504 | // requesting the reset synchronously after the initial Theme publication. | 1505 | // requesting the reset synchronously after the initial Theme publication. | ||
| 1505 | resetErr := sendHandshake(func() error { | 1506 | resetErr := sendHandshake(func() error { | ||
| 1506 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | 1507 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) |
| 1507 | if err != nil { | 1508 | if err != nil { | ||
| 1508 | return err | 1509 | return err | ||
| 1509 | } | 1510 | } | ||
| 1510 | - | return transport.Send(ports.Frame{Type: ports.MsgResize, Payload: payload}) | 1511 | + | return transport.Send(wire.Frame{Type: wire.MsgResize, Payload: payload}) |
| 1511 | }) | 1512 | }) | ||
| 1512 | if resetErr != nil { | 1513 | if resetErr != nil { | ||
| 1513 | resetErr = handshakeContextError(ctx, handshakeTimedOut, resetErr) | 1514 | resetErr = handshakeContextError(ctx, handshakeTimedOut, resetErr) | ||
| @@ -1629,12 +1630,12 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1629 | return fmt.Errorf("reading terminal geometry for parked route: %w", err) | 1630 | return fmt.Errorf("reading terminal geometry for parked route: %w", err) | ||
| 1630 | } | 1631 | } | ||
| 1631 | geometry = geometry.NormalizePixels() | 1632 | geometry = geometry.NormalizePixels() | ||
| 1632 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | 1633 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) |
| 1633 | if err != nil { | 1634 | if err != nil { | ||
| 1634 | return fmt.Errorf("encoding terminal size for parked route: %w", err) | 1635 | return fmt.Errorf("encoding terminal size for parked route: %w", err) | ||
| 1635 | } | 1636 | } | ||
| 1636 | select { | 1637 | select { | ||
| 1637 | - | case controlCh <- ports.Frame{Type: ports.MsgResize, Payload: payload}: | 1638 | + | case controlCh <- wire.Frame{Type: wire.MsgResize, Payload: payload}: |
| 1638 | return nil | 1639 | return nil | ||
| 1639 | case <-loopCtx.Done(): | 1640 | case <-loopCtx.Done(): | ||
| 1640 | return context.Canceled | 1641 | return context.Canceled | ||
| @@ -1646,12 +1647,12 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1646 | } | 1647 | } | ||
| 1647 | nextParkedRequestID++ | 1648 | nextParkedRequestID++ | ||
| 1648 | request := protocol.ParkedRouteRequest{RequestID: nextParkedRequestID, LeaseID: leaseID, Action: action, Target: target} | 1649 | request := protocol.ParkedRouteRequest{RequestID: nextParkedRequestID, LeaseID: leaseID, Action: action, Target: target} | ||
| 1649 | - | payload := ports.MarshalParkedRouteRequest(request) | 1650 | + | payload := wire.MarshalParkedRouteRequest(request) |
| 1650 | if payload == nil { | 1651 | if payload == nil { | ||
| 1651 | return errors.New("vev: invalid parked-route request") | 1652 | return errors.New("vev: invalid parked-route request") | ||
| 1652 | } | 1653 | } | ||
| 1653 | select { | 1654 | select { | ||
| 1654 | - | case controlCh <- ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: payload}: | 1655 | + | case controlCh <- wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: payload}: |
| 1655 | parkedPending = &parkedRoutePending{ | 1656 | parkedPending = &parkedRoutePending{ | ||
| 1656 | requestID: request.RequestID, action: action, leaseID: leaseID, | 1657 | requestID: request.RequestID, action: action, leaseID: leaseID, | ||
| 1657 | timer: clk.NewTimer(protocol.HandshakeTimeout), | 1658 | timer: clk.NewTimer(protocol.HandshakeTimeout), | ||
| @@ -1726,12 +1727,12 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1726 | return fmt.Errorf("reading terminal geometry for reconnect reconciliation: %w", serr) | 1727 | return fmt.Errorf("reading terminal geometry for reconnect reconciliation: %w", serr) | ||
| 1727 | } | 1728 | } | ||
| 1728 | geometry = geometry.NormalizePixels() | 1729 | geometry = geometry.NormalizePixels() | ||
| 1729 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | 1730 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) |
| 1730 | if err != nil { | 1731 | if err != nil { | ||
| 1731 | return fmt.Errorf("encoding terminal size for reconnect reconciliation: %w", err) | 1732 | return fmt.Errorf("encoding terminal size for reconnect reconciliation: %w", err) | ||
| 1732 | } | 1733 | } | ||
| 1733 | select { | 1734 | select { | ||
| 1734 | - | case sendCh <- ports.Frame{Type: ports.MsgResize, Payload: payload}: | 1735 | + | case sendCh <- wire.Frame{Type: wire.MsgResize, Payload: payload}: |
| 1735 | awaitingReconnectReset = true | 1736 | awaitingReconnectReset = true | ||
| 1736 | return nil | 1737 | return nil | ||
| 1737 | case <-loopCtx.Done(): | 1738 | case <-loopCtx.Done(): | ||
| @@ -1742,17 +1743,17 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1742 | if a.runner.ledger == nil { | 1743 | if a.runner.ledger == nil { | ||
| 1743 | return errors.New("vev: route ledger unavailable") | 1744 | return errors.New("vev: route ledger unavailable") | ||
| 1744 | } | 1745 | } | ||
| 1745 | - | snapshotPayload, err := ports.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) | 1746 | + | snapshotPayload, err := wire.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) |
| 1746 | if err != nil { | 1747 | if err != nil { | ||
| 1747 | return err | 1748 | return err | ||
| 1748 | } | 1749 | } | ||
| 1749 | - | attentionPayload, err := ports.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) | 1750 | + | attentionPayload, err := wire.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) |
| 1750 | if err != nil { | 1751 | if err != nil { | ||
| 1751 | return err | 1752 | return err | ||
| 1752 | } | 1753 | } | ||
| 1753 | - | for _, frame := range []ports.Frame{ | 1754 | + | for _, frame := range []wire.Frame{ |
| 1754 | - | {Type: ports.MsgRecentRouteSnapshot, Payload: snapshotPayload}, | 1755 | + | {Type: wire.MsgRecentRouteSnapshot, Payload: snapshotPayload}, |
| 1755 | - | {Type: ports.MsgRouteAttentionSubscription, Payload: attentionPayload}, | 1756 | + | {Type: wire.MsgRouteAttentionSubscription, Payload: attentionPayload}, |
| 1756 | } { | 1757 | } { | ||
| 1757 | select { | 1758 | select { | ||
| 1758 | case sendCh <- frame: | 1759 | case sendCh <- frame: | ||
| @@ -1763,7 +1764,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1763 | return nil | 1764 | return nil | ||
| 1764 | } | 1765 | } | ||
| 1765 | sendRouteFailure := func(action protocol.RouteNavigationAction, code protocol.RouteFailureCode) error { | 1766 | sendRouteFailure := func(action protocol.RouteNavigationAction, code protocol.RouteFailureCode) error { | ||
| 1766 | - | payload, err := ports.MarshalRouteNavigationFailure(protocol.RouteNavigationFailure{ | 1767 | + | payload, err := wire.MarshalRouteNavigationFailure(protocol.RouteNavigationFailure{ |
| 1767 | Key: action.Key, | 1768 | Key: action.Key, | ||
| 1768 | Generation: action.Generation, | 1769 | Generation: action.Generation, | ||
| 1769 | Code: code, | 1770 | Code: code, | ||
| @@ -1772,7 +1773,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1772 | return err | 1773 | return err | ||
| 1773 | } | 1774 | } | ||
| 1774 | select { | 1775 | select { | ||
| 1775 | - | case sendCh <- ports.Frame{Type: ports.MsgRouteNavigationFailure, Payload: payload}: | 1776 | + | case sendCh <- wire.Frame{Type: wire.MsgRouteNavigationFailure, Payload: payload}: |
| 1776 | return nil | 1777 | return nil | ||
| 1777 | case <-loopCtx.Done(): | 1778 | case <-loopCtx.Done(): | ||
| 1778 | return context.Canceled | 1779 | return context.Canceled | ||
| @@ -1827,7 +1828,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1827 | return welcomedResult(fmt.Errorf("dismissing reconnect toast: %w", err)) | 1828 | return welcomedResult(fmt.Errorf("dismissing reconnect toast: %w", err)) | ||
| 1828 | } | 1829 | } | ||
| 1829 | select { | 1830 | select { | ||
| 1830 | - | case sendCh <- ports.Frame{Type: ports.MsgClientNotice, Payload: ports.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkConnected})}: | 1831 | + | case sendCh <- wire.Frame{Type: wire.MsgClientNotice, Payload: wire.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkConnected})}: |
| 1831 | case <-loopCtx.Done(): | 1832 | case <-loopCtx.Done(): | ||
| 1832 | return welcomedResult(nil) | 1833 | return welcomedResult(nil) | ||
| 1833 | } | 1834 | } | ||
| @@ -1836,7 +1837,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1836 | if ev.State == ports.LinkStateDegraded { | 1837 | if ev.State == ports.LinkStateDegraded { | ||
| 1837 | log.Warn("UDP link degraded") | 1838 | log.Warn("UDP link degraded") | ||
| 1838 | select { | 1839 | select { | ||
| 1839 | - | case sendCh <- ports.Frame{Type: ports.MsgClientNotice, Payload: ports.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkDegraded})}: | 1840 | + | case sendCh <- wire.Frame{Type: wire.MsgClientNotice, Payload: wire.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkDegraded})}: |
| 1840 | case <-loopCtx.Done(): | 1841 | case <-loopCtx.Done(): | ||
| 1841 | return welcomedResult(nil) | 1842 | return welcomedResult(nil) | ||
| 1842 | } | 1843 | } | ||
| @@ -1884,8 +1885,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1884 | return welcomedResult(fmt.Errorf("vev: receiving from daemon: %w", r.err)) | 1885 | return welcomedResult(fmt.Errorf("vev: receiving from daemon: %w", r.err)) | ||
| 1885 | } | 1886 | } | ||
| 1886 | switch r.frame.Type { | 1887 | switch r.frame.Type { | ||
| 1887 | - | case ports.MsgOutput: | 1888 | + | case wire.MsgOutput: |
| 1888 | - | o, derr := ports.UnmarshalOutput(r.frame.Payload) | 1889 | + | o, derr := wire.UnmarshalOutput(r.frame.Payload) |
| 1889 | if derr != nil { | 1890 | if derr != nil { | ||
| 1890 | return welcomedResult(fmt.Errorf("vev: decoding output: %w", derr)) | 1891 | return welcomedResult(fmt.Errorf("vev: decoding output: %w", derr)) | ||
| 1891 | } | 1892 | } | ||
| @@ -1896,7 +1897,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1896 | // repeated gaps while that reset is in flight. | 1897 | // repeated gaps while that reset is in flight. | ||
| 1897 | if !outputResetRequested { | 1898 | if !outputResetRequested { | ||
| 1898 | select { | 1899 | select { | ||
| 1899 | - | case sendCh <- ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: | 1900 | + | case sendCh <- wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: |
| 1900 | outputResetRequested = true | 1901 | outputResetRequested = true | ||
| 1901 | case <-loopCtx.Done(): | 1902 | case <-loopCtx.Done(): | ||
| 1902 | return loopCanceledResult() | 1903 | return loopCanceledResult() | ||
| @@ -1946,8 +1947,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1946 | log.Debug("received first output") | 1947 | log.Debug("received first output") | ||
| 1947 | endHandshake() | 1948 | endHandshake() | ||
| 1948 | } | 1949 | } | ||
| 1949 | - | case ports.MsgAttachTarget: | 1950 | + | case wire.MsgAttachTarget: |
| 1950 | - | target, derr := ports.UnmarshalAttachTarget(r.frame.Payload) | 1951 | + | target, derr := wire.UnmarshalAttachTarget(r.frame.Payload) |
| 1951 | if derr != nil { | 1952 | if derr != nil { | ||
| 1952 | return welcomedResult(fmt.Errorf("vev: decoding attach target: %w", derr)) | 1953 | return welcomedResult(fmt.Errorf("vev: decoding attach target: %w", derr)) | ||
| 1953 | } | 1954 | } | ||
| @@ -1966,7 +1967,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1966 | } | 1967 | } | ||
| 1967 | nextSamePeerRequestID++ | 1968 | nextSamePeerRequestID++ | ||
| 1968 | request := a.runner.ledger.samePeerHandoff(request, target) | 1969 | request := a.runner.ledger.samePeerHandoff(request, target) | ||
| 1969 | - | payload, err := ports.MarshalSamePeerSwitchRequest(protocol.SamePeerSwitchRequest{ | 1970 | + | payload, err := wire.MarshalSamePeerSwitchRequest(protocol.SamePeerSwitchRequest{ |
| 1970 | RequestID: nextSamePeerRequestID, | 1971 | RequestID: nextSamePeerRequestID, | ||
| 1971 | Target: *target.ExactTarget, | 1972 | Target: *target.ExactTarget, | ||
| 1972 | PreferredTabID: request.PreferredTabID, | 1973 | PreferredTabID: request.PreferredTabID, | ||
| @@ -1977,7 +1978,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1977 | samePeerSwitch = &samePeerSwitchPending{requestID: nextSamePeerRequestID, target: *target.ExactTarget} | 1978 | samePeerSwitch = &samePeerSwitchPending{requestID: nextSamePeerRequestID, target: *target.ExactTarget} | ||
| 1978 | inputGate.setPaused(true) | 1979 | inputGate.setPaused(true) | ||
| 1979 | select { | 1980 | select { | ||
| 1980 | - | case controlCh <- ports.Frame{Type: ports.MsgSamePeerSwitchRequest, Payload: payload}: | 1981 | + | case controlCh <- wire.Frame{Type: wire.MsgSamePeerSwitchRequest, Payload: payload}: |
| 1981 | continue | 1982 | continue | ||
| 1982 | case <-loopCtx.Done(): | 1983 | case <-loopCtx.Done(): | ||
| 1983 | return loopCanceledResult() | 1984 | return loopCanceledResult() | ||
| @@ -1986,8 +1987,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 1986 | handoff := welcomedResult(nil) | 1987 | handoff := welcomedResult(nil) | ||
| 1987 | handoff.target = &target | 1988 | handoff.target = &target | ||
| 1988 | return handoff | 1989 | return handoff | ||
| 1989 | - | case ports.MsgParkedRouteResponse: | 1990 | + | case wire.MsgParkedRouteResponse: |
| 1990 | - | response, derr := ports.UnmarshalParkedRouteResponse(r.frame.Payload) | 1991 | + | response, derr := wire.UnmarshalParkedRouteResponse(r.frame.Payload) |
| 1991 | if derr != nil { | 1992 | if derr != nil { | ||
| 1992 | return welcomedResult(fmt.Errorf("vev: decoding parked-route response: %w", derr)) | 1993 | return welcomedResult(fmt.Errorf("vev: decoding parked-route response: %w", derr)) | ||
| 1993 | } | 1994 | } | ||
| @@ -2033,8 +2034,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2033 | return fallback | 2034 | return fallback | ||
| 2034 | } | 2035 | } | ||
| 2035 | } | 2036 | } | ||
| 2036 | - | case ports.MsgNavigationAction: | 2037 | + | case wire.MsgNavigationAction: |
| 2037 | - | directive, derr := ports.UnmarshalNavigationDirective(r.frame.Payload) | 2038 | + | directive, derr := wire.UnmarshalNavigationDirective(r.frame.Payload) |
| 2038 | if derr != nil { | 2039 | if derr != nil { | ||
| 2039 | return welcomedResult(fmt.Errorf("vev: decoding navigation action: %w", derr)) | 2040 | return welcomedResult(fmt.Errorf("vev: decoding navigation action: %w", derr)) | ||
| 2040 | } | 2041 | } | ||
| @@ -2052,8 +2053,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2052 | navigation := welcomedResult(nil) | 2053 | navigation := welcomedResult(nil) | ||
| 2053 | navigation.action = directive.Action | 2054 | navigation.action = directive.Action | ||
| 2054 | return navigation | 2055 | return navigation | ||
| 2055 | - | case ports.MsgNavigateRecentRoute: | 2056 | + | case wire.MsgNavigateRecentRoute: |
| 2056 | - | action, derr := ports.UnmarshalRouteNavigationAction(r.frame.Payload) | 2057 | + | action, derr := wire.UnmarshalRouteNavigationAction(r.frame.Payload) |
| 2057 | if derr != nil { | 2058 | if derr != nil { | ||
| 2058 | return welcomedResult(fmt.Errorf("vev: decoding route navigation action: %w", derr)) | 2059 | return welcomedResult(fmt.Errorf("vev: decoding route navigation action: %w", derr)) | ||
| 2059 | } | 2060 | } | ||
| @@ -2076,8 +2077,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2076 | navigation := welcomedResult(nil) | 2077 | navigation := welcomedResult(nil) | ||
| 2077 | navigation.routeAction = &action | 2078 | navigation.routeAction = &action | ||
| 2078 | return navigation | 2079 | return navigation | ||
| 2079 | - | case ports.MsgCommittedRouteIdentity: | 2080 | + | case wire.MsgCommittedRouteIdentity: |
| 2080 | - | identity, derr := ports.UnmarshalCommittedRouteIdentity(r.frame.Payload) | 2081 | + | identity, derr := wire.UnmarshalCommittedRouteIdentity(r.frame.Payload) |
| 2081 | if derr != nil { | 2082 | if derr != nil { | ||
| 2082 | return welcomedResult(fmt.Errorf("vev: decoding committed route identity: %w", derr)) | 2083 | return welcomedResult(fmt.Errorf("vev: decoding committed route identity: %w", derr)) | ||
| 2083 | } | 2084 | } | ||
| @@ -2099,8 +2100,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2099 | samePeerSwitch = nil | 2100 | samePeerSwitch = nil | ||
| 2100 | inputGate.setPaused(false) | 2101 | inputGate.setPaused(false) | ||
| 2101 | } | 2102 | } | ||
| 2102 | - | case ports.MsgSamePeerSwitchFailure: | 2103 | + | case wire.MsgSamePeerSwitchFailure: |
| 2103 | - | failure, derr := ports.UnmarshalSamePeerSwitchFailure(r.frame.Payload) | 2104 | + | failure, derr := wire.UnmarshalSamePeerSwitchFailure(r.frame.Payload) |
| 2104 | if derr != nil { | 2105 | if derr != nil { | ||
| 2105 | return welcomedResult(fmt.Errorf("vev: decoding same-peer switch failure: %w", derr)) | 2106 | return welcomedResult(fmt.Errorf("vev: decoding same-peer switch failure: %w", derr)) | ||
| 2106 | } | 2107 | } | ||
| @@ -2111,7 +2112,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2111 | transitionWaitingFull = true | 2112 | transitionWaitingFull = true | ||
| 2112 | if !outputResetRequested { | 2113 | if !outputResetRequested { | ||
| 2113 | select { | 2114 | select { | ||
| 2114 | - | case sendCh <- ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: | 2115 | + | case sendCh <- wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: |
| 2115 | outputResetRequested = true | 2116 | outputResetRequested = true | ||
| 2116 | case <-loopCtx.Done(): | 2117 | case <-loopCtx.Done(): | ||
| 2117 | return loopCanceledResult() | 2118 | return loopCanceledResult() | ||
| @@ -2121,8 +2122,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2121 | transition.stop() | 2122 | transition.stop() | ||
| 2122 | } | 2123 | } | ||
| 2123 | } | 2124 | } | ||
| 2124 | - | case ports.MsgRoutePosition: | 2125 | + | case wire.MsgRoutePosition: |
| 2125 | - | position, derr := ports.UnmarshalRoutePosition(r.frame.Payload) | 2126 | + | position, derr := wire.UnmarshalRoutePosition(r.frame.Payload) |
| 2126 | if derr != nil { | 2127 | if derr != nil { | ||
| 2127 | return welcomedResult(fmt.Errorf("vev: decoding route position: %w", derr)) | 2128 | return welcomedResult(fmt.Errorf("vev: decoding route position: %w", derr)) | ||
| 2128 | } | 2129 | } | ||
| @@ -2133,14 +2134,14 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2133 | return welcomedResult(fmt.Errorf("vev: remembering route position: %w", derr)) | 2134 | return welcomedResult(fmt.Errorf("vev: remembering route position: %w", derr)) | ||
| 2134 | } | 2135 | } | ||
| 2135 | routePosition = cloneRoutePosition(&position) | 2136 | routePosition = cloneRoutePosition(&position) | ||
| 2136 | - | case ports.MsgRouteNavigationFailure: | 2137 | + | case wire.MsgRouteNavigationFailure: |
| 2137 | - | failure, derr := ports.UnmarshalRouteNavigationFailure(r.frame.Payload) | 2138 | + | failure, derr := wire.UnmarshalRouteNavigationFailure(r.frame.Payload) |
| 2138 | if derr != nil { | 2139 | if derr != nil { | ||
| 2139 | return welcomedResult(fmt.Errorf("vev: decoding route navigation failure: %w", derr)) | 2140 | return welcomedResult(fmt.Errorf("vev: decoding route navigation failure: %w", derr)) | ||
| 2140 | } | 2141 | } | ||
| 2141 | log.Warn("route navigation rejected", "key", failure.Key, "generation", failure.Generation, "code", failure.Code) | 2142 | log.Warn("route navigation rejected", "key", failure.Key, "generation", failure.Generation, "code", failure.Code) | ||
| 2142 | - | case ports.MsgDetached: | 2143 | + | case wire.MsgDetached: |
| 2143 | - | d, derr := ports.UnmarshalDetached(r.frame.Payload) | 2144 | + | d, derr := wire.UnmarshalDetached(r.frame.Payload) |
| 2144 | if derr != nil { | 2145 | if derr != nil { | ||
| 2145 | return welcomedResult(fmt.Errorf("vev: decoding detached: %w", derr)) | 2146 | return welcomedResult(fmt.Errorf("vev: decoding detached: %w", derr)) | ||
| 2146 | } | 2147 | } | ||
| @@ -2151,7 +2152,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2151 | log.Warn("detached by daemon", "reason", d.Reason) | 2152 | log.Warn("detached by daemon", "reason", d.Reason) | ||
| 2152 | } | 2153 | } | ||
| 2153 | return welcomedResult(detachedResult(d.Reason)) | 2154 | return welcomedResult(detachedResult(d.Reason)) | ||
| 2154 | - | case ports.MsgPong: | 2155 | + | case wire.MsgPong: |
| 2155 | // Liveness reply; nothing to do. | 2156 | // Liveness reply; nothing to do. | ||
| 2156 | default: | 2157 | default: | ||
| 2157 | // Unknown/out-of-band message types are ignored so a newer | 2158 | // Unknown/out-of-band message types are ignored so a newer | ||
| @@ -2164,7 +2165,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||||
| 2164 | // recvResult carries one framed message (or a read error) from the receive | 2165 | // recvResult carries one framed message (or a read error) from the receive | ||
| 2165 | // pump to the main loop. | 2166 | // pump to the main loop. | ||
| 2166 | type recvResult struct { | 2167 | type recvResult struct { | ||
| 2167 | - | frame ports.Frame | 2168 | + | frame wire.Frame |
| 2168 | err error | 2169 | err error | ||
| 2169 | } | 2170 | } | ||
| 2170 | 2171 | ||||
| @@ -2227,9 +2228,9 @@ func (q *cumulativeAckQueue) take() (uint64, uint64) { | |||||
| 2227 | 2228 | ||||
| 2228 | // runSender preserves normal-frame order while allowing switch control and | 2229 | // runSender preserves normal-frame order while allowing switch control and | ||
| 2229 | // output ACKs to make progress when raw input is held for a same-peer switch. | 2230 | // output ACKs to make progress when raw input is held for a same-peer switch. | ||
| 2230 | - | func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.Transport, control <-chan ports.Frame, barriers <-chan chan struct{}, in <-chan ports.Frame, inputGate *samePeerInputGate, acks *cumulativeAckQueue, errCh chan<- error, log *slog.Logger) { | 2231 | + | func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.Transport, control <-chan wire.Frame, barriers <-chan chan struct{}, in <-chan wire.Frame, inputGate *samePeerInputGate, acks *cumulativeAckQueue, errCh chan<- error, log *slog.Logger) { |
| 2231 | defer log.Debug("sender pump exited") | 2232 | defer log.Debug("sender pump exited") | ||
| 2232 | - | send := func(f ports.Frame) bool { | 2233 | + | send := func(f wire.Frame) bool { |
| 2233 | if err := transport.Send(f); err != nil { | 2234 | if err := transport.Send(f); err != nil { | ||
| 2234 | select { | 2235 | select { | ||
| 2235 | case errCh <- err: | 2236 | case errCh <- err: | ||
| @@ -2245,7 +2246,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||||
| 2245 | if state == 0 { | 2246 | if state == 0 { | ||
| 2246 | return true | 2247 | return true | ||
| 2247 | } | 2248 | } | ||
| 2248 | - | payload, err := ports.MarshalAck(protocol.Ack{Epoch: epoch, State: state}) | 2249 | + | payload, err := wire.MarshalAck(protocol.Ack{Epoch: epoch, State: state}) |
| 2249 | if err != nil { | 2250 | if err != nil { | ||
| 2250 | select { | 2251 | select { | ||
| 2251 | case errCh <- fmt.Errorf("encoding output ACK: %w", err): | 2252 | case errCh <- fmt.Errorf("encoding output ACK: %w", err): | ||
| @@ -2254,7 +2255,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||||
| 2254 | cancel() | 2255 | cancel() | ||
| 2255 | return false | 2256 | return false | ||
| 2256 | } | 2257 | } | ||
| 2257 | - | return send(ports.Frame{Type: ports.MsgAck, Payload: payload}) | 2258 | + | return send(wire.Frame{Type: wire.MsgAck, Payload: payload}) |
| 2258 | } | 2259 | } | ||
| 2259 | flushPending := func() bool { | 2260 | flushPending := func() bool { | ||
| 2260 | for { | 2261 | for { | ||
| @@ -2286,7 +2287,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||||
| 2286 | close(done) | 2287 | close(done) | ||
| 2287 | return true | 2288 | return true | ||
| 2288 | } | 2289 | } | ||
| 2289 | - | var heldInput *ports.Frame | 2290 | + | var heldInput *wire.Frame |
| 2290 | for { | 2291 | for { | ||
| 2291 | if heldInput != nil { | 2292 | if heldInput != nil { | ||
| 2292 | paused, changed := inputGate.snapshot() | 2293 | paused, changed := inputGate.snapshot() | ||
| @@ -2353,7 +2354,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||||
| 2353 | return | 2354 | return | ||
| 2354 | default: | 2355 | default: | ||
| 2355 | } | 2356 | } | ||
| 2356 | - | if frame.Type == ports.MsgInput || frame.Type == ports.MsgImagePush { | 2357 | + | if frame.Type == wire.MsgInput || frame.Type == wire.MsgImagePush { |
| 2357 | if paused, _ := inputGate.snapshot(); paused { | 2358 | if paused, _ := inputGate.snapshot(); paused { | ||
| 2358 | held := frame | 2359 | held := frame | ||
| 2359 | heldInput = &held | 2360 | heldInput = &held | ||
| @@ -2725,7 +2726,7 @@ type stdinPump struct { | |||||
| 2725 | in io.Reader // compatibility for isolated scanner tests | 2726 | in io.Reader // compatibility for isolated scanner tests | ||
| 2726 | input *terminalInputPump | 2727 | input *terminalInputPump | ||
| 2727 | consumer uint64 | 2728 | consumer uint64 | ||
| 2728 | - | out chan<- ports.Frame | 2729 | + | out chan<- wire.Frame |
| 2729 | clock ports.Clock | 2730 | clock ports.Clock | ||
| 2730 | clipboard ports.ClipboardReader | 2731 | clipboard ports.ClipboardReader | ||
| 2731 | logger *slog.Logger | 2732 | logger *slog.Logger | ||
| @@ -2746,7 +2747,7 @@ func (p *stdinPump) run() { | |||||
| 2746 | var undeliveredMu sync.Mutex | 2747 | var undeliveredMu sync.Mutex | ||
| 2747 | var undelivered []byte | 2748 | var undelivered []byte | ||
| 2748 | sendOK.Store(true) | 2749 | sendOK.Store(true) | ||
| 2749 | - | send := func(frame ports.Frame) bool { | 2750 | + | send := func(frame wire.Frame) bool { |
| 2750 | if !sendOK.Load() { | 2751 | if !sendOK.Load() { | ||
| 2751 | return false | 2752 | return false | ||
| 2752 | } | 2753 | } | ||
| @@ -2785,7 +2786,7 @@ func (p *stdinPump) run() { | |||||
| 2785 | return | 2786 | return | ||
| 2786 | } | 2787 | } | ||
| 2787 | inputSeq++ | 2788 | inputSeq++ | ||
| 2788 | - | if !send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{InputSeq: inputSeq, Data: append([]byte(nil), data...)})}) { | 2789 | + | if !send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{InputSeq: inputSeq, Data: append([]byte(nil), data...)})}) { |
| 2789 | undeliveredMu.Lock() | 2790 | undeliveredMu.Lock() | ||
| 2790 | undelivered = append(undelivered, data...) | 2791 | undelivered = append(undelivered, data...) | ||
| 2791 | undeliveredMu.Unlock() | 2792 | undeliveredMu.Unlock() | ||
| @@ -2799,11 +2800,11 @@ func (p *stdinPump) run() { | |||||
| 2799 | reader: p.clipboard, | 2800 | reader: p.clipboard, | ||
| 2800 | log: p.logger, | 2801 | log: p.logger, | ||
| 2801 | sendNotice: func(action uint8) { | 2802 | sendNotice: func(action uint8) { | ||
| 2802 | - | send(ports.Frame{Type: ports.MsgClientNotice, Payload: ports.MarshalClientNotice(protocol.ClientNotice{Action: action})}) | 2803 | + | send(wire.Frame{Type: wire.MsgClientNotice, Payload: wire.MarshalClientNotice(protocol.ClientNotice{Action: action})}) |
| 2803 | }, | 2804 | }, | ||
| 2804 | sendImage: func(mime string, data []byte) { | 2805 | sendImage: func(mime string, data []byte) { | ||
| 2805 | inputSeq++ | 2806 | inputSeq++ | ||
| 2806 | - | send(ports.Frame{Type: ports.MsgImagePush, Payload: ports.MarshalImagePush(protocol.ImagePush{InputSeq: inputSeq, Mime: mime, Data: data})}) | 2807 | + | send(wire.Frame{Type: wire.MsgImagePush, Payload: wire.MarshalImagePush(protocol.ImagePush{InputSeq: inputSeq, Mime: mime, Data: data})}) |
| 2807 | }, | 2808 | }, | ||
| 2808 | next: coalescer.Scan, | 2809 | next: coalescer.Scan, | ||
| 2809 | } | 2810 | } | ||
| @@ -2945,7 +2946,7 @@ func (p *stdinPump) run() { | |||||
| 2945 | disarmMarkerDeadline() | 2946 | disarmMarkerDeadline() | ||
| 2946 | markers.flush(sink) | 2947 | markers.flush(sink) | ||
| 2947 | select { | 2948 | select { | ||
| 2948 | - | case p.out <- ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}: | 2949 | + | case p.out <- wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}: |
| 2949 | case <-p.ctx.Done(): | 2950 | case <-p.ctx.Done(): | ||
| 2950 | } | 2951 | } | ||
| 2951 | p.cancel() | 2952 | p.cancel() | ||
| @@ -2966,7 +2967,7 @@ func (p *stdinPump) run() { | |||||
| 2966 | // runResize forwards coalesced terminal resize events to the daemon. It | 2967 | // runResize forwards coalesced terminal resize events to the daemon. It | ||
| 2967 | // tolerates an already-closed resize channel (which the terminal adapter | 2968 | // tolerates an already-closed resize channel (which the terminal adapter | ||
| 2968 | // hands back when restore ran before ResizeEvents was first called). | 2969 | // hands back when restore ran before ResizeEvents was first called). | ||
| 2969 | - | func runResize(ctx context.Context, events <-chan domain.Geometry, out chan<- ports.Frame, sendLease *foregroundSendLease, log *slog.Logger) { | 2970 | + | func runResize(ctx context.Context, events <-chan domain.Geometry, out chan<- wire.Frame, sendLease *foregroundSendLease, log *slog.Logger) { |
| 2970 | defer log.Debug("resize pump exited") | 2971 | defer log.Debug("resize pump exited") | ||
| 2971 | for { | 2972 | for { | ||
| 2972 | select { | 2973 | select { | ||
| @@ -2975,12 +2976,12 @@ func runResize(ctx context.Context, events <-chan domain.Geometry, out chan<- po | |||||
| 2975 | return | 2976 | return | ||
| 2976 | } | 2977 | } | ||
| 2977 | geometry = geometry.NormalizePixels() | 2978 | geometry = geometry.NormalizePixels() | ||
| 2978 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | 2979 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) |
| 2979 | if err != nil { | 2980 | if err != nil { | ||
| 2980 | log.Error("encoding terminal resize", "error", err) | 2981 | log.Error("encoding terminal resize", "error", err) | ||
| 2981 | continue | 2982 | continue | ||
| 2982 | } | 2983 | } | ||
| 2983 | - | frame := ports.Frame{Type: ports.MsgResize, Payload: payload} | 2984 | + | frame := wire.Frame{Type: wire.MsgResize, Payload: payload} |
| 2984 | if !sendLease.send(func() bool { | 2985 | if !sendLease.send(func() bool { | ||
| 2985 | select { | 2986 | select { | ||
| 2986 | case out <- frame: | 2987 | case out <- frame: | ||
M internal/usecase/client/client_test.go +198 -197
| @@ -19,6 +19,7 @@ import ( | |||||
| 19 | "github.com/bnema/vev/internal/ports" | 19 | "github.com/bnema/vev/internal/ports" | ||
| 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 21 | "github.com/bnema/vev/internal/protocol" | 21 | "github.com/bnema/vev/internal/protocol" | ||
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 22 | "github.com/bnema/vev/internal/usecase/client" | 23 | "github.com/bnema/vev/internal/usecase/client" | ||
| 23 | ) | 24 | ) | ||
| 24 | 25 | ||||
| @@ -117,7 +118,7 @@ func (t *reconnectTestTimer) Stop() bool { | |||||
| 117 | 118 | ||||
| 118 | // recvItem is one scripted Recv result. | 119 | // recvItem is one scripted Recv result. | ||
| 119 | type recvItem struct { | 120 | type recvItem struct { | ||
| 120 | - | f ports.Frame | 121 | + | f wire.Frame |
| 121 | err error | 122 | err error | ||
| 122 | wait <-chan struct{} | 123 | wait <-chan struct{} | ||
| 123 | } | 124 | } | ||
| @@ -135,26 +136,26 @@ func scriptRecv(tr *portsmocks.MockTransport, items ...recvItem) func() { | |||||
| 135 | ch <- it | 136 | ch <- it | ||
| 136 | } | 137 | } | ||
| 137 | done := make(chan struct{}) | 138 | done := make(chan struct{}) | ||
| 138 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 139 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 139 | select { | 140 | select { | ||
| 140 | case it := <-ch: | 141 | case it := <-ch: | ||
| 141 | if it.wait != nil { | 142 | if it.wait != nil { | ||
| 142 | select { | 143 | select { | ||
| 143 | case <-it.wait: | 144 | case <-it.wait: | ||
| 144 | case <-done: | 145 | case <-done: | ||
| 145 | - | return ports.Frame{}, io.EOF | 146 | + | return wire.Frame{}, io.EOF |
| 146 | } | 147 | } | ||
| 147 | } | 148 | } | ||
| 148 | return it.f, it.err | 149 | return it.f, it.err | ||
| 149 | case <-done: | 150 | case <-done: | ||
| 150 | - | return ports.Frame{}, io.EOF | 151 | + | return wire.Frame{}, io.EOF |
| 151 | } | 152 | } | ||
| 152 | }).Maybe() | 153 | }).Maybe() | ||
| 153 | return func() { close(done) } | 154 | return func() { close(done) } | ||
| 154 | } | 155 | } | ||
| 155 | 156 | ||||
| 156 | - | func frameOf(t ports.MsgType, payload []byte) ports.Frame { | 157 | + | func frameOf(t wire.MsgType, payload []byte) wire.Frame { |
| 157 | - | return ports.Frame{Type: t, Payload: payload} | 158 | + | return wire.Frame{Type: t, Payload: payload} |
| 158 | } | 159 | } | ||
| 159 | 160 | ||||
| 160 | // blockingReader blocks on Read until closed, then returns EOF. Stands in | 161 | // blockingReader blocks on Read until closed, then returns EOF. Stands in | ||
| @@ -234,8 +235,8 @@ func newHappyTerminal(t *testing.T, out *bytes.Buffer, restoreCount *atomic.Int3 | |||||
| 234 | return tm, in | 235 | return tm, in | ||
| 235 | } | 236 | } | ||
| 236 | 237 | ||||
| 237 | - | func isType(typ ports.MsgType) any { | 238 | + | func isType(typ wire.MsgType) any { |
| 238 | - | return mock.MatchedBy(func(f ports.Frame) bool { return f.Type == typ }) | 239 | + | return mock.MatchedBy(func(f wire.Frame) bool { return f.Type == typ }) |
| 239 | } | 240 | } | ||
| 240 | 241 | ||||
| 241 | // transportDialer adapts one already-open test transport to the Runner API. | 242 | // transportDialer adapts one already-open test transport to the Runner API. | ||
| @@ -339,13 +340,13 @@ func TestRunBoundsPreWelcomeOperations(t *testing.T) { | |||||
| 339 | return io.ErrClosedPipe | 340 | return io.ErrClosedPipe | ||
| 340 | } | 341 | } | ||
| 341 | if tt.phase == "send" { | 342 | if tt.phase == "send" { | ||
| 342 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(ports.Frame) error { | 343 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(wire.Frame) error { |
| 343 | return block() | 344 | return block() | ||
| 344 | }).Once() | 345 | }).Once() | ||
| 345 | } else { | 346 | } else { | ||
| 346 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 347 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 347 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 348 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 348 | - | return ports.Frame{}, block() | 349 | + | return wire.Frame{}, block() |
| 349 | }).Once() | 350 | }).Once() | ||
| 350 | } | 351 | } | ||
| 351 | dialer := portsmocks.NewMockDialer(t) | 352 | dialer := portsmocks.NewMockDialer(t) | ||
| @@ -384,7 +385,7 @@ func TestRunBoundsPreWelcomeOperations(t *testing.T) { | |||||
| 384 | case <-time.After(time.Second): | 385 | case <-time.After(time.Second): | ||
| 385 | t.Fatal("handshake operation leaked after Run returned") | 386 | t.Fatal("handshake operation leaked after Run returned") | ||
| 386 | } | 387 | } | ||
| 387 | - | tr.AssertNotCalled(t, "Send", isType(ports.MsgTheme)) | 388 | + | tr.AssertNotCalled(t, "Send", isType(wire.MsgTheme)) |
| 388 | }) | 389 | }) | ||
| 389 | } | 390 | } | ||
| 390 | } | 391 | } | ||
| @@ -401,17 +402,17 @@ func TestAttachHelloIncludesTrueColor(t *testing.T) { | |||||
| 401 | 402 | ||||
| 402 | gotHello := make(chan protocol.Hello, 1) | 403 | gotHello := make(chan protocol.Hello, 1) | ||
| 403 | tr := portsmocks.NewMockTransport(t) | 404 | tr := portsmocks.NewMockTransport(t) | ||
| 404 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 405 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 405 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 406 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 406 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(f ports.Frame) error { | 407 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(f wire.Frame) error { |
| 407 | - | hello, err := ports.UnmarshalHello(f.Payload) | 408 | + | hello, err := wire.UnmarshalHello(f.Payload) |
| 408 | require.NoError(t, err) | 409 | require.NoError(t, err) | ||
| 409 | gotHello <- hello | 410 | gotHello <- hello | ||
| 410 | return nil | 411 | return nil | ||
| 411 | }).Once() | 412 | }).Once() | ||
| 412 | unblock := scriptRecv(tr, | 413 | unblock := scriptRecv(tr, | ||
| 413 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 414 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 414 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 415 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 415 | ) | 416 | ) | ||
| 416 | defer unblock() | 417 | defer unblock() | ||
| 417 | tr.EXPECT().Close().Return(nil).Once() | 418 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -434,14 +435,14 @@ func TestAttachPublishesCommittedRouteSnapshot(t *testing.T) { | |||||
| 434 | defer term.in.unblock() | 435 | defer term.in.unblock() | ||
| 435 | lifecycle := domain.SessionLifecycleID{9, 8, 7} | 436 | lifecycle := domain.SessionLifecycleID{9, 8, 7} | ||
| 436 | tr := &recordingTransport{recvs: []recvItem{ | 437 | tr := &recordingTransport{recvs: []recvItem{ | ||
| 437 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 438 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 438 | SessionID: "s1", | 439 | SessionID: "s1", | ||
| 439 | SessionName: "main", | 440 | SessionName: "main", | ||
| 440 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | 441 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | ||
| 441 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "main"}, | 442 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "main"}, | ||
| 442 | }, | 443 | }, | ||
| 443 | }))}, | 444 | }))}, | ||
| 444 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 445 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 445 | }} | 446 | }} | ||
| 446 | 447 | ||||
| 447 | err := runTestClient(context.Background(), attachTestDependencies(tr, term, realClock{}), client.AttachRequest{ | 448 | err := runTestClient(context.Background(), attachTestDependencies(tr, term, realClock{}), client.AttachRequest{ | ||
| @@ -458,14 +459,14 @@ func TestAttachPublishesCommittedRouteSnapshot(t *testing.T) { | |||||
| 458 | foundSubscription := false | 459 | foundSubscription := false | ||
| 459 | for _, frame := range tr.Sends() { | 460 | for _, frame := range tr.Sends() { | ||
| 460 | switch frame.Type { | 461 | switch frame.Type { | ||
| 461 | - | case ports.MsgRecentRouteSnapshot: | 462 | + | case wire.MsgRecentRouteSnapshot: |
| 462 | var err error | 463 | var err error | ||
| 463 | - | snapshot, err = ports.UnmarshalRecentRouteSnapshot(frame.Payload) | 464 | + | snapshot, err = wire.UnmarshalRecentRouteSnapshot(frame.Payload) |
| 464 | require.NoError(t, err) | 465 | require.NoError(t, err) | ||
| 465 | foundSnapshot = true | 466 | foundSnapshot = true | ||
| 466 | - | case ports.MsgRouteAttentionSubscription: | 467 | + | case wire.MsgRouteAttentionSubscription: |
| 467 | var err error | 468 | var err error | ||
| 468 | - | subscription, err = ports.UnmarshalRouteAttentionSubscription(frame.Payload) | 469 | + | subscription, err = wire.UnmarshalRouteAttentionSubscription(frame.Payload) |
| 469 | require.NoError(t, err) | 470 | require.NoError(t, err) | ||
| 470 | foundSubscription = true | 471 | foundSubscription = true | ||
| 471 | } | 472 | } | ||
| @@ -484,8 +485,8 @@ func TestLocalOnlyHandoffBetweenLocalSessionsKeepsClientRunning(t *testing.T) { | |||||
| 484 | 485 | ||||
| 485 | firstLifecycle := domain.SessionLifecycleID{1} | 486 | firstLifecycle := domain.SessionLifecycleID{1} | ||
| 486 | secondLifecycle := domain.SessionLifecycleID{2} | 487 | secondLifecycle := domain.SessionLifecycleID{2} | ||
| 487 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | 488 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID) wire.Frame { |
| 488 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 489 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 489 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | 490 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | ||
| 490 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | 491 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | ||
| 491 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | 492 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | ||
| @@ -495,12 +496,12 @@ func TestLocalOnlyHandoffBetweenLocalSessionsKeepsClientRunning(t *testing.T) { | |||||
| 495 | secondTarget := protocol.ExactSessionTarget{LifecycleID: secondLifecycle, SessionName: "second"} | 496 | secondTarget := protocol.ExactSessionTarget{LifecycleID: secondLifecycle, SessionName: "second"} | ||
| 496 | first := &recordingTransport{recvs: []recvItem{ | 497 | first := &recordingTransport{recvs: []recvItem{ | ||
| 497 | {f: welcome("first", firstLifecycle)}, | 498 | {f: welcome("first", firstLifecycle)}, | ||
| 498 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | 499 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 499 | Session: "second", Intent: protocol.IntentAttach, ExactTarget: &secondTarget, | 500 | Session: "second", Intent: protocol.IntentAttach, ExactTarget: &secondTarget, | ||
| 500 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, SamePeer: true, | 501 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, SamePeer: true, | ||
| 501 | }))}, | 502 | }))}, | ||
| 502 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: secondTarget}))}, | 503 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: secondTarget}))}, |
| 503 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 504 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 504 | }} | 505 | }} | ||
| 505 | dialer := &sequenceDialer{trs: []ports.Transport{first}} | 506 | dialer := &sequenceDialer{trs: []ports.Transport{first}} | ||
| 506 | 507 | ||||
| @@ -530,7 +531,7 @@ func TestAttachHelloPreservesCompleteAttachRequest(t *testing.T) { | |||||
| 530 | } | 531 | } | ||
| 531 | tr := &recordingTransport{recvs: []recvItem{ | 532 | tr := &recordingTransport{recvs: []recvItem{ | ||
| 532 | {f: welcomeFrame(0)}, | 533 | {f: welcomeFrame(0)}, | ||
| 533 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 534 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 534 | }} | 535 | }} | ||
| 535 | 536 | ||||
| 536 | require.NoError(t, runTestClient(context.Background(), attachTestDependencies(tr, term, realClock{}), request)) | 537 | require.NoError(t, runTestClient(context.Background(), attachTestDependencies(tr, term, realClock{}), request)) | ||
| @@ -550,8 +551,8 @@ func TestStoppedLocalHandoffDialsReplacementTransport(t *testing.T) { | |||||
| 550 | sourceLifecycle := domain.SessionLifecycleID{1} | 551 | sourceLifecycle := domain.SessionLifecycleID{1} | ||
| 551 | targetLifecycle := domain.SessionLifecycleID{2} | 552 | targetLifecycle := domain.SessionLifecycleID{2} | ||
| 552 | target := protocol.ExactSessionTarget{LifecycleID: targetLifecycle, SessionName: "stopped"} | 553 | target := protocol.ExactSessionTarget{LifecycleID: targetLifecycle, SessionName: "stopped"} | ||
| 553 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | 554 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID) wire.Frame { |
| 554 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 555 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 555 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | 556 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | ||
| 556 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | 557 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | ||
| 557 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | 558 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | ||
| @@ -560,14 +561,14 @@ func TestStoppedLocalHandoffDialsReplacementTransport(t *testing.T) { | |||||
| 560 | } | 561 | } | ||
| 561 | first := &recordingTransport{recvs: []recvItem{ | 562 | first := &recordingTransport{recvs: []recvItem{ | ||
| 562 | {f: welcome("source", sourceLifecycle)}, | 563 | {f: welcome("source", sourceLifecycle)}, | ||
| 563 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | 564 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 564 | Session: "stopped", Intent: protocol.IntentAttach, ExactTarget: &target, | 565 | Session: "stopped", Intent: protocol.IntentAttach, ExactTarget: &target, | ||
| 565 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 566 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 566 | }))}, | 567 | }))}, | ||
| 567 | }} | 568 | }} | ||
| 568 | second := &recordingTransport{recvs: []recvItem{ | 569 | second := &recordingTransport{recvs: []recvItem{ | ||
| 569 | {f: welcome("stopped", targetLifecycle)}, | 570 | {f: welcome("stopped", targetLifecycle)}, | ||
| 570 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 571 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 571 | }} | 572 | }} | ||
| 572 | dialer := &sequenceDialer{trs: []ports.Transport{first, second}} | 573 | dialer := &sequenceDialer{trs: []ports.Transport{first, second}} | ||
| 573 | 574 | ||||
| @@ -587,8 +588,8 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||||
| 587 | defer term.in.unblock() | 588 | defer term.in.unblock() | ||
| 588 | localLifecycle := domain.SessionLifecycleID{1} | 589 | localLifecycle := domain.SessionLifecycleID{1} | ||
| 589 | remoteLifecycle := domain.SessionLifecycleID{2} | 590 | remoteLifecycle := domain.SessionLifecycleID{2} | ||
| 590 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | 591 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID) wire.Frame { |
| 591 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 592 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 592 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | 593 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | ||
| 593 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}}, | 594 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}}, | ||
| 594 | })) | 595 | })) | ||
| @@ -599,7 +600,7 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||||
| 599 | } | 600 | } | ||
| 600 | local1 := &recordingTransport{recvs: []recvItem{ | 601 | local1 := &recordingTransport{recvs: []recvItem{ | ||
| 601 | {f: welcome("local", localLifecycle)}, | 602 | {f: welcome("local", localLifecycle)}, | ||
| 602 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | 603 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 603 | Endpoint: "remote", Session: "work", Intent: protocol.IntentAttach, | 604 | Endpoint: "remote", Session: "work", Intent: protocol.IntentAttach, | ||
| 604 | RemoteTarget: &remoteTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 605 | RemoteTarget: &remoteTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 605 | }))}, | 606 | }))}, | ||
| @@ -610,7 +611,7 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||||
| 610 | }} | 611 | }} | ||
| 611 | local2 := &recordingTransport{recvs: []recvItem{ | 612 | local2 := &recordingTransport{recvs: []recvItem{ | ||
| 612 | {f: welcome("local", localLifecycle)}, | 613 | {f: welcome("local", localLifecycle)}, | ||
| 613 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 614 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 614 | }} | 615 | }} | ||
| 615 | localDialer := &sequenceDialer{trs: []ports.Transport{local1, local2}} | 616 | localDialer := &sequenceDialer{trs: []ports.Transport{local1, local2}} | ||
| 616 | remoteDialer := &sequenceDialer{trs: []ports.Transport{remote}} | 617 | remoteDialer := &sequenceDialer{trs: []ports.Transport{remote}} | ||
| @@ -632,8 +633,8 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||||
| 632 | require.Equal(t, protocol.StartupOverlaySessionPicker, helloFromSend(t, local2).StartupOverlay) | 633 | require.Equal(t, protocol.StartupOverlaySessionPicker, helloFromSend(t, local2).StartupOverlay) | ||
| 633 | } | 634 | } | ||
| 634 | 635 | ||||
| 635 | - | func hybridWelcomeFrame(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | 636 | + | func hybridWelcomeFrame(name string, lifecycle domain.SessionLifecycleID) wire.Frame { |
| 636 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 637 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 637 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | 638 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | ||
| 638 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}}, | 639 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}}, | ||
| 639 | })) | 640 | })) | ||
| @@ -642,7 +643,7 @@ func hybridWelcomeFrame(name string, lifecycle domain.SessionLifecycleID) ports. | |||||
| 642 | func hybridLocalBootstrap(lifecycle domain.SessionLifecycleID, target domain.RemoteSessionTarget) *recordingTransport { | 643 | func hybridLocalBootstrap(lifecycle domain.SessionLifecycleID, target domain.RemoteSessionTarget) *recordingTransport { | ||
| 643 | return &recordingTransport{recvs: []recvItem{ | 644 | return &recordingTransport{recvs: []recvItem{ | ||
| 644 | {f: hybridWelcomeFrame("local", lifecycle)}, | 645 | {f: hybridWelcomeFrame("local", lifecycle)}, | ||
| 645 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | 646 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 646 | Endpoint: target.Endpoint, Session: target.SessionName, Intent: protocol.IntentAttach, | 647 | Endpoint: target.Endpoint, Session: target.SessionName, Intent: protocol.IntentAttach, | ||
| 647 | RemoteTarget: &target, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 648 | RemoteTarget: &target, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 648 | }))}, | 649 | }))}, | ||
| @@ -669,16 +670,16 @@ func hybridPickerDependencies(localDialer ports.Dialer, term ports.Terminal, clo | |||||
| 669 | return deps | 670 | return deps | ||
| 670 | } | 671 | } | ||
| 671 | 672 | ||||
| 672 | - | func hybridParkedRequestHandler(requests chan<- protocol.ParkedRouteRequest, requestErrors chan<- error, signals map[protocol.ParkedRouteAction]chan struct{}) func(ports.Frame) { | 673 | + | func hybridParkedRequestHandler(requests chan<- protocol.ParkedRouteRequest, requestErrors chan<- error, signals map[protocol.ParkedRouteAction]chan struct{}) func(wire.Frame) { |
| 673 | once := make(map[protocol.ParkedRouteAction]*sync.Once, len(signals)) | 674 | once := make(map[protocol.ParkedRouteAction]*sync.Once, len(signals)) | ||
| 674 | for action := range signals { | 675 | for action := range signals { | ||
| 675 | once[action] = &sync.Once{} | 676 | once[action] = &sync.Once{} | ||
| 676 | } | 677 | } | ||
| 677 | - | return func(frame ports.Frame) { | 678 | + | return func(frame wire.Frame) { |
| 678 | - | if frame.Type != ports.MsgParkedRouteRequest { | 679 | + | if frame.Type != wire.MsgParkedRouteRequest { |
| 679 | return | 680 | return | ||
| 680 | } | 681 | } | ||
| 681 | - | request, err := ports.UnmarshalParkedRouteRequest(frame.Payload) | 682 | + | request, err := wire.UnmarshalParkedRouteRequest(frame.Payload) |
| 682 | if err != nil { | 683 | if err != nil { | ||
| 683 | if requestErrors != nil { | 684 | if requestErrors != nil { | ||
| 684 | requestErrors <- err | 685 | requestErrors <- err | ||
| @@ -717,11 +718,11 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||||
| 717 | remote := &recordingTransport{recvs: []recvItem{ | 718 | remote := &recordingTransport{recvs: []recvItem{ | ||
| 718 | {f: hybridWelcomeFrame("source", remoteSourceLifecycle)}, | 719 | {f: hybridWelcomeFrame("source", remoteSourceLifecycle)}, | ||
| 719 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | 720 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | ||
| 720 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | 721 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, |
| 721 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: remoteTargetLifecycle, SessionName: "target"}})), wait: switchSent}, | 722 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: remoteTargetLifecycle, SessionName: "target"}})), wait: switchSent}, |
| 722 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteSwitched}))}, | 723 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteSwitched}))}, |
| 723 | - | {f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 2, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("target frame")}))}, | 724 | + | {f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 2, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("target frame")}))}, |
| 724 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 725 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 725 | }} | 726 | }} | ||
| 726 | remote.onSend = hybridParkedRequestHandler(parkedRequests, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | 727 | remote.onSend = hybridParkedRequestHandler(parkedRequests, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | ||
| 727 | protocol.ParkedRoutePrepare: parkSent, | 728 | protocol.ParkedRoutePrepare: parkSent, | ||
| @@ -729,14 +730,14 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||||
| 729 | }) | 730 | }) | ||
| 730 | localPicker := &recordingTransport{recvs: []recvItem{ | 731 | localPicker := &recordingTransport{recvs: []recvItem{ | ||
| 731 | {f: hybridWelcomeFrame("local", localLifecycle)}, | 732 | {f: hybridWelcomeFrame("local", localLifecycle)}, | ||
| 732 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | 733 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 733 | Endpoint: "remote", Session: "target", Intent: protocol.IntentAttach, | 734 | Endpoint: "remote", Session: "target", Intent: protocol.IntentAttach, | ||
| 734 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 735 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 735 | }))}, | 736 | }))}, | ||
| 736 | }} | 737 | }} | ||
| 737 | var resizeOnce sync.Once | 738 | var resizeOnce sync.Once | ||
| 738 | - | localPicker.onSend = func(frame ports.Frame) { | 739 | + | localPicker.onSend = func(frame wire.Frame) { |
| 739 | - | if frame.Type == ports.MsgHello { | 740 | + | if frame.Type == wire.MsgHello { |
| 740 | resizeOnce.Do(func() { term.setSize(domain.Size{Cols: 100, Rows: 40}) }) | 741 | resizeOnce.Do(func() { term.setSize(domain.Size{Cols: 100, Rows: 40}) }) | ||
| 741 | } | 742 | } | ||
| 742 | } | 743 | } | ||
| @@ -763,10 +764,10 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||||
| 763 | frames := remote.Sends() | 764 | frames := remote.Sends() | ||
| 764 | switchIndex := -1 | 765 | switchIndex := -1 | ||
| 765 | for i, frame := range frames { | 766 | for i, frame := range frames { | ||
| 766 | - | if frame.Type != ports.MsgParkedRouteRequest { | 767 | + | if frame.Type != wire.MsgParkedRouteRequest { |
| 767 | continue | 768 | continue | ||
| 768 | } | 769 | } | ||
| 769 | - | request, requestErr := ports.UnmarshalParkedRouteRequest(frame.Payload) | 770 | + | request, requestErr := wire.UnmarshalParkedRouteRequest(frame.Payload) |
| 770 | require.NoError(t, requestErr) | 771 | require.NoError(t, requestErr) | ||
| 771 | if request.Action == protocol.ParkedRouteSwitch { | 772 | if request.Action == protocol.ParkedRouteSwitch { | ||
| 772 | switchIndex = i | 773 | switchIndex = i | ||
| @@ -774,8 +775,8 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||||
| 774 | } | 775 | } | ||
| 775 | } | 776 | } | ||
| 776 | require.Positive(t, switchIndex) | 777 | require.Positive(t, switchIndex) | ||
| 777 | - | require.Equal(t, ports.MsgResize, frames[switchIndex-1].Type, "current size must precede the parked switch") | 778 | + | require.Equal(t, wire.MsgResize, frames[switchIndex-1].Type, "current size must precede the parked switch") |
| 778 | - | resize, resizeErr := ports.UnmarshalResize(frames[switchIndex-1].Payload) | 779 | + | resize, resizeErr := wire.UnmarshalResize(frames[switchIndex-1].Payload) |
| 779 | require.NoError(t, resizeErr) | 780 | require.NoError(t, resizeErr) | ||
| 780 | require.Equal(t, domain.Size{Cols: 100, Rows: 40}, resize.Size) | 781 | require.Equal(t, domain.Size{Cols: 100, Rows: 40}, resize.Size) | ||
| 781 | require.Equal(t, int32(1), remoteDialer.calls.Load(), "same-host picker switch must retain the authenticated remote transport") | 782 | require.Equal(t, int32(1), remoteDialer.calls.Load(), "same-host picker switch must retain the authenticated remote transport") | ||
| @@ -803,8 +804,8 @@ func TestHybridPickerExpiredSwitchFallsBackToNewDial(t *testing.T) { | |||||
| 803 | sourceRemote := &recordingTransport{recvs: []recvItem{ | 804 | sourceRemote := &recordingTransport{recvs: []recvItem{ | ||
| 804 | {f: hybridWelcomeFrame("source", sourceLifecycle)}, | 805 | {f: hybridWelcomeFrame("source", sourceLifecycle)}, | ||
| 805 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | 806 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | ||
| 806 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: prepareSent}, | 807 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: prepareSent}, |
| 807 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteExpired})), wait: switchSent}, | 808 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteExpired})), wait: switchSent}, |
| 808 | }} | 809 | }} | ||
| 809 | sourceRemote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | 810 | sourceRemote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | ||
| 810 | protocol.ParkedRoutePrepare: prepareSent, | 811 | protocol.ParkedRoutePrepare: prepareSent, | ||
| @@ -812,14 +813,14 @@ func TestHybridPickerExpiredSwitchFallsBackToNewDial(t *testing.T) { | |||||
| 812 | }) | 813 | }) | ||
| 813 | localPicker := &recordingTransport{recvs: []recvItem{ | 814 | localPicker := &recordingTransport{recvs: []recvItem{ | ||
| 814 | {f: hybridWelcomeFrame("local", localLifecycle)}, | 815 | {f: hybridWelcomeFrame("local", localLifecycle)}, | ||
| 815 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | 816 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 816 | Endpoint: "remote", Session: "target", Intent: protocol.IntentAttach, | 817 | Endpoint: "remote", Session: "target", Intent: protocol.IntentAttach, | ||
| 817 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 818 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 818 | }))}, | 819 | }))}, | ||
| 819 | }} | 820 | }} | ||
| 820 | targetRemote := &recordingTransport{recvs: []recvItem{ | 821 | targetRemote := &recordingTransport{recvs: []recvItem{ | ||
| 821 | {f: hybridWelcomeFrame("target", targetLifecycle)}, | 822 | {f: hybridWelcomeFrame("target", targetLifecycle)}, | ||
| 822 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 823 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 823 | }} | 824 | }} | ||
| 824 | localDialer := &sequenceDialer{trs: []ports.Transport{localInitial, localPicker}} | 825 | localDialer := &sequenceDialer{trs: []ports.Transport{localInitial, localPicker}} | ||
| 825 | remoteDialer := &sequenceDialer{trs: []ports.Transport{ | 826 | remoteDialer := &sequenceDialer{trs: []ports.Transport{ | ||
| @@ -951,10 +952,10 @@ func TestHybridPickerBackResumesRetainedRemoteTransport(t *testing.T) { | |||||
| 951 | remote := &recordingTransport{recvs: []recvItem{ | 952 | remote := &recordingTransport{recvs: []recvItem{ | ||
| 952 | {f: hybridWelcomeFrame("work", remoteLifecycle)}, | 953 | {f: hybridWelcomeFrame("work", remoteLifecycle)}, | ||
| 953 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | 954 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | ||
| 954 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | 955 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, |
| 955 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteResumed})), wait: resumeSent}, | 956 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteResumed})), wait: resumeSent}, |
| 956 | - | {f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("source frame")}))}, | 957 | + | {f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("source frame")}))}, |
| 957 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 958 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 958 | }} | 959 | }} | ||
| 959 | remote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | 960 | remote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | ||
| 960 | protocol.ParkedRoutePrepare: parkSent, | 961 | protocol.ParkedRoutePrepare: parkSent, | ||
| @@ -1002,7 +1003,7 @@ func TestHybridPickerDifferentHostFallsBackToNewRemoteDial(t *testing.T) { | |||||
| 1002 | sourceRemote := &recordingTransport{recvs: []recvItem{ | 1003 | sourceRemote := &recordingTransport{recvs: []recvItem{ | ||
| 1003 | {f: hybridWelcomeFrame("source", sourceLifecycle)}, | 1004 | {f: hybridWelcomeFrame("source", sourceLifecycle)}, | ||
| 1004 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | 1005 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | ||
| 1005 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | 1006 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, |
| 1006 | {err: io.EOF, wait: keepSourceOpen}, | 1007 | {err: io.EOF, wait: keepSourceOpen}, | ||
| 1007 | }} | 1008 | }} | ||
| 1008 | sourceRemote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | 1009 | sourceRemote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | ||
| @@ -1010,14 +1011,14 @@ func TestHybridPickerDifferentHostFallsBackToNewRemoteDial(t *testing.T) { | |||||
| 1010 | }) | 1011 | }) | ||
| 1011 | localPicker := &recordingTransport{recvs: []recvItem{ | 1012 | localPicker := &recordingTransport{recvs: []recvItem{ | ||
| 1012 | {f: hybridWelcomeFrame("local", localLifecycle)}, | 1013 | {f: hybridWelcomeFrame("local", localLifecycle)}, | ||
| 1013 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | 1014 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 1014 | Endpoint: targetTarget.Endpoint, Session: targetTarget.SessionName, Intent: protocol.IntentAttach, | 1015 | Endpoint: targetTarget.Endpoint, Session: targetTarget.SessionName, Intent: protocol.IntentAttach, | ||
| 1015 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 1016 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 1016 | }))}, | 1017 | }))}, | ||
| 1017 | }} | 1018 | }} | ||
| 1018 | targetRemote := &recordingTransport{recvs: []recvItem{ | 1019 | targetRemote := &recordingTransport{recvs: []recvItem{ | ||
| 1019 | {f: hybridWelcomeFrame("target", targetLifecycle)}, | 1020 | {f: hybridWelcomeFrame("target", targetLifecycle)}, | ||
| 1020 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1021 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1021 | }} | 1022 | }} | ||
| 1022 | localDialer := &sequenceDialer{trs: []ports.Transport{localInitial, localPicker}} | 1023 | localDialer := &sequenceDialer{trs: []ports.Transport{localInitial, localPicker}} | ||
| 1023 | sourceDialer := &sequenceDialer{trs: []ports.Transport{markedDatagramTransport{Transport: sourceRemote}}} | 1024 | sourceDialer := &sequenceDialer{trs: []ports.Transport{markedDatagramTransport{Transport: sourceRemote}}} | ||
| @@ -1048,8 +1049,8 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||||
| 1048 | remoteLifecycle := domain.SessionLifecycleID{2, 2, 2} | 1049 | remoteLifecycle := domain.SessionLifecycleID{2, 2, 2} | ||
| 1049 | newLifecycle := domain.SessionLifecycleID{3, 3, 3} | 1050 | newLifecycle := domain.SessionLifecycleID{3, 3, 3} | ||
| 1050 | remoteNewLifecycle := domain.SessionLifecycleID{4, 4, 4} | 1051 | remoteNewLifecycle := domain.SessionLifecycleID{4, 4, 4} | ||
| 1051 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) ports.Frame { | 1052 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) wire.Frame { |
| 1052 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 1053 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 1053 | SessionID: name + "-id", | 1054 | SessionID: name + "-id", | ||
| 1054 | SessionName: name, | 1055 | SessionName: name, | ||
| 1055 | ResumeToken: token, | 1056 | ResumeToken: token, | ||
| @@ -1073,14 +1074,14 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||||
| 1073 | 1074 | ||||
| 1074 | local1 := &recordingTransport{recvs: []recvItem{ | 1075 | local1 := &recordingTransport{recvs: []recvItem{ | ||
| 1075 | {f: welcome("test", localLifecycle, 11)}, | 1076 | {f: welcome("test", localLifecycle, 11)}, | ||
| 1076 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(remoteHandoff))}, | 1077 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(remoteHandoff))}, |
| 1077 | }} | 1078 | }} | ||
| 1078 | local2 := &recordingTransport{recvs: []recvItem{ | 1079 | local2 := &recordingTransport{recvs: []recvItem{ | ||
| 1079 | {f: welcome("test", localLifecycle, 11)}, | 1080 | {f: welcome("test", localLifecycle, 11)}, | ||
| 1080 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | 1081 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ |
| 1081 | Target: protocol.ExactSessionTarget{LifecycleID: newLifecycle, SessionName: "new"}, | 1082 | Target: protocol.ExactSessionTarget{LifecycleID: newLifecycle, SessionName: "new"}, | ||
| 1082 | }))}, | 1083 | }))}, | ||
| 1083 | - | {f: frameOf(ports.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 4, Key: 2, Generation: 2}))}, | 1084 | + | {f: frameOf(wire.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 4, Key: 2, Generation: 2}))}, |
| 1084 | }} | 1085 | }} | ||
| 1085 | local3 := &recordingTransport{recvs: []recvItem{ | 1086 | local3 := &recordingTransport{recvs: []recvItem{ | ||
| 1086 | {f: welcome("test", localLifecycle, 11)}, | 1087 | {f: welcome("test", localLifecycle, 11)}, | ||
| @@ -1088,21 +1089,21 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||||
| 1088 | }} | 1089 | }} | ||
| 1089 | remote1 := &recordingTransport{recvs: []recvItem{ | 1090 | remote1 := &recordingTransport{recvs: []recvItem{ | ||
| 1090 | {f: welcome("remote-manual", remoteLifecycle, 22)}, | 1091 | {f: welcome("remote-manual", remoteLifecycle, 22)}, | ||
| 1091 | - | {f: frameOf(ports.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 2, Key: 1, Generation: 1}))}, | 1092 | + | {f: frameOf(wire.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 2, Key: 1, Generation: 1}))}, |
| 1092 | }} | 1093 | }} | ||
| 1093 | remote2 := &recordingTransport{recvs: []recvItem{ | 1094 | remote2 := &recordingTransport{recvs: []recvItem{ | ||
| 1094 | {f: welcome("remote-manual", remoteLifecycle, 22)}, | 1095 | {f: welcome("remote-manual", remoteLifecycle, 22)}, | ||
| 1095 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | 1096 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ |
| 1096 | Target: protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, | 1097 | Target: protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, | ||
| 1097 | }))}, | 1098 | }))}, | ||
| 1098 | - | {f: frameOf(ports.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{ | 1099 | + | {f: frameOf(wire.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{ |
| 1099 | Target: protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, ActiveTabID: "tab-2", | 1100 | Target: protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, ActiveTabID: "tab-2", | ||
| 1100 | }))}, | 1101 | }))}, | ||
| 1101 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | 1102 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | ||
| 1102 | }} | 1103 | }} | ||
| 1103 | remote3 := &recordingTransport{recvs: []recvItem{ | 1104 | remote3 := &recordingTransport{recvs: []recvItem{ | ||
| 1104 | {f: welcome("remote-new", remoteNewLifecycle, 22)}, | 1105 | {f: welcome("remote-new", remoteNewLifecycle, 22)}, | ||
| 1105 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1106 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1106 | }} | 1107 | }} | ||
| 1107 | localDialer := &sequenceDialer{trs: []ports.Transport{local1, local2, local3}} | 1108 | localDialer := &sequenceDialer{trs: []ports.Transport{local1, local2, local3}} | ||
| 1108 | remoteDialer := &sequenceDialer{trs: []ports.Transport{remote1, remote2, remote3}} | 1109 | remoteDialer := &sequenceDialer{trs: []ports.Transport{remote1, remote2, remote3}} | ||
| @@ -1129,16 +1130,16 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||||
| 1129 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, remoteNewHello.ExactTarget) | 1130 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, remoteNewHello.ExactTarget) | ||
| 1130 | } | 1131 | } | ||
| 1131 | 1132 | ||||
| 1132 | - | func navigationDirectiveFrame(action protocol.NavigationAction) ports.Frame { | 1133 | + | func navigationDirectiveFrame(action protocol.NavigationAction) wire.Frame { |
| 1133 | directive := protocol.NavigationDirective{Action: action} | 1134 | directive := protocol.NavigationDirective{Action: action} | ||
| 1134 | if action == protocol.NavigationOpenHomePicker { | 1135 | if action == protocol.NavigationOpenHomePicker { | ||
| 1135 | directive.LeaseID = protocol.ParkedRouteLeaseID{1} | 1136 | directive.LeaseID = protocol.ParkedRouteLeaseID{1} | ||
| 1136 | } | 1137 | } | ||
| 1137 | - | return frameOf(ports.MsgNavigationAction, ports.MarshalNavigationDirective(directive)) | 1138 | + | return frameOf(wire.MsgNavigationAction, wire.MarshalNavigationDirective(directive)) |
| 1138 | } | 1139 | } | ||
| 1139 | 1140 | ||||
| 1140 | func mustMarshalCommittedIdentity(identity protocol.CommittedRouteIdentity) []byte { | 1141 | func mustMarshalCommittedIdentity(identity protocol.CommittedRouteIdentity) []byte { | ||
| 1141 | - | payload, err := ports.MarshalCommittedRouteIdentity(identity) | 1142 | + | payload, err := wire.MarshalCommittedRouteIdentity(identity) |
| 1142 | if err != nil { | 1143 | if err != nil { | ||
| 1143 | panic(err) | 1144 | panic(err) | ||
| 1144 | } | 1145 | } | ||
| @@ -1146,7 +1147,7 @@ func mustMarshalCommittedIdentity(identity protocol.CommittedRouteIdentity) []by | |||||
| 1146 | } | 1147 | } | ||
| 1147 | 1148 | ||||
| 1148 | func mustMarshalRouteAction(action protocol.RouteNavigationAction) []byte { | 1149 | func mustMarshalRouteAction(action protocol.RouteNavigationAction) []byte { | ||
| 1149 | - | payload, err := ports.MarshalRouteNavigationAction(action) | 1150 | + | payload, err := wire.MarshalRouteNavigationAction(action) |
| 1150 | if err != nil { | 1151 | if err != nil { | ||
| 1151 | panic(err) | 1152 | panic(err) | ||
| 1152 | } | 1153 | } | ||
| @@ -1154,7 +1155,7 @@ func mustMarshalRouteAction(action protocol.RouteNavigationAction) []byte { | |||||
| 1154 | } | 1155 | } | ||
| 1155 | 1156 | ||||
| 1156 | func mustMarshalRoutePosition(position protocol.RoutePosition) []byte { | 1157 | func mustMarshalRoutePosition(position protocol.RoutePosition) []byte { | ||
| 1157 | - | payload, err := ports.MarshalRoutePosition(position) | 1158 | + | payload, err := wire.MarshalRoutePosition(position) |
| 1158 | if err != nil { | 1159 | if err != nil { | ||
| 1159 | panic(err) | 1160 | panic(err) | ||
| 1160 | } | 1161 | } | ||
| @@ -1170,11 +1171,11 @@ func TestAttachTargetHandoffReturnsValidatedTargetAndClosesTransport(t *testing. | |||||
| 1170 | 1171 | ||||
| 1171 | target := protocol.AttachTarget{Endpoint: "remote.example", Session: "work", Intent: protocol.IntentAttach} | 1172 | target := protocol.AttachTarget{Endpoint: "remote.example", Session: "work", Intent: protocol.IntentAttach} | ||
| 1172 | tr := portsmocks.NewMockTransport(t) | 1173 | tr := portsmocks.NewMockTransport(t) | ||
| 1173 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1174 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1174 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1175 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1175 | unblock := scriptRecv(tr, | 1176 | unblock := scriptRecv(tr, | ||
| 1176 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "local"}))}, | 1177 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "local"}))}, |
| 1177 | - | recvItem{f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(target))}, | 1178 | + | recvItem{f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(target))}, |
| 1178 | ) | 1179 | ) | ||
| 1179 | defer unblock() | 1180 | defer unblock() | ||
| 1180 | tr.EXPECT().Close().Return(nil).Once() | 1181 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1197,10 +1198,10 @@ func TestAttachHelloIncludesCompleteLocalEnvironment(t *testing.T) { | |||||
| 1197 | 1198 | ||||
| 1198 | gotHello := make(chan protocol.Hello, 1) | 1199 | gotHello := make(chan protocol.Hello, 1) | ||
| 1199 | tr := portsmocks.NewMockTransport(t) | 1200 | tr := portsmocks.NewMockTransport(t) | ||
| 1200 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1201 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1201 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1202 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1202 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(f ports.Frame) error { | 1203 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(f wire.Frame) error { |
| 1203 | - | hello, err := ports.UnmarshalHello(f.Payload) | 1204 | + | hello, err := wire.UnmarshalHello(f.Payload) |
| 1204 | if err != nil { | 1205 | if err != nil { | ||
| 1205 | return err | 1206 | return err | ||
| 1206 | } | 1207 | } | ||
| @@ -1208,8 +1209,8 @@ func TestAttachHelloIncludesCompleteLocalEnvironment(t *testing.T) { | |||||
| 1208 | return nil | 1209 | return nil | ||
| 1209 | }).Once() | 1210 | }).Once() | ||
| 1210 | unblock := scriptRecv(tr, | 1211 | unblock := scriptRecv(tr, | ||
| 1211 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1212 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1212 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1213 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1213 | ) | 1214 | ) | ||
| 1214 | defer unblock() | 1215 | defer unblock() | ||
| 1215 | tr.EXPECT().Close().Return(nil).Once() | 1216 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1226,17 +1227,17 @@ func TestAttachHelloRequestsSingleOutputForDatagramTransport(t *testing.T) { | |||||
| 1226 | defer in.unblock() | 1227 | defer in.unblock() | ||
| 1227 | 1228 | ||||
| 1228 | tr := portsmocks.NewMockTransport(t) | 1229 | tr := portsmocks.NewMockTransport(t) | ||
| 1229 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1230 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1230 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1231 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1231 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(f ports.Frame) error { | 1232 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(f wire.Frame) error { |
| 1232 | - | hello, err := ports.UnmarshalHello(f.Payload) | 1233 | + | hello, err := wire.UnmarshalHello(f.Payload) |
| 1233 | require.NoError(t, err) | 1234 | require.NoError(t, err) | ||
| 1234 | require.Equal(t, uint8(1), hello.MaxOutputInFlight) | 1235 | require.Equal(t, uint8(1), hello.MaxOutputInFlight) | ||
| 1235 | return nil | 1236 | return nil | ||
| 1236 | }).Once() | 1237 | }).Once() | ||
| 1237 | unblock := scriptRecv(tr, | 1238 | unblock := scriptRecv(tr, | ||
| 1238 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1239 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1239 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1240 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1240 | ) | 1241 | ) | ||
| 1241 | defer unblock() | 1242 | defer unblock() | ||
| 1242 | tr.EXPECT().Close().Return(nil).Once() | 1243 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1252,13 +1253,13 @@ func TestAttachHappyPath(t *testing.T) { | |||||
| 1252 | defer in.unblock() | 1253 | defer in.unblock() | ||
| 1253 | 1254 | ||||
| 1254 | tr := portsmocks.NewMockTransport(t) | 1255 | tr := portsmocks.NewMockTransport(t) | ||
| 1255 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1256 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1256 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1257 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1257 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1258 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1258 | unblock := scriptRecv(tr, | 1259 | unblock := scriptRecv(tr, | ||
| 1259 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"}))}, | 1260 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"}))}, |
| 1260 | - | recvItem{f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("hello world")}))}, | 1261 | + | recvItem{f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("hello world")}))}, |
| 1261 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1262 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1262 | ) | 1263 | ) | ||
| 1263 | defer unblock() | 1264 | defer unblock() | ||
| 1264 | tr.EXPECT().Close().Return(nil).Once() | 1265 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1275,9 +1276,9 @@ func TestAttachVersionMismatch(t *testing.T) { | |||||
| 1275 | // EnterRaw must NOT be called on the error-before-welcome path. | 1276 | // EnterRaw must NOT be called on the error-before-welcome path. | ||
| 1276 | 1277 | ||||
| 1277 | tr := portsmocks.NewMockTransport(t) | 1278 | tr := portsmocks.NewMockTransport(t) | ||
| 1278 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1279 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1279 | tr.EXPECT().Recv().Return( | 1280 | tr.EXPECT().Recv().Return( | ||
| 1280 | - | frameOf(ports.MsgError, ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), | 1281 | + | frameOf(wire.MsgError, wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), |
| 1281 | nil, | 1282 | nil, | ||
| 1282 | ).Once() | 1283 | ).Once() | ||
| 1283 | tr.EXPECT().Close().Return(nil).Once() | 1284 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1287,7 +1288,7 @@ func TestAttachVersionMismatch(t *testing.T) { | |||||
| 1287 | var pe *client.ProtocolError | 1288 | var pe *client.ProtocolError | ||
| 1288 | require.True(t, errors.As(err, &pe), "want *client.ProtocolError, got %T", err) | 1289 | require.True(t, errors.As(err, &pe), "want *client.ProtocolError, got %T", err) | ||
| 1289 | require.Equal(t, protocol.ErrVersionMismatch, pe.Code) | 1290 | require.Equal(t, protocol.ErrVersionMismatch, pe.Code) | ||
| 1290 | - | tr.AssertNotCalled(t, "Send", isType(ports.MsgTheme)) | 1291 | + | tr.AssertNotCalled(t, "Send", isType(wire.MsgTheme)) |
| 1291 | } | 1292 | } | ||
| 1292 | 1293 | ||||
| 1293 | func TestAttachRestoredOnRecvErrorMidStream(t *testing.T) { | 1294 | func TestAttachRestoredOnRecvErrorMidStream(t *testing.T) { | ||
| @@ -1298,12 +1299,12 @@ func TestAttachRestoredOnRecvErrorMidStream(t *testing.T) { | |||||
| 1298 | defer in.unblock() | 1299 | defer in.unblock() | ||
| 1299 | 1300 | ||||
| 1300 | tr := portsmocks.NewMockTransport(t) | 1301 | tr := portsmocks.NewMockTransport(t) | ||
| 1301 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1302 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1302 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1303 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1303 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1304 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1304 | boom := errors.New("connection reset") | 1305 | boom := errors.New("connection reset") | ||
| 1305 | unblock := scriptRecv(tr, | 1306 | unblock := scriptRecv(tr, | ||
| 1306 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1307 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1307 | recvItem{err: boom}, | 1308 | recvItem{err: boom}, | ||
| 1308 | ) | 1309 | ) | ||
| 1309 | defer unblock() | 1310 | defer unblock() | ||
| @@ -1322,11 +1323,11 @@ func TestAttachDaemonVanishedOnEOF(t *testing.T) { | |||||
| 1322 | defer in.unblock() | 1323 | defer in.unblock() | ||
| 1323 | 1324 | ||||
| 1324 | tr := portsmocks.NewMockTransport(t) | 1325 | tr := portsmocks.NewMockTransport(t) | ||
| 1325 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1326 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1326 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1327 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1327 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1328 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1328 | unblock := scriptRecv(tr, | 1329 | unblock := scriptRecv(tr, | ||
| 1329 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1330 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1330 | recvItem{err: io.EOF}, | 1331 | recvItem{err: io.EOF}, | ||
| 1331 | ) | 1332 | ) | ||
| 1332 | defer unblock() | 1333 | defer unblock() | ||
| @@ -1356,35 +1357,35 @@ func TestAttachStdinForwardsSGRMouseReportAsSingleFrame(t *testing.T) { | |||||
| 1356 | gotInput := make(chan []byte, 2) | 1357 | gotInput := make(chan []byte, 2) | ||
| 1357 | allowDetach := make(chan struct{}) | 1358 | allowDetach := make(chan struct{}) | ||
| 1358 | tr := portsmocks.NewMockTransport(t) | 1359 | tr := portsmocks.NewMockTransport(t) | ||
| 1359 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1360 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1360 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1361 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1361 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1362 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1362 | - | tr.EXPECT().Send(isType(ports.MsgInput)).RunAndReturn(func(f ports.Frame) error { | 1363 | + | tr.EXPECT().Send(isType(wire.MsgInput)).RunAndReturn(func(f wire.Frame) error { |
| 1363 | - | in, err := ports.UnmarshalInput(f.Payload) | 1364 | + | in, err := wire.UnmarshalInput(f.Payload) |
| 1364 | require.NoError(t, err) | 1365 | require.NoError(t, err) | ||
| 1365 | gotInput <- in.Data | 1366 | gotInput <- in.Data | ||
| 1366 | close(allowDetach) | 1367 | close(allowDetach) | ||
| 1367 | return nil | 1368 | return nil | ||
| 1368 | }).Once() | 1369 | }).Once() | ||
| 1369 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | 1370 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) |
| 1370 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | 1371 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) |
| 1371 | recvCh := make(chan recvItem, 1) | 1372 | recvCh := make(chan recvItem, 1) | ||
| 1372 | recvCh <- recvItem{f: welcome} | 1373 | recvCh <- recvItem{f: welcome} | ||
| 1373 | closed := make(chan struct{}) | 1374 | closed := make(chan struct{}) | ||
| 1374 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 1375 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 1375 | select { | 1376 | select { | ||
| 1376 | case it := <-recvCh: | 1377 | case it := <-recvCh: | ||
| 1377 | return it.f, it.err | 1378 | return it.f, it.err | ||
| 1378 | case <-allowDetach: | 1379 | case <-allowDetach: | ||
| 1379 | select { | 1380 | select { | ||
| 1380 | case <-closed: | 1381 | case <-closed: | ||
| 1381 | - | return ports.Frame{}, io.EOF | 1382 | + | return wire.Frame{}, io.EOF |
| 1382 | default: | 1383 | default: | ||
| 1383 | close(closed) | 1384 | close(closed) | ||
| 1384 | return detached, nil | 1385 | return detached, nil | ||
| 1385 | } | 1386 | } | ||
| 1386 | case <-closed: | 1387 | case <-closed: | ||
| 1387 | - | return ports.Frame{}, io.EOF | 1388 | + | return wire.Frame{}, io.EOF |
| 1388 | } | 1389 | } | ||
| 1389 | }).Maybe() | 1390 | }).Maybe() | ||
| 1390 | tr.EXPECT().Close().Return(nil).Once() | 1391 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1418,35 +1419,35 @@ func TestAttachStdinCoalescesSplitBracketedPaste(t *testing.T) { | |||||
| 1418 | gotInput := make(chan []byte, 1) | 1419 | gotInput := make(chan []byte, 1) | ||
| 1419 | allowDetach := make(chan struct{}) | 1420 | allowDetach := make(chan struct{}) | ||
| 1420 | tr := portsmocks.NewMockTransport(t) | 1421 | tr := portsmocks.NewMockTransport(t) | ||
| 1421 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1422 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1422 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1423 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1423 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1424 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1424 | - | tr.EXPECT().Send(isType(ports.MsgInput)).RunAndReturn(func(f ports.Frame) error { | 1425 | + | tr.EXPECT().Send(isType(wire.MsgInput)).RunAndReturn(func(f wire.Frame) error { |
| 1425 | - | in, err := ports.UnmarshalInput(f.Payload) | 1426 | + | in, err := wire.UnmarshalInput(f.Payload) |
| 1426 | require.NoError(t, err) | 1427 | require.NoError(t, err) | ||
| 1427 | gotInput <- in.Data | 1428 | gotInput <- in.Data | ||
| 1428 | close(allowDetach) | 1429 | close(allowDetach) | ||
| 1429 | return nil | 1430 | return nil | ||
| 1430 | }).Once() | 1431 | }).Once() | ||
| 1431 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | 1432 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) |
| 1432 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | 1433 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) |
| 1433 | recvCh := make(chan recvItem, 1) | 1434 | recvCh := make(chan recvItem, 1) | ||
| 1434 | recvCh <- recvItem{f: welcome} | 1435 | recvCh <- recvItem{f: welcome} | ||
| 1435 | closed := make(chan struct{}) | 1436 | closed := make(chan struct{}) | ||
| 1436 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 1437 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 1437 | select { | 1438 | select { | ||
| 1438 | case it := <-recvCh: | 1439 | case it := <-recvCh: | ||
| 1439 | return it.f, it.err | 1440 | return it.f, it.err | ||
| 1440 | case <-allowDetach: | 1441 | case <-allowDetach: | ||
| 1441 | select { | 1442 | select { | ||
| 1442 | case <-closed: | 1443 | case <-closed: | ||
| 1443 | - | return ports.Frame{}, io.EOF | 1444 | + | return wire.Frame{}, io.EOF |
| 1444 | default: | 1445 | default: | ||
| 1445 | close(closed) | 1446 | close(closed) | ||
| 1446 | return detached, nil | 1447 | return detached, nil | ||
| 1447 | } | 1448 | } | ||
| 1448 | case <-closed: | 1449 | case <-closed: | ||
| 1449 | - | return ports.Frame{}, io.EOF | 1450 | + | return wire.Frame{}, io.EOF |
| 1450 | } | 1451 | } | ||
| 1451 | }).Maybe() | 1452 | }).Maybe() | ||
| 1452 | tr.EXPECT().Close().Return(nil).Once() | 1453 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1473,24 +1474,24 @@ func TestAttachForwardsResize(t *testing.T) { | |||||
| 1473 | var firstRecvOnce sync.Once | 1474 | var firstRecvOnce sync.Once | ||
| 1474 | 1475 | ||||
| 1475 | tr := portsmocks.NewMockTransport(t) | 1476 | tr := portsmocks.NewMockTransport(t) | ||
| 1476 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1477 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1477 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1478 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1478 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1479 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1479 | // The resize frame is forwarded via the sender goroutine. | 1480 | // The resize frame is forwarded via the sender goroutine. | ||
| 1480 | gotResize := make(chan protocol.Resize, 1) | 1481 | gotResize := make(chan protocol.Resize, 1) | ||
| 1481 | - | tr.EXPECT().Send(isType(ports.MsgResize)).RunAndReturn(func(f ports.Frame) error { | 1482 | + | tr.EXPECT().Send(isType(wire.MsgResize)).RunAndReturn(func(f wire.Frame) error { |
| 1482 | - | r, _ := ports.UnmarshalResize(f.Payload) | 1483 | + | r, _ := wire.UnmarshalResize(f.Payload) |
| 1483 | gotResize <- r | 1484 | gotResize <- r | ||
| 1484 | close(detachAfterResize) | 1485 | close(detachAfterResize) | ||
| 1485 | return nil | 1486 | return nil | ||
| 1486 | }).Once() | 1487 | }).Once() | ||
| 1487 | 1488 | ||||
| 1488 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | 1489 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) |
| 1489 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | 1490 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) |
| 1490 | recvCh := make(chan recvItem, 2) | 1491 | recvCh := make(chan recvItem, 2) | ||
| 1491 | recvCh <- recvItem{f: welcome} | 1492 | recvCh <- recvItem{f: welcome} | ||
| 1492 | done := make(chan struct{}) | 1493 | done := make(chan struct{}) | ||
| 1493 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 1494 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 1494 | firstRecvOnce.Do(func() { close(firstRecv) }) | 1495 | firstRecvOnce.Do(func() { close(firstRecv) }) | ||
| 1495 | select { | 1496 | select { | ||
| 1496 | case it := <-recvCh: | 1497 | case it := <-recvCh: | ||
| @@ -1499,13 +1500,13 @@ func TestAttachForwardsResize(t *testing.T) { | |||||
| 1499 | // Deliver the detach once the resize has been observed. | 1500 | // Deliver the detach once the resize has been observed. | ||
| 1500 | select { | 1501 | select { | ||
| 1501 | case <-done: | 1502 | case <-done: | ||
| 1502 | - | return ports.Frame{}, io.EOF | 1503 | + | return wire.Frame{}, io.EOF |
| 1503 | default: | 1504 | default: | ||
| 1504 | close(done) | 1505 | close(done) | ||
| 1505 | return detached, nil | 1506 | return detached, nil | ||
| 1506 | } | 1507 | } | ||
| 1507 | case <-done: | 1508 | case <-done: | ||
| 1508 | - | return ports.Frame{}, io.EOF | 1509 | + | return wire.Frame{}, io.EOF |
| 1509 | } | 1510 | } | ||
| 1510 | }).Maybe() | 1511 | }).Maybe() | ||
| 1511 | tr.EXPECT().Close().Return(nil).Once() | 1512 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1534,12 +1535,12 @@ func TestRunRestoresRawModeAfterAttachError(t *testing.T) { | |||||
| 1534 | defer in.unblock() | 1535 | defer in.unblock() | ||
| 1535 | 1536 | ||||
| 1536 | tr := portsmocks.NewMockTransport(t) | 1537 | tr := portsmocks.NewMockTransport(t) | ||
| 1537 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1538 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1538 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1539 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1539 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1540 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1540 | boom := errors.New("connection reset") | 1541 | boom := errors.New("connection reset") | ||
| 1541 | unblock := scriptRecv(tr, | 1542 | unblock := scriptRecv(tr, | ||
| 1542 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1543 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1543 | recvItem{err: boom}, | 1544 | recvItem{err: boom}, | ||
| 1544 | ) | 1545 | ) | ||
| 1545 | defer unblock() | 1546 | defer unblock() | ||
| @@ -1558,9 +1559,9 @@ func TestRunDoesNotEnterRawBeforePreWelcomeError(t *testing.T) { | |||||
| 1558 | // EnterRaw must NOT be called when the daemon rejects Hello before Welcome. | 1559 | // EnterRaw must NOT be called when the daemon rejects Hello before Welcome. | ||
| 1559 | 1560 | ||||
| 1560 | tr := portsmocks.NewMockTransport(t) | 1561 | tr := portsmocks.NewMockTransport(t) | ||
| 1561 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1562 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1562 | tr.EXPECT().Recv().Return( | 1563 | tr.EXPECT().Recv().Return( | ||
| 1563 | - | frameOf(ports.MsgError, ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), | 1564 | + | frameOf(wire.MsgError, wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), |
| 1564 | nil, | 1565 | nil, | ||
| 1565 | ).Once() | 1566 | ).Once() | ||
| 1566 | tr.EXPECT().Close().Return(nil).Once() | 1567 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -1571,7 +1572,7 @@ func TestRunDoesNotEnterRawBeforePreWelcomeError(t *testing.T) { | |||||
| 1571 | require.Error(t, err) | 1572 | require.Error(t, err) | ||
| 1572 | var pe *client.ProtocolError | 1573 | var pe *client.ProtocolError | ||
| 1573 | require.True(t, errors.As(err, &pe), "want *client.ProtocolError, got %T", err) | 1574 | require.True(t, errors.As(err, &pe), "want *client.ProtocolError, got %T", err) | ||
| 1574 | - | tr.AssertNotCalled(t, "Send", isType(ports.MsgTheme)) | 1575 | + | tr.AssertNotCalled(t, "Send", isType(wire.MsgTheme)) |
| 1575 | } | 1576 | } | ||
| 1576 | 1577 | ||||
| 1577 | func TestRunPhaseASingleAttempt(t *testing.T) { | 1578 | func TestRunPhaseASingleAttempt(t *testing.T) { | ||
| @@ -1604,14 +1605,14 @@ func (d *sequenceDialer) Dial(context.Context) (ports.Transport, error) { | |||||
| 1604 | type recordingTransport struct { | 1605 | type recordingTransport struct { | ||
| 1605 | mu sync.Mutex | 1606 | mu sync.Mutex | ||
| 1606 | recvs []recvItem | 1607 | recvs []recvItem | ||
| 1607 | - | sends []ports.Frame | 1608 | + | sends []wire.Frame |
| 1608 | closed atomic.Int32 | 1609 | closed atomic.Int32 | ||
| 1609 | stall <-chan struct{} | 1610 | stall <-chan struct{} | ||
| 1610 | - | onSend func(ports.Frame) | 1611 | + | onSend func(wire.Frame) |
| 1611 | onClose func() | 1612 | onClose func() | ||
| 1612 | } | 1613 | } | ||
| 1613 | 1614 | ||||
| 1614 | - | func (t *recordingTransport) Send(f ports.Frame) error { | 1615 | + | func (t *recordingTransport) Send(f wire.Frame) error { |
| 1615 | t.mu.Lock() | 1616 | t.mu.Lock() | ||
| 1616 | t.sends = append(t.sends, f) | 1617 | t.sends = append(t.sends, f) | ||
| 1617 | onSend := t.onSend | 1618 | onSend := t.onSend | ||
| @@ -1622,18 +1623,18 @@ func (t *recordingTransport) Send(f ports.Frame) error { | |||||
| 1622 | return nil | 1623 | return nil | ||
| 1623 | } | 1624 | } | ||
| 1624 | 1625 | ||||
| 1625 | - | func (t *recordingTransport) Sends() []ports.Frame { | 1626 | + | func (t *recordingTransport) Sends() []wire.Frame { |
| 1626 | t.mu.Lock() | 1627 | t.mu.Lock() | ||
| 1627 | defer t.mu.Unlock() | 1628 | defer t.mu.Unlock() | ||
| 1628 | - | return append([]ports.Frame(nil), t.sends...) | 1629 | + | return append([]wire.Frame(nil), t.sends...) |
| 1629 | } | 1630 | } | ||
| 1630 | 1631 | ||||
| 1631 | - | func (t *recordingTransport) Recv() (ports.Frame, error) { | 1632 | + | func (t *recordingTransport) Recv() (wire.Frame, error) { |
| 1632 | if len(t.recvs) == 0 { | 1633 | if len(t.recvs) == 0 { | ||
| 1633 | if t.stall != nil { | 1634 | if t.stall != nil { | ||
| 1634 | <-t.stall | 1635 | <-t.stall | ||
| 1635 | } | 1636 | } | ||
| 1636 | - | return ports.Frame{}, io.EOF | 1637 | + | return wire.Frame{}, io.EOF |
| 1637 | } | 1638 | } | ||
| 1638 | it := t.recvs[0] | 1639 | it := t.recvs[0] | ||
| 1639 | t.recvs = t.recvs[1:] | 1640 | t.recvs = t.recvs[1:] | ||
| @@ -1692,14 +1693,14 @@ func helloFromSend(t *testing.T, tr *recordingTransport) protocol.Hello { | |||||
| 1692 | t.Helper() | 1693 | t.Helper() | ||
| 1693 | sends := tr.Sends() | 1694 | sends := tr.Sends() | ||
| 1694 | require.NotEmpty(t, sends) | 1695 | require.NotEmpty(t, sends) | ||
| 1695 | - | require.Equal(t, ports.MsgHello, sends[0].Type) | 1696 | + | require.Equal(t, wire.MsgHello, sends[0].Type) |
| 1696 | - | h, err := ports.UnmarshalHello(sends[0].Payload) | 1697 | + | h, err := wire.UnmarshalHello(sends[0].Payload) |
| 1697 | require.NoError(t, err) | 1698 | require.NoError(t, err) | ||
| 1698 | return h | 1699 | return h | ||
| 1699 | } | 1700 | } | ||
| 1700 | 1701 | ||||
| 1701 | - | func welcomeFrame(token uint64) ports.Frame { | 1702 | + | func welcomeFrame(token uint64) wire.Frame { |
| 1702 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main", ResumeToken: token, Capabilities: protocol.CapabilityResume})) | 1703 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main", ResumeToken: token, Capabilities: protocol.CapabilityResume})) |
| 1703 | } | 1704 | } | ||
| 1704 | 1705 | ||||
| 1705 | func TestRunReconnectsWithRotatedTokenAndSameClientID(t *testing.T) { | 1706 | func TestRunReconnectsWithRotatedTokenAndSameClientID(t *testing.T) { | ||
| @@ -1707,7 +1708,7 @@ func TestRunReconnectsWithRotatedTokenAndSameClientID(t *testing.T) { | |||||
| 1707 | defer term.in.unblock() | 1708 | defer term.in.unblock() | ||
| 1708 | tr1 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {err: io.EOF}}} | 1709 | tr1 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {err: io.EOF}}} | ||
| 1709 | tr2 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(22)}, {err: io.EOF}}} | 1710 | tr2 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(22)}, {err: io.EOF}}} | ||
| 1710 | - | tr3 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(33)}, {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} | 1711 | + | tr3 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(33)}, {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} |
| 1711 | d := &sequenceDialer{trs: []ports.Transport{tr1, tr2, tr3}} | 1712 | d := &sequenceDialer{trs: []ports.Transport{tr1, tr2, tr3}} | ||
| 1712 | clock := &reconnectTestClock{} | 1713 | clock := &reconnectTestClock{} | ||
| 1713 | result := make(chan error, 1) | 1714 | result := make(chan error, 1) | ||
| @@ -1741,20 +1742,20 @@ func TestReconnectRestoresLastPublishedRouteTab(t *testing.T) { | |||||
| 1741 | defer term.in.unblock() | 1742 | defer term.in.unblock() | ||
| 1742 | lifecycle := domain.SessionLifecycleID{7, 8, 9} | 1743 | lifecycle := domain.SessionLifecycleID{7, 8, 9} | ||
| 1743 | target := protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "work"} | 1744 | target := protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "work"} | ||
| 1744 | - | welcome := func(token uint64) ports.Frame { | 1745 | + | welcome := func(token uint64) wire.Frame { |
| 1745 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 1746 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 1746 | SessionID: "work", SessionName: "work", ResumeToken: token, Capabilities: protocol.CapabilityResume, | 1747 | SessionID: "work", SessionName: "work", ResumeToken: token, Capabilities: protocol.CapabilityResume, | ||
| 1747 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: target}, | 1748 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: target}, | ||
| 1748 | })) | 1749 | })) | ||
| 1749 | } | 1750 | } | ||
| 1750 | tr1 := &recordingTransport{recvs: []recvItem{ | 1751 | tr1 := &recordingTransport{recvs: []recvItem{ | ||
| 1751 | {f: welcome(11)}, | 1752 | {f: welcome(11)}, | ||
| 1752 | - | {f: frameOf(ports.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{Target: target, ActiveTabID: "tab-2"}))}, | 1753 | + | {f: frameOf(wire.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{Target: target, ActiveTabID: "tab-2"}))}, |
| 1753 | {err: io.EOF}, | 1754 | {err: io.EOF}, | ||
| 1754 | }} | 1755 | }} | ||
| 1755 | tr2 := &recordingTransport{recvs: []recvItem{ | 1756 | tr2 := &recordingTransport{recvs: []recvItem{ | ||
| 1756 | {f: welcome(22)}, | 1757 | {f: welcome(22)}, | ||
| 1757 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1758 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1758 | }} | 1759 | }} | ||
| 1759 | dialer := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | 1760 | dialer := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | ||
| 1760 | clock := &reconnectTestClock{} | 1761 | clock := &reconnectTestClock{} | ||
| @@ -1780,8 +1781,8 @@ func TestRemoteReconnectDropsStalePickerTargetAfterDaemonSessionSwitch(t *testin | |||||
| 1780 | Endpoint: "remote", DisplayOrigin: "remote", LifecycleID: oldLifecycle, | 1781 | Endpoint: "remote", DisplayOrigin: "remote", LifecycleID: oldLifecycle, | ||
| 1781 | SessionName: "old", LiveTabID: "tab-1", | 1782 | SessionName: "old", LiveTabID: "tab-1", | ||
| 1782 | } | 1783 | } | ||
| 1783 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) ports.Frame { | 1784 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) wire.Frame { |
| 1784 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | 1785 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ |
| 1785 | SessionID: name, SessionName: name, ResumeToken: token, Capabilities: protocol.CapabilityResume, | 1786 | SessionID: name, SessionName: name, ResumeToken: token, Capabilities: protocol.CapabilityResume, | ||
| 1786 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | 1787 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | ||
| 1787 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | 1788 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | ||
| @@ -1790,14 +1791,14 @@ func TestRemoteReconnectDropsStalePickerTargetAfterDaemonSessionSwitch(t *testin | |||||
| 1790 | } | 1791 | } | ||
| 1791 | tr1 := &recordingTransport{recvs: []recvItem{ | 1792 | tr1 := &recordingTransport{recvs: []recvItem{ | ||
| 1792 | {f: welcome("old", oldLifecycle, 11)}, | 1793 | {f: welcome("old", oldLifecycle, 11)}, | ||
| 1793 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | 1794 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ |
| 1794 | Target: protocol.ExactSessionTarget{LifecycleID: newLifecycle, SessionName: "new"}, | 1795 | Target: protocol.ExactSessionTarget{LifecycleID: newLifecycle, SessionName: "new"}, | ||
| 1795 | }))}, | 1796 | }))}, | ||
| 1796 | {err: io.EOF}, | 1797 | {err: io.EOF}, | ||
| 1797 | }} | 1798 | }} | ||
| 1798 | tr2 := &recordingTransport{recvs: []recvItem{ | 1799 | tr2 := &recordingTransport{recvs: []recvItem{ | ||
| 1799 | {f: welcome("new", newLifecycle, 22)}, | 1800 | {f: welcome("new", newLifecycle, 22)}, | ||
| 1800 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1801 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1801 | }} | 1802 | }} | ||
| 1802 | dialer := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | 1803 | dialer := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | ||
| 1803 | clock := &reconnectTestClock{} | 1804 | clock := &reconnectTestClock{} | ||
| @@ -1838,8 +1839,8 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||||
| 1838 | }, | 1839 | }, | ||
| 1839 | remember: func() error { return nil }, | 1840 | remember: func() error { return nil }, | ||
| 1840 | recv: []recvItem{ | 1841 | recv: []recvItem{ | ||
| 1841 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1842 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1842 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1843 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1843 | }, | 1844 | }, | ||
| 1844 | wantCalled: true, | 1845 | wantCalled: true, | ||
| 1845 | }, | 1846 | }, | ||
| @@ -1852,8 +1853,8 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||||
| 1852 | }, | 1853 | }, | ||
| 1853 | remember: func() error { return errors.New("disk full") }, | 1854 | remember: func() error { return errors.New("disk full") }, | ||
| 1854 | recv: []recvItem{ | 1855 | recv: []recvItem{ | ||
| 1855 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1856 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1856 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1857 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1857 | }, | 1858 | }, | ||
| 1858 | wantCalled: true, | 1859 | wantCalled: true, | ||
| 1859 | }, | 1860 | }, | ||
| @@ -1869,8 +1870,8 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||||
| 1869 | return nil | 1870 | return nil | ||
| 1870 | }, | 1871 | }, | ||
| 1871 | recv: []recvItem{ | 1872 | recv: []recvItem{ | ||
| 1872 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1873 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1873 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 1874 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 1874 | }, | 1875 | }, | ||
| 1875 | }, | 1876 | }, | ||
| 1876 | { | 1877 | { | ||
| @@ -1885,7 +1886,7 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||||
| 1885 | return nil | 1886 | return nil | ||
| 1886 | }, | 1887 | }, | ||
| 1887 | recv: []recvItem{ | 1888 | recv: []recvItem{ | ||
| 1888 | - | {f: frameOf(ports.MsgError, ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"}))}, | 1889 | + | {f: frameOf(wire.MsgError, wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"}))}, |
| 1889 | }, | 1890 | }, | ||
| 1890 | preWelcomeReject: true, | 1891 | preWelcomeReject: true, | ||
| 1891 | wantErr: true, | 1892 | wantErr: true, | ||
| @@ -1899,7 +1900,7 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||||
| 1899 | }, | 1900 | }, | ||
| 1900 | remember: func() error { return nil }, | 1901 | remember: func() error { return nil }, | ||
| 1901 | recv: []recvItem{ | 1902 | recv: []recvItem{ | ||
| 1902 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 1903 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 1903 | {err: errors.New("connection reset")}, | 1904 | {err: errors.New("connection reset")}, | ||
| 1904 | }, | 1905 | }, | ||
| 1905 | wantCalled: true, | 1906 | wantCalled: true, | ||
| @@ -1940,9 +1941,9 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||||
| 1940 | 1941 | ||||
| 1941 | tr := portsmocks.NewMockTransport(t) | 1942 | tr := portsmocks.NewMockTransport(t) | ||
| 1942 | if !tt.preWelcomeReject { | 1943 | if !tt.preWelcomeReject { | ||
| 1943 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 1944 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 1944 | } | 1945 | } | ||
| 1945 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 1946 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 1946 | if tt.preWelcomeReject { | 1947 | if tt.preWelcomeReject { | ||
| 1947 | tr.EXPECT().Recv().Return(tt.recv[0].f, tt.recv[0].err).Once() | 1948 | tr.EXPECT().Recv().Return(tt.recv[0].f, tt.recv[0].err).Once() | ||
| 1948 | } else { | 1949 | } else { | ||
| @@ -1984,7 +1985,7 @@ func TestRunRememberRemoteHostAtMostOnceAcrossReconnects(t *testing.T) { | |||||
| 1984 | learnerDone := make(chan struct{}) | 1985 | learnerDone := make(chan struct{}) | ||
| 1985 | 1986 | ||||
| 1986 | tr1 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {err: io.EOF}}} | 1987 | tr1 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {err: io.EOF}}} | ||
| 1987 | - | tr2 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(22)}, {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} | 1988 | + | tr2 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(22)}, {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} |
| 1988 | d := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | 1989 | d := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | ||
| 1989 | 1990 | ||||
| 1990 | deps := testDependencies(d, term, realClock{}, nil, nil) | 1991 | deps := testDependencies(d, term, realClock{}, nil, nil) | ||
| @@ -2033,11 +2034,11 @@ func TestAttachRememberRemoteHostDoesNotBlockAfterWelcome(t *testing.T) { | |||||
| 2033 | learnerDone := make(chan struct{}) | 2034 | learnerDone := make(chan struct{}) | ||
| 2034 | 2035 | ||||
| 2035 | tr := portsmocks.NewMockTransport(t) | 2036 | tr := portsmocks.NewMockTransport(t) | ||
| 2036 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 2037 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 2037 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 2038 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 2038 | unblock := scriptRecv(tr, | 2039 | unblock := scriptRecv(tr, | ||
| 2039 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 2040 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 2040 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 2041 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 2041 | ) | 2042 | ) | ||
| 2042 | defer unblock() | 2043 | defer unblock() | ||
| 2043 | tr.EXPECT().Close().Return(nil).Once() | 2044 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -2114,11 +2115,11 @@ func TestRunRestoresTerminalBeforeWaitingForLearner(t *testing.T) { | |||||
| 2114 | learnerDone := make(chan struct{}) | 2115 | learnerDone := make(chan struct{}) | ||
| 2115 | 2116 | ||||
| 2116 | tr := portsmocks.NewMockTransport(t) | 2117 | tr := portsmocks.NewMockTransport(t) | ||
| 2117 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 2118 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 2118 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 2119 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 2119 | unblock := scriptRecv(tr, | 2120 | unblock := scriptRecv(tr, | ||
| 2120 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 2121 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 2121 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 2122 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 2122 | ) | 2123 | ) | ||
| 2123 | defer unblock() | 2124 | defer unblock() | ||
| 2124 | tr.EXPECT().Close().Return(nil).Once() | 2125 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -2211,11 +2212,11 @@ func TestRunReturnsWhenRemoteHostLearnerStalls(t *testing.T) { | |||||
| 2211 | }).Maybe() | 2212 | }).Maybe() | ||
| 2212 | 2213 | ||||
| 2213 | tr := portsmocks.NewMockTransport(t) | 2214 | tr := portsmocks.NewMockTransport(t) | ||
| 2214 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 2215 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 2215 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 2216 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 2216 | unblock := scriptRecv(tr, | 2217 | unblock := scriptRecv(tr, | ||
| 2217 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 2218 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 2218 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 2219 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 2219 | ) | 2220 | ) | ||
| 2220 | defer unblock() | 2221 | defer unblock() | ||
| 2221 | tr.EXPECT().Close().Return(nil).Once() | 2222 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -2267,7 +2268,7 @@ func TestRunReturnsWhenRemoteHostLearnerStalls(t *testing.T) { | |||||
| 2267 | func TestRunDoesNotRetryTerminalDetachedError(t *testing.T) { | 2268 | func TestRunDoesNotRetryTerminalDetachedError(t *testing.T) { | ||
| 2268 | term := newRunTerminal() | 2269 | term := newRunTerminal() | ||
| 2269 | defer term.in.unblock() | 2270 | defer term.in.unblock() | ||
| 2270 | - | tr := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonSessionKilled}))}}} | 2271 | + | tr := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonSessionKilled}))}}} |
| 2271 | d := &sequenceDialer{trs: []ports.Transport{tr}} | 2272 | d := &sequenceDialer{trs: []ports.Transport{tr}} | ||
| 2272 | 2273 | ||||
| 2273 | err := runTestClient(context.Background(), testDependencies(d, term, realClock{}, nil, nil), client.AttachRequest{Intent: protocol.IntentAttach, SessionName: "main", Remote: false}) | 2274 | err := runTestClient(context.Background(), testDependencies(d, term, realClock{}, nil, nil), client.AttachRequest{Intent: protocol.IntentAttach, SessionName: "main", Remote: false}) | ||
M internal/usecase/client/clipboard_intercept_test.go +25 -24
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 17 | "github.com/bnema/vev/internal/protocol" | 17 | "github.com/bnema/vev/internal/protocol" | ||
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 18 | "github.com/bnema/vev/internal/usecase/client" | 19 | "github.com/bnema/vev/internal/usecase/client" | ||
| 19 | ) | 20 | ) | ||
| 20 | 21 | ||||
| @@ -44,11 +45,11 @@ func runRemoteClipboardTest(t *testing.T, remote bool, clip ports.ClipboardReade | |||||
| 44 | allowDetach := make(chan struct{}) | 45 | allowDetach := make(chan struct{}) | ||
| 45 | 46 | ||||
| 46 | tr := portsmocks.NewMockTransport(t) | 47 | tr := portsmocks.NewMockTransport(t) | ||
| 47 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 48 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 48 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 49 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 49 | - | tr.EXPECT().Send(isType(ports.MsgResize)).Return(nil).Maybe() | 50 | + | tr.EXPECT().Send(isType(wire.MsgResize)).Return(nil).Maybe() |
| 50 | - | tr.EXPECT().Send(isType(ports.MsgInput)).RunAndReturn(func(f ports.Frame) error { | 51 | + | tr.EXPECT().Send(isType(wire.MsgInput)).RunAndReturn(func(f wire.Frame) error { |
| 51 | - | in, err := ports.UnmarshalInput(f.Payload) | 52 | + | in, err := wire.UnmarshalInput(f.Payload) |
| 52 | require.NoError(t, err) | 53 | require.NoError(t, err) | ||
| 53 | gotInput <- append([]byte(nil), in.Data...) | 54 | gotInput <- append([]byte(nil), in.Data...) | ||
| 54 | if bytes.IndexByte(in.Data, triggerByte) >= 0 { | 55 | if bytes.IndexByte(in.Data, triggerByte) >= 0 { | ||
| @@ -56,33 +57,33 @@ func runRemoteClipboardTest(t *testing.T, remote bool, clip ports.ClipboardReade | |||||
| 56 | } | 57 | } | ||
| 57 | return nil | 58 | return nil | ||
| 58 | }).Maybe() | 59 | }).Maybe() | ||
| 59 | - | tr.EXPECT().Send(isType(ports.MsgImagePush)).RunAndReturn(func(f ports.Frame) error { | 60 | + | tr.EXPECT().Send(isType(wire.MsgImagePush)).RunAndReturn(func(f wire.Frame) error { |
| 60 | - | ip, err := ports.UnmarshalImagePush(f.Payload) | 61 | + | ip, err := wire.UnmarshalImagePush(f.Payload) |
| 61 | require.NoError(t, err) | 62 | require.NoError(t, err) | ||
| 62 | gotImage <- ip | 63 | gotImage <- ip | ||
| 63 | return nil | 64 | return nil | ||
| 64 | }).Maybe() | 65 | }).Maybe() | ||
| 65 | - | tr.EXPECT().Send(isType(ports.MsgClientNotice)).Return(nil).Maybe() | 66 | + | tr.EXPECT().Send(isType(wire.MsgClientNotice)).Return(nil).Maybe() |
| 66 | 67 | ||||
| 67 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | 68 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) |
| 68 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | 69 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) |
| 69 | recvCh := make(chan recvItem, 1) | 70 | recvCh := make(chan recvItem, 1) | ||
| 70 | recvCh <- recvItem{f: welcome} | 71 | recvCh <- recvItem{f: welcome} | ||
| 71 | closed := make(chan struct{}) | 72 | closed := make(chan struct{}) | ||
| 72 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 73 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 73 | select { | 74 | select { | ||
| 74 | case it := <-recvCh: | 75 | case it := <-recvCh: | ||
| 75 | return it.f, it.err | 76 | return it.f, it.err | ||
| 76 | case <-allowDetach: | 77 | case <-allowDetach: | ||
| 77 | select { | 78 | select { | ||
| 78 | case <-closed: | 79 | case <-closed: | ||
| 79 | - | return ports.Frame{}, io.EOF | 80 | + | return wire.Frame{}, io.EOF |
| 80 | default: | 81 | default: | ||
| 81 | close(closed) | 82 | close(closed) | ||
| 82 | return detached, nil | 83 | return detached, nil | ||
| 83 | } | 84 | } | ||
| 84 | case <-closed: | 85 | case <-closed: | ||
| 85 | - | return ports.Frame{}, io.EOF | 86 | + | return wire.Frame{}, io.EOF |
| 86 | } | 87 | } | ||
| 87 | }).Maybe() | 88 | }).Maybe() | ||
| 88 | tr.EXPECT().Close().Return(nil).Once() | 89 | tr.EXPECT().Close().Return(nil).Once() | ||
| @@ -142,17 +143,17 @@ func TestRunRemoteClipboardCtrlVWithNoImageForwardsCtrlV(t *testing.T) { | |||||
| 142 | } | 143 | } | ||
| 143 | 144 | ||||
| 144 | type clipboardToastLifecycleTransport struct { | 145 | type clipboardToastLifecycleTransport struct { | ||
| 145 | - | recv chan ports.Frame | 146 | + | recv chan wire.Frame |
| 146 | - | sends chan ports.Frame | 147 | + | sends chan wire.Frame |
| 147 | } | 148 | } | ||
| 148 | 149 | ||||
| 149 | - | func (t *clipboardToastLifecycleTransport) Send(f ports.Frame) error { | 150 | + | func (t *clipboardToastLifecycleTransport) Send(f wire.Frame) error { |
| 150 | t.sends <- f | 151 | t.sends <- f | ||
| 151 | return nil | 152 | return nil | ||
| 152 | } | 153 | } | ||
| 153 | 154 | ||||
| 154 | - | func (t *clipboardToastLifecycleTransport) Recv() (ports.Frame, error) { return <-t.recv, nil } | 155 | + | func (t *clipboardToastLifecycleTransport) Recv() (wire.Frame, error) { return <-t.recv, nil } |
| 155 | - | func (*clipboardToastLifecycleTransport) Close() error { return nil } | 156 | + | func (*clipboardToastLifecycleTransport) Close() error { return nil } |
| 156 | 157 | ||||
| 157 | type clipboardToastLifecycleDialer struct{ transport ports.Transport } | 158 | type clipboardToastLifecycleDialer struct{ transport ports.Transport } | ||
| 158 | 159 | ||||
| @@ -175,8 +176,8 @@ func TestRunRemoteClipboardFailureNotifiesDaemonAndWritesOutputVerbatim(t *testi | |||||
| 175 | 176 | ||||
| 176 | clipboard := portsmocks.NewMockClipboardReader(t) | 177 | clipboard := portsmocks.NewMockClipboardReader(t) | ||
| 177 | clipboard.EXPECT().ReadImage(mock.Anything).Return("", nil, errors.New("read failed")).Once() | 178 | clipboard.EXPECT().ReadImage(mock.Anything).Return("", nil, errors.New("read failed")).Once() | ||
| 178 | - | transport := &clipboardToastLifecycleTransport{recv: make(chan ports.Frame, 8), sends: make(chan ports.Frame, 16)} | 179 | + | transport := &clipboardToastLifecycleTransport{recv: make(chan wire.Frame, 8), sends: make(chan wire.Frame, 16)} |
| 179 | - | transport.recv <- frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | 180 | + | transport.recv <- frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) |
| 180 | 181 | ||||
| 181 | result := make(chan error, 1) | 182 | result := make(chan error, 1) | ||
| 182 | go func() { | 183 | go func() { | ||
| @@ -187,10 +188,10 @@ func TestRunRemoteClipboardFailureNotifiesDaemonAndWritesOutputVerbatim(t *testi | |||||
| 187 | for !gotNotice { | 188 | for !gotNotice { | ||
| 188 | select { | 189 | select { | ||
| 189 | case sent := <-transport.sends: | 190 | case sent := <-transport.sends: | ||
| 190 | - | if sent.Type != ports.MsgClientNotice { | 191 | + | if sent.Type != wire.MsgClientNotice { |
| 191 | continue | 192 | continue | ||
| 192 | } | 193 | } | ||
| 193 | - | notice, err := ports.UnmarshalClientNotice(sent.Payload) | 194 | + | notice, err := wire.UnmarshalClientNotice(sent.Payload) |
| 194 | require.NoError(t, err) | 195 | require.NoError(t, err) | ||
| 195 | require.Equal(t, protocol.ClientNoticeClipboardFallback, notice.Action) | 196 | require.Equal(t, protocol.ClientNoticeClipboardFallback, notice.Action) | ||
| 196 | gotNotice = true | 197 | gotNotice = true | ||
| @@ -199,8 +200,8 @@ func TestRunRemoteClipboardFailureNotifiesDaemonAndWritesOutputVerbatim(t *testi | |||||
| 199 | } | 200 | } | ||
| 200 | } | 201 | } | ||
| 201 | beforeOutput := out.String() | 202 | beforeOutput := out.String() | ||
| 202 | - | transport.recv <- frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("incremental")})) | 203 | + | transport.recv <- frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("incremental")})) |
| 203 | - | transport.recv <- frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | 204 | + | transport.recv <- frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) |
| 204 | 205 | ||||
| 205 | select { | 206 | select { | ||
| 206 | case err := <-result: | 207 | case err := <-result: | ||
M internal/usecase/client/palette_attach_generation_test.go +14 -13
| @@ -17,6 +17,7 @@ import ( | |||||
| 17 | "github.com/bnema/vev/internal/domain" | 17 | "github.com/bnema/vev/internal/domain" | ||
| 18 | "github.com/bnema/vev/internal/ports" | 18 | "github.com/bnema/vev/internal/ports" | ||
| 19 | "github.com/bnema/vev/internal/protocol" | 19 | "github.com/bnema/vev/internal/protocol" | ||
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 20 | ) | 21 | ) | ||
| 21 | 22 | ||||
| 22 | // attachPaletteClock deliberately exposes each independently-created timer. | 23 | // attachPaletteClock deliberately exposes each independently-created timer. | ||
| @@ -115,11 +116,11 @@ func (*attachPaletteTerminalHarness) Flush() error { r | |||||
| 115 | 116 | ||||
| 116 | type attachPaletteTransport struct { | 117 | type attachPaletteTransport struct { | ||
| 117 | mu sync.Mutex | 118 | mu sync.Mutex | ||
| 118 | - | frames []ports.Frame | 119 | + | frames []wire.Frame |
| 119 | themes []protocol.Theme | 120 | themes []protocol.Theme | ||
| 120 | themeCh chan protocol.Theme | 121 | themeCh chan protocol.Theme | ||
| 121 | inputCh chan protocol.Input | 122 | inputCh chan protocol.Input | ||
| 122 | - | detached chan ports.Frame | 123 | + | detached chan wire.Frame |
| 123 | themeSendErr error | 124 | themeSendErr error | ||
| 124 | welcomed bool | 125 | welcomed bool | ||
| 125 | } | 126 | } | ||
| @@ -128,20 +129,20 @@ func newAttachPaletteTransport() *attachPaletteTransport { | |||||
| 128 | return &attachPaletteTransport{ | 129 | return &attachPaletteTransport{ | ||
| 129 | themeCh: make(chan protocol.Theme, 16), | 130 | themeCh: make(chan protocol.Theme, 16), | ||
| 130 | inputCh: make(chan protocol.Input, 16), | 131 | inputCh: make(chan protocol.Input, 16), | ||
| 131 | - | detached: make(chan ports.Frame, 1), | 132 | + | detached: make(chan wire.Frame, 1), |
| 132 | } | 133 | } | ||
| 133 | } | 134 | } | ||
| 134 | - | func (t *attachPaletteTransport) Send(frame ports.Frame) error { | 135 | + | func (t *attachPaletteTransport) Send(frame wire.Frame) error { |
| 135 | t.mu.Lock() | 136 | t.mu.Lock() | ||
| 136 | t.frames = append(t.frames, frame) | 137 | t.frames = append(t.frames, frame) | ||
| 137 | themeSendErr := t.themeSendErr | 138 | themeSendErr := t.themeSendErr | ||
| 138 | t.mu.Unlock() | 139 | t.mu.Unlock() | ||
| 139 | switch frame.Type { | 140 | switch frame.Type { | ||
| 140 | - | case ports.MsgTheme: | 141 | + | case wire.MsgTheme: |
| 141 | if themeSendErr != nil { | 142 | if themeSendErr != nil { | ||
| 142 | return themeSendErr | 143 | return themeSendErr | ||
| 143 | } | 144 | } | ||
| 144 | - | got, err := ports.UnmarshalTheme(frame.Payload) | 145 | + | got, err := wire.UnmarshalTheme(frame.Payload) |
| 145 | if err != nil { | 146 | if err != nil { | ||
| 146 | return err | 147 | return err | ||
| 147 | } | 148 | } | ||
| @@ -149,8 +150,8 @@ func (t *attachPaletteTransport) Send(frame ports.Frame) error { | |||||
| 149 | t.themes = append(t.themes, got) | 150 | t.themes = append(t.themes, got) | ||
| 150 | t.mu.Unlock() | 151 | t.mu.Unlock() | ||
| 151 | t.themeCh <- got | 152 | t.themeCh <- got | ||
| 152 | - | case ports.MsgInput: | 153 | + | case wire.MsgInput: |
| 153 | - | got, err := ports.UnmarshalInput(frame.Payload) | 154 | + | got, err := wire.UnmarshalInput(frame.Payload) |
| 154 | if err != nil { | 155 | if err != nil { | ||
| 155 | return err | 156 | return err | ||
| 156 | } | 157 | } | ||
| @@ -158,12 +159,12 @@ func (t *attachPaletteTransport) Send(frame ports.Frame) error { | |||||
| 158 | } | 159 | } | ||
| 159 | return nil | 160 | return nil | ||
| 160 | } | 161 | } | ||
| 161 | - | func (t *attachPaletteTransport) Recv() (ports.Frame, error) { | 162 | + | func (t *attachPaletteTransport) Recv() (wire.Frame, error) { |
| 162 | t.mu.Lock() | 163 | t.mu.Lock() | ||
| 163 | if !t.welcomed { | 164 | if !t.welcomed { | ||
| 164 | t.welcomed = true | 165 | t.welcomed = true | ||
| 165 | t.mu.Unlock() | 166 | t.mu.Unlock() | ||
| 166 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil | 167 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil |
| 167 | } | 168 | } | ||
| 168 | t.mu.Unlock() | 169 | t.mu.Unlock() | ||
| 169 | return <-t.detached, nil | 170 | return <-t.detached, nil | ||
| @@ -239,7 +240,7 @@ func (h *attachPaletteHarness) nextTimer(t *testing.T) *attachPaletteTimer { | |||||
| 239 | } | 240 | } | ||
| 240 | func (h *attachPaletteHarness) detach(t *testing.T) { | 241 | func (h *attachPaletteHarness) detach(t *testing.T) { | ||
| 241 | t.Helper() | 242 | t.Helper() | ||
| 242 | - | h.transport.detached <- ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} | 243 | + | h.transport.detached <- wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} |
| 243 | result := <-h.done | 244 | result := <-h.done | ||
| 244 | require.NoError(t, result.err) | 245 | require.NoError(t, result.err) | ||
| 245 | select { | 246 | select { | ||
| @@ -325,7 +326,7 @@ func TestAttachReconnectPreservesStandaloneEscapeBeforeClaimRevocation(t *testin | |||||
| 325 | 326 | ||||
| 326 | // Detach starts reconnect teardown. The residual must already be owned by | 327 | // Detach starts reconnect teardown. The residual must already be owned by | ||
| 327 | // the lifecycle reader at the precise point the old claim is revoked. | 328 | // the lifecycle reader at the precise point the old claim is revoked. | ||
| 328 | - | first.transport.detached <- ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} | 329 | + | first.transport.detached <- wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} |
| 329 | require.Equal(t, []byte("\x1b"), <-revoked) | 330 | require.Equal(t, []byte("\x1b"), <-revoked) | ||
| 330 | release() | 331 | release() | ||
| 331 | require.NoError(t, (<-first.done).err) | 332 | require.NoError(t, (<-first.done).err) | ||
| @@ -437,7 +438,7 @@ func TestStdinPumpSameReadSchemeAndOldMarkerCannotAdvanceReplacement(t *testing. | |||||
| 437 | // notification and publish its replacement generation before the scanner | 438 | // notification and publish its replacement generation before the scanner | ||
| 438 | // can deliver the old marker from the same terminal Read. | 439 | // can deliver the old marker from the same terminal Read. | ||
| 439 | events := make(chan paletteGenerationEvent) | 440 | events := make(chan paletteGenerationEvent) | ||
| 440 | - | out := make(chan ports.Frame, 1) | 441 | + | out := make(chan wire.Frame, 1) |
| 441 | schemeHandled := make(chan struct{}) | 442 | schemeHandled := make(chan struct{}) | ||
| 442 | pump := &stdinPump{ | 443 | pump := &stdinPump{ | ||
| 443 | ctx: ctx, | 444 | ctx: ctx, | ||
M internal/usecase/client/palette_attach_test.go +9 -8
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | "github.com/bnema/vev/internal/domain" | 15 | "github.com/bnema/vev/internal/domain" | ||
| 16 | "github.com/bnema/vev/internal/ports" | 16 | "github.com/bnema/vev/internal/ports" | ||
| 17 | "github.com/bnema/vev/internal/protocol" | 17 | "github.com/bnema/vev/internal/protocol" | ||
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 18 | ) | 19 | ) | ||
| 19 | 20 | ||||
| 20 | type paletteAttachClock struct{} | 21 | type paletteAttachClock struct{} | ||
| @@ -78,18 +79,18 @@ func (t *paletteAttachTerminal) Flush() error { return n | |||||
| 78 | 79 | ||||
| 79 | type paletteAttachTransport struct { | 80 | type paletteAttachTransport struct { | ||
| 80 | mu sync.Mutex | 81 | mu sync.Mutex | ||
| 81 | - | sent []ports.Frame | 82 | + | sent []wire.Frame |
| 82 | themes []protocol.Theme | 83 | themes []protocol.Theme | ||
| 83 | finals int | 84 | finals int | ||
| 84 | finalSet chan struct{} | 85 | finalSet chan struct{} | ||
| 85 | } | 86 | } | ||
| 86 | 87 | ||||
| 87 | - | func (t *paletteAttachTransport) Send(frame ports.Frame) error { | 88 | + | func (t *paletteAttachTransport) Send(frame wire.Frame) error { |
| 88 | t.mu.Lock() | 89 | t.mu.Lock() | ||
| 89 | defer t.mu.Unlock() | 90 | defer t.mu.Unlock() | ||
| 90 | t.sent = append(t.sent, frame) | 91 | t.sent = append(t.sent, frame) | ||
| 91 | - | if frame.Type == ports.MsgTheme { | 92 | + | if frame.Type == wire.MsgTheme { |
| 92 | - | theme, err := ports.UnmarshalTheme(frame.Payload) | 93 | + | theme, err := wire.UnmarshalTheme(frame.Payload) |
| 93 | if err != nil { | 94 | if err != nil { | ||
| 94 | return err | 95 | return err | ||
| 95 | } | 96 | } | ||
| @@ -104,15 +105,15 @@ func (t *paletteAttachTransport) Send(frame ports.Frame) error { | |||||
| 104 | return nil | 105 | return nil | ||
| 105 | } | 106 | } | ||
| 106 | 107 | ||||
| 107 | - | func (t *paletteAttachTransport) Recv() (ports.Frame, error) { | 108 | + | func (t *paletteAttachTransport) Recv() (wire.Frame, error) { |
| 108 | t.mu.Lock() | 109 | t.mu.Lock() | ||
| 109 | first := len(t.sent) == 1 | 110 | first := len(t.sent) == 1 | ||
| 110 | t.mu.Unlock() | 111 | t.mu.Unlock() | ||
| 111 | if first { | 112 | if first { | ||
| 112 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil | 113 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil |
| 113 | } | 114 | } | ||
| 114 | <-t.finalSet | 115 | <-t.finalSet | ||
| 115 | - | return ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}, nil | 116 | + | return wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}, nil |
| 116 | } | 117 | } | ||
| 117 | func (*paletteAttachTransport) Close() error { return nil } | 118 | func (*paletteAttachTransport) Close() error { return nil } | ||
| 118 | 119 | ||||
| @@ -155,7 +156,7 @@ func TestAttachPublishesOnlyClearedAndDefinitiveInitialPalette(t *testing.T) { | |||||
| 155 | transport.mu.Lock() | 156 | transport.mu.Lock() | ||
| 156 | defer transport.mu.Unlock() | 157 | defer transport.mu.Unlock() | ||
| 157 | require.Len(t, transport.sent, 3) | 158 | require.Len(t, transport.sent, 3) | ||
| 158 | - | require.Equal(t, []ports.MsgType{ports.MsgHello, ports.MsgTheme, ports.MsgTheme}, []ports.MsgType{ | 159 | + | require.Equal(t, []wire.MsgType{wire.MsgHello, wire.MsgTheme, wire.MsgTheme}, []wire.MsgType{ |
| 159 | transport.sent[0].Type, transport.sent[1].Type, transport.sent[2].Type, | 160 | transport.sent[0].Type, transport.sent[1].Type, transport.sent[2].Type, | ||
| 160 | }, "the protocol requires Hello before the two palette publications") | 161 | }, "the protocol requires Hello before the two palette publications") | ||
| 161 | require.Len(t, transport.themes, 2) | 162 | require.Len(t, transport.themes, 2) | ||
M internal/usecase/client/reconnect_toast_test.go +61 -60
| @@ -21,6 +21,7 @@ import ( | |||||
| 21 | "github.com/bnema/vev/internal/ports" | 21 | "github.com/bnema/vev/internal/ports" | ||
| 22 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 22 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 23 | "github.com/bnema/vev/internal/protocol" | 23 | "github.com/bnema/vev/internal/protocol" | ||
| 24 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 24 | ) | 25 | ) | ||
| 25 | 26 | ||||
| 26 | type reconnectToastTerminalHarness struct { | 27 | type reconnectToastTerminalHarness struct { | ||
| @@ -129,20 +130,20 @@ func (r *reconnectToastOutputRecorder) String() string { | |||||
| 129 | return r.all.String() | 130 | return r.all.String() | ||
| 130 | } | 131 | } | ||
| 131 | 132 | ||||
| 132 | - | func reconnectToastWelcome(token uint64) ports.Frame { | 133 | + | func reconnectToastWelcome(token uint64) wire.Frame { |
| 133 | return reconnectToastWelcomeNamed("", token) | 134 | return reconnectToastWelcomeNamed("", token) | ||
| 134 | } | 135 | } | ||
| 135 | 136 | ||||
| 136 | - | func reconnectToastWelcomeNamed(name string, token uint64) ports.Frame { | 137 | + | func reconnectToastWelcomeNamed(name string, token uint64) wire.Frame { |
| 137 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: name, ResumeToken: token, Capabilities: protocol.CapabilityResume})} | 138 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: name, ResumeToken: token, Capabilities: protocol.CapabilityResume})} |
| 138 | } | 139 | } | ||
| 139 | 140 | ||||
| 140 | - | func reconnectToastDetach(reason uint8) ports.Frame { | 141 | + | func reconnectToastDetach(reason uint8) wire.Frame { |
| 141 | - | return ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: reason})} | 142 | + | return wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: reason})} |
| 142 | } | 143 | } | ||
| 143 | 144 | ||||
| 144 | type reconnectToastRecv struct { | 145 | type reconnectToastRecv struct { | ||
| 145 | - | frame ports.Frame | 146 | + | frame wire.Frame |
| 146 | err error | 147 | err error | ||
| 147 | } | 148 | } | ||
| 148 | 149 | ||||
| @@ -163,7 +164,7 @@ func (d *reconnectToastSequenceDialer) Dial(context.Context) (ports.Transport, e | |||||
| 163 | type reconnectToastRecordingTransport struct { | 164 | type reconnectToastRecordingTransport struct { | ||
| 164 | mu sync.Mutex | 165 | mu sync.Mutex | ||
| 165 | recvs []reconnectToastRecv | 166 | recvs []reconnectToastRecv | ||
| 166 | - | sends []ports.Frame | 167 | + | sends []wire.Frame |
| 167 | closed bool | 168 | closed bool | ||
| 168 | } | 169 | } | ||
| 169 | 170 | ||||
| @@ -173,7 +174,7 @@ func newReconnectToastRecordingTransport(recvs ...reconnectToastRecv) *reconnect | |||||
| 173 | 174 | ||||
| 174 | type reconnectToastSentFrames struct { | 175 | type reconnectToastSentFrames struct { | ||
| 175 | mu sync.Mutex | 176 | mu sync.Mutex | ||
| 176 | - | frames []ports.Frame | 177 | + | frames []wire.Frame |
| 177 | changed chan struct{} | 178 | changed chan struct{} | ||
| 178 | } | 179 | } | ||
| 179 | 180 | ||||
| @@ -181,7 +182,7 @@ func newReconnectToastSentFrames() *reconnectToastSentFrames { | |||||
| 181 | return &reconnectToastSentFrames{changed: make(chan struct{}, 1)} | 182 | return &reconnectToastSentFrames{changed: make(chan struct{}, 1)} | ||
| 182 | } | 183 | } | ||
| 183 | 184 | ||||
| 184 | - | func (s *reconnectToastSentFrames) record(frame ports.Frame) { | 185 | + | func (s *reconnectToastSentFrames) record(frame wire.Frame) { |
| 185 | s.mu.Lock() | 186 | s.mu.Lock() | ||
| 186 | s.frames = append(s.frames, frame) | 187 | s.frames = append(s.frames, frame) | ||
| 187 | s.mu.Unlock() | 188 | s.mu.Unlock() | ||
| @@ -191,7 +192,7 @@ func (s *reconnectToastSentFrames) record(frame ports.Frame) { | |||||
| 191 | } | 192 | } | ||
| 192 | } | 193 | } | ||
| 193 | 194 | ||||
| 194 | - | func (s *reconnectToastSentFrames) find(match func(ports.Frame) bool) (ports.Frame, bool) { | 195 | + | func (s *reconnectToastSentFrames) find(match func(wire.Frame) bool) (wire.Frame, bool) { |
| 195 | s.mu.Lock() | 196 | s.mu.Lock() | ||
| 196 | defer s.mu.Unlock() | 197 | defer s.mu.Unlock() | ||
| 197 | for _, frame := range s.frames { | 198 | for _, frame := range s.frames { | ||
| @@ -199,7 +200,7 @@ func (s *reconnectToastSentFrames) find(match func(ports.Frame) bool) (ports.Fra | |||||
| 199 | return frame, true | 200 | return frame, true | ||
| 200 | } | 201 | } | ||
| 201 | } | 202 | } | ||
| 202 | - | return ports.Frame{}, false | 203 | + | return wire.Frame{}, false |
| 203 | } | 204 | } | ||
| 204 | 205 | ||||
| 205 | type reconnectToastLinkTransport struct { | 206 | type reconnectToastLinkTransport struct { | ||
| @@ -220,12 +221,12 @@ func newReconnectToastLinkTransport() *reconnectToastLinkTransport { | |||||
| 220 | } | 221 | } | ||
| 221 | } | 222 | } | ||
| 222 | 223 | ||||
| 223 | - | func (t *reconnectToastLinkTransport) Send(f ports.Frame) error { | 224 | + | func (t *reconnectToastLinkTransport) Send(f wire.Frame) error { |
| 224 | t.sends.record(f) | 225 | t.sends.record(f) | ||
| 225 | - | if f.Type != ports.MsgClientNotice { | 226 | + | if f.Type != wire.MsgClientNotice { |
| 226 | return nil | 227 | return nil | ||
| 227 | } | 228 | } | ||
| 228 | - | notice, err := ports.UnmarshalClientNotice(f.Payload) | 229 | + | notice, err := wire.UnmarshalClientNotice(f.Payload) |
| 229 | if err != nil { | 230 | if err != nil { | ||
| 230 | return err | 231 | return err | ||
| 231 | } | 232 | } | ||
| @@ -233,7 +234,7 @@ func (t *reconnectToastLinkTransport) Send(f ports.Frame) error { | |||||
| 233 | return nil | 234 | return nil | ||
| 234 | } | 235 | } | ||
| 235 | 236 | ||||
| 236 | - | func (t *reconnectToastLinkTransport) Recv() (ports.Frame, error) { | 237 | + | func (t *reconnectToastLinkTransport) Recv() (wire.Frame, error) { |
| 237 | recv := <-t.recvCh | 238 | recv := <-t.recvCh | ||
| 238 | return recv.frame, recv.err | 239 | return recv.frame, recv.err | ||
| 239 | } | 240 | } | ||
| @@ -244,18 +245,18 @@ func (t *reconnectToastLinkTransport) LinkEvents() <-chan ports.LinkEvent { retu | |||||
| 244 | 245 | ||||
| 245 | func (t *reconnectToastLinkTransport) LinkState() ports.LinkState { return t.state } | 246 | func (t *reconnectToastLinkTransport) LinkState() ports.LinkState { return t.state } | ||
| 246 | 247 | ||||
| 247 | - | func (t *reconnectToastRecordingTransport) Send(f ports.Frame) error { | 248 | + | func (t *reconnectToastRecordingTransport) Send(f wire.Frame) error { |
| 248 | t.mu.Lock() | 249 | t.mu.Lock() | ||
| 249 | defer t.mu.Unlock() | 250 | defer t.mu.Unlock() | ||
| 250 | t.sends = append(t.sends, f) | 251 | t.sends = append(t.sends, f) | ||
| 251 | return nil | 252 | return nil | ||
| 252 | } | 253 | } | ||
| 253 | 254 | ||||
| 254 | - | func (t *reconnectToastRecordingTransport) Recv() (ports.Frame, error) { | 255 | + | func (t *reconnectToastRecordingTransport) Recv() (wire.Frame, error) { |
| 255 | t.mu.Lock() | 256 | t.mu.Lock() | ||
| 256 | defer t.mu.Unlock() | 257 | defer t.mu.Unlock() | ||
| 257 | if len(t.recvs) == 0 { | 258 | if len(t.recvs) == 0 { | ||
| 258 | - | return ports.Frame{}, io.EOF | 259 | + | return wire.Frame{}, io.EOF |
| 259 | } | 260 | } | ||
| 260 | recv := t.recvs[0] | 261 | recv := t.recvs[0] | ||
| 261 | t.recvs = t.recvs[1:] | 262 | t.recvs = t.recvs[1:] | ||
| @@ -269,10 +270,10 @@ func (t *reconnectToastRecordingTransport) Close() error { | |||||
| 269 | return nil | 270 | return nil | ||
| 270 | } | 271 | } | ||
| 271 | 272 | ||||
| 272 | - | func (t *reconnectToastRecordingTransport) sentFrames() []ports.Frame { | 273 | + | func (t *reconnectToastRecordingTransport) sentFrames() []wire.Frame { |
| 273 | t.mu.Lock() | 274 | t.mu.Lock() | ||
| 274 | defer t.mu.Unlock() | 275 | defer t.mu.Unlock() | ||
| 275 | - | return append([]ports.Frame(nil), t.sends...) | 276 | + | return append([]wire.Frame(nil), t.sends...) |
| 276 | } | 277 | } | ||
| 277 | 278 | ||||
| 278 | func (t *reconnectToastRecordingTransport) wasClosed() bool { | 279 | func (t *reconnectToastRecordingTransport) wasClosed() bool { | ||
| @@ -288,9 +289,9 @@ func assertReconnectToastAttemptPublishesOnlyClearedTheme(t *testing.T, tr *reco | |||||
| 288 | t.Helper() | 289 | t.Helper() | ||
| 289 | frames := tr.sentFrames() | 290 | frames := tr.sentFrames() | ||
| 290 | require.GreaterOrEqual(t, len(frames), 2) | 291 | require.GreaterOrEqual(t, len(frames), 2) | ||
| 291 | - | require.Equal(t, ports.MsgHello, frames[0].Type) | 292 | + | require.Equal(t, wire.MsgHello, frames[0].Type) |
| 292 | - | require.Equal(t, ports.MsgTheme, frames[1].Type) | 293 | + | require.Equal(t, wire.MsgTheme, frames[1].Type) |
| 293 | - | theme, err := ports.UnmarshalTheme(frames[1].Payload) | 294 | + | theme, err := wire.UnmarshalTheme(frames[1].Payload) |
| 294 | require.NoError(t, err) | 295 | require.NoError(t, err) | ||
| 295 | require.False(t, theme.HasForeground) | 296 | require.False(t, theme.HasForeground) | ||
| 296 | require.False(t, theme.HasBackground) | 297 | require.False(t, theme.HasBackground) | ||
| @@ -302,8 +303,8 @@ func reconnectToastHelloFromSend(t *testing.T, tr *reconnectToastRecordingTransp | |||||
| 302 | t.Helper() | 303 | t.Helper() | ||
| 303 | frames := tr.sentFrames() | 304 | frames := tr.sentFrames() | ||
| 304 | require.NotEmpty(t, frames) | 305 | require.NotEmpty(t, frames) | ||
| 305 | - | require.Equal(t, ports.MsgHello, frames[0].Type) | 306 | + | require.Equal(t, wire.MsgHello, frames[0].Type) |
| 306 | - | hello, err := ports.UnmarshalHello(frames[0].Payload) | 307 | + | hello, err := wire.UnmarshalHello(frames[0].Payload) |
| 307 | require.NoError(t, err) | 308 | require.NoError(t, err) | ||
| 308 | return hello | 309 | return hello | ||
| 309 | } | 310 | } | ||
| @@ -394,7 +395,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||||
| 394 | require.Contains(t, firstToast, "┌") | 395 | require.Contains(t, firstToast, "┌") | ||
| 395 | require.Contains(t, firstToast, "probing UDP path") | 396 | require.Contains(t, firstToast, "probing UDP path") | ||
| 396 | 397 | ||||
| 397 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 398 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 398 | Epoch: 1, | 399 | Epoch: 1, | ||
| 399 | Base: 0, | 400 | Base: 0, | ||
| 400 | New: 2, | 401 | New: 2, | ||
| @@ -413,7 +414,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||||
| 413 | 414 | ||||
| 414 | beforeAwaitingReset := out.String() | 415 | beforeAwaitingReset := out.String() | ||
| 415 | beforeStatelessFlushes := flushes.Load() | 416 | beforeStatelessFlushes := flushes.Load() | ||
| 416 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 417 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 417 | Epoch: 1, | 418 | Epoch: 1, | ||
| 418 | Base: 0, | 419 | Base: 0, | ||
| 419 | New: 0, | 420 | New: 0, | ||
| @@ -425,7 +426,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||||
| 425 | }, time.Second, time.Millisecond) | 426 | }, time.Second, time.Millisecond) | ||
| 426 | 427 | ||||
| 427 | afterStateless := out.String() | 428 | afterStateless := out.String() | ||
| 428 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 429 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 429 | Epoch: 1, | 430 | Epoch: 1, | ||
| 430 | Base: 2, | 431 | Base: 2, | ||
| 431 | New: 3, | 432 | New: 3, | ||
| @@ -436,7 +437,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||||
| 436 | require.Contains(t, out.String(), "intervening incremental") | 437 | require.Contains(t, out.String(), "intervening incremental") | ||
| 437 | require.Contains(t, afterStateless[len(beforeAwaitingReset):], "stateless side effect") | 438 | require.Contains(t, afterStateless[len(beforeAwaitingReset):], "stateless side effect") | ||
| 438 | 439 | ||||
| 439 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 440 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 440 | Epoch: 2, | 441 | Epoch: 2, | ||
| 441 | Base: 0, | 442 | Base: 0, | ||
| 442 | New: 4, | 443 | New: 4, | ||
| @@ -449,7 +450,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||||
| 449 | require.NotContains(t, out.String()[len(beforeAwaitingReset):], strings.Repeat(" ", reconnectToastBoundsFor(term.size, "probing UDP path").Width)) | 450 | require.NotContains(t, out.String()[len(beforeAwaitingReset):], strings.Repeat(" ", reconnectToastBoundsFor(term.size, "probing UDP path").Width)) | ||
| 450 | 451 | ||||
| 451 | beforeIncrementFlushes := flushes.Load() | 452 | beforeIncrementFlushes := flushes.Load() | ||
| 452 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 453 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 453 | Epoch: 2, | 454 | Epoch: 2, | ||
| 454 | Base: 4, | 455 | Base: 4, | ||
| 455 | New: 5, | 456 | New: 5, | ||
| @@ -496,30 +497,30 @@ func TestActiveReconnectToastStageTransitionReconcilesBeforeRedraw(t *testing.T) | |||||
| 496 | {Epoch: 1, Base: 1, New: 2, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("first skipped increment")}, | 497 | {Epoch: 1, Base: 1, New: 2, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("first skipped increment")}, | ||
| 497 | {Epoch: 1, Base: 2, New: 3, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("second skipped increment")}, | 498 | {Epoch: 1, Base: 2, New: 3, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("second skipped increment")}, | ||
| 498 | } { | 499 | } { | ||
| 499 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(output)}} | 500 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(output)}} |
| 500 | require.Equal(t, beforeReset, out.String()) | 501 | require.Equal(t, beforeReset, out.String()) | ||
| 501 | } | 502 | } | ||
| 502 | - | requireSentFrame(t, tr.sends, "output reset request", func(frame ports.Frame) bool { | 503 | + | requireSentFrame(t, tr.sends, "output reset request", func(frame wire.Frame) bool { |
| 503 | - | return frame.Type == ports.MsgOutputResetRequest | 504 | + | return frame.Type == wire.MsgOutputResetRequest |
| 504 | }) | 505 | }) | ||
| 505 | - | _, sentAck := tr.sends.find(func(frame ports.Frame) bool { return frame.Type == ports.MsgAck }) | 506 | + | _, sentAck := tr.sends.find(func(frame wire.Frame) bool { return frame.Type == wire.MsgAck }) |
| 506 | require.False(t, sentAck, "discarded output must not be ACKed") | 507 | require.False(t, sentAck, "discarded output must not be ACKed") | ||
| 507 | 508 | ||||
| 508 | // Handoff cleanup is an ordered terminal side effect, not a replay state. | 509 | // Handoff cleanup is an ordered terminal side effect, not a replay state. | ||
| 509 | // It must cross the outstanding reset gate, flush before the control handoff, | 510 | // It must cross the outstanding reset gate, flush before the control handoff, | ||
| 510 | // and must not manufacture an independent ACK. | 511 | // and must not manufacture an independent ACK. | ||
| 511 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 512 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 512 | Epoch: 2, | 513 | Epoch: 2, | ||
| 513 | Size: domain.Size{Cols: 1, Rows: 1}, | 514 | Size: domain.Size{Cols: 1, Rows: 1}, | ||
| 514 | Data: []byte("handoff graphics cleanup"), | 515 | Data: []byte("handoff graphics cleanup"), | ||
| 515 | })}} | 516 | })}} | ||
| 516 | cleanup := requireReconnectToastOutput(t, out.completed) | 517 | cleanup := requireReconnectToastOutput(t, out.completed) | ||
| 517 | require.Contains(t, cleanup, "handoff graphics cleanup") | 518 | require.Contains(t, cleanup, "handoff graphics cleanup") | ||
| 518 | - | _, sentAck = tr.sends.find(func(frame ports.Frame) bool { return frame.Type == ports.MsgAck }) | 519 | + | _, sentAck = tr.sends.find(func(frame wire.Frame) bool { return frame.Type == wire.MsgAck }) |
| 519 | require.False(t, sentAck, "state-independent cleanup must not be ACKed") | 520 | require.False(t, sentAck, "state-independent cleanup must not be ACKed") | ||
| 520 | 521 | ||||
| 521 | beforeResetFlushes := flushes.Load() | 522 | beforeResetFlushes := flushes.Load() | ||
| 522 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 523 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 523 | Epoch: 2, | 524 | Epoch: 2, | ||
| 524 | Base: 0, | 525 | Base: 0, | ||
| 525 | New: 4, | 526 | New: 4, | ||
| @@ -534,7 +535,7 @@ func TestActiveReconnectToastStageTransitionReconcilesBeforeRedraw(t *testing.T) | |||||
| 534 | requireAckedState(t, tr.sends, 2, 4) | 535 | requireAckedState(t, tr.sends, 2, 4) | ||
| 535 | 536 | ||||
| 536 | beforeIncrementFlushes := flushes.Load() | 537 | beforeIncrementFlushes := flushes.Load() | ||
| 537 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 538 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 538 | Epoch: 2, | 539 | Epoch: 2, | ||
| 539 | Base: 4, | 540 | Base: 4, | ||
| 540 | New: 5, | 541 | New: 5, | ||
| @@ -563,7 +564,7 @@ func requireReconnectToastOutput(t *testing.T, completed <-chan string) string { | |||||
| 563 | } | 564 | } | ||
| 564 | } | 565 | } | ||
| 565 | 566 | ||||
| 566 | - | func requireSentFrame(t *testing.T, sends *reconnectToastSentFrames, description string, match func(ports.Frame) bool) ports.Frame { | 567 | + | func requireSentFrame(t *testing.T, sends *reconnectToastSentFrames, description string, match func(wire.Frame) bool) wire.Frame { |
| 567 | t.Helper() | 568 | t.Helper() | ||
| 568 | timer := time.NewTimer(time.Second) | 569 | timer := time.NewTimer(time.Second) | ||
| 569 | defer timer.Stop() | 570 | defer timer.Stop() | ||
| @@ -575,31 +576,31 @@ func requireSentFrame(t *testing.T, sends *reconnectToastSentFrames, description | |||||
| 575 | case <-sends.changed: | 576 | case <-sends.changed: | ||
| 576 | case <-timer.C: | 577 | case <-timer.C: | ||
| 577 | t.Fatalf("timed out waiting for %s", description) | 578 | t.Fatalf("timed out waiting for %s", description) | ||
| 578 | - | return ports.Frame{} | 579 | + | return wire.Frame{} |
| 579 | } | 580 | } | ||
| 580 | } | 581 | } | ||
| 581 | } | 582 | } | ||
| 582 | 583 | ||||
| 583 | func requireResize(t *testing.T, sends *reconnectToastSentFrames) protocol.Resize { | 584 | func requireResize(t *testing.T, sends *reconnectToastSentFrames) protocol.Resize { | ||
| 584 | t.Helper() | 585 | t.Helper() | ||
| 585 | - | frame := requireSentFrame(t, sends, "Resize frame", func(frame ports.Frame) bool { | 586 | + | frame := requireSentFrame(t, sends, "Resize frame", func(frame wire.Frame) bool { |
| 586 | - | return frame.Type == ports.MsgResize | 587 | + | return frame.Type == wire.MsgResize |
| 587 | }) | 588 | }) | ||
| 588 | - | resize, err := ports.UnmarshalResize(frame.Payload) | 589 | + | resize, err := wire.UnmarshalResize(frame.Payload) |
| 589 | require.NoError(t, err) | 590 | require.NoError(t, err) | ||
| 590 | return resize | 591 | return resize | ||
| 591 | } | 592 | } | ||
| 592 | 593 | ||||
| 593 | func requireAckedState(t *testing.T, sends *reconnectToastSentFrames, epoch, state uint64) { | 594 | func requireAckedState(t *testing.T, sends *reconnectToastSentFrames, epoch, state uint64) { | ||
| 594 | t.Helper() | 595 | t.Helper() | ||
| 595 | - | frame := requireSentFrame(t, sends, fmt.Sprintf("ACK for epoch %d state %d", epoch, state), func(frame ports.Frame) bool { | 596 | + | frame := requireSentFrame(t, sends, fmt.Sprintf("ACK for epoch %d state %d", epoch, state), func(frame wire.Frame) bool { |
| 596 | - | if frame.Type != ports.MsgAck { | 597 | + | if frame.Type != wire.MsgAck { |
| 597 | return false | 598 | return false | ||
| 598 | } | 599 | } | ||
| 599 | - | ack, err := ports.UnmarshalAck(frame.Payload) | 600 | + | ack, err := wire.UnmarshalAck(frame.Payload) |
| 600 | return err == nil && ack.Epoch == epoch && ack.State >= state | 601 | return err == nil && ack.Epoch == epoch && ack.State >= state | ||
| 601 | }) | 602 | }) | ||
| 602 | - | ack, err := ports.UnmarshalAck(frame.Payload) | 603 | + | ack, err := wire.UnmarshalAck(frame.Payload) |
| 603 | require.NoError(t, err) | 604 | require.NoError(t, err) | ||
| 604 | require.Equal(t, epoch, ack.Epoch) | 605 | require.Equal(t, epoch, ack.Epoch) | ||
| 605 | require.GreaterOrEqual(t, ack.State, state) | 606 | require.GreaterOrEqual(t, ack.State, state) | ||
| @@ -707,7 +708,7 @@ func TestLocalReconnectStatusFlushesDaemonOutputBeforeObservationAndAck(t *testi | |||||
| 707 | require.Eventually(t, func() bool { return flushes.Load() > beforeStatus }, time.Second, time.Millisecond) | 708 | require.Eventually(t, func() bool { return flushes.Load() > beforeStatus }, time.Second, time.Millisecond) | ||
| 708 | beforeOutput := flushes.Load() | 709 | beforeOutput := flushes.Load() | ||
| 709 | 710 | ||||
| 710 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 711 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 711 | Epoch: 1, | 712 | Epoch: 1, | ||
| 712 | Base: 0, | 713 | Base: 0, | ||
| 713 | New: 2, | 714 | New: 2, | ||
| @@ -759,7 +760,7 @@ func TestLocalReconnectStatusTransitionsDoNotRequestAuthoritativeReset(t *testin | |||||
| 759 | } | 760 | } | ||
| 760 | 761 | ||||
| 761 | const output = "local status output remains visible" | 762 | const output = "local status output remains visible" | ||
| 762 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 763 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 763 | Epoch: 1, | 764 | Epoch: 1, | ||
| 764 | Base: 0, | 765 | Base: 0, | ||
| 765 | New: 2, | 766 | New: 2, | ||
| @@ -769,7 +770,7 @@ func TestLocalReconnectStatusTransitionsDoNotRequestAuthoritativeReset(t *testin | |||||
| 769 | })}} | 770 | })}} | ||
| 770 | require.Eventually(t, func() bool { return strings.Contains(out.String(), output) }, time.Second, time.Millisecond) | 771 | require.Eventually(t, func() bool { return strings.Contains(out.String(), output) }, time.Second, time.Millisecond) | ||
| 771 | requireAckedState(t, tr.sends, 1, 2) | 772 | requireAckedState(t, tr.sends, 1, 2) | ||
| 772 | - | _, sentResize := tr.sends.find(func(frame ports.Frame) bool { return frame.Type == ports.MsgResize }) | 773 | + | _, sentResize := tr.sends.find(func(frame wire.Frame) bool { return frame.Type == wire.MsgResize }) |
| 773 | require.False(t, sentResize, "local reconnect status must not request a daemon reset") | 774 | require.False(t, sentResize, "local reconnect status must not request a daemon reset") | ||
| 774 | 775 | ||||
| 775 | tr.recvCh <- reconnectToastRecv{frame: reconnectToastDetach(protocol.ReasonDetach)} | 776 | tr.recvCh <- reconnectToastRecv{frame: reconnectToastDetach(protocol.ReasonDetach)} | ||
| @@ -827,7 +828,7 @@ func TestReconnectOverlayRedrawFailureDoesNotObserveOrAckOutput(t *testing.T) { | |||||
| 827 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | 828 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | ||
| 828 | requireReconnectToastOutput(t, out.completed) | 829 | requireReconnectToastOutput(t, out.completed) | ||
| 829 | arm() | 830 | arm() | ||
| 830 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | 831 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ |
| 831 | Epoch: 1, | 832 | Epoch: 1, | ||
| 832 | Base: 0, | 833 | Base: 0, | ||
| 833 | New: 2, | 834 | New: 2, | ||
| @@ -932,8 +933,8 @@ func newReconnectResetBlockingTransport() *reconnectResetBlockingTransport { | |||||
| 932 | } | 933 | } | ||
| 933 | } | 934 | } | ||
| 934 | 935 | ||||
| 935 | - | func (t *reconnectResetBlockingTransport) Send(frame ports.Frame) error { | 936 | + | func (t *reconnectResetBlockingTransport) Send(frame wire.Frame) error { |
| 936 | - | if frame.Type != ports.MsgResize { | 937 | + | if frame.Type != wire.MsgResize { |
| 937 | return nil | 938 | return nil | ||
| 938 | } | 939 | } | ||
| 939 | t.enterOnce.Do(func() { close(t.entered) }) | 940 | t.enterOnce.Do(func() { close(t.entered) }) | ||
| @@ -941,11 +942,11 @@ func (t *reconnectResetBlockingTransport) Send(frame ports.Frame) error { | |||||
| 941 | return io.ErrClosedPipe | 942 | return io.ErrClosedPipe | ||
| 942 | } | 943 | } | ||
| 943 | 944 | ||||
| 944 | - | func (t *reconnectResetBlockingTransport) Recv() (ports.Frame, error) { | 945 | + | func (t *reconnectResetBlockingTransport) Recv() (wire.Frame, error) { |
| 945 | t.mu.Lock() | 946 | t.mu.Lock() | ||
| 946 | defer t.mu.Unlock() | 947 | defer t.mu.Unlock() | ||
| 947 | if len(t.recvs) == 0 { | 948 | if len(t.recvs) == 0 { | ||
| 948 | - | return ports.Frame{}, io.EOF | 949 | + | return wire.Frame{}, io.EOF |
| 949 | } | 950 | } | ||
| 950 | recv := t.recvs[0] | 951 | recv := t.recvs[0] | ||
| 951 | t.recvs = t.recvs[1:] | 952 | t.recvs = t.recvs[1:] | ||
| @@ -1014,7 +1015,7 @@ func TestPreSenderReconnectResetIsBounded(t *testing.T) { | |||||
| 1014 | type reconnectToastBlockingSendTransport struct { | 1015 | type reconnectToastBlockingSendTransport struct { | ||
| 1015 | *reconnectToastLinkTransport | 1016 | *reconnectToastLinkTransport | ||
| 1016 | armed atomic.Bool | 1017 | armed atomic.Bool | ||
| 1017 | - | blockType ports.MsgType | 1018 | + | blockType wire.MsgType |
| 1018 | sendErr error | 1019 | sendErr error | ||
| 1019 | entered chan struct{} | 1020 | entered chan struct{} | ||
| 1020 | release chan struct{} | 1021 | release chan struct{} | ||
| @@ -1025,13 +1026,13 @@ type reconnectToastBlockingSendTransport struct { | |||||
| 1025 | func newReconnectToastBlockingSendTransport() *reconnectToastBlockingSendTransport { | 1026 | func newReconnectToastBlockingSendTransport() *reconnectToastBlockingSendTransport { | ||
| 1026 | return &reconnectToastBlockingSendTransport{ | 1027 | return &reconnectToastBlockingSendTransport{ | ||
| 1027 | reconnectToastLinkTransport: newReconnectToastLinkTransport(), | 1028 | reconnectToastLinkTransport: newReconnectToastLinkTransport(), | ||
| 1028 | - | blockType: ports.MsgClientNotice, | 1029 | + | blockType: wire.MsgClientNotice, |
| 1029 | entered: make(chan struct{}), | 1030 | entered: make(chan struct{}), | ||
| 1030 | release: make(chan struct{}), | 1031 | release: make(chan struct{}), | ||
| 1031 | } | 1032 | } | ||
| 1032 | } | 1033 | } | ||
| 1033 | 1034 | ||||
| 1034 | - | func (t *reconnectToastBlockingSendTransport) Send(frame ports.Frame) error { | 1035 | + | func (t *reconnectToastBlockingSendTransport) Send(frame wire.Frame) error { |
| 1035 | if err := t.reconnectToastLinkTransport.Send(frame); err != nil { | 1036 | if err := t.reconnectToastLinkTransport.Send(frame); err != nil { | ||
| 1036 | return err | 1037 | return err | ||
| 1037 | } | 1038 | } | ||
| @@ -1083,7 +1084,7 @@ func TestReconnectResetEnqueueCancellationExitsCleanly(t *testing.T) { | |||||
| 1083 | 1084 | ||||
| 1084 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | 1085 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | ||
| 1085 | requireTerminalSizeCalls(t, term, 2) | 1086 | requireTerminalSizeCalls(t, term, 2) | ||
| 1086 | - | tr.blockType = ports.MsgResize | 1087 | + | tr.blockType = wire.MsgResize |
| 1087 | tr.armed.Store(true) | 1088 | tr.armed.Store(true) | ||
| 1088 | term.resizeCh <- domain.Geometry{Size: term.size} | 1089 | term.resizeCh <- domain.Geometry{Size: term.size} | ||
| 1089 | select { | 1090 | select { | ||
| @@ -1123,7 +1124,7 @@ func TestReconnectResetCancellationPreservesQueuedSenderError(t *testing.T) { | |||||
| 1123 | 1124 | ||||
| 1124 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | 1125 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | ||
| 1125 | requireTerminalSizeCalls(t, term, 2) | 1126 | requireTerminalSizeCalls(t, term, 2) | ||
| 1126 | - | tr.blockType = ports.MsgResize | 1127 | + | tr.blockType = wire.MsgResize |
| 1127 | tr.armed.Store(true) | 1128 | tr.armed.Store(true) | ||
| 1128 | term.resizeCh <- domain.Geometry{Size: term.size} | 1129 | term.resizeCh <- domain.Geometry{Size: term.size} | ||
| 1129 | select { | 1130 | select { | ||
M internal/usecase/client/same_peer_switch_test.go +5 -5
| @@ -8,8 +8,8 @@ import ( | |||||
| 8 | "github.com/stretchr/testify/require" | 8 | "github.com/stretchr/testify/require" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | - | "github.com/bnema/vev/internal/ports" | |||
| 12 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | func TestCloseAndDialAttachTargetSkipsSamePeerSwitch(t *testing.T) { | 15 | func TestCloseAndDialAttachTargetSkipsSamePeerSwitch(t *testing.T) { | ||
| @@ -39,8 +39,8 @@ func TestCloseAndDialAttachTargetSkipsSamePeerSwitch(t *testing.T) { | |||||
| 39 | Session: "stopped", Intent: protocol.IntentAttach, ExactTarget: &exact, | 39 | Session: "stopped", Intent: protocol.IntentAttach, ExactTarget: &exact, | ||
| 40 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 40 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 41 | } | 41 | } | ||
| 42 | - | transport.recvCh <- reconnectToastRecv{frame: ports.Frame{ | 42 | + | transport.recvCh <- reconnectToastRecv{frame: wire.Frame{ |
| 43 | - | Type: ports.MsgAttachTarget, Payload: ports.MarshalAttachTarget(target), | 43 | + | Type: wire.MsgAttachTarget, Payload: wire.MarshalAttachTarget(target), |
| 44 | }} | 44 | }} | ||
| 45 | 45 | ||||
| 46 | select { | 46 | select { | ||
| @@ -50,8 +50,8 @@ func TestCloseAndDialAttachTargetSkipsSamePeerSwitch(t *testing.T) { | |||||
| 50 | case <-time.After(time.Second): | 50 | case <-time.After(time.Second): | ||
| 51 | t.Fatal("close-and-dial target did not return a handoff") | 51 | t.Fatal("close-and-dial target did not return a handoff") | ||
| 52 | } | 52 | } | ||
| 53 | - | _, sentSamePeer := transport.sends.find(func(frame ports.Frame) bool { | 53 | + | _, sentSamePeer := transport.sends.find(func(frame wire.Frame) bool { |
| 54 | - | return frame.Type == ports.MsgSamePeerSwitchRequest | 54 | + | return frame.Type == wire.MsgSamePeerSwitchRequest |
| 55 | }) | 55 | }) | ||
| 56 | require.False(t, sentSamePeer) | 56 | require.False(t, sentSamePeer) | ||
| 57 | } | 57 | } | ||
M internal/usecase/client/terminal_input_pump_test.go +23 -22
| @@ -13,6 +13,7 @@ import ( | |||||
| 13 | 13 | ||||
| 14 | "github.com/bnema/vev/internal/domain" | 14 | "github.com/bnema/vev/internal/domain" | ||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | ) | 17 | ) | ||
| 17 | 18 | ||||
| 18 | type lifecycleReader struct { | 19 | type lifecycleReader struct { | ||
| @@ -81,14 +82,14 @@ func requireSignal(t *testing.T, ch <-chan struct{}, message string) { | |||||
| 81 | } | 82 | } | ||
| 82 | } | 83 | } | ||
| 83 | 84 | ||||
| 84 | - | func requireFrame(t *testing.T, ch <-chan ports.Frame, message string) ports.Frame { | 85 | + | func requireFrame(t *testing.T, ch <-chan wire.Frame, message string) wire.Frame { |
| 85 | t.Helper() | 86 | t.Helper() | ||
| 86 | select { | 87 | select { | ||
| 87 | case frame := <-ch: | 88 | case frame := <-ch: | ||
| 88 | return frame | 89 | return frame | ||
| 89 | case <-time.After(time.Second): | 90 | case <-time.After(time.Second): | ||
| 90 | t.Fatal(message) | 91 | t.Fatal(message) | ||
| 91 | - | return ports.Frame{} | 92 | + | return wire.Frame{} |
| 92 | } | 93 | } | ||
| 93 | } | 94 | } | ||
| 94 | 95 | ||||
| @@ -181,7 +182,7 @@ func TestTerminalInputPumpCancellationHandoffPreservesQueuedBytes(t *testing.T) | |||||
| 181 | go func() { | 182 | go func() { | ||
| 182 | (&stdinPump{ | 183 | (&stdinPump{ | ||
| 183 | ctx: cancelledCtx, cancel: cancelCancelled, input: input, | 184 | ctx: cancelledCtx, cancel: cancelCancelled, input: input, | ||
| 184 | - | out: make(chan ports.Frame, 1), clock: newAttachPaletteClock(), | 185 | + | out: make(chan wire.Frame, 1), clock: newAttachPaletteClock(), |
| 185 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | 186 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | ||
| 186 | activeGeneration: &activeGeneration, | 187 | activeGeneration: &activeGeneration, | ||
| 187 | }).run() | 188 | }).run() | ||
| @@ -191,7 +192,7 @@ func TestTerminalInputPumpCancellationHandoffPreservesQueuedBytes(t *testing.T) | |||||
| 191 | 192 | ||||
| 192 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | 193 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | ||
| 193 | defer cancelReplacement() | 194 | defer cancelReplacement() | ||
| 194 | - | out := make(chan ports.Frame, len(want)) | 195 | + | out := make(chan wire.Frame, len(want)) |
| 195 | replacementDone := make(chan struct{}) | 196 | replacementDone := make(chan struct{}) | ||
| 196 | go func() { | 197 | go func() { | ||
| 197 | (&stdinPump{ | 198 | (&stdinPump{ | ||
| @@ -206,7 +207,7 @@ func TestTerminalInputPumpCancellationHandoffPreservesQueuedBytes(t *testing.T) | |||||
| 206 | var got []byte | 207 | var got []byte | ||
| 207 | for len(got) < len(want) { | 208 | for len(got) < len(want) { | ||
| 208 | frame := <-out | 209 | frame := <-out | ||
| 209 | - | input, err := ports.UnmarshalInput(frame.Payload) | 210 | + | input, err := wire.UnmarshalInput(frame.Payload) |
| 210 | require.NoError(t, err) | 211 | require.NoError(t, err) | ||
| 211 | got = append(got, input.Data...) | 212 | got = append(got, input.Data...) | ||
| 212 | } | 213 | } | ||
| @@ -229,7 +230,7 @@ func TestTerminalInputPumpCancellationAfterTakeRequeuesRawRead(t *testing.T) { | |||||
| 229 | go func() { | 230 | go func() { | ||
| 230 | (&stdinPump{ | 231 | (&stdinPump{ | ||
| 231 | ctx: ctx, cancel: cancel, input: input, consumer: consumer, | 232 | ctx: ctx, cancel: cancel, input: input, consumer: consumer, | ||
| 232 | - | out: make(chan ports.Frame, 1), clock: newAttachPaletteClock(), | 233 | + | out: make(chan wire.Frame, 1), clock: newAttachPaletteClock(), |
| 233 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | 234 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | ||
| 234 | afterInputTake: func() { | 235 | afterInputTake: func() { | ||
| 235 | close(taken) | 236 | close(taken) | ||
| @@ -263,7 +264,7 @@ func TestTerminalInputPumpCancellationPreservesStandaloneEscapeForReplacement(t | |||||
| 263 | oldDone := make(chan struct{}) | 264 | oldDone := make(chan struct{}) | ||
| 264 | go func() { | 265 | go func() { | ||
| 265 | (&stdinPump{ | 266 | (&stdinPump{ | ||
| 266 | - | ctx: oldCtx, cancel: cancelOld, input: input, out: make(chan ports.Frame, 1), | 267 | + | ctx: oldCtx, cancel: cancelOld, input: input, out: make(chan wire.Frame, 1), |
| 267 | clock: oldClock, logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | 268 | clock: oldClock, logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | ||
| 268 | activeGeneration: &activeGeneration, | 269 | activeGeneration: &activeGeneration, | ||
| 269 | }).run() | 270 | }).run() | ||
| @@ -278,7 +279,7 @@ func TestTerminalInputPumpCancellationPreservesStandaloneEscapeForReplacement(t | |||||
| 278 | newCtx, cancelNew := context.WithCancel(context.Background()) | 279 | newCtx, cancelNew := context.WithCancel(context.Background()) | ||
| 279 | defer cancelNew() | 280 | defer cancelNew() | ||
| 280 | newClock := newAttachPaletteClock() | 281 | newClock := newAttachPaletteClock() | ||
| 281 | - | out := make(chan ports.Frame, 1) | 282 | + | out := make(chan wire.Frame, 1) |
| 282 | newDone := make(chan struct{}) | 283 | newDone := make(chan struct{}) | ||
| 283 | go func() { | 284 | go func() { | ||
| 284 | (&stdinPump{ | 285 | (&stdinPump{ | ||
| @@ -291,7 +292,7 @@ func TestTerminalInputPumpCancellationPreservesStandaloneEscapeForReplacement(t | |||||
| 291 | (<-newClock.timers).fire() // marker ambiguity deadline | 292 | (<-newClock.timers).fire() // marker ambiguity deadline | ||
| 292 | (<-newClock.timers).fire() // paste coalescer's lone-ESC deadline | 293 | (<-newClock.timers).fire() // paste coalescer's lone-ESC deadline | ||
| 293 | frame := <-out | 294 | frame := <-out | ||
| 294 | - | got, err := ports.UnmarshalInput(frame.Payload) | 295 | + | got, err := wire.UnmarshalInput(frame.Payload) |
| 295 | require.NoError(t, err) | 296 | require.NoError(t, err) | ||
| 296 | require.Equal(t, []byte("\x1b"), got.Data) | 297 | require.Equal(t, []byte("\x1b"), got.Data) | ||
| 297 | 298 | ||||
| @@ -306,7 +307,7 @@ func TestTerminalInputPumpCancellationAfterInputBeforeOSCPreservesOnlyUndelivere | |||||
| 306 | ctx, cancel := context.WithCancel(context.Background()) | 307 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 307 | delivered := make(chan struct{}) | 308 | delivered := make(chan struct{}) | ||
| 308 | done := make(chan struct{}) | 309 | done := make(chan struct{}) | ||
| 309 | - | out := make(chan ports.Frame, 1) | 310 | + | out := make(chan wire.Frame, 1) |
| 310 | go func() { | 311 | go func() { | ||
| 311 | (&stdinPump{ | 312 | (&stdinPump{ | ||
| 312 | ctx: ctx, cancel: cancel, input: input, out: out, clock: newAttachPaletteClock(), | 313 | ctx: ctx, cancel: cancel, input: input, out: out, clock: newAttachPaletteClock(), | ||
| @@ -320,14 +321,14 @@ func TestTerminalInputPumpCancellationAfterInputBeforeOSCPreservesOnlyUndelivere | |||||
| 320 | close(done) | 321 | close(done) | ||
| 321 | }() | 322 | }() | ||
| 322 | frame := requireFrame(t, out, "timed out waiting for delivered input prefix") | 323 | frame := requireFrame(t, out, "timed out waiting for delivered input prefix") | ||
| 323 | - | got, err := ports.UnmarshalInput(frame.Payload) | 324 | + | got, err := wire.UnmarshalInput(frame.Payload) |
| 324 | require.NoError(t, err) | 325 | require.NoError(t, err) | ||
| 325 | require.Equal(t, []byte("x"), got.Data) | 326 | require.Equal(t, []byte("x"), got.Data) | ||
| 326 | requireSignal(t, delivered, "timed out waiting for cancellation after input delivery") | 327 | requireSignal(t, delivered, "timed out waiting for cancellation after input delivery") | ||
| 327 | requireSignal(t, done, "timed out waiting for cancelled stdin pump") | 328 | requireSignal(t, done, "timed out waiting for cancelled stdin pump") | ||
| 328 | 329 | ||||
| 329 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | 330 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | ||
| 330 | - | replacementOut := make(chan ports.Frame, 1) | 331 | + | replacementOut := make(chan wire.Frame, 1) |
| 331 | replacementDone := make(chan struct{}) | 332 | replacementDone := make(chan struct{}) | ||
| 332 | go func() { | 333 | go func() { | ||
| 333 | (&stdinPump{ | 334 | (&stdinPump{ | ||
| @@ -339,7 +340,7 @@ func TestTerminalInputPumpCancellationAfterInputBeforeOSCPreservesOnlyUndelivere | |||||
| 339 | close(replacementDone) | 340 | close(replacementDone) | ||
| 340 | }() | 341 | }() | ||
| 341 | frame = requireFrame(t, replacementOut, "timed out waiting for undelivered input suffix") | 342 | frame = requireFrame(t, replacementOut, "timed out waiting for undelivered input suffix") | ||
| 342 | - | got, err = ports.UnmarshalInput(frame.Payload) | 343 | + | got, err = wire.UnmarshalInput(frame.Payload) |
| 343 | require.NoError(t, err) | 344 | require.NoError(t, err) | ||
| 344 | require.Equal(t, []byte("y"), got.Data, "replacement must receive only the undelivered ordinary suffix") | 345 | require.Equal(t, []byte("y"), got.Data, "replacement must receive only the undelivered ordinary suffix") | ||
| 345 | 346 | ||||
| @@ -354,7 +355,7 @@ func TestTerminalInputPumpCancellationPreservesCoalescerHeldSuffix(t *testing.T) | |||||
| 354 | input.enqueue(terminalReadResult{data: raw}, 1) | 355 | input.enqueue(terminalReadResult{data: raw}, 1) | ||
| 355 | var activeGeneration atomic.Uint64 | 356 | var activeGeneration atomic.Uint64 | ||
| 356 | ctx, cancel := context.WithCancel(context.Background()) | 357 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 357 | - | out := make(chan ports.Frame, 1) | 358 | + | out := make(chan wire.Frame, 1) |
| 358 | done := make(chan struct{}) | 359 | done := make(chan struct{}) | ||
| 359 | go func() { | 360 | go func() { | ||
| 360 | (&stdinPump{ | 361 | (&stdinPump{ | ||
| @@ -366,14 +367,14 @@ func TestTerminalInputPumpCancellationPreservesCoalescerHeldSuffix(t *testing.T) | |||||
| 366 | close(done) | 367 | close(done) | ||
| 367 | }() | 368 | }() | ||
| 368 | frame := requireFrame(t, out, "timed out waiting for delivered input prefix") | 369 | frame := requireFrame(t, out, "timed out waiting for delivered input prefix") | ||
| 369 | - | got, err := ports.UnmarshalInput(frame.Payload) | 370 | + | got, err := wire.UnmarshalInput(frame.Payload) |
| 370 | require.NoError(t, err) | 371 | require.NoError(t, err) | ||
| 371 | require.Equal(t, []byte("x"), got.Data) | 372 | require.Equal(t, []byte("x"), got.Data) | ||
| 372 | requireSignal(t, done, "timed out waiting for cancelled stdin pump") | 373 | requireSignal(t, done, "timed out waiting for cancelled stdin pump") | ||
| 373 | 374 | ||||
| 374 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | 375 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | ||
| 375 | replacementClock := newAttachPaletteClock() | 376 | replacementClock := newAttachPaletteClock() | ||
| 376 | - | replacementOut := make(chan ports.Frame, 1) | 377 | + | replacementOut := make(chan wire.Frame, 1) |
| 377 | replacementDone := make(chan struct{}) | 378 | replacementDone := make(chan struct{}) | ||
| 378 | go func() { | 379 | go func() { | ||
| 379 | (&stdinPump{ | 380 | (&stdinPump{ | ||
| @@ -386,7 +387,7 @@ func TestTerminalInputPumpCancellationPreservesCoalescerHeldSuffix(t *testing.T) | |||||
| 386 | }() | 387 | }() | ||
| 387 | requireTimer(t, replacementClock.timers, "timed out waiting for paste-prefix ambiguity timer").fire() | 388 | requireTimer(t, replacementClock.timers, "timed out waiting for paste-prefix ambiguity timer").fire() | ||
| 388 | frame = requireFrame(t, replacementOut, "timed out waiting for coalescer-held suffix") | 389 | frame = requireFrame(t, replacementOut, "timed out waiting for coalescer-held suffix") | ||
| 389 | - | got, err = ports.UnmarshalInput(frame.Payload) | 390 | + | got, err = wire.UnmarshalInput(frame.Payload) |
| 390 | require.NoError(t, err) | 391 | require.NoError(t, err) | ||
| 391 | require.Equal(t, held, got.Data, "replacement must receive the coalescer-held suffix exactly once") | 392 | require.Equal(t, held, got.Data, "replacement must receive the coalescer-held suffix exactly once") | ||
| 392 | 393 | ||||
| @@ -424,7 +425,7 @@ func TestTerminalInputPumpCancellationAfterDeliveredCallbackDoesNotReplay(t *tes | |||||
| 424 | ctx, cancel := context.WithCancel(context.Background()) | 425 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 425 | delivered := make(chan struct{}) | 426 | delivered := make(chan struct{}) | ||
| 426 | done := make(chan struct{}) | 427 | done := make(chan struct{}) | ||
| 427 | - | out := make(chan ports.Frame, 1) | 428 | + | out := make(chan wire.Frame, 1) |
| 428 | go func() { | 429 | go func() { | ||
| 429 | (&stdinPump{ | 430 | (&stdinPump{ | ||
| 430 | ctx: ctx, cancel: cancel, input: input, out: out, clock: newAttachPaletteClock(), | 431 | ctx: ctx, cancel: cancel, input: input, out: out, clock: newAttachPaletteClock(), | ||
| @@ -438,7 +439,7 @@ func TestTerminalInputPumpCancellationAfterDeliveredCallbackDoesNotReplay(t *tes | |||||
| 438 | close(done) | 439 | close(done) | ||
| 439 | }() | 440 | }() | ||
| 440 | frame := <-out | 441 | frame := <-out | ||
| 441 | - | got, err := ports.UnmarshalInput(frame.Payload) | 442 | + | got, err := wire.UnmarshalInput(frame.Payload) |
| 442 | require.NoError(t, err) | 443 | require.NoError(t, err) | ||
| 443 | require.Equal(t, []byte("x"), got.Data) | 444 | require.Equal(t, []byte("x"), got.Data) | ||
| 444 | <-delivered | 445 | <-delivered | ||
| @@ -463,7 +464,7 @@ func TestTerminalInputPumpReusesOneReaderAcrossCancelledAttempts(t *testing.T) { | |||||
| 463 | go func() { | 464 | go func() { | ||
| 464 | (&stdinPump{ | 465 | (&stdinPump{ | ||
| 465 | ctx: firstCtx, cancel: cancelFirst, input: input, | 466 | ctx: firstCtx, cancel: cancelFirst, input: input, | ||
| 466 | - | out: make(chan ports.Frame), clock: newAttachPaletteClock(), | 467 | + | out: make(chan wire.Frame), clock: newAttachPaletteClock(), |
| 467 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | 468 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | ||
| 468 | activeGeneration: &activeGeneration, | 469 | activeGeneration: &activeGeneration, | ||
| 469 | }).run() | 470 | }).run() | ||
| @@ -474,7 +475,7 @@ func TestTerminalInputPumpReusesOneReaderAcrossCancelledAttempts(t *testing.T) { | |||||
| 474 | 475 | ||||
| 475 | secondCtx, cancelSecond := context.WithCancel(context.Background()) | 476 | secondCtx, cancelSecond := context.WithCancel(context.Background()) | ||
| 476 | defer cancelSecond() | 477 | defer cancelSecond() | ||
| 477 | - | out := make(chan ports.Frame, 1) | 478 | + | out := make(chan wire.Frame, 1) |
| 478 | secondDone := make(chan struct{}) | 479 | secondDone := make(chan struct{}) | ||
| 479 | go func() { | 480 | go func() { | ||
| 480 | (&stdinPump{ | 481 | (&stdinPump{ | ||
| @@ -488,7 +489,7 @@ func TestTerminalInputPumpReusesOneReaderAcrossCancelledAttempts(t *testing.T) { | |||||
| 488 | 489 | ||||
| 489 | reader.chunks <- []byte("x") | 490 | reader.chunks <- []byte("x") | ||
| 490 | frame := <-out | 491 | frame := <-out | ||
| 491 | - | got, err := ports.UnmarshalInput(frame.Payload) | 492 | + | got, err := wire.UnmarshalInput(frame.Payload) |
| 492 | require.NoError(t, err) | 493 | require.NoError(t, err) | ||
| 493 | require.Equal(t, []byte("x"), got.Data) | 494 | require.Equal(t, []byte("x"), got.Data) | ||
| 494 | require.Equal(t, 1, reader.maxActive(), "cancelled attempts must not leave competing reads") | 495 | require.Equal(t, 1, reader.maxActive(), "cancelled attempts must not leave competing reads") | ||
M internal/usecase/client/transport_observability_test.go +12 -11
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 17 | "github.com/bnema/vev/internal/protocol" | 17 | "github.com/bnema/vev/internal/protocol" | ||
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 18 | "github.com/bnema/vev/internal/usecase/client" | 19 | "github.com/bnema/vev/internal/usecase/client" | ||
| 19 | ) | 20 | ) | ||
| 20 | 21 | ||||
| @@ -46,12 +47,12 @@ func TestBlockingRuntimeObserverDoesNotDelayTerminalFlushOrACK(t *testing.T) { | |||||
| 46 | defer reporter.Close() | 47 | defer reporter.Close() | ||
| 47 | acked := make(chan struct{}) | 48 | acked := make(chan struct{}) | ||
| 48 | transport := portsmocks.NewMockTransport(t) | 49 | transport := portsmocks.NewMockTransport(t) | ||
| 49 | - | transport.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 50 | + | transport.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 50 | - | transport.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 51 | + | transport.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 51 | - | transport.EXPECT().Send(isType(ports.MsgAck)).Run(func(ports.Frame) { close(acked) }).Return(nil).Once() | 52 | + | transport.EXPECT().Send(isType(wire.MsgAck)).Run(func(wire.Frame) { close(acked) }).Return(nil).Once() |
| 52 | unblock := scriptRecv(transport, | 53 | unblock := scriptRecv(transport, | ||
| 53 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 54 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 54 | - | recvItem{f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("flush-before-observe"), New: 3}))}, | 55 | + | recvItem{f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("flush-before-observe"), New: 3}))}, |
| 55 | ) | 56 | ) | ||
| 56 | defer unblock() | 57 | defer unblock() | ||
| 57 | transport.EXPECT().Close().Return(nil).Once() | 58 | transport.EXPECT().Close().Return(nil).Once() | ||
| @@ -87,15 +88,15 @@ func TestTerminalFlushBoundaryTransportObservability(t *testing.T) { | |||||
| 87 | reporter := ports.NewSerializedRuntimeObserver(observer, 64) | 88 | reporter := ports.NewSerializedRuntimeObserver(observer, 64) | ||
| 88 | defer reporter.Close() | 89 | defer reporter.Close() | ||
| 89 | transport := portsmocks.NewMockTransport(t) | 90 | transport := portsmocks.NewMockTransport(t) | ||
| 90 | - | transport.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | 91 | + | transport.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() |
| 91 | - | transport.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | 92 | + | transport.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() |
| 92 | unblock := scriptRecv(transport, | 93 | unblock := scriptRecv(transport, | ||
| 93 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | 94 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, |
| 94 | - | recvItem{f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("unchanged-by-observer"), New: 3}))}, | 95 | + | recvItem{f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("unchanged-by-observer"), New: 3}))}, |
| 95 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | 96 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, |
| 96 | ) | 97 | ) | ||
| 97 | defer unblock() | 98 | defer unblock() | ||
| 98 | - | transport.EXPECT().Send(isType(ports.MsgAck)).Return(nil).Maybe() | 99 | + | transport.EXPECT().Send(isType(wire.MsgAck)).Return(nil).Maybe() |
| 99 | transport.EXPECT().Close().Return(nil).Once() | 100 | transport.EXPECT().Close().Return(nil).Once() | ||
| 100 | 101 | ||||
| 101 | err := runTestClient(context.Background(), testDependencies(transportDialer{transport: transport}, term, realClock{}, nil, reporter), client.AttachRequest{Intent: protocol.IntentEphemeral}) | 102 | err := runTestClient(context.Background(), testDependencies(transportDialer{transport: transport}, term, realClock{}, nil, reporter), client.AttachRequest{Intent: protocol.IntentEphemeral}) | ||
M internal/usecase/client/wire_external_test_helpers_test.go +2 -2
| @@ -1,12 +1,12 @@ | |||||
| 1 | package client_test | 1 | package client_test | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | - | "github.com/bnema/vev/internal/ports" | |||
| 5 | "github.com/bnema/vev/internal/protocol" | 4 | "github.com/bnema/vev/internal/protocol" | ||
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 6 | ) | 6 | ) | ||
| 7 | 7 | ||||
| 8 | func mustMarshalOutput(m protocol.Output) []byte { | 8 | func mustMarshalOutput(m protocol.Output) []byte { | ||
| 9 | - | payload, err := ports.MarshalOutput(m) | 9 | + | payload, err := wire.MarshalOutput(m) |
| 10 | if err != nil { | 10 | if err != nil { | ||
| 11 | panic(err) | 11 | panic(err) | ||
| 12 | } | 12 | } | ||
M internal/usecase/client/wire_test_helpers_test.go +2 -2
| @@ -1,12 +1,12 @@ | |||||
| 1 | package client | 1 | package client | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | - | "github.com/bnema/vev/internal/ports" | |||
| 5 | "github.com/bnema/vev/internal/protocol" | 4 | "github.com/bnema/vev/internal/protocol" | ||
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 6 | ) | 6 | ) | ||
| 7 | 7 | ||||
| 8 | func mustMarshalOutput(m protocol.Output) []byte { | 8 | func mustMarshalOutput(m protocol.Output) []byte { | ||
| 9 | - | payload, err := ports.MarshalOutput(m) | 9 | + | payload, err := wire.MarshalOutput(m) |
| 10 | if err != nil { | 10 | if err != nil { | ||
| 11 | panic(err) | 11 | panic(err) | ||
| 12 | } | 12 | } | ||
M internal/usecase/daemon/attachment_effect_gate.go +2 -1
| @@ -6,6 +6,7 @@ import ( | |||||
| 6 | "sync/atomic" | 6 | "sync/atomic" | ||
| 7 | 7 | ||||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 9 | ) | 10 | ) | ||
| 10 | 11 | ||||
| 11 | type attachmentEffectPhase uint8 | 12 | type attachmentEffectPhase uint8 | ||
| @@ -188,7 +189,7 @@ func (t *attachmentEffect) endTransportSend() { | |||||
| 188 | g.mu.Unlock() | 189 | g.mu.Unlock() | ||
| 189 | } | 190 | } | ||
| 190 | 191 | ||||
| 191 | - | func (t *attachmentEffect) sendControl(frame ports.Frame) error { | 192 | + | func (t *attachmentEffect) sendControl(frame wire.Frame) error { |
| 192 | if !t.current() || t.ac == nil || t.transport.transport == nil { | 193 | if !t.current() || t.ac == nil || t.transport.transport == nil { | ||
| 193 | return errAttachmentTransition | 194 | return errAttachmentTransition | ||
| 194 | } | 195 | } | ||
M internal/usecase/daemon/attachment_effect_gate_test.go +17 -17
| @@ -11,8 +11,8 @@ import ( | |||||
| 11 | 11 | ||||
| 12 | renderer "github.com/bnema/vev-vt" | 12 | renderer "github.com/bnema/vev-vt" | ||
| 13 | "github.com/bnema/vev/internal/domain" | 13 | "github.com/bnema/vev/internal/domain" | ||
| 14 | - | "github.com/bnema/vev/internal/ports" | |||
| 15 | "github.com/bnema/vev/internal/protocol" | 14 | "github.com/bnema/vev/internal/protocol" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | "github.com/bnema/vev/internal/usecase/keys" | 16 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 17 | ) | 17 | ) | ||
| 18 | 18 | ||||
| @@ -44,14 +44,14 @@ func newBlockedRenderReplacementTransport(d *Daemon, sess *session) *blockedRend | |||||
| 44 | } | 44 | } | ||
| 45 | } | 45 | } | ||
| 46 | 46 | ||||
| 47 | - | func (t *blockedRenderReplacementTransport) Send(ports.Frame) error { | 47 | + | func (t *blockedRenderReplacementTransport) Send(wire.Frame) error { |
| 48 | t.sendOnce.Do(func() { close(t.sendEntered) }) | 48 | t.sendOnce.Do(func() { close(t.sendEntered) }) | ||
| 49 | <-t.closed | 49 | <-t.closed | ||
| 50 | return errors.New("transport closed") | 50 | return errors.New("transport closed") | ||
| 51 | } | 51 | } | ||
| 52 | 52 | ||||
| 53 | - | func (*blockedRenderReplacementTransport) Recv() (ports.Frame, error) { | 53 | + | func (*blockedRenderReplacementTransport) Recv() (wire.Frame, error) { |
| 54 | - | return ports.Frame{}, io.EOF | 54 | + | return wire.Frame{}, io.EOF |
| 55 | } | 55 | } | ||
| 56 | 56 | ||||
| 57 | func (t *blockedRenderReplacementTransport) Close() error { | 57 | func (t *blockedRenderReplacementTransport) Close() error { | ||
| @@ -97,13 +97,13 @@ func newTeardownBlockingTransport() *teardownBlockingTransport { | |||||
| 97 | return &teardownBlockingTransport{sendEntered: make(chan struct{}), closed: make(chan struct{})} | 97 | return &teardownBlockingTransport{sendEntered: make(chan struct{}), closed: make(chan struct{})} | ||
| 98 | } | 98 | } | ||
| 99 | 99 | ||||
| 100 | - | func (t *teardownBlockingTransport) Send(ports.Frame) error { | 100 | + | func (t *teardownBlockingTransport) Send(wire.Frame) error { |
| 101 | t.sendOnce.Do(func() { close(t.sendEntered) }) | 101 | t.sendOnce.Do(func() { close(t.sendEntered) }) | ||
| 102 | <-t.closed | 102 | <-t.closed | ||
| 103 | return errors.New("transport closed") | 103 | return errors.New("transport closed") | ||
| 104 | } | 104 | } | ||
| 105 | 105 | ||||
| 106 | - | func (*teardownBlockingTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 106 | + | func (*teardownBlockingTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 107 | 107 | ||||
| 108 | func (t *teardownBlockingTransport) Close() error { | 108 | func (t *teardownBlockingTransport) Close() error { | ||
| 109 | t.closeOnce.Do(func() { close(t.closed) }) | 109 | t.closeOnce.Do(func() { close(t.closed) }) | ||
| @@ -568,7 +568,7 @@ func TestAttachmentEffectGateAdmittedActiveEffectsFinishBeforeReplacement(t *tes | |||||
| 568 | tests := []struct { | 568 | tests := []struct { | ||
| 569 | name string | 569 | name string | ||
| 570 | setup func(*Daemon, *session, *attachedClient, *transactionalResizePTY) | 570 | setup func(*Daemon, *session, *attachedClient, *transactionalResizePTY) | ||
| 571 | - | frame ports.Frame | 571 | + | frame wire.Frame |
| 572 | assert func(*testing.T, *attachedClient, *transactionalResizePTY) | 572 | assert func(*testing.T, *attachedClient, *transactionalResizePTY) | ||
| 573 | }{ | 573 | }{ | ||
| 574 | { | 574 | { | ||
| @@ -612,7 +612,7 @@ func TestAttachmentEffectGateAdmittedActiveEffectsFinishBeforeReplacement(t *tes | |||||
| 612 | }, | 612 | }, | ||
| 613 | { | 613 | { | ||
| 614 | name: "theme", | 614 | name: "theme", | ||
| 615 | - | frame: ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(protocol.Theme{ | 615 | + | frame: wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(protocol.Theme{ |
| 616 | HasForeground: true, Foreground: renderer.RGB{R: 1, G: 2, B: 3}, | 616 | HasForeground: true, Foreground: renderer.RGB{R: 1, G: 2, B: 3}, | ||
| 617 | HasBackground: true, Background: renderer.RGB{R: 4, G: 5, B: 6}, | 617 | HasBackground: true, Background: renderer.RGB{R: 4, G: 5, B: 6}, | ||
| 618 | })}, | 618 | })}, | ||
| @@ -625,7 +625,7 @@ func TestAttachmentEffectGateAdmittedActiveEffectsFinishBeforeReplacement(t *tes | |||||
| 625 | setup: func(_ *Daemon, _ *session, ac *attachedClient, _ *transactionalResizePTY) { | 625 | setup: func(_ *Daemon, _ *session, ac *attachedClient, _ *transactionalResizePTY) { | ||
| 626 | ac.output.next = 3 | 626 | ac.output.next = 3 | ||
| 627 | }, | 627 | }, | ||
| 628 | - | frame: ports.Frame{Type: ports.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 1})}, | 628 | + | frame: wire.Frame{Type: wire.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 1})}, |
| 629 | assert: func(t *testing.T, ac *attachedClient, _ *transactionalResizePTY) { | 629 | assert: func(t *testing.T, ac *attachedClient, _ *transactionalResizePTY) { | ||
| 630 | ac.sendMu.Lock() | 630 | ac.sendMu.Lock() | ||
| 631 | defer ac.sendMu.Unlock() | 631 | defer ac.sendMu.Unlock() | ||
| @@ -697,10 +697,10 @@ func TestAttachedRouteSnapshotIsAcceptedAsAnAttachmentValue(t *testing.T) { | |||||
| 697 | Home: activeRef, | 697 | Home: activeRef, | ||
| 698 | Entries: []protocol.RecentRouteEntry{testRouteEntry(7, 3, "previous", 7, protocol.RouteKindLocal)}, | 698 | Entries: []protocol.RecentRouteEntry{testRouteEntry(7, 3, "previous", 7, protocol.RouteKindLocal)}, | ||
| 699 | } | 699 | } | ||
| 700 | - | payload, err := ports.MarshalRecentRouteSnapshot(snapshot) | 700 | + | payload, err := wire.MarshalRecentRouteSnapshot(snapshot) |
| 701 | require.NoError(t, err) | 701 | require.NoError(t, err) | ||
| 702 | 702 | ||||
| 703 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: payload})) | 703 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: payload})) |
| 704 | require.Equal(t, snapshot, ac.routeSnapshotCopy()) | 704 | require.Equal(t, snapshot, ac.routeSnapshotCopy()) | ||
| 705 | } | 705 | } | ||
| 706 | 706 | ||||
| @@ -726,31 +726,31 @@ func TestAttachedNavigationCommandSendsResultAfterLocalTransition(t *testing.T) | |||||
| 726 | token := source.captureAttachmentCapability(ac, transport) | 726 | token := source.captureAttachmentCapability(ac, transport) | ||
| 727 | token.lease = rc.attachmentLease(ac) | 727 | token.lease = rc.attachmentLease(ac) | ||
| 728 | ac.installTestAttachmentCapability(token) | 728 | ac.installTestAttachmentCapability(token) | ||
| 729 | - | payload, err := ports.MarshalCommandRequest(protocol.CommandRequest{ | 729 | + | payload, err := wire.MarshalCommandRequest(protocol.CommandRequest{ |
| 730 | Version: protocol.Version, RequestID: 1, Slug: "back-session", Attached: true, | 730 | Version: protocol.Version, RequestID: 1, Slug: "back-session", Attached: true, | ||
| 731 | }) | 731 | }) | ||
| 732 | require.NoError(t, err) | 732 | require.NoError(t, err) | ||
| 733 | 733 | ||||
| 734 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgCommand, Payload: payload})) | 734 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgCommand, Payload: payload})) |
| 735 | require.Same(t, source, ac.currentAttachmentSession()) | 735 | require.Same(t, source, ac.currentAttachmentSession()) | ||
| 736 | frames := transport.Sends() | 736 | frames := transport.Sends() | ||
| 737 | require.NotEmpty(t, frames) | 737 | require.NotEmpty(t, frames) | ||
| 738 | var result protocol.CommandResult | 738 | var result protocol.CommandResult | ||
| 739 | for _, frame := range frames { | 739 | for _, frame := range frames { | ||
| 740 | - | if frame.Type != ports.MsgCommandResult { | 740 | + | if frame.Type != wire.MsgCommandResult { |
| 741 | continue | 741 | continue | ||
| 742 | } | 742 | } | ||
| 743 | - | result, err = ports.UnmarshalCommandResult(frame.Payload) | 743 | + | result, err = wire.UnmarshalCommandResult(frame.Payload) |
| 744 | require.NoError(t, err) | 744 | require.NoError(t, err) | ||
| 745 | break | 745 | break | ||
| 746 | } | 746 | } | ||
| 747 | require.True(t, result.OK, result.Text) | 747 | require.True(t, result.OK, result.Text) | ||
| 748 | var action protocol.RouteNavigationAction | 748 | var action protocol.RouteNavigationAction | ||
| 749 | for _, frame := range frames { | 749 | for _, frame := range frames { | ||
| 750 | - | if frame.Type != ports.MsgNavigateRecentRoute { | 750 | + | if frame.Type != wire.MsgNavigateRecentRoute { |
| 751 | continue | 751 | continue | ||
| 752 | } | 752 | } | ||
| 753 | - | action, err = ports.UnmarshalRouteNavigationAction(frame.Payload) | 753 | + | action, err = wire.UnmarshalRouteNavigationAction(frame.Payload) |
| 754 | require.NoError(t, err) | 754 | require.NoError(t, err) | ||
| 755 | } | 755 | } | ||
| 756 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 2, Key: 1, Generation: 1}, action) | 756 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 2, Key: 1, Generation: 1}, action) | ||
M internal/usecase/daemon/attachment_output.go +10 -9
| @@ -10,6 +10,7 @@ import ( | |||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | "github.com/bnema/vev/internal/ports" | 11 | "github.com/bnema/vev/internal/ports" | ||
| 12 | "github.com/bnema/vev/internal/protocol" | 12 | "github.com/bnema/vev/internal/protocol" | ||
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | ) | 14 | ) | ||
| 14 | 15 | ||||
| 15 | // attachmentOutput owns the terminal-output dependency chain and emitted | 16 | // attachmentOutput owns the terminal-output dependency chain and emitted | ||
| @@ -153,13 +154,13 @@ func (o *attachmentOutput) prepareFrame(d *Daemon, state *capturedRenderState, f | |||||
| 153 | return &preparedAttachmentOutput{output: o, ansi: ansi, graphics: preparedGraphics, cursor: cursor, data: data}, nil | 154 | return &preparedAttachmentOutput{output: o, ansi: ansi, graphics: preparedGraphics, cursor: cursor, data: data}, nil | ||
| 154 | } | 155 | } | ||
| 155 | 156 | ||||
| 156 | - | func (p *preparedAttachmentOutput) send(echoAck uint64, send func(ports.Frame) error) error { | 157 | + | func (p *preparedAttachmentOutput) send(echoAck uint64, send func(wire.Frame) error) error { |
| 157 | if p == nil || p.ansi == nil { | 158 | if p == nil || p.ansi == nil { | ||
| 158 | return nil | 159 | return nil | ||
| 159 | } | 160 | } | ||
| 160 | sendFrame := send | 161 | sendFrame := send | ||
| 161 | if p.graphics != nil { | 162 | if p.graphics != nil { | ||
| 162 | - | sendFrame = func(frame ports.Frame) error { | 163 | + | sendFrame = func(frame wire.Frame) error { |
| 163 | p.graphics.markSendAttempted() | 164 | p.graphics.markSendAttempted() | ||
| 164 | return send(frame) | 165 | return send(frame) | ||
| 165 | } | 166 | } | ||
| @@ -285,7 +286,7 @@ func (s *attachmentOutput) prepare(frame renderer.Frame, damage []renderer.Damag | |||||
| 285 | }, nil | 286 | }, nil | ||
| 286 | } | 287 | } | ||
| 287 | 288 | ||||
| 288 | - | func (p *preparedOutput) send(data []byte, echoAck uint64, send func(ports.Frame) error) error { | 289 | + | func (p *preparedOutput) send(data []byte, echoAck uint64, send func(wire.Frame) error) error { |
| 289 | if p == nil || p.stream == nil || p.attempted { | 290 | if p == nil || p.stream == nil || p.attempted { | ||
| 290 | return nil | 291 | return nil | ||
| 291 | } | 292 | } | ||
| @@ -379,21 +380,21 @@ func (p *preparedOutput) currentLocked() bool { | |||||
| 379 | (p.stream.attachment == nil || p.stream.attachment.lifecycle.generationValue() == p.connectionGeneration) | 380 | (p.stream.attachment == nil || p.stream.attachment.lifecycle.generationValue() == p.connectionGeneration) | ||
| 380 | } | 381 | } | ||
| 381 | 382 | ||||
| 382 | - | func marshalOutputState(data []byte, epoch, base, next, echoAck, viewRevision uint64, size domain.Size, full bool) (ports.Frame, error) { | 383 | + | func marshalOutputState(data []byte, epoch, base, next, echoAck, viewRevision uint64, size domain.Size, full bool) (wire.Frame, error) { |
| 383 | - | payload, err := ports.MarshalOutput(protocol.Output{ | 384 | + | payload, err := wire.MarshalOutput(protocol.Output{ |
| 384 | Epoch: epoch, Base: base, New: next, Echo: echoAck, ViewRevision: viewRevision, | 385 | Epoch: epoch, Base: base, New: next, Echo: echoAck, ViewRevision: viewRevision, | ||
| 385 | Size: size, Full: full, Data: data, | 386 | Size: size, Full: full, Data: data, | ||
| 386 | }) | 387 | }) | ||
| 387 | if err != nil { | 388 | if err != nil { | ||
| 388 | - | return ports.Frame{}, err | 389 | + | return wire.Frame{}, err |
| 389 | } | 390 | } | ||
| 390 | - | return ports.Frame{Type: ports.MsgOutput, Payload: payload}, nil | 391 | + | return wire.Frame{Type: wire.MsgOutput, Payload: payload}, nil |
| 391 | } | 392 | } | ||
| 392 | 393 | ||||
| 393 | // sideEffect builds an output frame without advancing the state stream. When | 394 | // sideEffect builds an output frame without advancing the state stream. When | ||
| 394 | // an attachment is present, callers must hold its sendMu; attachment-bound | 395 | // an attachment is present, callers must hold its sendMu; attachment-bound | ||
| 395 | // sends use sideEffectLocked after validating their transport incarnation. | 396 | // sends use sideEffectLocked after validating their transport incarnation. | ||
| 396 | - | func (s *attachmentOutput) sideEffect(data []byte, echoAck uint64) (ports.Frame, error) { | 397 | + | func (s *attachmentOutput) sideEffect(data []byte, echoAck uint64) (wire.Frame, error) { |
| 397 | s.lockView() | 398 | s.lockView() | ||
| 398 | defer s.unlockView() | 399 | defer s.unlockView() | ||
| 399 | return s.sideEffectLocked(data, echoAck) | 400 | return s.sideEffectLocked(data, echoAck) | ||
| @@ -402,7 +403,7 @@ func (s *attachmentOutput) sideEffect(data []byte, echoAck uint64) (ports.Frame, | |||||
| 402 | // sideEffectLocked requires the attachment view lock for both frame creation | 403 | // sideEffectLocked requires the attachment view lock for both frame creation | ||
| 403 | // and transport emission. Keeping that lock across the send prevents a view | 404 | // and transport emission. Keeping that lock across the send prevents a view | ||
| 404 | // publication from overtaking a frame that was fenced just before it. | 405 | // publication from overtaking a frame that was fenced just before it. | ||
| 405 | - | func (s *attachmentOutput) sideEffectLocked(data []byte, echoAck uint64) (ports.Frame, error) { | 406 | + | func (s *attachmentOutput) sideEffectLocked(data []byte, echoAck uint64) (wire.Frame, error) { |
| 406 | _, epoch, viewRevision := s.fenceLocked() | 407 | _, epoch, viewRevision := s.fenceLocked() | ||
| 407 | size := domain.Size{Cols: 1, Rows: 1} | 408 | size := domain.Size{Cols: 1, Rows: 1} | ||
| 408 | if s != nil && s.attachment != nil { | 409 | if s != nil && s.attachment != nil { | ||
M internal/usecase/daemon/attachment_output_test.go +32 -31
| @@ -11,6 +11,7 @@ import ( | |||||
| 11 | "github.com/bnema/vev/internal/domain" | 11 | "github.com/bnema/vev/internal/domain" | ||
| 12 | "github.com/bnema/vev/internal/ports" | 12 | "github.com/bnema/vev/internal/ports" | ||
| 13 | "github.com/bnema/vev/internal/protocol" | 13 | "github.com/bnema/vev/internal/protocol" | ||
| 14 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 14 | "github.com/bnema/vev/internal/usecase/layout" | 15 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 15 | "github.com/stretchr/testify/require" | 16 | "github.com/stretchr/testify/require" | ||
| 16 | ) | 17 | ) | ||
| @@ -22,7 +23,7 @@ func TestAttachmentOutputBuildsPipelinedDependencyChain(t *testing.T) { | |||||
| 22 | first, ok, err := drawOutputState(t, stream, firstFrame, nil, true, 7) | 23 | first, ok, err := drawOutputState(t, stream, firstFrame, nil, true, 7) | ||
| 23 | require.NoError(t, err) | 24 | require.NoError(t, err) | ||
| 24 | require.True(t, ok) | 25 | require.True(t, ok) | ||
| 25 | - | firstOut, err := ports.UnmarshalOutput(first.Payload) | 26 | + | firstOut, err := wire.UnmarshalOutput(first.Payload) |
| 26 | require.NoError(t, err) | 27 | require.NoError(t, err) | ||
| 27 | require.Equal(t, uint64(0), firstOut.Base) | 28 | require.Equal(t, uint64(0), firstOut.Base) | ||
| 28 | require.Equal(t, uint64(1), firstOut.New) | 29 | require.Equal(t, uint64(1), firstOut.New) | ||
| @@ -33,7 +34,7 @@ func TestAttachmentOutputBuildsPipelinedDependencyChain(t *testing.T) { | |||||
| 33 | second, ok, err := drawOutputState(t, stream, secondFrame, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false, 8) | 34 | second, ok, err := drawOutputState(t, stream, secondFrame, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false, 8) | ||
| 34 | require.NoError(t, err) | 35 | require.NoError(t, err) | ||
| 35 | require.True(t, ok) | 36 | require.True(t, ok) | ||
| 36 | - | secondOut, err := ports.UnmarshalOutput(second.Payload) | 37 | + | secondOut, err := wire.UnmarshalOutput(second.Payload) |
| 37 | require.NoError(t, err) | 38 | require.NoError(t, err) | ||
| 38 | require.Equal(t, firstOut.New, secondOut.Base) | 39 | require.Equal(t, firstOut.New, secondOut.Base) | ||
| 39 | require.Equal(t, uint64(2), secondOut.New) | 40 | require.Equal(t, uint64(2), secondOut.New) | ||
| @@ -91,7 +92,7 @@ func TestAttachmentOutputCapacityProbeDoesNotRaceWithSend(t *testing.T) { | |||||
| 91 | release := make(chan struct{}) | 92 | release := make(chan struct{}) | ||
| 92 | sendDone := make(chan error, 1) | 93 | sendDone := make(chan error, 1) | ||
| 93 | go func() { | 94 | go func() { | ||
| 94 | - | sendDone <- prepared.send(prepared.data, 0, func(ports.Frame) error { | 95 | + | sendDone <- prepared.send(prepared.data, 0, func(wire.Frame) error { |
| 95 | close(entered) | 96 | close(entered) | ||
| 96 | <-release | 97 | <-release | ||
| 97 | return nil | 98 | return nil | ||
| @@ -132,12 +133,12 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||||
| 132 | second := newAttachment() | 133 | second := newAttachment() | ||
| 133 | firstPrepared, err := first.prepare(frame, nil, true) | 134 | firstPrepared, err := first.prepare(frame, nil, true) | ||
| 134 | require.NoError(t, err) | 135 | require.NoError(t, err) | ||
| 135 | - | var firstFrame ports.Frame | 136 | + | var firstFrame wire.Frame |
| 136 | - | require.NoError(t, firstPrepared.send(firstPrepared.data, 0, func(frame ports.Frame) error { | 137 | + | require.NoError(t, firstPrepared.send(firstPrepared.data, 0, func(frame wire.Frame) error { |
| 137 | firstFrame = frame | 138 | firstFrame = frame | ||
| 138 | return nil | 139 | return nil | ||
| 139 | })) | 140 | })) | ||
| 140 | - | firstOutput, err := ports.UnmarshalOutput(firstFrame.Payload) | 141 | + | firstOutput, err := wire.UnmarshalOutput(firstFrame.Payload) |
| 141 | require.NoError(t, err) | 142 | require.NoError(t, err) | ||
| 142 | require.Equal(t, uint64(1), firstOutput.Epoch) | 143 | require.Equal(t, uint64(1), firstOutput.Epoch) | ||
| 143 | require.Equal(t, uint64(1), firstOutput.New) | 144 | require.Equal(t, uint64(1), firstOutput.New) | ||
| @@ -146,7 +147,7 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||||
| 146 | 147 | ||||
| 147 | secondPrepared, err := second.prepare(frame, nil, true) | 148 | secondPrepared, err := second.prepare(frame, nil, true) | ||
| 148 | require.NoError(t, err) | 149 | require.NoError(t, err) | ||
| 149 | - | require.NoError(t, secondPrepared.send(secondPrepared.data, 0, func(ports.Frame) error { return nil })) | 150 | + | require.NoError(t, secondPrepared.send(secondPrepared.data, 0, func(wire.Frame) error { return nil })) |
| 150 | require.Equal(t, uint64(1), second.epoch) | 151 | require.Equal(t, uint64(1), second.epoch) | ||
| 151 | require.Equal(t, uint64(1), second.next) | 152 | require.Equal(t, uint64(1), second.next) | ||
| 152 | require.Equal(t, uint64(1), first.next) | 153 | require.Equal(t, uint64(1), first.next) | ||
| @@ -160,7 +161,7 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||||
| 160 | require.Zero(t, first.next) | 161 | require.Zero(t, first.next) | ||
| 161 | require.Zero(t, first.acked) | 162 | require.Zero(t, first.acked) | ||
| 162 | var staleSent bool | 163 | var staleSent bool | ||
| 163 | - | require.NoError(t, pending.send(pending.data, 0, func(ports.Frame) error { | 164 | + | require.NoError(t, pending.send(pending.data, 0, func(wire.Frame) error { |
| 164 | staleSent = true | 165 | staleSent = true | ||
| 165 | return nil | 166 | return nil | ||
| 166 | })) | 167 | })) | ||
| @@ -171,12 +172,12 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||||
| 171 | 172 | ||||
| 172 | reset, err := first.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | 173 | reset, err := first.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | ||
| 173 | require.NoError(t, err) | 174 | require.NoError(t, err) | ||
| 174 | - | var resetFrame ports.Frame | 175 | + | var resetFrame wire.Frame |
| 175 | - | require.NoError(t, reset.send(reset.data, 0, func(frame ports.Frame) error { | 176 | + | require.NoError(t, reset.send(reset.data, 0, func(frame wire.Frame) error { |
| 176 | resetFrame = frame | 177 | resetFrame = frame | ||
| 177 | return nil | 178 | return nil | ||
| 178 | })) | 179 | })) | ||
| 179 | - | resetOutput, err := ports.UnmarshalOutput(resetFrame.Payload) | 180 | + | resetOutput, err := wire.UnmarshalOutput(resetFrame.Payload) |
| 180 | require.NoError(t, err) | 181 | require.NoError(t, err) | ||
| 181 | require.Equal(t, uint64(2), resetOutput.Epoch) | 182 | require.Equal(t, uint64(2), resetOutput.Epoch) | ||
| 182 | require.Zero(t, resetOutput.Base) | 183 | require.Zero(t, resetOutput.Base) | ||
| @@ -204,14 +205,14 @@ func TestPreparedOutputDropsReplacedConnectionAndView(t *testing.T) { | |||||
| 204 | fillOutputStateRows(frame, []string{"abc"}) | 205 | fillOutputStateRows(frame, []string{"abc"}) | ||
| 205 | initial, err := stream.prepare(frame, nil, true) | 206 | initial, err := stream.prepare(frame, nil, true) | ||
| 206 | require.NoError(t, err) | 207 | require.NoError(t, err) | ||
| 207 | - | require.NoError(t, initial.send(initial.data, 0, func(ports.Frame) error { return nil })) | 208 | + | require.NoError(t, initial.send(initial.data, 0, func(wire.Frame) error { return nil })) |
| 208 | changed := frame.Clone() | 209 | changed := frame.Clone() | ||
| 209 | changed.Set(0, 0, renderer.Cell{Rune: 'x', Style: renderer.DefaultStyle()}) | 210 | changed.Set(0, 0, renderer.Cell{Rune: 'x', Style: renderer.DefaultStyle()}) | ||
| 210 | pending, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | 211 | pending, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | ||
| 211 | require.NoError(t, err) | 212 | require.NoError(t, err) | ||
| 212 | tt.change(ac) | 213 | tt.change(ac) | ||
| 213 | var sent bool | 214 | var sent bool | ||
| 214 | - | require.NoError(t, pending.send(pending.data, 0, func(ports.Frame) error { | 215 | + | require.NoError(t, pending.send(pending.data, 0, func(wire.Frame) error { |
| 215 | sent = true | 216 | sent = true | ||
| 216 | return nil | 217 | return nil | ||
| 217 | })) | 218 | })) | ||
| @@ -220,7 +221,7 @@ func TestPreparedOutputDropsReplacedConnectionAndView(t *testing.T) { | |||||
| 220 | 221 | ||||
| 221 | retry, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | 222 | retry, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | ||
| 222 | require.NoError(t, err) | 223 | require.NoError(t, err) | ||
| 223 | - | require.NoError(t, retry.send(retry.data, 0, func(ports.Frame) error { return nil })) | 224 | + | require.NoError(t, retry.send(retry.data, 0, func(wire.Frame) error { return nil })) |
| 224 | require.Equal(t, uint64(2), stream.next) | 225 | require.Equal(t, uint64(2), stream.next) | ||
| 225 | }) | 226 | }) | ||
| 226 | } | 227 | } | ||
| @@ -243,7 +244,7 @@ func TestOutputStateSideEffectsDoNotAdvanceEpochStateOrACK(t *testing.T) { | |||||
| 243 | beforeEpoch, beforeNext, beforeAck := stream.epoch, stream.next, stream.acked | 244 | beforeEpoch, beforeNext, beforeAck := stream.epoch, stream.next, stream.acked | ||
| 244 | frame, err := stream.sideEffect([]byte("pty"), 9) | 245 | frame, err := stream.sideEffect([]byte("pty"), 9) | ||
| 245 | require.NoError(t, err) | 246 | require.NoError(t, err) | ||
| 246 | - | out, err := ports.UnmarshalOutput(frame.Payload) | 247 | + | out, err := wire.UnmarshalOutput(frame.Payload) |
| 247 | require.NoError(t, err) | 248 | require.NoError(t, err) | ||
| 248 | require.Equal(t, beforeEpoch, out.Epoch) | 249 | require.Equal(t, beforeEpoch, out.Epoch) | ||
| 249 | require.Zero(t, out.Base) | 250 | require.Zero(t, out.Base) | ||
| @@ -260,7 +261,7 @@ func TestAttachmentOutputFailedSendRetriesSnapshotWithoutAdvancing(t *testing.T) | |||||
| 260 | fillOutputStateRows(initial, []string{"abc"}) | 261 | fillOutputStateRows(initial, []string{"abc"}) | ||
| 261 | first, err := stream.prepare(initial, nil, true) | 262 | first, err := stream.prepare(initial, nil, true) | ||
| 262 | require.NoError(t, err) | 263 | require.NoError(t, err) | ||
| 263 | - | require.NoError(t, first.send(first.data, 0, func(ports.Frame) error { return nil })) | 264 | + | require.NoError(t, first.send(first.data, 0, func(wire.Frame) error { return nil })) |
| 264 | require.Equal(t, uint64(1), stream.next) | 265 | require.Equal(t, uint64(1), stream.next) | ||
| 265 | 266 | ||||
| 266 | changed := initial.Clone() | 267 | changed := initial.Clone() | ||
| @@ -272,7 +273,7 @@ func TestAttachmentOutputFailedSendRetriesSnapshotWithoutAdvancing(t *testing.T) | |||||
| 272 | require.Empty(t, probe.Bytes(), "preparation must not advance the renderer shadow") | 273 | require.Empty(t, probe.Bytes(), "preparation must not advance the renderer shadow") | ||
| 273 | 274 | ||||
| 274 | sendErr := errors.New("send failed") | 275 | sendErr := errors.New("send failed") | ||
| 275 | - | require.ErrorIs(t, pending.send(pending.data, 0, func(ports.Frame) error { return sendErr }), sendErr) | 276 | + | require.ErrorIs(t, pending.send(pending.data, 0, func(wire.Frame) error { return sendErr }), sendErr) |
| 276 | require.Equal(t, uint64(1), stream.next, "failed send must not advance the state chain") | 277 | require.Equal(t, uint64(1), stream.next, "failed send must not advance the state chain") | ||
| 277 | pending.commitNoSend() | 278 | pending.commitNoSend() | ||
| 278 | probe, err = stream.renderer.Prepare(initial, nil, false) | 279 | probe, err = stream.renderer.Prepare(initial, nil, false) | ||
| @@ -281,17 +282,17 @@ func TestAttachmentOutputFailedSendRetriesSnapshotWithoutAdvancing(t *testing.T) | |||||
| 281 | 282 | ||||
| 282 | retry, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | 283 | retry, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | ||
| 283 | require.NoError(t, err) | 284 | require.NoError(t, err) | ||
| 284 | - | var sent ports.Frame | 285 | + | var sent wire.Frame |
| 285 | - | require.NoError(t, retry.send(retry.data, 0, func(frame ports.Frame) error { | 286 | + | require.NoError(t, retry.send(retry.data, 0, func(frame wire.Frame) error { |
| 286 | sent = frame | 287 | sent = frame | ||
| 287 | return nil | 288 | return nil | ||
| 288 | })) | 289 | })) | ||
| 289 | - | out, err := ports.UnmarshalOutput(sent.Payload) | 290 | + | out, err := wire.UnmarshalOutput(sent.Payload) |
| 290 | require.NoError(t, err) | 291 | require.NoError(t, err) | ||
| 291 | require.Zero(t, out.Base, "retry after ambiguous send failure must be dependency-free") | 292 | require.Zero(t, out.Base, "retry after ambiguous send failure must be dependency-free") | ||
| 292 | require.Equal(t, uint64(2), out.New, "state numbers remain monotonic across rebases") | 293 | require.Equal(t, uint64(2), out.New, "state numbers remain monotonic across rebases") | ||
| 293 | require.Equal(t, uint64(2), stream.next, "successful retry advances the chain exactly once") | 294 | require.Equal(t, uint64(2), stream.next, "successful retry advances the chain exactly once") | ||
| 294 | - | require.NoError(t, retry.send(retry.data, 0, func(ports.Frame) error { | 295 | + | require.NoError(t, retry.send(retry.data, 0, func(wire.Frame) error { |
| 295 | t.Fatal("completed output sent twice") | 296 | t.Fatal("completed output sent twice") | ||
| 296 | return nil | 297 | return nil | ||
| 297 | })) | 298 | })) | ||
| @@ -307,7 +308,7 @@ func TestAttachmentOutputNoByteCommitAdvancesShadowWithoutState(t *testing.T) { | |||||
| 307 | fillOutputStateRows(frame, []string{"abc"}) | 308 | fillOutputStateRows(frame, []string{"abc"}) | ||
| 308 | initial, err := stream.prepare(frame, nil, true) | 309 | initial, err := stream.prepare(frame, nil, true) | ||
| 309 | require.NoError(t, err) | 310 | require.NoError(t, err) | ||
| 310 | - | require.NoError(t, initial.send(initial.data, 0, func(ports.Frame) error { return nil })) | 311 | + | require.NoError(t, initial.send(initial.data, 0, func(wire.Frame) error { return nil })) |
| 311 | 312 | ||||
| 312 | noOp, err := stream.prepare(frame, nil, false) | 313 | noOp, err := stream.prepare(frame, nil, false) | ||
| 313 | require.NoError(t, err) | 314 | require.NoError(t, err) | ||
| @@ -371,7 +372,7 @@ func (s *attachmentOutput) render(frame renderer.Frame, damage []renderer.Damage | |||||
| 371 | return prepared.data, nil | 372 | return prepared.data, nil | ||
| 372 | } | 373 | } | ||
| 373 | 374 | ||||
| 374 | - | func outputStateFrame(stream *attachmentOutput, data []byte, reset bool, echoAck uint64) ports.Frame { | 375 | + | func outputStateFrame(stream *attachmentOutput, data []byte, reset bool, echoAck uint64) wire.Frame { |
| 375 | stream.next++ | 376 | stream.next++ | ||
| 376 | base := stream.next - 1 | 377 | base := stream.next - 1 | ||
| 377 | if reset { | 378 | if reset { | ||
| @@ -384,22 +385,22 @@ func outputStateFrame(stream *attachmentOutput, data []byte, reset bool, echoAck | |||||
| 384 | return frame | 385 | return frame | ||
| 385 | } | 386 | } | ||
| 386 | 387 | ||||
| 387 | - | func drawOutputState(t *testing.T, stream *attachmentOutput, frame renderer.Frame, damage []renderer.Damage, reset bool, echoAck uint64) (ports.Frame, bool, error) { | 388 | + | func drawOutputState(t *testing.T, stream *attachmentOutput, frame renderer.Frame, damage []renderer.Damage, reset bool, echoAck uint64) (wire.Frame, bool, error) { |
| 388 | t.Helper() | 389 | t.Helper() | ||
| 389 | prepared, err := stream.prepare(frame, damage, reset) | 390 | prepared, err := stream.prepare(frame, damage, reset) | ||
| 390 | if err != nil || len(prepared.data) == 0 { | 391 | if err != nil || len(prepared.data) == 0 { | ||
| 391 | if prepared != nil { | 392 | if prepared != nil { | ||
| 392 | prepared.commitNoSend() | 393 | prepared.commitNoSend() | ||
| 393 | } | 394 | } | ||
| 394 | - | return ports.Frame{}, false, err | 395 | + | return wire.Frame{}, false, err |
| 395 | } | 396 | } | ||
| 396 | - | var output ports.Frame | 397 | + | var output wire.Frame |
| 397 | - | err = prepared.send(prepared.data, echoAck, func(frame ports.Frame) error { | 398 | + | err = prepared.send(prepared.data, echoAck, func(frame wire.Frame) error { |
| 398 | output = frame | 399 | output = frame | ||
| 399 | return nil | 400 | return nil | ||
| 400 | }) | 401 | }) | ||
| 401 | if err != nil { | 402 | if err != nil { | ||
| 402 | - | return ports.Frame{}, false, err | 403 | + | return wire.Frame{}, false, err |
| 403 | } | 404 | } | ||
| 404 | return output, true, nil | 405 | return output, true, nil | ||
| 405 | } | 406 | } | ||
| @@ -416,7 +417,7 @@ func TestAttachmentOutputResizeFrameThenNoopAndDamageAreDifferential(t *testing. | |||||
| 416 | resized, ok, err := drawOutputState(t, stream, screen.Frame, screen.Damage(), true, 0) | 417 | resized, ok, err := drawOutputState(t, stream, screen.Frame, screen.Damage(), true, 0) | ||
| 417 | require.NoError(t, err) | 418 | require.NoError(t, err) | ||
| 418 | require.True(t, ok) | 419 | require.True(t, ok) | ||
| 419 | - | resizeOutput, err := ports.UnmarshalOutput(resized.Payload) | 420 | + | resizeOutput, err := wire.UnmarshalOutput(resized.Payload) |
| 420 | require.NoError(t, err) | 421 | require.NoError(t, err) | ||
| 421 | require.Zero(t, resizeOutput.Base, "resize must emit the one reset frame") | 422 | require.Zero(t, resizeOutput.Base, "resize must emit the one reset frame") | ||
| 422 | screen.ClearDamage() | 423 | screen.ClearDamage() | ||
| @@ -429,7 +430,7 @@ func TestAttachmentOutputResizeFrameThenNoopAndDamageAreDifferential(t *testing. | |||||
| 429 | damaged, ok, err := drawOutputState(t, stream, screen.Frame, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false, 0) | 430 | damaged, ok, err := drawOutputState(t, stream, screen.Frame, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false, 0) | ||
| 430 | require.NoError(t, err) | 431 | require.NoError(t, err) | ||
| 431 | require.True(t, ok) | 432 | require.True(t, ok) | ||
| 432 | - | damageOutput, err := ports.UnmarshalOutput(damaged.Payload) | 433 | + | damageOutput, err := wire.UnmarshalOutput(damaged.Payload) |
| 433 | require.NoError(t, err) | 434 | require.NoError(t, err) | ||
| 434 | require.Equal(t, resizeOutput.New, damageOutput.Base, "later damage must remain incremental") | 435 | require.Equal(t, resizeOutput.New, damageOutput.Base, "later damage must remain incremental") | ||
| 435 | } | 436 | } | ||
| @@ -455,7 +456,7 @@ func TestAttachmentOutputFailedSendKeepsTextCursorAndGraphicsSpeculative(t *test | |||||
| 455 | require.NoError(t, err) | 456 | require.NoError(t, err) | ||
| 456 | 457 | ||||
| 457 | sendErr := errors.New("send failed") | 458 | sendErr := errors.New("send failed") | ||
| 458 | - | require.ErrorIs(t, prepared.send(0, func(ports.Frame) error { return sendErr }), sendErr) | 459 | + | require.ErrorIs(t, prepared.send(0, func(wire.Frame) error { return sendErr }), sendErr) |
| 459 | 460 | ||||
| 460 | require.Equal(t, cursorOut{valid: true, row: 1, col: 1}, output.lastCursor) | 461 | require.Equal(t, cursorOut{valid: true, row: 1, col: 1}, output.lastCursor) | ||
| 461 | require.Empty(t, graphicsState.assets) | 462 | require.Empty(t, graphicsState.assets) | ||
M internal/usecase/daemon/attachment_parking_test.go +5 -5
| @@ -6,15 +6,15 @@ import ( | |||||
| 6 | 6 | ||||
| 7 | "github.com/stretchr/testify/require" | 7 | "github.com/stretchr/testify/require" | ||
| 8 | 8 | ||||
| 9 | - | "github.com/bnema/vev/internal/ports" | |||
| 10 | "github.com/bnema/vev/internal/protocol" | 9 | "github.com/bnema/vev/internal/protocol" | ||
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 11 | ) | 11 | ) | ||
| 12 | 12 | ||||
| 13 | type resumeWelcomeFailureTransport struct { | 13 | type resumeWelcomeFailureTransport struct { | ||
| 14 | closeTrackingTransport | 14 | closeTrackingTransport | ||
| 15 | } | 15 | } | ||
| 16 | 16 | ||||
| 17 | - | func (*resumeWelcomeFailureTransport) Send(ports.Frame) error { return errWelcomeSendFailed } | 17 | + | func (*resumeWelcomeFailureTransport) Send(wire.Frame) error { return errWelcomeSendFailed } |
| 18 | 18 | ||||
| 19 | var errWelcomeSendFailed = errors.New("welcome send failed") | 19 | var errWelcomeSendFailed = errors.New("welcome send failed") | ||
| 20 | 20 | ||||
| @@ -142,7 +142,7 @@ func TestSuccessfulResumeRejectsOldCredentialAfterWelcome(t *testing.T) { | |||||
| 142 | d.clientGone(sess, ac, oldTransport, false) | 142 | d.clientGone(sess, ac, oldTransport, false) | ||
| 143 | 143 | ||||
| 144 | resumedTransport := &closeTrackingTransport{} | 144 | resumedTransport := &closeTrackingTransport{} | ||
| 145 | - | d.handleHello(resumedTransport, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", oldToken))}) | 145 | + | d.handleHello(resumedTransport, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", oldToken))}) |
| 146 | newToken := ac.resumeToken | 146 | newToken := ac.resumeToken | ||
| 147 | require.NotEqual(t, oldToken, newToken) | 147 | require.NotEqual(t, oldToken, newToken) | ||
| 148 | d.mu.Lock() | 148 | d.mu.Lock() | ||
| @@ -152,7 +152,7 @@ func TestSuccessfulResumeRejectsOldCredentialAfterWelcome(t *testing.T) { | |||||
| 152 | require.False(t, oldRetained) | 152 | require.False(t, oldRetained) | ||
| 153 | require.NotNil(t, newParked) | 153 | require.NotNil(t, newParked) | ||
| 154 | require.NotEmpty(t, resumedTransport.Sends()) | 154 | require.NotEmpty(t, resumedTransport.Sends()) | ||
| 155 | - | require.Equal(t, ports.MsgWelcome, resumedTransport.Sends()[0].Type, "Welcome must remain the first server frame after Hello") | 155 | + | require.Equal(t, wire.MsgWelcome, resumedTransport.Sends()[0].Type, "Welcome must remain the first server frame after Hello") |
| 156 | } | 156 | } | ||
| 157 | 157 | ||||
| 158 | func TestFailedResumeHandshakeKeepsParkedCredential(t *testing.T) { | 158 | func TestFailedResumeHandshakeKeepsParkedCredential(t *testing.T) { | ||
| @@ -166,7 +166,7 @@ func TestFailedResumeHandshakeKeepsParkedCredential(t *testing.T) { | |||||
| 166 | d.clientGone(sess, ac, oldTransport, false) | 166 | d.clientGone(sess, ac, oldTransport, false) | ||
| 167 | 167 | ||||
| 168 | failed := &resumeWelcomeFailureTransport{} | 168 | failed := &resumeWelcomeFailureTransport{} | ||
| 169 | - | d.handleHello(failed, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", token))}) | 169 | + | d.handleHello(failed, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", token))}) |
| 170 | require.Nil(t, ac.transport()) | 170 | require.Nil(t, ac.transport()) | ||
| 171 | d.mu.Lock() | 171 | d.mu.Lock() | ||
| 172 | parked := d.parked[token] | 172 | parked := d.parked[token] | ||
M internal/usecase/daemon/attachment_registry_test.go +3 -3
| @@ -5,7 +5,7 @@ import ( | |||||
| 5 | "testing" | 5 | "testing" | ||
| 6 | 6 | ||||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | - | "github.com/bnema/vev/internal/ports" | 8 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 9 | "github.com/stretchr/testify/require" | 9 | "github.com/stretchr/testify/require" | ||
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| @@ -99,7 +99,7 @@ func TestTabForAttachmentRepairRebasesOutputBeforePublishingRevision(t *testing. | |||||
| 99 | require.Greater(t, ac.output.currentEpoch(), beforeEpoch) | 99 | require.Greater(t, ac.output.currentEpoch(), beforeEpoch) | ||
| 100 | frame, err := ac.output.sideEffect([]byte("x"), 0) | 100 | frame, err := ac.output.sideEffect([]byte("x"), 0) | ||
| 101 | require.NoError(t, err) | 101 | require.NoError(t, err) | ||
| 102 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 102 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 103 | require.NoError(t, err) | 103 | require.NoError(t, err) | ||
| 104 | require.Equal(t, after.revision, output.ViewRevision) | 104 | require.Equal(t, after.revision, output.ViewRevision) | ||
| 105 | require.Equal(t, ac.output.currentEpoch(), output.Epoch) | 105 | require.Equal(t, ac.output.currentEpoch(), output.Epoch) | ||
| @@ -129,7 +129,7 @@ func TestPrepareRemovedTabViewRebasesOutputBeforeSideEffect(t *testing.T) { | |||||
| 129 | 129 | ||||
| 130 | frame, err := ac.output.sideEffect([]byte("replacement"), 0) | 130 | frame, err := ac.output.sideEffect([]byte("replacement"), 0) | ||
| 131 | require.NoError(t, err) | 131 | require.NoError(t, err) | ||
| 132 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 132 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 133 | require.NoError(t, err) | 133 | require.NoError(t, err) | ||
| 134 | require.Equal(t, after.revision, output.ViewRevision) | 134 | require.Equal(t, after.revision, output.ViewRevision) | ||
| 135 | require.NotEqual(t, beforeEpoch, output.Epoch) | 135 | require.NotEqual(t, beforeEpoch, output.Epoch) | ||
M internal/usecase/daemon/attachment_render_test.go +22 -21
| @@ -10,27 +10,28 @@ import ( | |||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | "github.com/bnema/vev/internal/ports" | 11 | "github.com/bnema/vev/internal/ports" | ||
| 12 | "github.com/bnema/vev/internal/protocol" | 12 | "github.com/bnema/vev/internal/protocol" | ||
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | "github.com/stretchr/testify/require" | 14 | "github.com/stretchr/testify/require" | ||
| 14 | ) | 15 | ) | ||
| 15 | 16 | ||||
| 16 | type blockedAttachmentTransport struct { | 17 | type blockedAttachmentTransport struct { | ||
| 17 | entered chan struct{} | 18 | entered chan struct{} | ||
| 18 | release chan struct{} | 19 | release chan struct{} | ||
| 19 | - | sends chan ports.Frame | 20 | + | sends chan wire.Frame |
| 20 | blocked atomic.Bool | 21 | blocked atomic.Bool | ||
| 21 | once sync.Once | 22 | once sync.Once | ||
| 22 | } | 23 | } | ||
| 23 | 24 | ||||
| 24 | - | func (t *blockedAttachmentTransport) Send(frame ports.Frame) error { | 25 | + | func (t *blockedAttachmentTransport) Send(frame wire.Frame) error { |
| 25 | - | if frame.Type == ports.MsgOutput && t.blocked.Load() { | 26 | + | if frame.Type == wire.MsgOutput && t.blocked.Load() { |
| 26 | t.once.Do(func() { close(t.entered) }) | 27 | t.once.Do(func() { close(t.entered) }) | ||
| 27 | <-t.release | 28 | <-t.release | ||
| 28 | } | 29 | } | ||
| 29 | t.sends <- frame | 30 | t.sends <- frame | ||
| 30 | return nil | 31 | return nil | ||
| 31 | } | 32 | } | ||
| 32 | - | func (*blockedAttachmentTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 33 | + | func (*blockedAttachmentTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 33 | - | func (*blockedAttachmentTransport) Close() error { return nil } | 34 | + | func (*blockedAttachmentTransport) Close() error { return nil } |
| 34 | 35 | ||||
| 35 | func TestStaleCapacityReadinessRequeuesWithoutAnotherInvalidation(t *testing.T) { | 36 | func TestStaleCapacityReadinessRequeuesWithoutAnotherInvalidation(t *testing.T) { | ||
| 36 | d, sess, ac, sends := newManualSessionWithPTYs(t, nil) | 37 | d, sess, ac, sends := newManualSessionWithPTYs(t, nil) | ||
| @@ -85,8 +86,8 @@ func TestStaleCapacityReadinessRequeuesWithoutAnotherInvalidation(t *testing.T) | |||||
| 85 | ac.output.syncCapacityLocked() | 86 | ac.output.syncCapacityLocked() | ||
| 86 | ac.sendMu.Unlock() | 87 | ac.sendMu.Unlock() | ||
| 87 | close(releaseRetry) | 88 | close(releaseRetry) | ||
| 88 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | 89 | + | frame := awaitFrame(t, sends, wire.MsgOutput) |
| 89 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 90 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 90 | require.NoError(t, err) | 91 | require.NoError(t, err) | ||
| 91 | require.Contains(t, string(output.Data), "capacity race") | 92 | require.Contains(t, string(output.Data), "capacity race") | ||
| 92 | awaitTestCompletion(t, fireDone, "initial fire did not finish") | 93 | awaitTestCompletion(t, fireDone, "initial fire did not finish") | ||
| @@ -146,10 +147,10 @@ func TestAttachmentFirstPaintDoesNotWaitForBlockedPeer(t *testing.T) { | |||||
| 146 | defer releasePTY() | 147 | defer releasePTY() | ||
| 147 | clock := &signalClock{timers: make(chan *signalTimer, 16)} | 148 | clock := &signalClock{timers: make(chan *signalTimer, 16)} | ||
| 148 | d := newTestDaemon(t, newFactory(t, pty), clock) | 149 | d := newTestDaemon(t, newFactory(t, pty), clock) | ||
| 149 | - | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | 150 | + | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} |
| 150 | sess, old, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, oldTransport) | 151 | sess, old, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, oldTransport) | ||
| 151 | require.NoError(t, err) | 152 | require.NoError(t, err) | ||
| 152 | - | newTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | 153 | + | newTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} |
| 153 | _, fresh, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}}, newTransport) | 154 | _, fresh, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}}, newTransport) | ||
| 154 | require.NoError(t, err) | 155 | require.NoError(t, err) | ||
| 155 | 156 | ||||
| @@ -172,7 +173,7 @@ func TestAttachmentFirstPaintDoesNotWaitForBlockedPeer(t *testing.T) { | |||||
| 172 | painted := make(chan bool, 1) | 173 | painted := make(chan bool, 1) | ||
| 173 | go func() { painted <- d.firstPaintForTransition(token) }() | 174 | go func() { painted <- d.firstPaintForTransition(token) }() | ||
| 174 | frame := awaitTestValue(t, newTransport.sends, "healthy attachment first paint was gated by slow peer") | 175 | frame := awaitTestValue(t, newTransport.sends, "healthy attachment first paint was gated by slow peer") | ||
| 175 | - | require.Equal(t, ports.MsgOutput, frame.Type) | 176 | + | require.Equal(t, wire.MsgOutput, frame.Type) |
| 176 | require.True(t, <-painted) | 177 | require.True(t, <-painted) | ||
| 177 | close(oldTransport.release) | 178 | close(oldTransport.release) | ||
| 178 | } | 179 | } | ||
| @@ -182,7 +183,7 @@ func TestMultiAttachmentHandshakeFirstPaintNotGatedByBlockedPeer(t *testing.T) { | |||||
| 182 | defer releasePTY() | 183 | defer releasePTY() | ||
| 183 | clock := &signalClock{timers: make(chan *signalTimer, 16)} | 184 | clock := &signalClock{timers: make(chan *signalTimer, 16)} | ||
| 184 | d := newTestDaemon(t, newFactory(t, pty), clock) | 185 | d := newTestDaemon(t, newFactory(t, pty), clock) | ||
| 185 | - | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | 186 | + | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} |
| 186 | sess, old, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, oldTransport) | 187 | sess, old, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, oldTransport) | ||
| 187 | require.NoError(t, err) | 188 | require.NoError(t, err) | ||
| 188 | rc := sess.renderCoordinator() | 189 | rc := sess.renderCoordinator() | ||
| @@ -202,16 +203,16 @@ func TestMultiAttachmentHandshakeFirstPaintNotGatedByBlockedPeer(t *testing.T) { | |||||
| 202 | awaitTestCompletion(t, oldTransport.entered, "slow attachment did not begin its blocked output") | 203 | awaitTestCompletion(t, oldTransport.entered, "slow attachment did not begin its blocked output") | ||
| 203 | 204 | ||||
| 204 | hello := protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}} | 205 | hello := protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}} | ||
| 205 | - | tr, sends, releaseConn := newConn(t, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}) | 206 | + | tr, sends, releaseConn := newConn(t, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}) |
| 206 | defer releaseConn() | 207 | defer releaseConn() | ||
| 207 | handshakeDone := make(chan struct{}) | 208 | handshakeDone := make(chan struct{}) | ||
| 208 | go func() { | 209 | go func() { | ||
| 209 | d.handleConn(tr) | 210 | d.handleConn(tr) | ||
| 210 | close(handshakeDone) | 211 | close(handshakeDone) | ||
| 211 | }() | 212 | }() | ||
| 212 | - | awaitFrame(t, sends, ports.MsgWelcome) | 213 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 213 | - | firstPaint := awaitFrame(t, sends, ports.MsgOutput) | 214 | + | firstPaint := awaitFrame(t, sends, wire.MsgOutput) |
| 214 | - | require.Equal(t, ports.MsgOutput, firstPaint.Type) | 215 | + | require.Equal(t, wire.MsgOutput, firstPaint.Type) |
| 215 | releaseConn() | 216 | releaseConn() | ||
| 216 | awaitTestCompletion(t, handshakeDone, "multi-attachment handshake did not complete after first paint") | 217 | awaitTestCompletion(t, handshakeDone, "multi-attachment handshake did not complete after first paint") | ||
| 217 | close(oldTransport.release) | 218 | close(oldTransport.release) | ||
| @@ -222,10 +223,10 @@ func TestAttachmentPaintFanoutDoesNotWaitForBlockedPeer(t *testing.T) { | |||||
| 222 | pty, releasePTY := newBlockingPTY(t) | 223 | pty, releasePTY := newBlockingPTY(t) | ||
| 223 | defer releasePTY() | 224 | defer releasePTY() | ||
| 224 | d := newTestDaemon(t, newFactory(t, pty), stubClock{}) | 225 | d := newTestDaemon(t, newFactory(t, pty), stubClock{}) | ||
| 225 | - | firstTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | 226 | + | firstTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} |
| 226 | sess, _, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, firstTransport) | 227 | sess, _, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, firstTransport) | ||
| 227 | require.NoError(t, err) | 228 | require.NoError(t, err) | ||
| 228 | - | secondTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | 229 | + | secondTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} |
| 229 | _, _, err = d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}}, secondTransport) | 230 | _, _, err = d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}}, secondTransport) | ||
| 230 | require.NoError(t, err) | 231 | require.NoError(t, err) | ||
| 231 | rc := sess.renderCoordinator() | 232 | rc := sess.renderCoordinator() | ||
| @@ -244,8 +245,8 @@ func TestAttachmentPaintFanoutDoesNotWaitForBlockedPeer(t *testing.T) { | |||||
| 244 | } | 245 | } | ||
| 245 | select { | 246 | select { | ||
| 246 | case frame := <-secondTransport.sends: | 247 | case frame := <-secondTransport.sends: | ||
| 247 | - | require.Equal(t, ports.MsgOutput, frame.Type) | 248 | + | require.Equal(t, wire.MsgOutput, frame.Type) |
| 248 | - | out, err := ports.UnmarshalOutput(frame.Payload) | 249 | + | out, err := wire.UnmarshalOutput(frame.Payload) |
| 249 | require.NoError(t, err) | 250 | require.NoError(t, err) | ||
| 250 | require.True(t, out.Full, "fan-out peers must send a fresh first frame even after another attachment acknowledges shared damage") | 251 | require.True(t, out.Full, "fan-out peers must send a fresh first frame even after another attachment acknowledges shared damage") | ||
| 251 | case <-time.After(time.Second): | 252 | case <-time.After(time.Second): | ||
| @@ -284,8 +285,8 @@ func TestAttachmentResizeUsesLatestClaimedSessionGeometry(t *testing.T) { | |||||
| 284 | require.True(t, rc.markAttachmentReady(secondLease)) | 285 | require.True(t, rc.markAttachmentReady(secondLease)) | ||
| 285 | resize := func(ac *attachedClient, tr ports.Transport, size domain.Size) { | 286 | resize := func(ac *attachedClient, tr ports.Transport, size domain.Size) { | ||
| 286 | token := sess.captureAttachmentCapability(ac, tr) | 287 | token := sess.captureAttachmentCapability(ac, tr) | ||
| 287 | - | d.handleAttachmentClientFrame(token, ports.Frame{ | 288 | + | d.handleAttachmentClientFrame(token, wire.Frame{ |
| 288 | - | Type: ports.MsgResize, | 289 | + | Type: wire.MsgResize, |
| 289 | Payload: mustMarshalResize(protocol.Resize{Size: size}), | 290 | Payload: mustMarshalResize(protocol.Resize{Size: size}), | ||
| 290 | }) | 291 | }) | ||
| 291 | } | 292 | } | ||
M internal/usecase/daemon/attachment_route_identity_test.go +5 -5
| @@ -5,8 +5,8 @@ import ( | |||||
| 5 | "testing" | 5 | "testing" | ||
| 6 | 6 | ||||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | - | "github.com/bnema/vev/internal/ports" | |||
| 9 | "github.com/bnema/vev/internal/protocol" | 8 | "github.com/bnema/vev/internal/protocol" | ||
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 10 | "github.com/stretchr/testify/require" | 10 | "github.com/stretchr/testify/require" | ||
| 11 | ) | 11 | ) | ||
| 12 | 12 | ||||
| @@ -14,8 +14,8 @@ type committedIdentityErrorTransport struct { | |||||
| 14 | closeTrackingTransport | 14 | closeTrackingTransport | ||
| 15 | } | 15 | } | ||
| 16 | 16 | ||||
| 17 | - | func (t *committedIdentityErrorTransport) Send(frame ports.Frame) error { | 17 | + | func (t *committedIdentityErrorTransport) Send(frame wire.Frame) error { |
| 18 | - | if frame.Type == ports.MsgCommittedRouteIdentity { | 18 | + | if frame.Type == wire.MsgCommittedRouteIdentity { |
| 19 | return errors.New("committed identity send failed") | 19 | return errors.New("committed identity send failed") | ||
| 20 | } | 20 | } | ||
| 21 | return t.closeTrackingTransport.Send(frame) | 21 | return t.closeTrackingTransport.Send(frame) | ||
| @@ -58,11 +58,11 @@ func TestAttachmentTransitionPublishesCommittedRouteIdentity(t *testing.T) { | |||||
| 58 | var identity protocol.CommittedRouteIdentity | 58 | var identity protocol.CommittedRouteIdentity | ||
| 59 | found := false | 59 | found := false | ||
| 60 | for _, frame := range transport.Sends() { | 60 | for _, frame := range transport.Sends() { | ||
| 61 | - | if frame.Type != ports.MsgCommittedRouteIdentity { | 61 | + | if frame.Type != wire.MsgCommittedRouteIdentity { |
| 62 | continue | 62 | continue | ||
| 63 | } | 63 | } | ||
| 64 | var decodeErr error | 64 | var decodeErr error | ||
| 65 | - | identity, decodeErr = ports.UnmarshalCommittedRouteIdentity(frame.Payload) | 65 | + | identity, decodeErr = wire.UnmarshalCommittedRouteIdentity(frame.Payload) |
| 66 | require.NoError(t, decodeErr) | 66 | require.NoError(t, decodeErr) | ||
| 67 | found = true | 67 | found = true | ||
| 68 | } | 68 | } | ||
M internal/usecase/daemon/attention_test.go +2 -1
| @@ -14,6 +14,7 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/domain" | 14 | "github.com/bnema/vev/internal/domain" | ||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 17 | "github.com/bnema/vev/internal/usecase/keys" | 18 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 18 | "github.com/bnema/vev/internal/usecase/layout" | 19 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 19 | "github.com/bnema/vev/internal/usecase/ui" | 20 | "github.com/bnema/vev/internal/usecase/ui" | ||
| @@ -166,7 +167,7 @@ func TestNoteAttentionDoesNotBlockOnWedgedOtherClient(t *testing.T) { | |||||
| 166 | trW := portsmocks.NewMockTransport(t) | 167 | trW := portsmocks.NewMockTransport(t) | ||
| 167 | block := make(chan struct{}) | 168 | block := make(chan struct{}) | ||
| 168 | t.Cleanup(func() { close(block) }) | 169 | t.Cleanup(func() { close(block) }) | ||
| 169 | - | trW.EXPECT().Send(mock.Anything).RunAndReturn(func(ports.Frame) error { | 170 | + | trW.EXPECT().Send(mock.Anything).RunAndReturn(func(wire.Frame) error { |
| 170 | <-block | 171 | <-block | ||
| 171 | return nil | 172 | return nil | ||
| 172 | }).Maybe() | 173 | }).Maybe() | ||
M internal/usecase/daemon/client.go +5 -4
| @@ -14,6 +14,7 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/domain" | 14 | "github.com/bnema/vev/internal/domain" | ||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | "github.com/bnema/vev/internal/protocol" | 16 | "github.com/bnema/vev/internal/protocol" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 17 | "github.com/bnema/vev/internal/usecase/keys" | 18 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 18 | "github.com/bnema/vev/internal/usecase/mouse" | 19 | "github.com/bnema/vev/internal/usecase/mouse" | ||
| 19 | themeui "github.com/bnema/vev/internal/usecase/theme" | 20 | themeui "github.com/bnema/vev/internal/usecase/theme" | ||
| @@ -409,7 +410,7 @@ var errTransportReplaced = errors.New("client transport was replaced") | |||||
| 409 | 410 | ||||
| 410 | // sendExpectedTransport writes only when expected is still the attachment's | 411 | // sendExpectedTransport writes only when expected is still the attachment's | ||
| 411 | // current transport incarnation. It preserves sendMu -> linkMu lock ordering. | 412 | // current transport incarnation. It preserves sendMu -> linkMu lock ordering. | ||
| 412 | - | func (ac *attachedClient) sendExpectedTransport(expected transportSnapshot, f ports.Frame) error { | 413 | + | func (ac *attachedClient) sendExpectedTransport(expected transportSnapshot, f wire.Frame) error { |
| 413 | ac.sendMu.Lock() | 414 | ac.sendMu.Lock() | ||
| 414 | defer ac.sendMu.Unlock() | 415 | defer ac.sendMu.Unlock() | ||
| 415 | if !ac.transportSnapshotCurrent(expected) { | 416 | if !ac.transportSnapshotCurrent(expected) { | ||
| @@ -435,7 +436,7 @@ func (ac *attachedClient) beginExpectedTransportSendLocked(expected transportSna | |||||
| 435 | return nil | 436 | return nil | ||
| 436 | } | 437 | } | ||
| 437 | 438 | ||||
| 438 | - | func (ac *attachedClient) sendExpectedTransportForAttachment(expected transportSnapshot, f ports.Frame, ticket *attachmentEffect) error { | 439 | + | func (ac *attachedClient) sendExpectedTransportForAttachment(expected transportSnapshot, f wire.Frame, ticket *attachmentEffect) error { |
| 439 | ac.sendMu.Lock() | 440 | ac.sendMu.Lock() | ||
| 440 | defer ac.sendMu.Unlock() | 441 | defer ac.sendMu.Unlock() | ||
| 441 | // A attachment-bound send requires a live ticket, and reports every rejection, | 442 | // A attachment-bound send requires a live ticket, and reports every rejection, | ||
| @@ -459,11 +460,11 @@ func (ac *attachedClient) sendExpectedTransportForAttachment(expected transportS | |||||
| 459 | // detachNotifyTimeout, the transport is force-closed, failing the in-flight | 460 | // detachNotifyTimeout, the transport is force-closed, failing the in-flight | ||
| 460 | // write. Detach/kill/shutdown paths use this so they are never gated on a | 461 | // write. Detach/kill/shutdown paths use this so they are never gated on a | ||
| 461 | // client that has stopped draining its socket. | 462 | // client that has stopped draining its socket. | ||
| 462 | - | func (d *Daemon) boundedSend(ac *attachedClient, f ports.Frame) { | 463 | + | func (d *Daemon) boundedSend(ac *attachedClient, f wire.Frame) { |
| 463 | _ = d.boundedSendErr(ac, f) | 464 | _ = d.boundedSendErr(ac, f) | ||
| 464 | } | 465 | } | ||
| 465 | 466 | ||||
| 466 | - | func (d *Daemon) boundedSendErr(ac *attachedClient, f ports.Frame) error { | 467 | + | func (d *Daemon) boundedSendErr(ac *attachedClient, f wire.Frame) error { |
| 467 | expected := ac.transportSnapshot() | 468 | expected := ac.transportSnapshot() | ||
| 468 | if expected.transport == nil { | 469 | if expected.transport == nil { | ||
| 469 | return errors.New("client transport is nil") | 470 | return errors.New("client transport is nil") | ||
M internal/usecase/daemon/client_frame_routing.go +30 -29
| @@ -7,6 +7,7 @@ import ( | |||||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | "github.com/bnema/vev/internal/protocol" | 9 | "github.com/bnema/vev/internal/protocol" | ||
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 10 | "github.com/bnema/vev/internal/usecase/command" | 11 | "github.com/bnema/vev/internal/usecase/command" | ||
| 11 | ) | 12 | ) | ||
| 12 | 13 | ||||
| @@ -75,7 +76,7 @@ func (d *Daemon) runConnLoop(ac *attachedClient) { | |||||
| 75 | } | 76 | } | ||
| 76 | 77 | ||||
| 77 | // handleAttachmentClientFrame owns the attached-client protocol. | 78 | // handleAttachmentClientFrame owns the attached-client protocol. | ||
| 78 | - | func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f ports.Frame) bool { | 79 | + | func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f wire.Frame) bool { |
| 79 | if !capability.current() { | 80 | if !capability.current() { | ||
| 80 | return false | 81 | return false | ||
| 81 | } | 82 | } | ||
| @@ -91,57 +92,57 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||||
| 91 | d.afterAttachmentEffectAdmitted(effect.capability()) | 92 | d.afterAttachmentEffectAdmitted(effect.capability()) | ||
| 92 | } | 93 | } | ||
| 93 | switch f.Type { | 94 | switch f.Type { | ||
| 94 | - | case ports.MsgInput: | 95 | + | case wire.MsgInput: |
| 95 | - | if in, derr := ports.UnmarshalInput(f.Payload); derr == nil { | 96 | + | if in, derr := wire.UnmarshalInput(f.Payload); derr == nil { |
| 96 | d.handleSequencedInputForAttachment(effect, in.InputSeq, in.Data) | 97 | d.handleSequencedInputForAttachment(effect, in.InputSeq, in.Data) | ||
| 97 | } | 98 | } | ||
| 98 | - | case ports.MsgResize: | 99 | + | case wire.MsgResize: |
| 99 | - | if rz, derr := ports.UnmarshalResize(f.Payload); derr == nil && effect.current() { | 100 | + | if rz, derr := wire.UnmarshalResize(f.Payload); derr == nil && effect.current() { |
| 100 | d.resizeAttachmentGeometryForLease(effect, rz.Geometry()) | 101 | d.resizeAttachmentGeometryForLease(effect, rz.Geometry()) | ||
| 101 | } | 102 | } | ||
| 102 | - | case ports.MsgTheme: | 103 | + | case wire.MsgTheme: |
| 103 | - | if th, derr := ports.UnmarshalTheme(f.Payload); derr == nil { | 104 | + | if th, derr := wire.UnmarshalTheme(f.Payload); derr == nil { |
| 104 | d.applyThemeForAttachment(effect, th) | 105 | d.applyThemeForAttachment(effect, th) | ||
| 105 | } | 106 | } | ||
| 106 | - | case ports.MsgImagePush: | 107 | + | case wire.MsgImagePush: |
| 107 | - | if ip, derr := ports.UnmarshalImagePush(f.Payload); derr == nil { | 108 | + | if ip, derr := wire.UnmarshalImagePush(f.Payload); derr == nil { |
| 108 | d.handleSequencedImagePushForAttachment(effect, ip.InputSeq, ip) | 109 | d.handleSequencedImagePushForAttachment(effect, ip.InputSeq, ip) | ||
| 109 | } | 110 | } | ||
| 110 | - | case ports.MsgClientNotice: | 111 | + | case wire.MsgClientNotice: |
| 111 | - | if notice, derr := ports.UnmarshalClientNotice(f.Payload); derr == nil { | 112 | + | if notice, derr := wire.UnmarshalClientNotice(f.Payload); derr == nil { |
| 112 | d.handleClientNoticeForAttachment(effect, notice) | 113 | d.handleClientNoticeForAttachment(effect, notice) | ||
| 113 | } else { | 114 | } else { | ||
| 114 | d.log.Warn("malformed client notice", "err", derr) | 115 | d.log.Warn("malformed client notice", "err", derr) | ||
| 115 | } | 116 | } | ||
| 116 | - | case ports.MsgDetach: | 117 | + | case wire.MsgDetach: |
| 117 | if effect.current() { | 118 | if effect.current() { | ||
| 118 | d.clientGoneForAttachment(effect, true) | 119 | d.clientGoneForAttachment(effect, true) | ||
| 119 | return true | 120 | return true | ||
| 120 | } | 121 | } | ||
| 121 | - | case ports.MsgAck: | 122 | + | case wire.MsgAck: |
| 122 | - | if ack, derr := ports.UnmarshalAck(f.Payload); derr == nil { | 123 | + | if ack, derr := wire.UnmarshalAck(f.Payload); derr == nil { |
| 123 | d.ackOutput(effect, ack.Epoch, ack.State) | 124 | d.ackOutput(effect, ack.Epoch, ack.State) | ||
| 124 | } | 125 | } | ||
| 125 | - | case ports.MsgOutputResetRequest: | 126 | + | case wire.MsgOutputResetRequest: |
| 126 | - | if _, derr := ports.UnmarshalOutputResetRequest(f.Payload); derr == nil { | 127 | + | if _, derr := wire.UnmarshalOutputResetRequest(f.Payload); derr == nil { |
| 127 | d.resetOutput(effect) | 128 | d.resetOutput(effect) | ||
| 128 | } | 129 | } | ||
| 129 | - | case ports.MsgSamePeerSwitchRequest: | 130 | + | case wire.MsgSamePeerSwitchRequest: |
| 130 | - | request, derr := ports.UnmarshalSamePeerSwitchRequest(f.Payload) | 131 | + | request, derr := wire.UnmarshalSamePeerSwitchRequest(f.Payload) |
| 131 | if derr != nil { | 132 | if derr != nil { | ||
| 132 | d.log.Warn("malformed same-peer switch request", "err", derr) | 133 | d.log.Warn("malformed same-peer switch request", "err", derr) | ||
| 133 | break | 134 | break | ||
| 134 | } | 135 | } | ||
| 135 | d.switchSamePeerForAttachment(effect, request) | 136 | d.switchSamePeerForAttachment(effect, request) | ||
| 136 | - | case ports.MsgParkedRouteRequest: | 137 | + | case wire.MsgParkedRouteRequest: |
| 137 | - | request, derr := ports.UnmarshalParkedRouteRequest(f.Payload) | 138 | + | request, derr := wire.UnmarshalParkedRouteRequest(f.Payload) |
| 138 | if derr != nil { | 139 | if derr != nil { | ||
| 139 | d.log.Warn("malformed parked-route request", "err", derr) | 140 | d.log.Warn("malformed parked-route request", "err", derr) | ||
| 140 | break | 141 | break | ||
| 141 | } | 142 | } | ||
| 142 | d.handleParkedRouteRequest(effect, request) | 143 | d.handleParkedRouteRequest(effect, request) | ||
| 143 | - | case ports.MsgRecentRouteSnapshot: | 144 | + | case wire.MsgRecentRouteSnapshot: |
| 144 | - | snapshot, derr := ports.UnmarshalRecentRouteSnapshot(f.Payload) | 145 | + | snapshot, derr := wire.UnmarshalRecentRouteSnapshot(f.Payload) |
| 145 | if derr != nil { | 146 | if derr != nil { | ||
| 146 | d.log.Warn("malformed recent route snapshot", "err", derr) | 147 | d.log.Warn("malformed recent route snapshot", "err", derr) | ||
| 147 | break | 148 | break | ||
| @@ -154,16 +155,16 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||||
| 154 | if err := d.sendCommittedRouteIdentityForAttachment(effect); err != nil { | 155 | if err := d.sendCommittedRouteIdentityForAttachment(effect); err != nil { | ||
| 155 | d.detachOnAttachmentSendError(effect.capability(), effect.transport.transport) | 156 | d.detachOnAttachmentSendError(effect.capability(), effect.transport.transport) | ||
| 156 | } | 157 | } | ||
| 157 | - | case ports.MsgRouteAttentionSubscription: | 158 | + | case wire.MsgRouteAttentionSubscription: |
| 158 | - | subscription, derr := ports.UnmarshalRouteAttentionSubscription(f.Payload) | 159 | + | subscription, derr := wire.UnmarshalRouteAttentionSubscription(f.Payload) |
| 159 | if derr != nil { | 160 | if derr != nil { | ||
| 160 | d.log.Warn("malformed route attention subscription", "err", derr) | 161 | d.log.Warn("malformed route attention subscription", "err", derr) | ||
| 161 | break | 162 | break | ||
| 162 | } | 163 | } | ||
| 163 | effect.ac.setRouteAttentionSubscription(subscription) | 164 | effect.ac.setRouteAttentionSubscription(subscription) | ||
| 164 | d.invalidateRender(effect.sess, effect.ac, false, "client_frame_routing.go:route-attention") | 165 | d.invalidateRender(effect.sess, effect.ac, false, "client_frame_routing.go:route-attention") | ||
| 165 | - | case ports.MsgRouteNavigationFailure: | 166 | + | case wire.MsgRouteNavigationFailure: |
| 166 | - | failure, derr := ports.UnmarshalRouteNavigationFailure(f.Payload) | 167 | + | failure, derr := wire.UnmarshalRouteNavigationFailure(f.Payload) |
| 167 | if derr != nil { | 168 | if derr != nil { | ||
| 168 | d.log.Warn("malformed route navigation failure", "err", derr) | 169 | d.log.Warn("malformed route navigation failure", "err", derr) | ||
| 169 | break | 170 | break | ||
| @@ -182,8 +183,8 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||||
| 182 | message = "that recent route no longer exists" | 183 | message = "that recent route no longer exists" | ||
| 183 | } | 184 | } | ||
| 184 | d.notify(effect.sess, domain.NoticeWarn, domain.NoticeSessionUnavailable, message, nil) | 185 | d.notify(effect.sess, domain.NoticeWarn, domain.NoticeSessionUnavailable, message, nil) | ||
| 185 | - | case ports.MsgCommand: | 186 | + | case wire.MsgCommand: |
| 186 | - | request, derr := ports.UnmarshalCommandRequest(f.Payload) | 187 | + | request, derr := wire.UnmarshalCommandRequest(f.Payload) |
| 187 | if derr != nil { | 188 | if derr != nil { | ||
| 188 | return false | 189 | return false | ||
| 189 | } | 190 | } | ||
| @@ -200,7 +201,7 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||||
| 200 | return true | 201 | return true | ||
| 201 | } | 202 | } | ||
| 202 | resultEffect.End() | 203 | resultEffect.End() | ||
| 203 | - | case ports.MsgPing: | 204 | + | case wire.MsgPing: |
| 204 | if err := effect.sendControl(framePong()); err != nil { | 205 | if err := effect.sendControl(framePong()); err != nil { | ||
| 205 | effect.End() | 206 | effect.End() | ||
| 206 | d.detachOnAttachmentSendError(effect.capability(), effect.transport.transport) | 207 | d.detachOnAttachmentSendError(effect.capability(), effect.transport.transport) | ||
M internal/usecase/daemon/clipboard_test.go +14 -13
| @@ -19,6 +19,7 @@ import ( | |||||
| 19 | "github.com/bnema/vev/internal/ports" | 19 | "github.com/bnema/vev/internal/ports" | ||
| 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 21 | "github.com/bnema/vev/internal/protocol" | 21 | "github.com/bnema/vev/internal/protocol" | ||
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 22 | scopy "github.com/bnema/vev/internal/usecase/copy" | 23 | scopy "github.com/bnema/vev/internal/usecase/copy" | ||
| 23 | ) | 24 | ) | ||
| 24 | 25 | ||||
| @@ -243,8 +244,8 @@ func TestPTYReaderForwardsOSC52ClipboardToAttachedClient(t *testing.T) { | |||||
| 243 | 244 | ||||
| 244 | var clipboardOutput string | 245 | var clipboardOutput string | ||
| 245 | for range 3 { | 246 | for range 3 { | ||
| 246 | - | f := awaitFrame(t, sends, ports.MsgOutput) | 247 | + | f := awaitFrame(t, sends, wire.MsgOutput) |
| 247 | - | out, err := ports.UnmarshalOutput(f.Payload) | 248 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 248 | require.NoError(t, err) | 249 | require.NoError(t, err) | ||
| 249 | clipboardOutput = string(out.Data) | 250 | clipboardOutput = string(out.Data) | ||
| 250 | if strings.Contains(clipboardOutput, "\x1b]52;c;aGVsbG8=\x07") { | 251 | if strings.Contains(clipboardOutput, "\x1b]52;c;aGVsbG8=\x07") { | ||
| @@ -276,7 +277,7 @@ func TestPTYReaderDropsOversizedClipboardPayload(t *testing.T) { | |||||
| 276 | 277 | ||||
| 277 | select { | 278 | select { | ||
| 278 | case f := <-sends: | 279 | case f := <-sends: | ||
| 279 | - | require.NotEqual(t, ports.MsgOutput, f.Type) | 280 | + | require.NotEqual(t, wire.MsgOutput, f.Type) |
| 280 | default: | 281 | default: | ||
| 281 | } | 282 | } | ||
| 282 | } | 283 | } | ||
| @@ -301,7 +302,7 @@ func TestPTYReaderDropsInvalidBase64Clipboard(t *testing.T) { | |||||
| 301 | 302 | ||||
| 302 | select { | 303 | select { | ||
| 303 | case f := <-sends: | 304 | case f := <-sends: | ||
| 304 | - | require.NotEqual(t, ports.MsgOutput, f.Type) | 305 | + | require.NotEqual(t, wire.MsgOutput, f.Type) |
| 305 | default: | 306 | default: | ||
| 306 | } | 307 | } | ||
| 307 | } | 308 | } | ||
| @@ -328,15 +329,15 @@ type staleClipboardErrorTransport struct { | |||||
| 328 | sends int | 329 | sends int | ||
| 329 | } | 330 | } | ||
| 330 | 331 | ||||
| 331 | - | func (t *staleClipboardErrorTransport) Send(ports.Frame) error { | 332 | + | func (t *staleClipboardErrorTransport) Send(wire.Frame) error { |
| 332 | t.mu.Lock() | 333 | t.mu.Lock() | ||
| 333 | t.sends++ | 334 | t.sends++ | ||
| 334 | t.mu.Unlock() | 335 | t.mu.Unlock() | ||
| 335 | return errors.New("stale clipboard send") | 336 | return errors.New("stale clipboard send") | ||
| 336 | } | 337 | } | ||
| 337 | 338 | ||||
| 338 | - | func (*staleClipboardErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 339 | + | func (*staleClipboardErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 339 | - | func (*staleClipboardErrorTransport) Close() error { return nil } | 340 | + | func (*staleClipboardErrorTransport) Close() error { return nil } |
| 340 | 341 | ||||
| 341 | func (t *staleClipboardErrorTransport) sendCount() int { | 342 | func (t *staleClipboardErrorTransport) sendCount() int { | ||
| 342 | t.mu.Lock() | 343 | t.mu.Lock() | ||
| @@ -383,13 +384,13 @@ func newMovingClipboardErrorTransport() *movingClipboardErrorTransport { | |||||
| 383 | } | 384 | } | ||
| 384 | } | 385 | } | ||
| 385 | 386 | ||||
| 386 | - | func (t *movingClipboardErrorTransport) Send(ports.Frame) error { | 387 | + | func (t *movingClipboardErrorTransport) Send(wire.Frame) error { |
| 387 | t.startedOnce.Do(func() { close(t.started) }) | 388 | t.startedOnce.Do(func() { close(t.started) }) | ||
| 388 | <-t.release | 389 | <-t.release | ||
| 389 | return errors.New("clipboard send failed after pane move") | 390 | return errors.New("clipboard send failed after pane move") | ||
| 390 | } | 391 | } | ||
| 391 | 392 | ||||
| 392 | - | func (*movingClipboardErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 393 | + | func (*movingClipboardErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 393 | 394 | ||||
| 394 | func (t *movingClipboardErrorTransport) Close() error { | 395 | func (t *movingClipboardErrorTransport) Close() error { | ||
| 395 | t.closeOnce.Do(func() { close(t.closed) }) | 396 | t.closeOnce.Do(func() { close(t.closed) }) | ||
| @@ -509,8 +510,8 @@ func newBlockingClipboardTransport() *blockingClipboardTransport { | |||||
| 509 | } | 510 | } | ||
| 510 | } | 511 | } | ||
| 511 | 512 | ||||
| 512 | - | func (tr *blockingClipboardTransport) Send(f ports.Frame) error { | 513 | + | func (tr *blockingClipboardTransport) Send(f wire.Frame) error { |
| 513 | - | out, err := ports.UnmarshalOutput(f.Payload) | 514 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 514 | if err != nil { | 515 | if err != nil { | ||
| 515 | return err | 516 | return err | ||
| 516 | } | 517 | } | ||
| @@ -532,5 +533,5 @@ func (tr *blockingClipboardTransport) Send(f ports.Frame) error { | |||||
| 532 | return nil | 533 | return nil | ||
| 533 | } | 534 | } | ||
| 534 | 535 | ||||
| 535 | - | func (tr *blockingClipboardTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 536 | + | func (tr *blockingClipboardTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 536 | - | func (tr *blockingClipboardTransport) Close() error { return nil } | 537 | + | func (tr *blockingClipboardTransport) Close() error { return nil } |
M internal/usecase/daemon/config_test.go +5 -5
| @@ -8,8 +8,8 @@ import ( | |||||
| 8 | 8 | ||||
| 9 | renderer "github.com/bnema/vev-vt" | 9 | renderer "github.com/bnema/vev-vt" | ||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | - | "github.com/bnema/vev/internal/ports" | |||
| 12 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | "github.com/bnema/vev/internal/usecase/keys" | 13 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 14 | themeui "github.com/bnema/vev/internal/usecase/theme" | 14 | themeui "github.com/bnema/vev/internal/usecase/theme" | ||
| 15 | ) | 15 | ) | ||
| @@ -318,11 +318,11 @@ func TestApplyConfigRepaintsActivePaletteWithoutReplacingModel(t *testing.T) { | |||||
| 318 | defer release() | 318 | defer release() | ||
| 319 | d, sess, ac, sends := newManualSessionWithPTYs(t, p) | 319 | d, sess, ac, sends := newManualSessionWithPTYs(t, p) | ||
| 320 | d.enterPalette(sess, ac) | 320 | d.enterPalette(sess, ac) | ||
| 321 | - | awaitFrame(t, sends, ports.MsgOutput) | 321 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 322 | d.handlePaletteInput(ac, []byte("new")) | 322 | d.handlePaletteInput(ac, []byte("new")) | ||
| 323 | - | awaitFrame(t, sends, ports.MsgOutput) | 323 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 324 | d.handlePaletteInput(ac, []byte{0x0e}) | 324 | d.handlePaletteInput(ac, []byte{0x0e}) | ||
| 325 | - | awaitFrame(t, sends, ports.MsgOutput) | 325 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 326 | 326 | ||||
| 327 | ac.overlays.paletteMu.Lock() | 327 | ac.overlays.paletteMu.Lock() | ||
| 328 | model := ac.overlays.palette | 328 | model := ac.overlays.palette | ||
| @@ -334,7 +334,7 @@ func TestApplyConfigRepaintsActivePaletteWithoutReplacingModel(t *testing.T) { | |||||
| 334 | cfg := domain.Defaults() | 334 | cfg := domain.Defaults() | ||
| 335 | cfg.Palette = domain.PaletteConfig{Anchor: domain.AnchorTopLeft, AnchorSet: true} | 335 | cfg.Palette = domain.PaletteConfig{Anchor: domain.AnchorTopLeft, AnchorSet: true} | ||
| 336 | d.ApplyConfig(cfg) | 336 | d.ApplyConfig(cfg) | ||
| 337 | - | awaitFrame(t, sends, ports.MsgOutput) | 337 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 338 | 338 | ||||
| 339 | ac.overlays.paletteMu.Lock() | 339 | ac.overlays.paletteMu.Lock() | ||
| 340 | defer ac.overlays.paletteMu.Unlock() | 340 | defer ac.overlays.paletteMu.Unlock() | ||
M internal/usecase/daemon/control.go +7 -6
| @@ -13,19 +13,20 @@ import ( | |||||
| 13 | "github.com/bnema/vev/internal/domain" | 13 | "github.com/bnema/vev/internal/domain" | ||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | "github.com/bnema/vev/internal/protocol" | 15 | "github.com/bnema/vev/internal/protocol" | ||
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | "github.com/bnema/vev/internal/usecase/command" | 17 | "github.com/bnema/vev/internal/usecase/command" | ||
| 17 | "github.com/bnema/vev/internal/usecase/layout" | 18 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 18 | ) | 19 | ) | ||
| 19 | 20 | ||||
| 20 | // handleCommand serves one one-shot control request. The leading version is | 21 | // handleCommand serves one one-shot control request. The leading version is | ||
| 21 | // checked before decoding the versioned body so newer layouts fail cleanly. | 22 | // checked before decoding the versioned body so newer layouts fail cleanly. | ||
| 22 | - | func (d *Daemon) handleCommand(tr ports.Transport, f ports.Frame) error { | 23 | + | func (d *Daemon) handleCommand(tr ports.Transport, f wire.Frame) error { |
| 23 | defer func() { _ = tr.Close() }() | 24 | defer func() { _ = tr.Close() }() | ||
| 24 | 25 | ||||
| 25 | - | if version, ok := ports.PeekCommandVersion(f.Payload); !ok || version != protocol.Version { | 26 | + | if version, ok := wire.PeekCommandVersion(f.Payload); !ok || version != protocol.Version { |
| 26 | return d.sendCommandResult(tr, protocol.CommandResult{Code: protocol.ErrVersionMismatch, Text: "protocol version mismatch"}) | 27 | return d.sendCommandResult(tr, protocol.CommandResult{Code: protocol.ErrVersionMismatch, Text: "protocol version mismatch"}) | ||
| 27 | } | 28 | } | ||
| 28 | - | request, err := ports.UnmarshalCommandRequest(f.Payload) | 29 | + | request, err := wire.UnmarshalCommandRequest(f.Payload) |
| 29 | if err != nil { | 30 | if err != nil { | ||
| 30 | return d.sendCommandResult(tr, protocol.CommandResult{Code: protocol.ErrInternal, Text: "malformed command request"}) | 31 | return d.sendCommandResult(tr, protocol.CommandResult{Code: protocol.ErrInternal, Text: "malformed command request"}) | ||
| 31 | } | 32 | } | ||
| @@ -79,7 +80,7 @@ func (d *Daemon) sendCommandResult(tr ports.Transport, result protocol.CommandRe | |||||
| 79 | // boundedControlSend keeps one-shot control handlers from waiting forever on a | 80 | // boundedControlSend keeps one-shot control handlers from waiting forever on a | ||
| 80 | // client that stopped reading. A timeout closes the exact transport so a | 81 | // client that stopped reading. A timeout closes the exact transport so a | ||
| 81 | // blocked Send can unwind before the handler returns. | 82 | // blocked Send can unwind before the handler returns. | ||
| 82 | - | func (d *Daemon) boundedControlSend(tr ports.Transport, frame ports.Frame) error { | 83 | + | func (d *Daemon) boundedControlSend(tr ports.Transport, frame wire.Frame) error { |
| 83 | _, err := d.boundedSendWith(tr, func() error { return tr.Send(frame) }) | 84 | _, err := d.boundedSendWith(tr, func() error { return tr.Send(frame) }) | ||
| 84 | if errors.Is(err, errSendTimedOut) { | 85 | if errors.Is(err, errSendTimedOut) { | ||
| 85 | _ = tr.Close() | 86 | _ = tr.Close() | ||
| @@ -87,8 +88,8 @@ func (d *Daemon) boundedControlSend(tr ports.Transport, frame ports.Frame) error | |||||
| 87 | return err | 88 | return err | ||
| 88 | } | 89 | } | ||
| 89 | 90 | ||||
| 90 | - | func frameCommandResult(result protocol.CommandResult) ports.Frame { | 91 | + | func frameCommandResult(result protocol.CommandResult) wire.Frame { |
| 91 | - | return ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(result)} | 92 | + | return wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(result)} |
| 92 | } | 93 | } | ||
| 93 | 94 | ||||
| 94 | func (d *Daemon) dispatchCommand(ctx context.Context, request protocol.CommandRequest) protocol.CommandResult { | 95 | func (d *Daemon) dispatchCommand(ctx context.Context, request protocol.CommandRequest) protocol.CommandResult { | ||
M internal/usecase/daemon/control_test.go +16 -15
| @@ -17,6 +17,7 @@ import ( | |||||
| 17 | "github.com/bnema/vev/internal/ports" | 17 | "github.com/bnema/vev/internal/ports" | ||
| 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 19 | "github.com/bnema/vev/internal/protocol" | 19 | "github.com/bnema/vev/internal/protocol" | ||
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 20 | "github.com/bnema/vev/internal/usecase/command" | 21 | "github.com/bnema/vev/internal/usecase/command" | ||
| 21 | "github.com/bnema/vev/internal/usecase/layout" | 22 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 22 | "github.com/stretchr/testify/require" | 23 | "github.com/stretchr/testify/require" | ||
| @@ -196,7 +197,7 @@ func TestHandleCommandAttachedRejectionReturnsSendFailure(t *testing.T) { | |||||
| 196 | func TestHandleCommandRejectsVersionBeforeDecodeOrDispatch(t *testing.T) { | 197 | func TestHandleCommandRejectsVersionBeforeDecodeOrDispatch(t *testing.T) { | ||
| 197 | // The version prefix is valid and mismatched, while the remainder is not a | 198 | // The version prefix is valid and mismatched, while the remainder is not a | ||
| 198 | // decodable request. The daemon must still return ErrVersionMismatch. | 199 | // decodable request. The daemon must still return ErrVersionMismatch. | ||
| 199 | - | frame := ports.Frame{Type: ports.MsgCommand, Payload: []byte{0, byte(protocol.Version + 1)}} | 200 | + | frame := wire.Frame{Type: wire.MsgCommand, Payload: []byte{0, byte(protocol.Version + 1)}} |
| 200 | tr, sends, _ := newConn(t, frame) | 201 | tr, sends, _ := newConn(t, frame) | ||
| 201 | 202 | ||||
| 202 | d := newTestDaemon(t, nil, stubClock{}) | 203 | d := newTestDaemon(t, nil, stubClock{}) | ||
| @@ -210,9 +211,9 @@ func TestHandleCommandRejectsVersionBeforeDecodeOrDispatch(t *testing.T) { | |||||
| 210 | func TestHandleConnRoutesCommand(t *testing.T) { | 211 | func TestHandleConnRoutesCommand(t *testing.T) { | ||
| 211 | d := newTestDaemon(t, nil, stubClock{}) | 212 | d := newTestDaemon(t, nil, stubClock{}) | ||
| 212 | request := protocol.CommandRequest{Version: protocol.Version, Slug: "list-sessions"} | 213 | request := protocol.CommandRequest{Version: protocol.Version, Slug: "list-sessions"} | ||
| 213 | - | payload, err := ports.MarshalCommandRequest(request) | 214 | + | payload, err := wire.MarshalCommandRequest(request) |
| 214 | require.NoError(t, err) | 215 | require.NoError(t, err) | ||
| 215 | - | frame := ports.Frame{Type: ports.MsgCommand, Payload: payload} | 216 | + | frame := wire.Frame{Type: wire.MsgCommand, Payload: payload} |
| 216 | tr, sends, _ := newConn(t, frame) | 217 | tr, sends, _ := newConn(t, frame) | ||
| 217 | 218 | ||||
| 218 | d.handleConn(tr) | 219 | d.handleConn(tr) | ||
| @@ -1299,7 +1300,7 @@ func TestHandleCommandOppositeMoveCommandsDoNotDeadlock(t *testing.T) { | |||||
| 1299 | done <- struct{}{} | 1300 | done <- struct{}{} | ||
| 1300 | }() | 1301 | }() | ||
| 1301 | close(start) | 1302 | close(start) | ||
| 1302 | - | for _, sends := range []chan ports.Frame{leftSends, rightSends} { | 1303 | + | for _, sends := range []chan wire.Frame{leftSends, rightSends} { |
| 1303 | select { | 1304 | select { | ||
| 1304 | case <-done: | 1305 | case <-done: | ||
| 1305 | result := awaitCommandResult(t, sends) | 1306 | result := awaitCommandResult(t, sends) | ||
| @@ -1324,14 +1325,14 @@ func addNamedMoveDestination(d *Daemon, name, tabID, paneID string) *session { | |||||
| 1324 | return sess | 1325 | return sess | ||
| 1325 | } | 1326 | } | ||
| 1326 | 1327 | ||||
| 1327 | - | func commandFrame(t *testing.T, request protocol.CommandRequest) ports.Frame { | 1328 | + | func commandFrame(t *testing.T, request protocol.CommandRequest) wire.Frame { |
| 1328 | t.Helper() | 1329 | t.Helper() | ||
| 1329 | if request.Version == 0 { | 1330 | if request.Version == 0 { | ||
| 1330 | request.Version = protocol.Version | 1331 | request.Version = protocol.Version | ||
| 1331 | } | 1332 | } | ||
| 1332 | - | payload, err := ports.MarshalCommandRequest(request) | 1333 | + | payload, err := wire.MarshalCommandRequest(request) |
| 1333 | require.NoError(t, err) | 1334 | require.NoError(t, err) | ||
| 1334 | - | return ports.Frame{Type: ports.MsgCommand, Payload: payload} | 1335 | + | return wire.Frame{Type: wire.MsgCommand, Payload: payload} |
| 1335 | } | 1336 | } | ||
| 1336 | 1337 | ||||
| 1337 | func sendCommand(t *testing.T, d *Daemon, request protocol.CommandRequest) protocol.CommandResult { | 1338 | func sendCommand(t *testing.T, d *Daemon, request protocol.CommandRequest) protocol.CommandResult { | ||
| @@ -1342,10 +1343,10 @@ func sendCommand(t *testing.T, d *Daemon, request protocol.CommandRequest) proto | |||||
| 1342 | return awaitCommandResult(t, sends) | 1343 | return awaitCommandResult(t, sends) | ||
| 1343 | } | 1344 | } | ||
| 1344 | 1345 | ||||
| 1345 | - | func awaitCommandResult(t *testing.T, sends chan ports.Frame) protocol.CommandResult { | 1346 | + | func awaitCommandResult(t *testing.T, sends chan wire.Frame) protocol.CommandResult { |
| 1346 | t.Helper() | 1347 | t.Helper() | ||
| 1347 | - | reply := awaitFrame(t, sends, ports.MsgCommandResult) | 1348 | + | reply := awaitFrame(t, sends, wire.MsgCommandResult) |
| 1348 | - | result, err := ports.UnmarshalCommandResult(reply.Payload) | 1349 | + | result, err := wire.UnmarshalCommandResult(reply.Payload) |
| 1349 | require.NoError(t, err) | 1350 | require.NoError(t, err) | ||
| 1350 | return result | 1351 | return result | ||
| 1351 | } | 1352 | } | ||
| @@ -1397,13 +1398,13 @@ func newBlockingControlSendTransport() *blockingControlSendTransport { | |||||
| 1397 | return &blockingControlSendTransport{started: make(chan struct{}), closed: make(chan struct{})} | 1398 | return &blockingControlSendTransport{started: make(chan struct{}), closed: make(chan struct{})} | ||
| 1398 | } | 1399 | } | ||
| 1399 | 1400 | ||||
| 1400 | - | func (tr *blockingControlSendTransport) Send(ports.Frame) error { | 1401 | + | func (tr *blockingControlSendTransport) Send(wire.Frame) error { |
| 1401 | tr.once.Do(func() { close(tr.started) }) | 1402 | tr.once.Do(func() { close(tr.started) }) | ||
| 1402 | <-tr.closed | 1403 | <-tr.closed | ||
| 1403 | return io.ErrClosedPipe | 1404 | return io.ErrClosedPipe | ||
| 1404 | } | 1405 | } | ||
| 1405 | 1406 | ||||
| 1406 | - | func (*blockingControlSendTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 1407 | + | func (*blockingControlSendTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 1407 | func (tr *blockingControlSendTransport) Close() error { | 1408 | func (tr *blockingControlSendTransport) Close() error { | ||
| 1408 | tr.once.Do(func() { close(tr.started) }) | 1409 | tr.once.Do(func() { close(tr.started) }) | ||
| 1409 | select { | 1410 | select { | ||
| @@ -1419,9 +1420,9 @@ type commandSendErrorTransport struct { | |||||
| 1419 | closed bool | 1420 | closed bool | ||
| 1420 | } | 1421 | } | ||
| 1421 | 1422 | ||||
| 1422 | - | func (tr *commandSendErrorTransport) Send(ports.Frame) error { return tr.err } | 1423 | + | func (tr *commandSendErrorTransport) Send(wire.Frame) error { return tr.err } |
| 1423 | - | func (*commandSendErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 1424 | + | func (*commandSendErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 1424 | - | func (tr *commandSendErrorTransport) Close() error { tr.closed = true; return nil } | 1425 | + | func (tr *commandSendErrorTransport) Close() error { tr.closed = true; return nil } |
| 1425 | 1426 | ||||
| 1426 | func addControlSession(d *Daemon, name, tabID, paneID string) *session { | 1427 | func addControlSession(d *Daemon, name, tabID, paneID string) *session { | ||
| 1427 | tb := newTabWithStableID(tabID, paneID, newQuietPTY(), domain.Size{Cols: 80, Rows: 22}) | 1428 | tb := newTabWithStableID(tabID, paneID, newQuietPTY(), domain.Size{Cols: 80, Rows: 22}) | ||
M internal/usecase/daemon/copymode_test.go +72 -71
| @@ -19,6 +19,7 @@ import ( | |||||
| 19 | "github.com/bnema/vev/internal/ports" | 19 | "github.com/bnema/vev/internal/ports" | ||
| 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 21 | "github.com/bnema/vev/internal/protocol" | 21 | "github.com/bnema/vev/internal/protocol" | ||
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 22 | scopy "github.com/bnema/vev/internal/usecase/copy" | 23 | scopy "github.com/bnema/vev/internal/usecase/copy" | ||
| 23 | "github.com/bnema/vev/internal/usecase/layout" | 24 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 24 | "github.com/bnema/vev/internal/usecase/ui" | 25 | "github.com/bnema/vev/internal/usecase/ui" | ||
| @@ -47,7 +48,7 @@ func TestOwnedSynchronousSendReturnsCapturedTransportAcrossReplacement(t *testin | |||||
| 47 | replacement := &closeTrackingTransport{} | 48 | replacement := &closeTrackingTransport{} | ||
| 48 | sendErr := errors.New("owned send failed") | 49 | sendErr := errors.New("owned send failed") | ||
| 49 | ac := &attachedClient{output: newOutputStateStream()} | 50 | ac := &attachedClient{output: newOutputStateStream()} | ||
| 50 | - | failed := &ownedSwapErrorTransport{ac: ac, replacement: replacement, err: sendErr, sent: make(chan ports.Frame, 1)} | 51 | + | failed := &ownedSwapErrorTransport{ac: ac, replacement: replacement, err: sendErr, sent: make(chan wire.Frame, 1)} |
| 51 | ac.replaceTransport(failed) | 52 | ac.replaceTransport(failed) | ||
| 52 | sess := &session{sessionCore: sessionCore{name: "work", attachments: map[*attachedClient]struct{}{ac: {}}}} | 53 | sess := &session{sessionCore: sessionCore{name: "work", attachments: map[*attachedClient]struct{}{ac: {}}}} | ||
| 53 | ac.setSession(sess) | 54 | ac.setSession(sess) | ||
| @@ -57,7 +58,7 @@ func TestOwnedSynchronousSendReturnsCapturedTransportAcrossReplacement(t *testin | |||||
| 57 | require.ErrorIs(t, err, sendErr) | 58 | require.ErrorIs(t, err, sendErr) | ||
| 58 | require.Same(t, failed, used) | 59 | require.Same(t, failed, used) | ||
| 59 | require.Same(t, replacement, ac.transport()) | 60 | require.Same(t, replacement, ac.transport()) | ||
| 60 | - | out, decodeErr := ports.UnmarshalOutput((<-failed.sent).Payload) | 61 | + | out, decodeErr := wire.UnmarshalOutput((<-failed.sent).Payload) |
| 61 | require.NoError(t, decodeErr) | 62 | require.NoError(t, decodeErr) | ||
| 62 | require.Equal(t, []byte("copy"), out.Data) | 63 | require.Equal(t, []byte("copy"), out.Data) | ||
| 63 | d.detachOnSendError(sess, ac, used) | 64 | d.detachOnSendError(sess, ac, used) | ||
| @@ -71,29 +72,29 @@ type swapErrorTransport struct { | |||||
| 71 | err error | 72 | err error | ||
| 72 | } | 73 | } | ||
| 73 | 74 | ||||
| 74 | - | func (t *swapErrorTransport) Send(ports.Frame) error { | 75 | + | func (t *swapErrorTransport) Send(wire.Frame) error { |
| 75 | t.ac.replaceTransport(t.replacement) | 76 | t.ac.replaceTransport(t.replacement) | ||
| 76 | return t.err | 77 | return t.err | ||
| 77 | } | 78 | } | ||
| 78 | 79 | ||||
| 79 | - | func (t *swapErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 80 | + | func (t *swapErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 80 | - | func (t *swapErrorTransport) Close() error { return nil } | 81 | + | func (t *swapErrorTransport) Close() error { return nil } |
| 81 | 82 | ||||
| 82 | type ownedSwapErrorTransport struct { | 83 | type ownedSwapErrorTransport struct { | ||
| 83 | ac *attachedClient | 84 | ac *attachedClient | ||
| 84 | replacement ports.Transport | 85 | replacement ports.Transport | ||
| 85 | err error | 86 | err error | ||
| 86 | - | sent chan ports.Frame | 87 | + | sent chan wire.Frame |
| 87 | } | 88 | } | ||
| 88 | 89 | ||||
| 89 | - | func (t *ownedSwapErrorTransport) Send(f ports.Frame) error { return t.SendSynchronous(f) } | 90 | + | func (t *ownedSwapErrorTransport) Send(f wire.Frame) error { return t.SendSynchronous(f) } |
| 90 | - | func (t *ownedSwapErrorTransport) SendSynchronous(f ports.Frame) error { | 91 | + | func (t *ownedSwapErrorTransport) SendSynchronous(f wire.Frame) error { |
| 91 | t.sent <- f | 92 | t.sent <- f | ||
| 92 | t.ac.replaceTransport(t.replacement) | 93 | t.ac.replaceTransport(t.replacement) | ||
| 93 | return t.err | 94 | return t.err | ||
| 94 | } | 95 | } | ||
| 95 | - | func (t *ownedSwapErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 96 | + | func (t *ownedSwapErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 96 | - | func (t *ownedSwapErrorTransport) Close() error { return nil } | 97 | + | func (t *ownedSwapErrorTransport) Close() error { return nil } |
| 97 | 98 | ||||
| 98 | // stubClock returns timers whose channel never fires, so a scheduler under it | 99 | // stubClock returns timers whose channel never fires, so a scheduler under it | ||
| 99 | // blocks in its debounce loop until the session context is cancelled. Used by | 100 | // blocks in its debounce loop until the session context is cancelled. Used by | ||
| @@ -117,7 +118,7 @@ func TestCopyModeDocumentCarriesPaneRowIDs(t *testing.T) { | |||||
| 117 | require.NotEqual(t, historyID, liveID) | 118 | require.NotEqual(t, historyID, liveID) | ||
| 118 | 119 | ||||
| 119 | d.enterCopyMode(sess, ac) | 120 | d.enterCopyMode(sess, ac) | ||
| 120 | - | awaitFrame(t, sends, ports.MsgOutput) | 121 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 121 | doc := ac.overlays.copyDocument | 122 | doc := ac.overlays.copyDocument | ||
| 122 | 123 | ||||
| 123 | require.Equal(t, 0, doc.FindRowID(historyID)) | 124 | require.Equal(t, 0, doc.FindRowID(historyID)) | ||
| @@ -197,7 +198,7 @@ func TestCopyModePaletteCommandEntersAndDoesNotForward(t *testing.T) { | |||||
| 197 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | 198 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | ||
| 198 | 199 | ||||
| 199 | d.handleInput(sess, ac, []byte("\x1b ")) | 200 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 200 | - | awaitFrame(t, sends, ports.MsgOutput) | 201 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 201 | d.handleInput(sess, ac, []byte("VIS\r")) | 202 | d.handleInput(sess, ac, []byte("VIS\r")) | ||
| 202 | 203 | ||||
| 203 | if ac.overlays.copyMode == nil { | 204 | if ac.overlays.copyMode == nil { | ||
| @@ -208,16 +209,16 @@ func TestCopyModePaletteCommandEntersAndDoesNotForward(t *testing.T) { | |||||
| 208 | t.Fatalf("scrollback binding forwarded to PTY: %q", got) | 209 | t.Fatalf("scrollback binding forwarded to PTY: %q", got) | ||
| 209 | default: | 210 | default: | ||
| 210 | } | 211 | } | ||
| 211 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 212 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 212 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 213 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 213 | require.NoError(t, err) | 214 | require.NoError(t, err) | ||
| 214 | if got := string(msg.Data); !strings.Contains(got, "[SCROLL]") || strings.Contains(got, "[SELECT]") || strings.Contains(got, "[COPY]") { | 215 | if got := string(msg.Data); !strings.Contains(got, "[SCROLL]") || strings.Contains(got, "[SELECT]") || strings.Contains(got, "[COPY]") { | ||
| 215 | t.Fatalf("passive scrollback paint = %q, want [SCROLL] without [SELECT]/[COPY]", got) | 216 | t.Fatalf("passive scrollback paint = %q, want [SCROLL] without [SELECT]/[COPY]", got) | ||
| 216 | } | 217 | } | ||
| 217 | 218 | ||||
| 218 | d.handleInput(sess, ac, []byte(" ")) | 219 | d.handleInput(sess, ac, []byte(" ")) | ||
| 219 | - | out = awaitFrame(t, sends, ports.MsgOutput) | 220 | + | out = awaitFrame(t, sends, wire.MsgOutput) |
| 220 | - | msg, err = ports.UnmarshalOutput(out.Payload) | 221 | + | msg, err = wire.UnmarshalOutput(out.Payload) |
| 221 | require.NoError(t, err) | 222 | require.NoError(t, err) | ||
| 222 | if got := string(msg.Data); !strings.Contains(got, "[SELECT]") || strings.Contains(got, "[SCROLL]") { | 223 | if got := string(msg.Data); !strings.Contains(got, "[SELECT]") || strings.Contains(got, "[SCROLL]") { | ||
| 223 | t.Fatalf("visual selection paint = %q, want [SELECT] without [SCROLL]", got) | 224 | t.Fatalf("visual selection paint = %q, want [SELECT] without [SCROLL]", got) | ||
| @@ -233,9 +234,9 @@ func TestCopyModeSearchModalRoutesBatchedInputAfterSlash(t *testing.T) { | |||||
| 233 | copy(pane.screen.Frame.Row(1), testRow("beta alpha")) | 234 | copy(pane.screen.Frame.Row(1), testRow("beta alpha")) | ||
| 234 | 235 | ||||
| 235 | d.enterCopyMode(sess, ac) | 236 | d.enterCopyMode(sess, ac) | ||
| 236 | - | awaitFrame(t, sends, ports.MsgOutput) | 237 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 237 | d.handleInput(sess, ac, []byte("/alpha\r")) | 238 | d.handleInput(sess, ac, []byte("/alpha\r")) | ||
| 238 | - | awaitFrame(t, sends, ports.MsgOutput) | 239 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 239 | 240 | ||||
| 240 | require.Nil(t, ac.overlays.copySearch) | 241 | require.Nil(t, ac.overlays.copySearch) | ||
| 241 | require.NotNil(t, ac.overlays.copyMode) | 242 | require.NotNil(t, ac.overlays.copyMode) | ||
| @@ -257,32 +258,32 @@ func TestCopyModeSearchModalJumpsAndKeepsNavigation(t *testing.T) { | |||||
| 257 | copy(pane.screen.Frame.Row(2), testRow("gamma")) | 258 | copy(pane.screen.Frame.Row(2), testRow("gamma")) | ||
| 258 | 259 | ||||
| 259 | d.enterCopyMode(sess, ac) | 260 | d.enterCopyMode(sess, ac) | ||
| 260 | - | awaitFrame(t, sends, ports.MsgOutput) | 261 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 261 | d.handleInput(sess, ac, []byte("/")) | 262 | d.handleInput(sess, ac, []byte("/")) | ||
| 262 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 263 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 263 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 264 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 264 | require.NoError(t, err) | 265 | require.NoError(t, err) | ||
| 265 | require.Contains(t, string(msg.Data), "Search") | 266 | require.Contains(t, string(msg.Data), "Search") | ||
| 266 | require.NotNil(t, ac.overlays.copySearch) | 267 | require.NotNil(t, ac.overlays.copySearch) | ||
| 267 | 268 | ||||
| 268 | d.handleInput(sess, ac, []byte("alpha")) | 269 | d.handleInput(sess, ac, []byte("alpha")) | ||
| 269 | - | out = awaitFrame(t, sends, ports.MsgOutput) | 270 | + | out = awaitFrame(t, sends, wire.MsgOutput) |
| 270 | - | msg, err = ports.UnmarshalOutput(out.Payload) | 271 | + | msg, err = wire.UnmarshalOutput(out.Payload) |
| 271 | require.NoError(t, err) | 272 | require.NoError(t, err) | ||
| 272 | require.Contains(t, string(msg.Data), "/alpha") | 273 | require.Contains(t, string(msg.Data), "/alpha") | ||
| 273 | require.Contains(t, string(msg.Data), "1:1 alpha") | 274 | require.Contains(t, string(msg.Data), "1:1 alpha") | ||
| 274 | require.Contains(t, string(msg.Data), "2:6 beta alpha") | 275 | require.Contains(t, string(msg.Data), "2:6 beta alpha") | ||
| 275 | 276 | ||||
| 276 | d.handleInput(sess, ac, []byte("\r")) | 277 | d.handleInput(sess, ac, []byte("\r")) | ||
| 277 | - | awaitFrame(t, sends, ports.MsgOutput) | 278 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 278 | require.Nil(t, ac.overlays.copySearch) | 279 | require.Nil(t, ac.overlays.copySearch) | ||
| 279 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row) | 280 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row) | ||
| 280 | 281 | ||||
| 281 | d.handleInput(sess, ac, []byte("n")) | 282 | d.handleInput(sess, ac, []byte("n")) | ||
| 282 | - | awaitFrame(t, sends, ports.MsgOutput) | 283 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 283 | require.Equal(t, 1, ac.overlays.copyMode.Cursor().Row) | 284 | require.Equal(t, 1, ac.overlays.copyMode.Cursor().Row) | ||
| 284 | d.handleInput(sess, ac, []byte("N")) | 285 | d.handleInput(sess, ac, []byte("N")) | ||
| 285 | - | awaitFrame(t, sends, ports.MsgOutput) | 286 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 286 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row) | 287 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row) | ||
| 287 | 288 | ||||
| 288 | select { | 289 | select { | ||
| @@ -301,17 +302,17 @@ func TestCopyModeSearchModalSelectionPreviewsBehindModal(t *testing.T) { | |||||
| 301 | copy(pane.screen.Frame.Row(2), testRow("gamma")) | 302 | copy(pane.screen.Frame.Row(2), testRow("gamma")) | ||
| 302 | 303 | ||||
| 303 | d.enterCopyMode(sess, ac) | 304 | d.enterCopyMode(sess, ac) | ||
| 304 | - | awaitFrame(t, sends, ports.MsgOutput) | 305 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 305 | 306 | ||||
| 306 | d.handleInput(sess, ac, []byte("/")) | 307 | d.handleInput(sess, ac, []byte("/")) | ||
| 307 | - | awaitFrame(t, sends, ports.MsgOutput) | 308 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 308 | d.handleInput(sess, ac, []byte("alpha")) | 309 | d.handleInput(sess, ac, []byte("alpha")) | ||
| 309 | - | awaitFrame(t, sends, ports.MsgOutput) | 310 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 310 | require.NotNil(t, ac.overlays.copySearch) | 311 | require.NotNil(t, ac.overlays.copySearch) | ||
| 311 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row, "typing a query previews the selected first result behind the modal") | 312 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row, "typing a query previews the selected first result behind the modal") | ||
| 312 | 313 | ||||
| 313 | d.handleInput(sess, ac, []byte{0x0e}) | 314 | d.handleInput(sess, ac, []byte{0x0e}) | ||
| 314 | - | awaitFrame(t, sends, ports.MsgOutput) | 315 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 315 | require.NotNil(t, ac.overlays.copySearch) | 316 | require.NotNil(t, ac.overlays.copySearch) | ||
| 316 | require.Equal(t, 1, ac.overlays.copyMode.Cursor().Row, "moving modal selection previews that result without Enter") | 317 | require.Equal(t, 1, ac.overlays.copyMode.Cursor().Row, "moving modal selection previews that result without Enter") | ||
| 317 | } | 318 | } | ||
| @@ -325,9 +326,9 @@ func TestCopyModeSearchModalCapturesMouseAndClearsOnExit(t *testing.T) { | |||||
| 325 | copy(pane.screen.Frame.Row(0), testRow("live alpha")) | 326 | copy(pane.screen.Frame.Row(0), testRow("live alpha")) | ||
| 326 | 327 | ||||
| 327 | d.enterCopyMode(sess, ac) | 328 | d.enterCopyMode(sess, ac) | ||
| 328 | - | awaitFrame(t, sends, ports.MsgOutput) | 329 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 329 | d.handleInput(sess, ac, []byte("/alpha")) | 330 | d.handleInput(sess, ac, []byte("/alpha")) | ||
| 330 | - | awaitFrame(t, sends, ports.MsgOutput) | 331 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 331 | require.NotNil(t, ac.overlays.copySearch) | 332 | require.NotNil(t, ac.overlays.copySearch) | ||
| 332 | cursor := ac.overlays.copyMode.Cursor().Row | 333 | cursor := ac.overlays.copyMode.Cursor().Row | ||
| 333 | 334 | ||||
| @@ -336,11 +337,11 @@ func TestCopyModeSearchModalCapturesMouseAndClearsOnExit(t *testing.T) { | |||||
| 336 | require.Equal(t, cursor, ac.overlays.copyMode.Cursor().Row) | 337 | require.Equal(t, cursor, ac.overlays.copyMode.Cursor().Row) | ||
| 337 | 338 | ||||
| 338 | d.handleInput(sess, ac, []byte("\x1b")) | 339 | d.handleInput(sess, ac, []byte("\x1b")) | ||
| 339 | - | awaitFrame(t, sends, ports.MsgOutput) | 340 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 340 | require.Nil(t, ac.overlays.copySearch) | 341 | require.Nil(t, ac.overlays.copySearch) | ||
| 341 | require.NotNil(t, ac.overlays.copyMode) | 342 | require.NotNil(t, ac.overlays.copyMode) | ||
| 342 | d.handleInput(sess, ac, []byte("q")) | 343 | d.handleInput(sess, ac, []byte("q")) | ||
| 343 | - | awaitFrame(t, sends, ports.MsgOutput) | 344 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 344 | require.Nil(t, ac.overlays.copySearch) | 345 | require.Nil(t, ac.overlays.copySearch) | ||
| 345 | require.Nil(t, ac.overlays.copyMode) | 346 | require.Nil(t, ac.overlays.copyMode) | ||
| 346 | } | 347 | } | ||
| @@ -355,7 +356,7 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||||
| 355 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | 356 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | ||
| 356 | 357 | ||||
| 357 | d.enterCopyMode(sess, ac) | 358 | d.enterCopyMode(sess, ac) | ||
| 358 | - | awaitFrame(t, sends, ports.MsgOutput) | 359 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 359 | d.handleInput(sess, ac, []byte{'g', ' ', 'j', 'y'}) | 360 | d.handleInput(sess, ac, []byte{'g', ' ', 'j', 'y'}) | ||
| 360 | 361 | ||||
| 361 | select { | 362 | select { | ||
| @@ -363,8 +364,8 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||||
| 363 | t.Fatalf("copy-mode navigation forwarded to PTY: %q", got) | 364 | t.Fatalf("copy-mode navigation forwarded to PTY: %q", got) | ||
| 364 | default: | 365 | default: | ||
| 365 | } | 366 | } | ||
| 366 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 367 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 367 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 368 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 368 | require.NoError(t, err) | 369 | require.NoError(t, err) | ||
| 369 | if got, want := string(msg.Data), "\x1b]52;c;b2xkMQpvbGQy\x07"; got != want { | 370 | if got, want := string(msg.Data), "\x1b]52;c;b2xkMQpvbGQy\x07"; got != want { | ||
| 370 | t.Fatalf("OSC52 = %q, want %q", got, want) | 371 | t.Fatalf("OSC52 = %q, want %q", got, want) | ||
| @@ -372,8 +373,8 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||||
| 372 | if ac.overlays.copyMode != nil { | 373 | if ac.overlays.copyMode != nil { | ||
| 373 | t.Fatal("copy mode still active after yank") | 374 | t.Fatal("copy mode still active after yank") | ||
| 374 | } | 375 | } | ||
| 375 | - | live := awaitFrame(t, sends, ports.MsgOutput) | 376 | + | live := awaitFrame(t, sends, wire.MsgOutput) |
| 376 | - | liveMsg, err := ports.UnmarshalOutput(live.Payload) | 377 | + | liveMsg, err := wire.UnmarshalOutput(live.Payload) |
| 377 | require.NoError(t, err) | 378 | require.NoError(t, err) | ||
| 378 | if strings.Contains(string(liveMsg.Data), "[COPY]") || strings.Contains(string(liveMsg.Data), "[SCROLL]") { | 379 | if strings.Contains(string(liveMsg.Data), "[COPY]") || strings.Contains(string(liveMsg.Data), "[SCROLL]") { | ||
| 379 | t.Fatalf("live repaint still contains copy/scroll status: %q", string(liveMsg.Data)) | 380 | t.Fatalf("live repaint still contains copy/scroll status: %q", string(liveMsg.Data)) | ||
| @@ -386,8 +387,8 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||||
| 386 | } | 387 | } | ||
| 387 | 388 | ||||
| 388 | d.paint(sess, ac, true, nil) | 389 | d.paint(sess, ac, true, nil) | ||
| 389 | - | followup := awaitFrame(t, sends, ports.MsgOutput) | 390 | + | followup := awaitFrame(t, sends, wire.MsgOutput) |
| 390 | - | followupMsg, err := ports.UnmarshalOutput(followup.Payload) | 391 | + | followupMsg, err := wire.UnmarshalOutput(followup.Payload) |
| 391 | require.NoError(t, err) | 392 | require.NoError(t, err) | ||
| 392 | if strings.Contains(string(followupMsg.Data), "copied 9 chars to clipboard") { | 393 | if strings.Contains(string(followupMsg.Data), "copied 9 chars to clipboard") { | ||
| 393 | t.Fatalf("copy feedback persisted after next repaint: %q", string(followupMsg.Data)) | 394 | t.Fatalf("copy feedback persisted after next repaint: %q", string(followupMsg.Data)) | ||
| @@ -430,9 +431,9 @@ func TestScrollbackEvictionFeedsCopyModeYank(t *testing.T) { | |||||
| 430 | } | 431 | } | ||
| 431 | var hg sync.WaitGroup | 432 | var hg sync.WaitGroup | ||
| 432 | hg.Go(func() { d.handleConn(tr) }) | 433 | hg.Go(func() { d.handleConn(tr) }) | ||
| 433 | - | awaitFrame(t, sends, ports.MsgWelcome) | 434 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 434 | advanceRender() // initial coordinator invalidation | 435 | advanceRender() // initial coordinator invalidation | ||
| 435 | - | awaitFrame(t, sends, ports.MsgOutput) | 436 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 436 | 437 | ||||
| 437 | for i := range 12 { | 438 | for i := range 12 { | ||
| 438 | reads <- fmt.Appendf(nil, "line-%02d\r\n", i) | 439 | reads <- fmt.Appendf(nil, "line-%02d\r\n", i) | ||
| @@ -469,8 +470,8 @@ func TestScrollbackEvictionFeedsCopyModeYank(t *testing.T) { | |||||
| 469 | 470 | ||||
| 470 | var payload string | 471 | var payload string | ||
| 471 | require.Eventually(t, func() bool { | 472 | require.Eventually(t, func() bool { | ||
| 472 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 473 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 473 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 474 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 474 | require.NoError(t, err) | 475 | require.NoError(t, err) | ||
| 475 | payload = string(msg.Data) | 476 | payload = string(msg.Data) | ||
| 476 | return strings.HasPrefix(payload, "\x1b]52;c;") | 477 | return strings.HasPrefix(payload, "\x1b]52;c;") | ||
| @@ -495,14 +496,14 @@ func TestCopyModeEscapeRestoresLiveFullRepaint(t *testing.T) { | |||||
| 495 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | 496 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | ||
| 496 | 497 | ||||
| 497 | d.enterCopyMode(sess, ac) | 498 | d.enterCopyMode(sess, ac) | ||
| 498 | - | awaitFrame(t, sends, ports.MsgOutput) | 499 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 499 | d.handleInput(sess, ac, []byte("q")) | 500 | d.handleInput(sess, ac, []byte("q")) | ||
| 500 | 501 | ||||
| 501 | if ac.overlays.copyMode != nil { | 502 | if ac.overlays.copyMode != nil { | ||
| 502 | t.Fatal("copy mode still active after q") | 503 | t.Fatal("copy mode still active after q") | ||
| 503 | } | 504 | } | ||
| 504 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 505 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 505 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 506 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 506 | require.NoError(t, err) | 507 | require.NoError(t, err) | ||
| 507 | if strings.Contains(string(msg.Data), "[COPY]") || !strings.Contains(string(msg.Data), "live") { | 508 | if strings.Contains(string(msg.Data), "[COPY]") || !strings.Contains(string(msg.Data), "live") { | ||
| 508 | t.Fatalf("exit repaint = %q, want live full repaint without copy status", string(msg.Data)) | 509 | t.Fatalf("exit repaint = %q, want live full repaint without copy status", string(msg.Data)) | ||
| @@ -531,7 +532,7 @@ func TestCopyModeSplitArrowDoesNotExit(t *testing.T) { | |||||
| 531 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | 532 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | ||
| 532 | 533 | ||||
| 533 | d.enterCopyMode(sess, ac) | 534 | d.enterCopyMode(sess, ac) | ||
| 534 | - | awaitFrame(t, sends, ports.MsgOutput) | 535 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 535 | for _, input := range tc.input { | 536 | for _, input := range tc.input { | ||
| 536 | d.handleInput(sess, ac, input) | 537 | d.handleInput(sess, ac, input) | ||
| 537 | } | 538 | } | ||
| @@ -551,11 +552,11 @@ func TestCopyModeOversizedYankShowsTooLargeFeedback(t *testing.T) { | |||||
| 551 | copy(sess.tabs[0].focusedPane().screen.Frame.Row(0), testRow(longLine)) | 552 | copy(sess.tabs[0].focusedPane().screen.Frame.Row(0), testRow(longLine)) | ||
| 552 | 553 | ||||
| 553 | d.enterCopyMode(sess, ac) | 554 | d.enterCopyMode(sess, ac) | ||
| 554 | - | awaitFrame(t, sends, ports.MsgOutput) | 555 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 555 | d.handleInput(sess, ac, []byte{' ', 'y'}) | 556 | d.handleInput(sess, ac, []byte{' ', 'y'}) | ||
| 556 | 557 | ||||
| 557 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 558 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 558 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 559 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 559 | require.NoError(t, err) | 560 | require.NoError(t, err) | ||
| 560 | if strings.Contains(string(msg.Data), "\x1b]52;") { | 561 | if strings.Contains(string(msg.Data), "\x1b]52;") { | ||
| 561 | t.Fatalf("oversized yank emitted OSC52: %q", string(msg.Data)) | 562 | t.Fatalf("oversized yank emitted OSC52: %q", string(msg.Data)) | ||
| @@ -574,7 +575,7 @@ func TestCopyModeLoneEscapeExitsAfterDelay(t *testing.T) { | |||||
| 574 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | 575 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | ||
| 575 | 576 | ||||
| 576 | d.enterCopyMode(sess, ac) | 577 | d.enterCopyMode(sess, ac) | ||
| 577 | - | awaitFrame(t, sends, ports.MsgOutput) | 578 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 578 | d.handleInput(sess, ac, []byte("\x1b")) | 579 | d.handleInput(sess, ac, []byte("\x1b")) | ||
| 579 | timer := <-clk.timers | 580 | timer := <-clk.timers | ||
| 580 | ac.overlays.copyMu.Lock() | 581 | ac.overlays.copyMu.Lock() | ||
| @@ -598,11 +599,11 @@ func TestCopyModePendingEscapeDoesNotCloseNewMode(t *testing.T) { | |||||
| 598 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | 599 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | ||
| 599 | 600 | ||||
| 600 | d.enterCopyMode(sess, ac) | 601 | d.enterCopyMode(sess, ac) | ||
| 601 | - | awaitFrame(t, sends, ports.MsgOutput) | 602 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 602 | d.handleInput(sess, ac, []byte("\x1b")) | 603 | d.handleInput(sess, ac, []byte("\x1b")) | ||
| 603 | timer := <-clk.timers | 604 | timer := <-clk.timers | ||
| 604 | d.enterCopyMode(sess, ac) | 605 | d.enterCopyMode(sess, ac) | ||
| 605 | - | awaitFrame(t, sends, ports.MsgOutput) | 606 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 606 | 607 | ||||
| 607 | ac.overlays.copyMu.Lock() | 608 | ac.overlays.copyMu.Lock() | ||
| 608 | require.Nil(t, ac.overlays.copyESC.timer) | 609 | require.Nil(t, ac.overlays.copyESC.timer) | ||
| @@ -641,14 +642,14 @@ func TestCopyModeEmptyYankDoesNotClearClipboard(t *testing.T) { | |||||
| 641 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | 642 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | ||
| 642 | 643 | ||||
| 643 | d.enterCopyMode(sess, ac) | 644 | d.enterCopyMode(sess, ac) | ||
| 644 | - | awaitFrame(t, sends, ports.MsgOutput) | 645 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 645 | d.handleInput(sess, ac, tc.input) | 646 | d.handleInput(sess, ac, tc.input) | ||
| 646 | 647 | ||||
| 647 | if ac.overlays.copyMode != nil { | 648 | if ac.overlays.copyMode != nil { | ||
| 648 | t.Fatal("copy mode still active after empty yank") | 649 | t.Fatal("copy mode still active after empty yank") | ||
| 649 | } | 650 | } | ||
| 650 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 651 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 651 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 652 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 652 | require.NoError(t, err) | 653 | require.NoError(t, err) | ||
| 653 | if strings.Contains(string(msg.Data), "\x1b]52;") { | 654 | if strings.Contains(string(msg.Data), "\x1b]52;") { | ||
| 654 | t.Fatalf("empty yank emitted OSC52 clipboard clear: %q", string(msg.Data)) | 655 | t.Fatalf("empty yank emitted OSC52 clipboard clear: %q", string(msg.Data)) | ||
| @@ -667,7 +668,7 @@ func TestHandleCopyInputUsesImmutableSnapshotWithoutPaneLock(t *testing.T) { | |||||
| 667 | pane := testAttachmentTab(sess).focusedPane() | 668 | pane := testAttachmentTab(sess).focusedPane() | ||
| 668 | pane.screen.Write([]byte("live")) | 669 | pane.screen.Write([]byte("live")) | ||
| 669 | d.enterCopyMode(sess, ac) | 670 | d.enterCopyMode(sess, ac) | ||
| 670 | - | awaitFrame(t, sends, ports.MsgOutput) | 671 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 671 | 672 | ||||
| 672 | pane.mu.Lock() | 673 | pane.mu.Lock() | ||
| 673 | defer pane.mu.Unlock() | 674 | defer pane.mu.Unlock() | ||
| @@ -769,7 +770,7 @@ func TestCopyModeCapturesSourceAndRetainsItAcrossFocusMove(t *testing.T) { | |||||
| 769 | } | 770 | } | ||
| 770 | 771 | ||||
| 771 | d.enterCopyMode(sess, ac) | 772 | d.enterCopyMode(sess, ac) | ||
| 772 | - | awaitFrame(t, sends, ports.MsgOutput) | 773 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 773 | ac.overlays.copyMu.Lock() | 774 | ac.overlays.copyMu.Lock() | ||
| 774 | captured := ac.overlays.copyPane | 775 | captured := ac.overlays.copyPane | ||
| 775 | ac.overlays.copyMu.Unlock() | 776 | ac.overlays.copyMu.Unlock() | ||
| @@ -780,8 +781,8 @@ func TestCopyModeCapturesSourceAndRetainsItAcrossFocusMove(t *testing.T) { | |||||
| 780 | tb.mu.Unlock() | 781 | tb.mu.Unlock() | ||
| 781 | 782 | ||||
| 782 | d.handleInput(sess, ac, []byte{'g', ' ', 'j', 'y'}) | 783 | d.handleInput(sess, ac, []byte{'g', ' ', 'j', 'y'}) | ||
| 783 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 784 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 784 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 785 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 785 | require.NoError(t, err) | 786 | require.NoError(t, err) | ||
| 786 | wantOSC := "\x1b]52;c;" + base64.StdEncoding.EncodeToString([]byte(tc.wantText)) + "\x07" | 787 | wantOSC := "\x1b]52;c;" + base64.StdEncoding.EncodeToString([]byte(tc.wantText)) + "\x07" | ||
| 787 | require.Equal(t, wantOSC, string(msg.Data)) | 788 | require.Equal(t, wantOSC, string(msg.Data)) | ||
| @@ -809,15 +810,15 @@ func TestFloatingCopyModeWheelUsesCapturedSnapshot(t *testing.T) { | |||||
| 809 | fp.mu.Unlock() | 810 | fp.mu.Unlock() | ||
| 810 | 811 | ||||
| 811 | d.enterCopyMode(sess, ac) | 812 | d.enterCopyMode(sess, ac) | ||
| 812 | - | awaitFrame(t, sends, ports.MsgOutput) | 813 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 813 | require.Equal(t, total-1, ac.overlays.copyMode.Cursor().Row) | 814 | require.Equal(t, total-1, ac.overlays.copyMode.Cursor().Row) | ||
| 814 | 815 | ||||
| 815 | d.copyWheel(sess, ac, -3) | 816 | d.copyWheel(sess, ac, -3) | ||
| 816 | - | awaitFrame(t, sends, ports.MsgOutput) | 817 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 817 | require.Equal(t, total-4, ac.overlays.copyMode.Cursor().Row) | 818 | require.Equal(t, total-4, ac.overlays.copyMode.Cursor().Row) | ||
| 818 | 819 | ||||
| 819 | d.copyWheel(sess, ac, 3) | 820 | d.copyWheel(sess, ac, 3) | ||
| 820 | - | awaitFrame(t, sends, ports.MsgOutput) | 821 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 821 | require.Nil(t, ac.overlays.copyMode, "wheel down reaching the captured bottom exits copy mode") | 822 | require.Nil(t, ac.overlays.copyMode, "wheel down reaching the captured bottom exits copy mode") | ||
| 822 | } | 823 | } | ||
| 823 | 824 | ||||
| @@ -832,7 +833,7 @@ func TestFloatingCopyModeMouseSelectsFloatingRows(t *testing.T) { | |||||
| 832 | fp.screen.Write([]byte("live")) | 833 | fp.screen.Write([]byte("live")) | ||
| 833 | 834 | ||||
| 834 | d.enterCopyMode(sess, ac) | 835 | d.enterCopyMode(sess, ac) | ||
| 835 | - | awaitFrame(t, sends, ports.MsgOutput) | 836 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 836 | ac.overlays.copyMu.Lock() | 837 | ac.overlays.copyMu.Lock() | ||
| 837 | viewportTop := ac.overlays.copyMode.ViewportTop | 838 | viewportTop := ac.overlays.copyMode.ViewportTop | ||
| 838 | ac.overlays.copyMu.Unlock() | 839 | ac.overlays.copyMu.Unlock() | ||
| @@ -842,12 +843,12 @@ func TestFloatingCopyModeMouseSelectsFloatingRows(t *testing.T) { | |||||
| 842 | // offset); clicking a row must select exactly that row. | 843 | // offset); clicking a row must select exactly that row. | ||
| 843 | press := fmt.Sprintf("\x1b[<0;%d;%dM", inner.X+3, inner.Y+3) | 844 | press := fmt.Sprintf("\x1b[<0;%d;%dM", inner.X+3, inner.Y+3) | ||
| 844 | d.handleInput(sess, ac, []byte(press)) | 845 | d.handleInput(sess, ac, []byte(press)) | ||
| 845 | - | awaitFrame(t, sends, ports.MsgOutput) | 846 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 846 | require.Equal(t, viewportTop+1, ac.overlays.copyMode.Cursor().Row) | 847 | require.Equal(t, viewportTop+1, ac.overlays.copyMode.Cursor().Row) | ||
| 847 | 848 | ||||
| 848 | motion := fmt.Sprintf("\x1b[<32;%d;%dM", inner.X+3, inner.Y+4) | 849 | motion := fmt.Sprintf("\x1b[<32;%d;%dM", inner.X+3, inner.Y+4) | ||
| 849 | d.handleInput(sess, ac, []byte(motion)) | 850 | d.handleInput(sess, ac, []byte(motion)) | ||
| 850 | - | awaitFrame(t, sends, ports.MsgOutput) | 851 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 851 | selection := ac.overlays.copyMode.Selection() | 852 | selection := ac.overlays.copyMode.Selection() | ||
| 852 | require.True(t, selection.Enabled) | 853 | require.True(t, selection.Enabled) | ||
| 853 | require.Equal(t, viewportTop+1, selection.Anchor.Row) | 854 | require.Equal(t, viewportTop+1, selection.Anchor.Row) | ||
| @@ -863,7 +864,7 @@ func TestFloatingExitClearsCopyModeBeforeRepaint(t *testing.T) { | |||||
| 863 | fp.screen.Write([]byte("flt-live")) | 864 | fp.screen.Write([]byte("flt-live")) | ||
| 864 | 865 | ||||
| 865 | d.enterCopyMode(sess, ac) | 866 | d.enterCopyMode(sess, ac) | ||
| 866 | - | awaitFrame(t, sends, ports.MsgOutput) | 867 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 867 | tb.mu.Lock() | 868 | tb.mu.Lock() | ||
| 868 | generation := tb.floating.generation | 869 | generation := tb.floating.generation | ||
| 869 | publishPaneOwner(fp, sess, tb, generation) | 870 | publishPaneOwner(fp, sess, tb, generation) | ||
| @@ -896,8 +897,8 @@ func TestMouseDragCopyEntryCapturesSourceForYank(t *testing.T) { | |||||
| 896 | require.Same(t, pane, captured, "drag entry must capture the copy source pane") | 897 | require.Same(t, pane, captured, "drag entry must capture the copy source pane") | ||
| 897 | 898 | ||||
| 898 | d.handleInput(sess, ac, []byte("y")) | 899 | d.handleInput(sess, ac, []byte("y")) | ||
| 899 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 900 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 900 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 901 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 901 | require.NoError(t, err) | 902 | require.NoError(t, err) | ||
| 902 | want := "\x1b]52;c;" + base64.StdEncoding.EncodeToString([]byte("alpha\nb")) + "\x07" | 903 | want := "\x1b]52;c;" + base64.StdEncoding.EncodeToString([]byte("alpha\nb")) + "\x07" | ||
| 903 | require.Equal(t, want, string(msg.Data)) | 904 | require.Equal(t, want, string(msg.Data)) | ||
M internal/usecase/daemon/daemon.go +14 -13
| @@ -18,6 +18,7 @@ import ( | |||||
| 18 | "github.com/bnema/vev/internal/domain" | 18 | "github.com/bnema/vev/internal/domain" | ||
| 19 | "github.com/bnema/vev/internal/ports" | 19 | "github.com/bnema/vev/internal/ports" | ||
| 20 | "github.com/bnema/vev/internal/protocol" | 20 | "github.com/bnema/vev/internal/protocol" | ||
| 21 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 21 | "github.com/bnema/vev/internal/usecase/keys" | 22 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 22 | recoveryusecase "github.com/bnema/vev/internal/usecase/recovery" | 23 | recoveryusecase "github.com/bnema/vev/internal/usecase/recovery" | ||
| 23 | ) | 24 | ) | ||
| @@ -1020,7 +1021,7 @@ func (d *Daemon) handleConn(tr ports.Transport) { | |||||
| 1020 | defer finishHandshake() | 1021 | defer finishHandshake() | ||
| 1021 | defer stopTransport() | 1022 | defer stopTransport() | ||
| 1022 | 1023 | ||||
| 1023 | - | var first ports.Frame | 1024 | + | var first wire.Frame |
| 1024 | err := boundedHandshakeOperation(handshakeCtx, tr, func() error { | 1025 | err := boundedHandshakeOperation(handshakeCtx, tr, func() error { | ||
| 1025 | var recvErr error | 1026 | var recvErr error | ||
| 1026 | first, recvErr = tr.Recv() | 1027 | first, recvErr = tr.Recv() | ||
| @@ -1033,27 +1034,27 @@ func (d *Daemon) handleConn(tr ports.Transport) { | |||||
| 1033 | return | 1034 | return | ||
| 1034 | } | 1035 | } | ||
| 1035 | switch first.Type { | 1036 | switch first.Type { | ||
| 1036 | - | case ports.MsgList: | 1037 | + | case wire.MsgList: |
| 1037 | stopTransport() | 1038 | stopTransport() | ||
| 1038 | finishHandshake() | 1039 | finishHandshake() | ||
| 1039 | d.handleList(tr) | 1040 | d.handleList(tr) | ||
| 1040 | - | case ports.MsgCommand: | 1041 | + | case wire.MsgCommand: |
| 1041 | stopTransport() | 1042 | stopTransport() | ||
| 1042 | finishHandshake() | 1043 | finishHandshake() | ||
| 1043 | if err := d.handleCommand(tr, first); err != nil { | 1044 | if err := d.handleCommand(tr, first); err != nil { | ||
| 1044 | d.log.Warn("command handler failed", "err", err) | 1045 | d.log.Warn("command handler failed", "err", err) | ||
| 1045 | } | 1046 | } | ||
| 1046 | - | case ports.MsgRemotePreviewRequest: | 1047 | + | case wire.MsgRemotePreviewRequest: |
| 1047 | stopTransport() | 1048 | stopTransport() | ||
| 1048 | finishHandshake() | 1049 | finishHandshake() | ||
| 1049 | if err := d.handleRemotePreview(tr, first); err != nil { | 1050 | if err := d.handleRemotePreview(tr, first); err != nil { | ||
| 1050 | d.log.Warn("remote preview handler failed", "err", err) | 1051 | d.log.Warn("remote preview handler failed", "err", err) | ||
| 1051 | } | 1052 | } | ||
| 1052 | - | case ports.MsgKill: | 1053 | + | case wire.MsgKill: |
| 1053 | stopTransport() | 1054 | stopTransport() | ||
| 1054 | finishHandshake() | 1055 | finishHandshake() | ||
| 1055 | d.handleKill(tr, first) | 1056 | d.handleKill(tr, first) | ||
| 1056 | - | case ports.MsgHello: | 1057 | + | case wire.MsgHello: |
| 1057 | d.handleHelloWithContext(handshakeCtx, timedOut, stopTransport, finishHandshake, tr, first) | 1058 | d.handleHelloWithContext(handshakeCtx, timedOut, stopTransport, finishHandshake, tr, first) | ||
| 1058 | default: | 1059 | default: | ||
| 1059 | d.log.Warn("hello rejected", "err", "expected hello", "type", first.Type) | 1060 | d.log.Warn("hello rejected", "err", "expected hello", "type", first.Type) | ||
| @@ -1110,10 +1111,10 @@ func (d *Daemon) handleList(tr ports.Transport) { | |||||
| 1110 | // handleKill terminates the requested live session or stopped named session, | 1111 | // handleKill terminates the requested live session or stopped named session, | ||
| 1111 | // or all sessions, and closes the control connection; the resulting EOF is the | 1112 | // or all sessions, and closes the control connection; the resulting EOF is the | ||
| 1112 | // client's success signal. | 1113 | // client's success signal. | ||
| 1113 | - | func (d *Daemon) handleKill(tr ports.Transport, f ports.Frame) { | 1114 | + | func (d *Daemon) handleKill(tr ports.Transport, f wire.Frame) { |
| 1114 | defer func() { _ = tr.Close() }() | 1115 | defer func() { _ = tr.Close() }() | ||
| 1115 | 1116 | ||||
| 1116 | - | k, err := ports.UnmarshalKill(f.Payload) | 1117 | + | k, err := wire.UnmarshalKill(f.Payload) |
| 1117 | if err != nil { | 1118 | if err != nil { | ||
| 1118 | _ = d.boundedControlSend(tr, frameError(protocol.ErrInternal, "malformed kill request")) | 1119 | _ = d.boundedControlSend(tr, frameError(protocol.ErrInternal, "malformed kill request")) | ||
| 1119 | return | 1120 | return | ||
| @@ -1151,7 +1152,7 @@ func (d *Daemon) handleKill(tr ports.Transport, f ports.Frame) { | |||||
| 1151 | // handleHello runs the attach handshake for direct package callers. Accepted | 1152 | // handleHello runs the attach handshake for direct package callers. Accepted | ||
| 1152 | // connections use handleHelloWithContext so the deadline also covers the first | 1153 | // connections use handleHelloWithContext so the deadline also covers the first | ||
| 1153 | // frame read in handleConn. | 1154 | // frame read in handleConn. | ||
| 1154 | - | func (d *Daemon) handleHello(tr ports.Transport, f ports.Frame) { | 1155 | + | func (d *Daemon) handleHello(tr ports.Transport, f wire.Frame) { |
| 1155 | handshakeCtx, timedOut, finishHandshake := d.newHandshakeContext(context.Background()) | 1156 | handshakeCtx, timedOut, finishHandshake := d.newHandshakeContext(context.Background()) | ||
| 1156 | stopTransport := watchHandshakeTransport(handshakeCtx, tr) | 1157 | stopTransport := watchHandshakeTransport(handshakeCtx, tr) | ||
| 1157 | defer finishHandshake() | 1158 | defer finishHandshake() | ||
| @@ -1161,21 +1162,21 @@ func (d *Daemon) handleHello(tr ports.Transport, f ports.Frame) { | |||||
| 1161 | 1162 | ||||
| 1162 | // handleHelloWithContext runs the attach handshake: version check, intent | 1163 | // handleHelloWithContext runs the attach handshake: version check, intent | ||
| 1163 | // routing, Welcome, guaranteed first paint, then the per-connection input loop. | 1164 | // routing, Welcome, guaranteed first paint, then the per-connection input loop. | ||
| 1164 | - | func (d *Daemon) handleHelloWithContext(handshakeCtx context.Context, timedOut <-chan struct{}, stopHandshakeTransport, finishHandshake func(), tr ports.Transport, f ports.Frame) { | 1165 | + | func (d *Daemon) handleHelloWithContext(handshakeCtx context.Context, timedOut <-chan struct{}, stopHandshakeTransport, finishHandshake func(), tr ports.Transport, f wire.Frame) { |
| 1165 | if err := handshakeContextError(context.Background(), timedOut, handshakeCtx.Err()); err != nil { | 1166 | if err := handshakeContextError(context.Background(), timedOut, handshakeCtx.Err()); err != nil { | ||
| 1166 | _ = tr.Close() | 1167 | _ = tr.Close() | ||
| 1167 | return | 1168 | return | ||
| 1168 | } | 1169 | } | ||
| 1169 | - | sendHandshake := func(frame ports.Frame) error { | 1170 | + | sendHandshake := func(frame wire.Frame) error { |
| 1170 | err := boundedHandshakeOperation(handshakeCtx, tr, func() error { return tr.Send(frame) }) | 1171 | err := boundedHandshakeOperation(handshakeCtx, tr, func() error { return tr.Send(frame) }) | ||
| 1171 | if err != nil { | 1172 | if err != nil { | ||
| 1172 | return handshakeContextError(context.Background(), timedOut, err) | 1173 | return handshakeContextError(context.Background(), timedOut, err) | ||
| 1173 | } | 1174 | } | ||
| 1174 | return nil | 1175 | return nil | ||
| 1175 | } | 1176 | } | ||
| 1176 | - | h, err := ports.UnmarshalHello(f.Payload) | 1177 | + | h, err := wire.UnmarshalHello(f.Payload) |
| 1177 | if err != nil { | 1178 | if err != nil { | ||
| 1178 | - | if version, ok := ports.PeekHelloVersion(f.Payload); ok && version != protocol.Version { | 1179 | + | if version, ok := wire.PeekHelloVersion(f.Payload); ok && version != protocol.Version { |
| 1179 | d.log.Warn("hello rejected", "err", "protocol version mismatch", "version", version, "expected", protocol.Version) | 1180 | d.log.Warn("hello rejected", "err", "protocol version mismatch", "version", version, "expected", protocol.Version) | ||
| 1180 | _ = sendHandshake(frameError(protocol.ErrVersionMismatch, "protocol version mismatch")) | 1181 | _ = sendHandshake(frameError(protocol.ErrVersionMismatch, "protocol version mismatch")) | ||
| 1181 | } else { | 1182 | } else { | ||
M internal/usecase/daemon/daemon_test.go +36 -35
| @@ -17,6 +17,7 @@ import ( | |||||
| 17 | "github.com/bnema/vev/internal/ports" | 17 | "github.com/bnema/vev/internal/ports" | ||
| 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 19 | "github.com/bnema/vev/internal/protocol" | 19 | "github.com/bnema/vev/internal/protocol" | ||
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 20 | "github.com/bnema/vev/internal/usecase/keys" | 21 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 21 | ) | 22 | ) | ||
| 22 | 23 | ||||
| @@ -236,11 +237,11 @@ func newFactorySeq(t *testing.T, ptys ...ports.PTY) *portsmocks.MockPTYFactory { | |||||
| 236 | // newConn scripts a MockTransport: Recv yields first then more (in order), | 237 | // newConn scripts a MockTransport: Recv yields first then more (in order), | ||
| 237 | // then blocks until the connection is released or Closed (returning io.EOF). | 238 | // then blocks until the connection is released or Closed (returning io.EOF). | ||
| 238 | // Every Send is captured on the returned channel. | 239 | // Every Send is captured on the returned channel. | ||
| 239 | - | func newConn(t *testing.T, first ports.Frame, more ...ports.Frame) (*portsmocks.MockTransport, chan ports.Frame, func()) { | 240 | + | func newConn(t *testing.T, first wire.Frame, more ...wire.Frame) (*portsmocks.MockTransport, chan wire.Frame, func()) { |
| 240 | t.Helper() | 241 | t.Helper() | ||
| 241 | tr := portsmocks.NewMockTransport(t) | 242 | tr := portsmocks.NewMockTransport(t) | ||
| 242 | - | sends := make(chan ports.Frame, 64) | 243 | + | sends := make(chan wire.Frame, 64) |
| 243 | - | recvCh := make(chan ports.Frame, 1+len(more)) | 244 | + | recvCh := make(chan wire.Frame, 1+len(more)) |
| 244 | recvCh <- first | 245 | recvCh <- first | ||
| 245 | for _, f := range more { | 246 | for _, f := range more { | ||
| 246 | recvCh <- f | 247 | recvCh <- f | ||
| @@ -249,15 +250,15 @@ func newConn(t *testing.T, first ports.Frame, more ...ports.Frame) (*portsmocks. | |||||
| 249 | var once sync.Once | 250 | var once sync.Once | ||
| 250 | closeDone := func() { once.Do(func() { close(done) }) } | 251 | closeDone := func() { once.Do(func() { close(done) }) } | ||
| 251 | 252 | ||||
| 252 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 253 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 253 | select { | 254 | select { | ||
| 254 | case f := <-recvCh: | 255 | case f := <-recvCh: | ||
| 255 | return f, nil | 256 | return f, nil | ||
| 256 | case <-done: | 257 | case <-done: | ||
| 257 | - | return ports.Frame{}, io.EOF | 258 | + | return wire.Frame{}, io.EOF |
| 258 | } | 259 | } | ||
| 259 | }).Maybe() | 260 | }).Maybe() | ||
| 260 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | 261 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { |
| 261 | sends <- f | 262 | sends <- f | ||
| 262 | return nil | 263 | return nil | ||
| 263 | }).Maybe() | 264 | }).Maybe() | ||
| @@ -265,14 +266,14 @@ func newConn(t *testing.T, first ports.Frame, more ...ports.Frame) (*portsmocks. | |||||
| 265 | return tr, sends, closeDone | 266 | return tr, sends, closeDone | ||
| 266 | } | 267 | } | ||
| 267 | 268 | ||||
| 268 | - | func mustHello(intent uint8, name string, sz domain.Size) ports.Frame { | 269 | + | func mustHello(intent uint8, name string, sz domain.Size) wire.Frame { |
| 269 | - | return ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | 270 | + | return wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ |
| 270 | Version: protocol.Version, Intent: intent, Name: name, Size: sz, TermEnv: "xterm-256color", | 271 | Version: protocol.Version, Intent: intent, Name: name, Size: sz, TermEnv: "xterm-256color", | ||
| 271 | })} | 272 | })} | ||
| 272 | } | 273 | } | ||
| 273 | 274 | ||||
| 274 | - | func frameInput(data []byte) ports.Frame { | 275 | + | func frameInput(data []byte) wire.Frame { |
| 275 | - | return ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: data})} | 276 | + | return wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: data})} |
| 276 | } | 277 | } | ||
| 277 | 278 | ||||
| 278 | func screenLineText(s *vt.Screen, y int) string { | 279 | func screenLineText(s *vt.Screen, y int) string { | ||
| @@ -284,7 +285,7 @@ func screenLineText(s *vt.Screen, y int) string { | |||||
| 284 | } | 285 | } | ||
| 285 | 286 | ||||
| 286 | // awaitFrame waits for the next frame of type typ on ch, failing on timeout. | 287 | // awaitFrame waits for the next frame of type typ on ch, failing on timeout. | ||
| 287 | - | func awaitFrame(t *testing.T, ch chan ports.Frame, typ ports.MsgType) ports.Frame { | 288 | + | func awaitFrame(t *testing.T, ch chan wire.Frame, typ wire.MsgType) wire.Frame { |
| 288 | t.Helper() | 289 | t.Helper() | ||
| 289 | deadline := time.After(2 * time.Second) | 290 | deadline := time.After(2 * time.Second) | ||
| 290 | for { | 291 | for { | ||
| @@ -318,10 +319,10 @@ func sessionCount(d *Daemon) int { | |||||
| 318 | 319 | ||||
| 319 | func listSessions(t *testing.T, d *Daemon) protocol.Sessions { | 320 | func listSessions(t *testing.T, d *Daemon) protocol.Sessions { | ||
| 320 | t.Helper() | 321 | t.Helper() | ||
| 321 | - | tr, sends, _ := newConn(t, ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})}) | 322 | + | tr, sends, _ := newConn(t, wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})}) |
| 322 | d.handleList(tr) | 323 | d.handleList(tr) | ||
| 323 | - | f := awaitFrame(t, sends, ports.MsgSessions) | 324 | + | f := awaitFrame(t, sends, wire.MsgSessions) |
| 324 | - | sessions, err := ports.UnmarshalSessions(f.Payload) | 325 | + | sessions, err := wire.UnmarshalSessions(f.Payload) |
| 325 | require.NoError(t, err) | 326 | require.NoError(t, err) | ||
| 326 | return sessions | 327 | return sessions | ||
| 327 | } | 328 | } | ||
| @@ -331,7 +332,7 @@ func listSessions(t *testing.T, d *Daemon) protocol.Sessions { | |||||
| 331 | // transport mock while channels make both sides of the wire deterministic. | 332 | // transport mock while channels make both sides of the wire deterministic. | ||
| 332 | type welcomeBlockingTransport struct { | 333 | type welcomeBlockingTransport struct { | ||
| 333 | tr *portsmocks.MockTransport | 334 | tr *portsmocks.MockTransport | ||
| 334 | - | sends chan ports.Frame | 335 | + | sends chan wire.Frame |
| 335 | welcomeEntered chan struct{} | 336 | welcomeEntered chan struct{} | ||
| 336 | releaseWelcome chan struct{} | 337 | releaseWelcome chan struct{} | ||
| 337 | recvDone chan struct{} | 338 | recvDone chan struct{} | ||
| @@ -342,23 +343,23 @@ type welcomeBlockingTransport struct { | |||||
| 342 | func newWelcomeBlockingTransport(t *testing.T) *welcomeBlockingTransport { | 343 | func newWelcomeBlockingTransport(t *testing.T) *welcomeBlockingTransport { | ||
| 343 | t.Helper() | 344 | t.Helper() | ||
| 344 | b := &welcomeBlockingTransport{ | 345 | b := &welcomeBlockingTransport{ | ||
| 345 | - | sends: make(chan ports.Frame, 8), | 346 | + | sends: make(chan wire.Frame, 8), |
| 346 | welcomeEntered: make(chan struct{}), | 347 | welcomeEntered: make(chan struct{}), | ||
| 347 | releaseWelcome: make(chan struct{}), | 348 | releaseWelcome: make(chan struct{}), | ||
| 348 | recvDone: make(chan struct{}), | 349 | recvDone: make(chan struct{}), | ||
| 349 | } | 350 | } | ||
| 350 | b.tr = portsmocks.NewMockTransport(t) | 351 | b.tr = portsmocks.NewMockTransport(t) | ||
| 351 | - | b.tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | 352 | + | b.tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { |
| 352 | b.sends <- f | 353 | b.sends <- f | ||
| 353 | - | if f.Type == ports.MsgWelcome { | 354 | + | if f.Type == wire.MsgWelcome { |
| 354 | close(b.welcomeEntered) | 355 | close(b.welcomeEntered) | ||
| 355 | <-b.releaseWelcome | 356 | <-b.releaseWelcome | ||
| 356 | } | 357 | } | ||
| 357 | return nil | 358 | return nil | ||
| 358 | }).Maybe() | 359 | }).Maybe() | ||
| 359 | - | b.tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 360 | + | b.tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 360 | <-b.recvDone | 361 | <-b.recvDone | ||
| 361 | - | return ports.Frame{}, io.EOF | 362 | + | return wire.Frame{}, io.EOF |
| 362 | }).Maybe() | 363 | }).Maybe() | ||
| 363 | b.tr.EXPECT().Close().Return(nil).Maybe() | 364 | b.tr.EXPECT().Close().Return(nil).Maybe() | ||
| 364 | t.Cleanup(b.finish) | 365 | t.Cleanup(b.finish) | ||
| @@ -374,11 +375,11 @@ func (b *welcomeBlockingTransport) finish() { | |||||
| 374 | b.closeOnce.Do(func() { close(b.recvDone) }) | 375 | b.closeOnce.Do(func() { close(b.recvDone) }) | ||
| 375 | } | 376 | } | ||
| 376 | 377 | ||||
| 377 | - | func newCapturingTransport(t testing.TB) (*portsmocks.MockTransport, chan ports.Frame) { | 378 | + | func newCapturingTransport(t testing.TB) (*portsmocks.MockTransport, chan wire.Frame) { |
| 378 | t.Helper() | 379 | t.Helper() | ||
| 379 | tr := portsmocks.NewMockTransport(t) | 380 | tr := portsmocks.NewMockTransport(t) | ||
| 380 | - | sends := make(chan ports.Frame, 64) | 381 | + | sends := make(chan wire.Frame, 64) |
| 381 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | 382 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { |
| 382 | sends <- f | 383 | sends <- f | ||
| 383 | return nil | 384 | return nil | ||
| 384 | }).Maybe() | 385 | }).Maybe() | ||
| @@ -386,22 +387,22 @@ func newCapturingTransport(t testing.TB) (*portsmocks.MockTransport, chan ports. | |||||
| 386 | return tr, sends | 387 | return tr, sends | ||
| 387 | } | 388 | } | ||
| 388 | 389 | ||||
| 389 | - | func newManualSessionWithPTYs(t testing.TB, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | 390 | + | func newManualSessionWithPTYs(t testing.TB, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { |
| 390 | t.Helper() | 391 | t.Helper() | ||
| 391 | return newManualSessionWithPTYsClock(t, stubClock{}, ptys...) | 392 | return newManualSessionWithPTYsClock(t, stubClock{}, ptys...) | ||
| 392 | } | 393 | } | ||
| 393 | 394 | ||||
| 394 | - | func newManualSessionWithPTYsClock(t testing.TB, clock ports.Clock, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | 395 | + | func newManualSessionWithPTYsClock(t testing.TB, clock ports.Clock, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { |
| 395 | t.Helper() | 396 | t.Helper() | ||
| 396 | return newManualSessionWithPTYsClockCleanup(t, clock, true, ptys...) | 397 | return newManualSessionWithPTYsClockCleanup(t, clock, true, ptys...) | ||
| 397 | } | 398 | } | ||
| 398 | 399 | ||||
| 399 | - | func newManualSessionWithPTYsCleanup(t testing.TB, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | 400 | + | func newManualSessionWithPTYsCleanup(t testing.TB, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { |
| 400 | t.Helper() | 401 | t.Helper() | ||
| 401 | return newManualSessionWithPTYsClockCleanup(t, stubClock{}, registerCleanup, ptys...) | 402 | return newManualSessionWithPTYsClockCleanup(t, stubClock{}, registerCleanup, ptys...) | ||
| 402 | } | 403 | } | ||
| 403 | 404 | ||||
| 404 | - | func newManualSessionWithPTYsClockCleanup(t testing.TB, clock ports.Clock, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | 405 | + | func newManualSessionWithPTYsClockCleanup(t testing.TB, clock ports.Clock, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { |
| 405 | t.Helper() | 406 | t.Helper() | ||
| 406 | d := newTestDaemonWithCleanup(t, nil, clock, registerCleanup) | 407 | d := newTestDaemonWithCleanup(t, nil, clock, registerCleanup) | ||
| 407 | tr, sends := newCapturingTransport(t) | 408 | tr, sends := newCapturingTransport(t) | ||
| @@ -432,7 +433,7 @@ func newManualSessionWithPTYsClockCleanup(t testing.TB, clock ports.Clock, regis | |||||
| 432 | return d, sess, ac, sends | 433 | return d, sess, ac, sends | ||
| 433 | } | 434 | } | ||
| 434 | 435 | ||||
| 435 | - | func newManualTabSession(t *testing.T, n int) (*Daemon, *session, *attachedClient, chan ports.Frame, []func()) { | 436 | + | func newManualTabSession(t *testing.T, n int) (*Daemon, *session, *attachedClient, chan wire.Frame, []func()) { |
| 436 | t.Helper() | 437 | t.Helper() | ||
| 437 | ptys := make([]ports.PTY, 0, n) | 438 | ptys := make([]ports.PTY, 0, n) | ||
| 438 | releases := make([]func(), 0, n) | 439 | releases := make([]func(), 0, n) | ||
| @@ -671,8 +672,8 @@ func TestHandleHelloDefersFreshOutputUntilWelcome(t *testing.T) { | |||||
| 671 | 672 | ||||
| 672 | awaitTestCompletion(t, tr.welcomeEntered, "timed out waiting for Welcome send") | 673 | awaitTestCompletion(t, tr.welcomeEntered, "timed out waiting for Welcome send") | ||
| 673 | handshakeTimer := awaitHandshakeTimer(t, clock) | 674 | handshakeTimer := awaitHandshakeTimer(t, clock) | ||
| 674 | - | welcome := awaitFrame(t, tr.sends, ports.MsgWelcome) | 675 | + | welcome := awaitFrame(t, tr.sends, wire.MsgWelcome) |
| 675 | - | require.Equal(t, ports.MsgWelcome, welcome.Type) | 676 | + | require.Equal(t, wire.MsgWelcome, welcome.Type) |
| 676 | sess := firstSession(d) | 677 | sess := firstSession(d) | ||
| 677 | sess.mu.Lock() | 678 | sess.mu.Lock() | ||
| 678 | ac := sess.snapshotAttachmentsLocked()[0] | 679 | ac := sess.snapshotAttachmentsLocked()[0] | ||
| @@ -695,8 +696,8 @@ func TestHandleHelloDefersFreshOutputUntilWelcome(t *testing.T) { | |||||
| 695 | requireNoCoordinatorOutputFrame(t, tr.sends) | 696 | requireNoCoordinatorOutputFrame(t, tr.sends) | ||
| 696 | 697 | ||||
| 697 | tr.release() | 698 | tr.release() | ||
| 698 | - | output := awaitFrame(t, tr.sends, ports.MsgOutput) | 699 | + | output := awaitFrame(t, tr.sends, wire.MsgOutput) |
| 699 | - | first, err := ports.UnmarshalOutput(output.Payload) | 700 | + | first, err := wire.UnmarshalOutput(output.Payload) |
| 700 | require.NoError(t, err) | 701 | require.NoError(t, err) | ||
| 701 | require.Zero(t, first.Base, "the first post-Welcome frame is full") | 702 | require.Zero(t, first.Base, "the first post-Welcome frame is full") | ||
| 702 | tr.finish() | 703 | tr.finish() | ||
| @@ -710,10 +711,10 @@ func TestHandleHelloDefersFreshOutputUntilWelcome(t *testing.T) { | |||||
| 710 | // MsgDetached send until the transport is closed (mirroring a full kernel | 711 | // MsgDetached send until the transport is closed (mirroring a full kernel | ||
| 711 | // send buffer: only Close fails the in-flight write). Serve must still tear | 712 | // send buffer: only Close fails the in-flight write). Serve must still tear | ||
| 712 | 713 | ||||
| 713 | - | func mustOutputData(t *testing.T, sends chan ports.Frame) []byte { | 714 | + | func mustOutputData(t *testing.T, sends chan wire.Frame) []byte { |
| 714 | t.Helper() | 715 | t.Helper() | ||
| 715 | - | f := awaitFrame(t, sends, ports.MsgOutput) | 716 | + | f := awaitFrame(t, sends, wire.MsgOutput) |
| 716 | - | out, err := ports.UnmarshalOutput(f.Payload) | 717 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 717 | require.NoError(t, err) | 718 | require.NoError(t, err) | ||
| 718 | return out.Data | 719 | return out.Data | ||
| 719 | } | 720 | } | ||
M internal/usecase/daemon/final_acceptance_test.go +4 -4
| @@ -5,8 +5,8 @@ import ( | |||||
| 5 | 5 | ||||
| 6 | vt "github.com/bnema/vev-vt" | 6 | vt "github.com/bnema/vev-vt" | ||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | - | "github.com/bnema/vev/internal/ports" | |||
| 9 | "github.com/bnema/vev/internal/protocol" | 8 | "github.com/bnema/vev/internal/protocol" | ||
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 10 | "github.com/bnema/vev/internal/usecase/layout" | 10 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 11 | "github.com/stretchr/testify/require" | 11 | "github.com/stretchr/testify/require" | ||
| 12 | ) | 12 | ) | ||
| @@ -149,9 +149,9 @@ func TestAcceptanceAttachmentStateIsolationAcrossResetResizeAndDetach(t *testing | |||||
| 149 | firstEpoch := first.output.currentEpoch() | 149 | firstEpoch := first.output.currentEpoch() | ||
| 150 | secondEpoch := second.output.currentEpoch() | 150 | secondEpoch := second.output.currentEpoch() | ||
| 151 | 151 | ||||
| 152 | - | d.handleAttachmentClientFrame(secondToken, ports.Frame{ | 152 | + | d.handleAttachmentClientFrame(secondToken, wire.Frame{ |
| 153 | - | Type: ports.MsgOutputResetRequest, | 153 | + | Type: wire.MsgOutputResetRequest, |
| 154 | - | Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{}), | 154 | + | Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{}), |
| 155 | }) | 155 | }) | ||
| 156 | require.Greater(t, second.output.currentEpoch(), secondEpoch) | 156 | require.Greater(t, second.output.currentEpoch(), secondEpoch) | ||
| 157 | require.Equal(t, firstEpoch, first.output.currentEpoch(), "peer output reset crossed attachment boundary") | 157 | require.Equal(t, firstEpoch, first.output.currentEpoch(), "peer output reset crossed attachment boundary") | ||
M internal/usecase/daemon/floating_test.go +6 -5
| @@ -18,6 +18,7 @@ import ( | |||||
| 18 | "github.com/bnema/vev/internal/ports" | 18 | "github.com/bnema/vev/internal/ports" | ||
| 19 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 19 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 20 | "github.com/bnema/vev/internal/protocol" | 20 | "github.com/bnema/vev/internal/protocol" | ||
| 21 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 21 | scopy "github.com/bnema/vev/internal/usecase/copy" | 22 | scopy "github.com/bnema/vev/internal/usecase/copy" | ||
| 22 | "github.com/bnema/vev/internal/usecase/layout" | 23 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 23 | themeui "github.com/bnema/vev/internal/usecase/theme" | 24 | themeui "github.com/bnema/vev/internal/usecase/theme" | ||
| @@ -482,7 +483,7 @@ func TestFloatingTeardownClearsCapturedCopyMode(t *testing.T) { | |||||
| 482 | } | 483 | } | ||
| 483 | 484 | ||||
| 484 | func TestFloatingEOFRepaintsVisibleSlotOnly(t *testing.T) { | 485 | func TestFloatingEOFRepaintsVisibleSlotOnly(t *testing.T) { | ||
| 485 | - | newCase := func(t *testing.T, state floatingState) (*Daemon, *session, *attachedClient, chan ports.Frame, *tab, *pane, func()) { | 486 | + | newCase := func(t *testing.T, state floatingState) (*Daemon, *session, *attachedClient, chan wire.Frame, *tab, *pane, func()) { |
| 486 | t.Helper() | 487 | t.Helper() | ||
| 487 | normalPTY, releaseNormal := newBlockingPTY(t) | 488 | normalPTY, releaseNormal := newBlockingPTY(t) | ||
| 488 | d, sess, ac, sends := newManualSessionWithPTYs(t, normalPTY) | 489 | d, sess, ac, sends := newManualSessionWithPTYs(t, normalPTY) | ||
| @@ -513,8 +514,8 @@ func TestFloatingEOFRepaintsVisibleSlotOnly(t *testing.T) { | |||||
| 513 | // Establish a renderer shadow first. The EOF repaint must reset it and | 514 | // Establish a renderer shadow first. The EOF repaint must reset it and | ||
| 514 | // redraw the underlying cell rather than depending on popup damage. | 515 | // redraw the underlying cell rather than depending on popup damage. | ||
| 515 | d.paint(sess, ac, true, nil) | 516 | d.paint(sess, ac, true, nil) | ||
| 516 | - | baseline := awaitFrame(t, sends, ports.MsgOutput) | 517 | + | baseline := awaitFrame(t, sends, wire.MsgOutput) |
| 517 | - | baselineOutput, err := ports.UnmarshalOutput(baseline.Payload) | 518 | + | baselineOutput, err := wire.UnmarshalOutput(baseline.Payload) |
| 518 | require.NoError(t, err) | 519 | require.NoError(t, err) | ||
| 519 | require.Contains(t, string(baselineOutput.Data), "underlying-cell") | 520 | require.Contains(t, string(baselineOutput.Data), "underlying-cell") | ||
| 520 | 521 | ||||
| @@ -541,8 +542,8 @@ func TestFloatingEOFRepaintsVisibleSlotOnly(t *testing.T) { | |||||
| 541 | require.Equal(t, floatingUninitialized, tb.floating.state) | 542 | require.Equal(t, floatingUninitialized, tb.floating.state) | ||
| 542 | require.Nil(t, tb.floating.pane) | 543 | require.Nil(t, tb.floating.pane) | ||
| 543 | tb.mu.Unlock() | 544 | tb.mu.Unlock() | ||
| 544 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | 545 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) |
| 545 | - | output, err := ports.UnmarshalOutput(repaint.Payload) | 546 | + | output, err := wire.UnmarshalOutput(repaint.Payload) |
| 546 | require.NoError(t, err) | 547 | require.NoError(t, err) | ||
| 547 | require.Zero(t, output.Base, "visible EOF must force a dependency-free full repaint") | 548 | require.Zero(t, output.Base, "visible EOF must force a dependency-free full repaint") | ||
| 548 | require.Contains(t, string(output.Data), "underlying-cell", "repaint must restore cells previously covered by the popup") | 549 | require.Contains(t, string(output.Data), "underlying-cell", "repaint must restore cells previously covered by the popup") | ||
M internal/usecase/daemon/graphics_output_test.go +12 -11
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | "github.com/bnema/vev/internal/domain" | 15 | "github.com/bnema/vev/internal/domain" | ||
| 16 | "github.com/bnema/vev/internal/ports" | 16 | "github.com/bnema/vev/internal/ports" | ||
| 17 | "github.com/bnema/vev/internal/protocol" | 17 | "github.com/bnema/vev/internal/protocol" | ||
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 18 | "github.com/bnema/vev/internal/usecase/layout" | 19 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 19 | "github.com/stretchr/testify/require" | 20 | "github.com/stretchr/testify/require" | ||
| 20 | ) | 21 | ) | ||
| @@ -53,7 +54,7 @@ type lateGraphicsCleanupTransport struct { | |||||
| 53 | started chan struct{} | 54 | started chan struct{} | ||
| 54 | release chan struct{} | 55 | release chan struct{} | ||
| 55 | finished chan struct{} | 56 | finished chan struct{} | ||
| 56 | - | sends chan ports.Frame | 57 | + | sends chan wire.Frame |
| 57 | startedOnce sync.Once | 58 | startedOnce sync.Once | ||
| 58 | finishOnce sync.Once | 59 | finishOnce sync.Once | ||
| 59 | } | 60 | } | ||
| @@ -63,11 +64,11 @@ func newLateGraphicsCleanupTransport() *lateGraphicsCleanupTransport { | |||||
| 63 | started: make(chan struct{}), | 64 | started: make(chan struct{}), | ||
| 64 | release: make(chan struct{}), | 65 | release: make(chan struct{}), | ||
| 65 | finished: make(chan struct{}), | 66 | finished: make(chan struct{}), | ||
| 66 | - | sends: make(chan ports.Frame, 1), | 67 | + | sends: make(chan wire.Frame, 1), |
| 67 | } | 68 | } | ||
| 68 | } | 69 | } | ||
| 69 | 70 | ||||
| 70 | - | func (t *lateGraphicsCleanupTransport) Send(frame ports.Frame) error { | 71 | + | func (t *lateGraphicsCleanupTransport) Send(frame wire.Frame) error { |
| 71 | t.startedOnce.Do(func() { close(t.started) }) | 72 | t.startedOnce.Do(func() { close(t.started) }) | ||
| 72 | <-t.release | 73 | <-t.release | ||
| 73 | t.sends <- frame | 74 | t.sends <- frame | ||
| @@ -75,8 +76,8 @@ func (t *lateGraphicsCleanupTransport) Send(frame ports.Frame) error { | |||||
| 75 | return nil | 76 | return nil | ||
| 76 | } | 77 | } | ||
| 77 | 78 | ||||
| 78 | - | func (*lateGraphicsCleanupTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 79 | + | func (*lateGraphicsCleanupTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 79 | - | func (*lateGraphicsCleanupTransport) Close() error { return nil } | 80 | + | func (*lateGraphicsCleanupTransport) Close() error { return nil } |
| 80 | 81 | ||||
| 81 | func TestGraphicsOutputReplaysStaticKittenIcatFixture(t *testing.T) { | 82 | func TestGraphicsOutputReplaysStaticKittenIcatFixture(t *testing.T) { | ||
| 82 | state := newGraphicsOutputState() | 83 | state := newGraphicsOutputState() | ||
| @@ -127,8 +128,8 @@ func TestKittyAttachmentPaintCarriesGraphicsInTheOutputStateRecord(t *testing.T) | |||||
| 127 | pane.screen.Write(fixture) | 128 | pane.screen.Write(fixture) | ||
| 128 | 129 | ||||
| 129 | d.paint(sess, ac, true, nil) | 130 | d.paint(sess, ac, true, nil) | ||
| 130 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | 131 | + | frame := awaitFrame(t, sends, wire.MsgOutput) |
| 131 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 132 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 132 | require.NoError(t, err) | 133 | require.NoError(t, err) | ||
| 133 | require.Contains(t, string(output.Data), "\x1b_Ga=t,i=") | 134 | require.Contains(t, string(output.Data), "\x1b_Ga=t,i=") | ||
| 134 | require.Contains(t, string(output.Data), ",f=100") | 135 | require.Contains(t, string(output.Data), ",f=100") | ||
| @@ -157,8 +158,8 @@ func TestFreshCapabilityDowngradePreservesForeignTerminalGraphics(t *testing.T) | |||||
| 157 | require.False(t, ac.output.graphicsUnsupportedWarned.Load(), "replacement terminal must receive its own unsupported-graphics warning") | 158 | require.False(t, ac.output.graphicsUnsupportedWarned.Load(), "replacement terminal must receive its own unsupported-graphics warning") | ||
| 158 | 159 | ||||
| 159 | d.paint(sess, ac, true, nil) | 160 | d.paint(sess, ac, true, nil) | ||
| 160 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | 161 | + | frame := awaitFrame(t, sends, wire.MsgOutput) |
| 161 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 162 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 162 | require.NoError(t, err) | 163 | require.NoError(t, err) | ||
| 163 | require.Positive(t, output.New) | 164 | require.Positive(t, output.New) | ||
| 164 | require.NotContains(t, string(output.Data), "\x1b_Ga=d,d=A", "vev must never globally delete terminal images") | 165 | require.NotContains(t, string(output.Data), "\x1b_Ga=d,d=A", "vev must never globally delete terminal images") | ||
| @@ -449,7 +450,7 @@ func TestGraphicsNamespaceStaysQuarantinedAfterSocketSendSuccessWithoutTerminalF | |||||
| 449 | require.Nil(t, ac.output.graphicsOutput) | 450 | require.Nil(t, ac.output.graphicsOutput) | ||
| 450 | sends := transport.Sends() | 451 | sends := transport.Sends() | ||
| 451 | require.Len(t, sends, 1) | 452 | require.Len(t, sends, 1) | ||
| 452 | - | cleanup, err := ports.UnmarshalOutput(sends[0].Payload) | 453 | + | cleanup, err := wire.UnmarshalOutput(sends[0].Payload) |
| 453 | require.NoError(t, err) | 454 | require.NoError(t, err) | ||
| 454 | require.Zero(t, cleanup.New, "graphics cleanup is an unacknowledged side-effect frame") | 455 | require.Zero(t, cleanup.New, "graphics cleanup is an unacknowledged side-effect frame") | ||
| 455 | 456 | ||||
| @@ -572,7 +573,7 @@ func TestGraphicsNamespaceQuarantineFencesTimedOutLateDelete(t *testing.T) { | |||||
| 572 | close(transport.release) | 573 | close(transport.release) | ||
| 573 | staleFrame := awaitTestValue(t, transport.sends, "late stale cleanup did not execute") | 574 | staleFrame := awaitTestValue(t, transport.sends, "late stale cleanup did not execute") | ||
| 574 | awaitTestCompletion(t, transport.finished, "late stale cleanup did not return") | 575 | awaitTestCompletion(t, transport.finished, "late stale cleanup did not return") | ||
| 575 | - | staleOutput, err := ports.UnmarshalOutput(staleFrame.Payload) | 576 | + | staleOutput, err := wire.UnmarshalOutput(staleFrame.Payload) |
| 576 | require.NoError(t, err) | 577 | require.NoError(t, err) | ||
| 577 | require.Contains(t, string(staleOutput.Data), "i="+strconv.FormatUint(oldID, 10)) | 578 | require.Contains(t, string(staleOutput.Data), "i="+strconv.FormatUint(oldID, 10)) | ||
| 578 | require.NotContains(t, string(staleOutput.Data), "i="+strconv.FormatUint(newID, 10), "late cleanup must never target the fresh attachment") | 579 | require.NotContains(t, string(staleOutput.Data), "i="+strconv.FormatUint(newID, 10), "late cleanup must never target the fresh attachment") | ||
M internal/usecase/daemon/handshake_test.go +6 -6
| @@ -10,8 +10,8 @@ import ( | |||||
| 10 | "github.com/stretchr/testify/require" | 10 | "github.com/stretchr/testify/require" | ||
| 11 | 11 | ||||
| 12 | "github.com/bnema/vev/internal/domain" | 12 | "github.com/bnema/vev/internal/domain" | ||
| 13 | - | "github.com/bnema/vev/internal/ports" | |||
| 14 | "github.com/bnema/vev/internal/protocol" | 13 | "github.com/bnema/vev/internal/protocol" | ||
| 14 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 15 | ) | 15 | ) | ||
| 16 | 16 | ||||
| 17 | type handshakeBlockingTransport struct { | 17 | type handshakeBlockingTransport struct { | ||
| @@ -29,8 +29,8 @@ func newHandshakeBlockingTransport(blockWelcome bool) *handshakeBlockingTranspor | |||||
| 29 | } | 29 | } | ||
| 30 | } | 30 | } | ||
| 31 | 31 | ||||
| 32 | - | func (t *handshakeBlockingTransport) Send(frame ports.Frame) error { | 32 | + | func (t *handshakeBlockingTransport) Send(frame wire.Frame) error { |
| 33 | - | if t.blockWelcome && frame.Type == ports.MsgWelcome { | 33 | + | if t.blockWelcome && frame.Type == wire.MsgWelcome { |
| 34 | close(t.welcome) | 34 | close(t.welcome) | ||
| 35 | <-t.closed | 35 | <-t.closed | ||
| 36 | return io.ErrClosedPipe | 36 | return io.ErrClosedPipe | ||
| @@ -38,9 +38,9 @@ func (t *handshakeBlockingTransport) Send(frame ports.Frame) error { | |||||
| 38 | return nil | 38 | return nil | ||
| 39 | } | 39 | } | ||
| 40 | 40 | ||||
| 41 | - | func (t *handshakeBlockingTransport) Recv() (ports.Frame, error) { | 41 | + | func (t *handshakeBlockingTransport) Recv() (wire.Frame, error) { |
| 42 | <-t.closed | 42 | <-t.closed | ||
| 43 | - | return ports.Frame{}, io.ErrClosedPipe | 43 | + | return wire.Frame{}, io.ErrClosedPipe |
| 44 | } | 44 | } | ||
| 45 | 45 | ||||
| 46 | func (t *handshakeBlockingTransport) Close() error { | 46 | func (t *handshakeBlockingTransport) Close() error { | ||
| @@ -183,7 +183,7 @@ func TestFailedResumeHandshakeRestoresParkedCredential(t *testing.T) { | |||||
| 183 | resumeTransport := newHandshakeBlockingTransport(true) | 183 | resumeTransport := newHandshakeBlockingTransport(true) | ||
| 184 | done := make(chan struct{}) | 184 | done := make(chan struct{}) | ||
| 185 | go func() { | 185 | go func() { | ||
| 186 | - | d.handleHello(resumeTransport, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(helloResumeCapable(protocol.IntentResume, sess.name, token))}) | 186 | + | d.handleHello(resumeTransport, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(helloResumeCapable(protocol.IntentResume, sess.name, token))}) |
| 187 | close(done) | 187 | close(done) | ||
| 188 | }() | 188 | }() | ||
| 189 | 189 | ||||
M internal/usecase/daemon/input_test.go +29 -29
| @@ -15,9 +15,9 @@ import ( | |||||
| 15 | 15 | ||||
| 16 | vt "github.com/bnema/vev-vt" | 16 | vt "github.com/bnema/vev-vt" | ||
| 17 | "github.com/bnema/vev/internal/domain" | 17 | "github.com/bnema/vev/internal/domain" | ||
| 18 | - | "github.com/bnema/vev/internal/ports" | |||
| 19 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 20 | "github.com/bnema/vev/internal/protocol" | 19 | "github.com/bnema/vev/internal/protocol" | ||
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 21 | scopy "github.com/bnema/vev/internal/usecase/copy" | 21 | scopy "github.com/bnema/vev/internal/usecase/copy" | ||
| 22 | "github.com/bnema/vev/internal/usecase/keys" | 22 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 23 | "github.com/bnema/vev/internal/usecase/layout" | 23 | "github.com/bnema/vev/internal/usecase/layout" | ||
| @@ -196,8 +196,8 @@ func TestSwitchTabFirstFrameDoesNotReuseSamePaneIDCapture(t *testing.T) { | |||||
| 196 | source.screen.Write([]byte("source")) | 196 | source.screen.Write([]byte("source")) | ||
| 197 | source.mu.Unlock() | 197 | source.mu.Unlock() | ||
| 198 | d.paint(sess, ac, true, nil) | 198 | d.paint(sess, ac, true, nil) | ||
| 199 | - | first := awaitFrame(t, sends, ports.MsgOutput) | 199 | + | first := awaitFrame(t, sends, wire.MsgOutput) |
| 200 | - | firstOutput, err := ports.UnmarshalOutput(first.Payload) | 200 | + | firstOutput, err := wire.UnmarshalOutput(first.Payload) |
| 201 | require.NoError(t, err) | 201 | require.NoError(t, err) | ||
| 202 | terminal := vt.NewScreen(ac.size.Cols, ac.size.Rows) | 202 | terminal := vt.NewScreen(ac.size.Cols, ac.size.Rows) | ||
| 203 | terminal.Write(firstOutput.Data) | 203 | terminal.Write(firstOutput.Data) | ||
| @@ -212,8 +212,8 @@ func TestSwitchTabFirstFrameDoesNotReuseSamePaneIDCapture(t *testing.T) { | |||||
| 212 | daemonKeyHandler{d: d, ac: ac}.Action(keys.ActionSwitchTab2, nil) | 212 | daemonKeyHandler{d: d, ac: ac}.Action(keys.ActionSwitchTab2, nil) | ||
| 213 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | 213 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | ||
| 214 | 214 | ||||
| 215 | - | second := awaitFrame(t, sends, ports.MsgOutput) | 215 | + | second := awaitFrame(t, sends, wire.MsgOutput) |
| 216 | - | secondOutput, err := ports.UnmarshalOutput(second.Payload) | 216 | + | secondOutput, err := wire.UnmarshalOutput(second.Payload) |
| 217 | require.NoError(t, err) | 217 | require.NoError(t, err) | ||
| 218 | require.Zero(t, secondOutput.Base, "tab switch must emit the complete target frame first") | 218 | require.Zero(t, secondOutput.Base, "tab switch must emit the complete target frame first") | ||
| 219 | terminal.Write(secondOutput.Data) | 219 | terminal.Write(secondOutput.Data) | ||
| @@ -309,11 +309,11 @@ func TestAltFToggleRetainedFloatingPaneRepaintsImmediately(t *testing.T) { | |||||
| 309 | 309 | ||||
| 310 | // Establish the client shadow while the retained popup is hidden. | 310 | // Establish the client shadow while the retained popup is hidden. | ||
| 311 | d.paint(sess, ac, true, nil) | 311 | d.paint(sess, ac, true, nil) | ||
| 312 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 312 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 313 | 313 | ||||
| 314 | // Route the real Alt+F binding. Showing a retained pane must paint once. | 314 | // Route the real Alt+F binding. Showing a retained pane must paint once. | ||
| 315 | d.handleInput(sess, ac, []byte("\x1bf")) | 315 | d.handleInput(sess, ac, []byte("\x1bf")) | ||
| 316 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 316 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 317 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | 317 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | ||
| 318 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "┌") | 318 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "┌") | ||
| 319 | select { | 319 | select { | ||
| @@ -325,7 +325,7 @@ func TestAltFToggleRetainedFloatingPaneRepaintsImmediately(t *testing.T) { | |||||
| 325 | // The second real key must repaint immediately, rather than waiting for | 325 | // The second real key must repaint immediately, rather than waiting for | ||
| 326 | // unrelated output, while retaining the existing PTY and context. | 326 | // unrelated output, while retaining the existing PTY and context. | ||
| 327 | d.handleInput(sess, ac, []byte("\x1bf")) | 327 | d.handleInput(sess, ac, []byte("\x1bf")) | ||
| 328 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 328 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 329 | require.NotContains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | 329 | require.NotContains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | ||
| 330 | tb := testAttachmentTab(sess) | 330 | tb := testAttachmentTab(sess) | ||
| 331 | tb.mu.Lock() | 331 | tb.mu.Lock() | ||
| @@ -343,7 +343,7 @@ func TestAltFToggleRetainedFloatingPaneRepaintsImmediately(t *testing.T) { | |||||
| 343 | // A third show uses the installed pane; it must not launch or emit a second | 343 | // A third show uses the installed pane; it must not launch or emit a second | ||
| 344 | // resize/start frame. | 344 | // resize/start frame. | ||
| 345 | d.handleInput(sess, ac, []byte("\x1bf")) | 345 | d.handleInput(sess, ac, []byte("\x1bf")) | ||
| 346 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 346 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 347 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | 347 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | ||
| 348 | tb.mu.Lock() | 348 | tb.mu.Lock() | ||
| 349 | require.Equal(t, floatingVisible, tb.floating.state) | 349 | require.Equal(t, floatingVisible, tb.floating.state) | ||
| @@ -630,13 +630,13 @@ func TestBracketedMultilinePasteForwardsDelimitersAndNewlines(t *testing.T) { | |||||
| 630 | func TestOverlayInputPrecedence(t *testing.T) { | 630 | func TestOverlayInputPrecedence(t *testing.T) { | ||
| 631 | cases := []struct { | 631 | cases := []struct { | ||
| 632 | name string | 632 | name string | ||
| 633 | - | setup func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) | 633 | + | setup func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) |
| 634 | input []byte | 634 | input []byte | ||
| 635 | check func(t *testing.T, ac *attachedClient, writes chan []byte) | 635 | check func(t *testing.T, ac *attachedClient, writes chan []byte) | ||
| 636 | }{ | 636 | }{ | ||
| 637 | { | 637 | { | ||
| 638 | name: "prompt before palette picker copy and normal", | 638 | name: "prompt before palette picker copy and normal", | ||
| 639 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | 639 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { |
| 640 | t.Helper() | 640 | t.Helper() | ||
| 641 | d.enterCopyMode(sess, ac) | 641 | d.enterCopyMode(sess, ac) | ||
| 642 | d.enterPicker(sess, ac) | 642 | d.enterPicker(sess, ac) | ||
| @@ -655,7 +655,7 @@ func TestOverlayInputPrecedence(t *testing.T) { | |||||
| 655 | }, | 655 | }, | ||
| 656 | { | 656 | { | ||
| 657 | name: "palette before picker copy and normal", | 657 | name: "palette before picker copy and normal", | ||
| 658 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | 658 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { |
| 659 | t.Helper() | 659 | t.Helper() | ||
| 660 | d.enterCopyMode(sess, ac) | 660 | d.enterCopyMode(sess, ac) | ||
| 661 | d.enterPicker(sess, ac) | 661 | d.enterPicker(sess, ac) | ||
| @@ -672,7 +672,7 @@ func TestOverlayInputPrecedence(t *testing.T) { | |||||
| 672 | }, | 672 | }, | ||
| 673 | { | 673 | { | ||
| 674 | name: "picker before copy and normal", | 674 | name: "picker before copy and normal", | ||
| 675 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | 675 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { |
| 676 | t.Helper() | 676 | t.Helper() | ||
| 677 | d.enterCopyMode(sess, ac) | 677 | d.enterCopyMode(sess, ac) | ||
| 678 | d.enterPicker(sess, ac) | 678 | d.enterPicker(sess, ac) | ||
| @@ -689,7 +689,7 @@ func TestOverlayInputPrecedence(t *testing.T) { | |||||
| 689 | }, | 689 | }, | ||
| 690 | { | 690 | { | ||
| 691 | name: "copy before normal", | 691 | name: "copy before normal", | ||
| 692 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | 692 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { |
| 693 | t.Helper() | 693 | t.Helper() | ||
| 694 | d.enterCopyMode(sess, ac) | 694 | d.enterCopyMode(sess, ac) | ||
| 695 | }, | 695 | }, | ||
| @@ -798,8 +798,8 @@ func TestPaletteBackSessionSendsClientPreviousRouteAction(t *testing.T) { | |||||
| 798 | }) | 798 | }) | ||
| 799 | 799 | ||||
| 800 | require.NoError(t, d.backSessionForAttachment(effect)) | 800 | require.NoError(t, d.backSessionForAttachment(effect)) | ||
| 801 | - | frame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | 801 | + | frame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) |
| 802 | - | action, err := ports.UnmarshalRouteNavigationAction(frame.Payload) | 802 | + | action, err := wire.UnmarshalRouteNavigationAction(frame.Payload) |
| 803 | require.NoError(t, err) | 803 | require.NoError(t, err) | ||
| 804 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 3, Key: 2, Generation: 2}, action) | 804 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 3, Key: 2, Generation: 2}, action) | ||
| 805 | } | 805 | } | ||
| @@ -825,7 +825,7 @@ func TestSwitchSourceDoesNotOwnPreviousRoute(t *testing.T) { | |||||
| 825 | require.Equal(t, uint64(0), ac.routeSnapshotCopy().Generation, "route ownership starts in the client") | 825 | require.Equal(t, uint64(0), ac.routeSnapshotCopy().Generation, "route ownership starts in the client") | ||
| 826 | } | 826 | } | ||
| 827 | 827 | ||||
| 828 | - | func newRecentNavigationTestSessions(t *testing.T) (*Daemon, *session, *attachedClient, chan ports.Frame, []func()) { | 828 | + | func newRecentNavigationTestSessions(t *testing.T) (*Daemon, *session, *attachedClient, chan wire.Frame, []func()) { |
| 829 | t.Helper() | 829 | t.Helper() | ||
| 830 | p1, release1 := newBlockingPTY(t) | 830 | p1, release1 := newBlockingPTY(t) | ||
| 831 | p2, release2 := newBlockingPTY(t) | 831 | p2, release2 := newBlockingPTY(t) | ||
| @@ -881,8 +881,8 @@ func TestAltDDetachesCurrentClient(t *testing.T) { | |||||
| 881 | d.handleInput(sess, ac, []byte("DET\r")) | 881 | d.handleInput(sess, ac, []byte("DET\r")) | ||
| 882 | 882 | ||||
| 883 | require.Empty(t, sess.snapshotAttachments()) | 883 | require.Empty(t, sess.snapshotAttachments()) | ||
| 884 | - | f := awaitFrame(t, sends, ports.MsgDetached) | 884 | + | f := awaitFrame(t, sends, wire.MsgDetached) |
| 885 | - | det, err := ports.UnmarshalDetached(f.Payload) | 885 | + | det, err := wire.UnmarshalDetached(f.Payload) |
| 886 | require.NoError(t, err) | 886 | require.NoError(t, err) | ||
| 887 | require.Equal(t, protocol.ReasonDetach, det.Reason) | 887 | require.Equal(t, protocol.ReasonDetach, det.Reason) | ||
| 888 | } | 888 | } | ||
| @@ -894,13 +894,13 @@ func TestRNSOpensPromptAndEnterPromotesEphemeralSession(t *testing.T) { | |||||
| 894 | sess.name = "0" | 894 | sess.name = "0" | ||
| 895 | 895 | ||||
| 896 | d.handleInput(sess, ac, []byte("\x1b ")) | 896 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 897 | - | awaitFrame(t, sends, ports.MsgOutput) | 897 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 898 | d.handleInput(sess, ac, []byte("RNS\r")) | 898 | d.handleInput(sess, ac, []byte("RNS\r")) | ||
| 899 | - | awaitFrame(t, sends, ports.MsgOutput) | 899 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 900 | require.True(t, ac.overlays.promptActive()) | 900 | require.True(t, ac.overlays.promptActive()) | ||
| 901 | 901 | ||||
| 902 | d.handleInput(sess, ac, []byte("\r")) | 902 | d.handleInput(sess, ac, []byte("\r")) | ||
| 903 | - | awaitFrame(t, sends, ports.MsgOutput) | 903 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 904 | 904 | ||||
| 905 | require.False(t, ac.overlays.promptActive()) | 905 | require.False(t, ac.overlays.promptActive()) | ||
| 906 | require.False(t, sess.ephemeral) | 906 | require.False(t, sess.ephemeral) | ||
| @@ -917,16 +917,16 @@ func TestRNTOpensPromptAndRenamesActiveTab(t *testing.T) { | |||||
| 917 | selectTestAttachmentTab(sess, 1) | 917 | selectTestAttachmentTab(sess, 1) | ||
| 918 | 918 | ||||
| 919 | d.handleInput(sess, ac, []byte("\x1b ")) | 919 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 920 | - | awaitFrame(t, sends, ports.MsgOutput) | 920 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 921 | d.handleInput(sess, ac, []byte("RNT\r")) | 921 | d.handleInput(sess, ac, []byte("RNT\r")) | ||
| 922 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 922 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 923 | require.True(t, ac.overlays.promptActive()) | 923 | require.True(t, ac.overlays.promptActive()) | ||
| 924 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 924 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 925 | require.NoError(t, err) | 925 | require.NoError(t, err) | ||
| 926 | require.Contains(t, string(msg.Data), "> 2") | 926 | require.Contains(t, string(msg.Data), "> 2") | ||
| 927 | 927 | ||||
| 928 | d.handleInput(sess, ac, []byte("\x7flogs\r")) | 928 | d.handleInput(sess, ac, []byte("\x7flogs\r")) | ||
| 929 | - | awaitFrame(t, sends, ports.MsgOutput) | 929 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 930 | 930 | ||||
| 931 | require.False(t, ac.overlays.promptActive()) | 931 | require.False(t, ac.overlays.promptActive()) | ||
| 932 | require.Equal(t, "logs", sess.tabs[1].name) | 932 | require.Equal(t, "logs", sess.tabs[1].name) | ||
| @@ -1091,9 +1091,9 @@ func TestCopyModeMouseHorizontalReverseDragUsesExactOSC52(t *testing.T) { | |||||
| 1091 | d.handleInput(sess, ac, []byte("y")) | 1091 | d.handleInput(sess, ac, []byte("y")) | ||
| 1092 | var msg protocol.Output | 1092 | var msg protocol.Output | ||
| 1093 | require.Eventually(t, func() bool { | 1093 | require.Eventually(t, func() bool { | ||
| 1094 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | 1094 | + | frame := awaitFrame(t, sends, wire.MsgOutput) |
| 1095 | var err error | 1095 | var err error | ||
| 1096 | - | msg, err = ports.UnmarshalOutput(frame.Payload) | 1096 | + | msg, err = wire.UnmarshalOutput(frame.Payload) |
| 1097 | return err == nil && string(msg.Data) == string(scopy.OSC52("lph")[0]) | 1097 | return err == nil && string(msg.Data) == string(scopy.OSC52("lph")[0]) | ||
| 1098 | }, 2*time.Second, 5*time.Millisecond) | 1098 | }, 2*time.Second, 5*time.Millisecond) | ||
| 1099 | require.Equal(t, scopy.OSC52("lph")[0], msg.Data) | 1099 | require.Equal(t, scopy.OSC52("lph")[0], msg.Data) | ||
| @@ -1573,7 +1573,7 @@ func TestMouseGatedWhileNoticesOverlayActive(t *testing.T) { | |||||
| 1573 | 1573 | ||||
| 1574 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | 1574 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | ||
| 1575 | d.enterNotices(sess, ac) | 1575 | d.enterNotices(sess, ac) | ||
| 1576 | - | awaitFrame(t, sends, ports.MsgOutput) | 1576 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1577 | require.True(t, ac.overlays.noticesActive()) | 1577 | require.True(t, ac.overlays.noticesActive()) | ||
| 1578 | 1578 | ||||
| 1579 | // Same coordinates that TestMouseHitTestFocusesPaneAndTranslatesSGRColumns | 1579 | // Same coordinates that TestMouseHitTestFocusesPaneAndTranslatesSGRColumns | ||
M internal/usecase/daemon/notice_render_test.go +7 -7
| @@ -9,24 +9,24 @@ import ( | |||||
| 9 | 9 | ||||
| 10 | vt "github.com/bnema/vev-vt" | 10 | vt "github.com/bnema/vev-vt" | ||
| 11 | "github.com/bnema/vev/internal/domain" | 11 | "github.com/bnema/vev/internal/domain" | ||
| 12 | - | "github.com/bnema/vev/internal/ports" | 12 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | // replayOutputFrames decodes and writes each MsgOutput frame's terminal bytes | 15 | // replayOutputFrames decodes and writes each MsgOutput frame's terminal bytes | ||
| 16 | // into screen, growing its shadow the same way a real client would. | 16 | // into screen, growing its shadow the same way a real client would. | ||
| 17 | - | func replayOutputFrames(t *testing.T, screen *vt.Screen, frames []ports.Frame) { | 17 | + | func replayOutputFrames(t *testing.T, screen *vt.Screen, frames []wire.Frame) { |
| 18 | t.Helper() | 18 | t.Helper() | ||
| 19 | for _, f := range frames { | 19 | for _, f := range frames { | ||
| 20 | - | require.Equal(t, ports.MsgOutput, f.Type) | 20 | + | require.Equal(t, wire.MsgOutput, f.Type) |
| 21 | - | out, err := ports.UnmarshalOutput(f.Payload) | 21 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 22 | require.NoError(t, err) | 22 | require.NoError(t, err) | ||
| 23 | screen.Write(out.Data) | 23 | screen.Write(out.Data) | ||
| 24 | } | 24 | } | ||
| 25 | } | 25 | } | ||
| 26 | 26 | ||||
| 27 | // drainAllFrames collects every frame already queued on sends without blocking. | 27 | // drainAllFrames collects every frame already queued on sends without blocking. | ||
| 28 | - | func drainAllFrames(sends chan ports.Frame) []ports.Frame { | 28 | + | func drainAllFrames(sends chan wire.Frame) []wire.Frame { |
| 29 | - | var out []ports.Frame | 29 | + | var out []wire.Frame |
| 30 | for { | 30 | for { | ||
| 31 | select { | 31 | select { | ||
| 32 | case f := <-sends: | 32 | case f := <-sends: | ||
| @@ -96,7 +96,7 @@ func TestPaintComposesNoticeToastTopRightAndExpiresOnTTL(t *testing.T) { | |||||
| 96 | awaitToastCount(t, ac, 0) | 96 | awaitToastCount(t, ac, 0) | ||
| 97 | select { | 97 | select { | ||
| 98 | case f := <-sends: | 98 | case f := <-sends: | ||
| 99 | - | replayOutputFrames(t, screen, append([]ports.Frame{f}, drainAllFrames(sends)...)) | 99 | + | replayOutputFrames(t, screen, append([]wire.Frame{f}, drainAllFrames(sends)...)) |
| 100 | case <-time.After(2 * time.Second): | 100 | case <-time.After(2 * time.Second): | ||
| 101 | t.Fatal("expiry did not invalidate the render") | 101 | t.Fatal("expiry did not invalidate the render") | ||
| 102 | } | 102 | } | ||
M internal/usecase/daemon/notices_overlay_test.go +31 -31
| @@ -11,7 +11,7 @@ import ( | |||||
| 11 | 11 | ||||
| 12 | renderer "github.com/bnema/vev-vt" | 12 | renderer "github.com/bnema/vev-vt" | ||
| 13 | "github.com/bnema/vev/internal/domain" | 13 | "github.com/bnema/vev/internal/domain" | ||
| 14 | - | "github.com/bnema/vev/internal/ports" | 14 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 15 | "github.com/bnema/vev/internal/usecase/notices" | 15 | "github.com/bnema/vev/internal/usecase/notices" | ||
| 16 | themeui "github.com/bnema/vev/internal/usecase/theme" | 16 | themeui "github.com/bnema/vev/internal/usecase/theme" | ||
| 17 | ) | 17 | ) | ||
| @@ -47,13 +47,13 @@ func TestNoticesOpenViaPaletteCommandShowsModalWithHistory(t *testing.T) { | |||||
| 47 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Severity: domain.NoticeError, Message: "couldn't open pane", Time: time.Unix(1, 0)}) | 47 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Severity: domain.NoticeError, Message: "couldn't open pane", Time: time.Unix(1, 0)}) | ||
| 48 | 48 | ||||
| 49 | d.enterPalette(sess, ac) | 49 | d.enterPalette(sess, ac) | ||
| 50 | - | awaitFrame(t, sends, ports.MsgOutput) | 50 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 51 | d.handlePaletteInput(ac, []byte("NTC\r")) | 51 | d.handlePaletteInput(ac, []byte("NTC\r")) | ||
| 52 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 52 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 53 | 53 | ||||
| 54 | require.False(t, ac.overlays.paletteActive()) | 54 | require.False(t, ac.overlays.paletteActive()) | ||
| 55 | require.NotNil(t, ac.overlays.noticesOverlay) | 55 | require.NotNil(t, ac.overlays.noticesOverlay) | ||
| 56 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 56 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 57 | require.NoError(t, err) | 57 | require.NoError(t, err) | ||
| 58 | require.Contains(t, string(msg.Data), "Notifications") | 58 | require.Contains(t, string(msg.Data), "Notifications") | ||
| 59 | require.Contains(t, string(msg.Data), "pane-spawn") | 59 | require.Contains(t, string(msg.Data), "pane-spawn") | ||
| @@ -69,32 +69,32 @@ func TestNoticesJKNavigatesSelection(t *testing.T) { | |||||
| 69 | d.notices.record(domain.Notification{Code: domain.NoticeInternal, Message: "third", Time: time.Unix(3, 0)}) | 69 | d.notices.record(domain.Notification{Code: domain.NoticeInternal, Message: "third", Time: time.Unix(3, 0)}) | ||
| 70 | 70 | ||||
| 71 | d.enterNotices(sess, ac) | 71 | d.enterNotices(sess, ac) | ||
| 72 | - | awaitFrame(t, sends, ports.MsgOutput) | 72 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 73 | selected, ok := ac.overlays.noticesOverlay.Selected() | 73 | selected, ok := ac.overlays.noticesOverlay.Selected() | ||
| 74 | require.True(t, ok) | 74 | require.True(t, ok) | ||
| 75 | require.Equal(t, "third", selected.Message) | 75 | require.Equal(t, "third", selected.Message) | ||
| 76 | 76 | ||||
| 77 | d.handleInput(sess, ac, []byte("j")) | 77 | d.handleInput(sess, ac, []byte("j")) | ||
| 78 | - | awaitFrame(t, sends, ports.MsgOutput) | 78 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 79 | selected, ok = ac.overlays.noticesOverlay.Selected() | 79 | selected, ok = ac.overlays.noticesOverlay.Selected() | ||
| 80 | require.True(t, ok) | 80 | require.True(t, ok) | ||
| 81 | require.Equal(t, "second", selected.Message) | 81 | require.Equal(t, "second", selected.Message) | ||
| 82 | 82 | ||||
| 83 | d.handleInput(sess, ac, []byte("j")) | 83 | d.handleInput(sess, ac, []byte("j")) | ||
| 84 | - | awaitFrame(t, sends, ports.MsgOutput) | 84 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 85 | selected, ok = ac.overlays.noticesOverlay.Selected() | 85 | selected, ok = ac.overlays.noticesOverlay.Selected() | ||
| 86 | require.True(t, ok) | 86 | require.True(t, ok) | ||
| 87 | require.Equal(t, "first", selected.Message) | 87 | require.Equal(t, "first", selected.Message) | ||
| 88 | 88 | ||||
| 89 | // One more 'j' at the bottom must clamp rather than wrap. | 89 | // One more 'j' at the bottom must clamp rather than wrap. | ||
| 90 | d.handleInput(sess, ac, []byte("j")) | 90 | d.handleInput(sess, ac, []byte("j")) | ||
| 91 | - | awaitFrame(t, sends, ports.MsgOutput) | 91 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 92 | selected, ok = ac.overlays.noticesOverlay.Selected() | 92 | selected, ok = ac.overlays.noticesOverlay.Selected() | ||
| 93 | require.True(t, ok) | 93 | require.True(t, ok) | ||
| 94 | require.Equal(t, "first", selected.Message) | 94 | require.Equal(t, "first", selected.Message) | ||
| 95 | 95 | ||||
| 96 | d.handleInput(sess, ac, []byte("k")) | 96 | d.handleInput(sess, ac, []byte("k")) | ||
| 97 | - | awaitFrame(t, sends, ports.MsgOutput) | 97 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 98 | selected, ok = ac.overlays.noticesOverlay.Selected() | 98 | selected, ok = ac.overlays.noticesOverlay.Selected() | ||
| 99 | require.True(t, ok) | 99 | require.True(t, ok) | ||
| 100 | require.Equal(t, "second", selected.Message) | 100 | require.Equal(t, "second", selected.Message) | ||
| @@ -109,11 +109,11 @@ func TestNoticesQAndCtrlCCloseImmediatelyAndClearState(t *testing.T) { | |||||
| 109 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | 109 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | ||
| 110 | 110 | ||||
| 111 | d.enterNotices(sess, ac) | 111 | d.enterNotices(sess, ac) | ||
| 112 | - | awaitFrame(t, sends, ports.MsgOutput) | 112 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 113 | require.True(t, ac.overlays.noticesActive()) | 113 | require.True(t, ac.overlays.noticesActive()) | ||
| 114 | 114 | ||||
| 115 | d.handleInput(sess, ac, []byte{key}) | 115 | d.handleInput(sess, ac, []byte{key}) | ||
| 116 | - | awaitFrame(t, sends, ports.MsgOutput) | 116 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 117 | 117 | ||||
| 118 | require.False(t, ac.overlays.noticesActive()) | 118 | require.False(t, ac.overlays.noticesActive()) | ||
| 119 | require.Nil(t, ac.overlays.noticesOverlay) | 119 | require.Nil(t, ac.overlays.noticesOverlay) | ||
| @@ -128,7 +128,7 @@ func TestNoticesLoneEscapeClosesAfterDelay(t *testing.T) { | |||||
| 128 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | 128 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | ||
| 129 | 129 | ||||
| 130 | d.enterNotices(sess, ac) | 130 | d.enterNotices(sess, ac) | ||
| 131 | - | awaitFrame(t, sends, ports.MsgOutput) | 131 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 132 | 132 | ||||
| 133 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | 133 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | ||
| 134 | d.clock = clk | 134 | d.clock = clk | ||
| @@ -138,7 +138,7 @@ func TestNoticesLoneEscapeClosesAfterDelay(t *testing.T) { | |||||
| 138 | 138 | ||||
| 139 | timer.ch <- time.Now() | 139 | timer.ch <- time.Now() | ||
| 140 | require.Eventually(t, func() bool { return !ac.overlays.noticesActive() }, time.Second, 5*time.Millisecond) | 140 | require.Eventually(t, func() bool { return !ac.overlays.noticesActive() }, time.Second, 5*time.Millisecond) | ||
| 141 | - | awaitFrame(t, sends, ports.MsgOutput) | 141 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 142 | } | 142 | } | ||
| 143 | 143 | ||||
| 144 | func TestNoticesSplitArrowNavigatesWithoutClosing(t *testing.T) { | 144 | func TestNoticesSplitArrowNavigatesWithoutClosing(t *testing.T) { | ||
| @@ -161,7 +161,7 @@ func TestNoticesSplitArrowNavigatesWithoutClosing(t *testing.T) { | |||||
| 161 | d.notices.record(domain.Notification{Code: domain.NoticeTabSpawn, Message: "second", Time: time.Unix(2, 0)}) | 161 | d.notices.record(domain.Notification{Code: domain.NoticeTabSpawn, Message: "second", Time: time.Unix(2, 0)}) | ||
| 162 | 162 | ||||
| 163 | d.enterNotices(sess, ac) | 163 | d.enterNotices(sess, ac) | ||
| 164 | - | awaitFrame(t, sends, ports.MsgOutput) | 164 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 165 | for _, input := range tc.input { | 165 | for _, input := range tc.input { | ||
| 166 | d.handleInput(sess, ac, input) | 166 | d.handleInput(sess, ac, input) | ||
| 167 | } | 167 | } | ||
| @@ -343,10 +343,10 @@ func TestNoticesOpenWithEmptyHistoryShowsPlaceholderWithoutPanic(t *testing.T) { | |||||
| 343 | defer release() | 343 | defer release() | ||
| 344 | 344 | ||||
| 345 | require.NotPanics(t, func() { d.enterNotices(sess, ac) }) | 345 | require.NotPanics(t, func() { d.enterNotices(sess, ac) }) | ||
| 346 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 346 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 347 | 347 | ||||
| 348 | require.NotNil(t, ac.overlays.noticesOverlay) | 348 | require.NotNil(t, ac.overlays.noticesOverlay) | ||
| 349 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 349 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 350 | require.NoError(t, err) | 350 | require.NoError(t, err) | ||
| 351 | require.Contains(t, string(msg.Data), "Notifications") | 351 | require.Contains(t, string(msg.Data), "Notifications") | ||
| 352 | require.Contains(t, string(msg.Data), "No notifications") | 352 | require.Contains(t, string(msg.Data), "No notifications") | ||
| @@ -391,11 +391,11 @@ func TestYankLastNotificationCommandCopiesOSC52AndShowsFeedback(t *testing.T) { | |||||
| 391 | want := noticeYankPayload(n) | 391 | want := noticeYankPayload(n) | ||
| 392 | 392 | ||||
| 393 | d.enterPalette(sess, ac) | 393 | d.enterPalette(sess, ac) | ||
| 394 | - | awaitFrame(t, sends, ports.MsgOutput) | 394 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 395 | d.handlePaletteInput(ac, []byte("YLN\r")) | 395 | d.handlePaletteInput(ac, []byte("YLN\r")) | ||
| 396 | 396 | ||||
| 397 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 397 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 398 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 398 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 399 | require.NoError(t, err) | 399 | require.NoError(t, err) | ||
| 400 | payload := string(msg.Data) | 400 | payload := string(msg.Data) | ||
| 401 | require.True(t, strings.HasPrefix(payload, "\x1b]52;c;"), "OSC52 payload = %q", payload) | 401 | require.True(t, strings.HasPrefix(payload, "\x1b]52;c;"), "OSC52 payload = %q", payload) | ||
| @@ -404,8 +404,8 @@ func TestYankLastNotificationCommandCopiesOSC52AndShowsFeedback(t *testing.T) { | |||||
| 404 | require.NoError(t, err) | 404 | require.NoError(t, err) | ||
| 405 | require.Equal(t, want, string(decoded)) | 405 | require.Equal(t, want, string(decoded)) | ||
| 406 | 406 | ||||
| 407 | - | live := awaitFrame(t, sends, ports.MsgOutput) | 407 | + | live := awaitFrame(t, sends, wire.MsgOutput) |
| 408 | - | liveMsg, err := ports.UnmarshalOutput(live.Payload) | 408 | + | liveMsg, err := wire.UnmarshalOutput(live.Payload) |
| 409 | require.NoError(t, err) | 409 | require.NoError(t, err) | ||
| 410 | require.Contains(t, string(liveMsg.Data), "copied notification details") | 410 | require.Contains(t, string(liveMsg.Data), "copied notification details") | ||
| 411 | } | 411 | } | ||
| @@ -416,11 +416,11 @@ func TestYankLastNotificationWithEmptyHistoryShowsWarnToast(t *testing.T) { | |||||
| 416 | defer release() | 416 | defer release() | ||
| 417 | 417 | ||||
| 418 | d.enterPalette(sess, ac) | 418 | d.enterPalette(sess, ac) | ||
| 419 | - | awaitFrame(t, sends, ports.MsgOutput) | 419 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 420 | d.handlePaletteInput(ac, []byte("YLN\r")) | 420 | d.handlePaletteInput(ac, []byte("YLN\r")) | ||
| 421 | 421 | ||||
| 422 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 422 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 423 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 423 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 424 | require.NoError(t, err) | 424 | require.NoError(t, err) | ||
| 425 | require.Contains(t, string(msg.Data), "no notifications yet") | 425 | require.Contains(t, string(msg.Data), "no notifications yet") | ||
| 426 | 426 | ||||
| @@ -439,7 +439,7 @@ func TestNoticesYKeyYanksSelectedNotification(t *testing.T) { | |||||
| 439 | d.notices.record(domain.Notification{Code: domain.NoticeTabSpawn, Severity: domain.NoticeError, Message: "second", Time: time.Unix(2, 0)}) | 439 | d.notices.record(domain.Notification{Code: domain.NoticeTabSpawn, Severity: domain.NoticeError, Message: "second", Time: time.Unix(2, 0)}) | ||
| 440 | 440 | ||||
| 441 | d.enterNotices(sess, ac) | 441 | d.enterNotices(sess, ac) | ||
| 442 | - | awaitFrame(t, sends, ports.MsgOutput) | 442 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 443 | selected, ok := ac.overlays.noticesOverlay.Selected() | 443 | selected, ok := ac.overlays.noticesOverlay.Selected() | ||
| 444 | require.True(t, ok) | 444 | require.True(t, ok) | ||
| 445 | require.Equal(t, "second", selected.Message) | 445 | require.Equal(t, "second", selected.Message) | ||
| @@ -447,8 +447,8 @@ func TestNoticesYKeyYanksSelectedNotification(t *testing.T) { | |||||
| 447 | 447 | ||||
| 448 | d.handleInput(sess, ac, []byte("y")) | 448 | d.handleInput(sess, ac, []byte("y")) | ||
| 449 | 449 | ||||
| 450 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 450 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 451 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 451 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 452 | require.NoError(t, err) | 452 | require.NoError(t, err) | ||
| 453 | payload := string(msg.Data) | 453 | payload := string(msg.Data) | ||
| 454 | require.True(t, strings.HasPrefix(payload, "\x1b]52;c;"), "OSC52 payload = %q", payload) | 454 | require.True(t, strings.HasPrefix(payload, "\x1b]52;c;"), "OSC52 payload = %q", payload) | ||
| @@ -481,11 +481,11 @@ func TestNoticesBatchedYankCapturesSelectionAtY(t *testing.T) { | |||||
| 481 | d.notices.record(domain.Notification{Code: domain.NoticeInternal, Message: "third", Time: time.Unix(3, 0)}) | 481 | d.notices.record(domain.Notification{Code: domain.NoticeInternal, Message: "third", Time: time.Unix(3, 0)}) | ||
| 482 | 482 | ||||
| 483 | d.enterNotices(sess, ac) | 483 | d.enterNotices(sess, ac) | ||
| 484 | - | awaitFrame(t, sends, ports.MsgOutput) | 484 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 485 | d.handleInput(sess, ac, tt.input) | 485 | d.handleInput(sess, ac, tt.input) | ||
| 486 | 486 | ||||
| 487 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 487 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 488 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 488 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 489 | require.NoError(t, err) | 489 | require.NoError(t, err) | ||
| 490 | payload := strings.TrimSuffix(strings.TrimPrefix(string(msg.Data), "\x1b]52;c;"), "\a") | 490 | payload := strings.TrimSuffix(strings.TrimPrefix(string(msg.Data), "\x1b]52;c;"), "\a") | ||
| 491 | decoded, err := base64.StdEncoding.DecodeString(payload) | 491 | decoded, err := base64.StdEncoding.DecodeString(payload) | ||
| @@ -505,7 +505,7 @@ func TestNoticesYKeyWithNoSelectionIsNoOp(t *testing.T) { | |||||
| 505 | defer release() | 505 | defer release() | ||
| 506 | 506 | ||||
| 507 | require.NotPanics(t, func() { d.enterNotices(sess, ac) }) | 507 | require.NotPanics(t, func() { d.enterNotices(sess, ac) }) | ||
| 508 | - | awaitFrame(t, sends, ports.MsgOutput) | 508 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 509 | 509 | ||||
| 510 | require.NotPanics(t, func() { d.handleInput(sess, ac, []byte("y")) }) | 510 | require.NotPanics(t, func() { d.handleInput(sess, ac, []byte("y")) }) | ||
| 511 | require.True(t, ac.overlays.noticesActive()) | 511 | require.True(t, ac.overlays.noticesActive()) | ||
M internal/usecase/daemon/notify_test.go +10 -9
| @@ -17,6 +17,7 @@ import ( | |||||
| 17 | "github.com/bnema/vev/internal/ports" | 17 | "github.com/bnema/vev/internal/ports" | ||
| 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 19 | "github.com/bnema/vev/internal/protocol" | 19 | "github.com/bnema/vev/internal/protocol" | ||
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 20 | ) | 21 | ) | ||
| 21 | 22 | ||||
| 22 | func TestReportAttachmentErrorPreservesLocalOrNilScope(t *testing.T) { | 23 | func TestReportAttachmentErrorPreservesLocalOrNilScope(t *testing.T) { | ||
| @@ -56,11 +57,11 @@ func TestMalformedClientNoticeIsIgnored(t *testing.T) { | |||||
| 56 | d.attachCoordinator(sess, nil, ac, true) | 57 | d.attachCoordinator(sess, nil, ac, true) | ||
| 57 | tr, ok := ac.tr.(*portsmocks.MockTransport) | 58 | tr, ok := ac.tr.(*portsmocks.MockTransport) | ||
| 58 | require.True(t, ok, "attached client transport must be a MockTransport") | 59 | require.True(t, ok, "attached client transport must be a MockTransport") | ||
| 59 | - | frames := []ports.Frame{ | 60 | + | frames := []wire.Frame{ |
| 60 | - | {Type: ports.MsgClientNotice, Payload: []byte{0xff}}, | 61 | + | {Type: wire.MsgClientNotice, Payload: []byte{0xff}}, |
| 61 | - | {Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}, | 62 | + | {Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}, |
| 62 | } | 63 | } | ||
| 63 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 64 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 64 | frame := frames[0] | 65 | frame := frames[0] | ||
| 65 | frames = frames[1:] | 66 | frames = frames[1:] | ||
| 66 | return frame, nil | 67 | return frame, nil | ||
| @@ -268,7 +269,7 @@ func (c *noticeClock) durations() []time.Duration { | |||||
| 268 | // caller-supplied clock so toast TTLs are deterministic. The session has no | 269 | // caller-supplied clock so toast TTLs are deterministic. The session has no | ||
| 269 | // render coordinator, so invalidateRender paints directly and every repaint is | 270 | // render coordinator, so invalidateRender paints directly and every repaint is | ||
| 270 | // observable as a frame on the returned channel. | 271 | // observable as a frame on the returned channel. | ||
| 271 | - | func newNoticeFixture(t *testing.T, clk ports.Clock) (*Daemon, *session, *attachedClient, chan ports.Frame) { | 272 | + | func newNoticeFixture(t *testing.T, clk ports.Clock) (*Daemon, *session, *attachedClient, chan wire.Frame) { |
| 272 | t.Helper() | 273 | t.Helper() | ||
| 273 | p, _ := newBlockingPTY(t) | 274 | p, _ := newBlockingPTY(t) | ||
| 274 | d := newTestDaemon(t, nil, clk) | 275 | d := newTestDaemon(t, nil, clk) | ||
| @@ -864,8 +865,8 @@ func TestToastExpiresOnFakeClock(t *testing.T) { | |||||
| 864 | 865 | ||||
| 865 | d.notify(sess, domain.NoticeError, domain.NoticePaneSpawn, "could not open pane", nil) | 866 | d.notify(sess, domain.NoticeError, domain.NoticePaneSpawn, "could not open pane", nil) | ||
| 866 | awaitToastCount(t, ac, 1) | 867 | awaitToastCount(t, ac, 1) | ||
| 867 | - | shown := awaitFrame(t, sends, ports.MsgOutput) | 868 | + | shown := awaitFrame(t, sends, wire.MsgOutput) |
| 868 | - | shownOutput, err := ports.UnmarshalOutput(shown.Payload) | 869 | + | shownOutput, err := wire.UnmarshalOutput(shown.Payload) |
| 869 | require.NoError(t, err) | 870 | require.NoError(t, err) | ||
| 870 | terminal := vt.NewScreen(80, 25) | 871 | terminal := vt.NewScreen(80, 25) | ||
| 871 | terminal.Write(shownOutput.Data) | 872 | terminal.Write(shownOutput.Data) | ||
| @@ -880,8 +881,8 @@ func TestToastExpiresOnFakeClock(t *testing.T) { | |||||
| 880 | _, overflow := visibleToasts(ac) | 881 | _, overflow := visibleToasts(ac) | ||
| 881 | require.Zero(t, overflow, "overflow resets once no toast is visible") | 882 | require.Zero(t, overflow, "overflow resets once no toast is visible") | ||
| 882 | 883 | ||||
| 883 | - | expired := awaitFrame(t, sends, ports.MsgOutput) | 884 | + | expired := awaitFrame(t, sends, wire.MsgOutput) |
| 884 | - | expiredOutput, err := ports.UnmarshalOutput(expired.Payload) | 885 | + | expiredOutput, err := wire.UnmarshalOutput(expired.Payload) |
| 885 | require.NoError(t, err) | 886 | require.NoError(t, err) | ||
| 886 | terminal.Write(expiredOutput.Data) | 887 | terminal.Write(expiredOutput.Data) | ||
| 887 | ac.sendMu.Lock() | 888 | ac.sendMu.Lock() | ||
M internal/usecase/daemon/output_state_sync_test.go +37 -36
| @@ -13,36 +13,37 @@ import ( | |||||
| 13 | "github.com/bnema/vev/internal/domain" | 13 | "github.com/bnema/vev/internal/domain" | ||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | "github.com/bnema/vev/internal/protocol" | 15 | "github.com/bnema/vev/internal/protocol" | ||
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | "github.com/stretchr/testify/require" | 17 | "github.com/stretchr/testify/require" | ||
| 17 | ) | 18 | ) | ||
| 18 | 19 | ||||
| 19 | type datagramTestTransport struct { | 20 | type datagramTestTransport struct { | ||
| 20 | - | sends chan ports.Frame | 21 | + | sends chan wire.Frame |
| 21 | - | recv chan ports.Frame | 22 | + | recv chan wire.Frame |
| 22 | once sync.Once | 23 | once sync.Once | ||
| 23 | } | 24 | } | ||
| 24 | 25 | ||||
| 25 | type failingOutputTransport struct{} | 26 | type failingOutputTransport struct{} | ||
| 26 | 27 | ||||
| 27 | - | func (failingOutputTransport) Send(ports.Frame) error { return errors.New("send failed") } | 28 | + | func (failingOutputTransport) Send(wire.Frame) error { return errors.New("send failed") } |
| 28 | - | func (failingOutputTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 29 | + | func (failingOutputTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 29 | - | func (failingOutputTransport) Close() error { return nil } | 30 | + | func (failingOutputTransport) Close() error { return nil } |
| 30 | 31 | ||||
| 31 | type asyncPaintTransport struct { | 32 | type asyncPaintTransport struct { | ||
| 32 | - | syncSends chan ports.Frame | 33 | + | syncSends chan wire.Frame |
| 33 | - | asyncSends chan ports.Frame | 34 | + | asyncSends chan wire.Frame |
| 34 | } | 35 | } | ||
| 35 | 36 | ||||
| 36 | - | func (t *asyncPaintTransport) Send(f ports.Frame) error { t.syncSends <- f; return nil } | 37 | + | func (t *asyncPaintTransport) Send(f wire.Frame) error { t.syncSends <- f; return nil } |
| 37 | - | func (t *asyncPaintTransport) SendAsync(f ports.Frame) error { t.asyncSends <- f; return nil } | 38 | + | func (t *asyncPaintTransport) SendAsync(f wire.Frame) error { t.asyncSends <- f; return nil } |
| 38 | - | func (t *asyncPaintTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 39 | + | func (t *asyncPaintTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 39 | - | func (t *asyncPaintTransport) Close() error { return nil } | 40 | + | func (t *asyncPaintTransport) Close() error { return nil } |
| 40 | 41 | ||||
| 41 | type timedSideEffectTransport struct { | 42 | type timedSideEffectTransport struct { | ||
| 42 | closeTrackingTransport | 43 | closeTrackingTransport | ||
| 43 | } | 44 | } | ||
| 44 | 45 | ||||
| 45 | - | func (t *timedSideEffectTransport) SendSynchronous(f ports.Frame) error { | 46 | + | func (t *timedSideEffectTransport) SendSynchronous(f wire.Frame) error { |
| 46 | return t.Send(f) | 47 | return t.Send(f) | ||
| 47 | } | 48 | } | ||
| 48 | 49 | ||||
| @@ -54,14 +55,14 @@ func (noWatchdogClock) NewTimer(time.Duration) ports.Timer { | |||||
| 54 | } | 55 | } | ||
| 55 | 56 | ||||
| 56 | func newDatagramTestTransport() *datagramTestTransport { | 57 | func newDatagramTestTransport() *datagramTestTransport { | ||
| 57 | - | return &datagramTestTransport{sends: make(chan ports.Frame, 64), recv: make(chan ports.Frame, 64)} | 58 | + | return &datagramTestTransport{sends: make(chan wire.Frame, 64), recv: make(chan wire.Frame, 64)} |
| 58 | } | 59 | } | ||
| 59 | 60 | ||||
| 60 | - | func (t *datagramTestTransport) Send(f ports.Frame) error { t.sends <- f; return nil } | 61 | + | func (t *datagramTestTransport) Send(f wire.Frame) error { t.sends <- f; return nil } |
| 61 | - | func (t *datagramTestTransport) Recv() (ports.Frame, error) { | 62 | + | func (t *datagramTestTransport) Recv() (wire.Frame, error) { |
| 62 | f, ok := <-t.recv | 63 | f, ok := <-t.recv | ||
| 63 | if !ok { | 64 | if !ok { | ||
| 64 | - | return ports.Frame{}, io.EOF | 65 | + | return wire.Frame{}, io.EOF |
| 65 | } | 66 | } | ||
| 66 | return f, nil | 67 | return f, nil | ||
| 67 | } | 68 | } | ||
| @@ -90,20 +91,20 @@ func TestDatagramAttachPipelinesRendererBeforeAck(t *testing.T) { | |||||
| 90 | 91 | ||||
| 91 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | 92 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | ||
| 92 | d.paint(sess, ac, false, nil) | 93 | d.paint(sess, ac, false, nil) | ||
| 93 | - | first := awaitFrame(t, tr.sends, ports.MsgOutput) | 94 | + | first := awaitFrame(t, tr.sends, wire.MsgOutput) |
| 94 | - | out, err := ports.UnmarshalOutput(first.Payload) | 95 | + | out, err := wire.UnmarshalOutput(first.Payload) |
| 95 | require.NoError(t, err) | 96 | require.NoError(t, err) | ||
| 96 | require.Equal(t, uint64(1), out.New) | 97 | require.Equal(t, uint64(1), out.New) | ||
| 97 | 98 | ||||
| 98 | sess.tabs[0].focusedPane().screen.Write([]byte("\rB")) | 99 | sess.tabs[0].focusedPane().screen.Write([]byte("\rB")) | ||
| 99 | d.paint(sess, ac, false, nil) | 100 | d.paint(sess, ac, false, nil) | ||
| 100 | - | updated := awaitFrame(t, tr.sends, ports.MsgOutput) | 101 | + | updated := awaitFrame(t, tr.sends, wire.MsgOutput) |
| 101 | - | out, err = ports.UnmarshalOutput(updated.Payload) | 102 | + | out, err = wire.UnmarshalOutput(updated.Payload) |
| 102 | require.NoError(t, err) | 103 | require.NoError(t, err) | ||
| 103 | require.Equal(t, uint64(2), out.New) | 104 | require.Equal(t, uint64(2), out.New) | ||
| 104 | // Both states were emitted before the MsgAck; the ordered dependency chain | 105 | // Both states were emitted before the MsgAck; the ordered dependency chain | ||
| 105 | // must therefore remain valid without waiting for renderer acknowledgement. | 106 | // must therefore remain valid without waiting for renderer acknowledgement. | ||
| 106 | - | tr.recv <- ports.Frame{Type: ports.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: out.Epoch, State: out.New})} | 107 | + | tr.recv <- wire.Frame{Type: wire.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: out.Epoch, State: out.New})} |
| 107 | require.NoError(t, tr.Close()) | 108 | require.NoError(t, tr.Close()) | ||
| 108 | d.runConnLoop(ac) | 109 | d.runConnLoop(ac) | ||
| 109 | 110 | ||||
| @@ -117,13 +118,13 @@ func TestPaintExplicitlyUsesAsyncTransportCapability(t *testing.T) { | |||||
| 117 | p, releasePTY := newBlockingPTY(t) | 118 | p, releasePTY := newBlockingPTY(t) | ||
| 118 | defer releasePTY() | 119 | defer releasePTY() | ||
| 119 | d, sess, ac, _ := newManualSessionWithPTYs(t, p) | 120 | d, sess, ac, _ := newManualSessionWithPTYs(t, p) | ||
| 120 | - | tr := &asyncPaintTransport{syncSends: make(chan ports.Frame, 1), asyncSends: make(chan ports.Frame, 1)} | 121 | + | tr := &asyncPaintTransport{syncSends: make(chan wire.Frame, 1), asyncSends: make(chan wire.Frame, 1)} |
| 121 | ac.replaceTransport(tr) | 122 | ac.replaceTransport(tr) | ||
| 122 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | 123 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | ||
| 123 | 124 | ||||
| 124 | d.paint(sess, ac, false, nil) | 125 | d.paint(sess, ac, false, nil) | ||
| 125 | 126 | ||||
| 126 | - | awaitFrame(t, tr.asyncSends, ports.MsgOutput) | 127 | + | awaitFrame(t, tr.asyncSends, wire.MsgOutput) |
| 127 | select { | 128 | select { | ||
| 128 | case frame := <-tr.syncSends: | 129 | case frame := <-tr.syncSends: | ||
| 129 | t.Fatalf("paint used synchronous Send: %+v", frame) | 130 | t.Fatalf("paint used synchronous Send: %+v", frame) | ||
| @@ -155,7 +156,7 @@ func TestDatagramMultipleUnackedScrollPaintsMatchLatestFrame(t *testing.T) { | |||||
| 155 | pane.screen.ClearDamage() | 156 | pane.screen.ClearDamage() | ||
| 156 | client := vt.NewScreen(80, 25) | 157 | client := vt.NewScreen(80, 25) | ||
| 157 | d.paint(sess, ac, true, nil) | 158 | d.paint(sess, ac, true, nil) | ||
| 158 | - | first := mustApplyOutput(t, client, awaitFrame(t, tr.sends, ports.MsgOutput)) | 159 | + | first := mustApplyOutput(t, client, awaitFrame(t, tr.sends, wire.MsgOutput)) |
| 159 | ac.ackOutputState(first.Epoch, first.New) | 160 | ac.ackOutputState(first.Epoch, first.New) | ||
| 160 | 161 | ||||
| 161 | // Preserve the frame after one scroll while inducing a real VT scroll | 162 | // Preserve the frame after one scroll while inducing a real VT scroll | ||
| @@ -175,7 +176,7 @@ func TestDatagramMultipleUnackedScrollPaintsMatchLatestFrame(t *testing.T) { | |||||
| 175 | pane.screen.Write([]byte("\nq")) | 176 | pane.screen.Write([]byte("\nq")) | ||
| 176 | pane.screen.Frame = desired.Clone() | 177 | pane.screen.Frame = desired.Clone() | ||
| 177 | d.paint(sess, ac, false, nil) | 178 | d.paint(sess, ac, false, nil) | ||
| 178 | - | mustApplyOutput(t, client, awaitFrame(t, tr.sends, ports.MsgOutput)) | 179 | + | mustApplyOutput(t, client, awaitFrame(t, tr.sends, wire.MsgOutput)) |
| 179 | } | 180 | } | ||
| 180 | 181 | ||||
| 181 | require.Equal(t, 'B', client.Frame.At(0, 1).Rune, | 182 | require.Equal(t, 'B', client.Frame.At(0, 1).Rune, | ||
| @@ -198,9 +199,9 @@ func outputStateRow(row []renderer.Cell) string { | |||||
| 198 | return string(runes) | 199 | return string(runes) | ||
| 199 | } | 200 | } | ||
| 200 | 201 | ||||
| 201 | - | func mustApplyOutput(t *testing.T, screen *vt.Screen, frame ports.Frame) protocol.Output { | 202 | + | func mustApplyOutput(t *testing.T, screen *vt.Screen, frame wire.Frame) protocol.Output { |
| 202 | t.Helper() | 203 | t.Helper() | ||
| 203 | - | out, err := ports.UnmarshalOutput(frame.Payload) | 204 | + | out, err := wire.UnmarshalOutput(frame.Payload) |
| 204 | require.NoError(t, err) | 205 | require.NoError(t, err) | ||
| 205 | screen.Write(out.Data) | 206 | screen.Write(out.Data) | ||
| 206 | return out | 207 | return out | ||
| @@ -213,7 +214,7 @@ func TestLocalAttachStillAdvancesRendererOnSend(t *testing.T) { | |||||
| 213 | 214 | ||||
| 214 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | 215 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | ||
| 215 | d.paint(sess, ac, false, nil) | 216 | d.paint(sess, ac, false, nil) | ||
| 216 | - | awaitFrame(t, sends, ports.MsgOutput) | 217 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 217 | 218 | ||||
| 218 | // The first paint updates the renderer shadow without waiting for MsgAck. | 219 | // The first paint updates the renderer shadow without waiting for MsgAck. | ||
| 219 | d.paint(sess, ac, false, nil) | 220 | d.paint(sess, ac, false, nil) | ||
| @@ -228,13 +229,13 @@ func TestLocalOutputAckDoesNotMoveRendererShadowBackward(t *testing.T) { | |||||
| 228 | 229 | ||||
| 229 | pane.screen.Write([]byte("A")) | 230 | pane.screen.Write([]byte("A")) | ||
| 230 | d.paint(sess, ac, false, nil) | 231 | d.paint(sess, ac, false, nil) | ||
| 231 | - | first := awaitFrame(t, sends, ports.MsgOutput) | 232 | + | first := awaitFrame(t, sends, wire.MsgOutput) |
| 232 | - | out, err := ports.UnmarshalOutput(first.Payload) | 233 | + | out, err := wire.UnmarshalOutput(first.Payload) |
| 233 | require.NoError(t, err) | 234 | require.NoError(t, err) | ||
| 234 | 235 | ||||
| 235 | pane.screen.Write([]byte("\rB")) | 236 | pane.screen.Write([]byte("\rB")) | ||
| 236 | d.paint(sess, ac, false, nil) | 237 | d.paint(sess, ac, false, nil) | ||
| 237 | - | awaitFrame(t, sends, ports.MsgOutput) | 238 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 238 | 239 | ||||
| 239 | ac.ackOutputState(out.Epoch, out.New) | 240 | ac.ackOutputState(out.Epoch, out.New) | ||
| 240 | d.paint(sess, ac, false, nil) | 241 | d.paint(sess, ac, false, nil) | ||
| @@ -252,7 +253,7 @@ func TestRawTerminalSideEffectDoesNotEnterFullOutputWindow(t *testing.T) { | |||||
| 252 | require.Equal(t, uint64(maxUnackedOutputStates), ac.output.outstanding()) | 253 | require.Equal(t, uint64(maxUnackedOutputStates), ac.output.outstanding()) | ||
| 253 | sends := tr.Sends() | 254 | sends := tr.Sends() | ||
| 254 | require.Len(t, sends, 1) | 255 | require.Len(t, sends, 1) | ||
| 255 | - | out, err := ports.UnmarshalOutput(sends[0].Payload) | 256 | + | out, err := wire.UnmarshalOutput(sends[0].Payload) |
| 256 | require.NoError(t, err) | 257 | require.NoError(t, err) | ||
| 257 | require.Zero(t, out.Base) | 258 | require.Zero(t, out.Base) | ||
| 258 | require.Zero(t, out.New) | 259 | require.Zero(t, out.New) | ||
| @@ -304,7 +305,7 @@ func TestResizeGrowthFirstFrameIncludesConcurrentPTYRedraw(t *testing.T) { | |||||
| 304 | pane.screen.Write([]byte(strings.Repeat("A", 79))) | 305 | pane.screen.Write([]byte(strings.Repeat("A", 79))) | ||
| 305 | d.paint(sess, ac, true, nil) | 306 | d.paint(sess, ac, true, nil) | ||
| 306 | client := vt.NewScreen(80, 24) | 307 | client := vt.NewScreen(80, 24) | ||
| 307 | - | initial := mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 308 | + | initial := mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 308 | ac.ackOutputState(initial.Epoch, initial.New) | 309 | ac.ackOutputState(initial.Epoch, initial.New) | ||
| 309 | 310 | ||||
| 310 | d.sessWg.Add(1) | 311 | d.sessWg.Add(1) | ||
| @@ -325,7 +326,7 @@ func TestResizeGrowthFirstFrameIncludesConcurrentPTYRedraw(t *testing.T) { | |||||
| 325 | require.Equal(t, 'B', pane.screen.Frame.At(100, 0).Rune, "replay must parse the redraw before commit") | 326 | require.Equal(t, 'B', pane.screen.Frame.At(100, 0).Rune, "replay must parse the redraw before commit") | ||
| 326 | 327 | ||||
| 327 | client.Resize(120, 24) | 328 | client.Resize(120, 24) | ||
| 328 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 329 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 329 | require.Equal(t, 'B', client.Frame.At(100, 1).Rune, | 330 | require.Equal(t, 'B', client.Frame.At(100, 1).Rune, | ||
| 330 | "first grown frame exposed stale pre-SIGWINCH pane content") | 331 | "first grown frame exposed stale pre-SIGWINCH pane content") | ||
| 331 | select { | 332 | select { | ||
| @@ -356,7 +357,7 @@ func TestResizeWithoutPTYOutputFlushesOneFullFrameAtDeadline(t *testing.T) { | |||||
| 356 | done := captureResizeCallbackDone(t, sess.renderCoordinator()) | 357 | done := captureResizeCallbackDone(t, sess.renderCoordinator()) | ||
| 357 | timer.ch <- time.Now() | 358 | timer.ch <- time.Now() | ||
| 358 | awaitTestCompletion(t, done, "resize callback did not complete") | 359 | awaitTestCompletion(t, done, "resize callback did not complete") | ||
| 359 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | 360 | + | frame := awaitFrame(t, sends, wire.MsgOutput) |
| 360 | client := vt.NewScreen(120, 24) | 361 | client := vt.NewScreen(120, 24) | ||
| 361 | out := mustApplyOutput(t, client, frame) | 362 | out := mustApplyOutput(t, client, frame) | ||
| 362 | require.Zero(t, out.Base) | 363 | require.Zero(t, out.Base) | ||
| @@ -395,7 +396,7 @@ func TestResizeBurstFlushesOnlyLatestGeometry(t *testing.T) { | |||||
| 395 | requireNoOutputFrame(t, sends) | 396 | requireNoOutputFrame(t, sends) | ||
| 396 | latest.ch <- time.Now() | 397 | latest.ch <- time.Now() | ||
| 397 | awaitTestCompletion(t, latestDone, "latest resize callback did not complete") | 398 | awaitTestCompletion(t, latestDone, "latest resize callback did not complete") | ||
| 398 | - | awaitFrame(t, sends, ports.MsgOutput) | 399 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 399 | require.Equal(t, domain.Size{Cols: 120, Rows: 24}, ac.size) | 400 | require.Equal(t, domain.Size{Cols: 120, Rows: 24}, ac.size) | ||
| 400 | require.Equal(t, 120, testAttachmentTab(sess).focusedPane().screen.Frame.Width) | 401 | require.Equal(t, 120, testAttachmentTab(sess).focusedPane().screen.Frame.Width) | ||
| 401 | requireNoOutputFrame(t, sends) | 402 | requireNoOutputFrame(t, sends) | ||
M internal/usecase/daemon/paint_gate_test.go +3 -3
| @@ -4,16 +4,16 @@ import ( | |||||
| 4 | "testing" | 4 | "testing" | ||
| 5 | "time" | 5 | "time" | ||
| 6 | 6 | ||||
| 7 | - | "github.com/bnema/vev/internal/ports" | 7 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 8 | ) | 8 | ) | ||
| 9 | 9 | ||||
| 10 | - | func requireNoOutputFrame(t *testing.T, sends chan ports.Frame) { | 10 | + | func requireNoOutputFrame(t *testing.T, sends chan wire.Frame) { |
| 11 | t.Helper() | 11 | t.Helper() | ||
| 12 | deadline := time.After(50 * time.Millisecond) | 12 | deadline := time.After(50 * time.Millisecond) | ||
| 13 | for { | 13 | for { | ||
| 14 | select { | 14 | select { | ||
| 15 | case f := <-sends: | 15 | case f := <-sends: | ||
| 16 | - | if f.Type == ports.MsgOutput { | 16 | + | if f.Type == wire.MsgOutput { |
| 17 | t.Fatalf("unexpected output frame: %+v", f) | 17 | t.Fatalf("unexpected output frame: %+v", f) | ||
| 18 | } | 18 | } | ||
| 19 | case <-deadline: | 19 | case <-deadline: | ||
M internal/usecase/daemon/palette_test.go +80 -79
| @@ -14,6 +14,7 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 16 | "github.com/bnema/vev/internal/protocol" | 16 | "github.com/bnema/vev/internal/protocol" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 17 | "github.com/bnema/vev/internal/usecase/command" | 18 | "github.com/bnema/vev/internal/usecase/command" | ||
| 18 | "github.com/bnema/vev/internal/usecase/palette" | 19 | "github.com/bnema/vev/internal/usecase/palette" | ||
| 19 | "github.com/bnema/vev/internal/usecase/picker" | 20 | "github.com/bnema/vev/internal/usecase/picker" | ||
| @@ -130,8 +131,8 @@ func TestPaletteOpenTypeEnterRunAndEscClose(t *testing.T) { | |||||
| 130 | 131 | ||||
| 131 | d.handleInput(sess, ac, []byte("\x1b ")) | 132 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 132 | require.True(t, ac.overlays.paletteActive()) | 133 | require.True(t, ac.overlays.paletteActive()) | ||
| 133 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 134 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 134 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 135 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 135 | require.NoError(t, err) | 136 | require.NoError(t, err) | ||
| 136 | require.Contains(t, string(msg.Data), "Commands") | 137 | require.Contains(t, string(msg.Data), "Commands") | ||
| 137 | 138 | ||||
| @@ -139,13 +140,13 @@ func TestPaletteOpenTypeEnterRunAndEscClose(t *testing.T) { | |||||
| 139 | require.False(t, ac.overlays.paletteActive()) | 140 | require.False(t, ac.overlays.paletteActive()) | ||
| 140 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | 141 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | ||
| 141 | requireFloatingInitialized(t, testAttachmentTab(sess)) | 142 | requireFloatingInitialized(t, testAttachmentTab(sess)) | ||
| 142 | - | awaitFrame(t, sends, ports.MsgOutput) | 143 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 143 | 144 | ||||
| 144 | d.handleInput(sess, ac, []byte("\x1b ")) | 145 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 145 | - | awaitFrame(t, sends, ports.MsgOutput) | 146 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 146 | d.handleInput(sess, ac, []byte("\x1b")) | 147 | d.handleInput(sess, ac, []byte("\x1b")) | ||
| 147 | require.False(t, ac.overlays.paletteActive()) | 148 | require.False(t, ac.overlays.paletteActive()) | ||
| 148 | - | awaitFrame(t, sends, ports.MsgOutput) | 149 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 149 | } | 150 | } | ||
| 150 | 151 | ||||
| 151 | // TestPaletteCommandFailureSurfacesAsNotice drives a palette command whose Run | 152 | // TestPaletteCommandFailureSurfacesAsNotice drives a palette command whose Run | ||
| @@ -162,9 +163,9 @@ func TestPaletteCommandFailureSurfacesAsNotice(t *testing.T) { | |||||
| 162 | d.ptys = ptys | 163 | d.ptys = ptys | ||
| 163 | 164 | ||||
| 164 | d.handleInput(sess, ac, []byte("\x1b ")) | 165 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 165 | - | awaitFrame(t, sends, ports.MsgOutput) | 166 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 166 | d.handleInput(sess, ac, []byte("CNT\r")) | 167 | d.handleInput(sess, ac, []byte("CNT\r")) | ||
| 167 | - | awaitFrame(t, sends, ports.MsgOutput) | 168 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 168 | 169 | ||||
| 169 | history := d.notices.history() | 170 | history := d.notices.history() | ||
| 170 | require.NotEmpty(t, history, "failed palette command must record a notice") | 171 | require.NotEmpty(t, history, "failed palette command must record a notice") | ||
| @@ -291,13 +292,13 @@ func TestPaletteEnterFreezesActiveSessionSelectionAgainstTrailingInput(t *testin | |||||
| 291 | target.createdAt = 42 | 292 | target.createdAt = 42 | ||
| 292 | 293 | ||||
| 293 | d.handleInput(current, ac, []byte("\x1b ")) | 294 | d.handleInput(current, ac, []byte("\x1b ")) | ||
| 294 | - | awaitFrame(t, sends, ports.MsgOutput) | 295 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 295 | d.handleInput(current, ac, []byte("recent\rx")) | 296 | d.handleInput(current, ac, []byte("recent\rx")) | ||
| 296 | 297 | ||||
| 297 | require.Same(t, target, ac.currentSession(), "Enter must retain the selected session despite trailing frame bytes") | 298 | require.Same(t, target, ac.currentSession(), "Enter must retain the selected session despite trailing frame bytes") | ||
| 298 | require.False(t, ac.overlays.paletteActive(), "trailing input must not prevent the captured selection from closing the palette") | 299 | require.False(t, ac.overlays.paletteActive(), "trailing input must not prevent the captured selection from closing the palette") | ||
| 299 | - | awaitFrame(t, sends, ports.MsgOutput) | 300 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 300 | - | awaitFrame(t, sends, ports.MsgOutput) | 301 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 301 | } | 302 | } | ||
| 302 | 303 | ||||
| 303 | func TestPaletteSelectedActiveSessionSwitchesWithoutRecordingCommandRecency(t *testing.T) { | 304 | func TestPaletteSelectedActiveSessionSwitchesWithoutRecordingCommandRecency(t *testing.T) { | ||
| @@ -307,15 +308,15 @@ func TestPaletteSelectedActiveSessionSwitchesWithoutRecordingCommandRecency(t *t | |||||
| 307 | target.createdAt = 42 | 308 | target.createdAt = 42 | ||
| 308 | 309 | ||||
| 309 | d.handleInput(current, ac, []byte("\x1b ")) | 310 | d.handleInput(current, ac, []byte("\x1b ")) | ||
| 310 | - | awaitFrame(t, sends, ports.MsgOutput) | 311 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 311 | d.handleInput(current, ac, []byte("recent\r")) | 312 | d.handleInput(current, ac, []byte("recent\r")) | ||
| 312 | 313 | ||||
| 313 | require.Same(t, target, ac.currentSession()) | 314 | require.Same(t, target, ac.currentSession()) | ||
| 314 | require.Contains(t, target.snapshotAttachments(), ac, "canonical handoff reuses the attached client") | 315 | require.Contains(t, target.snapshotAttachments(), ac, "canonical handoff reuses the attached client") | ||
| 315 | require.False(t, ac.overlays.paletteActive()) | 316 | require.False(t, ac.overlays.paletteActive()) | ||
| 316 | require.Empty(t, d.paletteRecent, "session selections are not command recency") | 317 | require.Empty(t, d.paletteRecent, "session selections are not command recency") | ||
| 317 | - | awaitFrame(t, sends, ports.MsgOutput) | 318 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 318 | - | awaitFrame(t, sends, ports.MsgOutput) | 319 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 319 | } | 320 | } | ||
| 320 | 321 | ||||
| 321 | func TestPaletteStoppedSessionResumeFailureKeepsPaletteAndSourceAttachment(t *testing.T) { | 322 | func TestPaletteStoppedSessionResumeFailureKeepsPaletteAndSourceAttachment(t *testing.T) { | ||
| @@ -329,7 +330,7 @@ func TestPaletteStoppedSessionResumeFailureKeepsPaletteAndSourceAttachment(t *te | |||||
| 329 | d.ptys = ptys | 330 | d.ptys = ptys | ||
| 330 | 331 | ||||
| 331 | d.handleInput(current, ac, []byte("\x1b ")) | 332 | d.handleInput(current, ac, []byte("\x1b ")) | ||
| 332 | - | awaitFrame(t, sends, ports.MsgOutput) | 333 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 333 | d.handleInput(current, ac, []byte("stopped\r")) | 334 | d.handleInput(current, ac, []byte("stopped\r")) | ||
| 334 | 335 | ||||
| 335 | require.Same(t, current, ac.currentSession(), "failed resume must retain the source attachment") | 336 | require.Same(t, current, ac.currentSession(), "failed resume must retain the source attachment") | ||
| @@ -341,7 +342,7 @@ func TestPaletteStoppedSessionResumeFailureKeepsPaletteAndSourceAttachment(t *te | |||||
| 341 | require.Equal(t, "requested session is unavailable", ac.overlays.paletteFeedback) | 342 | require.Equal(t, "requested session is unavailable", ac.overlays.paletteFeedback) | ||
| 342 | ac.overlays.paletteMu.Unlock() | 343 | ac.overlays.paletteMu.Unlock() | ||
| 343 | require.Equal(t, stopped, d.inactive[stopped.name], "failed resume must retain stopped lifecycle metadata") | 344 | require.Equal(t, stopped, d.inactive[stopped.name], "failed resume must retain stopped lifecycle metadata") | ||
| 344 | - | awaitFrame(t, sends, ports.MsgOutput) | 345 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 345 | } | 346 | } | ||
| 346 | 347 | ||||
| 347 | func TestPaletteSelectedStoppedSessionResumesAndSwitches(t *testing.T) { | 348 | func TestPaletteSelectedStoppedSessionResumesAndSwitches(t *testing.T) { | ||
| @@ -354,7 +355,7 @@ func TestPaletteSelectedStoppedSessionResumesAndSwitches(t *testing.T) { | |||||
| 354 | d.inactive["stopped"] = inactiveSession{name: "stopped", cwd: "/tmp", createdAt: 42, state: protocol.SessionDown} | 355 | d.inactive["stopped"] = inactiveSession{name: "stopped", cwd: "/tmp", createdAt: 42, state: protocol.SessionDown} | ||
| 355 | 356 | ||||
| 356 | d.handleInput(current, ac, []byte("\x1b ")) | 357 | d.handleInput(current, ac, []byte("\x1b ")) | ||
| 357 | - | awaitFrame(t, sends, ports.MsgOutput) | 358 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 358 | generation := ac.lifecycle.generationValue() | 359 | generation := ac.lifecycle.generationValue() | ||
| 359 | d.handleInput(current, ac, []byte("stopped\r")) | 360 | d.handleInput(current, ac, []byte("stopped\r")) | ||
| 360 | 361 | ||||
| @@ -364,11 +365,11 @@ func TestPaletteSelectedStoppedSessionResumesAndSwitches(t *testing.T) { | |||||
| 364 | require.Equal(t, true, resumed.attachmentRegistered(ac)) | 365 | require.Equal(t, true, resumed.attachmentRegistered(ac)) | ||
| 365 | require.Greater(t, ac.lifecycle.generationValue(), generation, "stopped-session handoff must publish through the attachment transition") | 366 | require.Greater(t, ac.lifecycle.generationValue(), generation, "stopped-session handoff must publish through the attachment transition") | ||
| 366 | require.False(t, ac.overlays.paletteActive()) | 367 | require.False(t, ac.overlays.paletteActive()) | ||
| 367 | - | firstPaint := awaitFrame(t, sends, ports.MsgOutput) | 368 | + | firstPaint := awaitFrame(t, sends, wire.MsgOutput) |
| 368 | - | firstOutput, err := ports.UnmarshalOutput(firstPaint.Payload) | 369 | + | firstOutput, err := wire.UnmarshalOutput(firstPaint.Payload) |
| 369 | require.NoError(t, err) | 370 | require.NoError(t, err) | ||
| 370 | require.Zero(t, firstOutput.Base, "stopped-session first paint must reset moving output state") | 371 | require.Zero(t, firstOutput.Base, "stopped-session first paint must reset moving output state") | ||
| 371 | - | awaitFrame(t, sends, ports.MsgOutput) | 372 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 372 | } | 373 | } | ||
| 373 | 374 | ||||
| 374 | func TestPaletteJRSActivatesOnlyExactContextualHint(t *testing.T) { | 375 | func TestPaletteJRSActivatesOnlyExactContextualHint(t *testing.T) { | ||
| @@ -378,9 +379,9 @@ func TestPaletteJRSActivatesOnlyExactContextualHint(t *testing.T) { | |||||
| 378 | ac.setRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 1, Active: protocol.RouteRef{Key: 1, Generation: 1}}) | 379 | ac.setRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 1, Active: protocol.RouteRef{Key: 1, Generation: 1}}) | ||
| 379 | 380 | ||||
| 380 | d.handleInput(sess, ac, []byte("\x1b ")) | 381 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 381 | - | awaitFrame(t, sends, ports.MsgOutput) | 382 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 382 | d.handleInput(sess, ac, []byte("JRS")) | 383 | d.handleInput(sess, ac, []byte("JRS")) | ||
| 383 | - | awaitFrame(t, sends, ports.MsgOutput) | 384 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 384 | 385 | ||||
| 385 | ac.overlays.paletteMu.Lock() | 386 | ac.overlays.paletteMu.Lock() | ||
| 386 | require.Equal(t, command.ContextHintRecentSessions, ac.overlays.paletteHints.Kind) | 387 | require.Equal(t, command.ContextHintRecentSessions, ac.overlays.paletteHints.Kind) | ||
| @@ -388,7 +389,7 @@ func TestPaletteJRSActivatesOnlyExactContextualHint(t *testing.T) { | |||||
| 388 | ac.overlays.paletteMu.Unlock() | 389 | ac.overlays.paletteMu.Unlock() | ||
| 389 | 390 | ||||
| 390 | d.handleInput(sess, ac, []byte("\b\b\bRNS")) | 391 | d.handleInput(sess, ac, []byte("\b\b\bRNS")) | ||
| 391 | - | awaitFrame(t, sends, ports.MsgOutput) | 392 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 392 | ac.overlays.paletteMu.Lock() | 393 | ac.overlays.paletteMu.Lock() | ||
| 393 | require.Equal(t, command.ContextHintNone, ac.overlays.paletteHints.Kind) | 394 | require.Equal(t, command.ContextHintNone, ac.overlays.paletteHints.Kind) | ||
| 394 | ac.overlays.paletteMu.Unlock() | 395 | ac.overlays.paletteMu.Unlock() | ||
| @@ -402,25 +403,25 @@ func TestPaletteJRSUsesEffectiveOverrideOnly(t *testing.T) { | |||||
| 402 | d.ApplyConfig(domain.Config{Codes: map[string]string{"jump-recent-session": "RJS"}}) | 403 | d.ApplyConfig(domain.Config{Codes: map[string]string{"jump-recent-session": "RJS"}}) | ||
| 403 | 404 | ||||
| 404 | d.handleInputForAttachment(token, []byte("\x1b ")) | 405 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 405 | - | awaitFrame(t, sends, ports.MsgOutput) | 406 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 406 | d.handleInputForAttachment(token, []byte("RJS")) | 407 | d.handleInputForAttachment(token, []byte("RJS")) | ||
| 407 | - | awaitFrame(t, sends, ports.MsgOutput) | 408 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 408 | ac.overlays.paletteMu.Lock() | 409 | ac.overlays.paletteMu.Lock() | ||
| 409 | require.Equal(t, command.ContextHintRecentSessions, ac.overlays.paletteHints.Kind) | 410 | require.Equal(t, command.ContextHintRecentSessions, ac.overlays.paletteHints.Kind) | ||
| 410 | ac.overlays.paletteMu.Unlock() | 411 | ac.overlays.paletteMu.Unlock() | ||
| 411 | d.handleInputForAttachment(token, []byte(" 1\r")) | 412 | d.handleInputForAttachment(token, []byte(" 1\r")) | ||
| 412 | 413 | ||||
| 413 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | 414 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) |
| 414 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | 415 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) |
| 415 | require.NoError(t, err) | 416 | require.NoError(t, err) | ||
| 416 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 1, Key: 2, Generation: 1}, action) | 417 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 1, Key: 2, Generation: 1}, action) | ||
| 417 | require.Same(t, current, ac.currentSession()) | 418 | require.Same(t, current, ac.currentSession()) | ||
| 418 | require.False(t, ac.overlays.paletteActive()) | 419 | require.False(t, ac.overlays.paletteActive()) | ||
| 419 | 420 | ||||
| 420 | d.handleInputForAttachment(token, []byte("\x1b ")) | 421 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 421 | - | awaitFrame(t, sends, ports.MsgOutput) | 422 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 422 | d.handleInputForAttachment(token, []byte("JRS")) | 423 | d.handleInputForAttachment(token, []byte("JRS")) | ||
| 423 | - | awaitFrame(t, sends, ports.MsgOutput) | 424 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 424 | ac.overlays.paletteMu.Lock() | 425 | ac.overlays.paletteMu.Lock() | ||
| 425 | require.Equal(t, command.ContextHintNone, ac.overlays.paletteHints.Kind) | 426 | require.Equal(t, command.ContextHintNone, ac.overlays.paletteHints.Kind) | ||
| 426 | ac.overlays.paletteMu.Unlock() | 427 | ac.overlays.paletteMu.Unlock() | ||
| @@ -588,11 +589,11 @@ func TestPaletteRemoteCatalogSelectionSendsExactAttachTarget(t *testing.T) { | |||||
| 588 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | 589 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | ||
| 589 | 590 | ||||
| 590 | d.handleInputForAttachment(token, []byte("\x1b ")) | 591 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 591 | - | awaitFrame(t, sends, ports.MsgOutput) | 592 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 592 | d.handleInputForAttachment(token, []byte("work@arch\r")) | 593 | d.handleInputForAttachment(token, []byte("work@arch\r")) | ||
| 593 | 594 | ||||
| 594 | - | frame := awaitFrame(t, sends, ports.MsgAttachTarget) | 595 | + | frame := awaitFrame(t, sends, wire.MsgAttachTarget) |
| 595 | - | target, err := ports.UnmarshalAttachTarget(frame.Payload) | 596 | + | target, err := wire.UnmarshalAttachTarget(frame.Payload) |
| 596 | require.NoError(t, err) | 597 | require.NoError(t, err) | ||
| 597 | remoteTarget := domain.RemoteSessionTarget{ | 598 | remoteTarget := domain.RemoteSessionTarget{ | ||
| 598 | Endpoint: "user@arch", DisplayOrigin: "arch", LifecycleID: remoteLifecycle, | 599 | Endpoint: "user@arch", DisplayOrigin: "arch", LifecycleID: remoteLifecycle, | ||
| @@ -627,7 +628,7 @@ func TestPaletteCachedRemoteSelectionFailsClosed(t *testing.T) { | |||||
| 627 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | 628 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | ||
| 628 | 629 | ||||
| 629 | d.handleInputForAttachment(token, []byte("\x1b ")) | 630 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 630 | - | awaitFrame(t, sends, ports.MsgOutput) | 631 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 631 | d.handleInputForAttachment(token, []byte("cached@arch\r")) | 632 | d.handleInputForAttachment(token, []byte("cached@arch\r")) | ||
| 632 | 633 | ||||
| 633 | require.Same(t, current, ac.currentAttachmentSession()) | 634 | require.Same(t, current, ac.currentAttachmentSession()) | ||
| @@ -639,7 +640,7 @@ func TestPaletteCachedRemoteSelectionFailsClosed(t *testing.T) { | |||||
| 639 | for { | 640 | for { | ||
| 640 | select { | 641 | select { | ||
| 641 | case frame := <-sends: | 642 | case frame := <-sends: | ||
| 642 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type) | 643 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type) |
| 643 | default: | 644 | default: | ||
| 644 | return | 645 | return | ||
| 645 | } | 646 | } | ||
| @@ -772,7 +773,7 @@ func TestPaletteLifecycleTargetRejectsSameNameReplacement(t *testing.T) { | |||||
| 772 | for { | 773 | for { | ||
| 773 | select { | 774 | select { | ||
| 774 | case frame := <-sends: | 775 | case frame := <-sends: | ||
| 775 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type) | 776 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type) |
| 776 | default: | 777 | default: | ||
| 777 | return | 778 | return | ||
| 778 | } | 779 | } | ||
| @@ -793,11 +794,11 @@ func TestPaletteFuzzyRemoteRecentRouteSendsExactNavigationAction(t *testing.T) { | |||||
| 793 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | 794 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | ||
| 794 | 795 | ||||
| 795 | d.handleInputForAttachment(token, []byte("\x1b ")) | 796 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 796 | - | awaitFrame(t, sends, ports.MsgOutput) | 797 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 797 | d.handleInputForAttachment(token, []byte("logs@edge\r")) | 798 | d.handleInputForAttachment(token, []byte("logs@edge\r")) | ||
| 798 | 799 | ||||
| 799 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | 800 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) |
| 800 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | 801 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) |
| 801 | require.NoError(t, err) | 802 | require.NoError(t, err) | ||
| 802 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 9, Key: 8, Generation: 4}, action) | 803 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 9, Key: 8, Generation: 4}, action) | ||
| 803 | require.False(t, ac.overlays.paletteActive()) | 804 | require.False(t, ac.overlays.paletteActive()) | ||
| @@ -809,12 +810,12 @@ func TestPaletteFuzzySelectedStaticCommandExecutes(t *testing.T) { | |||||
| 809 | defer releases[1]() | 810 | defer releases[1]() | ||
| 810 | 811 | ||||
| 811 | d.handleInput(sess, ac, []byte("\x1b ")) | 812 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 812 | - | awaitFrame(t, sends, ports.MsgOutput) | 813 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 813 | d.handleInput(sess, ac, []byte("next\r")) | 814 | d.handleInput(sess, ac, []byte("next\r")) | ||
| 814 | 815 | ||||
| 815 | require.False(t, ac.overlays.paletteActive()) | 816 | require.False(t, ac.overlays.paletteActive()) | ||
| 816 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | 817 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | ||
| 817 | - | awaitFrame(t, sends, ports.MsgOutput) | 818 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 818 | } | 819 | } | ||
| 819 | 820 | ||||
| 820 | func TestPaletteJRSUsesCapturedRankAfterMRUChanges(t *testing.T) { | 821 | func TestPaletteJRSUsesCapturedRankAfterMRUChanges(t *testing.T) { | ||
| @@ -823,13 +824,13 @@ func TestPaletteJRSUsesCapturedRankAfterMRUChanges(t *testing.T) { | |||||
| 823 | ac.setRouteSnapshot(testRecentRouteSnapshot()) | 824 | ac.setRouteSnapshot(testRecentRouteSnapshot()) | ||
| 824 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | 825 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | ||
| 825 | d.handleInputForAttachment(token, []byte("\x1b ")) | 826 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 826 | - | awaitFrame(t, sends, ports.MsgOutput) | 827 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 827 | // Reordering live MRU after opening must not shift rank 1 from its capture. | 828 | // Reordering live MRU after opening must not shift rank 1 from its capture. | ||
| 828 | d.sessions[domain.SessionID("older")].core().mruAt.Store(100) | 829 | d.sessions[domain.SessionID("older")].core().mruAt.Store(100) | ||
| 829 | d.handleInputForAttachment(token, []byte("JRS 1\r")) | 830 | d.handleInputForAttachment(token, []byte("JRS 1\r")) | ||
| 830 | 831 | ||||
| 831 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | 832 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) |
| 832 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | 833 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) |
| 833 | require.NoError(t, err) | 834 | require.NoError(t, err) | ||
| 834 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 1, Key: 2, Generation: 1}, action) | 835 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 1, Key: 2, Generation: 1}, action) | ||
| 835 | require.Same(t, current, ac.currentSession()) | 836 | require.Same(t, current, ac.currentSession()) | ||
| @@ -877,7 +878,7 @@ func TestPaletteJRSDoesNotRevalidateTargetInDaemon(t *testing.T) { | |||||
| 877 | } | 878 | } | ||
| 878 | token := beginRecentRoutePaletteEffect(t, d, sess, ac) | 879 | token := beginRecentRoutePaletteEffect(t, d, sess, ac) | ||
| 879 | d.handleInputForAttachment(token, []byte("\x1b ")) | 880 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 880 | - | awaitFrame(t, sends, ports.MsgOutput) | 881 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 881 | inputHandled := make(chan struct{}) | 882 | inputHandled := make(chan struct{}) | ||
| 882 | go func() { | 883 | go func() { | ||
| 883 | d.handleInputForAttachment(token, []byte("JRS 1\r")) | 884 | d.handleInputForAttachment(token, []byte("JRS 1\r")) | ||
| @@ -889,8 +890,8 @@ func TestPaletteJRSDoesNotRevalidateTargetInDaemon(t *testing.T) { | |||||
| 889 | close(releaseHandoff) | 890 | close(releaseHandoff) | ||
| 890 | awaitTestCompletion(t, inputHandled, "JRS route-action input did not complete") | 891 | awaitTestCompletion(t, inputHandled, "JRS route-action input did not complete") | ||
| 891 | 892 | ||||
| 892 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | 893 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) |
| 893 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | 894 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) |
| 894 | require.NoError(t, err) | 895 | require.NoError(t, err) | ||
| 895 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 7, Key: 9, Generation: 4}, action) | 896 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 7, Key: 9, Generation: 4}, action) | ||
| 896 | require.False(t, ac.overlays.paletteActive()) | 897 | require.False(t, ac.overlays.paletteActive()) | ||
| @@ -903,7 +904,7 @@ func TestPaletteJRSOutOfRangeKeepsPaletteOpenWithoutClamping(t *testing.T) { | |||||
| 903 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | 904 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | ||
| 904 | 905 | ||||
| 905 | d.handleInputForAttachment(token, []byte("\x1b ")) | 906 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 906 | - | awaitFrame(t, sends, ports.MsgOutput) | 907 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 907 | d.handleInputForAttachment(token, []byte("JRS 3\r")) | 908 | d.handleInputForAttachment(token, []byte("JRS 3\r")) | ||
| 908 | 909 | ||||
| 909 | require.Same(t, current, ac.currentSession()) | 910 | require.Same(t, current, ac.currentSession()) | ||
| @@ -912,7 +913,7 @@ func TestPaletteJRSOutOfRangeKeepsPaletteOpenWithoutClamping(t *testing.T) { | |||||
| 912 | require.Equal(t, "JRS 3", ac.overlays.palette.Query()) | 913 | require.Equal(t, "JRS 3", ac.overlays.palette.Query()) | ||
| 913 | require.Equal(t, "requested recent session is unavailable", ac.overlays.paletteFeedback) | 914 | require.Equal(t, "requested recent session is unavailable", ac.overlays.paletteFeedback) | ||
| 914 | ac.overlays.paletteMu.Unlock() | 915 | ac.overlays.paletteMu.Unlock() | ||
| 915 | - | awaitFrame(t, sends, ports.MsgOutput) | 916 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 916 | } | 917 | } | ||
| 917 | 918 | ||||
| 918 | func TestPaletteJRSMalformedRankFeedback(t *testing.T) { | 919 | func TestPaletteJRSMalformedRankFeedback(t *testing.T) { | ||
| @@ -920,7 +921,7 @@ func TestPaletteJRSMalformedRankFeedback(t *testing.T) { | |||||
| 920 | defer releaseAll(releases) | 921 | defer releaseAll(releases) | ||
| 921 | 922 | ||||
| 922 | d.handleInput(current, ac, []byte("\x1b ")) | 923 | d.handleInput(current, ac, []byte("\x1b ")) | ||
| 923 | - | awaitFrame(t, sends, ports.MsgOutput) | 924 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 924 | d.handleInput(current, ac, []byte("JRS 0\r")) | 925 | d.handleInput(current, ac, []byte("JRS 0\r")) | ||
| 925 | 926 | ||||
| 926 | require.Same(t, current, ac.currentSession()) | 927 | require.Same(t, current, ac.currentSession()) | ||
| @@ -929,7 +930,7 @@ func TestPaletteJRSMalformedRankFeedback(t *testing.T) { | |||||
| 929 | require.Equal(t, "JRS 0", ac.overlays.palette.Query()) | 930 | require.Equal(t, "JRS 0", ac.overlays.palette.Query()) | ||
| 930 | require.Equal(t, "rank must be one positive decimal", ac.overlays.paletteFeedback) | 931 | require.Equal(t, "rank must be one positive decimal", ac.overlays.paletteFeedback) | ||
| 931 | ac.overlays.paletteMu.Unlock() | 932 | ac.overlays.paletteMu.Unlock() | ||
| 932 | - | awaitFrame(t, sends, ports.MsgOutput) | 933 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 933 | } | 934 | } | ||
| 934 | 935 | ||||
| 935 | func TestPaletteFailureDoesNotOverwriteChangedQueryInSameGeneration(t *testing.T) { | 936 | func TestPaletteFailureDoesNotOverwriteChangedQueryInSameGeneration(t *testing.T) { | ||
| @@ -964,8 +965,8 @@ func TestPaletteFailureDoesNotOverwriteNewerInteraction(t *testing.T) { | |||||
| 964 | ac.overlays.paletteMu.Lock() | 965 | ac.overlays.paletteMu.Lock() | ||
| 965 | require.Empty(t, ac.overlays.paletteFeedback) | 966 | require.Empty(t, ac.overlays.paletteFeedback) | ||
| 966 | ac.overlays.paletteMu.Unlock() | 967 | ac.overlays.paletteMu.Unlock() | ||
| 967 | - | awaitFrame(t, sends, ports.MsgOutput) | 968 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 968 | - | awaitFrame(t, sends, ports.MsgOutput) | 969 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 969 | } | 970 | } | ||
| 970 | 971 | ||||
| 971 | func TestPaletteTFPExecutesFloatingToggle(t *testing.T) { | 972 | func TestPaletteTFPExecutesFloatingToggle(t *testing.T) { | ||
| @@ -976,14 +977,14 @@ func TestPaletteTFPExecutesFloatingToggle(t *testing.T) { | |||||
| 976 | installTestFloating(tb, newPane("floating", nil, domain.Size{Cols: 20, Rows: 5}), false) | 977 | installTestFloating(tb, newPane("floating", nil, domain.Size{Cols: 20, Rows: 5}), false) | ||
| 977 | 978 | ||||
| 978 | d.handleInput(sess, ac, []byte("\x1b ")) | 979 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 979 | - | awaitFrame(t, sends, ports.MsgOutput) | 980 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 980 | d.handleInput(sess, ac, []byte("TFP\r")) | 981 | d.handleInput(sess, ac, []byte("TFP\r")) | ||
| 981 | 982 | ||||
| 982 | require.False(t, ac.overlays.paletteActive()) | 983 | require.False(t, ac.overlays.paletteActive()) | ||
| 983 | tb.mu.Lock() | 984 | tb.mu.Lock() | ||
| 984 | require.Equal(t, floatingVisible, tb.floating.state) | 985 | require.Equal(t, floatingVisible, tb.floating.state) | ||
| 985 | tb.mu.Unlock() | 986 | tb.mu.Unlock() | ||
| 986 | - | awaitFrame(t, sends, ports.MsgOutput) | 987 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 987 | } | 988 | } | ||
| 988 | 989 | ||||
| 989 | func TestPaletteCNSPromptsForSessionNameThenCreatesAndSwitches(t *testing.T) { | 990 | func TestPaletteCNSPromptsForSessionNameThenCreatesAndSwitches(t *testing.T) { | ||
| @@ -995,10 +996,10 @@ func TestPaletteCNSPromptsForSessionNameThenCreatesAndSwitches(t *testing.T) { | |||||
| 995 | d.ptys = newFactorySeq(t, p2) | 996 | d.ptys = newFactorySeq(t, p2) | ||
| 996 | 997 | ||||
| 997 | d.handleInput(sess, ac, []byte("\x1b ")) | 998 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 998 | - | awaitFrame(t, sends, ports.MsgOutput) | 999 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 999 | d.handleInput(sess, ac, []byte("CNS\r")) | 1000 | d.handleInput(sess, ac, []byte("CNS\r")) | ||
| 1000 | - | promptFrame := awaitFrame(t, sends, ports.MsgOutput) | 1001 | + | promptFrame := awaitFrame(t, sends, wire.MsgOutput) |
| 1001 | - | promptOutput, err := ports.UnmarshalOutput(promptFrame.Payload) | 1002 | + | promptOutput, err := wire.UnmarshalOutput(promptFrame.Payload) |
| 1002 | require.NoError(t, err) | 1003 | require.NoError(t, err) | ||
| 1003 | require.False(t, ac.overlays.paletteActive()) | 1004 | require.False(t, ac.overlays.paletteActive()) | ||
| 1004 | require.True(t, ac.overlays.promptActive()) | 1005 | require.True(t, ac.overlays.promptActive()) | ||
| @@ -1009,12 +1010,12 @@ func TestPaletteCNSPromptsForSessionNameThenCreatesAndSwitches(t *testing.T) { | |||||
| 1009 | // The submit first paints the newly attached session while the prompt is | 1010 | // The submit first paints the newly attached session while the prompt is | ||
| 1010 | // still open, then handlePromptInput closes the prompt and repaints the | 1011 | // still open, then handlePromptInput closes the prompt and repaints the | ||
| 1011 | // client's current session. The final frame must be for the new session. | 1012 | // client's current session. The final frame must be for the new session. | ||
| 1012 | - | firstPaint := awaitFrame(t, sends, ports.MsgOutput) | 1013 | + | firstPaint := awaitFrame(t, sends, wire.MsgOutput) |
| 1013 | - | firstOutput, err := ports.UnmarshalOutput(firstPaint.Payload) | 1014 | + | firstOutput, err := wire.UnmarshalOutput(firstPaint.Payload) |
| 1014 | require.NoError(t, err) | 1015 | require.NoError(t, err) | ||
| 1015 | require.Zero(t, firstOutput.Base, "new-session first paint must reset moving output state") | 1016 | require.Zero(t, firstOutput.Base, "new-session first paint must reset moving output state") | ||
| 1016 | - | finalRepaint := awaitFrame(t, sends, ports.MsgOutput) | 1017 | + | finalRepaint := awaitFrame(t, sends, wire.MsgOutput) |
| 1017 | - | finalOutput, err := ports.UnmarshalOutput(finalRepaint.Payload) | 1018 | + | finalOutput, err := wire.UnmarshalOutput(finalRepaint.Payload) |
| 1018 | require.NoError(t, err) | 1019 | require.NoError(t, err) | ||
| 1019 | require.False(t, ac.overlays.promptActive()) | 1020 | require.False(t, ac.overlays.promptActive()) | ||
| 1020 | require.Equal(t, 2, sessionCount(d)) | 1021 | require.Equal(t, 2, sessionCount(d)) | ||
| @@ -1049,9 +1050,9 @@ func TestPaletteDirectSessionCreation(t *testing.T) { | |||||
| 1049 | d.ptys = newFactorySeq(t, p2) | 1050 | d.ptys = newFactorySeq(t, p2) | ||
| 1050 | 1051 | ||||
| 1051 | d.handleInput(sess, ac, []byte("\x1b ")) | 1052 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1052 | - | awaitFrame(t, sends, ports.MsgOutput) | 1053 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1053 | d.handleInput(sess, ac, []byte(tc.input)) | 1054 | d.handleInput(sess, ac, []byte(tc.input)) | ||
| 1054 | - | awaitFrame(t, sends, ports.MsgOutput) | 1055 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1055 | 1056 | ||||
| 1056 | require.False(t, ac.overlays.paletteActive()) | 1057 | require.False(t, ac.overlays.paletteActive()) | ||
| 1057 | require.False(t, ac.overlays.promptActive()) | 1058 | require.False(t, ac.overlays.promptActive()) | ||
| @@ -1072,13 +1073,13 @@ func TestPaletteReopensWithSuccessfulCommandFirst(t *testing.T) { | |||||
| 1072 | defer releases[1]() | 1073 | defer releases[1]() | ||
| 1073 | 1074 | ||||
| 1074 | d.handleInput(sess, ac, []byte("\x1b ")) | 1075 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1075 | - | awaitFrame(t, sends, ports.MsgOutput) | 1076 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1076 | d.handleInput(sess, ac, []byte("NXT\r")) | 1077 | d.handleInput(sess, ac, []byte("NXT\r")) | ||
| 1077 | require.False(t, ac.overlays.paletteActive()) | 1078 | require.False(t, ac.overlays.paletteActive()) | ||
| 1078 | - | awaitFrame(t, sends, ports.MsgOutput) | 1079 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1079 | 1080 | ||||
| 1080 | d.handleInput(sess, ac, []byte("\x1b ")) | 1081 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1081 | - | awaitFrame(t, sends, ports.MsgOutput) | 1082 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1082 | result, ok := ac.overlays.palette.Selected() | 1083 | result, ok := ac.overlays.palette.Selected() | ||
| 1083 | require.True(t, ok) | 1084 | require.True(t, ok) | ||
| 1084 | cmd, ok := result.Command() | 1085 | cmd, ok := result.Command() | ||
| @@ -1163,15 +1164,15 @@ func TestPaletteCommandNoopRepaintsAfterClose(t *testing.T) { | |||||
| 1163 | defer releases[0]() | 1164 | defer releases[0]() | ||
| 1164 | 1165 | ||||
| 1165 | d.handleInput(sess, ac, []byte("\x1b ")) | 1166 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1166 | - | paletteFrame := awaitFrame(t, sends, ports.MsgOutput) | 1167 | + | paletteFrame := awaitFrame(t, sends, wire.MsgOutput) |
| 1167 | - | paletteOutput, err := ports.UnmarshalOutput(paletteFrame.Payload) | 1168 | + | paletteOutput, err := wire.UnmarshalOutput(paletteFrame.Payload) |
| 1168 | require.NoError(t, err) | 1169 | require.NoError(t, err) | ||
| 1169 | require.Contains(t, string(paletteOutput.Data), "Commands") | 1170 | require.Contains(t, string(paletteOutput.Data), "Commands") | ||
| 1170 | 1171 | ||||
| 1171 | d.handleInput(sess, ac, []byte("NXT\r")) | 1172 | d.handleInput(sess, ac, []byte("NXT\r")) | ||
| 1172 | require.False(t, ac.overlays.paletteActive()) | 1173 | require.False(t, ac.overlays.paletteActive()) | ||
| 1173 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | 1174 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) |
| 1174 | - | repaintOutput, err := ports.UnmarshalOutput(repaint.Payload) | 1175 | + | repaintOutput, err := wire.UnmarshalOutput(repaint.Payload) |
| 1175 | require.NoError(t, err) | 1176 | require.NoError(t, err) | ||
| 1176 | require.NotContains(t, string(repaintOutput.Data), "Commands") | 1177 | require.NotContains(t, string(repaintOutput.Data), "Commands") | ||
| 1177 | } | 1178 | } | ||
| @@ -1184,11 +1185,11 @@ func TestPaletteCreateTabErrorRepaintsAfterClose(t *testing.T) { | |||||
| 1184 | d.ptys = ptys | 1185 | d.ptys = ptys | ||
| 1185 | 1186 | ||||
| 1186 | d.handleInput(sess, ac, []byte("\x1b ")) | 1187 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1187 | - | awaitFrame(t, sends, ports.MsgOutput) | 1188 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1188 | d.handleInput(sess, ac, []byte("CNT\r")) | 1189 | d.handleInput(sess, ac, []byte("CNT\r")) | ||
| 1189 | require.False(t, ac.overlays.paletteActive()) | 1190 | require.False(t, ac.overlays.paletteActive()) | ||
| 1190 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | 1191 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) |
| 1191 | - | repaintOutput, err := ports.UnmarshalOutput(repaint.Payload) | 1192 | + | repaintOutput, err := wire.UnmarshalOutput(repaint.Payload) |
| 1192 | require.NoError(t, err) | 1193 | require.NoError(t, err) | ||
| 1193 | require.NotContains(t, string(repaintOutput.Data), "Commands") | 1194 | require.NotContains(t, string(repaintOutput.Data), "Commands") | ||
| 1194 | require.Len(t, sess.tabs, 1) | 1195 | require.Len(t, sess.tabs, 1) | ||
| @@ -1199,10 +1200,10 @@ func TestPaletteEnterNoMatchKeepsOpenAndEscapeSplit(t *testing.T) { | |||||
| 1199 | defer releases[0]() | 1200 | defer releases[0]() | ||
| 1200 | 1201 | ||||
| 1201 | d.handleInput(sess, ac, []byte("\x1b ")) | 1202 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1202 | - | awaitFrame(t, sends, ports.MsgOutput) | 1203 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1203 | d.handleInput(sess, ac, []byte("zzzz\r")) | 1204 | d.handleInput(sess, ac, []byte("zzzz\r")) | ||
| 1204 | require.True(t, ac.overlays.paletteActive()) | 1205 | require.True(t, ac.overlays.paletteActive()) | ||
| 1205 | - | awaitFrame(t, sends, ports.MsgOutput) | 1206 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1206 | 1207 | ||||
| 1207 | d.handlePaletteInput(ac, []byte{0x1b, '['}) | 1208 | d.handlePaletteInput(ac, []byte{0x1b, '['}) | ||
| 1208 | require.True(t, ac.overlays.paletteActive()) | 1209 | require.True(t, ac.overlays.paletteActive()) | ||
| @@ -1210,7 +1211,7 @@ func TestPaletteEnterNoMatchKeepsOpenAndEscapeSplit(t *testing.T) { | |||||
| 1210 | d.handlePaletteInput(ac, []byte{'A'}) | 1211 | d.handlePaletteInput(ac, []byte{'A'}) | ||
| 1211 | require.True(t, ac.overlays.paletteActive()) | 1212 | require.True(t, ac.overlays.paletteActive()) | ||
| 1212 | require.Empty(t, ac.overlays.palettePending) | 1213 | require.Empty(t, ac.overlays.palettePending) | ||
| 1213 | - | awaitFrame(t, sends, ports.MsgOutput) | 1214 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1214 | } | 1215 | } | ||
| 1215 | 1216 | ||||
| 1216 | func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | 1217 | func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | ||
| @@ -1218,10 +1219,10 @@ func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | |||||
| 1218 | defer releases[0]() | 1219 | defer releases[0]() | ||
| 1219 | 1220 | ||||
| 1220 | d.handleInput(sess, ac, []byte("\x1b ")) | 1221 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1221 | - | awaitFrame(t, sends, ports.MsgOutput) | 1222 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1222 | 1223 | ||||
| 1223 | d.handlePaletteInput(ac, []byte{0x0e}) | 1224 | d.handlePaletteInput(ac, []byte{0x0e}) | ||
| 1224 | - | awaitFrame(t, sends, ports.MsgOutput) | 1225 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1225 | result, ok := ac.overlays.palette.Selected() | 1226 | result, ok := ac.overlays.palette.Selected() | ||
| 1226 | require.True(t, ok) | 1227 | require.True(t, ok) | ||
| 1227 | cmd, ok := result.Command() | 1228 | cmd, ok := result.Command() | ||
| @@ -1229,7 +1230,7 @@ func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | |||||
| 1229 | require.Equal(t, "CNS", cmd.Code) | 1230 | require.Equal(t, "CNS", cmd.Code) | ||
| 1230 | 1231 | ||||
| 1231 | d.handlePaletteInput(ac, []byte{0x10}) | 1232 | d.handlePaletteInput(ac, []byte{0x10}) | ||
| 1232 | - | awaitFrame(t, sends, ports.MsgOutput) | 1233 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1233 | result, ok = ac.overlays.palette.Selected() | 1234 | result, ok = ac.overlays.palette.Selected() | ||
| 1234 | require.True(t, ok) | 1235 | require.True(t, ok) | ||
| 1235 | cmd, ok = result.Command() | 1236 | cmd, ok = result.Command() | ||
| @@ -1337,7 +1338,7 @@ func TestPaletteUTF8PendingCompletesFilter(t *testing.T) { | |||||
| 1337 | defer releases[0]() | 1338 | defer releases[0]() | ||
| 1338 | 1339 | ||||
| 1339 | d.handleInput(sess, ac, []byte("\x1b ")) | 1340 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 1340 | - | awaitFrame(t, sends, ports.MsgOutput) | 1341 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1341 | d.handlePaletteInput(ac, []byte{0xc3}) | 1342 | d.handlePaletteInput(ac, []byte{0xc3}) | ||
| 1342 | require.Equal(t, []byte{0xc3}, ac.overlays.palettePending) | 1343 | require.Equal(t, []byte{0xc3}, ac.overlays.palettePending) | ||
| 1343 | d.handlePaletteInput(ac, []byte{0xa9}) | 1344 | d.handlePaletteInput(ac, []byte{0xa9}) | ||
M internal/usecase/daemon/pane_actions_test.go +3 -2
| @@ -16,6 +16,7 @@ import ( | |||||
| 16 | "github.com/bnema/vev/internal/domain" | 16 | "github.com/bnema/vev/internal/domain" | ||
| 17 | "github.com/bnema/vev/internal/ports" | 17 | "github.com/bnema/vev/internal/ports" | ||
| 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 19 | scopy "github.com/bnema/vev/internal/usecase/copy" | 20 | scopy "github.com/bnema/vev/internal/usecase/copy" | ||
| 20 | "github.com/bnema/vev/internal/usecase/layout" | 21 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 21 | ) | 22 | ) | ||
| @@ -695,7 +696,7 @@ func TestClosePaneRepaintFanoutRespectsAttachmentScope(t *testing.T) { | |||||
| 695 | closingPTY.EXPECT().Close().Return(nil).Once() | 696 | closingPTY.EXPECT().Close().Return(nil).Once() | ||
| 696 | 697 | ||||
| 697 | clients := make([]*attachedClient, 2) | 698 | clients := make([]*attachedClient, 2) | ||
| 698 | - | sends := make([]chan ports.Frame, 2) | 699 | + | sends := make([]chan wire.Frame, 2) |
| 699 | for i := range clients { | 700 | for i := range clients { | ||
| 700 | tr, sent := newCapturingTransport(t) | 701 | tr, sent := newCapturingTransport(t) | ||
| 701 | clients[i] = &attachedClient{tr: tr, output: newOutputStateStream(), size: domain.Size{Cols: 41, Rows: 12}} | 702 | clients[i] = &attachedClient{tr: tr, output: newOutputStateStream(), size: domain.Size{Cols: 41, Rows: 12}} | ||
| @@ -715,7 +716,7 @@ func TestClosePaneRepaintFanoutRespectsAttachmentScope(t *testing.T) { | |||||
| 715 | select { | 716 | select { | ||
| 716 | case frame := <-sends[i]: | 717 | case frame := <-sends[i]: | ||
| 717 | require.True(t, want, "attachment %d unexpectedly repainted: %#v", i, frame) | 718 | require.True(t, want, "attachment %d unexpectedly repainted: %#v", i, frame) | ||
| 718 | - | require.Equal(t, ports.MsgOutput, frame.Type) | 719 | + | require.Equal(t, wire.MsgOutput, frame.Type) |
| 719 | default: | 720 | default: | ||
| 720 | require.False(t, want, "attachment %d was not repainted", i) | 721 | require.False(t, want, "attachment %d was not repainted", i) | ||
| 721 | } | 722 | } | ||
M internal/usecase/daemon/parked_route.go +5 -4
| @@ -9,6 +9,7 @@ import ( | |||||
| 9 | "github.com/bnema/vev/internal/domain" | 9 | "github.com/bnema/vev/internal/domain" | ||
| 10 | "github.com/bnema/vev/internal/ports" | 10 | "github.com/bnema/vev/internal/ports" | ||
| 11 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | ) | 13 | ) | ||
| 13 | 14 | ||||
| 14 | const parkedRouteLeaseTTL = 15 * time.Minute | 15 | const parkedRouteLeaseTTL = 15 * time.Minute | ||
| @@ -237,12 +238,12 @@ func (ac *attachedClient) consumePublishedParkedRoute(previous, published attach | |||||
| 237 | return 0 | 238 | return 0 | ||
| 238 | } | 239 | } | ||
| 239 | 240 | ||||
| 240 | - | func parkedRouteResponseFrame(response protocol.ParkedRouteResponse) (ports.Frame, error) { | 241 | + | func parkedRouteResponseFrame(response protocol.ParkedRouteResponse) (wire.Frame, error) { |
| 241 | - | payload := ports.MarshalParkedRouteResponse(response) | 242 | + | payload := wire.MarshalParkedRouteResponse(response) |
| 242 | if payload == nil { | 243 | if payload == nil { | ||
| 243 | - | return ports.Frame{}, errAttachmentTransition | 244 | + | return wire.Frame{}, errAttachmentTransition |
| 244 | } | 245 | } | ||
| 245 | - | return ports.Frame{Type: ports.MsgParkedRouteResponse, Payload: payload}, nil | 246 | + | return wire.Frame{Type: wire.MsgParkedRouteResponse, Payload: payload}, nil |
| 246 | } | 247 | } | ||
| 247 | 248 | ||||
| 248 | func (d *Daemon) sendParkedRouteResponse(effect *attachmentEffect, response protocol.ParkedRouteResponse) error { | 249 | func (d *Daemon) sendParkedRouteResponse(effect *attachmentEffect, response protocol.ParkedRouteResponse) error { | ||
M internal/usecase/daemon/parked_route_test.go +37 -36
| @@ -14,28 +14,29 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 16 | "github.com/bnema/vev/internal/protocol" | 16 | "github.com/bnema/vev/internal/protocol" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 17 | ) | 18 | ) | ||
| 18 | 19 | ||||
| 19 | type parkedRouteFailTransport struct{} | 20 | type parkedRouteFailTransport struct{} | ||
| 20 | 21 | ||||
| 21 | - | func (parkedRouteFailTransport) Send(ports.Frame) error { return errors.New("send failed") } | 22 | + | func (parkedRouteFailTransport) Send(wire.Frame) error { return errors.New("send failed") } |
| 22 | - | func (parkedRouteFailTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 23 | + | func (parkedRouteFailTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 23 | - | func (parkedRouteFailTransport) Close() error { return nil } | 24 | + | func (parkedRouteFailTransport) Close() error { return nil } |
| 24 | 25 | ||||
| 25 | type parkedRouteExpiryTransport struct { | 26 | type parkedRouteExpiryTransport struct { | ||
| 26 | - | sends chan ports.Frame | 27 | + | sends chan wire.Frame |
| 27 | closed chan struct{} | 28 | closed chan struct{} | ||
| 28 | once sync.Once | 29 | once sync.Once | ||
| 29 | } | 30 | } | ||
| 30 | 31 | ||||
| 31 | - | func (t *parkedRouteExpiryTransport) Send(frame ports.Frame) error { | 32 | + | func (t *parkedRouteExpiryTransport) Send(frame wire.Frame) error { |
| 32 | t.sends <- frame | 33 | t.sends <- frame | ||
| 33 | return nil | 34 | return nil | ||
| 34 | } | 35 | } | ||
| 35 | 36 | ||||
| 36 | - | func (t *parkedRouteExpiryTransport) Recv() (ports.Frame, error) { | 37 | + | func (t *parkedRouteExpiryTransport) Recv() (wire.Frame, error) { |
| 37 | <-t.closed | 38 | <-t.closed | ||
| 38 | - | return ports.Frame{}, io.EOF | 39 | + | return wire.Frame{}, io.EOF |
| 39 | } | 40 | } | ||
| 40 | 41 | ||||
| 41 | func (t *parkedRouteExpiryTransport) Close() error { | 42 | func (t *parkedRouteExpiryTransport) Close() error { | ||
| @@ -62,7 +63,7 @@ func (c *parkedRouteClock) setNow(now time.Time) { | |||||
| 62 | c.mu.Unlock() | 63 | c.mu.Unlock() | ||
| 63 | } | 64 | } | ||
| 64 | 65 | ||||
| 65 | - | func armAndPrepareParkedRoute(t *testing.T, d *Daemon, source *session, ac *attachedClient, sends chan ports.Frame) protocol.ParkedRouteLeaseID { | 66 | + | func armAndPrepareParkedRoute(t *testing.T, d *Daemon, source *session, ac *attachedClient, sends chan wire.Frame) protocol.ParkedRouteLeaseID { |
| 66 | t.Helper() | 67 | t.Helper() | ||
| 67 | ac.navigationCapabilities |= protocol.NavigationCapabilityHomePicker | 68 | ac.navigationCapabilities |= protocol.NavigationCapabilityHomePicker | ||
| 68 | token := source.captureAttachmentCapability(ac, ac.transport()) | 69 | token := source.captureAttachmentCapability(ac, ac.transport()) | ||
| @@ -70,14 +71,14 @@ func armAndPrepareParkedRoute(t *testing.T, d *Daemon, source *session, ac *atta | |||||
| 70 | require.True(t, admitted) | 71 | require.True(t, admitted) | ||
| 71 | require.NoError(t, d.sendNavigationActionForAttachment(effect, protocol.NavigationOpenHomePicker)) | 72 | require.NoError(t, d.sendNavigationActionForAttachment(effect, protocol.NavigationOpenHomePicker)) | ||
| 72 | effect.End() | 73 | effect.End() | ||
| 73 | - | directiveFrame := awaitFrame(t, sends, ports.MsgNavigationAction) | 74 | + | directiveFrame := awaitFrame(t, sends, wire.MsgNavigationAction) |
| 74 | - | directive, err := ports.UnmarshalNavigationDirective(directiveFrame.Payload) | 75 | + | directive, err := wire.UnmarshalNavigationDirective(directiveFrame.Payload) |
| 75 | require.NoError(t, err) | 76 | require.NoError(t, err) | ||
| 76 | 77 | ||||
| 77 | prepare := protocol.ParkedRouteRequest{RequestID: 1, LeaseID: directive.LeaseID, Action: protocol.ParkedRoutePrepare} | 78 | prepare := protocol.ParkedRouteRequest{RequestID: 1, LeaseID: directive.LeaseID, Action: protocol.ParkedRoutePrepare} | ||
| 78 | - | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(prepare)})) | 79 | + | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(prepare)})) |
| 79 | - | readyFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | 80 | + | readyFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) |
| 80 | - | ready, err := ports.UnmarshalParkedRouteResponse(readyFrame.Payload) | 81 | + | ready, err := wire.UnmarshalParkedRouteResponse(readyFrame.Payload) |
| 81 | require.NoError(t, err) | 82 | require.NoError(t, err) | ||
| 82 | require.Equal(t, protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady}, ready) | 83 | require.Equal(t, protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady}, ready) | ||
| 83 | return directive.LeaseID | 84 | return directive.LeaseID | ||
| @@ -108,12 +109,12 @@ func TestParkedRouteSwitchesExactLiveTargetOnRetainedTransport(t *testing.T) { | |||||
| 108 | SessionName: "target", LiveTabID: domain.TabStableID(target.tabs[0].stableID), | 109 | SessionName: "target", LiveTabID: domain.TabStableID(target.tabs[0].stableID), | ||
| 109 | } | 110 | } | ||
| 110 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &targetRequest} | 111 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &targetRequest} | ||
| 111 | - | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)})) | 112 | + | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)})) |
| 112 | 113 | ||||
| 113 | require.Same(t, target, ac.currentAttachmentSession()) | 114 | require.Same(t, target, ac.currentAttachmentSession()) | ||
| 114 | require.False(t, ac.parkedRouteOutput.Load()) | 115 | require.False(t, ac.parkedRouteOutput.Load()) | ||
| 115 | - | responseFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | 116 | + | responseFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) |
| 116 | - | response, err := ports.UnmarshalParkedRouteResponse(responseFrame.Payload) | 117 | + | response, err := wire.UnmarshalParkedRouteResponse(responseFrame.Payload) |
| 117 | require.NoError(t, err) | 118 | require.NoError(t, err) | ||
| 118 | require.Equal(t, protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteSwitched}, response) | 119 | require.Equal(t, protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteSwitched}, response) | ||
| 119 | } | 120 | } | ||
| @@ -147,11 +148,11 @@ func TestParkedRouteSwitchAcceptedBeforeLeaseExpiryCommitsAtomically(t *testing. | |||||
| 147 | SessionName: "target", LiveTabID: domain.TabStableID(target.tabs[0].stableID), | 148 | SessionName: "target", LiveTabID: domain.TabStableID(target.tabs[0].stableID), | ||
| 148 | } | 149 | } | ||
| 149 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &targetRequest} | 150 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &targetRequest} | ||
| 150 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)}) | 151 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)}) |
| 151 | 152 | ||||
| 152 | require.Same(t, target, ac.currentAttachmentSession()) | 153 | require.Same(t, target, ac.currentAttachmentSession()) | ||
| 153 | - | responseFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | 154 | + | responseFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) |
| 154 | - | response, err := ports.UnmarshalParkedRouteResponse(responseFrame.Payload) | 155 | + | response, err := wire.UnmarshalParkedRouteResponse(responseFrame.Payload) |
| 155 | require.NoError(t, err) | 156 | require.NoError(t, err) | ||
| 156 | require.Equal(t, protocol.ParkedRouteSwitched, response.Status) | 157 | require.Equal(t, protocol.ParkedRouteSwitched, response.Status) | ||
| 157 | } | 158 | } | ||
| @@ -185,7 +186,7 @@ func TestParkedRouteRestoresExactStoppedTargetWithDaemonEnvironment(t *testing.T | |||||
| 185 | SessionName: "stopped", Stopped: true, StoppedTab: domain.NewStableTabSelector("tab-b"), | 186 | SessionName: "stopped", Stopped: true, StoppedTab: domain.NewStableTabSelector("tab-b"), | ||
| 186 | } | 187 | } | ||
| 187 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &target} | 188 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &target} | ||
| 188 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)}) | 189 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)}) |
| 189 | 190 | ||||
| 190 | restored := ac.currentAttachmentSession() | 191 | restored := ac.currentAttachmentSession() | ||
| 191 | require.NotNil(t, restored) | 192 | require.NotNil(t, restored) | ||
| @@ -210,23 +211,23 @@ func TestParkedRouteStaleTargetLeavesSourceResumable(t *testing.T) { | |||||
| 210 | SessionName: "missing", LiveTabID: "tab-1", | 211 | SessionName: "missing", LiveTabID: "tab-1", | ||
| 211 | } | 212 | } | ||
| 212 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &missing} | 213 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &missing} | ||
| 213 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)}) | 214 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)}) |
| 214 | - | staleFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | 215 | + | staleFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) |
| 215 | - | stale, err := ports.UnmarshalParkedRouteResponse(staleFrame.Payload) | 216 | + | stale, err := wire.UnmarshalParkedRouteResponse(staleFrame.Payload) |
| 216 | require.NoError(t, err) | 217 | require.NoError(t, err) | ||
| 217 | require.Equal(t, protocol.ParkedRouteStaleTarget, stale.Status) | 218 | require.Equal(t, protocol.ParkedRouteStaleTarget, stale.Status) | ||
| 218 | require.Same(t, source, ac.currentAttachmentSession()) | 219 | require.Same(t, source, ac.currentAttachmentSession()) | ||
| 219 | require.True(t, ac.parkedRouteOutput.Load()) | 220 | require.True(t, ac.parkedRouteOutput.Load()) | ||
| 220 | 221 | ||||
| 221 | resume := protocol.ParkedRouteRequest{RequestID: 3, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | 222 | resume := protocol.ParkedRouteRequest{RequestID: 3, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | ||
| 222 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(resume)}) | 223 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(resume)}) |
| 223 | - | resumedFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | 224 | + | resumedFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) |
| 224 | - | resumed, err := ports.UnmarshalParkedRouteResponse(resumedFrame.Payload) | 225 | + | resumed, err := wire.UnmarshalParkedRouteResponse(resumedFrame.Payload) |
| 225 | require.NoError(t, err) | 226 | require.NoError(t, err) | ||
| 226 | require.Equal(t, protocol.ParkedRouteResumed, resumed.Status) | 227 | require.Equal(t, protocol.ParkedRouteResumed, resumed.Status) | ||
| 227 | require.False(t, ac.parkedRouteOutput.Load()) | 228 | require.False(t, ac.parkedRouteOutput.Load()) | ||
| 228 | - | outputFrame := awaitFrame(t, sends, ports.MsgOutput) | 229 | + | outputFrame := awaitFrame(t, sends, wire.MsgOutput) |
| 229 | - | output, err := ports.UnmarshalOutput(outputFrame.Payload) | 230 | + | output, err := wire.UnmarshalOutput(outputFrame.Payload) |
| 230 | require.NoError(t, err) | 231 | require.NoError(t, err) | ||
| 231 | require.True(t, output.Full) | 232 | require.True(t, output.Full) | ||
| 232 | } | 233 | } | ||
| @@ -245,10 +246,10 @@ func TestParkedRouteDoesNotReplayOneShotEffectsAfterResume(t *testing.T) { | |||||
| 245 | } | 246 | } | ||
| 246 | 247 | ||||
| 247 | resume := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | 248 | resume := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | ||
| 248 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(resume)}) | 249 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(resume)}) |
| 249 | - | _ = awaitFrame(t, sends, ports.MsgParkedRouteResponse) | 250 | + | _ = awaitFrame(t, sends, wire.MsgParkedRouteResponse) |
| 250 | - | outputFrame := awaitFrame(t, sends, ports.MsgOutput) | 251 | + | outputFrame := awaitFrame(t, sends, wire.MsgOutput) |
| 251 | - | output, err := ports.UnmarshalOutput(outputFrame.Payload) | 252 | + | output, err := wire.UnmarshalOutput(outputFrame.Payload) |
| 252 | require.NoError(t, err) | 253 | require.NoError(t, err) | ||
| 253 | require.True(t, output.Full) | 254 | require.True(t, output.Full) | ||
| 254 | require.NotContains(t, string(output.Data), "one-shot effect") | 255 | require.NotContains(t, string(output.Data), "one-shot effect") | ||
| @@ -270,9 +271,9 @@ func TestParkedRouteExpiredLeaseFailsClosed(t *testing.T) { | |||||
| 270 | ac.parkedRoute.expiresAt = d.clock.Now() | 271 | ac.parkedRoute.expiresAt = d.clock.Now() | ||
| 271 | ac.parkedRouteMu.Unlock() | 272 | ac.parkedRouteMu.Unlock() | ||
| 272 | resume := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | 273 | resume := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | ||
| 273 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(resume)}) | 274 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(resume)}) |
| 274 | - | responseFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | 275 | + | responseFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) |
| 275 | - | response, err := ports.UnmarshalParkedRouteResponse(responseFrame.Payload) | 276 | + | response, err := wire.UnmarshalParkedRouteResponse(responseFrame.Payload) |
| 276 | require.NoError(t, err) | 277 | require.NoError(t, err) | ||
| 277 | require.Equal(t, protocol.ParkedRouteExpired, response.Status) | 278 | require.Equal(t, protocol.ParkedRouteExpired, response.Status) | ||
| 278 | require.Same(t, source, ac.currentAttachmentSession()) | 279 | require.Same(t, source, ac.currentAttachmentSession()) | ||
| @@ -308,7 +309,7 @@ func TestParkedRouteLeaseExpiryClosesExactRetainedTransport(t *testing.T) { | |||||
| 308 | clock.EXPECT().Now().Return(time.Time{}).Maybe() | 309 | clock.EXPECT().Now().Return(time.Time{}).Maybe() | ||
| 309 | clock.EXPECT().NewTimer(mock.Anything).Return(timer).Once() | 310 | clock.EXPECT().NewTimer(mock.Anything).Return(timer).Once() | ||
| 310 | d.clock = clock | 311 | d.clock = clock | ||
| 311 | - | transport := &parkedRouteExpiryTransport{sends: make(chan ports.Frame, 8), closed: make(chan struct{})} | 312 | + | transport := &parkedRouteExpiryTransport{sends: make(chan wire.Frame, 8), closed: make(chan struct{})} |
| 312 | ac.replaceTransport(transport) | 313 | ac.replaceTransport(transport) | ||
| 313 | 314 | ||||
| 314 | _ = armAndPrepareParkedRoute(t, d, source, ac, transport.sends) | 315 | _ = armAndPrepareParkedRoute(t, d, source, ac, transport.sends) | ||
M internal/usecase/daemon/performance_benchmark_test.go +9 -8
| @@ -16,6 +16,7 @@ import ( | |||||
| 16 | "github.com/bnema/vev/internal/domain" | 16 | "github.com/bnema/vev/internal/domain" | ||
| 17 | "github.com/bnema/vev/internal/ports" | 17 | "github.com/bnema/vev/internal/ports" | ||
| 18 | "github.com/bnema/vev/internal/protocol" | 18 | "github.com/bnema/vev/internal/protocol" | ||
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 19 | "github.com/bnema/vev/internal/usecase/layout" | 20 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 20 | snapcodec "github.com/bnema/vev/internal/usecase/snapshot" | 21 | snapcodec "github.com/bnema/vev/internal/usecase/snapshot" | ||
| 21 | ) | 22 | ) | ||
| @@ -184,12 +185,12 @@ func TestPerformanceFixtureExplicitCloseReleasesIterationState(t *testing.T) { | |||||
| 184 | func TestCountingOutputTransportCountsOpaquePayloadAndRejectsShortPayload(t *testing.T) { | 185 | func TestCountingOutputTransportCountsOpaquePayloadAndRejectsShortPayload(t *testing.T) { | ||
| 185 | transport := &countingOutputTransport{} | 186 | transport := &countingOutputTransport{} | ||
| 186 | 187 | ||||
| 187 | - | err := transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 23)}) | 188 | + | err := transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 23)}) |
| 188 | require.Error(t, err) | 189 | require.Error(t, err) | ||
| 189 | require.Equal(t, countingOutputMetrics{}, transport.metrics()) | 190 | require.Equal(t, countingOutputMetrics{}, transport.metrics()) | ||
| 190 | 191 | ||||
| 191 | payload := append(make([]byte, 24), 0xff, 0x00, 0xfe) | 192 | payload := append(make([]byte, 24), 0xff, 0x00, 0xfe) | ||
| 192 | - | require.NoError(t, transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: payload})) | 193 | + | require.NoError(t, transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: payload})) |
| 193 | require.Equal(t, countingOutputMetrics{frames: 1, bytes: 3, payloadBytes: uint64(len(payload))}, transport.metrics()) | 194 | require.Equal(t, countingOutputMetrics{frames: 1, bytes: 3, payloadBytes: uint64(len(payload))}, transport.metrics()) | ||
| 194 | require.Equal(t, payload, transport.lastPayload()) | 195 | require.Equal(t, payload, transport.lastPayload()) | ||
| 195 | 196 | ||||
| @@ -230,7 +231,7 @@ func TestPerformanceFixtureCounters(t *testing.T) { | |||||
| 230 | func TestRenderStageHooksCountProductionBoundariesOnFailedSend(t *testing.T) { | 231 | func TestRenderStageHooksCountProductionBoundariesOnFailedSend(t *testing.T) { | ||
| 231 | d, sess, ac, sends := newManualSessionWithPTYs(t, nil) | 232 | d, sess, ac, sends := newManualSessionWithPTYs(t, nil) | ||
| 232 | d.paint(sess, ac, true, nil) | 233 | d.paint(sess, ac, true, nil) | ||
| 233 | - | _ = awaitFrame(t, sends, ports.MsgOutput) | 234 | + | _ = awaitFrame(t, sends, wire.MsgOutput) |
| 234 | var captures, compositions, emissions int | 235 | var captures, compositions, emissions int | ||
| 235 | ac.renderStages = renderStageHooks{ | 236 | ac.renderStages = renderStageHooks{ | ||
| 236 | capture: func() { captures++ }, | 237 | capture: func() { captures++ }, | ||
| @@ -446,7 +447,7 @@ func benchmarkDaemonLargeHistory(b *testing.B, workload string, run func(*perfor | |||||
| 446 | } | 447 | } | ||
| 447 | metrics := fixture.metrics() | 448 | metrics := fixture.metrics() | ||
| 448 | if payload := fixture.output.lastPayload(); payload != nil { | 449 | if payload := fixture.output.lastPayload(); payload != nil { | ||
| 449 | - | if _, err := ports.UnmarshalOutput(payload); err != nil { | 450 | + | if _, err := wire.UnmarshalOutput(payload); err != nil { |
| 450 | b.Fatalf("decode last output: %v", err) | 451 | b.Fatalf("decode last output: %v", err) | ||
| 451 | } | 452 | } | ||
| 452 | } | 453 | } | ||
| @@ -1347,8 +1348,8 @@ type countingOutputTransport struct { | |||||
| 1347 | last []byte | 1348 | last []byte | ||
| 1348 | } | 1349 | } | ||
| 1349 | 1350 | ||||
| 1350 | - | func (t *countingOutputTransport) Send(frame ports.Frame) error { | 1351 | + | func (t *countingOutputTransport) Send(frame wire.Frame) error { |
| 1351 | - | if frame.Type != ports.MsgOutput { | 1352 | + | if frame.Type != wire.MsgOutput { |
| 1352 | return nil | 1353 | return nil | ||
| 1353 | } | 1354 | } | ||
| 1354 | if len(frame.Payload) < outputPayloadHeaderBytes { | 1355 | if len(frame.Payload) < outputPayloadHeaderBytes { | ||
| @@ -1362,8 +1363,8 @@ func (t *countingOutputTransport) Send(frame ports.Frame) error { | |||||
| 1362 | t.mu.Unlock() | 1363 | t.mu.Unlock() | ||
| 1363 | return nil | 1364 | return nil | ||
| 1364 | } | 1365 | } | ||
| 1365 | - | func (*countingOutputTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 1366 | + | func (*countingOutputTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 1366 | - | func (*countingOutputTransport) Close() error { return nil } | 1367 | + | func (*countingOutputTransport) Close() error { return nil } |
| 1367 | func (t *countingOutputTransport) reset() { | 1368 | func (t *countingOutputTransport) reset() { | ||
| 1368 | t.mu.Lock() | 1369 | t.mu.Lock() | ||
| 1369 | t.countingOutputMetrics = countingOutputMetrics{} | 1370 | t.countingOutputMetrics = countingOutputMetrics{} | ||
M internal/usecase/daemon/picker.go +5 -4
| @@ -11,6 +11,7 @@ import ( | |||||
| 11 | "github.com/bnema/vev/internal/domain" | 11 | "github.com/bnema/vev/internal/domain" | ||
| 12 | "github.com/bnema/vev/internal/ports" | 12 | "github.com/bnema/vev/internal/ports" | ||
| 13 | "github.com/bnema/vev/internal/protocol" | 13 | "github.com/bnema/vev/internal/protocol" | ||
| 14 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 14 | "github.com/bnema/vev/internal/usecase/layout" | 15 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 15 | "github.com/bnema/vev/internal/usecase/picker" | 16 | "github.com/bnema/vev/internal/usecase/picker" | ||
| 16 | "github.com/bnema/vev/internal/usecase/ui" | 17 | "github.com/bnema/vev/internal/usecase/ui" | ||
| @@ -923,7 +924,7 @@ func (d *Daemon) sendLocalAttachTargetForAttachment(effect *attachmentEffect, ta | |||||
| 923 | // Explicit tab rows already take the direct transition path above, while | 924 | // Explicit tab rows already take the direct transition path above, while | ||
| 924 | // stopped sessions have no active target session and retain the fallback. | 925 | // stopped sessions have no active target session and retain the fallback. | ||
| 925 | samePeerEligible := guard.allowSamePeer && targetSess != nil && target.TabIndex <= 0 | 926 | samePeerEligible := guard.allowSamePeer && targetSess != nil && target.TabIndex <= 0 | ||
| 926 | - | payload := ports.MarshalAttachTarget(protocol.AttachTarget{ | 927 | + | payload := wire.MarshalAttachTarget(protocol.AttachTarget{ |
| 927 | Session: sessionName, | 928 | Session: sessionName, | ||
| 928 | Intent: protocol.IntentAttach, | 929 | Intent: protocol.IntentAttach, | ||
| 929 | ExactTarget: exactTarget, | 930 | ExactTarget: exactTarget, | ||
| @@ -943,7 +944,7 @@ func (d *Daemon) sendLocalAttachTargetForAttachment(effect *attachmentEffect, ta | |||||
| 943 | } else { | 944 | } else { | ||
| 944 | effect.ac.offerSamePeerTarget(*exactTarget) | 945 | effect.ac.offerSamePeerTarget(*exactTarget) | ||
| 945 | } | 946 | } | ||
| 946 | - | if err := effect.sendControl(ports.Frame{Type: ports.MsgAttachTarget, Payload: payload}); err != nil { | 947 | + | if err := effect.sendControl(wire.Frame{Type: wire.MsgAttachTarget, Payload: payload}); err != nil { |
| 947 | if samePeerEligible { | 948 | if samePeerEligible { | ||
| 948 | effect.ac.clearSamePeerOffer() | 949 | effect.ac.clearSamePeerOffer() | ||
| 949 | } | 950 | } | ||
| @@ -989,11 +990,11 @@ func (d *Daemon) sendRemoteAttachTargetForAttachment(effect *attachmentEffect, t | |||||
| 989 | RemoteTarget: &remoteTarget, | 990 | RemoteTarget: &remoteTarget, | ||
| 990 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 991 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 991 | } | 992 | } | ||
| 992 | - | payload := ports.MarshalAttachTarget(handoff) | 993 | + | payload := wire.MarshalAttachTarget(handoff) |
| 993 | if payload == nil { | 994 | if payload == nil { | ||
| 994 | return failUnavailable() | 995 | return failUnavailable() | ||
| 995 | } | 996 | } | ||
| 996 | - | if err := effect.sendControl(ports.Frame{Type: ports.MsgAttachTarget, Payload: payload}); err != nil { | 997 | + | if err := effect.sendControl(wire.Frame{Type: wire.MsgAttachTarget, Payload: payload}); err != nil { |
| 997 | return domain.UserErr(domain.NoticeSessionUnavailable, "couldn't attach to remote session", err) | 998 | return domain.UserErr(domain.NoticeSessionUnavailable, "couldn't attach to remote session", err) | ||
| 998 | } | 999 | } | ||
| 999 | if guard.closePicker { | 1000 | if guard.closePicker { | ||
M internal/usecase/daemon/picker_test.go +30 -29
| @@ -17,6 +17,7 @@ import ( | |||||
| 17 | "github.com/bnema/vev/internal/ports" | 17 | "github.com/bnema/vev/internal/ports" | ||
| 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 19 | "github.com/bnema/vev/internal/protocol" | 19 | "github.com/bnema/vev/internal/protocol" | ||
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 20 | "github.com/bnema/vev/internal/usecase/layout" | 21 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 21 | "github.com/bnema/vev/internal/usecase/picker" | 22 | "github.com/bnema/vev/internal/usecase/picker" | ||
| 22 | recoveryusecase "github.com/bnema/vev/internal/usecase/recovery" | 23 | recoveryusecase "github.com/bnema/vev/internal/usecase/recovery" | ||
| @@ -34,9 +35,9 @@ type remotePickerSendErrorTransport struct { | |||||
| 34 | err error | 35 | err error | ||
| 35 | } | 36 | } | ||
| 36 | 37 | ||||
| 37 | - | func (t *remotePickerSendErrorTransport) Send(ports.Frame) error { return t.err } | 38 | + | func (t *remotePickerSendErrorTransport) Send(wire.Frame) error { return t.err } |
| 38 | - | func (*remotePickerSendErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 39 | + | func (*remotePickerSendErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 39 | - | func (*remotePickerSendErrorTransport) Close() error { return nil } | 40 | + | func (*remotePickerSendErrorTransport) Close() error { return nil } |
| 40 | 41 | ||||
| 41 | type refusingSnapshotDeleteRepository struct { | 42 | type refusingSnapshotDeleteRepository struct { | ||
| 42 | noOpSnapshotRepository | 43 | noOpSnapshotRepository | ||
| @@ -222,11 +223,11 @@ func TestPickerSortToggleFlipsModeAndKeepsSelection(t *testing.T) { | |||||
| 222 | d.mu.Unlock() | 223 | d.mu.Unlock() | ||
| 223 | 224 | ||||
| 224 | d.enterPicker(sess, ac) | 225 | d.enterPicker(sess, ac) | ||
| 225 | - | awaitFrame(t, sends, ports.MsgOutput) | 226 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 226 | // Move off the attached session's active tab: a navigate rebuild snaps | 227 | // Move off the attached session's active tab: a navigate rebuild snaps | ||
| 227 | // back to it unless the toggle preserves the selection. | 228 | // back to it unless the toggle preserves the selection. | ||
| 228 | d.handleInput(sess, ac, tc.navigate) | 229 | d.handleInput(sess, ac, tc.navigate) | ||
| 229 | - | awaitFrame(t, sends, ports.MsgOutput) | 230 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 230 | ac.overlays.pickerMu.Lock() | 231 | ac.overlays.pickerMu.Lock() | ||
| 231 | before, ok := ac.overlays.picker.Selected() | 232 | before, ok := ac.overlays.picker.Selected() | ||
| 232 | ac.overlays.pickerMu.Unlock() | 233 | ac.overlays.pickerMu.Unlock() | ||
| @@ -239,7 +240,7 @@ func TestPickerSortToggleFlipsModeAndKeepsSelection(t *testing.T) { | |||||
| 239 | } | 240 | } | ||
| 240 | 241 | ||||
| 241 | d.handleInput(sess, ac, []byte("s")) | 242 | d.handleInput(sess, ac, []byte("s")) | ||
| 242 | - | awaitFrame(t, sends, ports.MsgOutput) | 243 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 243 | 244 | ||||
| 244 | require.Equal(t, uint32(pickerSortGrouped), d.pickerSort.Load()) | 245 | require.Equal(t, uint32(pickerSortGrouped), d.pickerSort.Load()) | ||
| 245 | require.True(t, ac.overlays.pickerActive()) | 246 | require.True(t, ac.overlays.pickerActive()) | ||
| @@ -252,7 +253,7 @@ func TestPickerSortToggleFlipsModeAndKeepsSelection(t *testing.T) { | |||||
| 252 | require.Equal(t, " Sessions · grouped ", title) | 253 | require.Equal(t, " Sessions · grouped ", title) | ||
| 253 | 254 | ||||
| 254 | d.handleInput(sess, ac, []byte("s")) | 255 | d.handleInput(sess, ac, []byte("s")) | ||
| 255 | - | awaitFrame(t, sends, ports.MsgOutput) | 256 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 256 | 257 | ||||
| 257 | require.Equal(t, uint32(pickerSortRecent), d.pickerSort.Load()) | 258 | require.Equal(t, uint32(pickerSortRecent), d.pickerSort.Load()) | ||
| 258 | require.True(t, ac.overlays.pickerActive()) | 259 | require.True(t, ac.overlays.pickerActive()) | ||
| @@ -812,7 +813,7 @@ func TestPickerResumesStoppedSessionWithPersistedTabNames(t *testing.T) { | |||||
| 812 | d.inactive["work"] = inactiveSession{name: "work", cwd: "/tmp/work", createdAt: 7, tabNames: []string{"shell", "logs"}, record: domain.CatalogueRecord{Name: "work"}, state: protocol.SessionDown} | 813 | d.inactive["work"] = inactiveSession{name: "work", cwd: "/tmp/work", createdAt: 7, tabNames: []string{"shell", "logs"}, record: domain.CatalogueRecord{Name: "work"}, state: protocol.SessionDown} | ||
| 813 | 814 | ||||
| 814 | d.resumeStoppedAndSwitch(from, ac, picker.Target{Name: "work", Stopped: true}) | 815 | d.resumeStoppedAndSwitch(from, ac, picker.Target{Name: "work", Stopped: true}) | ||
| 815 | - | awaitFrame(t, sends, ports.MsgOutput) | 816 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 816 | 817 | ||||
| 817 | target := ac.currentSession() | 818 | target := ac.currentSession() | ||
| 818 | require.NotNil(t, target) | 819 | require.NotNil(t, target) | ||
| @@ -835,16 +836,16 @@ func TestPickerSameSessionNavigationSwitchAndEscClose(t *testing.T) { | |||||
| 835 | }() | 836 | }() | ||
| 836 | 837 | ||||
| 837 | d.enterPicker(sess, ac) | 838 | d.enterPicker(sess, ac) | ||
| 838 | - | awaitFrame(t, sends, ports.MsgOutput) | 839 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 839 | d.handleInput(sess, ac, []byte("j")) | 840 | d.handleInput(sess, ac, []byte("j")) | ||
| 840 | - | awaitFrame(t, sends, ports.MsgOutput) | 841 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 841 | d.handleInput(sess, ac, []byte("\r")) | 842 | d.handleInput(sess, ac, []byte("\r")) | ||
| 842 | 843 | ||||
| 843 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | 844 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | ||
| 844 | requireFloatingInitialized(t, testAttachmentTab(sess)) | 845 | requireFloatingInitialized(t, testAttachmentTab(sess)) | ||
| 845 | - | awaitFrame(t, sends, ports.MsgOutput) | 846 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 846 | d.enterPicker(sess, ac) | 847 | d.enterPicker(sess, ac) | ||
| 847 | - | awaitFrame(t, sends, ports.MsgOutput) | 848 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 848 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | 849 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | ||
| 849 | d.clock = clk | 850 | d.clock = clk | ||
| 850 | d.handleInput(sess, ac, []byte("\x1b")) | 851 | d.handleInput(sess, ac, []byte("\x1b")) | ||
| @@ -852,7 +853,7 @@ func TestPickerSameSessionNavigationSwitchAndEscClose(t *testing.T) { | |||||
| 852 | require.True(t, ac.overlays.pickerActive()) | 853 | require.True(t, ac.overlays.pickerActive()) | ||
| 853 | timer.ch <- time.Now() | 854 | timer.ch <- time.Now() | ||
| 854 | require.Eventually(t, func() bool { return !ac.overlays.pickerActive() }, time.Second, 5*time.Millisecond) | 855 | require.Eventually(t, func() bool { return !ac.overlays.pickerActive() }, time.Second, 5*time.Millisecond) | ||
| 855 | - | awaitFrame(t, sends, ports.MsgOutput) | 856 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 856 | } | 857 | } | ||
| 857 | 858 | ||||
| 858 | func TestPickerSplitArrowNavigatesWithoutExiting(t *testing.T) { | 859 | func TestPickerSplitArrowNavigatesWithoutExiting(t *testing.T) { | ||
| @@ -876,7 +877,7 @@ func TestPickerSplitArrowNavigatesWithoutExiting(t *testing.T) { | |||||
| 876 | }() | 877 | }() | ||
| 877 | 878 | ||||
| 878 | d.enterPicker(sess, ac) | 879 | d.enterPicker(sess, ac) | ||
| 879 | - | awaitFrame(t, sends, ports.MsgOutput) | 880 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 880 | for _, input := range tc.input { | 881 | for _, input := range tc.input { | ||
| 881 | d.handleInput(sess, ac, input) | 882 | d.handleInput(sess, ac, input) | ||
| 882 | } | 883 | } | ||
| @@ -950,7 +951,7 @@ func TestPickerLoneEscapeExitsAfterDelay(t *testing.T) { | |||||
| 950 | defer releases[0]() | 951 | defer releases[0]() | ||
| 951 | 952 | ||||
| 952 | d.enterPicker(sess, ac) | 953 | d.enterPicker(sess, ac) | ||
| 953 | - | awaitFrame(t, sends, ports.MsgOutput) | 954 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 954 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | 955 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | ||
| 955 | d.clock = clk | 956 | d.clock = clk | ||
| 956 | d.handleInput(sess, ac, []byte("\x1b")) | 957 | d.handleInput(sess, ac, []byte("\x1b")) | ||
| @@ -984,10 +985,10 @@ func TestPickerStalePaintAfterSessionSwitchSendsNoFrame(t *testing.T) { | |||||
| 984 | d.sessions[sess2.id] = sess2 | 985 | d.sessions[sess2.id] = sess2 | ||
| 985 | 986 | ||||
| 986 | d.firstPaint(sess1, ac1) | 987 | d.firstPaint(sess1, ac1) | ||
| 987 | - | awaitFrame(t, sends1, ports.MsgOutput) | 988 | + | awaitFrame(t, sends1, wire.MsgOutput) |
| 988 | d.stealClientForTarget(sess1, ac1, sess2, picker.Target{Session: sess2.id}) | 989 | d.stealClientForTarget(sess1, ac1, sess2, picker.Target{Session: sess2.id}) | ||
| 989 | d.firstPaint(sess2, ac1) | 990 | d.firstPaint(sess2, ac1) | ||
| 990 | - | awaitFrame(t, sends1, ports.MsgOutput) | 991 | + | awaitFrame(t, sends1, wire.MsgOutput) |
| 991 | require.Same(t, sess2, ac1.currentSession()) | 992 | require.Same(t, sess2, ac1.currentSession()) | ||
| 992 | for len(sends1) > 0 { | 993 | for len(sends1) > 0 { | ||
| 993 | <-sends1 | 994 | <-sends1 | ||
| @@ -1011,7 +1012,7 @@ func TestPickerSessionSwitchPublishesBeforeInFlightPaintSendCompletes(t *testing | |||||
| 1011 | enteredSend := make(chan struct{}) | 1012 | enteredSend := make(chan struct{}) | ||
| 1012 | releaseSend := make(chan struct{}) | 1013 | releaseSend := make(chan struct{}) | ||
| 1013 | tr := portsmocks.NewMockTransport(t) | 1014 | tr := portsmocks.NewMockTransport(t) | ||
| 1014 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(ports.Frame) error { | 1015 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(wire.Frame) error { |
| 1015 | close(enteredSend) | 1016 | close(enteredSend) | ||
| 1016 | <-releaseSend | 1017 | <-releaseSend | ||
| 1017 | return nil | 1018 | return nil | ||
| @@ -1370,14 +1371,14 @@ func TestPickerResizeRecomposesModal(t *testing.T) { | |||||
| 1370 | defer releasePTY() | 1371 | defer releasePTY() | ||
| 1371 | 1372 | ||||
| 1372 | d.enterPicker(sess, ac) | 1373 | d.enterPicker(sess, ac) | ||
| 1373 | - | awaitFrame(t, sends, ports.MsgOutput) | 1374 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1374 | d.resize(sess, ac, domain.Size{Cols: 100, Rows: 30}) | 1375 | d.resize(sess, ac, domain.Size{Cols: 100, Rows: 30}) | ||
| 1375 | // Picker recomposition is the relevant event here; do not depend on a real | 1376 | // Picker recomposition is the relevant event here; do not depend on a real | ||
| 1376 | // resize-idle timer in this synchronous rendering test. | 1377 | // resize-idle timer in this synchronous rendering test. | ||
| 1377 | d.paint(sess, ac, false, nil) | 1378 | d.paint(sess, ac, false, nil) | ||
| 1378 | 1379 | ||||
| 1379 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 1380 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 1380 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 1381 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 1381 | require.NoError(t, err) | 1382 | require.NoError(t, err) | ||
| 1382 | require.Contains(t, string(msg.Data), "┌") | 1383 | require.Contains(t, string(msg.Data), "┌") | ||
| 1383 | require.Contains(t, string(msg.Data), "Sessions") | 1384 | require.Contains(t, string(msg.Data), "Sessions") | ||
| @@ -1455,11 +1456,11 @@ func TestPickerEnterOnStoppedSessionRestoreFailureSurfacesNoticeAndStaysPut(t *t | |||||
| 1455 | d.ptys = ptys | 1456 | d.ptys = ptys | ||
| 1456 | 1457 | ||||
| 1457 | d.enterPicker(from, ac) | 1458 | d.enterPicker(from, ac) | ||
| 1458 | - | awaitFrame(t, sends, ports.MsgOutput) | 1459 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1459 | d.handleInput(from, ac, []byte("j")) | 1460 | d.handleInput(from, ac, []byte("j")) | ||
| 1460 | - | awaitFrame(t, sends, ports.MsgOutput) | 1461 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1461 | d.handleInput(from, ac, []byte("\r")) | 1462 | d.handleInput(from, ac, []byte("\r")) | ||
| 1462 | - | awaitFrame(t, sends, ports.MsgOutput) | 1463 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1463 | 1464 | ||||
| 1464 | history := d.notices.history() | 1465 | history := d.notices.history() | ||
| 1465 | require.Len(t, history, 1, "failed stopped-session restore must record exactly one notice") | 1466 | require.Len(t, history, 1, "failed stopped-session restore must record exactly one notice") | ||
| @@ -1615,10 +1616,10 @@ func TestPickerKillActiveSessionSnapshotDeleteRefusalReportsOnceAndKeepsPicker(t | |||||
| 1615 | require.NoError(t, d.catalogue.Create(record)) | 1616 | require.NoError(t, d.catalogue.Create(record)) | ||
| 1616 | 1617 | ||||
| 1617 | d.enterPicker(from, ac) | 1618 | d.enterPicker(from, ac) | ||
| 1618 | - | awaitFrame(t, sends, ports.MsgOutput) | 1619 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1619 | // MRU-desc order is from(current), recent, older; "j" moves onto "recent". | 1620 | // MRU-desc order is from(current), recent, older; "j" moves onto "recent". | ||
| 1620 | d.handleInput(from, ac, []byte("j")) | 1621 | d.handleInput(from, ac, []byte("j")) | ||
| 1621 | - | awaitFrame(t, sends, ports.MsgOutput) | 1622 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1622 | d.handleInput(from, ac, []byte("x")) | 1623 | d.handleInput(from, ac, []byte("x")) | ||
| 1623 | 1624 | ||||
| 1624 | history := d.notices.history() | 1625 | history := d.notices.history() | ||
| @@ -1662,11 +1663,11 @@ func TestPickerKillStoppedSessionPersistDeleteFailureSurfacesNoticeAndKeepsEntry | |||||
| 1662 | d.inactive["stopped"] = inactiveSession{name: "stopped", cwd: "/tmp/stopped", createdAt: 7, incarnation: record.IncarnationID, record: record} | 1663 | d.inactive["stopped"] = inactiveSession{name: "stopped", cwd: "/tmp/stopped", createdAt: 7, incarnation: record.IncarnationID, record: record} | ||
| 1663 | 1664 | ||||
| 1664 | d.enterPicker(from, ac) | 1665 | d.enterPicker(from, ac) | ||
| 1665 | - | awaitFrame(t, sends, ports.MsgOutput) | 1666 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1666 | d.handleInput(from, ac, []byte("j")) | 1667 | d.handleInput(from, ac, []byte("j")) | ||
| 1667 | - | awaitFrame(t, sends, ports.MsgOutput) | 1668 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1668 | d.handleInput(from, ac, []byte("x")) | 1669 | d.handleInput(from, ac, []byte("x")) | ||
| 1669 | - | awaitFrame(t, sends, ports.MsgOutput) | 1670 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 1670 | 1671 | ||||
| 1671 | history := d.notices.history() | 1672 | history := d.notices.history() | ||
| 1672 | require.NotEmpty(t, history, "failed persisted-record delete must record a notice") | 1673 | require.NotEmpty(t, history, "failed persisted-record delete must record a notice") | ||
M internal/usecase/daemon/prompt_test.go +20 -19
| @@ -9,6 +9,7 @@ import ( | |||||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | "github.com/bnema/vev/internal/ports" | 11 | "github.com/bnema/vev/internal/ports" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | ) | 13 | ) | ||
| 13 | 14 | ||||
| 14 | type failingPTYFactory struct{ err error } | 15 | type failingPTYFactory struct{ err error } | ||
| @@ -29,8 +30,8 @@ func TestEnterPromptRendersTitleAndPrefill(t *testing.T) { | |||||
| 29 | defer release() | 30 | defer release() | ||
| 30 | 31 | ||||
| 31 | d.enterPrompt(sess, ac, " Rename session ", "0", func(string) error { return nil }) | 32 | d.enterPrompt(sess, ac, " Rename session ", "0", func(string) error { return nil }) | ||
| 32 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 33 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 33 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 34 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 34 | require.NoError(t, err) | 35 | require.NoError(t, err) | ||
| 35 | require.Contains(t, string(msg.Data), "Rename session") | 36 | require.Contains(t, string(msg.Data), "Rename session") | ||
| 36 | require.Contains(t, string(msg.Data), "> 0") | 37 | require.Contains(t, string(msg.Data), "> 0") | ||
| @@ -45,14 +46,14 @@ func TestPromptSubmitRenamesAndPromotesSession(t *testing.T) { | |||||
| 45 | sess.ephemeral = true | 46 | sess.ephemeral = true | ||
| 46 | 47 | ||||
| 47 | d.enterPrompt(sess, ac, " Rename session ", sess.name, func(name string) error { return d.renameSession(sess, name) }) | 48 | d.enterPrompt(sess, ac, " Rename session ", sess.name, func(name string) error { return d.renameSession(sess, name) }) | ||
| 48 | - | awaitFrame(t, sends, ports.MsgOutput) | 49 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 49 | d.handlePromptInput(ac, []byte("work\r")) | 50 | d.handlePromptInput(ac, []byte("work\r")) | ||
| 50 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | 51 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) |
| 51 | 52 | ||||
| 52 | require.False(t, ac.overlays.promptActive()) | 53 | require.False(t, ac.overlays.promptActive()) | ||
| 53 | require.Equal(t, "0work", sess.name) | 54 | require.Equal(t, "0work", sess.name) | ||
| 54 | require.False(t, sess.ephemeral) | 55 | require.False(t, sess.ephemeral) | ||
| 55 | - | out, err := ports.UnmarshalOutput(repaint.Payload) | 56 | + | out, err := wire.UnmarshalOutput(repaint.Payload) |
| 56 | require.NoError(t, err) | 57 | require.NoError(t, err) | ||
| 57 | require.Contains(t, string(out.Data), "0work") | 58 | require.Contains(t, string(out.Data), "0work") | ||
| 58 | require.NotContains(t, string(out.Data), "0work*") | 59 | require.NotContains(t, string(out.Data), "0work*") | ||
| @@ -69,13 +70,13 @@ func TestPromptSubmitErrorKeepsPromptOpen(t *testing.T) { | |||||
| 69 | d.sessions["other"] = &session{sessionCore: sessionCore{id: "other", name: "taken"}, ctx: ctx, cancel: cancel, tabs: []*tab{newTestTabWithContext(p2, ctx, cancel)}} | 70 | d.sessions["other"] = &session{sessionCore: sessionCore{id: "other", name: "taken"}, ctx: ctx, cancel: cancel, tabs: []*tab{newTestTabWithContext(p2, ctx, cancel)}} | ||
| 70 | 71 | ||||
| 71 | d.enterPrompt(sess, ac, " Rename session ", "", func(name string) error { return d.renameSession(sess, name) }) | 72 | d.enterPrompt(sess, ac, " Rename session ", "", func(name string) error { return d.renameSession(sess, name) }) | ||
| 72 | - | awaitFrame(t, sends, ports.MsgOutput) | 73 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 73 | d.handlePromptInput(ac, []byte("taken\r")) | 74 | d.handlePromptInput(ac, []byte("taken\r")) | ||
| 74 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | 75 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) |
| 75 | 76 | ||||
| 76 | require.True(t, ac.overlays.promptActive()) | 77 | require.True(t, ac.overlays.promptActive()) | ||
| 77 | require.NotEqual(t, "taken", sess.name) | 78 | require.NotEqual(t, "taken", sess.name) | ||
| 78 | - | out, err := ports.UnmarshalOutput(repaint.Payload) | 79 | + | out, err := wire.UnmarshalOutput(repaint.Payload) |
| 79 | require.NoError(t, err) | 80 | require.NoError(t, err) | ||
| 80 | require.Contains(t, string(out.Data), "name already in use") | 81 | require.Contains(t, string(out.Data), "name already in use") | ||
| 81 | } | 82 | } | ||
| @@ -92,10 +93,10 @@ func TestPromptSubmitSessionSpawnFailureReportsOneSafeNotice(t *testing.T) { | |||||
| 92 | d.enterPrompt(sess, ac, " Create session ", "", func(name string) error { | 93 | d.enterPrompt(sess, ac, " Create session ", "", func(name string) error { | ||
| 93 | return d.createSessionAndSwitch(sess, ac, name) | 94 | return d.createSessionAndSwitch(sess, ac, name) | ||
| 94 | }) | 95 | }) | ||
| 95 | - | awaitFrame(t, sends, ports.MsgOutput) | 96 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 96 | d.handlePromptInput(ac, []byte("new\r")) | 97 | d.handlePromptInput(ac, []byte("new\r")) | ||
| 97 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | 98 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) |
| 98 | - | output, err := ports.UnmarshalOutput(repaint.Payload) | 99 | + | output, err := wire.UnmarshalOutput(repaint.Payload) |
| 99 | require.NoError(t, err) | 100 | require.NoError(t, err) | ||
| 100 | require.Contains(t, string(output.Data), "couldn't create session: shell failed to start") | 101 | require.Contains(t, string(output.Data), "couldn't create session: shell failed to start") | ||
| 101 | 102 | ||||
| @@ -140,10 +141,10 @@ func TestPromptSubmitValidationErrorStaysInlineOnly(t *testing.T) { | |||||
| 140 | d.enterPrompt(sess, ac, " Create session ", "", func(name string) error { | 141 | d.enterPrompt(sess, ac, " Create session ", "", func(name string) error { | ||
| 141 | return d.createSessionAndSwitch(sess, ac, name) | 142 | return d.createSessionAndSwitch(sess, ac, name) | ||
| 142 | }) | 143 | }) | ||
| 143 | - | awaitFrame(t, sends, ports.MsgOutput) | 144 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 144 | d.handlePromptInput(ac, tt.input) | 145 | d.handlePromptInput(ac, tt.input) | ||
| 145 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | 146 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) |
| 146 | - | output, err := ports.UnmarshalOutput(repaint.Payload) | 147 | + | output, err := wire.UnmarshalOutput(repaint.Payload) |
| 147 | require.NoError(t, err) | 148 | require.NoError(t, err) | ||
| 148 | require.Contains(t, string(output.Data), tt.wantErr.Error()) | 149 | require.Contains(t, string(output.Data), tt.wantErr.Error()) | ||
| 149 | 150 | ||||
| @@ -160,9 +161,9 @@ func TestPromptEscapeCancelsWithoutRename(t *testing.T) { | |||||
| 160 | oldName := sess.name | 161 | oldName := sess.name | ||
| 161 | 162 | ||||
| 162 | d.enterPrompt(sess, ac, " Rename session ", oldName, func(name string) error { return d.renameSession(sess, name) }) | 163 | d.enterPrompt(sess, ac, " Rename session ", oldName, func(name string) error { return d.renameSession(sess, name) }) | ||
| 163 | - | awaitFrame(t, sends, ports.MsgOutput) | 164 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 164 | d.handlePromptInput(ac, []byte("new\x1b")) | 165 | d.handlePromptInput(ac, []byte("new\x1b")) | ||
| 165 | - | awaitFrame(t, sends, ports.MsgOutput) | 166 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 166 | 167 | ||||
| 167 | require.False(t, ac.overlays.promptActive()) | 168 | require.False(t, ac.overlays.promptActive()) | ||
| 168 | require.Equal(t, oldName, sess.name) | 169 | require.Equal(t, oldName, sess.name) | ||
| @@ -176,13 +177,13 @@ func TestPaletteRNSOpensRenamePrompt(t *testing.T) { | |||||
| 176 | sess.ephemeral = true | 177 | sess.ephemeral = true | ||
| 177 | 178 | ||||
| 178 | d.enterPalette(sess, ac) | 179 | d.enterPalette(sess, ac) | ||
| 179 | - | awaitFrame(t, sends, ports.MsgOutput) | 180 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 180 | d.handlePaletteInput(ac, []byte("RNS\r")) | 181 | d.handlePaletteInput(ac, []byte("RNS\r")) | ||
| 181 | - | out := awaitFrame(t, sends, ports.MsgOutput) | 182 | + | out := awaitFrame(t, sends, wire.MsgOutput) |
| 182 | 183 | ||||
| 183 | require.False(t, ac.overlays.paletteActive()) | 184 | require.False(t, ac.overlays.paletteActive()) | ||
| 184 | require.True(t, ac.overlays.promptActive()) | 185 | require.True(t, ac.overlays.promptActive()) | ||
| 185 | - | msg, err := ports.UnmarshalOutput(out.Payload) | 186 | + | msg, err := wire.UnmarshalOutput(out.Payload) |
| 186 | require.NoError(t, err) | 187 | require.NoError(t, err) | ||
| 187 | require.Contains(t, string(msg.Data), "Rename session") | 188 | require.Contains(t, string(msg.Data), "Rename session") | ||
| 188 | require.Contains(t, string(msg.Data), "> 0") | 189 | require.Contains(t, string(msg.Data), "> 0") | ||
M internal/usecase/daemon/recent_route_snapshot_test.go +6 -6
| @@ -4,8 +4,8 @@ import ( | |||||
| 4 | "testing" | 4 | "testing" | ||
| 5 | 5 | ||||
| 6 | "github.com/bnema/vev/internal/domain" | 6 | "github.com/bnema/vev/internal/domain" | ||
| 7 | - | "github.com/bnema/vev/internal/ports" | |||
| 8 | "github.com/bnema/vev/internal/protocol" | 7 | "github.com/bnema/vev/internal/protocol" | ||
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 9 | "github.com/stretchr/testify/require" | 9 | "github.com/stretchr/testify/require" | ||
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| @@ -69,11 +69,11 @@ func TestRecentRouteSnapshotRepaintsWithoutDeferredIdentity(t *testing.T) { | |||||
| 69 | ac.installTestAttachmentCapability(token) | 69 | ac.installTestAttachmentCapability(token) | ||
| 70 | ac.setRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 1}) | 70 | ac.setRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 1}) | ||
| 71 | 71 | ||||
| 72 | - | payload, err := ports.MarshalRecentRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 2}) | 72 | + | payload, err := wire.MarshalRecentRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 2}) |
| 73 | require.NoError(t, err) | 73 | require.NoError(t, err) | ||
| 74 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: payload})) | 74 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: payload})) |
| 75 | 75 | ||||
| 76 | - | awaitFrame(t, sends, ports.MsgOutput) | 76 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 77 | } | 77 | } | ||
| 78 | 78 | ||||
| 79 | func TestAttachmentRouteSnapshotCopiesPublishedEntries(t *testing.T) { | 79 | func TestAttachmentRouteSnapshotCopiesPublishedEntries(t *testing.T) { | ||
| @@ -115,11 +115,11 @@ func TestPaletteRecentRouteSelectionSendsTypedClientAction(t *testing.T) { | |||||
| 115 | var action protocol.RouteNavigationAction | 115 | var action protocol.RouteNavigationAction | ||
| 116 | found := false | 116 | found := false | ||
| 117 | for _, frame := range frames { | 117 | for _, frame := range frames { | ||
| 118 | - | if frame.Type != ports.MsgNavigateRecentRoute { | 118 | + | if frame.Type != wire.MsgNavigateRecentRoute { |
| 119 | continue | 119 | continue | ||
| 120 | } | 120 | } | ||
| 121 | var err error | 121 | var err error | ||
| 122 | - | action, err = ports.UnmarshalRouteNavigationAction(frame.Payload) | 122 | + | action, err = wire.UnmarshalRouteNavigationAction(frame.Payload) |
| 123 | require.NoError(t, err) | 123 | require.NoError(t, err) | ||
| 124 | found = true | 124 | found = true | ||
| 125 | } | 125 | } | ||
M internal/usecase/daemon/remote_attach.go +7 -6
| @@ -7,6 +7,7 @@ import ( | |||||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | "github.com/bnema/vev/internal/protocol" | 9 | "github.com/bnema/vev/internal/protocol" | ||
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 10 | ) | 11 | ) | ||
| 11 | 12 | ||||
| 12 | // routeRemoteTargetWithContext is the exact-target branch for picker handoffs. | 13 | // routeRemoteTargetWithContext is the exact-target branch for picker handoffs. | ||
| @@ -119,12 +120,12 @@ func (d *Daemon) sendNavigationActionForAttachment(effect *attachmentEffect, act | |||||
| 119 | effect.ac.clearParkedRoute() | 120 | effect.ac.clearParkedRoute() | ||
| 120 | } | 121 | } | ||
| 121 | } | 122 | } | ||
| 122 | - | payload := ports.MarshalNavigationDirective(directive) | 123 | + | payload := wire.MarshalNavigationDirective(directive) |
| 123 | if payload == nil { | 124 | if payload == nil { | ||
| 124 | rollback() | 125 | rollback() | ||
| 125 | return errAttachmentTransition | 126 | return errAttachmentTransition | ||
| 126 | } | 127 | } | ||
| 127 | - | if err := effect.sendControl(ports.Frame{Type: ports.MsgNavigationAction, Payload: payload}); err != nil { | 128 | + | if err := effect.sendControl(wire.Frame{Type: wire.MsgNavigationAction, Payload: payload}); err != nil { |
| 128 | rollback() | 129 | rollback() | ||
| 129 | return err | 130 | return err | ||
| 130 | } | 131 | } | ||
| @@ -132,11 +133,11 @@ func (d *Daemon) sendNavigationActionForAttachment(effect *attachmentEffect, act | |||||
| 132 | } | 133 | } | ||
| 133 | 134 | ||||
| 134 | func (d *Daemon) sendRecentRouteNavigationActionForAttachment(effect *attachmentEffect, action protocol.RouteNavigationAction) error { | 135 | func (d *Daemon) sendRecentRouteNavigationActionForAttachment(effect *attachmentEffect, action protocol.RouteNavigationAction) error { | ||
| 135 | - | payload, err := ports.MarshalRouteNavigationAction(action) | 136 | + | payload, err := wire.MarshalRouteNavigationAction(action) |
| 136 | if err != nil { | 137 | if err != nil { | ||
| 137 | return errAttachmentTransition | 138 | return errAttachmentTransition | ||
| 138 | } | 139 | } | ||
| 139 | - | return effect.sendControl(ports.Frame{Type: ports.MsgNavigateRecentRoute, Payload: payload}) | 140 | + | return effect.sendControl(wire.Frame{Type: wire.MsgNavigateRecentRoute, Payload: payload}) |
| 140 | } | 141 | } | ||
| 141 | 142 | ||||
| 142 | func (d *Daemon) sendCommittedRouteIdentityForAttachment(effect *attachmentEffect) error { | 143 | func (d *Daemon) sendCommittedRouteIdentityForAttachment(effect *attachmentEffect) error { | ||
| @@ -149,11 +150,11 @@ func (d *Daemon) sendCommittedRouteIdentityForAttachment(effect *attachmentEffec | |||||
| 149 | Ephemeral: effect.sess.ephemeral, | 150 | Ephemeral: effect.sess.ephemeral, | ||
| 150 | } | 151 | } | ||
| 151 | effect.sess.mu.Unlock() | 152 | effect.sess.mu.Unlock() | ||
| 152 | - | payload, err := ports.MarshalCommittedRouteIdentity(identity) | 153 | + | payload, err := wire.MarshalCommittedRouteIdentity(identity) |
| 153 | if err != nil { | 154 | if err != nil { | ||
| 154 | return errAttachmentTransition | 155 | return errAttachmentTransition | ||
| 155 | } | 156 | } | ||
| 156 | - | return effect.sendControl(ports.Frame{Type: ports.MsgCommittedRouteIdentity, Payload: payload}) | 157 | + | return effect.sendControl(wire.Frame{Type: wire.MsgCommittedRouteIdentity, Payload: payload}) |
| 157 | } | 158 | } | ||
| 158 | 159 | ||||
| 159 | func (d *Daemon) finishRouteAttach(sess *session, tr ports.Transport, sz domain.Size, h protocol.Hello, routeCreated, purge bool) (*attachedClient, error) { | 160 | func (d *Daemon) finishRouteAttach(sess *session, tr ports.Transport, sz domain.Size, h protocol.Hello, routeCreated, purge bool) (*attachedClient, error) { | ||
M internal/usecase/daemon/remote_attach_test.go +8 -7
| @@ -9,6 +9,7 @@ import ( | |||||
| 9 | "github.com/bnema/vev/internal/domain" | 9 | "github.com/bnema/vev/internal/domain" | ||
| 10 | "github.com/bnema/vev/internal/ports" | 10 | "github.com/bnema/vev/internal/ports" | ||
| 11 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | "github.com/bnema/vev/internal/usecase/picker" | 13 | "github.com/bnema/vev/internal/usecase/picker" | ||
| 13 | ) | 14 | ) | ||
| 14 | 15 | ||||
| @@ -30,7 +31,7 @@ func TestLocalPickerOfferCarriesExactLifecycle(t *testing.T) { | |||||
| 30 | 31 | ||||
| 31 | require.NoError(t, d.switchToTargetForAttachment(effect, picker.Target{Session: target.id}, sessionHandoffGuard{allowSamePeer: true}, "picker-select")) | 32 | require.NoError(t, d.switchToTargetForAttachment(effect, picker.Target{Session: target.id}, sessionHandoffGuard{allowSamePeer: true}, "picker-select")) | ||
| 32 | frame := receiveRemotePicker(t, sends, "local attach target") | 33 | frame := receiveRemotePicker(t, sends, "local attach target") | ||
| 33 | - | got, err := ports.UnmarshalAttachTarget(frame.Payload) | 34 | + | got, err := wire.UnmarshalAttachTarget(frame.Payload) |
| 34 | require.NoError(t, err) | 35 | require.NoError(t, err) | ||
| 35 | require.Empty(t, got.Endpoint) | 36 | require.Empty(t, got.Endpoint) | ||
| 36 | require.Equal(t, protocol.IntentAttach, got.Intent) | 37 | require.Equal(t, protocol.IntentAttach, got.Intent) | ||
| @@ -61,10 +62,10 @@ func TestStoppedLocalPickerHandoffWaitsForClientClose(t *testing.T) { | |||||
| 61 | }, sessionHandoffGuard{closePicker: true, allowSamePeer: true}, "picker-select")) | 62 | }, sessionHandoffGuard{closePicker: true, allowSamePeer: true}, "picker-select")) | ||
| 62 | 63 | ||||
| 63 | cleanup := receiveRemotePicker(t, sends, "graphics cleanup") | 64 | cleanup := receiveRemotePicker(t, sends, "graphics cleanup") | ||
| 64 | - | require.Equal(t, ports.MsgOutput, cleanup.Type) | 65 | + | require.Equal(t, wire.MsgOutput, cleanup.Type) |
| 65 | handoff := receiveRemotePicker(t, sends, "stopped local attach target") | 66 | handoff := receiveRemotePicker(t, sends, "stopped local attach target") | ||
| 66 | - | require.Equal(t, ports.MsgAttachTarget, handoff.Type) | 67 | + | require.Equal(t, wire.MsgAttachTarget, handoff.Type) |
| 67 | - | target, err := ports.UnmarshalAttachTarget(handoff.Payload) | 68 | + | target, err := wire.UnmarshalAttachTarget(handoff.Payload) |
| 68 | require.NoError(t, err) | 69 | require.NoError(t, err) | ||
| 69 | require.False(t, target.SamePeer) | 70 | require.False(t, target.SamePeer) | ||
| 70 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "stopped"}, target.ExactTarget) | 71 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "stopped"}, target.ExactTarget) | ||
| @@ -93,7 +94,7 @@ func TestRemotePickerRichHandoffCarriesLifecycleTabAndPolicy(t *testing.T) { | |||||
| 93 | target := picker.Target{Session: key.ID(), RemoteKey: &key, RemoteTarget: &remoteTarget, TabID: "tab-1"} | 94 | target := picker.Target{Session: key.ID(), RemoteKey: &key, RemoteTarget: &remoteTarget, TabID: "tab-1"} | ||
| 94 | require.NoError(t, d.sendRemoteAttachTargetForAttachment(effect, target, sessionHandoffGuard{closePicker: true}, "picker-select")) | 95 | require.NoError(t, d.sendRemoteAttachTargetForAttachment(effect, target, sessionHandoffGuard{closePicker: true}, "picker-select")) | ||
| 95 | frame := receiveRemotePicker(t, sends, "rich attach target") | 96 | frame := receiveRemotePicker(t, sends, "rich attach target") | ||
| 96 | - | got, err := ports.UnmarshalAttachTarget(frame.Payload) | 97 | + | got, err := wire.UnmarshalAttachTarget(frame.Payload) |
| 97 | require.NoError(t, err) | 98 | require.NoError(t, err) | ||
| 98 | require.NotNil(t, got.RemoteTarget) | 99 | require.NotNil(t, got.RemoteTarget) | ||
| 99 | require.Equal(t, remoteTarget, *got.RemoteTarget) | 100 | require.Equal(t, remoteTarget, *got.RemoteTarget) | ||
| @@ -140,7 +141,7 @@ func TestRemotePickerRichHandoffRejectsMismatchedRouteKey(t *testing.T) { | |||||
| 140 | for { | 141 | for { | ||
| 141 | select { | 142 | select { | ||
| 142 | case frame := <-sends: | 143 | case frame := <-sends: | ||
| 143 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type) | 144 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type) |
| 144 | default: | 145 | default: | ||
| 145 | return | 146 | return | ||
| 146 | } | 147 | } | ||
| @@ -174,7 +175,7 @@ func TestRemotePickerRichHandoffRejectsReplacedLifecycle(t *testing.T) { | |||||
| 174 | for { | 175 | for { | ||
| 175 | select { | 176 | select { | ||
| 176 | case frame := <-sends: | 177 | case frame := <-sends: | ||
| 177 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type, "rejected handoff must not send an attach target") | 178 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type, "rejected handoff must not send an attach target") |
| 178 | default: | 179 | default: | ||
| 179 | return | 180 | return | ||
| 180 | } | 181 | } | ||
M internal/usecase/daemon/remote_picker_test.go +9 -8
| @@ -18,6 +18,7 @@ import ( | |||||
| 18 | "github.com/bnema/vev/internal/ports" | 18 | "github.com/bnema/vev/internal/ports" | ||
| 19 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 19 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 20 | "github.com/bnema/vev/internal/protocol" | 20 | "github.com/bnema/vev/internal/protocol" | ||
| 21 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 21 | "github.com/bnema/vev/internal/usecase/picker" | 22 | "github.com/bnema/vev/internal/usecase/picker" | ||
| 22 | ) | 23 | ) | ||
| 23 | 24 | ||||
| @@ -696,8 +697,8 @@ func TestRemotePickerHandoffSendsTargetAndLeavesNoShadowSession(t *testing.T) { | |||||
| 696 | require.NoError(t, d.sendRemoteAttachTargetForAttachment(effect, target, sessionHandoffGuard{closePicker: true}, "picker-select")) | 697 | require.NoError(t, d.sendRemoteAttachTargetForAttachment(effect, target, sessionHandoffGuard{closePicker: true}, "picker-select")) | ||
| 697 | 698 | ||||
| 698 | frame := receiveRemotePicker(t, sends, "attach target") | 699 | frame := receiveRemotePicker(t, sends, "attach target") | ||
| 699 | - | require.Equal(t, ports.MsgAttachTarget, frame.Type) | 700 | + | require.Equal(t, wire.MsgAttachTarget, frame.Type) |
| 700 | - | got, err := ports.UnmarshalAttachTarget(frame.Payload) | 701 | + | got, err := wire.UnmarshalAttachTarget(frame.Payload) |
| 701 | require.NoError(t, err) | 702 | require.NoError(t, err) | ||
| 702 | require.Equal(t, protocol.AttachTarget{Endpoint: "arch", Session: "work", Intent: protocol.IntentAttach, RemoteTarget: &remoteTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned}, got) | 703 | require.Equal(t, protocol.AttachTarget{Endpoint: "arch", Session: "work", Intent: protocol.IntentAttach, RemoteTarget: &remoteTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned}, got) | ||
| 703 | require.Nil(t, ac.currentAttachmentSession()) | 704 | require.Nil(t, ac.currentAttachmentSession()) | ||
| @@ -748,7 +749,7 @@ func TestRemotePickerSelectsStoppedRemoteTabAndRestoresIt(t *testing.T) { | |||||
| 748 | require.NoError(t, local.sendRemoteAttachTargetForAttachment(effect, selected, sessionHandoffGuard{closePicker: true}, "picker-select")) | 749 | require.NoError(t, local.sendRemoteAttachTargetForAttachment(effect, selected, sessionHandoffGuard{closePicker: true}, "picker-select")) | ||
| 749 | 750 | ||||
| 750 | frame := receiveRemotePicker(t, sends, "stopped remote target") | 751 | frame := receiveRemotePicker(t, sends, "stopped remote target") | ||
| 751 | - | handoff, err := ports.UnmarshalAttachTarget(frame.Payload) | 752 | + | handoff, err := wire.UnmarshalAttachTarget(frame.Payload) |
| 752 | require.NoError(t, err) | 753 | require.NoError(t, err) | ||
| 753 | require.NotNil(t, handoff.RemoteTarget) | 754 | require.NotNil(t, handoff.RemoteTarget) | ||
| 754 | require.Equal(t, selected.RemoteTarget, handoff.RemoteTarget) | 755 | require.Equal(t, selected.RemoteTarget, handoff.RemoteTarget) | ||
| @@ -819,7 +820,7 @@ func TestRemotePickerResurrectsStoppedRemoteSessionWithoutTabMetadata(t *testing | |||||
| 819 | require.NoError(t, local.sendRemoteAttachTargetForAttachment(effect, selected, sessionHandoffGuard{closePicker: true}, "picker-select")) | 820 | require.NoError(t, local.sendRemoteAttachTargetForAttachment(effect, selected, sessionHandoffGuard{closePicker: true}, "picker-select")) | ||
| 820 | 821 | ||||
| 821 | frame := receiveRemotePicker(t, sends, "stopped remote target without tab metadata") | 822 | frame := receiveRemotePicker(t, sends, "stopped remote target without tab metadata") | ||
| 822 | - | handoff, err := ports.UnmarshalAttachTarget(frame.Payload) | 823 | + | handoff, err := wire.UnmarshalAttachTarget(frame.Payload) |
| 823 | require.NoError(t, err) | 824 | require.NoError(t, err) | ||
| 824 | require.Equal(t, selected.RemoteTarget, handoff.RemoteTarget) | 825 | require.Equal(t, selected.RemoteTarget, handoff.RemoteTarget) | ||
| 825 | 826 | ||||
| @@ -862,8 +863,8 @@ func TestNavigationActionHandoffSendsBoundedAction(t *testing.T) { | |||||
| 862 | defer effect.End() | 863 | defer effect.End() | ||
| 863 | require.NoError(t, d.sendNavigationActionForAttachment(effect, tt.action)) | 864 | require.NoError(t, d.sendNavigationActionForAttachment(effect, tt.action)) | ||
| 864 | frame := receiveRemotePicker(t, sends, "navigation action") | 865 | frame := receiveRemotePicker(t, sends, "navigation action") | ||
| 865 | - | require.Equal(t, ports.MsgNavigationAction, frame.Type) | 866 | + | require.Equal(t, wire.MsgNavigationAction, frame.Type) |
| 866 | - | directive, err := ports.UnmarshalNavigationDirective(frame.Payload) | 867 | + | directive, err := wire.UnmarshalNavigationDirective(frame.Payload) |
| 867 | require.NoError(t, err) | 868 | require.NoError(t, err) | ||
| 868 | require.Equal(t, tt.action, directive.Action) | 869 | require.Equal(t, tt.action, directive.Action) | ||
| 869 | if tt.action == protocol.NavigationOpenHomePicker { | 870 | if tt.action == protocol.NavigationOpenHomePicker { | ||
| @@ -920,10 +921,10 @@ func TestRemotePickerHandoffSendFailureKeepsPickerOpen(t *testing.T) { | |||||
| 920 | require.Same(t, sess, ac.currentAttachmentSession()) | 921 | require.Same(t, sess, ac.currentAttachmentSession()) | ||
| 921 | } | 922 | } | ||
| 922 | 923 | ||||
| 923 | - | func addRemoteRefreshPickerOwner(t *testing.T, d *Daemon, id domain.SessionID, transports ...ports.Transport) (*session, *attachedClient, chan ports.Frame) { | 924 | + | func addRemoteRefreshPickerOwner(t *testing.T, d *Daemon, id domain.SessionID, transports ...ports.Transport) (*session, *attachedClient, chan wire.Frame) { |
| 924 | t.Helper() | 925 | t.Helper() | ||
| 925 | var tr ports.Transport | 926 | var tr ports.Transport | ||
| 926 | - | var sends chan ports.Frame | 927 | + | var sends chan wire.Frame |
| 927 | if len(transports) != 0 { | 928 | if len(transports) != 0 { | ||
| 928 | tr = transports[0] | 929 | tr = transports[0] | ||
| 929 | } else { | 930 | } else { | ||
M internal/usecase/daemon/remote_preview.go +6 -5
| @@ -7,11 +7,12 @@ import ( | |||||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | "github.com/bnema/vev/internal/protocol" | 9 | "github.com/bnema/vev/internal/protocol" | ||
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 10 | ) | 11 | ) | ||
| 11 | 12 | ||||
| 12 | - | func (d *Daemon) handleRemotePreview(tr ports.Transport, frame ports.Frame) error { | 13 | + | func (d *Daemon) handleRemotePreview(tr ports.Transport, frame wire.Frame) error { |
| 13 | defer func() { _ = tr.Close() }() | 14 | defer func() { _ = tr.Close() }() | ||
| 14 | - | request, err := ports.UnmarshalRemotePreviewRequest(frame.Payload) | 15 | + | request, err := wire.UnmarshalRemotePreviewRequest(frame.Payload) |
| 15 | if err != nil { | 16 | if err != nil { | ||
| 16 | return d.sendRemotePreview(tr, protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewMalformed}) | 17 | return d.sendRemotePreview(tr, protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewMalformed}) | ||
| 17 | } | 18 | } | ||
| @@ -27,11 +28,11 @@ func (d *Daemon) handleRemotePreview(tr ports.Transport, frame ports.Frame) erro | |||||
| 27 | } | 28 | } | ||
| 28 | 29 | ||||
| 29 | func (d *Daemon) sendRemotePreview(tr ports.Transport, preview protocol.RemotePreview) error { | 30 | func (d *Daemon) sendRemotePreview(tr ports.Transport, preview protocol.RemotePreview) error { | ||
| 30 | - | payload := ports.MarshalRemotePreview(preview) | 31 | + | payload := wire.MarshalRemotePreview(preview) |
| 31 | if payload == nil { | 32 | if payload == nil { | ||
| 32 | - | payload = ports.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewMalformed}) | 33 | + | payload = wire.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewMalformed}) |
| 33 | } | 34 | } | ||
| 34 | - | return d.boundedControlSend(tr, ports.Frame{Type: ports.MsgRemotePreviewResponse, Payload: payload}) | 35 | + | return d.boundedControlSend(tr, wire.Frame{Type: wire.MsgRemotePreviewResponse, Payload: payload}) |
| 35 | } | 36 | } | ||
| 36 | 37 | ||||
| 37 | var errRemotePreviewNoSuchTarget = errors.New("daemon: remote preview target does not exist") | 38 | var errRemotePreviewNoSuchTarget = errors.New("daemon: remote preview target does not exist") | ||
M internal/usecase/daemon/render_coordinator_handshake_test.go +7 -7
| @@ -9,13 +9,13 @@ import ( | |||||
| 9 | "github.com/stretchr/testify/require" | 9 | "github.com/stretchr/testify/require" | ||
| 10 | 10 | ||||
| 11 | "github.com/bnema/vev/internal/domain" | 11 | "github.com/bnema/vev/internal/domain" | ||
| 12 | - | "github.com/bnema/vev/internal/ports" | 12 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | // fanoutBlockingTransport blocks only the first output send. The paired | 15 | // fanoutBlockingTransport blocks only the first output send. The paired | ||
| 16 | // healthy attachment must still receive its frame while this peer is stuck. | 16 | // healthy attachment must still receive its frame while this peer is stuck. | ||
| 17 | type fanoutBlockingTransport struct { | 17 | type fanoutBlockingTransport struct { | ||
| 18 | - | sent chan ports.Frame | 18 | + | sent chan wire.Frame |
| 19 | entered chan struct{} | 19 | entered chan struct{} | ||
| 20 | release chan struct{} | 20 | release chan struct{} | ||
| 21 | done chan struct{} | 21 | done chan struct{} | ||
| @@ -26,16 +26,16 @@ type fanoutBlockingTransport struct { | |||||
| 26 | 26 | ||||
| 27 | func newFanoutBlockingTransport() *fanoutBlockingTransport { | 27 | func newFanoutBlockingTransport() *fanoutBlockingTransport { | ||
| 28 | return &fanoutBlockingTransport{ | 28 | return &fanoutBlockingTransport{ | ||
| 29 | - | sent: make(chan ports.Frame, 8), | 29 | + | sent: make(chan wire.Frame, 8), |
| 30 | entered: make(chan struct{}), | 30 | entered: make(chan struct{}), | ||
| 31 | release: make(chan struct{}), | 31 | release: make(chan struct{}), | ||
| 32 | done: make(chan struct{}), | 32 | done: make(chan struct{}), | ||
| 33 | } | 33 | } | ||
| 34 | } | 34 | } | ||
| 35 | 35 | ||||
| 36 | - | func (t *fanoutBlockingTransport) Send(frame ports.Frame) error { | 36 | + | func (t *fanoutBlockingTransport) Send(frame wire.Frame) error { |
| 37 | t.sent <- frame | 37 | t.sent <- frame | ||
| 38 | - | if frame.Type == ports.MsgOutput { | 38 | + | if frame.Type == wire.MsgOutput { |
| 39 | t.enteredOne.Do(func() { close(t.entered) }) | 39 | t.enteredOne.Do(func() { close(t.entered) }) | ||
| 40 | <-t.release | 40 | <-t.release | ||
| 41 | } | 41 | } | ||
| @@ -43,7 +43,7 @@ func (t *fanoutBlockingTransport) Send(frame ports.Frame) error { | |||||
| 43 | return nil | 43 | return nil | ||
| 44 | } | 44 | } | ||
| 45 | 45 | ||||
| 46 | - | func (t *fanoutBlockingTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 46 | + | func (t *fanoutBlockingTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 47 | 47 | ||||
| 48 | func (t *fanoutBlockingTransport) Close() error { | 48 | func (t *fanoutBlockingTransport) Close() error { | ||
| 49 | t.releaseOne.Do(func() { close(t.release) }) | 49 | t.releaseOne.Do(func() { close(t.release) }) | ||
| @@ -102,7 +102,7 @@ func TestRenderCoordinatorFanoutDoesNotWaitForSlowTransport(t *testing.T) { | |||||
| 102 | 102 | ||||
| 103 | select { | 103 | select { | ||
| 104 | case frame := <-healthySends: | 104 | case frame := <-healthySends: | ||
| 105 | - | require.Equal(t, ports.MsgOutput, frame.Type, "healthy attachment did not receive output") | 105 | + | require.Equal(t, wire.MsgOutput, frame.Type, "healthy attachment did not receive output") |
| 106 | case <-time.After(2 * time.Second): | 106 | case <-time.After(2 * time.Second): | ||
| 107 | t.Fatal("healthy attachment remained blocked behind the slow transport") | 107 | t.Fatal("healthy attachment remained blocked behind the slow transport") | ||
| 108 | } | 108 | } | ||
M internal/usecase/daemon/render_coordinator_test.go +4 -3
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 17 | "github.com/bnema/vev/internal/protocol" | 17 | "github.com/bnema/vev/internal/protocol" | ||
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 18 | "github.com/bnema/vev/internal/usecase/keys" | 19 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 19 | "github.com/bnema/vev/internal/usecase/layout" | 20 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 20 | ) | 21 | ) | ||
| @@ -267,12 +268,12 @@ func awaitLatestCoordinatorTimer(t *testing.T, clk *coordinatorMockClock) *coord | |||||
| 267 | } | 268 | } | ||
| 268 | } | 269 | } | ||
| 269 | 270 | ||||
| 270 | - | func requireNoCoordinatorOutputFrame(t *testing.T, sends chan ports.Frame) { | 271 | + | func requireNoCoordinatorOutputFrame(t *testing.T, sends chan wire.Frame) { |
| 271 | t.Helper() | 272 | t.Helper() | ||
| 272 | for { | 273 | for { | ||
| 273 | select { | 274 | select { | ||
| 274 | case frame := <-sends: | 275 | case frame := <-sends: | ||
| 275 | - | if frame.Type == ports.MsgRoutePosition { | 276 | + | if frame.Type == wire.MsgRoutePosition { |
| 276 | continue | 277 | continue | ||
| 277 | } | 278 | } | ||
| 278 | t.Fatalf("unexpected output frame: %+v", frame) | 279 | t.Fatalf("unexpected output frame: %+v", frame) | ||
| @@ -1509,7 +1510,7 @@ func TestRenderCoordinatorSyncBatchSurvivesAttachmentLifecycle(t *testing.T) { | |||||
| 1509 | } | 1510 | } | ||
| 1510 | 1511 | ||||
| 1511 | func TestRenderCoordinatorResizeEpochDispatch(t *testing.T) { | 1512 | func TestRenderCoordinatorResizeEpochDispatch(t *testing.T) { | ||
| 1512 | - | newResizeFixture := func(t *testing.T) (*Daemon, *session, *attachedClient, chan ports.Frame, *coordinatorMockClock, chan renderInvalidation) { | 1513 | + | newResizeFixture := func(t *testing.T) (*Daemon, *session, *attachedClient, chan wire.Frame, *coordinatorMockClock, chan renderInvalidation) { |
| 1513 | t.Helper() | 1514 | t.Helper() | ||
| 1514 | p, releasePTY := newBlockingPTY(t) | 1515 | p, releasePTY := newBlockingPTY(t) | ||
| 1515 | t.Cleanup(releasePTY) | 1516 | t.Cleanup(releasePTY) | ||
M internal/usecase/daemon/render_damage_receipt_test.go +3 -2
| @@ -6,6 +6,7 @@ import ( | |||||
| 6 | renderer "github.com/bnema/vev-vt" | 6 | renderer "github.com/bnema/vev-vt" | ||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 9 | "github.com/bnema/vev/internal/usecase/layout" | 10 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 10 | "github.com/bnema/vev/internal/usecase/picker" | 11 | "github.com/bnema/vev/internal/usecase/picker" | ||
| 11 | "github.com/stretchr/testify/require" | 12 | "github.com/stretchr/testify/require" | ||
| @@ -156,7 +157,7 @@ func TestRenderDamageReceiptRetainsRealVTDamageAcrossFailedEmission(t *testing.T | |||||
| 156 | state, composed = captureComposeForReceiptTest(t, sess, ac) | 157 | state, composed = captureComposeForReceiptTest(t, sess, ac) | ||
| 157 | require.True(t, d.emitFrame(sess, ac, state, composed)) | 158 | require.True(t, d.emitFrame(sess, ac, state, composed)) | ||
| 158 | frame := <-sends | 159 | frame := <-sends | ||
| 159 | - | out, err := ports.UnmarshalOutput(frame.Payload) | 160 | + | out, err := wire.UnmarshalOutput(frame.Payload) |
| 160 | require.NoError(t, err) | 161 | require.NoError(t, err) | ||
| 161 | require.Contains(t, string(out.Data), "changed", "retry must emit the retained terminal bytes") | 162 | require.Contains(t, string(out.Data), "changed", "retry must emit the retained terminal bytes") | ||
| 162 | p.mu.Lock() | 163 | p.mu.Lock() | ||
| @@ -223,7 +224,7 @@ func TestPrepareFailureFallbackOnlySuppressesRecursiveNoticePaint(t *testing.T) | |||||
| 223 | require.True(t, d.emitFrame(sess, ac, state, composed)) | 224 | require.True(t, d.emitFrame(sess, ac, state, composed)) | ||
| 224 | require.Len(t, d.notices.history(), want) | 225 | require.Len(t, d.notices.history(), want) | ||
| 225 | frame := <-sends | 226 | frame := <-sends | ||
| 226 | - | require.Equal(t, ports.MsgOutput, frame.Type, "outer failure %d must repaint its notice", want) | 227 | + | require.Equal(t, wire.MsgOutput, frame.Type, "outer failure %d must repaint its notice", want) |
| 227 | require.False(t, ac.prepareFailureFallback.Load()) | 228 | require.False(t, ac.prepareFailureFallback.Load()) | ||
| 228 | } | 229 | } | ||
| 229 | } | 230 | } | ||
M internal/usecase/daemon/render_pipeline.go +3 -2
| @@ -7,6 +7,7 @@ import ( | |||||
| 7 | "github.com/bnema/vev/internal/domain" | 7 | "github.com/bnema/vev/internal/domain" | ||
| 8 | "github.com/bnema/vev/internal/ports" | 8 | "github.com/bnema/vev/internal/ports" | ||
| 9 | "github.com/bnema/vev/internal/protocol" | 9 | "github.com/bnema/vev/internal/protocol" | ||
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 10 | "github.com/bnema/vev/internal/usecase/layout" | 11 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 11 | "github.com/bnema/vev/internal/usecase/notices" | 12 | "github.com/bnema/vev/internal/usecase/notices" | ||
| 12 | "github.com/bnema/vev/internal/usecase/palette" | 13 | "github.com/bnema/vev/internal/usecase/palette" | ||
| @@ -539,7 +540,7 @@ func (d *Daemon) emitFrame(entry *session, ac *attachedClient, state *capturedRe | |||||
| 539 | } | 540 | } | ||
| 540 | 541 | ||||
| 541 | if position.ActiveTabID != "" && position != ac.output.lastRoutePosition { | 542 | if position.ActiveTabID != "" && position != ac.output.lastRoutePosition { | ||
| 542 | - | payload, positionMarshalErr := ports.MarshalRoutePosition(position) | 543 | + | payload, positionMarshalErr := wire.MarshalRoutePosition(position) |
| 543 | if positionMarshalErr != nil { | 544 | if positionMarshalErr != nil { | ||
| 544 | d.log.Error("marshal route position", "err", positionMarshalErr) | 545 | d.log.Error("marshal route position", "err", positionMarshalErr) | ||
| 545 | } else { | 546 | } else { | ||
| @@ -560,7 +561,7 @@ func (d *Daemon) emitFrame(entry *session, ac *attachedClient, state *capturedRe | |||||
| 560 | if async, ok := sendTr.(ports.AsyncTransport); ok { | 561 | if async, ok := sendTr.(ports.AsyncTransport); ok { | ||
| 561 | send = async.SendAsync | 562 | send = async.SendAsync | ||
| 562 | } | 563 | } | ||
| 563 | - | sendErr = send(ports.Frame{Type: ports.MsgRoutePosition, Payload: payload}) | 564 | + | sendErr = send(wire.Frame{Type: wire.MsgRoutePosition, Payload: payload}) |
| 564 | } | 565 | } | ||
| 565 | } | 566 | } | ||
| 566 | if marks.attachmentEffect != nil && interruptible { | 567 | if marks.attachmentEffect != nil && interruptible { | ||
M internal/usecase/daemon/render_pipeline_cache_test.go +5 -5
| @@ -8,7 +8,7 @@ import ( | |||||
| 8 | 8 | ||||
| 9 | renderer "github.com/bnema/vev-vt" | 9 | renderer "github.com/bnema/vev-vt" | ||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | - | "github.com/bnema/vev/internal/ports" | 11 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 12 | "github.com/bnema/vev/internal/usecase/layout" | 12 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 13 | themeui "github.com/bnema/vev/internal/usecase/theme" | 13 | themeui "github.com/bnema/vev/internal/usecase/theme" | ||
| 14 | "github.com/bnema/vev/internal/usecase/ui" | 14 | "github.com/bnema/vev/internal/usecase/ui" | ||
| @@ -17,9 +17,9 @@ import ( | |||||
| 17 | 17 | ||||
| 18 | type cacheFailTransport struct{} | 18 | type cacheFailTransport struct{} | ||
| 19 | 19 | ||||
| 20 | - | func (cacheFailTransport) Send(ports.Frame) error { return errors.New("send failed") } | 20 | + | func (cacheFailTransport) Send(wire.Frame) error { return errors.New("send failed") } |
| 21 | - | func (cacheFailTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 21 | + | func (cacheFailTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 22 | - | func (cacheFailTransport) Close() error { return nil } | 22 | + | func (cacheFailTransport) Close() error { return nil } |
| 23 | 23 | ||||
| 24 | func TestPipelineCachePublishesOnlyAfterEmission(t *testing.T) { | 24 | func TestPipelineCachePublishesOnlyAfterEmission(t *testing.T) { | ||
| 25 | for _, failure := range []struct { | 25 | for _, failure := range []struct { | ||
| @@ -69,7 +69,7 @@ func TestPipelineCachePublishesOnlyAfterEmission(t *testing.T) { | |||||
| 69 | require.True(t, d.emitFrame(sess, ac, &state, pending)) | 69 | require.True(t, d.emitFrame(sess, ac, &state, pending)) | ||
| 70 | require.Equal(t, pending.cache, ac.pipelineCache) | 70 | require.Equal(t, pending.cache, ac.pipelineCache) | ||
| 71 | frame := <-sends | 71 | frame := <-sends | ||
| 72 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 72 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 73 | require.NoError(t, err) | 73 | require.NoError(t, err) | ||
| 74 | require.Contains(t, string(output.Data), "next", "the retry must emit state retained after the failed emission") | 74 | require.Contains(t, string(output.Data), "next", "the retry must emit state retained after the failed emission") | ||
| 75 | }) | 75 | }) | ||
M internal/usecase/daemon/render_pipeline_test.go +10 -10
| @@ -14,7 +14,7 @@ import ( | |||||
| 14 | vt "github.com/bnema/vev-vt" | 14 | vt "github.com/bnema/vev-vt" | ||
| 15 | renderer "github.com/bnema/vev-vt/ansi" | 15 | renderer "github.com/bnema/vev-vt/ansi" | ||
| 16 | "github.com/bnema/vev/internal/domain" | 16 | "github.com/bnema/vev/internal/domain" | ||
| 17 | - | "github.com/bnema/vev/internal/ports" | 17 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 18 | "github.com/bnema/vev/internal/testutil/replaytest" | 18 | "github.com/bnema/vev/internal/testutil/replaytest" | ||
| 19 | scopy "github.com/bnema/vev/internal/usecase/copy" | 19 | scopy "github.com/bnema/vev/internal/usecase/copy" | ||
| 20 | "github.com/bnema/vev/internal/usecase/layout" | 20 | "github.com/bnema/vev/internal/usecase/layout" | ||
| @@ -32,11 +32,11 @@ import ( | |||||
| 32 | // assertions must not depend on any adapter's framing implementation. | 32 | // assertions must not depend on any adapter's framing implementation. | ||
| 33 | type scriptedReplayTransport struct { | 33 | type scriptedReplayTransport struct { | ||
| 34 | t *testing.T | 34 | t *testing.T | ||
| 35 | - | frames []ports.Frame | 35 | + | frames []wire.Frame |
| 36 | next int | 36 | next int | ||
| 37 | } | 37 | } | ||
| 38 | 38 | ||||
| 39 | - | func (s *scriptedReplayTransport) Send(got ports.Frame) error { | 39 | + | func (s *scriptedReplayTransport) Send(got wire.Frame) error { |
| 40 | s.t.Helper() | 40 | s.t.Helper() | ||
| 41 | if s.next >= len(s.frames) { | 41 | if s.next >= len(s.frames) { | ||
| 42 | s.t.Errorf("unexpected frame %#v", got) | 42 | s.t.Errorf("unexpected frame %#v", got) | ||
| @@ -48,8 +48,8 @@ func (s *scriptedReplayTransport) Send(got ports.Frame) error { | |||||
| 48 | require.Equal(s.t, want.Payload, got.Payload) | 48 | require.Equal(s.t, want.Payload, got.Payload) | ||
| 49 | return nil | 49 | return nil | ||
| 50 | } | 50 | } | ||
| 51 | - | func (*scriptedReplayTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | 51 | + | func (*scriptedReplayTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } |
| 52 | - | func (*scriptedReplayTransport) Close() error { return nil } | 52 | + | func (*scriptedReplayTransport) Close() error { return nil } |
| 53 | 53 | ||||
| 54 | func TestTransportReplayFinalShadowAndTerminalBytes(t *testing.T) { | 54 | func TestTransportReplayFinalShadowAndTerminalBytes(t *testing.T) { | ||
| 55 | frames := replaytest.Transcript() | 55 | frames := replaytest.Transcript() | ||
| @@ -57,7 +57,7 @@ func TestTransportReplayFinalShadowAndTerminalBytes(t *testing.T) { | |||||
| 57 | terminal := vt.NewScreen(8, 3) | 57 | terminal := vt.NewScreen(8, 3) | ||
| 58 | for _, frame := range frames { | 58 | for _, frame := range frames { | ||
| 59 | require.NoError(t, transport.Send(frame)) | 59 | require.NoError(t, transport.Send(frame)) | ||
| 60 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 60 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 61 | require.NoError(t, err) | 61 | require.NoError(t, err) | ||
| 62 | require.Equal(t, frame.Payload, mustMarshalOutput(output), "output payload must remain byte exact") | 62 | require.Equal(t, frame.Payload, mustMarshalOutput(output), "output payload must remain byte exact") | ||
| 63 | terminal.Write(output.Data) | 63 | terminal.Write(output.Data) | ||
| @@ -253,7 +253,7 @@ func TestEmitFrameFailedSendDoesNotPublishCursorOrOutputState(t *testing.T) { | |||||
| 253 | require.True(t, d.emitFrame(sess, ac, &state, composed)) | 253 | require.True(t, d.emitFrame(sess, ac, &state, composed)) | ||
| 254 | require.Equal(t, cursorOut{valid: true, row: 3, col: 4, style: 2, hasStyle: true}, ac.output.lastCursor) | 254 | require.Equal(t, cursorOut{valid: true, row: 3, col: 4, style: 2, hasStyle: true}, ac.output.lastCursor) | ||
| 255 | require.Equal(t, uint64(1), ac.output.next) | 255 | require.Equal(t, uint64(1), ac.output.next) | ||
| 256 | - | out, err := ports.UnmarshalOutput((<-sends).Payload) | 256 | + | out, err := wire.UnmarshalOutput((<-sends).Payload) |
| 257 | require.NoError(t, err) | 257 | require.NoError(t, err) | ||
| 258 | require.Zero(t, out.Base) | 258 | require.Zero(t, out.Base) | ||
| 259 | require.Equal(t, uint64(1), out.New) | 259 | require.Equal(t, uint64(1), out.New) | ||
| @@ -332,12 +332,12 @@ func TestComposeEmitExactReplayTiledFloatingBarsOverlayAndCursor(t *testing.T) { | |||||
| 332 | stream := newOutputStateStream() | 332 | stream := newOutputStateStream() | ||
| 333 | prepared, err := stream.prepareFrame(nil, &state, composed.frame, composed.damage, composed.reset, composed.cursor) | 333 | prepared, err := stream.prepareFrame(nil, &state, composed.frame, composed.damage, composed.reset, composed.cursor) | ||
| 334 | require.NoError(t, err) | 334 | require.NoError(t, err) | ||
| 335 | - | var outputFrame ports.Frame | 335 | + | var outputFrame wire.Frame |
| 336 | - | require.NoError(t, prepared.send(0, func(frame ports.Frame) error { | 336 | + | require.NoError(t, prepared.send(0, func(frame wire.Frame) error { |
| 337 | outputFrame = frame | 337 | outputFrame = frame | ||
| 338 | return nil | 338 | return nil | ||
| 339 | })) | 339 | })) | ||
| 340 | - | output, err := ports.UnmarshalOutput(outputFrame.Payload) | 340 | + | output, err := wire.UnmarshalOutput(outputFrame.Payload) |
| 341 | require.NoError(t, err) | 341 | require.NoError(t, err) | ||
| 342 | terminalBytes := output.Data | 342 | terminalBytes := output.Data | ||
| 343 | require.Equal(t, "\x1b[1;1H\x1b[0;7m tab \x1b[0m R\x1b[2;1HAAAAAAAAAAAA\x1b[3;1HBBB┌─fl─┐BBB\x1b[4;1H───Prompt───\x1b[5;1HPROMPT\x1b[K\x1b[B\x1b[2K\x1b[7;1H\x1b[0;7m sess \x1b[0m B\x1b[0m\x1b[?25l", string(terminalBytes)) | 343 | require.Equal(t, "\x1b[1;1H\x1b[0;7m tab \x1b[0m R\x1b[2;1HAAAAAAAAAAAA\x1b[3;1HBBB┌─fl─┐BBB\x1b[4;1H───Prompt───\x1b[5;1HPROMPT\x1b[K\x1b[B\x1b[2K\x1b[7;1H\x1b[0;7m sess \x1b[0m B\x1b[0m\x1b[?25l", string(terminalBytes)) | ||
M internal/usecase/daemon/render_test.go +26 -26
| @@ -19,9 +19,9 @@ import ( | |||||
| 19 | vt "github.com/bnema/vev-vt" | 19 | vt "github.com/bnema/vev-vt" | ||
| 20 | renderer "github.com/bnema/vev-vt/ansi" | 20 | renderer "github.com/bnema/vev-vt/ansi" | ||
| 21 | "github.com/bnema/vev/internal/domain" | 21 | "github.com/bnema/vev/internal/domain" | ||
| 22 | - | "github.com/bnema/vev/internal/ports" | |||
| 23 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 22 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 24 | "github.com/bnema/vev/internal/protocol" | 23 | "github.com/bnema/vev/internal/protocol" | ||
| 24 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 25 | scopy "github.com/bnema/vev/internal/usecase/copy" | 25 | scopy "github.com/bnema/vev/internal/usecase/copy" | ||
| 26 | "github.com/bnema/vev/internal/usecase/layout" | 26 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 27 | themeui "github.com/bnema/vev/internal/usecase/theme" | 27 | themeui "github.com/bnema/vev/internal/usecase/theme" | ||
| @@ -38,14 +38,14 @@ func TestPaletteBackdropDimsSimultaneousCopyMode(t *testing.T) { | |||||
| 38 | pane.screen.Write([]byte("\x1b[38;2;180;90;30mX")) | 38 | pane.screen.Write([]byte("\x1b[38;2;180;90;30mX")) | ||
| 39 | 39 | ||||
| 40 | d.enterCopyMode(sess, ac) | 40 | d.enterCopyMode(sess, ac) | ||
| 41 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 41 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 42 | undimmed := client.Frame.At(0, 1) | 42 | undimmed := client.Frame.At(0, 1) | ||
| 43 | require.Equal(t, 'X', undimmed.Rune, "fixture must address copy-mode pane content") | 43 | require.Equal(t, 'X', undimmed.Rune, "fixture must address copy-mode pane content") | ||
| 44 | copyBar := append([]renderer.Cell(nil), client.Frame.Row(client.Frame.Height-1)...) | 44 | copyBar := append([]renderer.Cell(nil), client.Frame.Row(client.Frame.Height-1)...) | ||
| 45 | require.Contains(t, rowText(copyBar), "[SCROLL]", "fixture must capture the copy status bar") | 45 | require.Contains(t, rowText(copyBar), "[SCROLL]", "fixture must capture the copy status bar") | ||
| 46 | 46 | ||||
| 47 | d.enterPalette(sess, ac) | 47 | d.enterPalette(sess, ac) | ||
| 48 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 48 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 49 | dimmed := client.Frame.At(0, 1) | 49 | dimmed := client.Frame.At(0, 1) | ||
| 50 | require.Equal(t, undimmed.Rune, dimmed.Rune, "palette backdrop must preserve copy content") | 50 | require.Equal(t, undimmed.Rune, dimmed.Rune, "palette backdrop must preserve copy content") | ||
| 51 | require.Equal(t, themeui.NewDimmer(theme).Dim(undimmed.Style), dimmed.Style, "palette backdrop must dim the composed copy frame") | 51 | require.Equal(t, themeui.NewDimmer(theme).Dim(undimmed.Style), dimmed.Style, "palette backdrop must dim the composed copy frame") | ||
| @@ -84,8 +84,8 @@ func TestFirstPaintRetainedFloatingPaneEmitsOneReset(t *testing.T) { | |||||
| 84 | 84 | ||||
| 85 | d.firstPaint(sess, ac) | 85 | d.firstPaint(sess, ac) | ||
| 86 | 86 | ||||
| 87 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | 87 | + | frame := awaitFrame(t, sends, wire.MsgOutput) |
| 88 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 88 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 89 | require.NoError(t, err) | 89 | require.NoError(t, err) | ||
| 90 | require.Zero(t, output.Base, "first paint must be a mandatory reset") | 90 | require.Zero(t, output.Base, "first paint must be a mandatory reset") | ||
| 91 | select { | 91 | select { | ||
| @@ -107,13 +107,13 @@ func TestPaletteBackdropDimsSimultaneousPicker(t *testing.T) { | |||||
| 107 | pane.screen.Write([]byte("X")) | 107 | pane.screen.Write([]byte("X")) | ||
| 108 | 108 | ||||
| 109 | d.enterPicker(sess, ac) | 109 | d.enterPicker(sess, ac) | ||
| 110 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 110 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 111 | pickerTitle := client.Frame.At(31, 2) | 111 | pickerTitle := client.Frame.At(31, 2) | ||
| 112 | require.Equal(t, 'S', pickerTitle.Rune, "fixture must address the picker title") | 112 | require.Equal(t, 'S', pickerTitle.Rune, "fixture must address the picker title") | ||
| 113 | undimmedPane := client.Frame.At(0, 1) | 113 | undimmedPane := client.Frame.At(0, 1) | ||
| 114 | 114 | ||||
| 115 | d.enterPalette(sess, ac) | 115 | d.enterPalette(sess, ac) | ||
| 116 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 116 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 117 | dimmedPickerTitle := pickerTitle | 117 | dimmedPickerTitle := pickerTitle | ||
| 118 | dimmedPickerTitle.Style = themeui.NewDimmer(backdropTheme()).Dim(pickerTitle.Style) | 118 | dimmedPickerTitle.Style = themeui.NewDimmer(backdropTheme()).Dim(pickerTitle.Style) | ||
| 119 | require.Equal(t, dimmedPickerTitle, client.Frame.At(31, 2), "the lower-priority picker must be part of the palette backdrop") | 119 | require.Equal(t, dimmedPickerTitle, client.Frame.At(31, 2), "the lower-priority picker must be part of the palette backdrop") | ||
| @@ -129,13 +129,13 @@ func TestPaletteBackdropProductionRenderAndDismissal(t *testing.T) { | |||||
| 129 | pane := sess.tabs[0].focusedPane() | 129 | pane := sess.tabs[0].focusedPane() | ||
| 130 | pane.screen.Write([]byte("X")) | 130 | pane.screen.Write([]byte("X")) | ||
| 131 | d.paint(sess, ac, true, nil) | 131 | d.paint(sess, ac, true, nil) | ||
| 132 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 132 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 133 | undimmed := client.Frame.At(0, 1) | 133 | undimmed := client.Frame.At(0, 1) | ||
| 134 | topBar := client.Frame.At(0, 0) | 134 | topBar := client.Frame.At(0, 0) | ||
| 135 | bottomBar := client.Frame.At(0, 24) | 135 | bottomBar := client.Frame.At(0, 24) | ||
| 136 | 136 | ||||
| 137 | d.handleInput(sess, ac, []byte("\x1b ")) | 137 | d.handleInput(sess, ac, []byte("\x1b ")) | ||
| 138 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 138 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 139 | dimmed := client.Frame.At(0, 1) | 139 | dimmed := client.Frame.At(0, 1) | ||
| 140 | require.Equal(t, 'X', dimmed.Rune) | 140 | require.Equal(t, 'X', dimmed.Rune) | ||
| 141 | require.Equal(t, themeui.NewDimmer(backdropTheme()).Dim(undimmed.Style), dimmed.Style, "open palette must use the theme dim style") | 141 | require.Equal(t, themeui.NewDimmer(backdropTheme()).Dim(undimmed.Style), dimmed.Style, "open palette must use the theme dim style") | ||
| @@ -147,7 +147,7 @@ func TestPaletteBackdropProductionRenderAndDismissal(t *testing.T) { | |||||
| 147 | require.Equal(t, dimmedBottomBar, client.Frame.At(0, 24), "bottom chrome is part of the complete backdrop") | 147 | require.Equal(t, dimmedBottomBar, client.Frame.At(0, 24), "bottom chrome is part of the complete backdrop") | ||
| 148 | 148 | ||||
| 149 | d.handleInput(sess, ac, []byte("\x1b")) | 149 | d.handleInput(sess, ac, []byte("\x1b")) | ||
| 150 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | 150 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) |
| 151 | require.Equal(t, undimmed, client.Frame.At(0, 1), "full redraw restores pane rune and style") | 151 | require.Equal(t, undimmed, client.Frame.At(0, 1), "full redraw restores pane rune and style") | ||
| 152 | require.Equal(t, topBar, client.Frame.At(0, 0)) | 152 | require.Equal(t, topBar, client.Frame.At(0, 0)) | ||
| 153 | require.Equal(t, bottomBar, client.Frame.At(0, 24)) | 153 | require.Equal(t, bottomBar, client.Frame.At(0, 24)) | ||
| @@ -189,10 +189,10 @@ func awaitPTYReadProcessed(t *testing.T, processed <-chan struct{}) { | |||||
| 189 | <-processed | 189 | <-processed | ||
| 190 | } | 190 | } | ||
| 191 | 191 | ||||
| 192 | - | func awaitOutputFrameWithoutSleep(t *testing.T, sends <-chan ports.Frame) ports.Frame { | 192 | + | func awaitOutputFrameWithoutSleep(t *testing.T, sends <-chan wire.Frame) wire.Frame { |
| 193 | t.Helper() | 193 | t.Helper() | ||
| 194 | frame := <-sends | 194 | frame := <-sends | ||
| 195 | - | require.Equal(t, ports.MsgOutput, frame.Type) | 195 | + | require.Equal(t, wire.MsgOutput, frame.Type) |
| 196 | return frame | 196 | return frame | ||
| 197 | } | 197 | } | ||
| 198 | 198 | ||||
| @@ -332,7 +332,7 @@ func TestPTYReaderSyncVisibilityTransitions(t *testing.T) { | |||||
| 332 | awaitPTYReadProcessed(t, inactiveProcessed) | 332 | awaitPTYReadProcessed(t, inactiveProcessed) | ||
| 333 | fireCoordinatorTimer(t, rc, drainCoordinatorTimers(clock), urgentRenderDeadline) | 333 | fireCoordinatorTimer(t, rc, drainCoordinatorTimers(clock), urgentRenderDeadline) | ||
| 334 | frame := awaitOutputFrameWithoutSleep(t, sends) | 334 | frame := awaitOutputFrameWithoutSleep(t, sends) | ||
| 335 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 335 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 336 | require.NoError(t, err) | 336 | require.NoError(t, err) | ||
| 337 | require.Contains(t, string(output.Data), "partial complete") | 337 | require.Contains(t, string(output.Data), "partial complete") | ||
| 338 | requireNoCoordinatorOutputFrame(t, sends) | 338 | requireNoCoordinatorOutputFrame(t, sends) | ||
| @@ -365,7 +365,7 @@ func TestPTYReaderSyncVisibilityTransitions(t *testing.T) { | |||||
| 365 | awaitPTYReadProcessed(t, newProcessed) | 365 | awaitPTYReadProcessed(t, newProcessed) | ||
| 366 | fireCoordinatorTimer(t, rc, drainCoordinatorTimers(clock), minOutputRenderDeadline) | 366 | fireCoordinatorTimer(t, rc, drainCoordinatorTimers(clock), minOutputRenderDeadline) | ||
| 367 | frame := awaitOutputFrameWithoutSleep(t, sends) | 367 | frame := awaitOutputFrameWithoutSleep(t, sends) | ||
| 368 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 368 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 369 | require.NoError(t, err) | 369 | require.NoError(t, err) | ||
| 370 | require.Contains(t, string(output.Data), "newly active") | 370 | require.Contains(t, string(output.Data), "newly active") | ||
| 371 | require.NotContains(t, string(output.Data), "old partial") | 371 | require.NotContains(t, string(output.Data), "old partial") | ||
| @@ -515,7 +515,7 @@ func TestPaneRenderableActiveAttachmentDoesNotScanPickerPreviews(t *testing.T) { | |||||
| 515 | } | 515 | } | ||
| 516 | 516 | ||||
| 517 | func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | 517 | func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | ||
| 518 | - | newFixture := func(t *testing.T) (*Daemon, *session, *tab, *pane, chan ports.Frame) { | 518 | + | newFixture := func(t *testing.T) (*Daemon, *session, *tab, *pane, chan wire.Frame) { |
| 519 | t.Helper() | 519 | t.Helper() | ||
| 520 | p, release := newBlockingPTY(t) | 520 | p, release := newBlockingPTY(t) | ||
| 521 | t.Cleanup(release) | 521 | t.Cleanup(release) | ||
| @@ -589,8 +589,8 @@ func TestAltXClosesFinalTabAndDetaches(t *testing.T) { | |||||
| 589 | d.handleInput(sess, ac, []byte("CLT\r")) | 589 | d.handleInput(sess, ac, []byte("CLT\r")) | ||
| 590 | 590 | ||||
| 591 | require.Equal(t, 0, sessionCount(d)) | 591 | require.Equal(t, 0, sessionCount(d)) | ||
| 592 | - | f := awaitFrame(t, sends, ports.MsgDetached) | 592 | + | f := awaitFrame(t, sends, wire.MsgDetached) |
| 593 | - | det, err := ports.UnmarshalDetached(f.Payload) | 593 | + | det, err := wire.UnmarshalDetached(f.Payload) |
| 594 | require.NoError(t, err) | 594 | require.NoError(t, err) | ||
| 595 | require.Equal(t, protocol.ReasonSessionKilled, det.Reason) | 595 | require.Equal(t, protocol.ReasonSessionKilled, det.Reason) | ||
| 596 | } | 596 | } | ||
| @@ -610,8 +610,8 @@ func TestPTYEOFClosesActiveNonFinalTabAndRepaintsRemaining(t *testing.T) { | |||||
| 610 | require.Eventually(t, func() bool { return tabCount(sess) == 1 }, 2*time.Second, 5*time.Millisecond) | 610 | require.Eventually(t, func() bool { return tabCount(sess) == 1 }, 2*time.Second, 5*time.Millisecond) | ||
| 611 | require.Equal(t, 1, sessionCount(d)) | 611 | require.Equal(t, 1, sessionCount(d)) | ||
| 612 | require.Equal(t, 0, testAttachmentTabIndex(sess)) | 612 | require.Equal(t, 0, testAttachmentTabIndex(sess)) | ||
| 613 | - | f := awaitFrame(t, sends, ports.MsgOutput) | 613 | + | f := awaitFrame(t, sends, wire.MsgOutput) |
| 614 | - | out, err := ports.UnmarshalOutput(f.Payload) | 614 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 615 | require.NoError(t, err) | 615 | require.NoError(t, err) | ||
| 616 | data := string(out.Data) | 616 | data := string(out.Data) | ||
| 617 | require.Contains(t, data, "remaining") | 617 | require.Contains(t, data, "remaining") | ||
| @@ -636,8 +636,8 @@ func TestPTYEOFClosesInactiveNonFinalTabAndRepaintsStatus(t *testing.T) { | |||||
| 636 | require.Eventually(t, func() bool { return tabCount(sess) == 1 }, 2*time.Second, 5*time.Millisecond) | 636 | require.Eventually(t, func() bool { return tabCount(sess) == 1 }, 2*time.Second, 5*time.Millisecond) | ||
| 637 | require.Equal(t, 1, sessionCount(d)) | 637 | require.Equal(t, 1, sessionCount(d)) | ||
| 638 | require.Equal(t, 0, testAttachmentTabIndex(sess)) | 638 | require.Equal(t, 0, testAttachmentTabIndex(sess)) | ||
| 639 | - | f := awaitFrame(t, sends, ports.MsgOutput) | 639 | + | f := awaitFrame(t, sends, wire.MsgOutput) |
| 640 | - | out, err := ports.UnmarshalOutput(f.Payload) | 640 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 641 | require.NoError(t, err) | 641 | require.NoError(t, err) | ||
| 642 | data := string(out.Data) | 642 | data := string(out.Data) | ||
| 643 | require.Contains(t, data, "active") | 643 | require.Contains(t, data, "active") | ||
| @@ -655,8 +655,8 @@ func TestPTYEOFFinalTabKillsSessionAndDetaches(t *testing.T) { | |||||
| 655 | releases[0]() | 655 | releases[0]() | ||
| 656 | 656 | ||||
| 657 | require.Eventually(t, func() bool { return sessionCount(d) == 0 }, 2*time.Second, 5*time.Millisecond) | 657 | require.Eventually(t, func() bool { return sessionCount(d) == 0 }, 2*time.Second, 5*time.Millisecond) | ||
| 658 | - | f := awaitFrame(t, sends, ports.MsgDetached) | 658 | + | f := awaitFrame(t, sends, wire.MsgDetached) |
| 659 | - | det, err := ports.UnmarshalDetached(f.Payload) | 659 | + | det, err := wire.UnmarshalDetached(f.Payload) |
| 660 | require.NoError(t, err) | 660 | require.NoError(t, err) | ||
| 661 | require.Equal(t, protocol.ReasonSessionKilled, det.Reason) | 661 | require.Equal(t, protocol.ReasonSessionKilled, det.Reason) | ||
| 662 | 662 | ||||
| @@ -933,8 +933,8 @@ func TestResizeOrdersPTYBeforeScreen(t *testing.T) { | |||||
| 933 | var gotOutput atomic.Bool | 933 | var gotOutput atomic.Bool | ||
| 934 | tr := portsmocks.NewMockTransport(t) | 934 | tr := portsmocks.NewMockTransport(t) | ||
| 935 | tr.EXPECT().Close().Return(nil).Maybe() | 935 | tr.EXPECT().Close().Return(nil).Maybe() | ||
| 936 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | 936 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { |
| 937 | - | if f.Type == ports.MsgOutput { | 937 | + | if f.Type == wire.MsgOutput { |
| 938 | gotOutput.Store(true) | 938 | gotOutput.Store(true) | ||
| 939 | } | 939 | } | ||
| 940 | return nil | 940 | return nil | ||
| @@ -1053,7 +1053,7 @@ func TestPTYKittyIcatDetectionGetsResponsesWrittenBackToPTY(t *testing.T) { | |||||
| 1053 | } | 1053 | } | ||
| 1054 | select { | 1054 | select { | ||
| 1055 | case f := <-sends: | 1055 | case f := <-sends: | ||
| 1056 | - | require.NotEqual(t, ports.MsgOutput, f.Type) | 1056 | + | require.NotEqual(t, wire.MsgOutput, f.Type) |
| 1057 | default: | 1057 | default: | ||
| 1058 | } | 1058 | } | ||
| 1059 | } | 1059 | } | ||
M internal/usecase/daemon/resume_test.go +24 -23
| @@ -16,23 +16,24 @@ import ( | |||||
| 16 | "github.com/bnema/vev/internal/ports" | 16 | "github.com/bnema/vev/internal/ports" | ||
| 17 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 17 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 18 | "github.com/bnema/vev/internal/protocol" | 18 | "github.com/bnema/vev/internal/protocol" | ||
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 19 | "github.com/bnema/vev/internal/usecase/layout" | 20 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 20 | ) | 21 | ) | ||
| 21 | 22 | ||||
| 22 | type closeTrackingTransport struct { | 23 | type closeTrackingTransport struct { | ||
| 23 | mu sync.Mutex | 24 | mu sync.Mutex | ||
| 24 | closed bool | 25 | closed bool | ||
| 25 | - | sends []ports.Frame | 26 | + | sends []wire.Frame |
| 26 | } | 27 | } | ||
| 27 | 28 | ||||
| 28 | - | func (t *closeTrackingTransport) Send(f ports.Frame) error { | 29 | + | func (t *closeTrackingTransport) Send(f wire.Frame) error { |
| 29 | t.mu.Lock() | 30 | t.mu.Lock() | ||
| 30 | defer t.mu.Unlock() | 31 | defer t.mu.Unlock() | ||
| 31 | t.sends = append(t.sends, f) | 32 | t.sends = append(t.sends, f) | ||
| 32 | return nil | 33 | return nil | ||
| 33 | } | 34 | } | ||
| 34 | - | func (t *closeTrackingTransport) Recv() (ports.Frame, error) { | 35 | + | func (t *closeTrackingTransport) Recv() (wire.Frame, error) { |
| 35 | - | return ports.Frame{}, errors.New("closed") | 36 | + | return wire.Frame{}, errors.New("closed") |
| 36 | } | 37 | } | ||
| 37 | func (t *closeTrackingTransport) Close() error { | 38 | func (t *closeTrackingTransport) Close() error { | ||
| 38 | t.mu.Lock() | 39 | t.mu.Lock() | ||
| @@ -46,10 +47,10 @@ func (t *closeTrackingTransport) Closed() bool { | |||||
| 46 | return t.closed | 47 | return t.closed | ||
| 47 | } | 48 | } | ||
| 48 | 49 | ||||
| 49 | - | func (t *closeTrackingTransport) Sends() []ports.Frame { | 50 | + | func (t *closeTrackingTransport) Sends() []wire.Frame { |
| 50 | t.mu.Lock() | 51 | t.mu.Lock() | ||
| 51 | defer t.mu.Unlock() | 52 | defer t.mu.Unlock() | ||
| 52 | - | return append([]ports.Frame(nil), t.sends...) | 53 | + | return append([]wire.Frame(nil), t.sends...) |
| 53 | } | 54 | } | ||
| 54 | 55 | ||||
| 55 | type closeCountingBlockedTransport struct { | 56 | type closeCountingBlockedTransport struct { | ||
| @@ -63,13 +64,13 @@ func newCloseCountingBlockedTransport() *closeCountingBlockedTransport { | |||||
| 63 | return &closeCountingBlockedTransport{closed: make(chan struct{})} | 64 | return &closeCountingBlockedTransport{closed: make(chan struct{})} | ||
| 64 | } | 65 | } | ||
| 65 | 66 | ||||
| 66 | - | func (t *closeCountingBlockedTransport) Send(ports.Frame) error { | 67 | + | func (t *closeCountingBlockedTransport) Send(wire.Frame) error { |
| 67 | <-t.closed | 68 | <-t.closed | ||
| 68 | return errors.New("closed") | 69 | return errors.New("closed") | ||
| 69 | } | 70 | } | ||
| 70 | 71 | ||||
| 71 | - | func (t *closeCountingBlockedTransport) Recv() (ports.Frame, error) { | 72 | + | func (t *closeCountingBlockedTransport) Recv() (wire.Frame, error) { |
| 72 | - | return ports.Frame{}, errors.New("closed") | 73 | + | return wire.Frame{}, errors.New("closed") |
| 73 | } | 74 | } | ||
| 74 | 75 | ||||
| 75 | func (t *closeCountingBlockedTransport) Close() error { | 76 | func (t *closeCountingBlockedTransport) Close() error { | ||
| @@ -326,14 +327,14 @@ func TestHandleHelloResumeDefersFreshOutputUntilWelcome(t *testing.T) { | |||||
| 326 | done := make(chan struct{}) | 327 | done := make(chan struct{}) | ||
| 327 | resumeHello := helloResumeCapable(protocol.IntentResume, sess.name, token) | 328 | resumeHello := helloResumeCapable(protocol.IntentResume, sess.name, token) | ||
| 328 | go func() { | 329 | go func() { | ||
| 329 | - | d.handleHello(tr.tr, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(resumeHello)}) | 330 | + | d.handleHello(tr.tr, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(resumeHello)}) |
| 330 | close(done) | 331 | close(done) | ||
| 331 | }() | 332 | }() | ||
| 332 | 333 | ||||
| 333 | <-tr.welcomeEntered | 334 | <-tr.welcomeEntered | ||
| 334 | handshakeTimer := awaitHandshakeTimer(t, clock) | 335 | handshakeTimer := awaitHandshakeTimer(t, clock) | ||
| 335 | welcome := <-tr.sends | 336 | welcome := <-tr.sends | ||
| 336 | - | require.Equal(t, ports.MsgWelcome, welcome.Type) | 337 | + | require.Equal(t, wire.MsgWelcome, welcome.Type) |
| 337 | sess.mu.Lock() | 338 | sess.mu.Lock() | ||
| 338 | resumed := sess.snapshotAttachmentsLocked()[0] | 339 | resumed := sess.snapshotAttachmentsLocked()[0] | ||
| 339 | sess.mu.Unlock() | 340 | sess.mu.Unlock() | ||
| @@ -351,8 +352,8 @@ func TestHandleHelloResumeDefersFreshOutputUntilWelcome(t *testing.T) { | |||||
| 351 | requireNoCoordinatorOutputFrame(t, tr.sends) | 352 | requireNoCoordinatorOutputFrame(t, tr.sends) | ||
| 352 | 353 | ||||
| 353 | tr.release() | 354 | tr.release() | ||
| 354 | - | output := awaitFrame(t, tr.sends, ports.MsgOutput) | 355 | + | output := awaitFrame(t, tr.sends, wire.MsgOutput) |
| 355 | - | first, err := ports.UnmarshalOutput(output.Payload) | 356 | + | first, err := wire.UnmarshalOutput(output.Payload) |
| 356 | require.NoError(t, err) | 357 | require.NoError(t, err) | ||
| 357 | require.Zero(t, first.Base) | 358 | require.Zero(t, first.Base) | ||
| 358 | tr.finish() | 359 | tr.finish() | ||
| @@ -1094,7 +1095,7 @@ func TestOutputAckLagAloneDoesNotForceFullStateRepaint(t *testing.T) { | |||||
| 1094 | 1095 | ||||
| 1095 | f := outputStateFrame(ac.output, []byte("incremental while reliable backlog drains"), reset, 0) | 1096 | f := outputStateFrame(ac.output, []byte("incremental while reliable backlog drains"), reset, 0) | ||
| 1096 | ac.sendMu.Unlock() | 1097 | ac.sendMu.Unlock() | ||
| 1097 | - | out, err := ports.UnmarshalOutput(f.Payload) | 1098 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 1098 | require.NoError(t, err) | 1099 | require.NoError(t, err) | ||
| 1099 | require.Equal(t, uint64(5), out.Base, "output should remain incremental unless an explicit reset is requested") | 1100 | require.Equal(t, uint64(5), out.Base, "output should remain incremental unless an explicit reset is requested") | ||
| 1100 | require.Equal(t, uint64(6), out.New) | 1101 | require.Equal(t, uint64(6), out.New) | ||
| @@ -1104,7 +1105,7 @@ func TestOutputAckLagAloneDoesNotForceFullStateRepaint(t *testing.T) { | |||||
| 1104 | require.True(t, reset, "explicit reset should still force full repaint") | 1105 | require.True(t, reset, "explicit reset should still force full repaint") | ||
| 1105 | full := outputStateFrame(ac.output, []byte("explicit full repaint"), reset, 0) | 1106 | full := outputStateFrame(ac.output, []byte("explicit full repaint"), reset, 0) | ||
| 1106 | ac.sendMu.Unlock() | 1107 | ac.sendMu.Unlock() | ||
| 1107 | - | fullOut, err := ports.UnmarshalOutput(full.Payload) | 1108 | + | fullOut, err := wire.UnmarshalOutput(full.Payload) |
| 1108 | require.NoError(t, err) | 1109 | require.NoError(t, err) | ||
| 1109 | require.Equal(t, uint64(0), fullOut.Base) | 1110 | require.Equal(t, uint64(0), fullOut.Base) | ||
| 1110 | require.Equal(t, uint64(7), fullOut.New) | 1111 | require.Equal(t, uint64(7), fullOut.New) | ||
| @@ -1185,9 +1186,9 @@ func TestResumeRebasesFullOutputWindowBeforeFirstPaint(t *testing.T) { | |||||
| 1185 | require.Same(t, ac, resumedAC) | 1186 | require.Same(t, ac, resumedAC) | ||
| 1186 | d.paint(resumedSess, resumedAC, true, nil) | 1187 | d.paint(resumedSess, resumedAC, true, nil) | ||
| 1187 | 1188 | ||||
| 1188 | - | sends := testFramesOfType(newTr.Sends(), ports.MsgOutput) | 1189 | + | sends := testFramesOfType(newTr.Sends(), wire.MsgOutput) |
| 1189 | require.Len(t, sends, 1) | 1190 | require.Len(t, sends, 1) | ||
| 1190 | - | first, err := ports.UnmarshalOutput(sends[0].Payload) | 1191 | + | first, err := wire.UnmarshalOutput(sends[0].Payload) |
| 1191 | require.NoError(t, err) | 1192 | require.NoError(t, err) | ||
| 1192 | require.Zero(t, first.Base) | 1193 | require.Zero(t, first.Base) | ||
| 1193 | require.Equal(t, uint64(1), first.New) | 1194 | require.Equal(t, uint64(1), first.New) | ||
| @@ -1195,9 +1196,9 @@ func TestResumeRebasesFullOutputWindowBeforeFirstPaint(t *testing.T) { | |||||
| 1195 | 1196 | ||||
| 1196 | resumedSess.tabs[0].focusedPane().screen.Write([]byte("A")) | 1197 | resumedSess.tabs[0].focusedPane().screen.Write([]byte("A")) | ||
| 1197 | d.paint(resumedSess, resumedAC, false, nil) | 1198 | d.paint(resumedSess, resumedAC, false, nil) | ||
| 1198 | - | sends = testFramesOfType(newTr.Sends(), ports.MsgOutput) | 1199 | + | sends = testFramesOfType(newTr.Sends(), wire.MsgOutput) |
| 1199 | require.Len(t, sends, 2) | 1200 | require.Len(t, sends, 2) | ||
| 1200 | - | second, err := ports.UnmarshalOutput(sends[1].Payload) | 1201 | + | second, err := wire.UnmarshalOutput(sends[1].Payload) |
| 1201 | require.NoError(t, err) | 1202 | require.NoError(t, err) | ||
| 1202 | require.Equal(t, first.New, second.Base) | 1203 | require.Equal(t, first.New, second.Base) | ||
| 1203 | } | 1204 | } | ||
| @@ -1245,9 +1246,9 @@ func TestParkingReleasesPaneCapturesBeforeHeadlessCloseAndResume(t *testing.T) { | |||||
| 1245 | require.True(t, resumedSess.renderCoordinator().markAttachmentReady(resumedSess.renderCoordinator().attachmentLease(resumedAC))) | 1246 | require.True(t, resumedSess.renderCoordinator().markAttachmentReady(resumedSess.renderCoordinator().attachmentLease(resumedAC))) | ||
| 1246 | d.firstPaint(resumedSess, resumedAC) | 1247 | d.firstPaint(resumedSess, resumedAC) | ||
| 1247 | 1248 | ||||
| 1248 | - | sends := testFramesOfType(newTransport.Sends(), ports.MsgOutput) | 1249 | + | sends := testFramesOfType(newTransport.Sends(), wire.MsgOutput) |
| 1249 | require.Len(t, sends, 1) | 1250 | require.Len(t, sends, 1) | ||
| 1250 | - | output, err := ports.UnmarshalOutput(sends[0].Payload) | 1251 | + | output, err := wire.UnmarshalOutput(sends[0].Payload) |
| 1251 | require.NoError(t, err) | 1252 | require.NoError(t, err) | ||
| 1252 | require.Zero(t, output.Base, "resume must start with a complete frame") | 1253 | require.Zero(t, output.Base, "resume must start with a complete frame") | ||
| 1253 | terminal := vt.NewScreen(resumedAC.size.Cols, resumedAC.size.Rows) | 1254 | terminal := vt.NewScreen(resumedAC.size.Cols, resumedAC.size.Rows) | ||
| @@ -1543,9 +1544,9 @@ func TestRawTerminalSideEffectsAreOutputStateNeutral(t *testing.T) { | |||||
| 1543 | 1544 | ||||
| 1544 | sends := tr.Sends() | 1545 | sends := tr.Sends() | ||
| 1545 | require.Len(t, sends, 2) | 1546 | require.Len(t, sends, 2) | ||
| 1546 | - | first, err := ports.UnmarshalOutput(sends[0].Payload) | 1547 | + | first, err := wire.UnmarshalOutput(sends[0].Payload) |
| 1547 | require.NoError(t, err) | 1548 | require.NoError(t, err) | ||
| 1548 | - | second, err := ports.UnmarshalOutput(sends[1].Payload) | 1549 | + | second, err := wire.UnmarshalOutput(sends[1].Payload) |
| 1549 | require.NoError(t, err) | 1550 | require.NoError(t, err) | ||
| 1550 | require.Zero(t, first.Base) | 1551 | require.Zero(t, first.Base) | ||
| 1551 | require.Zero(t, first.New) | 1552 | require.Zero(t, first.New) | ||
M internal/usecase/daemon/route_position_test.go +3 -3
| @@ -7,8 +7,8 @@ import ( | |||||
| 7 | "github.com/stretchr/testify/require" | 7 | "github.com/stretchr/testify/require" | ||
| 8 | 8 | ||||
| 9 | "github.com/bnema/vev/internal/domain" | 9 | "github.com/bnema/vev/internal/domain" | ||
| 10 | - | "github.com/bnema/vev/internal/ports" | |||
| 11 | "github.com/bnema/vev/internal/protocol" | 10 | "github.com/bnema/vev/internal/protocol" | ||
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | ) | 12 | ) | ||
| 13 | 13 | ||||
| 14 | func TestRouteAppliesPreferredTabPerAttachment(t *testing.T) { | 14 | func TestRouteAppliesPreferredTabPerAttachment(t *testing.T) { | ||
| @@ -96,10 +96,10 @@ func TestPaintPublishesChangedAttachmentRoutePosition(t *testing.T) { | |||||
| 96 | 96 | ||||
| 97 | var positions []protocol.RoutePosition | 97 | var positions []protocol.RoutePosition | ||
| 98 | for _, frame := range tr.Sends() { | 98 | for _, frame := range tr.Sends() { | ||
| 99 | - | if frame.Type != ports.MsgRoutePosition { | 99 | + | if frame.Type != wire.MsgRoutePosition { |
| 100 | continue | 100 | continue | ||
| 101 | } | 101 | } | ||
| 102 | - | position, err := ports.UnmarshalRoutePosition(frame.Payload) | 102 | + | position, err := wire.UnmarshalRoutePosition(frame.Payload) |
| 103 | require.NoError(t, err) | 103 | require.NoError(t, err) | ||
| 104 | positions = append(positions, position) | 104 | positions = append(positions, position) | ||
| 105 | } | 105 | } | ||
M internal/usecase/daemon/same_peer_switch.go +3 -3
| @@ -2,8 +2,8 @@ package daemon | |||||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "github.com/bnema/vev/internal/domain" | 4 | "github.com/bnema/vev/internal/domain" | ||
| 5 | - | "github.com/bnema/vev/internal/ports" | |||
| 6 | "github.com/bnema/vev/internal/protocol" | 5 | "github.com/bnema/vev/internal/protocol" | ||
| 6 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 7 | ) | 7 | ) | ||
| 8 | 8 | ||||
| 9 | func (ac *attachedClient) offerSamePeerTarget(target protocol.ExactSessionTarget) { | 9 | func (ac *attachedClient) offerSamePeerTarget(target protocol.ExactSessionTarget) { | ||
| @@ -122,11 +122,11 @@ func (d *Daemon) sendSamePeerSwitchFailure(effect *attachmentEffect, requestID u | |||||
| 122 | } | 122 | } | ||
| 123 | defer sender.End() | 123 | defer sender.End() | ||
| 124 | } | 124 | } | ||
| 125 | - | payload, err := ports.MarshalSamePeerSwitchFailure(protocol.SamePeerSwitchFailure{RequestID: requestID, Code: code}) | 125 | + | payload, err := wire.MarshalSamePeerSwitchFailure(protocol.SamePeerSwitchFailure{RequestID: requestID, Code: code}) |
| 126 | if err != nil { | 126 | if err != nil { | ||
| 127 | return | 127 | return | ||
| 128 | } | 128 | } | ||
| 129 | - | if err := sender.sendControl(ports.Frame{Type: ports.MsgSamePeerSwitchFailure, Payload: payload}); err != nil { | 129 | + | if err := sender.sendControl(wire.Frame{Type: wire.MsgSamePeerSwitchFailure, Payload: payload}); err != nil { |
| 130 | d.detachOnAttachmentSendError(sender.capability(), sender.transport.transport) | 130 | d.detachOnAttachmentSendError(sender.capability(), sender.transport.transport) | ||
| 131 | } | 131 | } | ||
| 132 | } | 132 | } | ||
M internal/usecase/daemon/same_peer_switch_test.go +10 -10
| @@ -6,8 +6,8 @@ import ( | |||||
| 6 | "github.com/stretchr/testify/require" | 6 | "github.com/stretchr/testify/require" | ||
| 7 | 7 | ||||
| 8 | "github.com/bnema/vev/internal/domain" | 8 | "github.com/bnema/vev/internal/domain" | ||
| 9 | - | "github.com/bnema/vev/internal/ports" | |||
| 10 | "github.com/bnema/vev/internal/protocol" | 9 | "github.com/bnema/vev/internal/protocol" | ||
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 11 | ) | 11 | ) | ||
| 12 | 12 | ||||
| 13 | func TestPaletteSessionSelectionCompletesSamePeerSwitch(t *testing.T) { | 13 | func TestPaletteSessionSelectionCompletesSamePeerSwitch(t *testing.T) { | ||
| @@ -31,10 +31,10 @@ func TestPaletteSessionSelectionCompletesSamePeerSwitch(t *testing.T) { | |||||
| 31 | 31 | ||||
| 32 | token := beginRecentRoutePaletteEffect(t, d, source, ac) | 32 | token := beginRecentRoutePaletteEffect(t, d, source, ac) | ||
| 33 | d.handleInputForAttachment(token, []byte("\x1b ")) | 33 | d.handleInputForAttachment(token, []byte("\x1b ")) | ||
| 34 | - | awaitFrame(t, sends, ports.MsgOutput) | 34 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 35 | d.handleInputForAttachment(token, []byte("target\r")) | 35 | d.handleInputForAttachment(token, []byte("target\r")) | ||
| 36 | - | targetFrame := awaitFrame(t, sends, ports.MsgAttachTarget) | 36 | + | targetFrame := awaitFrame(t, sends, wire.MsgAttachTarget) |
| 37 | - | attachTarget, err := ports.UnmarshalAttachTarget(targetFrame.Payload) | 37 | + | attachTarget, err := wire.UnmarshalAttachTarget(targetFrame.Payload) |
| 38 | require.NoError(t, err) | 38 | require.NoError(t, err) | ||
| 39 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "target"}, attachTarget.ExactTarget) | 39 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "target"}, attachTarget.ExactTarget) | ||
| 40 | 40 | ||||
| @@ -43,8 +43,8 @@ func TestPaletteSessionSelectionCompletesSamePeerSwitch(t *testing.T) { | |||||
| 43 | }) | 43 | }) | ||
| 44 | 44 | ||||
| 45 | require.Same(t, target, ac.currentAttachmentSession()) | 45 | require.Same(t, target, ac.currentAttachmentSession()) | ||
| 46 | - | identityFrame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | 46 | + | identityFrame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) |
| 47 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(identityFrame.Payload) | 47 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(identityFrame.Payload) |
| 48 | require.NoError(t, err) | 48 | require.NoError(t, err) | ||
| 49 | require.Equal(t, attachTarget.ExactTarget, &identity.Target) | 49 | require.Equal(t, attachTarget.ExactTarget, &identity.Target) | ||
| 50 | } | 50 | } | ||
| @@ -86,8 +86,8 @@ func TestSamePeerSwitchTransitionsExactTargetAndPreferredTab(t *testing.T) { | |||||
| 86 | 86 | ||||
| 87 | require.Same(t, target, ac.currentAttachmentSession()) | 87 | require.Same(t, target, ac.currentAttachmentSession()) | ||
| 88 | require.Equal(t, domain.TabStableID(target.tabs[1].stableID), ac.viewSnapshot().tabID) | 88 | require.Equal(t, domain.TabStableID(target.tabs[1].stableID), ac.viewSnapshot().tabID) | ||
| 89 | - | identityFrame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | 89 | + | identityFrame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) |
| 90 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(identityFrame.Payload) | 90 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(identityFrame.Payload) |
| 91 | require.NoError(t, err) | 91 | require.NoError(t, err) | ||
| 92 | require.Equal(t, protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "target"}, identity.Target) | 92 | require.Equal(t, protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "target"}, identity.Target) | ||
| 93 | } | 93 | } | ||
| @@ -120,8 +120,8 @@ func TestSamePeerSwitchRejectsStaleTargetWithoutMutation(t *testing.T) { | |||||
| 120 | }) | 120 | }) | ||
| 121 | 121 | ||||
| 122 | require.Same(t, source, ac.currentAttachmentSession()) | 122 | require.Same(t, source, ac.currentAttachmentSession()) | ||
| 123 | - | failureFrame := awaitFrame(t, sends, ports.MsgSamePeerSwitchFailure) | 123 | + | failureFrame := awaitFrame(t, sends, wire.MsgSamePeerSwitchFailure) |
| 124 | - | failure, err := ports.UnmarshalSamePeerSwitchFailure(failureFrame.Payload) | 124 | + | failure, err := wire.UnmarshalSamePeerSwitchFailure(failureFrame.Payload) |
| 125 | require.NoError(t, err) | 125 | require.NoError(t, err) | ||
| 126 | require.Equal(t, protocol.SamePeerSwitchFailure{RequestID: 1, Code: protocol.SamePeerSwitchStaleTarget}, failure) | 126 | require.Equal(t, protocol.SamePeerSwitchFailure{RequestID: 1, Code: protocol.SamePeerSwitchStaleTarget}, failure) | ||
| 127 | } | 127 | } | ||
M internal/usecase/daemon/session_back_route_test.go +3 -3
| @@ -3,8 +3,8 @@ package daemon | |||||
| 3 | import ( | 3 | import ( | ||
| 4 | "testing" | 4 | "testing" | ||
| 5 | 5 | ||||
| 6 | - | "github.com/bnema/vev/internal/ports" | |||
| 7 | "github.com/bnema/vev/internal/protocol" | 6 | "github.com/bnema/vev/internal/protocol" | ||
| 7 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 8 | "github.com/stretchr/testify/require" | 8 | "github.com/stretchr/testify/require" | ||
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| @@ -32,11 +32,11 @@ func TestBackSessionUsesClientPreviousRouteAfterSnapshotPublication(t *testing.T | |||||
| 32 | var action protocol.RouteNavigationAction | 32 | var action protocol.RouteNavigationAction | ||
| 33 | found := false | 33 | found := false | ||
| 34 | for _, frame := range frames { | 34 | for _, frame := range frames { | ||
| 35 | - | if frame.Type != ports.MsgNavigateRecentRoute { | 35 | + | if frame.Type != wire.MsgNavigateRecentRoute { |
| 36 | continue | 36 | continue | ||
| 37 | } | 37 | } | ||
| 38 | var err error | 38 | var err error | ||
| 39 | - | action, err = ports.UnmarshalRouteNavigationAction(frame.Payload) | 39 | + | action, err = wire.UnmarshalRouteNavigationAction(frame.Payload) |
| 40 | require.NoError(t, err) | 40 | require.NoError(t, err) | ||
| 41 | found = true | 41 | found = true | ||
| 42 | } | 42 | } | ||
M internal/usecase/daemon/session_rename_purge_test.go +7 -7
| @@ -6,9 +6,9 @@ import ( | |||||
| 6 | "github.com/stretchr/testify/require" | 6 | "github.com/stretchr/testify/require" | ||
| 7 | 7 | ||||
| 8 | "github.com/bnema/vev/internal/domain" | 8 | "github.com/bnema/vev/internal/domain" | ||
| 9 | - | "github.com/bnema/vev/internal/ports" | |||
| 10 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 9 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 11 | "github.com/bnema/vev/internal/protocol" | 10 | "github.com/bnema/vev/internal/protocol" | ||
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | ) | 12 | ) | ||
| 13 | 13 | ||||
| 14 | func TestRenamePublishesCommittedRouteIdentityToAttachedClients(t *testing.T) { | 14 | func TestRenamePublishesCommittedRouteIdentityToAttachedClients(t *testing.T) { | ||
| @@ -24,8 +24,8 @@ func TestRenamePublishesCommittedRouteIdentityToAttachedClients(t *testing.T) { | |||||
| 24 | 24 | ||||
| 25 | require.NoError(t, d.renameSession(sess, "vps-infra")) | 25 | require.NoError(t, d.renameSession(sess, "vps-infra")) | ||
| 26 | 26 | ||||
| 27 | - | frame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | 27 | + | frame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) |
| 28 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(frame.Payload) | 28 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(frame.Payload) |
| 29 | require.NoError(t, err) | 29 | require.NoError(t, err) | ||
| 30 | require.Equal(t, protocol.ExactSessionTarget{ | 30 | require.Equal(t, protocol.ExactSessionTarget{ | ||
| 31 | LifecycleID: domain.IncarnationID{1}, | 31 | LifecycleID: domain.IncarnationID{1}, | ||
| @@ -54,12 +54,12 @@ func TestRenameDefersCommittedRouteIdentityUntilFirstRouteSnapshot(t *testing.T) | |||||
| 54 | ActiveEntry: protocol.RecentRouteEntry{Key: 1, Generation: 1, Target: testRouteTarget("0", 1), Name: "0", Kind: protocol.RouteKindLocal}, | 54 | ActiveEntry: protocol.RecentRouteEntry{Key: 1, Generation: 1, Target: testRouteTarget("0", 1), Name: "0", Kind: protocol.RouteKindLocal}, | ||
| 55 | Home: activeRef, | 55 | Home: activeRef, | ||
| 56 | } | 56 | } | ||
| 57 | - | payload, err := ports.MarshalRecentRouteSnapshot(snapshot) | 57 | + | payload, err := wire.MarshalRecentRouteSnapshot(snapshot) |
| 58 | require.NoError(t, err) | 58 | require.NoError(t, err) | ||
| 59 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: payload})) | 59 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: payload})) |
| 60 | 60 | ||||
| 61 | - | frame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | 61 | + | frame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) |
| 62 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(frame.Payload) | 62 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(frame.Payload) |
| 63 | require.NoError(t, err) | 63 | require.NoError(t, err) | ||
| 64 | require.Equal(t, protocol.ExactSessionTarget{ | 64 | require.Equal(t, protocol.ExactSessionTarget{ | ||
| 65 | LifecycleID: domain.IncarnationID{1}, | 65 | LifecycleID: domain.IncarnationID{1}, | ||
M internal/usecase/daemon/session_test.go +46 -45
| @@ -20,6 +20,7 @@ import ( | |||||
| 20 | "github.com/bnema/vev/internal/ports" | 20 | "github.com/bnema/vev/internal/ports" | ||
| 21 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 21 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 22 | "github.com/bnema/vev/internal/protocol" | 22 | "github.com/bnema/vev/internal/protocol" | ||
| 23 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 23 | "github.com/bnema/vev/internal/usecase/picker" | 24 | "github.com/bnema/vev/internal/usecase/picker" | ||
| 24 | themeui "github.com/bnema/vev/internal/usecase/theme" | 25 | themeui "github.com/bnema/vev/internal/usecase/theme" | ||
| 25 | ) | 26 | ) | ||
| @@ -42,12 +43,12 @@ func TestHandshakeEphemeralHappy(t *testing.T) { | |||||
| 42 | var hg sync.WaitGroup | 43 | var hg sync.WaitGroup | ||
| 43 | hg.Go(func() { d.handleConn(tr) }) | 44 | hg.Go(func() { d.handleConn(tr) }) | ||
| 44 | 45 | ||||
| 45 | - | w := awaitFrame(t, sends, ports.MsgWelcome) | 46 | + | w := awaitFrame(t, sends, wire.MsgWelcome) |
| 46 | - | welcome, err := ports.UnmarshalWelcome(w.Payload) | 47 | + | welcome, err := wire.UnmarshalWelcome(w.Payload) |
| 47 | require.NoError(t, err) | 48 | require.NoError(t, err) | ||
| 48 | require.Equal(t, "0", welcome.SessionName) | 49 | require.Equal(t, "0", welcome.SessionName) | ||
| 49 | require.True(t, welcome.Ephemeral) | 50 | require.True(t, welcome.Ephemeral) | ||
| 50 | - | awaitFrame(t, sends, ports.MsgOutput) // guaranteed first paint | 51 | + | awaitFrame(t, sends, wire.MsgOutput) // guaranteed first paint |
| 51 | require.Equal(t, 1, sessionCount(d)) | 52 | require.Equal(t, 1, sessionCount(d)) | ||
| 52 | 53 | ||||
| 53 | releaseConn() | 54 | releaseConn() | ||
| @@ -64,8 +65,8 @@ func TestHandshakeNewHappy(t *testing.T) { | |||||
| 64 | var hg sync.WaitGroup | 65 | var hg sync.WaitGroup | ||
| 65 | hg.Go(func() { d.handleConn(tr) }) | 66 | hg.Go(func() { d.handleConn(tr) }) | ||
| 66 | 67 | ||||
| 67 | - | w := awaitFrame(t, sends, ports.MsgWelcome) | 68 | + | w := awaitFrame(t, sends, wire.MsgWelcome) |
| 68 | - | welcome, err := ports.UnmarshalWelcome(w.Payload) | 69 | + | welcome, err := wire.UnmarshalWelcome(w.Payload) |
| 69 | require.NoError(t, err) | 70 | require.NoError(t, err) | ||
| 70 | require.Equal(t, "work", welcome.SessionName) | 71 | require.Equal(t, "work", welcome.SessionName) | ||
| 71 | require.False(t, welcome.Ephemeral) | 72 | require.False(t, welcome.Ephemeral) | ||
| @@ -84,15 +85,15 @@ func TestHandshakeNewHappy(t *testing.T) { | |||||
| 84 | func TestHandshakeVersionMismatch(t *testing.T) { | 85 | func TestHandshakeVersionMismatch(t *testing.T) { | ||
| 85 | // No Open expectation: the factory must never be asked to spawn a PTY. | 86 | // No Open expectation: the factory must never be asked to spawn a PTY. | ||
| 86 | d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{}) | 87 | d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{}) | ||
| 87 | - | bad := ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | 88 | + | bad := wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ |
| 88 | Version: protocol.Version + 99, Intent: protocol.IntentEphemeral, Size: domain.Size{Cols: 80, Rows: 24}, | 89 | Version: protocol.Version + 99, Intent: protocol.IntentEphemeral, Size: domain.Size{Cols: 80, Rows: 24}, | ||
| 89 | })} | 90 | })} | ||
| 90 | tr, sends, _ := newConn(t, bad) | 91 | tr, sends, _ := newConn(t, bad) | ||
| 91 | 92 | ||||
| 92 | d.handleConn(tr) // returns after the rejection; no session, no goroutines | 93 | d.handleConn(tr) // returns after the rejection; no session, no goroutines | ||
| 93 | 94 | ||||
| 94 | - | e := awaitFrame(t, sends, ports.MsgError) | 95 | + | e := awaitFrame(t, sends, wire.MsgError) |
| 95 | - | em, err := ports.UnmarshalErrorMsg(e.Payload) | 96 | + | em, err := wire.UnmarshalErrorMsg(e.Payload) |
| 96 | require.NoError(t, err) | 97 | require.NoError(t, err) | ||
| 97 | require.Equal(t, protocol.ErrVersionMismatch, em.Code) | 98 | require.Equal(t, protocol.ErrVersionMismatch, em.Code) | ||
| 98 | require.Equal(t, 0, sessionCount(d)) | 99 | require.Equal(t, 0, sessionCount(d)) | ||
| @@ -108,11 +109,11 @@ func TestHandshakeOldHelloLayoutReportsVersionMismatch(t *testing.T) { | |||||
| 108 | 0x00, 0x18, | 109 | 0x00, 0x18, | ||
| 109 | 0x00, 0x00, | 110 | 0x00, 0x00, | ||
| 110 | } | 111 | } | ||
| 111 | - | tr, sends, _ := newConn(t, ports.Frame{Type: ports.MsgHello, Payload: oldLayout}) | 112 | + | tr, sends, _ := newConn(t, wire.Frame{Type: wire.MsgHello, Payload: oldLayout}) |
| 112 | d.handleConn(tr) | 113 | d.handleConn(tr) | ||
| 113 | 114 | ||||
| 114 | - | e := awaitFrame(t, sends, ports.MsgError) | 115 | + | e := awaitFrame(t, sends, wire.MsgError) |
| 115 | - | em, err := ports.UnmarshalErrorMsg(e.Payload) | 116 | + | em, err := wire.UnmarshalErrorMsg(e.Payload) |
| 116 | require.NoError(t, err) | 117 | require.NoError(t, err) | ||
| 117 | require.Equal(t, protocol.ErrVersionMismatch, em.Code) | 118 | require.Equal(t, protocol.ErrVersionMismatch, em.Code) | ||
| 118 | require.Equal(t, 0, sessionCount(d)) | 119 | require.Equal(t, 0, sessionCount(d)) | ||
| @@ -126,8 +127,8 @@ func TestHandshakeNameTaken(t *testing.T) { | |||||
| 126 | tr, sends, _ := newConn(t, mustHello(protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24})) | 127 | tr, sends, _ := newConn(t, mustHello(protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24})) | ||
| 127 | d.handleConn(tr) | 128 | d.handleConn(tr) | ||
| 128 | 129 | ||||
| 129 | - | e := awaitFrame(t, sends, ports.MsgError) | 130 | + | e := awaitFrame(t, sends, wire.MsgError) |
| 130 | - | em, _ := ports.UnmarshalErrorMsg(e.Payload) | 131 | + | em, _ := wire.UnmarshalErrorMsg(e.Payload) |
| 131 | require.Equal(t, protocol.ErrNameTaken, em.Code) | 132 | require.Equal(t, protocol.ErrNameTaken, em.Code) | ||
| 132 | } | 133 | } | ||
| 133 | 134 | ||||
| @@ -136,14 +137,14 @@ func TestHandshakeNoSuchSession(t *testing.T) { | |||||
| 136 | tr, sends, _ := newConn(t, mustHello(protocol.IntentAttach, "ghost", domain.Size{Cols: 80, Rows: 24})) | 137 | tr, sends, _ := newConn(t, mustHello(protocol.IntentAttach, "ghost", domain.Size{Cols: 80, Rows: 24})) | ||
| 137 | d.handleConn(tr) | 138 | d.handleConn(tr) | ||
| 138 | 139 | ||||
| 139 | - | e := awaitFrame(t, sends, ports.MsgError) | 140 | + | e := awaitFrame(t, sends, wire.MsgError) |
| 140 | - | em, _ := ports.UnmarshalErrorMsg(e.Payload) | 141 | + | em, _ := wire.UnmarshalErrorMsg(e.Payload) |
| 141 | require.Equal(t, protocol.ErrNoSuchSession, em.Code) | 142 | require.Equal(t, protocol.ErrNoSuchSession, em.Code) | ||
| 142 | } | 143 | } | ||
| 143 | 144 | ||||
| 144 | func TestKillAllEmptyDaemonSignalsShutdown(t *testing.T) { | 145 | func TestKillAllEmptyDaemonSignalsShutdown(t *testing.T) { | ||
| 145 | d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{}) | 146 | d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{}) | ||
| 146 | - | tr, _, _ := newConn(t, ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})}) | 147 | + | tr, _, _ := newConn(t, wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})}) |
| 147 | d.handleConn(tr) | 148 | d.handleConn(tr) | ||
| 148 | 149 | ||||
| 149 | select { | 150 | select { | ||
| @@ -232,8 +233,8 @@ func TestCreateTabClosesPTYIfSessionKilledDuringOpen(t *testing.T) { | |||||
| 232 | tr, sends, releaseConn := newConn(t, mustHello(protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24})) | 233 | tr, sends, releaseConn := newConn(t, mustHello(protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24})) | ||
| 233 | var hg sync.WaitGroup | 234 | var hg sync.WaitGroup | ||
| 234 | hg.Go(func() { d.handleConn(tr) }) | 235 | hg.Go(func() { d.handleConn(tr) }) | ||
| 235 | - | awaitFrame(t, sends, ports.MsgWelcome) | 236 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 236 | - | awaitFrame(t, sends, ports.MsgOutput) | 237 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 237 | sess := firstSession(d) | 238 | sess := firstSession(d) | ||
| 238 | require.NotNil(t, sess) | 239 | require.NotNil(t, sess) | ||
| 239 | 240 | ||||
| @@ -289,13 +290,13 @@ func TestDetachKeepsEphemeralHeadless(t *testing.T) { | |||||
| 289 | d := newTestDaemon(t, newFactory(t, p), stubClock{}) | 290 | d := newTestDaemon(t, newFactory(t, p), stubClock{}) | ||
| 290 | tr, sends, _ := newConn(t, | 291 | tr, sends, _ := newConn(t, | ||
| 291 | mustHello(protocol.IntentEphemeral, "", domain.Size{Cols: 80, Rows: 24}), | 292 | mustHello(protocol.IntentEphemeral, "", domain.Size{Cols: 80, Rows: 24}), | ||
| 292 | - | ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}, | 293 | + | wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}, |
| 293 | ) | 294 | ) | ||
| 294 | 295 | ||||
| 295 | var hg sync.WaitGroup | 296 | var hg sync.WaitGroup | ||
| 296 | hg.Go(func() { d.handleConn(tr) }) | 297 | hg.Go(func() { d.handleConn(tr) }) | ||
| 297 | - | awaitFrame(t, sends, ports.MsgWelcome) | 298 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 298 | - | awaitFrame(t, sends, ports.MsgDetached) | 299 | + | awaitFrame(t, sends, wire.MsgDetached) |
| 299 | hg.Wait() | 300 | hg.Wait() | ||
| 300 | 301 | ||||
| 301 | require.Equal(t, 1, sessionCount(d), "ephemeral session survives explicit detach") | 302 | require.Equal(t, 1, sessionCount(d), "ephemeral session survives explicit detach") | ||
| @@ -338,14 +339,14 @@ func TestDetachKeepsNamed(t *testing.T) { | |||||
| 338 | d := newTestDaemon(t, newFactory(t, p), stubClock{}) | 339 | d := newTestDaemon(t, newFactory(t, p), stubClock{}) | ||
| 339 | tr, sends, _ := newConn(t, | 340 | tr, sends, _ := newConn(t, | ||
| 340 | mustHello(protocol.IntentNew, "keep", domain.Size{Cols: 80, Rows: 24}), | 341 | mustHello(protocol.IntentNew, "keep", domain.Size{Cols: 80, Rows: 24}), | ||
| 341 | - | ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}, | 342 | + | wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}, |
| 342 | ) | 343 | ) | ||
| 343 | 344 | ||||
| 344 | var hg sync.WaitGroup | 345 | var hg sync.WaitGroup | ||
| 345 | hg.Go(func() { d.handleConn(tr) }) | 346 | hg.Go(func() { d.handleConn(tr) }) | ||
| 346 | - | awaitFrame(t, sends, ports.MsgWelcome) | 347 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 347 | - | awaitFrame(t, sends, ports.MsgDetached) // ack for explicit detach | 348 | + | awaitFrame(t, sends, wire.MsgDetached) // ack for explicit detach |
| 348 | - | hg.Wait() // handler returns after detach | 349 | + | hg.Wait() // handler returns after detach |
| 349 | 350 | ||||
| 350 | require.Equal(t, 1, sessionCount(d), "named session survives detach") | 351 | require.Equal(t, 1, sessionCount(d), "named session survives detach") | ||
| 351 | sess := firstSession(d) | 352 | sess := firstSession(d) | ||
| @@ -375,8 +376,8 @@ func TestReaderEOFRemovesSessionAndSignalsShutdown(t *testing.T) { | |||||
| 375 | hg.Go(func() { d.handleConn(tr) }) | 376 | hg.Go(func() { d.handleConn(tr) }) | ||
| 376 | 377 | ||||
| 377 | // The client is detached with ReasonSessionKilled when the child exits. | 378 | // The client is detached with ReasonSessionKilled when the child exits. | ||
| 378 | - | det := awaitFrame(t, sends, ports.MsgDetached) | 379 | + | det := awaitFrame(t, sends, wire.MsgDetached) |
| 379 | - | dm, _ := ports.UnmarshalDetached(det.Payload) | 380 | + | dm, _ := wire.UnmarshalDetached(det.Payload) |
| 380 | require.Equal(t, protocol.ReasonSessionKilled, dm.Reason) | 381 | require.Equal(t, protocol.ReasonSessionKilled, dm.Reason) | ||
| 381 | 382 | ||||
| 382 | select { | 383 | select { | ||
| @@ -418,8 +419,8 @@ func TestServeReturnsWhenLastSessionExits(t *testing.T) { | |||||
| 418 | served := make(chan error, 1) | 419 | served := make(chan error, 1) | ||
| 419 | go func() { served <- d.Serve(context.Background(), l) }() | 420 | go func() { served <- d.Serve(context.Background(), l) }() | ||
| 420 | 421 | ||||
| 421 | - | awaitFrame(t, sends, ports.MsgWelcome) | 422 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 422 | - | awaitFrame(t, sends, ports.MsgOutput) | 423 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 423 | 424 | ||||
| 424 | // Child exits -> session removed -> registry empties -> Serve returns. | 425 | // Child exits -> session removed -> registry empties -> Serve returns. | ||
| 425 | releasePTY() | 426 | releasePTY() | ||
| @@ -459,13 +460,13 @@ func TestServeGracefulShutdownOnContextCancel(t *testing.T) { | |||||
| 459 | served := make(chan error, 1) | 460 | served := make(chan error, 1) | ||
| 460 | go func() { served <- d.Serve(ctx, l) }() | 461 | go func() { served <- d.Serve(ctx, l) }() | ||
| 461 | 462 | ||||
| 462 | - | awaitFrame(t, sends, ports.MsgWelcome) | 463 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 463 | - | awaitFrame(t, sends, ports.MsgOutput) | 464 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 464 | 465 | ||||
| 465 | cancel() // graceful shutdown | 466 | cancel() // graceful shutdown | ||
| 466 | 467 | ||||
| 467 | - | det := awaitFrame(t, sends, ports.MsgDetached) | 468 | + | det := awaitFrame(t, sends, wire.MsgDetached) |
| 468 | - | dm, _ := ports.UnmarshalDetached(det.Payload) | 469 | + | dm, _ := wire.UnmarshalDetached(det.Payload) |
| 469 | require.Equal(t, protocol.ReasonServerShutdown, dm.Reason) | 470 | require.Equal(t, protocol.ReasonServerShutdown, dm.Reason) | ||
| 470 | 471 | ||||
| 471 | select { | 472 | select { | ||
| @@ -515,11 +516,11 @@ func TestHelloRacingShutdownIsRejected(t *testing.T) { | |||||
| 515 | tr1, sends1, release1 := newConn(t, mustHello(protocol.IntentEphemeral, "", domain.Size{Cols: 80, Rows: 24})) | 516 | tr1, sends1, release1 := newConn(t, mustHello(protocol.IntentEphemeral, "", domain.Size{Cols: 80, Rows: 24})) | ||
| 516 | var hg sync.WaitGroup | 517 | var hg sync.WaitGroup | ||
| 517 | hg.Go(func() { d.handleConn(tr1) }) | 518 | hg.Go(func() { d.handleConn(tr1) }) | ||
| 518 | - | awaitFrame(t, sends1, ports.MsgWelcome) | 519 | + | awaitFrame(t, sends1, wire.MsgWelcome) |
| 519 | // firstPaint starts the background prewarm asynchronously. It is valid for | 520 | // firstPaint starts the background prewarm asynchronously. It is valid for | ||
| 520 | // this Open to occur before shutdown, so do not mistake it for the racing | 521 | // this Open to occur before shutdown, so do not mistake it for the racing | ||
| 521 | // Hello's forbidden launch. | 522 | // Hello's forbidden launch. | ||
| 522 | - | awaitFrame(t, sends1, ports.MsgOutput) | 523 | + | awaitFrame(t, sends1, wire.MsgOutput) |
| 523 | select { | 524 | select { | ||
| 524 | case <-preShutdownFloatingOpen: | 525 | case <-preShutdownFloatingOpen: | ||
| 525 | case <-time.After(time.Second): | 526 | case <-time.After(time.Second): | ||
| @@ -548,8 +549,8 @@ func TestHelloRacingShutdownIsRejected(t *testing.T) { | |||||
| 548 | } { | 549 | } { | ||
| 549 | tr2, sends2, _ := newConn(t, mustHello(intent.intent, intent.sess, domain.Size{Cols: 80, Rows: 24})) | 550 | tr2, sends2, _ := newConn(t, mustHello(intent.intent, intent.sess, domain.Size{Cols: 80, Rows: 24})) | ||
| 550 | d.handleConn(tr2) | 551 | d.handleConn(tr2) | ||
| 551 | - | e := awaitFrame(t, sends2, ports.MsgError) | 552 | + | e := awaitFrame(t, sends2, wire.MsgError) |
| 552 | - | em, err := ports.UnmarshalErrorMsg(e.Payload) | 553 | + | em, err := wire.UnmarshalErrorMsg(e.Payload) |
| 553 | require.NoError(t, err) | 554 | require.NoError(t, err) | ||
| 554 | require.Equal(t, protocol.ErrServerShutdown, em.Code, "%s hello racing shutdown must be rejected", intent.name) | 555 | require.Equal(t, protocol.ErrServerShutdown, em.Code, "%s hello racing shutdown must be rejected", intent.name) | ||
| 555 | } | 556 | } | ||
| @@ -573,23 +574,23 @@ func TestServeReturnsDespiteWedgedClientOnShutdown(t *testing.T) { | |||||
| 573 | p, _ := newBlockingPTY(t) // Close unblocks the parked reader | 574 | p, _ := newBlockingPTY(t) // Close unblocks the parked reader | ||
| 574 | 575 | ||||
| 575 | tr := portsmocks.NewMockTransport(t) | 576 | tr := portsmocks.NewMockTransport(t) | ||
| 576 | - | sends := make(chan ports.Frame, 64) | 577 | + | sends := make(chan wire.Frame, 64) |
| 577 | - | recvCh := make(chan ports.Frame, 1) | 578 | + | recvCh := make(chan wire.Frame, 1) |
| 578 | recvCh <- mustHello(protocol.IntentNew, "wedge", domain.Size{Cols: 80, Rows: 24}) | 579 | recvCh <- mustHello(protocol.IntentNew, "wedge", domain.Size{Cols: 80, Rows: 24}) | ||
| 579 | connDone := make(chan struct{}) | 580 | connDone := make(chan struct{}) | ||
| 580 | var connOnce sync.Once | 581 | var connOnce sync.Once | ||
| 581 | closeConn := func() { connOnce.Do(func() { close(connDone) }) } | 582 | closeConn := func() { connOnce.Do(func() { close(connDone) }) } | ||
| 582 | 583 | ||||
| 583 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | 584 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { |
| 584 | select { | 585 | select { | ||
| 585 | case f := <-recvCh: | 586 | case f := <-recvCh: | ||
| 586 | return f, nil | 587 | return f, nil | ||
| 587 | case <-connDone: | 588 | case <-connDone: | ||
| 588 | - | return ports.Frame{}, io.EOF | 589 | + | return wire.Frame{}, io.EOF |
| 589 | } | 590 | } | ||
| 590 | }).Maybe() | 591 | }).Maybe() | ||
| 591 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | 592 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { |
| 592 | - | if f.Type == ports.MsgDetached { | 593 | + | if f.Type == wire.MsgDetached { |
| 593 | // Wedged: blocks until the transport is force-closed. | 594 | // Wedged: blocks until the transport is force-closed. | ||
| 594 | <-connDone | 595 | <-connDone | ||
| 595 | return io.ErrClosedPipe | 596 | return io.ErrClosedPipe | ||
| @@ -621,8 +622,8 @@ func TestServeReturnsDespiteWedgedClientOnShutdown(t *testing.T) { | |||||
| 621 | served := make(chan error, 1) | 622 | served := make(chan error, 1) | ||
| 622 | go func() { served <- d.Serve(ctx, l) }() | 623 | go func() { served <- d.Serve(ctx, l) }() | ||
| 623 | 624 | ||||
| 624 | - | awaitFrame(t, sends, ports.MsgWelcome) | 625 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 625 | - | awaitFrame(t, sends, ports.MsgOutput) | 626 | + | awaitFrame(t, sends, wire.MsgOutput) |
| 626 | 627 | ||||
| 627 | cancel() // shutdown with the wedged client still attached | 628 | cancel() // shutdown with the wedged client still attached | ||
| 628 | 629 | ||||
M internal/usecase/daemon/snapshot_scheduler_test.go +4 -3
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | "github.com/bnema/vev/internal/ports" | 15 | "github.com/bnema/vev/internal/ports" | ||
| 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 17 | "github.com/bnema/vev/internal/protocol" | 17 | "github.com/bnema/vev/internal/protocol" | ||
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 18 | ) | 19 | ) | ||
| 19 | 20 | ||||
| 20 | func TestSnapshotCoordinatorQuarantineCancelsPublicationBeforeDelete(t *testing.T) { | 21 | func TestSnapshotCoordinatorQuarantineCancelsPublicationBeforeDelete(t *testing.T) { | ||
| @@ -311,7 +312,7 @@ func TestServeShutdownDeadlineStillJoinsPaneExitWriter(t *testing.T) { | |||||
| 311 | served := make(chan error, 1) | 312 | served := make(chan error, 1) | ||
| 312 | go func() { served <- d.Serve(ctx, listener) }() | 313 | go func() { served <- d.Serve(ctx, listener) }() | ||
| 313 | 314 | ||||
| 314 | - | awaitFrame(t, sends, ports.MsgWelcome) | 315 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 315 | sess := firstSession(d) | 316 | sess := firstSession(d) | ||
| 316 | require.NotNil(t, sess) | 317 | require.NotNil(t, sess) | ||
| 317 | 318 | ||||
| @@ -476,7 +477,7 @@ func TestServeShutdownCheckpointsBeforeStoppingSnapshotWorker(t *testing.T) { | |||||
| 476 | served := make(chan error, 1) | 477 | served := make(chan error, 1) | ||
| 477 | go func() { served <- d.Serve(ctx, l) }() | 478 | go func() { served <- d.Serve(ctx, l) }() | ||
| 478 | 479 | ||||
| 479 | - | awaitFrame(t, sends, ports.MsgWelcome) | 480 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 480 | markSnapshotDirty(firstSession(d)) | 481 | markSnapshotDirty(firstSession(d)) | ||
| 481 | d.snapshotWake <- struct{}{} | 482 | d.snapshotWake <- struct{}{} | ||
| 482 | first := <-published | 483 | first := <-published | ||
| @@ -533,7 +534,7 @@ func TestServeShutdownDeadlineStillJoinsUncooperativeSnapshotRepository(t *testi | |||||
| 533 | served := make(chan error, 1) | 534 | served := make(chan error, 1) | ||
| 534 | go func() { served <- d.Serve(ctx, l) }() | 535 | go func() { served <- d.Serve(ctx, l) }() | ||
| 535 | 536 | ||||
| 536 | - | awaitFrame(t, sends, ports.MsgWelcome) | 537 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 537 | markSnapshotDirty(firstSession(d)) | 538 | markSnapshotDirty(firstSession(d)) | ||
| 538 | d.snapshotWake <- struct{}{} | 539 | d.snapshotWake <- struct{}{} | ||
| 539 | select { | 540 | select { | ||
M internal/usecase/daemon/status_test.go +6 -6
| @@ -13,8 +13,8 @@ import ( | |||||
| 13 | 13 | ||||
| 14 | renderer "github.com/bnema/vev-vt/ansi" | 14 | renderer "github.com/bnema/vev-vt/ansi" | ||
| 15 | "github.com/bnema/vev/internal/domain" | 15 | "github.com/bnema/vev/internal/domain" | ||
| 16 | - | "github.com/bnema/vev/internal/ports" | |||
| 17 | "github.com/bnema/vev/internal/protocol" | 16 | "github.com/bnema/vev/internal/protocol" | ||
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 18 | "github.com/bnema/vev/internal/usecase/command" | 18 | "github.com/bnema/vev/internal/usecase/command" | ||
| 19 | "github.com/bnema/vev/internal/usecase/layout" | 19 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 20 | "github.com/bnema/vev/internal/usecase/palette" | 20 | "github.com/bnema/vev/internal/usecase/palette" | ||
| @@ -1445,13 +1445,13 @@ func TestStatusCoalescesCreateSwitchAndResize(t *testing.T) { | |||||
| 1445 | frameInput([]byte("\x1b ")), | 1445 | frameInput([]byte("\x1b ")), | ||
| 1446 | frameInput([]byte("CNT\r")), | 1446 | frameInput([]byte("CNT\r")), | ||
| 1447 | frameInput([]byte("\x1b1")), | 1447 | frameInput([]byte("\x1b1")), | ||
| 1448 | - | ports.Frame{Type: ports.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 22, Rows: 6}})}, | 1448 | + | wire.Frame{Type: wire.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 22, Rows: 6}})}, |
| 1449 | ) | 1449 | ) | ||
| 1450 | 1450 | ||||
| 1451 | var hg sync.WaitGroup | 1451 | var hg sync.WaitGroup | ||
| 1452 | hg.Go(func() { d.handleConn(tr) }) | 1452 | hg.Go(func() { d.handleConn(tr) }) | ||
| 1453 | - | awaitFrame(t, sends, ports.MsgWelcome) | 1453 | + | awaitFrame(t, sends, wire.MsgWelcome) |
| 1454 | - | first := awaitFrame(t, sends, ports.MsgOutput) | 1454 | + | first := awaitFrame(t, sends, wire.MsgOutput) |
| 1455 | require.Eventually(t, func() bool { | 1455 | require.Eventually(t, func() bool { | ||
| 1456 | sessions := listSessions(t, d) | 1456 | sessions := listSessions(t, d) | ||
| 1457 | return len(sessions.Sessions) == 1 && sessions.Sessions[0].Tabs == 2 | 1457 | return len(sessions.Sessions) == 1 && sessions.Sessions[0].Tabs == 2 | ||
| @@ -1466,8 +1466,8 @@ func TestStatusCoalescesCreateSwitchAndResize(t *testing.T) { | |||||
| 1466 | "timed out awaiting resized output frame", | 1466 | "timed out awaiting resized output frame", | ||
| 1467 | ) | 1467 | ) | ||
| 1468 | 1468 | ||||
| 1469 | - | for _, f := range []ports.Frame{first, resized} { | 1469 | + | for _, f := range []wire.Frame{first, resized} { |
| 1470 | - | out, err := ports.UnmarshalOutput(f.Payload) | 1470 | + | out, err := wire.UnmarshalOutput(f.Payload) |
| 1471 | require.NoError(t, err) | 1471 | require.NoError(t, err) | ||
| 1472 | require.Contains(t, string(out.Data), "work") | 1472 | require.Contains(t, string(out.Data), "work") | ||
| 1473 | require.Contains(t, string(out.Data), ";7m", "active status tab should be inverse-highlighted") | 1473 | require.Contains(t, string(out.Data), ";7m", "active status tab should be inverse-highlighted") | ||
M internal/usecase/daemon/test_wait_helpers_test.go +8 -8
| @@ -4,13 +4,13 @@ import ( | |||||
| 4 | "testing" | 4 | "testing" | ||
| 5 | "time" | 5 | "time" | ||
| 6 | 6 | ||||
| 7 | - | "github.com/bnema/vev/internal/ports" | 7 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 8 | ) | 8 | ) | ||
| 9 | 9 | ||||
| 10 | const testWaitTimeout = 2 * time.Second | 10 | const testWaitTimeout = 2 * time.Second | ||
| 11 | 11 | ||||
| 12 | - | func testFramesOfType(frames []ports.Frame, typ ports.MsgType) []ports.Frame { | 12 | + | func testFramesOfType(frames []wire.Frame, typ wire.MsgType) []wire.Frame { |
| 13 | - | matched := make([]ports.Frame, 0, len(frames)) | 13 | + | matched := make([]wire.Frame, 0, len(frames)) |
| 14 | for _, frame := range frames { | 14 | for _, frame := range frames { | ||
| 15 | if frame.Type == typ { | 15 | if frame.Type == typ { | ||
| 16 | matched = append(matched, frame) | 16 | matched = append(matched, frame) | ||
| @@ -40,21 +40,21 @@ func awaitTestCompletion(t *testing.T, done <-chan struct{}, failure string) { | |||||
| 40 | 40 | ||||
| 41 | func awaitCoordinatorOutput( | 41 | func awaitCoordinatorOutput( | ||
| 42 | t *testing.T, | 42 | t *testing.T, | ||
| 43 | - | sends <-chan ports.Frame, | 43 | + | sends <-chan wire.Frame, |
| 44 | timers <-chan *coordinatorMockTimer, | 44 | timers <-chan *coordinatorMockTimer, | ||
| 45 | frameContext string, | 45 | frameContext string, | ||
| 46 | timeoutFailure string, | 46 | timeoutFailure string, | ||
| 47 | - | ) ports.Frame { | 47 | + | ) wire.Frame { |
| 48 | t.Helper() | 48 | t.Helper() | ||
| 49 | deadline := time.NewTimer(testWaitTimeout) | 49 | deadline := time.NewTimer(testWaitTimeout) | ||
| 50 | defer deadline.Stop() | 50 | defer deadline.Stop() | ||
| 51 | for { | 51 | for { | ||
| 52 | select { | 52 | select { | ||
| 53 | case frame := <-sends: | 53 | case frame := <-sends: | ||
| 54 | - | if frame.Type == ports.MsgRoutePosition { | 54 | + | if frame.Type == wire.MsgRoutePosition { |
| 55 | continue | 55 | continue | ||
| 56 | } | 56 | } | ||
| 57 | - | if frame.Type != ports.MsgOutput { | 57 | + | if frame.Type != wire.MsgOutput { |
| 58 | t.Fatalf("unexpected frame type %d %s", frame.Type, frameContext) | 58 | t.Fatalf("unexpected frame type %d %s", frame.Type, frameContext) | ||
| 59 | } | 59 | } | ||
| 60 | return frame | 60 | return frame | ||
| @@ -62,7 +62,7 @@ func awaitCoordinatorOutput( | |||||
| 62 | timer.ch <- time.Time{} | 62 | timer.ch <- time.Time{} | ||
| 63 | case <-deadline.C: | 63 | case <-deadline.C: | ||
| 64 | t.Fatal(timeoutFailure) | 64 | t.Fatal(timeoutFailure) | ||
| 65 | - | return ports.Frame{} | 65 | + | return wire.Frame{} |
| 66 | } | 66 | } | ||
| 67 | } | 67 | } | ||
| 68 | } | 68 | } | ||
M internal/usecase/daemon/transactional_resize_test.go +5 -4
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | 12 | ||||
| 13 | "github.com/bnema/vev/internal/domain" | 13 | "github.com/bnema/vev/internal/domain" | ||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 15 | "github.com/bnema/vev/internal/usecase/layout" | 16 | "github.com/bnema/vev/internal/usecase/layout" | ||
| 16 | "github.com/bnema/vev/internal/usecase/ui" | 17 | "github.com/bnema/vev/internal/usecase/ui" | ||
| 17 | "github.com/bnema/vev/internal/usecase/visualsearch" | 18 | "github.com/bnema/vev/internal/usecase/visualsearch" | ||
| @@ -189,8 +190,8 @@ func TestProcessPTYDataRetainsCallbacksDuringResizeReplay(t *testing.T) { | |||||
| 189 | // normal asynchronous client path, proving replay uses processPTYData. | 190 | // normal asynchronous client path, proving replay uses processPTYData. | ||
| 190 | var clipboardOutput string | 191 | var clipboardOutput string | ||
| 191 | for { | 192 | for { | ||
| 192 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | 193 | + | frame := awaitFrame(t, sends, wire.MsgOutput) |
| 193 | - | out, err := ports.UnmarshalOutput(frame.Payload) | 194 | + | out, err := wire.UnmarshalOutput(frame.Payload) |
| 194 | require.NoError(t, err) | 195 | require.NoError(t, err) | ||
| 195 | clipboardOutput = string(out.Data) | 196 | clipboardOutput = string(out.Data) | ||
| 196 | if strings.Contains(clipboardOutput, "\x1b]52;c;YQ==\a") { | 197 | if strings.Contains(clipboardOutput, "\x1b]52;c;YQ==\a") { | ||
| @@ -839,8 +840,8 @@ func TestTransactionalResizeObsoleteTimerCallbacksCommitOnlyLatestEpoch(t *testi | |||||
| 839 | // The resize deadline is the only debounce: commit fires its sticky reset | 840 | // The resize deadline is the only debounce: commit fires its sticky reset | ||
| 840 | // through S2 immediately (subject to ACK/sync gates). | 841 | // through S2 immediately (subject to ACK/sync gates). | ||
| 841 | frame := <-frames | 842 | frame := <-frames | ||
| 842 | - | require.Equal(t, ports.MsgOutput, frame.Type, "the committed epoch emits a full frame") | 843 | + | require.Equal(t, wire.MsgOutput, frame.Type, "the committed epoch emits a full frame") |
| 843 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 844 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 844 | require.NoError(t, err) | 845 | require.NoError(t, err) | ||
| 845 | require.Zero(t, output.Base, "the accepted resize frame must reset the renderer state") | 846 | require.Zero(t, output.Base, "the accepted resize frame must reset the renderer state") | ||
| 846 | select { | 847 | select { | ||
M internal/usecase/daemon/transport_observability_test.go +9 -8
| @@ -9,6 +9,7 @@ import ( | |||||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | "github.com/bnema/vev/internal/ports" | 11 | "github.com/bnema/vev/internal/ports" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 12 | ) | 13 | ) | ||
| 13 | 14 | ||||
| 14 | // This acceptance boundary exercises the attached resize, render, and ACK | 15 | // This acceptance boundary exercises the attached resize, render, and ACK | ||
| @@ -25,11 +26,11 @@ func TestTransportObservabilityDaemonBoundaries(t *testing.T) { | |||||
| 25 | if !d.resizeForFirstPaint(sess, ac, domain.Size{Cols: 90, Rows: 25}) { | 26 | if !d.resizeForFirstPaint(sess, ac, domain.Size{Cols: 90, Rows: 25}) { | ||
| 26 | t.Fatal("first resize was not accepted") | 27 | t.Fatal("first resize was not accepted") | ||
| 27 | } | 28 | } | ||
| 28 | - | first := awaitFrame(t, sends, ports.MsgOutput) | 29 | + | first := awaitFrame(t, sends, wire.MsgOutput) |
| 29 | - | if first.Type != ports.MsgOutput { | 30 | + | if first.Type != wire.MsgOutput { |
| 30 | t.Fatalf("first frame = %v, want output", first.Type) | 31 | t.Fatalf("first frame = %v, want output", first.Type) | ||
| 31 | } | 32 | } | ||
| 32 | - | output, err := ports.UnmarshalOutput(first.Payload) | 33 | + | output, err := wire.UnmarshalOutput(first.Payload) |
| 33 | if err != nil { | 34 | if err != nil { | ||
| 34 | t.Fatalf("decode first output: %v", err) | 35 | t.Fatalf("decode first output: %v", err) | ||
| 35 | } | 36 | } | ||
| @@ -38,8 +39,8 @@ func TestTransportObservabilityDaemonBoundaries(t *testing.T) { | |||||
| 38 | } | 39 | } | ||
| 39 | ac.ackOutputState(output.Epoch, output.New) | 40 | ac.ackOutputState(output.Epoch, output.New) | ||
| 40 | rc.notifyAck() | 41 | rc.notifyAck() | ||
| 41 | - | second := awaitFrame(t, sends, ports.MsgOutput) | 42 | + | second := awaitFrame(t, sends, wire.MsgOutput) |
| 42 | - | if second.Type != ports.MsgOutput { | 43 | + | if second.Type != wire.MsgOutput { |
| 43 | t.Fatalf("second frame = %v, want output", second.Type) | 44 | t.Fatalf("second frame = %v, want output", second.Type) | ||
| 44 | } | 45 | } | ||
| 45 | 46 | ||||
| @@ -118,8 +119,8 @@ func TestTransportObservabilityBlockedRenderObserverReleasesArchitectureLocks(t | |||||
| 118 | close(paintDone) | 119 | close(paintDone) | ||
| 119 | }() | 120 | }() | ||
| 120 | awaitDaemonObserver(t, observer.entered, "blocked render observer") | 121 | awaitDaemonObserver(t, observer.entered, "blocked render observer") | ||
| 121 | - | frame := awaitFrame(t, sends, ports.MsgOutput) // The frame was emitted before the observer began its I/O. | 122 | + | frame := awaitFrame(t, sends, wire.MsgOutput) // The frame was emitted before the observer began its I/O. |
| 122 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 123 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 123 | if err != nil { | 124 | if err != nil { | ||
| 124 | t.Fatalf("decode emitted output: %v", err) | 125 | t.Fatalf("decode emitted output: %v", err) | ||
| 125 | } | 126 | } | ||
| @@ -153,7 +154,7 @@ func TestTransportObservabilityBlockedRenderObserverReleasesArchitectureLocks(t | |||||
| 153 | d.paint(sess, ac, false, nil) | 154 | d.paint(sess, ac, false, nil) | ||
| 154 | close(secondPaint) | 155 | close(secondPaint) | ||
| 155 | }() | 156 | }() | ||
| 156 | - | _ = awaitFrame(t, sends, ports.MsgOutput) // The second frame is live even though serialized observer I/O waits. | 157 | + | _ = awaitFrame(t, sends, wire.MsgOutput) // The second frame is live even though serialized observer I/O waits. |
| 157 | 158 | ||||
| 158 | close(observer.release) | 159 | close(observer.release) | ||
| 159 | awaitDaemonObserver(t, paintDone, "first render completion") | 160 | awaitDaemonObserver(t, paintDone, "first render completion") | ||
M internal/usecase/daemon/wire.go +17 -17
| @@ -3,11 +3,11 @@ package daemon | |||||
| 3 | 3 | ||||
| 4 | import ( | 4 | import ( | ||
| 5 | "github.com/bnema/vev/internal/domain" | 5 | "github.com/bnema/vev/internal/domain" | ||
| 6 | - | "github.com/bnema/vev/internal/ports" | |||
| 7 | "github.com/bnema/vev/internal/protocol" | 6 | "github.com/bnema/vev/internal/protocol" | ||
| 7 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 8 | ) | 8 | ) | ||
| 9 | 9 | ||||
| 10 | - | func frameWelcome(s *session, resumeToken uint64) (ports.Frame, error) { | 10 | + | func frameWelcome(s *session, resumeToken uint64) (wire.Frame, error) { |
| 11 | s.mu.Lock() | 11 | s.mu.Lock() | ||
| 12 | var identity *protocol.CommittedRouteIdentity | 12 | var identity *protocol.CommittedRouteIdentity | ||
| 13 | if s.incarnation != (domain.SessionLifecycleID{}) { | 13 | if s.incarnation != (domain.SessionLifecycleID{}) { | ||
| @@ -25,36 +25,36 @@ func frameWelcome(s *session, resumeToken uint64) (ports.Frame, error) { | |||||
| 25 | } | 25 | } | ||
| 26 | s.mu.Unlock() | 26 | s.mu.Unlock() | ||
| 27 | w.ResumeToken = resumeToken | 27 | w.ResumeToken = resumeToken | ||
| 28 | - | payload := ports.MarshalWelcome(w) | 28 | + | payload := wire.MarshalWelcome(w) |
| 29 | if payload == nil { | 29 | if payload == nil { | ||
| 30 | - | return ports.Frame{}, protocol.ErrInvalidRouteWire | 30 | + | return wire.Frame{}, protocol.ErrInvalidRouteWire |
| 31 | } | 31 | } | ||
| 32 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: payload}, nil | 32 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: payload}, nil |
| 33 | } | 33 | } | ||
| 34 | 34 | ||||
| 35 | - | func frameError(code uint16, text string) ports.Frame { | 35 | + | func frameError(code uint16, text string) wire.Frame { |
| 36 | - | return ports.Frame{Type: ports.MsgError, Payload: ports.MarshalErrorMsg(protocol.ErrorMsg{Code: code, Text: text})} | 36 | + | return wire.Frame{Type: wire.MsgError, Payload: wire.MarshalErrorMsg(protocol.ErrorMsg{Code: code, Text: text})} |
| 37 | } | 37 | } | ||
| 38 | 38 | ||||
| 39 | - | func frameOutputState(b []byte, baseState uint64, state uint64, echoAck uint64) (ports.Frame, error) { | 39 | + | func frameOutputState(b []byte, baseState uint64, state uint64, echoAck uint64) (wire.Frame, error) { |
| 40 | - | payload, err := ports.MarshalOutput(protocol.Output{ | 40 | + | payload, err := wire.MarshalOutput(protocol.Output{ |
| 41 | Epoch: 1, Base: baseState, New: state, Echo: echoAck, | 41 | Epoch: 1, Base: baseState, New: state, Echo: echoAck, | ||
| 42 | Size: domain.Size{Cols: 1, Rows: 1}, Full: state != 0 && baseState == 0, Data: b, | 42 | Size: domain.Size{Cols: 1, Rows: 1}, Full: state != 0 && baseState == 0, Data: b, | ||
| 43 | }) | 43 | }) | ||
| 44 | if err != nil { | 44 | if err != nil { | ||
| 45 | - | return ports.Frame{}, err | 45 | + | return wire.Frame{}, err |
| 46 | } | 46 | } | ||
| 47 | - | return ports.Frame{Type: ports.MsgOutput, Payload: payload}, nil | 47 | + | return wire.Frame{Type: wire.MsgOutput, Payload: payload}, nil |
| 48 | } | 48 | } | ||
| 49 | 49 | ||||
| 50 | - | func frameDetached(reason uint8) ports.Frame { | 50 | + | func frameDetached(reason uint8) wire.Frame { |
| 51 | - | return ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: reason})} | 51 | + | return wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: reason})} |
| 52 | } | 52 | } | ||
| 53 | 53 | ||||
| 54 | - | func framePong() ports.Frame { | 54 | + | func framePong() wire.Frame { |
| 55 | - | return ports.Frame{Type: ports.MsgPong, Payload: ports.MarshalPong(protocol.Pong{})} | 55 | + | return wire.Frame{Type: wire.MsgPong, Payload: wire.MarshalPong(protocol.Pong{})} |
| 56 | } | 56 | } | ||
| 57 | 57 | ||||
| 58 | - | func frameSessions(infos []protocol.SessionInfo) ports.Frame { | 58 | + | func frameSessions(infos []protocol.SessionInfo) wire.Frame { |
| 59 | - | return ports.Frame{Type: ports.MsgSessions, Payload: ports.MarshalSessions(protocol.Sessions{Sessions: infos})} | 59 | + | return wire.Frame{Type: wire.MsgSessions, Payload: wire.MarshalSessions(protocol.Sessions{Sessions: infos})} |
| 60 | } | 60 | } | ||
M internal/usecase/daemon/wire_metadata_test.go +2 -2
| @@ -5,7 +5,7 @@ import ( | |||||
| 5 | "sync" | 5 | "sync" | ||
| 6 | "testing" | 6 | "testing" | ||
| 7 | 7 | ||||
| 8 | - | "github.com/bnema/vev/internal/ports" | 8 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| 11 | func TestFrameWelcomeSnapshotsSessionMetadataUnderLock(t *testing.T) { | 11 | func TestFrameWelcomeSnapshotsSessionMetadataUnderLock(t *testing.T) { | ||
| @@ -27,7 +27,7 @@ func TestFrameWelcomeSnapshotsSessionMetadataUnderLock(t *testing.T) { | |||||
| 27 | if frameErr != nil { | 27 | if frameErr != nil { | ||
| 28 | t.Fatalf("frameWelcome() error = %v", frameErr) | 28 | t.Fatalf("frameWelcome() error = %v", frameErr) | ||
| 29 | } | 29 | } | ||
| 30 | - | welcome, err := ports.UnmarshalWelcome(frame.Payload) | 30 | + | welcome, err := wire.UnmarshalWelcome(frame.Payload) |
| 31 | if err != nil { | 31 | if err != nil { | ||
| 32 | t.Fatalf("UnmarshalWelcome() error = %v", err) | 32 | t.Fatalf("UnmarshalWelcome() error = %v", err) | ||
| 33 | } | 33 | } | ||
M internal/usecase/daemon/wire_test_helpers_test.go +4 -4
| @@ -1,12 +1,12 @@ | |||||
| 1 | package daemon | 1 | package daemon | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | - | "github.com/bnema/vev/internal/ports" | |||
| 5 | "github.com/bnema/vev/internal/protocol" | 4 | "github.com/bnema/vev/internal/protocol" | ||
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 6 | ) | 6 | ) | ||
| 7 | 7 | ||||
| 8 | func mustMarshalOutput(m protocol.Output) []byte { | 8 | func mustMarshalOutput(m protocol.Output) []byte { | ||
| 9 | - | payload, err := ports.MarshalOutput(m) | 9 | + | payload, err := wire.MarshalOutput(m) |
| 10 | if err != nil { | 10 | if err != nil { | ||
| 11 | panic(err) | 11 | panic(err) | ||
| 12 | } | 12 | } | ||
| @@ -14,7 +14,7 @@ func mustMarshalOutput(m protocol.Output) []byte { | |||||
| 14 | } | 14 | } | ||
| 15 | 15 | ||||
| 16 | func mustMarshalAck(m protocol.Ack) []byte { | 16 | func mustMarshalAck(m protocol.Ack) []byte { | ||
| 17 | - | payload, err := ports.MarshalAck(m) | 17 | + | payload, err := wire.MarshalAck(m) |
| 18 | if err != nil { | 18 | if err != nil { | ||
| 19 | panic(err) | 19 | panic(err) | ||
| 20 | } | 20 | } | ||
| @@ -22,7 +22,7 @@ func mustMarshalAck(m protocol.Ack) []byte { | |||||
| 22 | } | 22 | } | ||
| 23 | 23 | ||||
| 24 | func mustMarshalResize(m protocol.Resize) []byte { | 24 | func mustMarshalResize(m protocol.Resize) []byte { | ||
| 25 | - | payload, err := ports.MarshalResize(m) | 25 | + | payload, err := wire.MarshalResize(m) |
| 26 | if err != nil { | 26 | if err != nil { | ||
| 27 | panic(err) | 27 | panic(err) | ||
| 28 | } | 28 | } | ||
M scripts/remote-picker-harness/main.go +32 -31
| @@ -21,6 +21,7 @@ import ( | |||||
| 21 | "github.com/bnema/vev/internal/domain" | 21 | "github.com/bnema/vev/internal/domain" | ||
| 22 | "github.com/bnema/vev/internal/ports" | 22 | "github.com/bnema/vev/internal/ports" | ||
| 23 | "github.com/bnema/vev/internal/protocol" | 23 | "github.com/bnema/vev/internal/protocol" | ||
| 24 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 24 | ) | 25 | ) | ||
| 25 | 26 | ||||
| 26 | const ( | 27 | const ( | ||
| @@ -458,7 +459,7 @@ func localEnvironment() []string { | |||||
| 458 | } | 459 | } | ||
| 459 | 460 | ||||
| 460 | type harnessFrame struct { | 461 | type harnessFrame struct { | ||
| 461 | - | frame ports.Frame | 462 | + | frame wire.Frame |
| 462 | err error | 463 | err error | ||
| 463 | } | 464 | } | ||
| 464 | 465 | ||||
| @@ -642,44 +643,44 @@ func attachAndCheck(ctx context.Context, tr *harnessTransport, hello protocol.He | |||||
| 642 | if hello.EnvironmentPolicy == 0 { | 643 | if hello.EnvironmentPolicy == 0 { | ||
| 643 | hello.EnvironmentPolicy = protocol.EnvironmentPolicyClientOwned | 644 | hello.EnvironmentPolicy = protocol.EnvironmentPolicyClientOwned | ||
| 644 | } | 645 | } | ||
| 645 | - | payload := ports.MarshalHello(hello) | 646 | + | payload := wire.MarshalHello(hello) |
| 646 | - | if err := tr.Send(ports.Frame{Type: ports.MsgHello, Payload: payload}); err != nil { | 647 | + | if err := tr.Send(wire.Frame{Type: wire.MsgHello, Payload: payload}); err != nil { |
| 647 | return err | 648 | return err | ||
| 648 | } | 649 | } | ||
| 649 | frame, err := receiveWithTimeout(ctx, tr) | 650 | frame, err := receiveWithTimeout(ctx, tr) | ||
| 650 | if err != nil { | 651 | if err != nil { | ||
| 651 | return err | 652 | return err | ||
| 652 | } | 653 | } | ||
| 653 | - | if frame.Type == ports.MsgError { | 654 | + | if frame.Type == wire.MsgError { |
| 654 | - | message, decodeErr := ports.UnmarshalErrorMsg(frame.Payload) | 655 | + | message, decodeErr := wire.UnmarshalErrorMsg(frame.Payload) |
| 655 | if decodeErr != nil { | 656 | if decodeErr != nil { | ||
| 656 | return decodeErr | 657 | return decodeErr | ||
| 657 | } | 658 | } | ||
| 658 | return fmt.Errorf("remote error code %d", message.Code) | 659 | return fmt.Errorf("remote error code %d", message.Code) | ||
| 659 | } | 660 | } | ||
| 660 | - | if frame.Type != ports.MsgWelcome { | 661 | + | if frame.Type != wire.MsgWelcome { |
| 661 | return fmt.Errorf("welcome frame type %d", frame.Type) | 662 | return fmt.Errorf("welcome frame type %d", frame.Type) | ||
| 662 | } | 663 | } | ||
| 663 | tr.probe.recordControl(probeEventWelcome) | 664 | tr.probe.recordControl(probeEventWelcome) | ||
| 664 | - | if err := tr.Send(ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(protocol.Theme{TrueColor: hello.TrueColor, SchemeKnown: true})}); err != nil { | 665 | + | if err := tr.Send(wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(protocol.Theme{TrueColor: hello.TrueColor, SchemeKnown: true})}); err != nil { |
| 665 | return fmt.Errorf("send initial theme: %w", err) | 666 | return fmt.Errorf("send initial theme: %w", err) | ||
| 666 | } | 667 | } | ||
| 667 | return nil | 668 | return nil | ||
| 668 | } | 669 | } | ||
| 669 | 670 | ||||
| 670 | func sendRawInput(tr *harnessTransport, data string) error { | 671 | func sendRawInput(tr *harnessTransport, data string) error { | ||
| 671 | - | return tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(data)})}) | 672 | + | return tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(data)})}) |
| 672 | } | 673 | } | ||
| 673 | 674 | ||||
| 674 | - | func processOutputFrame(tr *harnessTransport, frame ports.Frame) error { | 675 | + | func processOutputFrame(tr *harnessTransport, frame wire.Frame) error { |
| 675 | - | output, err := ports.UnmarshalOutput(frame.Payload) | 676 | + | output, err := wire.UnmarshalOutput(frame.Payload) |
| 676 | if err != nil { | 677 | if err != nil { | ||
| 677 | return err | 678 | return err | ||
| 678 | } | 679 | } | ||
| 679 | result := tr.probe.apply(output) | 680 | result := tr.probe.apply(output) | ||
| 680 | if !result.Accepted { | 681 | if !result.Accepted { | ||
| 681 | if !tr.probe.resetPending { | 682 | if !tr.probe.resetPending { | ||
| 682 | - | if err := tr.Send(ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})}); err != nil { | 683 | + | if err := tr.Send(wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})}); err != nil { |
| 683 | return err | 684 | return err | ||
| 684 | } | 685 | } | ||
| 685 | tr.probe.resetPending = true | 686 | tr.probe.resetPending = true | ||
| @@ -690,11 +691,11 @@ func processOutputFrame(tr *harnessTransport, frame ports.Frame) error { | |||||
| 690 | if !result.StateBearing { | 691 | if !result.StateBearing { | ||
| 691 | return nil | 692 | return nil | ||
| 692 | } | 693 | } | ||
| 693 | - | payload, err := ports.MarshalAck(result.Ack) | 694 | + | payload, err := wire.MarshalAck(result.Ack) |
| 694 | if err != nil { | 695 | if err != nil { | ||
| 695 | return err | 696 | return err | ||
| 696 | } | 697 | } | ||
| 697 | - | if err := tr.Send(ports.Frame{Type: ports.MsgAck, Payload: payload}); err != nil { | 698 | + | if err := tr.Send(wire.Frame{Type: wire.MsgAck, Payload: payload}); err != nil { |
| 698 | return err | 699 | return err | ||
| 699 | } | 700 | } | ||
| 700 | tr.probe.resetPending = false | 701 | tr.probe.resetPending = false | ||
| @@ -714,7 +715,7 @@ func awaitOutputContains(ctx context.Context, tr *harnessTransport, want string) | |||||
| 714 | if err != nil { | 715 | if err != nil { | ||
| 715 | return err | 716 | return err | ||
| 716 | } | 717 | } | ||
| 717 | - | if frame.Type != ports.MsgOutput { | 718 | + | if frame.Type != wire.MsgOutput { |
| 718 | continue | 719 | continue | ||
| 719 | } | 720 | } | ||
| 720 | if err := processOutputFrame(tr, frame); err != nil { | 721 | if err := processOutputFrame(tr, frame); err != nil { | ||
| @@ -738,7 +739,7 @@ func awaitRemotePickerPreview(ctx context.Context, tr *harnessTransport, marker | |||||
| 738 | if err != nil { | 739 | if err != nil { | ||
| 739 | return fmt.Errorf("no rendered remote preview after %d output frames (loading=%t): %w", tr.probe.outputFrames, sawLoading, err) | 740 | return fmt.Errorf("no rendered remote preview after %d output frames (loading=%t): %w", tr.probe.outputFrames, sawLoading, err) | ||
| 740 | } | 741 | } | ||
| 741 | - | if frame.Type != ports.MsgOutput { | 742 | + | if frame.Type != wire.MsgOutput { |
| 742 | continue | 743 | continue | ||
| 743 | } | 744 | } | ||
| 744 | if err := processOutputFrame(tr, frame); err != nil { | 745 | if err := processOutputFrame(tr, frame); err != nil { | ||
| @@ -768,7 +769,7 @@ func remotePreviewContains(preview protocol.RemotePreview, want string) bool { | |||||
| 768 | } | 769 | } | ||
| 769 | 770 | ||||
| 770 | func sendInputAndAwait(ctx context.Context, tr *harnessTransport, command, want string) error { | 771 | func sendInputAndAwait(ctx context.Context, tr *harnessTransport, command, want string) error { | ||
| 771 | - | if err := tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(command + "\n")})}); err != nil { | 772 | + | if err := tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(command + "\n")})}); err != nil { |
| 772 | return err | 773 | return err | ||
| 773 | } | 774 | } | ||
| 774 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | 775 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | ||
| @@ -779,7 +780,7 @@ func sendInputAndAwait(ctx context.Context, tr *harnessTransport, command, want | |||||
| 779 | if err != nil { | 780 | if err != nil { | ||
| 780 | return fmt.Errorf("waiting for marker after %d output frames/%d bytes: %w", tr.probe.outputFrames, tr.probe.outputBytes, err) | 781 | return fmt.Errorf("waiting for marker after %d output frames/%d bytes: %w", tr.probe.outputFrames, tr.probe.outputBytes, err) | ||
| 781 | } | 782 | } | ||
| 782 | - | if frame.Type != ports.MsgOutput { | 783 | + | if frame.Type != wire.MsgOutput { |
| 783 | continue | 784 | continue | ||
| 784 | } | 785 | } | ||
| 785 | if err := processOutputFrame(tr, frame); err != nil { | 786 | if err := processOutputFrame(tr, frame); err != nil { | ||
| @@ -801,11 +802,11 @@ func sendCommand(ctx context.Context, tr *harnessTransport, slug string) error { | |||||
| 801 | Attached: true, | 802 | Attached: true, | ||
| 802 | Slug: slug, | 803 | Slug: slug, | ||
| 803 | } | 804 | } | ||
| 804 | - | payload, err := ports.MarshalCommandRequest(request) | 805 | + | payload, err := wire.MarshalCommandRequest(request) |
| 805 | if err != nil { | 806 | if err != nil { | ||
| 806 | return err | 807 | return err | ||
| 807 | } | 808 | } | ||
| 808 | - | if err := tr.Send(ports.Frame{Type: ports.MsgCommand, Payload: payload}); err != nil { | 809 | + | if err := tr.Send(wire.Frame{Type: wire.MsgCommand, Payload: payload}); err != nil { |
| 809 | return err | 810 | return err | ||
| 810 | } | 811 | } | ||
| 811 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | 812 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | ||
| @@ -815,16 +816,16 @@ func sendCommand(ctx context.Context, tr *harnessTransport, slug string) error { | |||||
| 815 | if err != nil { | 816 | if err != nil { | ||
| 816 | return err | 817 | return err | ||
| 817 | } | 818 | } | ||
| 818 | - | if frame.Type == ports.MsgOutput { | 819 | + | if frame.Type == wire.MsgOutput { |
| 819 | if err := processOutputFrame(tr, frame); err != nil { | 820 | if err := processOutputFrame(tr, frame); err != nil { | ||
| 820 | return err | 821 | return err | ||
| 821 | } | 822 | } | ||
| 822 | continue | 823 | continue | ||
| 823 | } | 824 | } | ||
| 824 | - | if frame.Type != ports.MsgCommandResult { | 825 | + | if frame.Type != wire.MsgCommandResult { |
| 825 | continue | 826 | continue | ||
| 826 | } | 827 | } | ||
| 827 | - | result, err := ports.UnmarshalCommandResult(frame.Payload) | 828 | + | result, err := wire.UnmarshalCommandResult(frame.Payload) |
| 828 | if err != nil { | 829 | if err != nil { | ||
| 829 | return err | 830 | return err | ||
| 830 | } | 831 | } | ||
| @@ -836,7 +837,7 @@ func sendCommand(ctx context.Context, tr *harnessTransport, slug string) error { | |||||
| 836 | } | 837 | } | ||
| 837 | 838 | ||||
| 838 | func detach(ctx context.Context, tr *harnessTransport) error { | 839 | func detach(ctx context.Context, tr *harnessTransport) error { | ||
| 839 | - | if err := tr.Send(ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}); err != nil { | 840 | + | if err := tr.Send(wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}); err != nil { |
| 840 | return err | 841 | return err | ||
| 841 | } | 842 | } | ||
| 842 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | 843 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | ||
| @@ -846,7 +847,7 @@ func detach(ctx context.Context, tr *harnessTransport) error { | |||||
| 846 | if err != nil { | 847 | if err != nil { | ||
| 847 | return err | 848 | return err | ||
| 848 | } | 849 | } | ||
| 849 | - | if frame.Type == ports.MsgDetached { | 850 | + | if frame.Type == wire.MsgDetached { |
| 850 | return nil | 851 | return nil | ||
| 851 | } | 852 | } | ||
| 852 | } | 853 | } | ||
| @@ -871,18 +872,18 @@ func expectNoSuchTarget(ctx context.Context, tr *harnessTransport, target domain | |||||
| 871 | RemoteTarget: &target, | 872 | RemoteTarget: &target, | ||
| 872 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | 873 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | ||
| 873 | } | 874 | } | ||
| 874 | - | payload := ports.MarshalHello(hello) | 875 | + | payload := wire.MarshalHello(hello) |
| 875 | - | if err := tr.Send(ports.Frame{Type: ports.MsgHello, Payload: payload}); err != nil { | 876 | + | if err := tr.Send(wire.Frame{Type: wire.MsgHello, Payload: payload}); err != nil { |
| 876 | return err | 877 | return err | ||
| 877 | } | 878 | } | ||
| 878 | frame, err := receiveWithTimeout(ctx, tr) | 879 | frame, err := receiveWithTimeout(ctx, tr) | ||
| 879 | if err != nil { | 880 | if err != nil { | ||
| 880 | return err | 881 | return err | ||
| 881 | } | 882 | } | ||
| 882 | - | if frame.Type != ports.MsgError { | 883 | + | if frame.Type != wire.MsgError { |
| 883 | return fmt.Errorf("stale target returned frame type %d", frame.Type) | 884 | return fmt.Errorf("stale target returned frame type %d", frame.Type) | ||
| 884 | } | 885 | } | ||
| 885 | - | message, err := ports.UnmarshalErrorMsg(frame.Payload) | 886 | + | message, err := wire.UnmarshalErrorMsg(frame.Payload) |
| 886 | if err != nil { | 887 | if err != nil { | ||
| 887 | return err | 888 | return err | ||
| 888 | } | 889 | } | ||
| @@ -1002,7 +1003,7 @@ func assertNoDirectHandoff(tr *harnessTransport) error { | |||||
| 1002 | queued := len(tr.frames) | 1003 | queued := len(tr.frames) | ||
| 1003 | for range queued { | 1004 | for range queued { | ||
| 1004 | outcome := <-tr.frames | 1005 | outcome := <-tr.frames | ||
| 1005 | - | if outcome.frame.Type == ports.MsgAttachTarget { | 1006 | + | if outcome.frame.Type == wire.MsgAttachTarget { |
| 1006 | tr.probe.recordIncoming(outcome.frame) | 1007 | tr.probe.recordIncoming(outcome.frame) | ||
| 1007 | } else { | 1008 | } else { | ||
| 1008 | tr.queued = append(tr.queued, outcome) | 1009 | tr.queued = append(tr.queued, outcome) | ||
| @@ -1014,7 +1015,7 @@ func assertNoDirectHandoff(tr *harnessTransport) error { | |||||
| 1014 | return nil | 1015 | return nil | ||
| 1015 | } | 1016 | } | ||
| 1016 | 1017 | ||||
| 1017 | - | func receiveWithTimeout(ctx context.Context, tr *harnessTransport) (ports.Frame, error) { | 1018 | + | func receiveWithTimeout(ctx context.Context, tr *harnessTransport) (wire.Frame, error) { |
| 1018 | if len(tr.queued) != 0 { | 1019 | if len(tr.queued) != 0 { | ||
| 1019 | outcome := tr.queued[0] | 1020 | outcome := tr.queued[0] | ||
| 1020 | tr.queued = tr.queued[1:] | 1021 | tr.queued = tr.queued[1:] | ||
| @@ -1025,7 +1026,7 @@ func receiveWithTimeout(ctx context.Context, tr *harnessTransport) (ports.Frame, | |||||
| 1025 | } | 1026 | } | ||
| 1026 | select { | 1027 | select { | ||
| 1027 | case <-ctx.Done(): | 1028 | case <-ctx.Done(): | ||
| 1028 | - | return ports.Frame{}, ctx.Err() | 1029 | + | return wire.Frame{}, ctx.Err() |
| 1029 | case outcome := <-tr.frames: | 1030 | case outcome := <-tr.frames: | ||
| 1030 | if outcome.err == nil { | 1031 | if outcome.err == nil { | ||
| 1031 | tr.probe.recordIncoming(outcome.frame) | 1032 | tr.probe.recordIncoming(outcome.frame) | ||
M scripts/remote-picker-harness/main_test.go +4 -4
| @@ -5,7 +5,7 @@ import ( | |||||
| 5 | "strings" | 5 | "strings" | ||
| 6 | "testing" | 6 | "testing" | ||
| 7 | 7 | ||||
| 8 | - | "github.com/bnema/vev/internal/ports" | 8 | + | "github.com/bnema/vev/internal/protocol/wire" |
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| 11 | func TestBoundedStderrRetainsAtMostDiagnosticLimit(t *testing.T) { | 11 | func TestBoundedStderrRetainsAtMostDiagnosticLimit(t *testing.T) { | ||
| @@ -50,13 +50,13 @@ func TestAssertNoDirectHandoffProcessesInitialFramesAndRetainsOutput(t *testing. | |||||
| 50 | probe: &visualProbe{}, | 50 | probe: &visualProbe{}, | ||
| 51 | frames: make(chan harnessFrame, 2), | 51 | frames: make(chan harnessFrame, 2), | ||
| 52 | } | 52 | } | ||
| 53 | - | tr.frames <- harnessFrame{frame: ports.Frame{Type: ports.MsgOutput}} | 53 | + | tr.frames <- harnessFrame{frame: wire.Frame{Type: wire.MsgOutput}} |
| 54 | - | tr.frames <- harnessFrame{frame: ports.Frame{Type: ports.MsgAttachTarget}} | 54 | + | tr.frames <- harnessFrame{frame: wire.Frame{Type: wire.MsgAttachTarget}} |
| 55 | 55 | ||||
| 56 | if err := assertNoDirectHandoff(tr); err == nil { | 56 | if err := assertNoDirectHandoff(tr); err == nil { | ||
| 57 | t.Fatal("direct handoff was not rejected") | 57 | t.Fatal("direct handoff was not rejected") | ||
| 58 | } | 58 | } | ||
| 59 | - | if len(tr.queued) != 1 || tr.queued[0].frame.Type != ports.MsgOutput { | 59 | + | if len(tr.queued) != 1 || tr.queued[0].frame.Type != wire.MsgOutput { |
| 60 | t.Fatalf("queued frames = %#v, want one retained output", tr.queued) | 60 | t.Fatalf("queued frames = %#v, want one retained output", tr.queued) | ||
| 61 | } | 61 | } | ||
| 62 | if tr.probe.unexpectedHandoffs != 1 { | 62 | if tr.probe.unexpectedHandoffs != 1 { | ||
M scripts/remote-picker-harness/visual_probe.go +3 -3
| @@ -11,8 +11,8 @@ import ( | |||||
| 11 | 11 | ||||
| 12 | vt "github.com/bnema/vev-vt" | 12 | vt "github.com/bnema/vev-vt" | ||
| 13 | "github.com/bnema/vev/internal/domain" | 13 | "github.com/bnema/vev/internal/domain" | ||
| 14 | - | "github.com/bnema/vev/internal/ports" | |||
| 15 | "github.com/bnema/vev/internal/protocol" | 14 | "github.com/bnema/vev/internal/protocol" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 16 | ) | 16 | ) | ||
| 17 | 17 | ||||
| 18 | const ( | 18 | const ( | ||
| @@ -237,8 +237,8 @@ func (p *visualProbe) contains(want string) bool { | |||||
| 237 | return strings.Contains(p.text(), want) | 237 | return strings.Contains(p.text(), want) | ||
| 238 | } | 238 | } | ||
| 239 | 239 | ||||
| 240 | - | func (p *visualProbe) recordIncoming(frame ports.Frame) { | 240 | + | func (p *visualProbe) recordIncoming(frame wire.Frame) { |
| 241 | - | if p == nil || frame.Type != ports.MsgAttachTarget { | 241 | + | if p == nil || frame.Type != wire.MsgAttachTarget { |
| 242 | return | 242 | return | ||
| 243 | } | 243 | } | ||
| 244 | p.unexpectedHandoffs++ | 244 | p.unexpectedHandoffs++ | ||
M scripts/remote-picker-harness/visual_probe_test.go +11 -11
| @@ -8,8 +8,8 @@ import ( | |||||
| 8 | "testing" | 8 | "testing" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/vev/internal/domain" | 10 | "github.com/bnema/vev/internal/domain" | ||
| 11 | - | "github.com/bnema/vev/internal/ports" | |||
| 12 | "github.com/bnema/vev/internal/protocol" | 11 | "github.com/bnema/vev/internal/protocol" | ||
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 13 | "github.com/stretchr/testify/require" | 13 | "github.com/stretchr/testify/require" | ||
| 14 | ) | 14 | ) | ||
| 15 | 15 | ||||
| @@ -19,24 +19,24 @@ const ( | |||||
| 19 | ) | 19 | ) | ||
| 20 | 20 | ||||
| 21 | type probeTestTransport struct { | 21 | type probeTestTransport struct { | ||
| 22 | - | sent []ports.Frame | 22 | + | sent []wire.Frame |
| 23 | } | 23 | } | ||
| 24 | 24 | ||||
| 25 | - | func (t *probeTestTransport) Send(frame ports.Frame) error { | 25 | + | func (t *probeTestTransport) Send(frame wire.Frame) error { |
| 26 | t.sent = append(t.sent, frame) | 26 | t.sent = append(t.sent, frame) | ||
| 27 | return nil | 27 | return nil | ||
| 28 | } | 28 | } | ||
| 29 | 29 | ||||
| 30 | - | func (*probeTestTransport) Recv() (ports.Frame, error) { return ports.Frame{}, errors.New("not used") } | 30 | + | func (*probeTestTransport) Recv() (wire.Frame, error) { return wire.Frame{}, errors.New("not used") } |
| 31 | - | func (*probeTestTransport) Close() error { return nil } | 31 | + | func (*probeTestTransport) Close() error { return nil } |
| 32 | 32 | ||||
| 33 | - | func probeTestOutput(t *testing.T, output protocol.Output) ports.Frame { | 33 | + | func probeTestOutput(t *testing.T, output protocol.Output) wire.Frame { |
| 34 | t.Helper() | 34 | t.Helper() | ||
| 35 | - | payload, err := ports.MarshalOutput(output) | 35 | + | payload, err := wire.MarshalOutput(output) |
| 36 | if err != nil { | 36 | if err != nil { | ||
| 37 | t.Fatalf("marshal output: %v", err) | 37 | t.Fatalf("marshal output: %v", err) | ||
| 38 | } | 38 | } | ||
| 39 | - | return ports.Frame{Type: ports.MsgOutput, Payload: payload} | 39 | + | return wire.Frame{Type: wire.MsgOutput, Payload: payload} |
| 40 | } | 40 | } | ||
| 41 | 41 | ||||
| 42 | func TestVisualProbePersistsFullAndIncrementalOutput(t *testing.T) { | 42 | func TestVisualProbePersistsFullAndIncrementalOutput(t *testing.T) { | ||
| @@ -240,9 +240,9 @@ func TestProcessOutputFrameACKsOnlyAcceptedStateBearingFrames(t *testing.T) { | |||||
| 240 | var ackCount, resetCount int | 240 | var ackCount, resetCount int | ||
| 241 | for _, frame := range transport.sent { | 241 | for _, frame := range transport.sent { | ||
| 242 | switch frame.Type { | 242 | switch frame.Type { | ||
| 243 | - | case ports.MsgAck: | 243 | + | case wire.MsgAck: |
| 244 | ackCount++ | 244 | ackCount++ | ||
| 245 | - | case ports.MsgOutputResetRequest: | 245 | + | case wire.MsgOutputResetRequest: |
| 246 | resetCount++ | 246 | resetCount++ | ||
| 247 | } | 247 | } | ||
| 248 | } | 248 | } | ||
| @@ -268,7 +268,7 @@ func TestCaptureUnifiedPickerRowsRequiresLocalAndRemoteEntries(t *testing.T) { | |||||
| 268 | 268 | ||||
| 269 | func TestVisualProbeRecordsUnexpectedAttachTarget(t *testing.T) { | 269 | func TestVisualProbeRecordsUnexpectedAttachTarget(t *testing.T) { | ||
| 270 | probe := newVisualProbe(domain.Size{Cols: probeTestCols, Rows: probeTestRows}) | 270 | probe := newVisualProbe(domain.Size{Cols: probeTestCols, Rows: probeTestRows}) | ||
| 271 | - | probe.recordIncoming(ports.Frame{Type: ports.MsgAttachTarget}) | 271 | + | probe.recordIncoming(wire.Frame{Type: wire.MsgAttachTarget}) |
| 272 | 272 | ||||
| 273 | if probe.unexpectedHandoffs != 1 { | 273 | if probe.unexpectedHandoffs != 1 { | ||
| 274 | t.Fatalf("unexpected handoffs = %d, want 1", probe.unexpectedHandoffs) | 274 | t.Fatalf("unexpected handoffs = %d, want 1", probe.unexpectedHandoffs) | ||
M transport_replay_integration_test.go +6 -5
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | "github.com/bnema/vev/internal/adapters/sshstdio" | 12 | "github.com/bnema/vev/internal/adapters/sshstdio" | ||
| 13 | "github.com/bnema/vev/internal/ports" | 13 | "github.com/bnema/vev/internal/ports" | ||
| 14 | "github.com/bnema/vev/internal/protocol" | 14 | "github.com/bnema/vev/internal/protocol" | ||
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |||
| 15 | "github.com/bnema/vev/internal/testutil/replaytest" | 16 | "github.com/bnema/vev/internal/testutil/replaytest" | ||
| 16 | "github.com/stretchr/testify/require" | 17 | "github.com/stretchr/testify/require" | ||
| 17 | ) | 18 | ) | ||
| @@ -39,7 +40,7 @@ func TestTransportReplayIntegration(t *testing.T) { | |||||
| 39 | got, err := receiver.Recv() | 40 | got, err := receiver.Recv() | ||
| 40 | require.NoError(t, err) | 41 | require.NoError(t, err) | ||
| 41 | require.Equal(t, want, got) | 42 | require.Equal(t, want, got) | ||
| 42 | - | output, err := ports.UnmarshalOutput(got.Payload) | 43 | + | output, err := wire.UnmarshalOutput(got.Payload) |
| 43 | require.NoError(t, err) | 44 | require.NoError(t, err) | ||
| 44 | bytes = append(bytes, output.Data...) | 45 | bytes = append(bytes, output.Data...) | ||
| 45 | terminal.Write(output.Data) | 46 | terminal.Write(output.Data) | ||
| @@ -102,7 +103,7 @@ func TestThemeGenerationTransportSequences(t *testing.T) { | |||||
| 102 | done := make(chan error, 1) | 103 | done := make(chan error, 1) | ||
| 103 | go func() { | 104 | go func() { | ||
| 104 | for _, snapshot := range sequence { | 105 | for _, snapshot := range sequence { | ||
| 105 | - | if err := sender.Send(ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(snapshot)}); err != nil { | 106 | + | if err := sender.Send(wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(snapshot)}); err != nil { |
| 106 | done <- err | 107 | done <- err | ||
| 107 | return | 108 | return | ||
| 108 | } | 109 | } | ||
| @@ -113,9 +114,9 @@ func TestThemeGenerationTransportSequences(t *testing.T) { | |||||
| 113 | for _, want := range sequence { | 114 | for _, want := range sequence { | ||
| 114 | frame, err := receiver.Recv() | 115 | frame, err := receiver.Recv() | ||
| 115 | require.NoError(t, err) | 116 | require.NoError(t, err) | ||
| 116 | - | require.Equal(t, ports.MsgTheme, frame.Type) | 117 | + | require.Equal(t, wire.MsgTheme, frame.Type) |
| 117 | - | require.Equal(t, ports.MarshalTheme(want), frame.Payload, "theme payload must be preserved byte-for-byte before decode") | 118 | + | require.Equal(t, wire.MarshalTheme(want), frame.Payload, "theme payload must be preserved byte-for-byte before decode") |
| 118 | - | got, err := ports.UnmarshalTheme(frame.Payload) | 119 | + | got, err := wire.UnmarshalTheme(frame.Payload) |
| 119 | require.NoError(t, err) | 120 | require.NoError(t, err) | ||
| 120 | require.Equal(t, want, got) | 121 | require.Equal(t, want, got) | ||
| 121 | } | 122 | } | ||