diff options
| -rw-r--r-- | internal/clients/connectors/serverconnection_test.go | 30 | ||||
| -rw-r--r-- | internal/clients/interactive_control_test.go | 43 |
2 files changed, 73 insertions, 0 deletions
diff --git a/internal/clients/connectors/serverconnection_test.go b/internal/clients/connectors/serverconnection_test.go index 76c4eb6..01fe4af 100644 --- a/internal/clients/connectors/serverconnection_test.go +++ b/internal/clients/connectors/serverconnection_test.go @@ -333,6 +333,36 @@ func TestServerConnectionApplySessionSpecRejectsUnexpectedAck(t *testing.T) { } } +func TestServerConnectionApplySessionSpecTimesOutWaitingForAck(t *testing.T) { + resetClientLogger(t) + + mock := &mockHandler{ + waitForCapabilities: true, + capabilities: map[string]bool{ + protocol.CapabilityQueryUpdateV1: true, + }, + } + conn := &ServerConnection{ + server: "srv1", + handler: mock, + } + + err := conn.ApplySessionSpec(sessionspec.Spec{ + Mode: omode.TailClient, + Files: []string{"/var/log/app.log"}, + Regex: "ERROR", + }, 10*time.Millisecond) + if !errors.Is(err, ErrSessionAckTimeout) { + t.Fatalf("expected ErrSessionAckTimeout, got %v", err) + } + if len(mock.commands) != 1 { + t.Fatalf("expected session command to be sent before timeout, got %d", len(mock.commands)) + } + if _, _, ok := conn.CommittedSession(); ok { + t.Fatalf("unexpected committed session after missing ack") + } +} + type testSSHSettings struct { port int timeout time.Duration diff --git a/internal/clients/interactive_control_test.go b/internal/clients/interactive_control_test.go index 1cc31ec..a8b5aa0 100644 --- a/internal/clients/interactive_control_test.go +++ b/internal/clients/interactive_control_test.go @@ -169,6 +169,49 @@ func TestApplyInteractiveReloadCommitsSharedState(t *testing.T) { } } +func TestApplyInteractiveReloadRejectsMismatchedCommittedGenerations(t *testing.T) { + connA := &interactiveReloadConnector{server: "srv1", supported: true, generation: 4} + connB := &interactiveReloadConnector{server: "srv2", supported: true, generation: 5} + maker := &interactiveReloadMaker{} + + client := &baseClient{ + Args: config.Args{ + Mode: omode.GrepClient, + What: "/var/log/app.log", + RegexStr: "ERROR", + }, + sessionSpec: SessionSpec{ + Mode: omode.GrepClient, + Files: []string{"/var/log/app.log"}, + Regex: "ERROR", + }, + connections: []connectors.Connector{connA, connB}, + maker: maker, + } + + nextArgs := config.Args{ + Mode: omode.GrepClient, + What: "/tmp/new.log", + RegexStr: "WARN", + } + nextSpec := SessionSpec{ + Mode: omode.GrepClient, + Files: []string{"/tmp/new.log"}, + Regex: "WARN", + } + + err := client.applyInteractiveReload(nextArgs, nextSpec) + if err == nil || err.Error() != "mismatched committed generations: got 4 and 5" { + t.Fatalf("expected mismatched generation error, got %v", err) + } + if client.Args.What != "/var/log/app.log" || client.sessionSpec.Regex != "ERROR" { + t.Fatalf("client state changed on mismatched generations: args=%#v spec=%#v", client.Args, client.sessionSpec) + } + if len(maker.commits) != 0 { + t.Fatalf("expected no committed shared state, got %#v", maker.commits) + } +} + type interactiveReloadConnector struct { appliedSpec sessionspec.Spec applyErr error |
