package agent import ( "context" "errors" "testing" "time" rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1" "github.com/rvbox/rvbox/internal/agentproto" "github.com/rvbox/rvbox/internal/domain" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" ) func TestHandshakeHelloWelcome_HP_SES_07(t *testing.T) { t.Parallel() welcome := &rvboxv1.AgentEnvelope{SessionId: "issued-session", SessionGeneration: 7, Payload: &rvboxv1.AgentEnvelope_ServerWelcome{ServerWelcome: &rvboxv1.ServerWelcome{SelectedProtocol: &rvboxv1.ProtocolVersion{Major: 1, Minor: 0}, ServerTime: timestamppb.New(time.Date(2026, time.September, 6, 0, 0, 0, 0, time.UTC))}}} encoded, err := proto.Marshal(welcome) if err != nil { t.Fatal(err) } transport := &fakeTransport{read: encoded} session, err := Handshake(context.Background(), transport, validHello(), agentproto.DefaultLimits()) if err != nil { t.Fatal(err) } if session.ID != "issued-session" || session.Generation != 7 || session.Protocol.GetMajor() != 1 { t.Fatalf("session = %#v", session) } var sent rvboxv1.AgentEnvelope if err := proto.Unmarshal(transport.written, &sent); err != nil || sent.GetClientHello() == nil || sent.GetSessionId() != "" || sent.GetSessionGeneration() != 0 { t.Fatalf("sent ClientHello valid=%t session=%q generation=%d err=%v", sent.GetClientHello() != nil, sent.GetSessionId(), sent.GetSessionGeneration(), err) } } func TestHandshakeRejectsNonWelcome_BH_SES_07(t *testing.T) { t.Parallel() bad := &rvboxv1.AgentEnvelope{SessionId: "issued-session", SessionGeneration: 7, Payload: &rvboxv1.AgentEnvelope_ClientCapacity{ClientCapacity: &rvboxv1.ClientCapacity{MaxRunningCommands: 1, MaxQueuedCommands: 1}}} encoded, err := proto.Marshal(bad) if err != nil { t.Fatal(err) } _, err = Handshake(context.Background(), &fakeTransport{read: encoded}, validHello(), agentproto.DefaultLimits()) if !errors.Is(err, ErrProtocolHandshake) { t.Fatalf("non-welcome handshake error = %v, want ErrProtocolHandshake", err) } } func TestReconcileSnapshot_HP_SES_08(t *testing.T) { t.Parallel() result := &rvboxv1.AgentEnvelope{SessionId: "issued-session", SessionGeneration: 7, Payload: &rvboxv1.AgentEnvelope_ReconcileResult{ReconcileResult: &rvboxv1.ReconcileResult{}}} encoded, err := proto.Marshal(result) if err != nil { t.Fatal(err) } transport := &fakeTransport{read: encoded} reconciled, err := Reconcile(context.Background(), transport, Session{ID: "issued-session", Generation: 7}, &rvboxv1.ReconcileSnapshot{}, agentproto.DefaultLimits()) if err != nil || reconciled == nil { t.Fatalf("Reconcile = %#v, %v", reconciled, err) } var sent rvboxv1.AgentEnvelope if err := proto.Unmarshal(transport.written, &sent); err != nil || sent.GetReconcileSnapshot() == nil || sent.GetSessionId() != "issued-session" || sent.GetSessionGeneration() != 7 { t.Fatalf("sent snapshot valid=%t session=%q generation=%d err=%v", sent.GetReconcileSnapshot() != nil, sent.GetSessionId(), sent.GetSessionGeneration(), err) } } func TestApplyReconcileResult_HP_SES_12(t *testing.T) { t.Parallel() active := "019c46f1-1d02-7000-8000-000000000062" terminal := "019c46f1-1d02-7000-8000-000000000063" store := &reconcileStore{} terminated, err := ApplyReconcileResult(context.Background(), store, &rvboxv1.ReconcileResult{ TerminateLocalIssueUuids: []string{active}, DiscardLocalTerminalIssueUuids: []string{terminal}, }, time.Date(2026, time.September, 6, 0, 0, 0, 0, time.UTC)) if err != nil || len(terminated) != 1 || terminated[0].String() != active || len(store.discarded) != 1 || store.discarded[0].String() != terminal { t.Fatalf("ApplyReconcileResult = terminated=%v discarded=%v err=%v", terminated, store.discarded, err) } if _, err := ApplyReconcileResult(context.Background(), store, &rvboxv1.ReconcileResult{TerminateLocalIssueUuids: []string{active}, DiscardLocalTerminalIssueUuids: []string{active}}, time.Now()); !errors.Is(err, ErrInvalidReconcileResult) { t.Fatalf("overlapping result error = %v", err) } } type fakeTransport struct { written []byte read []byte } type reconcileStore struct{ discarded []domain.UUID } func (store *reconcileStore) DiscardTerminal(_ context.Context, issue domain.UUID, _ time.Time) error { store.discarded = append(store.discarded, issue) return nil } func (transport *fakeTransport) Write(_ context.Context, value []byte) error { transport.written = append([]byte(nil), value...) return nil } func (transport *fakeTransport) Read(context.Context) ([]byte, error) { if transport.read == nil { return nil, ErrSessionClosed } return append([]byte(nil), transport.read...), nil } func (transport *fakeTransport) Close() error { return nil } func validHello() *rvboxv1.ClientHello { return &rvboxv1.ClientHello{ClientId: "win-client", SupportedProtocol: &rvboxv1.ProtocolRange{Major: 1, MinMinor: 0, MaxMinor: 0}, DaemonVersion: "test", Platform: rvboxv1.Platform_PLATFORM_WINDOWS, Architecture: "amd64", DaemonCwd: `C:\`, SupportedShells: []rvboxv1.ShellType{rvboxv1.ShellType_SHELL_POWERSHELL}, ClientInstanceId: "019c46f1-1d02-7000-8000-000000000061", MaxRunningCommands: 1, MaxQueuedCommands: 1, SentAt: timestamppb.Now()} }