This is an automated email from the ASF dual-hosted git repository.

jimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-seata-go.git


The following commit(s) were added to refs/heads/master by this push:
     new 075cb83c test: improve test coverage for pkg/integration/grpc (#970)
075cb83c is described below

commit 075cb83c20bd70d73353c8d503f22986c65003c2
Author: EVERFID <[email protected]>
AuthorDate: Wed Nov 5 11:23:25 2025 +0800

    test: improve test coverage for pkg/integration/grpc (#970)
---
 .../grpc/grpc_transaction_interceptor_test.go      | 354 +++++++++++++++++++++
 1 file changed, 354 insertions(+)

diff --git a/pkg/integration/grpc/grpc_transaction_interceptor_test.go 
b/pkg/integration/grpc/grpc_transaction_interceptor_test.go
new file mode 100644
index 00000000..a4579d53
--- /dev/null
+++ b/pkg/integration/grpc/grpc_transaction_interceptor_test.go
@@ -0,0 +1,354 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package grpc
+
+import (
+       "context"
+       "errors"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "google.golang.org/grpc"
+       "google.golang.org/grpc/metadata"
+
+       "seata.apache.org/seata-go/pkg/constant"
+       "seata.apache.org/seata-go/pkg/tm"
+)
+
+func TestClientTransactionInterceptor_WithSeataContext(t *testing.T) {
+       ctx := tm.InitSeataContext(context.Background())
+       tm.SetXID(ctx, "test-client-xid-123")
+
+       invoked := false
+       var capturedCtx context.Context
+
+       mockInvoker := func(ctx context.Context, method string, req, reply 
interface{},
+               cc *grpc.ClientConn, opts ...grpc.CallOption) error {
+               invoked = true
+               capturedCtx = ctx
+               return nil
+       }
+
+       err := ClientTransactionInterceptor(ctx, "/test.Service/Method", nil, 
nil, nil, mockInvoker)
+
+       assert.NoError(t, err)
+       assert.True(t, invoked)
+       assert.NotNil(t, capturedCtx)
+
+       // Verify XID was added to metadata
+       md, ok := metadata.FromOutgoingContext(capturedCtx)
+       assert.True(t, ok)
+       xidSlice := md.Get(constant.XidKey)
+       assert.NotEmpty(t, xidSlice)
+       assert.Equal(t, "test-client-xid-123", xidSlice[0])
+}
+
+func TestClientTransactionInterceptor_WithoutSeataContext(t *testing.T) {
+       ctx := context.Background()
+
+       invoked := false
+       var capturedCtx context.Context
+
+       mockInvoker := func(ctx context.Context, method string, req, reply 
interface{},
+               cc *grpc.ClientConn, opts ...grpc.CallOption) error {
+               invoked = true
+               capturedCtx = ctx
+               return nil
+       }
+
+       err := ClientTransactionInterceptor(ctx, "/test.Service/Method", nil, 
nil, nil, mockInvoker)
+
+       assert.NoError(t, err)
+       assert.True(t, invoked)
+       assert.NotNil(t, capturedCtx)
+
+       // Verify no XID metadata was added
+       md, ok := metadata.FromOutgoingContext(capturedCtx)
+       if ok {
+               xidSlice := md.Get(constant.XidKey)
+               assert.Empty(t, xidSlice)
+       }
+}
+
+func TestClientTransactionInterceptor_InvokerError(t *testing.T) {
+       ctx := tm.InitSeataContext(context.Background())
+       tm.SetXID(ctx, "test-xid")
+
+       expectedErr := errors.New("mock invoker error")
+       mockInvoker := func(ctx context.Context, method string, req, reply 
interface{},
+               cc *grpc.ClientConn, opts ...grpc.CallOption) error {
+               return expectedErr
+       }
+
+       err := ClientTransactionInterceptor(ctx, "/test.Service/Method", nil, 
nil, nil, mockInvoker)
+
+       assert.Error(t, err)
+       assert.Equal(t, expectedErr, err)
+}
+
+func TestClientTransactionInterceptor_EmptyXID(t *testing.T) {
+       ctx := tm.InitSeataContext(context.Background())
+       tm.SetXID(ctx, "")
+
+       var capturedCtx context.Context
+       mockInvoker := func(ctx context.Context, method string, req, reply 
interface{},
+               cc *grpc.ClientConn, opts ...grpc.CallOption) error {
+               capturedCtx = ctx
+               return nil
+       }
+
+       err := ClientTransactionInterceptor(ctx, "/test.Service/Method", nil, 
nil, nil, mockInvoker)
+
+       assert.NoError(t, err)
+
+       // Even with empty XID, metadata should be set if Seata context exists
+       _, ok := metadata.FromOutgoingContext(capturedCtx)
+       assert.True(t, ok)
+}
+
+func TestServerTransactionInterceptor_WithXidKey(t *testing.T) {
+       md := metadata.New(map[string]string{
+               constant.XidKey: "server-xid-456",
+       })
+       ctx := metadata.NewIncomingContext(context.Background(), md)
+
+       handlerCalled := false
+       var handlerCtx context.Context
+
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCalled = true
+               handlerCtx = ctx
+               return "response", nil
+       }
+
+       resp, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+       assert.True(t, handlerCalled)
+       assert.Equal(t, "response", resp)
+       assert.NotNil(t, handlerCtx)
+
+       // Verify XID was set in context
+       xid := tm.GetXID(handlerCtx)
+       assert.Equal(t, "server-xid-456", xid)
+}
+
+func TestServerTransactionInterceptor_WithXidKeyLowercase(t *testing.T) {
+       md := metadata.New(map[string]string{
+               constant.XidKeyLowercase: "server-xid-lowercase-789",
+       })
+       ctx := metadata.NewIncomingContext(context.Background(), md)
+
+       var handlerCtx context.Context
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCtx = ctx
+               return "response", nil
+       }
+
+       resp, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+       assert.Equal(t, "response", resp)
+
+       xid := tm.GetXID(handlerCtx)
+       assert.Equal(t, "server-xid-lowercase-789", xid)
+}
+
+func TestServerTransactionInterceptor_XidKeyPrecedence(t *testing.T) {
+       md := metadata.New(map[string]string{
+               constant.XidKey:          "primary-xid",
+               constant.XidKeyLowercase: "secondary-xid",
+       })
+       ctx := metadata.NewIncomingContext(context.Background(), md)
+
+       var handlerCtx context.Context
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCtx = ctx
+               return "response", nil
+       }
+
+       _, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+
+       xid := tm.GetXID(handlerCtx)
+       assert.Equal(t, "primary-xid", xid)
+}
+
+func TestServerTransactionInterceptor_NoMetadata(t *testing.T) {
+       ctx := context.Background()
+
+       handlerCalled := false
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCalled = true
+               return "response", nil
+       }
+
+       resp, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+       assert.True(t, handlerCalled)
+       assert.Equal(t, "response", resp)
+}
+
+func TestServerTransactionInterceptor_NilMetadataSlice(t *testing.T) {
+       ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{})
+
+       handlerCalled := false
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCalled = true
+               return "response", nil
+       }
+
+       resp, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+       assert.True(t, handlerCalled)
+       assert.Equal(t, "response", resp)
+}
+
+func TestServerTransactionInterceptor_EmptyXid(t *testing.T) {
+       md := metadata.New(map[string]string{
+               constant.XidKey: "",
+       })
+       ctx := metadata.NewIncomingContext(context.Background(), md)
+
+       handlerCalled := false
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCalled = true
+               return "response", nil
+       }
+
+       resp, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+       assert.True(t, handlerCalled)
+       assert.Equal(t, "response", resp)
+}
+
+func TestServerTransactionInterceptor_OnlyLowercaseXid(t *testing.T) {
+       md := metadata.New(map[string]string{
+               constant.XidKeyLowercase: "fallback-xid",
+       })
+       ctx := metadata.NewIncomingContext(context.Background(), md)
+
+       var handlerCtx context.Context
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCtx = ctx
+               return "response", nil
+       }
+
+       _, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+
+       xid := tm.GetXID(handlerCtx)
+       assert.Equal(t, "fallback-xid", xid)
+}
+
+func TestServerTransactionInterceptor_HandlerError(t *testing.T) {
+       md := metadata.New(map[string]string{
+               constant.XidKey: "test-xid",
+       })
+       ctx := metadata.NewIncomingContext(context.Background(), md)
+
+       expectedErr := errors.New("handler error")
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               return nil, expectedErr
+       }
+
+       resp, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.Error(t, err)
+       assert.Equal(t, expectedErr, err)
+       assert.Nil(t, resp)
+}
+
+func TestServerTransactionInterceptor_MultipleXidValues(t *testing.T) {
+       md := metadata.MD{
+               constant.XidKey: []string{"xid-1", "xid-2", "xid-3"},
+       }
+       ctx := metadata.NewIncomingContext(context.Background(), md)
+
+       var handlerCtx context.Context
+       mockHandler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               handlerCtx = ctx
+               return "response", nil
+       }
+
+       _, err := ServerTransactionInterceptor(ctx, nil, nil, mockHandler)
+
+       assert.NoError(t, err)
+
+       // Should use the first value
+       xid := tm.GetXID(handlerCtx)
+       assert.Equal(t, "xid-1", xid)
+}
+
+func TestClientTransactionInterceptor_Timing(t *testing.T) {
+       ctx := tm.InitSeataContext(context.Background())
+       tm.SetXID(ctx, "timing-test-xid")
+
+       mockInvoker := func(ctx context.Context, method string, req, reply 
interface{},
+               cc *grpc.ClientConn, opts ...grpc.CallOption) error {
+               // Simulate some work
+               return nil
+       }
+
+       err := ClientTransactionInterceptor(ctx, "/test.Service/Method", nil, 
nil, nil, mockInvoker)
+
+       assert.NoError(t, err)
+}
+
+func TestClientAndServerInterceptor_Integration(t *testing.T) {
+       // Simulate client sending request
+       clientCtx := tm.InitSeataContext(context.Background())
+       tm.SetXID(clientCtx, "integration-xid-999")
+
+       var serverCtx context.Context
+
+       // Mock client invoker that simulates server receiving the request
+       mockInvoker := func(ctx context.Context, method string, req, reply 
interface{},
+               cc *grpc.ClientConn, opts ...grpc.CallOption) error {
+
+               // Extract metadata from client context
+               md, ok := metadata.FromOutgoingContext(ctx)
+               assert.True(t, ok)
+
+               // Simulate server receiving this metadata
+               incomingCtx := 
metadata.NewIncomingContext(context.Background(), md)
+
+               // Server interceptor processes it
+               mockHandler := func(ctx context.Context, req interface{}) 
(interface{}, error) {
+                       serverCtx = ctx
+                       return "ok", nil
+               }
+
+               _, err := ServerTransactionInterceptor(incomingCtx, req, nil, 
mockHandler)
+               return err
+       }
+
+       err := ClientTransactionInterceptor(clientCtx, "/test.Service/Method", 
nil, nil, nil, mockInvoker)
+
+       assert.NoError(t, err)
+       assert.NotNil(t, serverCtx)
+
+       // Verify XID propagated from client to server
+       serverXid := tm.GetXID(serverCtx)
+       assert.Equal(t, "integration-xid-999", serverXid)
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to