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

alexstocks pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git

commit 725897ed9d01ce1ad351f49e74066d0cf51e5dff
Author: Sirui Huang <[email protected]>
AuthorDate: Sun Dec 21 10:55:20 2025 +0800

    add the unit test (#3121)
---
 client/action_test.go |  99 ++++++++++++++++++++++++++
 client/client_test.go | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 293 insertions(+)

diff --git a/client/action_test.go b/client/action_test.go
new file mode 100644
index 000000000..c6ef042a6
--- /dev/null
+++ b/client/action_test.go
@@ -0,0 +1,99 @@
+/*
+ * 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 client
+
+import (
+       "os"
+       "strconv"
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/require"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/global"
+)
+
+func TestGetEnv(t *testing.T) {
+       key := "TEST_GET_ENV_KEY"
+       _ = os.Unsetenv(key)
+       require.Equal(t, "fallback", getEnv(key, "fallback"))
+
+       require.NoError(t, os.Setenv(key, "value"))
+       defer os.Unsetenv(key)
+       require.Equal(t, "value", getEnv(key, "fallback"))
+}
+
+func TestUpdateOrCreateMeshURL(t *testing.T) {
+       t.Run("mesh disabled", func(t *testing.T) {
+               refOpts := &ReferenceOptions{
+                       Reference: &global.ReferenceConfig{URL: ""},
+                       Consumer:  &global.ConsumerConfig{MeshEnabled: false},
+               }
+               updateOrCreateMeshURL(refOpts)
+               require.Equal(t, "", refOpts.Reference.URL)
+       })
+
+       t.Run("mesh enabled build url", func(t *testing.T) {
+               defer os.Unsetenv(constant.PodNamespaceEnvKey)
+               defer os.Unsetenv(constant.ClusterDomainKey)
+               require.NoError(t, os.Setenv(constant.PodNamespaceEnvKey, "ns"))
+               require.NoError(t, os.Setenv(constant.ClusterDomainKey, 
"cluster.local"))
+
+               refOpts := &ReferenceOptions{
+                       Reference: &global.ReferenceConfig{
+                               Protocol:         constant.TriProtocol,
+                               ProvidedBy:       "svc",
+                               MeshProviderPort: 0,
+                       },
+                       Consumer: &global.ConsumerConfig{MeshEnabled: true},
+               }
+               updateOrCreateMeshURL(refOpts)
+               expected := "tri://svc.ns" + constant.SVC + "cluster.local:" + 
strconv.Itoa(constant.DefaultMeshPort)
+               require.Equal(t, expected, refOpts.Reference.URL)
+       })
+
+       t.Run("panic non tri protocol", func(t *testing.T) {
+               refOpts := &ReferenceOptions{
+                       Reference: &global.ReferenceConfig{
+                               Protocol:   "dubbo",
+                               ProvidedBy: "svc",
+                       },
+                       Consumer: &global.ConsumerConfig{MeshEnabled: true},
+               }
+               require.Panics(t, func() {
+                       updateOrCreateMeshURL(refOpts)
+               })
+       })
+
+       t.Run("panic empty providedBy", func(t *testing.T) {
+               refOpts := &ReferenceOptions{
+                       Reference: &global.ReferenceConfig{
+                               Protocol:   constant.TriProtocol,
+                               ProvidedBy: "",
+                       },
+                       Consumer: &global.ConsumerConfig{MeshEnabled: true},
+               }
+               require.Panics(t, func() {
+                       updateOrCreateMeshURL(refOpts)
+               })
+       })
+}
diff --git a/client/client_test.go b/client/client_test.go
new file mode 100644
index 000000000..699f314bf
--- /dev/null
+++ b/client/client_test.go
@@ -0,0 +1,194 @@
+/*
+ * 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 client
+
+import (
+       "context"
+       "errors"
+       "testing"
+       "time"
+)
+
+import (
+       "github.com/stretchr/testify/require"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/protocol/base"
+       "dubbo.apache.org/dubbo-go/v3/protocol/result"
+)
+
+type fakeInvoker struct {
+       lastCtx        context.Context
+       lastInvocation base.Invocation
+       res            result.Result
+}
+
+func (f *fakeInvoker) GetURL() *common.URL {
+       return nil
+}
+
+func (f *fakeInvoker) IsAvailable() bool {
+       return true
+}
+
+func (f *fakeInvoker) Destroy() {}
+
+func (f *fakeInvoker) Invoke(ctx context.Context, inv base.Invocation) 
result.Result {
+       f.lastCtx = ctx
+       f.lastInvocation = inv
+       return f.res
+}
+
+func TestClientDefinitionConnection(t *testing.T) {
+       var def ClientDefinition
+       conn, err := def.GetConnection()
+       require.Error(t, err)
+       require.Nil(t, conn)
+
+       expectedConn := &Connection{}
+       def.SetConnection(expectedConn)
+       gotConn, err := def.GetConnection()
+       require.NoError(t, err)
+       require.Equal(t, expectedConn, gotConn)
+}
+
+func TestGenerateInvocation(t *testing.T) {
+       resp := new(int)
+       opts := &CallOptions{RequestTimeout: "1s", Retries: "2"}
+
+       inv, err := generateInvocation("Echo", []any{"foo", 1}, resp, 
constant.CallUnary, opts)
+       require.NoError(t, err)
+
+       timeout, _ := inv.GetAttachment(constant.TimeoutKey)
+       retries, _ := inv.GetAttachment(constant.RetriesKey)
+       require.Equal(t, "1s", timeout)
+       require.Equal(t, "2", retries)
+
+       attr, ok := inv.GetAttribute(constant.CallTypeKey)
+       require.True(t, ok)
+       require.Equal(t, constant.CallUnary, attr)
+
+       require.Equal(t, []any{"foo", 1}, inv.Arguments())
+       require.Equal(t, resp, inv.Reply())
+       require.Equal(t, []any{"foo", 1, resp}, inv.ParameterRawValues())
+}
+
+func TestConnectionCallPassesOptions(t *testing.T) {
+       invRes := &result.RPCResult{}
+       invoker := &fakeInvoker{res: invRes}
+       conn := &Connection{refOpts: &ReferenceOptions{invoker: invoker}}
+
+       resp := new(string)
+       res, err := conn.call(context.Background(), []any{"req"}, resp, "Ping", 
constant.CallUnary, WithCallRequestTimeout(1500*time.Millisecond), 
WithCallRetries(3))
+       require.NoError(t, err)
+       require.Equal(t, invRes, res)
+
+       inv := invoker.lastInvocation
+       timeout, _ := inv.GetAttachment(constant.TimeoutKey)
+       retries, _ := inv.GetAttachment(constant.RetriesKey)
+       require.Equal(t, "1.5s", timeout)
+       require.Equal(t, "3", retries)
+
+       requireCallType(t, inv, constant.CallUnary)
+       require.Equal(t, []any{"req", resp}, inv.ParameterRawValues())
+}
+
+func TestCallUnary(t *testing.T) {
+       t.Run("success", func(t *testing.T) {
+               invoker := &fakeInvoker{res: &result.RPCResult{}}
+               conn := &Connection{refOpts: &ReferenceOptions{invoker: 
invoker}}
+
+               resp := new(string)
+               err := conn.CallUnary(context.Background(), []any{"a"}, resp, 
"Unary")
+               require.NoError(t, err)
+               requireCallType(t, invoker.lastInvocation, constant.CallUnary)
+               require.Equal(t, []any{"a", resp}, 
invoker.lastInvocation.ParameterRawValues())
+       })
+
+       t.Run("error", func(t *testing.T) {
+               resErr := errors.New("fail")
+               invoker := &fakeInvoker{res: &result.RPCResult{Err: resErr}}
+               conn := &Connection{refOpts: &ReferenceOptions{invoker: 
invoker}}
+
+               err := conn.CallUnary(context.Background(), []any{"a"}, 
new(string), "Unary")
+               require.ErrorIs(t, err, resErr)
+       })
+}
+
+func TestCallClientStream(t *testing.T) {
+       resVal := "stream"
+       invoker := &fakeInvoker{res: &result.RPCResult{Rest: resVal}}
+       conn := &Connection{refOpts: &ReferenceOptions{invoker: invoker}}
+
+       out, err := conn.CallClientStream(context.Background(), "ClientStream")
+       require.NoError(t, err)
+       require.Equal(t, resVal, out)
+
+       requireCallType(t, invoker.lastInvocation, constant.CallClientStream)
+       require.Empty(t, invoker.lastInvocation.ParameterRawValues())
+}
+
+func TestCallServerStream(t *testing.T) {
+       t.Run("success", func(t *testing.T) {
+               req := "payload"
+               resVal := "server-stream"
+               invoker := &fakeInvoker{res: &result.RPCResult{Rest: resVal}}
+               conn := &Connection{refOpts: &ReferenceOptions{invoker: 
invoker}}
+
+               out, err := conn.CallServerStream(context.Background(), req, 
"ServerStream")
+               require.NoError(t, err)
+               require.Equal(t, resVal, out)
+
+               requireCallType(t, invoker.lastInvocation, 
constant.CallServerStream)
+               require.Equal(t, []any{req}, 
invoker.lastInvocation.ParameterRawValues())
+       })
+
+       t.Run("error", func(t *testing.T) {
+               req := "payload"
+               resErr := errors.New("stream err")
+               invoker := &fakeInvoker{res: &result.RPCResult{Err: resErr}}
+               conn := &Connection{refOpts: &ReferenceOptions{invoker: 
invoker}}
+
+               out, err := conn.CallServerStream(context.Background(), req, 
"ServerStream")
+               require.ErrorIs(t, err, resErr)
+               require.Nil(t, out)
+       })
+}
+
+func TestCallBidiStream(t *testing.T) {
+       resVal := "bidi"
+       invoker := &fakeInvoker{res: &result.RPCResult{Rest: resVal}}
+       conn := &Connection{refOpts: &ReferenceOptions{invoker: invoker}}
+
+       out, err := conn.CallBidiStream(context.Background(), "Bidi")
+       require.NoError(t, err)
+       require.Equal(t, resVal, out)
+
+       requireCallType(t, invoker.lastInvocation, constant.CallBidiStream)
+       require.Empty(t, invoker.lastInvocation.ParameterRawValues())
+}
+
+func requireCallType(t *testing.T, inv base.Invocation, callType string) {
+       t.Helper()
+       attr, ok := inv.GetAttribute(constant.CallTypeKey)
+       require.True(t, ok)
+       require.Equal(t, callType, attr)
+}

Reply via email to