feat(go): add single-shot Write2 session helper (§4.1)
Add Write2/Write2Raw to the Go client Session, mirroring the existing Write/WriteRaw pair, so all five language clients now expose write2. Includes three TDD tests covering payload propagation, raw-reply return, and nil-value rejection.
This commit is contained in:
@@ -363,6 +363,89 @@ func TestBulkMethodsShortCircuitOnEmptySliceWithoutRoundTrip(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrite2BuildsCommandWithTimestampAndReturnsNoError(t *testing.T) {
|
||||
fake := &fakeGatewayServer{
|
||||
invokeReply: &pb.MxCommandReply{
|
||||
SessionId: "session-1",
|
||||
Kind: pb.MxCommandKind_MX_COMMAND_KIND_WRITE2,
|
||||
ProtocolStatus: &pb.ProtocolStatus{
|
||||
Code: pb.ProtocolStatusCode_PROTOCOL_STATUS_CODE_OK,
|
||||
},
|
||||
},
|
||||
}
|
||||
client, cleanup := newBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
session := NewSessionForID(client, "session-1")
|
||||
|
||||
val := Int32Value(99)
|
||||
ts := Int32Value(77)
|
||||
err := session.Write2(context.Background(), 12, 34, val, ts, 100)
|
||||
if err != nil {
|
||||
t.Fatalf("Write2() error = %v", err)
|
||||
}
|
||||
|
||||
req := fake.invokeRequest
|
||||
if req.GetCommand().GetKind() != pb.MxCommandKind_MX_COMMAND_KIND_WRITE2 {
|
||||
t.Fatalf("command kind = %s, want WRITE2", req.GetCommand().GetKind())
|
||||
}
|
||||
w2 := req.GetCommand().GetWrite2()
|
||||
if w2.GetServerHandle() != 12 {
|
||||
t.Fatalf("server handle = %d, want 12", w2.GetServerHandle())
|
||||
}
|
||||
if w2.GetItemHandle() != 34 {
|
||||
t.Fatalf("item handle = %d, want 34", w2.GetItemHandle())
|
||||
}
|
||||
if w2.GetValue().GetInt32Value() != 99 {
|
||||
t.Fatalf("value int32 = %d, want 99", w2.GetValue().GetInt32Value())
|
||||
}
|
||||
if w2.GetTimestampValue().GetInt32Value() != 77 {
|
||||
t.Fatalf("timestamp value int32 = %d, want 77", w2.GetTimestampValue().GetInt32Value())
|
||||
}
|
||||
if w2.GetUserId() != 100 {
|
||||
t.Fatalf("user id = %d, want 100", w2.GetUserId())
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrite2RawReturnsRawReply(t *testing.T) {
|
||||
fake := &fakeGatewayServer{
|
||||
invokeReply: &pb.MxCommandReply{
|
||||
SessionId: "session-1",
|
||||
Kind: pb.MxCommandKind_MX_COMMAND_KIND_WRITE2,
|
||||
ProtocolStatus: &pb.ProtocolStatus{
|
||||
Code: pb.ProtocolStatusCode_PROTOCOL_STATUS_CODE_OK,
|
||||
},
|
||||
},
|
||||
}
|
||||
client, cleanup := newBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
session := NewSessionForID(client, "session-1")
|
||||
|
||||
reply, err := session.Write2Raw(context.Background(), 12, 34, Int32Value(1), Int32Value(0), 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Write2Raw() error = %v", err)
|
||||
}
|
||||
if reply == nil {
|
||||
t.Fatal("Write2Raw() returned nil reply")
|
||||
}
|
||||
if reply.GetKind() != pb.MxCommandKind_MX_COMMAND_KIND_WRITE2 {
|
||||
t.Fatalf("reply kind = %s, want WRITE2", reply.GetKind())
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrite2RejectsNilValue(t *testing.T) {
|
||||
fake := &fakeGatewayServer{}
|
||||
client, cleanup := newBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
session := NewSessionForID(client, "session-1")
|
||||
|
||||
if err := session.Write2(context.Background(), 12, 34, nil, Int32Value(0), 0); err == nil {
|
||||
t.Fatal("Write2(nil value) returned no error")
|
||||
}
|
||||
if err := session.Write2(context.Background(), 12, 34, Int32Value(1), nil, 0); err == nil {
|
||||
t.Fatal("Write2(nil timestampValue) returned no error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadBulkForwardsTimeoutAndUnpacksCachedFlag(t *testing.T) {
|
||||
fake := &fakeGatewayServer{
|
||||
invokeReply: &pb.MxCommandReply{
|
||||
|
||||
@@ -580,6 +580,35 @@ func (s *Session) WriteRaw(ctx context.Context, serverHandle, itemHandle int32,
|
||||
})
|
||||
}
|
||||
|
||||
// Write2 invokes MXAccess Write2 (timestamped single-item write).
|
||||
func (s *Session) Write2(ctx context.Context, serverHandle, itemHandle int32, value, timestampValue *MxValue, userID int32) error {
|
||||
_, err := s.Write2Raw(ctx, serverHandle, itemHandle, value, timestampValue, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// Write2Raw invokes MXAccess Write2 (timestamped single-item write) and returns the raw reply.
|
||||
func (s *Session) Write2Raw(ctx context.Context, serverHandle, itemHandle int32, value, timestampValue *MxValue, userID int32) (*MxCommandReply, error) {
|
||||
if value == nil {
|
||||
return nil, errors.New("mxgateway: write2 value is required")
|
||||
}
|
||||
if timestampValue == nil {
|
||||
return nil, errors.New("mxgateway: write2 timestamp value is required")
|
||||
}
|
||||
|
||||
return s.invokeCommand(ctx, &pb.MxCommand{
|
||||
Kind: pb.MxCommandKind_MX_COMMAND_KIND_WRITE2,
|
||||
Payload: &pb.MxCommand_Write2{
|
||||
Write2: &pb.Write2Command{
|
||||
ServerHandle: serverHandle,
|
||||
ItemHandle: itemHandle,
|
||||
Value: value,
|
||||
TimestampValue: timestampValue,
|
||||
UserId: userID,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Events streams ordered session events until the server ends the stream,
|
||||
// context cancellation stops Recv, or a terminal error is sent.
|
||||
func (s *Session) Events(ctx context.Context) (<-chan EventResult, error) {
|
||||
|
||||
Reference in New Issue
Block a user