From e25d23e241bee89522eec395fe4b7e80b4556809 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Mon, 20 Jan 2025 09:46:02 +0000 Subject: [PATCH 01/15] Custom Cmd(Generic Cluster cmd), Ping with Route Signed-off-by: Niharika Bhavaraju --- .../connection_management_cluster_commands.go | 14 +++ go/api/generic_cluster_commands.go | 2 + go/api/glide_cluster_client.go | 92 ++++++++++++++++ go/integTest/cluster_commands_test.go | 104 ++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 go/api/connection_management_cluster_commands.go diff --git a/go/api/connection_management_cluster_commands.go b/go/api/connection_management_cluster_commands.go new file mode 100644 index 0000000000..5790429622 --- /dev/null +++ b/go/api/connection_management_cluster_commands.go @@ -0,0 +1,14 @@ +// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 + +package api + +// Supports commands and transactions for the "Connection Management" group of commands for cluster client. +// +// See [valkey.io] for details. +// +// [valkey.io]: https://valkey.io/commands/#connection +type ConnectionManagementClusterCommands interface { + PingWithRoute(route route) (string, error) + + PingWithMessageRoute(message string, route route) (string, error) +} diff --git a/go/api/generic_cluster_commands.go b/go/api/generic_cluster_commands.go index cd46fca42b..85d9929782 100644 --- a/go/api/generic_cluster_commands.go +++ b/go/api/generic_cluster_commands.go @@ -34,4 +34,6 @@ type GenericClusterCommands interface { // // [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command CustomCommand(args []string) (ClusterValue[interface{}], error) + + CustomCommandWithRoute(args []string, route route) (ClusterValue[interface{}], error) } diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index cc672a91b5..ea677bdcc3 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -13,6 +13,7 @@ var _ GlideClusterClient = (*glideClusterClient)(nil) type GlideClusterClient interface { BaseClient GenericClusterCommands + ConnectionManagementClusterCommands } // glideClusterClient implements cluster mode operations by extending baseClient functionality. @@ -41,3 +42,94 @@ func (client *glideClusterClient) CustomCommand(args []string) (ClusterValue[int } return CreateClusterValue(data), nil } + +// CustomCommandWithRoute executes a single command, specified by args, without checking inputs. Every part of the command, +// including the command name and subcommands, should be added as a separate value in args. The returning value depends on +// the executed +// command. +// +// The command will be routed automatically based on the passed command's default request policy. +// +// See [Valkey GLIDE Wiki] for details on the restrictions and limitations of the custom command API. +// +// Parameters: +// +// args - Arguments for the custom command including the command name. +// route - Specifies the routing configuration for the command. The client will route the +// command to the nodes defined by route. +// +// Return value: +// +// The returning value depends on the executed command and route. +// +// For example: +// +// route := api.SimpleNodeRoute(api.RandomRoute) +// result, err := client.CustomCommand([]string{"ping"}, route) +// result.Value().(string): "PONG" +// +// [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command +func (client *glideClusterClient) CustomCommandWithRoute(args []string, route route) (ClusterValue[interface{}], error) { + res, err := client.executeCommandWithRoute(C.CustomCommand, args, route) + if err != nil { + return CreateEmptyClusterValue(), err + } + data, err := handleInterfaceResponse(res) + if err != nil { + return CreateEmptyClusterValue(), err + } + return CreateClusterValue(data), nil +} + +// Pings the server. +// +// Parameters: +// +// route - Specifies the routing configuration for the command. +// The client will route the command to the nodes defined by route. +// +// Return value: +// +// Returns "PONG". +// +// For example: +// +// route := api.SimpleNodeRoute(api.RandomRoute) +// result, err := client.Ping(route) +// fmt.Println(result) // Output: "PONG" +// +// [valkey.io]: https://valkey.io/commands/ping/ +func (client *glideClusterClient) PingWithRoute(route route) (string, error) { + res, err := client.executeCommandWithRoute(C.Ping, []string{}, route) + if err != nil { + return defaultStringResponse, err + } + return handleStringResponse(res) +} + +// Pings the server with a custom message. +// +// Parameters: +// +// message - A message to include in the `PING` command. +// route - Specifies the routing configuration for the command. +// The client will route the command to the nodes defined by route. +// +// Return value: +// +// Returns the copy of message. +// +// For example: +// +// route := api.SimpleNodeRoute(api.RandomRoute) +// result, err := client.PingWithMessage("Hello", route) +// fmt.Println(result) // Output: "Hello" +// +// [valkey.io]: https://valkey.io/commands/ping/ +func (client *glideClusterClient) PingWithMessageRoute(message string, route route) (string, error) { + res, err := client.executeCommandWithRoute(C.Ping, []string{message}, route) + if err != nil { + return defaultStringResponse, err + } + return handleStringResponse(res) +} diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index 142f0cf273..60726868d3 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -3,9 +3,11 @@ package integTest import ( + "fmt" "strings" "github.com/stretchr/testify/assert" + "github.com/valkey-io/valkey-glide/go/glide/api" ) func (suite *GlideTestSuite) TestClusterCustomCommandInfo() { @@ -27,3 +29,105 @@ func (suite *GlideTestSuite) TestClusterCustomCommandEcho() { // ECHO is routed to a single random node assert.Equal(suite.T(), "GO GLIDE GO", result.Value().(string)) } + +func (suite *GlideTestSuite) TestPingWithRoute_ValidRoute() { + client := suite.defaultClusterClient() + route := api.SimpleNodeRoute(api.RandomRoute) + result, err := client.PingWithRoute(route) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), "PONG", result) +} + +func (suite *GlideTestSuite) TestPingWithRoute_InvalidRoute() { + client := suite.defaultClusterClient() + invalidRoute := api.NewByAddressRoute("invalidHost", 9999) + + result, err := client.PingWithRoute(invalidRoute) + + assert.NotNil(suite.T(), err) + assert.Empty(suite.T(), result) +} + +func (suite *GlideTestSuite) TestPingWithMessageRoute_ValidRoute_ValidMessage() { + client := suite.defaultClusterClient() + route := api.SimpleNodeRoute(api.RandomRoute) + + customMessage := "Hello Glide" + + result, err := client.PingWithMessageRoute(customMessage, route) + + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), customMessage, result) +} + +func (suite *GlideTestSuite) TestPingWithMessageRoute_EmptyMessage() { + client := suite.defaultClusterClient() + route := api.SimpleNodeRoute(api.RandomRoute) + + customMessage := "" + + result, err := client.PingWithMessageRoute(customMessage, route) + + assert.NoError(suite.T(), err) + + assert.Equal(suite.T(), customMessage, result) +} + +func (suite *GlideTestSuite) TestPingWithMessageRoute_InvalidRoute() { + client := suite.defaultClusterClient() + invalidRoute := api.NewByAddressRoute("invalidHost", 9999) + + customMessage := "Hello Glide" + + result, err := client.PingWithMessageRoute(customMessage, invalidRoute) + + assert.NotNil(suite.T(), err) + assert.Empty(suite.T(), result) +} + +func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Info() { + client := suite.defaultClusterClient() + route := api.SimpleNodeRoute(api.AllPrimaries) + result, err := client.CustomCommandWithRoute([]string{"INFO"}, route) + assert.Nil(suite.T(), err) + for _, value := range result.Value().(map[string]interface{}) { + assert.True(suite.T(), strings.Contains(value.(string), "# Stats")) + } +} + +func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Echo() { + client := suite.defaultClusterClient() + route := api.SimpleNodeRoute(api.RandomRoute) + result, err := client.CustomCommandWithRoute([]string{"ECHO", "GO GLIDE GO"}, route) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "GO GLIDE GO", result.Value().(string)) +} + +func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_InvalidRoute() { + client := suite.defaultClusterClient() + invalidRoute := api.NewByAddressRoute("invalidHost", 9999) + result, err := client.CustomCommandWithRoute([]string{"PING"}, invalidRoute) + assert.NotNil(suite.T(), err) + assert.Equal(suite.T(), api.CreateEmptyClusterValue(), result) +} + +func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { + client := suite.defaultClusterClient() + route := api.SimpleNodeRoute(api.AllNodes) + result, err := client.CustomCommandWithRoute([]string{"PING"}, route) + + assert.Nil(suite.T(), err) + value := result.Value() + + fmt.Printf("Value type: %T\n", value) + + if result.IsMultiValue() { + responses := value.(map[string]interface{}) + assert.Greater(suite.T(), len(responses), 0) + for _, response := range responses { + assert.Equal(suite.T(), "PONG", response.(string)) + } + } else { + assert.Equal(suite.T(), "PONG", value.(string)) + } +} From b082b3001c75f45fd1ea94e9248b2b975bb56e8b Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 22 Jan 2025 11:31:28 +0000 Subject: [PATCH 02/15] Added Ping , PingWithOptions Signed-off-by: Niharika Bhavaraju --- go/api/base_client.go | 76 ++---- go/api/command_options.go | 11 +- go/api/{ => config}/request_routing_config.go | 31 +-- .../connection_management_cluster_commands.go | 6 +- go/api/connection_management_commands.go | 25 +- go/api/{ => errors}/errors.go | 43 ++-- go/api/generic_cluster_commands.go | 4 +- go/api/glide_client.go | 83 +++++++ go/api/glide_cluster_client.go | 59 ++--- go/api/options/ping_options.go | 35 +++ go/api/response_handlers.go | 42 ++-- go/integTest/cluster_commands_test.go | 112 +++++---- go/integTest/connection_test.go | 3 +- .../request_routing_config_test.go | 27 +-- go/integTest/shared_commands_test.go | 217 ++++++++---------- go/integTest/standalone_commands_test.go | 66 +++++- 16 files changed, 457 insertions(+), 383 deletions(-) rename go/api/{ => config}/request_routing_config.go (86%) rename go/api/{ => errors}/errors.go (58%) create mode 100644 go/api/options/ping_options.go rename go/{api => integTest}/request_routing_config_test.go (69%) diff --git a/go/api/base_client.go b/go/api/base_client.go index b05528fbcb..6f74f9e96f 100644 --- a/go/api/base_client.go +++ b/go/api/base_client.go @@ -10,12 +10,13 @@ package api import "C" import ( - "errors" "fmt" "math" "strconv" "unsafe" + "github.com/valkey-io/valkey-glide/go/glide/api/config" + "github.com/valkey-io/valkey-glide/go/glide/api/errors" "github.com/valkey-io/valkey-glide/go/glide/api/options" "github.com/valkey-io/valkey-glide/go/glide/protobuf" "github.com/valkey-io/valkey-glide/go/glide/utils" @@ -30,7 +31,6 @@ type BaseClient interface { SetCommands StreamCommands SortedSetCommands - ConnectionManagementCommands HyperLogLogCommands GenericBaseCommands // Close terminates the client by closing all associated resources. @@ -53,8 +53,10 @@ func successCallback(channelPtr unsafe.Pointer, cResponse *C.struct_CommandRespo //export failureCallback func failureCallback(channelPtr unsafe.Pointer, cErrorMessage *C.char, cErrorType C.RequestErrorType) { + defer C.free_error_message(cErrorMessage) + msg := C.GoString(cErrorMessage) resultChannel := *(*chan payload)(channelPtr) - resultChannel <- payload{value: nil, error: goError(cErrorType, cErrorMessage)} + resultChannel <- payload{value: nil, error: errors.GoError(uint32(cErrorType), msg)} } type clientConfiguration interface { @@ -91,7 +93,7 @@ func createClient(config clientConfiguration) (*baseClient, error) { cErr := cResponse.connection_error_message if cErr != nil { message := C.GoString(cErr) - return nil, &ConnectionError{message} + return nil, &errors.ConnectionError{message} } return &baseClient{cResponse.conn_ptr}, nil @@ -114,10 +116,10 @@ func (client *baseClient) executeCommand(requestType C.RequestType, args []strin func (client *baseClient) executeCommandWithRoute( requestType C.RequestType, args []string, - route route, + route config.Route, ) (*C.struct_CommandResponse, error) { if client.coreClient == nil { - return nil, &ClosingError{"ExecuteCommand failed. The client is closed."} + return nil, &errors.ClosingError{"ExecuteCommand failed. The client is closed."} } var cArgsPtr *C.uintptr_t = nil var argLengthsPtr *C.ulong = nil @@ -133,9 +135,9 @@ func (client *baseClient) executeCommandWithRoute( var routeBytesPtr *C.uchar = nil var routeBytesCount C.uintptr_t = 0 if route != nil { - routeProto, err := route.toRoutesProtobuf() + routeProto, err := route.ToRoutesProtobuf() if err != nil { - return nil, &RequestError{"ExecuteCommand failed due to invalid route"} + return nil, &errors.RequestError{"ExecuteCommand failed due to invalid route"} } msg, err := proto.Marshal(routeProto) if err != nil { @@ -356,7 +358,7 @@ func (client *baseClient) LCS(key1 string, key2 string) (string, error) { func (client *baseClient) GetDel(key string) (Result[string], error) { if key == "" { - return CreateNilStringResult(), errors.New("key is required") + return CreateNilStringResult(), &errors.RequestError{"key is required"} } result, err := client.executeCommand(C.GetDel, []string{key}) @@ -1033,7 +1035,7 @@ func (client *baseClient) LMPop(keys []string, listDirection ListDirection) (map // Check for potential length overflow. if len(keys) > math.MaxInt-2 { - return nil, &RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{"Length overflow for the provided keys"} } // args slice will have 2 more arguments with the keys provided. @@ -1061,7 +1063,7 @@ func (client *baseClient) LMPopCount( // Check for potential length overflow. if len(keys) > math.MaxInt-4 { - return nil, &RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{"Length overflow for the provided keys"} } // args slice will have 4 more arguments with the keys provided. @@ -1089,7 +1091,7 @@ func (client *baseClient) BLMPop( // Check for potential length overflow. if len(keys) > math.MaxInt-3 { - return nil, &RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{"Length overflow for the provided keys"} } // args slice will have 3 more arguments with the keys provided. @@ -1118,7 +1120,7 @@ func (client *baseClient) BLMPopCount( // Check for potential length overflow. if len(keys) > math.MaxInt-5 { - return nil, &RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{"Length overflow for the provided keys"} } // args slice will have 5 more arguments with the keys provided. @@ -1193,26 +1195,6 @@ func (client *baseClient) BLMove( return handleStringOrNilResponse(result) } -func (client *baseClient) Ping() (string, error) { - result, err := client.executeCommand(C.Ping, []string{}) - if err != nil { - return defaultStringResponse, err - } - - return handleStringResponse(result) -} - -func (client *baseClient) PingWithMessage(message string) (string, error) { - args := []string{message} - - result, err := client.executeCommand(C.Ping, args) - if err != nil { - return defaultStringResponse, err - } - - return handleStringResponse(result) -} - func (client *baseClient) Del(keys []string) (int64, error) { result, err := client.executeCommand(C.Del, keys) if err != nil { @@ -2608,34 +2590,6 @@ func (client *baseClient) ObjectEncoding(key string) (Result[string], error) { return handleStringOrNilResponse(result) } -// Echo the provided message back. -// The command will be routed a random node. -// -// Parameters: -// -// message - The provided message. -// -// Return value: -// -// The provided message -// -// For example: -// -// result, err := client.Echo("Hello World") -// if err != nil { -// // handle error -// } -// fmt.Println(result.Value()) // Output: Hello World -// -// [valkey.io]: https://valkey.io/commands/echo/ -func (client *baseClient) Echo(message string) (Result[string], error) { - result, err := client.executeCommand(C.Echo, []string{message}) - if err != nil { - return CreateNilStringResult(), err - } - return handleStringOrNilResponse(result) -} - // Removes all elements in the sorted set stored at `key` with a lexicographical order // between `rangeQuery.Start` and `rangeQuery.End`. // diff --git a/go/api/command_options.go b/go/api/command_options.go index dcf17446bc..3c1c6c2f85 100644 --- a/go/api/command_options.go +++ b/go/api/command_options.go @@ -5,6 +5,7 @@ package api import ( "strconv" + "github.com/valkey-io/valkey-glide/go/glide/api/errors" "github.com/valkey-io/valkey-glide/go/glide/utils" ) @@ -63,7 +64,7 @@ func (opts *SetOptions) toArgs() ([]string, error) { case KeepExisting: args = append(args, string(opts.Expiry.Type)) default: - err = &RequestError{"Invalid expiry type"} + err = &errors.RequestError{"Invalid expiry type"} } } @@ -101,7 +102,7 @@ func (opts *GetExOptions) toArgs() ([]string, error) { case Persist: args = append(args, string(opts.Expiry.Type)) default: - err = &RequestError{"Invalid expiry type"} + err = &errors.RequestError{"Invalid expiry type"} } } @@ -144,7 +145,7 @@ func (expireCondition ExpireCondition) toString() (string, error) { case NewExpiryLessThanCurrent: return string(NewExpiryLessThanCurrent), nil default: - return "", &RequestError{"Invalid expire condition"} + return "", &errors.RequestError{"Invalid expire condition"} } } @@ -254,7 +255,7 @@ func (insertPosition InsertPosition) toString() (string, error) { case After: return string(After), nil default: - return "", &RequestError{"Invalid insert position"} + return "", &errors.RequestError{"Invalid insert position"} } } @@ -275,7 +276,7 @@ func (listDirection ListDirection) toString() (string, error) { case Right: return string(Right), nil default: - return "", &RequestError{"Invalid list direction"} + return "", &errors.RequestError{"Invalid list direction"} } } diff --git a/go/api/request_routing_config.go b/go/api/config/request_routing_config.go similarity index 86% rename from go/api/request_routing_config.go rename to go/api/config/request_routing_config.go index 3a1c53b124..64f676f084 100644 --- a/go/api/request_routing_config.go +++ b/go/api/config/request_routing_config.go @@ -1,22 +1,23 @@ // Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 -package api +package config import ( "fmt" "strconv" "strings" + "github.com/valkey-io/valkey-glide/go/glide/api/errors" "github.com/valkey-io/valkey-glide/go/glide/protobuf" ) // Request routing basic interface. Please use one of the following: -// - [api.SimpleNodeRoute] -// - [api.SlotIdRoute] -// - [api.SlotKeyRoute] -// - [api.ByAddressRoute] -type route interface { - toRoutesProtobuf() (*protobuf.Routes, error) +// - [config.SimpleNodeRoute] +// - [config.SlotIdRoute] +// - [config.SlotKeyRoute] +// - [config.ByAddressRoute] +type Route interface { + ToRoutesProtobuf() (*protobuf.Routes, error) } type SimpleNodeRoute int @@ -32,7 +33,7 @@ const ( RandomRoute ) -func (simpleNodeRoute SimpleNodeRoute) toRoutesProtobuf() (*protobuf.Routes, error) { +func (simpleNodeRoute SimpleNodeRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { simpleRouteProto, err := mapSimpleNodeRoute(simpleNodeRoute) if err != nil { return nil, err @@ -55,7 +56,7 @@ func mapSimpleNodeRoute(simpleNodeRoute SimpleNodeRoute) (protobuf.SimpleRoutes, case RandomRoute: return protobuf.SimpleRoutes_Random, nil default: - return protobuf.SimpleRoutes_Random, &RequestError{"Invalid simple node route"} + return protobuf.SimpleRoutes_Random, &errors.RequestError{"Invalid simple node route"} } } @@ -76,7 +77,7 @@ func mapSlotType(slotType SlotType) (protobuf.SlotTypes, error) { case SlotTypeReplica: return protobuf.SlotTypes_Replica, nil default: - return protobuf.SlotTypes_Primary, &RequestError{"Invalid slot type"} + return protobuf.SlotTypes_Primary, &errors.RequestError{"Invalid slot type"} } } @@ -94,7 +95,7 @@ func NewSlotIdRoute(slotType SlotType, slotId int32) *SlotIdRoute { return &SlotIdRoute{slotType: slotType, slotID: slotId} } -func (slotIdRoute *SlotIdRoute) toRoutesProtobuf() (*protobuf.Routes, error) { +func (slotIdRoute *SlotIdRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { slotType, err := mapSlotType(slotIdRoute.slotType) if err != nil { return nil, err @@ -124,7 +125,7 @@ func NewSlotKeyRoute(slotType SlotType, slotKey string) *SlotKeyRoute { return &SlotKeyRoute{slotType: slotType, slotKey: slotKey} } -func (slotKeyRoute *SlotKeyRoute) toRoutesProtobuf() (*protobuf.Routes, error) { +func (slotKeyRoute *SlotKeyRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { slotType, err := mapSlotType(slotKeyRoute.slotType) if err != nil { return nil, err @@ -159,7 +160,7 @@ func NewByAddressRoute(host string, port int32) *ByAddressRoute { func NewByAddressRouteWithHost(host string) (*ByAddressRoute, error) { split := strings.Split(host, ":") if len(split) != 2 { - return nil, &RequestError{ + return nil, &errors.RequestError{ fmt.Sprintf( "no port provided, or host is not in the expected format 'hostname:port'. Received: %s", host, ), @@ -168,7 +169,7 @@ func NewByAddressRouteWithHost(host string) (*ByAddressRoute, error) { port, err := strconv.ParseInt(split[1], 10, 32) if err != nil { - return nil, &RequestError{ + return nil, &errors.RequestError{ fmt.Sprintf( "port must be a valid integer. Received: %s", split[1], ), @@ -178,7 +179,7 @@ func NewByAddressRouteWithHost(host string) (*ByAddressRoute, error) { return &ByAddressRoute{host: split[0], port: int32(port)}, nil } -func (byAddressRoute *ByAddressRoute) toRoutesProtobuf() (*protobuf.Routes, error) { +func (byAddressRoute *ByAddressRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { request := &protobuf.Routes{ Value: &protobuf.Routes_ByAddressRoute{ ByAddressRoute: &protobuf.ByAddressRoute{ diff --git a/go/api/connection_management_cluster_commands.go b/go/api/connection_management_cluster_commands.go index 5790429622..7d26674b7d 100644 --- a/go/api/connection_management_cluster_commands.go +++ b/go/api/connection_management_cluster_commands.go @@ -2,13 +2,13 @@ package api +import "github.com/valkey-io/valkey-glide/go/glide/api/options" + // Supports commands and transactions for the "Connection Management" group of commands for cluster client. // // See [valkey.io] for details. // // [valkey.io]: https://valkey.io/commands/#connection type ConnectionManagementClusterCommands interface { - PingWithRoute(route route) (string, error) - - PingWithMessageRoute(message string, route route) (string, error) + PingWithOptions(pingOptions *options.PingOptions) (string, error) } diff --git a/go/api/connection_management_commands.go b/go/api/connection_management_commands.go index f9d4a1dada..3ab0bc266e 100644 --- a/go/api/connection_management_commands.go +++ b/go/api/connection_management_commands.go @@ -2,36 +2,17 @@ package api +import "github.com/valkey-io/valkey-glide/go/glide/api/options" + // Supports commands and transactions for the "Connection Management" group of commands for standalone client. // // See [valkey.io] for details. // // [valkey.io]: https://valkey.io/commands/#connection type ConnectionManagementCommands interface { - // Pings the server. - // - // Return value: - // Returns "PONG". - // - // For example: - // result, err := client.Ping() - // - // [valkey.io]: https://valkey.io/commands/ping/ Ping() (string, error) - // Pings the server with a custom message. - // - // Parameters: - // message - A message to include in the `PING` command. - // - // Return value: - // Returns the copy of message. - // - // For example: - // result, err := client.PingWithMessage("Hello") - // - // [valkey.io]: https://valkey.io/commands/ping/ - PingWithMessage(message string) (string, error) + PingWithOptions(pingOptions *options.PingOptions) (string, error) // Echo the provided message back. // The command will be routed a random node. diff --git a/go/api/errors.go b/go/api/errors/errors.go similarity index 58% rename from go/api/errors.go rename to go/api/errors/errors.go index 4fa4fad92a..e4331f7dd7 100644 --- a/go/api/errors.go +++ b/go/api/errors/errors.go @@ -1,25 +1,25 @@ // Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 -package api +package errors // #cgo LDFLAGS: -L../target/release -lglide_rs -// #include "../lib.h" +// #include "../../lib.h" import "C" // ConnectionError is a client error that occurs when there is an error while connecting or when a connection // disconnects. type ConnectionError struct { - msg string + Msg string } -func (e *ConnectionError) Error() string { return e.msg } +func (e *ConnectionError) Error() string { return e.Msg } // RequestError is a client error that occurs when an error is reported during a request. type RequestError struct { - msg string + Msg string } -func (e *RequestError) Error() string { return e.msg } +func (e *RequestError) Error() string { return e.Msg } // ExecAbortError is a client error that occurs when a transaction is aborted. type ExecAbortError struct { @@ -44,22 +44,35 @@ func (e *DisconnectError) Error() string { return e.msg } // ClosingError is a client error that indicates that the client has closed and is no longer usable. type ClosingError struct { - msg string + Msg string } -func (e *ClosingError) Error() string { return e.msg } +func (e *ClosingError) Error() string { return e.Msg } + +// func GoError(cErrorType C.RequestErrorType, cErrorMessage *C.char) error { +// defer C.free_error_message(cErrorMessage) +// msg := C.GoString(cErrorMessage) +// switch cErrorType { +// case C.ExecAbort: +// return &ExecAbortError{msg} +// case C.Timeout: +// return &TimeoutError{msg} +// case C.Disconnect: +// return &DisconnectError{msg} +// default: +// return &RequestError{msg} +// } +// } -func goError(cErrorType C.RequestErrorType, cErrorMessage *C.char) error { - defer C.free_error_message(cErrorMessage) - msg := C.GoString(cErrorMessage) +func GoError(cErrorType uint32, errorMessage string) error { switch cErrorType { case C.ExecAbort: - return &ExecAbortError{msg} + return &ExecAbortError{errorMessage} case C.Timeout: - return &TimeoutError{msg} + return &TimeoutError{errorMessage} case C.Disconnect: - return &DisconnectError{msg} + return &DisconnectError{errorMessage} default: - return &RequestError{msg} + return &RequestError{errorMessage} } } diff --git a/go/api/generic_cluster_commands.go b/go/api/generic_cluster_commands.go index 85d9929782..9ede24aa26 100644 --- a/go/api/generic_cluster_commands.go +++ b/go/api/generic_cluster_commands.go @@ -2,6 +2,8 @@ package api +import "github.com/valkey-io/valkey-glide/go/glide/api/config" + // GenericClusterCommands supports commands for the "Generic Commands" group for cluster client. // // See [valkey.io] for details. @@ -35,5 +37,5 @@ type GenericClusterCommands interface { // [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command CustomCommand(args []string) (ClusterValue[interface{}], error) - CustomCommandWithRoute(args []string, route route) (ClusterValue[interface{}], error) + CustomCommandWithRoute(args []string, route config.Route) (ClusterValue[interface{}], error) } diff --git a/go/api/glide_client.go b/go/api/glide_client.go index 51ea9ef4b4..90bb314b85 100644 --- a/go/api/glide_client.go +++ b/go/api/glide_client.go @@ -7,6 +7,8 @@ package api import "C" import ( + "github.com/valkey-io/valkey-glide/go/glide/api/errors" + "github.com/valkey-io/valkey-glide/go/glide/api/options" "github.com/valkey-io/valkey-glide/go/glide/utils" ) @@ -18,6 +20,7 @@ type GlideClient interface { BaseClient GenericCommands ServerManagementCommands + ConnectionManagementCommands } // glideClient implements standalone mode operations by extending baseClient functionality. @@ -67,3 +70,83 @@ func (client *glideClient) Select(index int64) (string, error) { return handleStringResponse(result) } + +// Echo the provided message back. +// The command will be routed a random node. +// +// Parameters: +// +// message - The provided message. +// +// Return value: +// +// The provided message +// +// For example: +// +// result, err := client.Echo("Hello World") +// if err != nil { +// // handle error +// } +// fmt.Println(result.Value()) // Output: Hello World +// +// [valkey.io]: https://valkey.io/commands/echo/ +func (client *baseClient) Echo(message string) (Result[string], error) { + result, err := client.executeCommand(C.Echo, []string{message}) + if err != nil { + return CreateNilStringResult(), err + } + return handleStringOrNilResponse(result) +} + +// Pings the server. +// +// Return value: +// +// Returns "PONG". +// +// For example: +// +// result, err := client.Ping() +// +// [valkey.io]: https://valkey.io/commands/ping/ +func (client *glideClient) Ping() (string, error) { + result, err := client.executeCommand(C.Ping, []string{}) + if err != nil { + return defaultStringResponse, err + } + return handleStringResponse(result) +} + +// Pings the server. +// +// Parameters: +// +// pingOptions - The PingOptions type. +// +// Return value: +// +// Returns "PONG" or the copy of message. +// +// For example: +// +// options := options.NewPingOptionsBuilder().SetMessage("hello") +// result, err := client.PingWithOptions(options) +// result: "hello" +// +// [valkey.io]: https://valkey.io/commands/ping/ +func (client *glideClient) PingWithOptions(opts *options.PingOptions) (string, error) { + if opts != nil && opts.Route != nil { + return defaultStringResponse, &errors.RequestError{"Route option is only available in cluster mode"} + } + args, err := opts.ToArgs() + if err != nil { + return defaultStringResponse, err + } + result, err := client.executeCommand(C.Ping, append([]string{}, args...)) + if err != nil { + return defaultStringResponse, err + } + + return handleStringResponse(result) +} diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index ea677bdcc3..c2f4d03ed4 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -5,6 +5,10 @@ package api // #cgo LDFLAGS: -L../target/release -lglide_rs // #include "../lib.h" import "C" +import ( + "github.com/valkey-io/valkey-glide/go/glide/api/config" + "github.com/valkey-io/valkey-glide/go/glide/api/options" +) // GlideClusterClient interface compliance check. var _ GlideClusterClient = (*glideClusterClient)(nil) @@ -45,10 +49,7 @@ func (client *glideClusterClient) CustomCommand(args []string) (ClusterValue[int // CustomCommandWithRoute executes a single command, specified by args, without checking inputs. Every part of the command, // including the command name and subcommands, should be added as a separate value in args. The returning value depends on -// the executed -// command. -// -// The command will be routed automatically based on the passed command's default request policy. +// the executed command. // // See [Valkey GLIDE Wiki] for details on the restrictions and limitations of the custom command API. // @@ -56,7 +57,7 @@ func (client *glideClusterClient) CustomCommand(args []string) (ClusterValue[int // // args - Arguments for the custom command including the command name. // route - Specifies the routing configuration for the command. The client will route the -// command to the nodes defined by route. +// command to the nodes defined by route. // // Return value: // @@ -64,12 +65,12 @@ func (client *glideClusterClient) CustomCommand(args []string) (ClusterValue[int // // For example: // -// route := api.SimpleNodeRoute(api.RandomRoute) +// route := config.SimpleNodeRoute(config.RandomRoute) // result, err := client.CustomCommand([]string{"ping"}, route) // result.Value().(string): "PONG" // // [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command -func (client *glideClusterClient) CustomCommandWithRoute(args []string, route route) (ClusterValue[interface{}], error) { +func (client *glideClusterClient) CustomCommandWithRoute(args []string, route config.Route) (ClusterValue[interface{}], error) { res, err := client.executeCommandWithRoute(C.CustomCommand, args, route) if err != nil { return CreateEmptyClusterValue(), err @@ -85,51 +86,29 @@ func (client *glideClusterClient) CustomCommandWithRoute(args []string, route ro // // Parameters: // -// route - Specifies the routing configuration for the command. -// The client will route the command to the nodes defined by route. +// pingOptions - The PingOptions type. // // Return value: // -// Returns "PONG". +// Returns "PONG" or the copy of message. // // For example: // -// route := api.SimpleNodeRoute(api.RandomRoute) -// result, err := client.Ping(route) -// fmt.Println(result) // Output: "PONG" +// route := config.SimpleNodeRoute(config.RandomRoute) +// options := options.NewPingOptionsBuilder().SetRoute(route).SetMessage("Hello") +// result, err := client.PingWithOptions(options) +// fmt.Println(result) // Output: "Hello" // // [valkey.io]: https://valkey.io/commands/ping/ -func (client *glideClusterClient) PingWithRoute(route route) (string, error) { - res, err := client.executeCommandWithRoute(C.Ping, []string{}, route) +func (client *glideClusterClient) PingWithOptions(opts *options.PingOptions) (string, error) { + args, err := opts.ToArgs() if err != nil { return defaultStringResponse, err } - return handleStringResponse(res) -} - -// Pings the server with a custom message. -// -// Parameters: -// -// message - A message to include in the `PING` command. -// route - Specifies the routing configuration for the command. -// The client will route the command to the nodes defined by route. -// -// Return value: -// -// Returns the copy of message. -// -// For example: -// -// route := api.SimpleNodeRoute(api.RandomRoute) -// result, err := client.PingWithMessage("Hello", route) -// fmt.Println(result) // Output: "Hello" -// -// [valkey.io]: https://valkey.io/commands/ping/ -func (client *glideClusterClient) PingWithMessageRoute(message string, route route) (string, error) { - res, err := client.executeCommandWithRoute(C.Ping, []string{message}, route) + result, err := client.executeCommandWithRoute(C.Ping, args, opts.Route) if err != nil { return defaultStringResponse, err } - return handleStringResponse(res) + + return handleStringResponse(result) } diff --git a/go/api/options/ping_options.go b/go/api/options/ping_options.go new file mode 100644 index 0000000000..486b12e805 --- /dev/null +++ b/go/api/options/ping_options.go @@ -0,0 +1,35 @@ +// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 + +package options + +import ( + "github.com/valkey-io/valkey-glide/go/glide/api/config" +) + +type PingOptions struct { + message string + Route config.Route +} + +func NewPingOptionsBuilder() *PingOptions { + return &PingOptions{} +} + +func (pingOptions *PingOptions) SetMessage(msg string) *PingOptions { + pingOptions.message = msg + return pingOptions +} + +func (pingOptions *PingOptions) SetRoute(route config.Route) *PingOptions { + pingOptions.Route = route + return pingOptions +} + +func (opts *PingOptions) ToArgs() ([]string, error) { + args := []string{} + + if opts.message != "" { + args = append(args, opts.message) + } + return args, nil +} diff --git a/go/api/response_handlers.go b/go/api/response_handlers.go index dd7fbe2712..70ffa7e581 100644 --- a/go/api/response_handlers.go +++ b/go/api/response_handlers.go @@ -11,6 +11,8 @@ import ( "reflect" "strconv" "unsafe" + + "github.com/valkey-io/valkey-glide/go/glide/api/errors" ) func checkResponseType(response *C.struct_CommandResponse, expectedType C.ResponseType, isNilable bool) error { @@ -18,7 +20,7 @@ func checkResponseType(response *C.struct_CommandResponse, expectedType C.Respon expectedTypeStr := C.get_response_type_string(expectedTypeInt) if !isNilable && response == nil { - return &RequestError{ + return &errors.RequestError{ fmt.Sprintf( "Unexpected return type from Valkey: got nil, expected %s", C.GoString(expectedTypeStr), @@ -35,7 +37,7 @@ func checkResponseType(response *C.struct_CommandResponse, expectedType C.Respon } actualTypeStr := C.get_response_type_string(response.response_type) - return &RequestError{ + return &errors.RequestError{ fmt.Sprintf( "Unexpected return type from Valkey: got %s, expected %s", C.GoString(actualTypeStr), @@ -89,7 +91,7 @@ func parseInterface(response *C.struct_CommandResponse) (interface{}, error) { return parseSet(response) } - return nil, &RequestError{"Unexpected return type from Valkey"} + return nil, &errors.RequestError{"Unexpected return type from Valkey"} } func parseString(response *C.struct_CommandResponse) (interface{}, error) { @@ -373,7 +375,7 @@ func handleStringDoubleMapResponse(response *C.struct_CommandResponse) (map[stri } result, ok := converted.(map[string]float64) if !ok { - return nil, &RequestError{fmt.Sprintf("unexpected type of map: %T", converted)} + return nil, &errors.RequestError{fmt.Sprintf("unexpected type of map: %T", converted)} } return result, nil } @@ -400,7 +402,7 @@ func handleStringToStringMapResponse(response *C.struct_CommandResponse) (map[st } result, ok := converted.(map[string]string) if !ok { - return nil, &RequestError{fmt.Sprintf("unexpected type of map: %T", converted)} + return nil, &errors.RequestError{fmt.Sprintf("unexpected type of map: %T", converted)} } return result, nil } @@ -437,7 +439,7 @@ func handleStringToStringArrayMapOrNilResponse( return result, nil } - return nil, &RequestError{fmt.Sprintf("unexpected type received: %T", res)} + return nil, &errors.RequestError{fmt.Sprintf("unexpected type received: %T", res)} } func handleStringSetResponse(response *C.struct_CommandResponse) (map[string]struct{}, error) { @@ -543,7 +545,7 @@ func (node mapConverter[T]) convert(data interface{}) (interface{}, error) { if node.canBeNil { return nil, nil } else { - return nil, &RequestError{fmt.Sprintf("Unexpected type received: nil, expected: map[string]%v", getType[T]())} + return nil, &errors.RequestError{fmt.Sprintf("Unexpected type received: nil, expected: map[string]%v", getType[T]())} } } result := make(map[string]T) @@ -552,7 +554,7 @@ func (node mapConverter[T]) convert(data interface{}) (interface{}, error) { if node.next == nil { valueT, ok := value.(T) if !ok { - return nil, &RequestError{fmt.Sprintf("Unexpected type of map element: %T, expected: %v", value, getType[T]())} + return nil, &errors.RequestError{fmt.Sprintf("Unexpected type of map element: %T, expected: %v", value, getType[T]())} } result[key] = valueT } else { @@ -567,7 +569,7 @@ func (node mapConverter[T]) convert(data interface{}) (interface{}, error) { } valueT, ok := val.(T) if !ok { - return nil, &RequestError{fmt.Sprintf("Unexpected type of map element: %T, expected: %v", val, getType[T]())} + return nil, &errors.RequestError{fmt.Sprintf("Unexpected type of map element: %T, expected: %v", val, getType[T]())} } result[key] = valueT } @@ -587,7 +589,7 @@ func (node arrayConverter[T]) convert(data interface{}) (interface{}, error) { if node.canBeNil { return nil, nil } else { - return nil, &RequestError{fmt.Sprintf("Unexpected type received: nil, expected: []%v", getType[T]())} + return nil, &errors.RequestError{fmt.Sprintf("Unexpected type received: nil, expected: []%v", getType[T]())} } } arrData := data.([]interface{}) @@ -596,7 +598,7 @@ func (node arrayConverter[T]) convert(data interface{}) (interface{}, error) { if node.next == nil { valueT, ok := value.(T) if !ok { - return nil, &RequestError{ + return nil, &errors.RequestError{ fmt.Sprintf("Unexpected type of array element: %T, expected: %v", value, getType[T]()), } } @@ -613,7 +615,7 @@ func (node arrayConverter[T]) convert(data interface{}) (interface{}, error) { } valueT, ok := val.(T) if !ok { - return nil, &RequestError{fmt.Sprintf("Unexpected type of array element: %T, expected: %v", val, getType[T]())} + return nil, &errors.RequestError{fmt.Sprintf("Unexpected type of array element: %T, expected: %v", val, getType[T]())} } result = append(result, valueT) } @@ -638,7 +640,7 @@ func handleXAutoClaimResponse(response *C.struct_CommandResponse) (XAutoClaimRes arr := slice.([]interface{}) len := len(arr) if len < 2 || len > 3 { - return null, &RequestError{fmt.Sprintf("Unexpected response array length: %d", len)} + return null, &errors.RequestError{fmt.Sprintf("Unexpected response array length: %d", len)} } converted, err := mapConverter[[][]string]{ arrayConverter[[]string]{ @@ -655,7 +657,7 @@ func handleXAutoClaimResponse(response *C.struct_CommandResponse) (XAutoClaimRes } claimedEntries, ok := converted.(map[string][][]string) if !ok { - return null, &RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} + return null, &errors.RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} } var deletedMessages []string deletedMessages = nil @@ -669,7 +671,7 @@ func handleXAutoClaimResponse(response *C.struct_CommandResponse) (XAutoClaimRes } deletedMessages, ok = converted.([]string) if !ok { - return null, &RequestError{fmt.Sprintf("unexpected type of third element: %T", converted)} + return null, &errors.RequestError{fmt.Sprintf("unexpected type of third element: %T", converted)} } } return XAutoClaimResponse{arr[0].(string), claimedEntries, deletedMessages}, nil @@ -689,7 +691,7 @@ func handleXAutoClaimJustIdResponse(response *C.struct_CommandResponse) (XAutoCl arr := slice.([]interface{}) len := len(arr) if len < 2 || len > 3 { - return null, &RequestError{fmt.Sprintf("Unexpected response array length: %d", len)} + return null, &errors.RequestError{fmt.Sprintf("Unexpected response array length: %d", len)} } converted, err := arrayConverter[string]{ nil, @@ -700,7 +702,7 @@ func handleXAutoClaimJustIdResponse(response *C.struct_CommandResponse) (XAutoCl } claimedEntries, ok := converted.([]string) if !ok { - return null, &RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} + return null, &errors.RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} } var deletedMessages []string deletedMessages = nil @@ -714,7 +716,7 @@ func handleXAutoClaimJustIdResponse(response *C.struct_CommandResponse) (XAutoCl } deletedMessages, ok = converted.([]string) if !ok { - return null, &RequestError{fmt.Sprintf("unexpected type of third element: %T", converted)} + return null, &errors.RequestError{fmt.Sprintf("unexpected type of third element: %T", converted)} } } return XAutoClaimJustIdResponse{arr[0].(string), claimedEntries, deletedMessages}, nil @@ -751,7 +753,7 @@ func handleXReadResponse(response *C.struct_CommandResponse) (map[string]map[str if result, ok := res.(map[string]map[string][][]string); ok { return result, nil } - return nil, &RequestError{fmt.Sprintf("unexpected type received: %T", res)} + return nil, &errors.RequestError{fmt.Sprintf("unexpected type received: %T", res)} } func handleXReadGroupResponse(response *C.struct_CommandResponse) (map[string]map[string][][]string, error) { @@ -785,7 +787,7 @@ func handleXReadGroupResponse(response *C.struct_CommandResponse) (map[string]ma if result, ok := res.(map[string]map[string][][]string); ok { return result, nil } - return nil, &RequestError{fmt.Sprintf("unexpected type received: %T", res)} + return nil, &errors.RequestError{fmt.Sprintf("unexpected type received: %T", res)} } func handleXPendingSummaryResponse(response *C.struct_CommandResponse) (XPendingSummary, error) { diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index 60726868d3..bf060e020b 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/valkey-io/valkey-glide/go/glide/api" + "github.com/valkey-io/valkey-glide/go/glide/api/config" + "github.com/valkey-io/valkey-glide/go/glide/api/options" ) func (suite *GlideTestSuite) TestClusterCustomCommandInfo() { @@ -30,64 +32,9 @@ func (suite *GlideTestSuite) TestClusterCustomCommandEcho() { assert.Equal(suite.T(), "GO GLIDE GO", result.Value().(string)) } -func (suite *GlideTestSuite) TestPingWithRoute_ValidRoute() { - client := suite.defaultClusterClient() - route := api.SimpleNodeRoute(api.RandomRoute) - result, err := client.PingWithRoute(route) - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), "PONG", result) -} - -func (suite *GlideTestSuite) TestPingWithRoute_InvalidRoute() { - client := suite.defaultClusterClient() - invalidRoute := api.NewByAddressRoute("invalidHost", 9999) - - result, err := client.PingWithRoute(invalidRoute) - - assert.NotNil(suite.T(), err) - assert.Empty(suite.T(), result) -} - -func (suite *GlideTestSuite) TestPingWithMessageRoute_ValidRoute_ValidMessage() { - client := suite.defaultClusterClient() - route := api.SimpleNodeRoute(api.RandomRoute) - - customMessage := "Hello Glide" - - result, err := client.PingWithMessageRoute(customMessage, route) - - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), customMessage, result) -} - -func (suite *GlideTestSuite) TestPingWithMessageRoute_EmptyMessage() { - client := suite.defaultClusterClient() - route := api.SimpleNodeRoute(api.RandomRoute) - - customMessage := "" - - result, err := client.PingWithMessageRoute(customMessage, route) - - assert.NoError(suite.T(), err) - - assert.Equal(suite.T(), customMessage, result) -} - -func (suite *GlideTestSuite) TestPingWithMessageRoute_InvalidRoute() { - client := suite.defaultClusterClient() - invalidRoute := api.NewByAddressRoute("invalidHost", 9999) - - customMessage := "Hello Glide" - - result, err := client.PingWithMessageRoute(customMessage, invalidRoute) - - assert.NotNil(suite.T(), err) - assert.Empty(suite.T(), result) -} - func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Info() { client := suite.defaultClusterClient() - route := api.SimpleNodeRoute(api.AllPrimaries) + route := config.SimpleNodeRoute(config.AllPrimaries) result, err := client.CustomCommandWithRoute([]string{"INFO"}, route) assert.Nil(suite.T(), err) for _, value := range result.Value().(map[string]interface{}) { @@ -97,7 +44,7 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Info() { func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Echo() { client := suite.defaultClusterClient() - route := api.SimpleNodeRoute(api.RandomRoute) + route := config.SimpleNodeRoute(config.RandomRoute) result, err := client.CustomCommandWithRoute([]string{"ECHO", "GO GLIDE GO"}, route) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "GO GLIDE GO", result.Value().(string)) @@ -105,7 +52,7 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Echo() { func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_InvalidRoute() { client := suite.defaultClusterClient() - invalidRoute := api.NewByAddressRoute("invalidHost", 9999) + invalidRoute := config.NewByAddressRoute("invalidHost", 9999) result, err := client.CustomCommandWithRoute([]string{"PING"}, invalidRoute) assert.NotNil(suite.T(), err) assert.Equal(suite.T(), api.CreateEmptyClusterValue(), result) @@ -113,7 +60,7 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_InvalidRoute() { func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { client := suite.defaultClusterClient() - route := api.SimpleNodeRoute(api.AllNodes) + route := config.SimpleNodeRoute(config.AllNodes) result, err := client.CustomCommandWithRoute([]string{"PING"}, route) assert.Nil(suite.T(), err) @@ -131,3 +78,50 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { assert.Equal(suite.T(), "PONG", value.(string)) } } + +func (suite *GlideTestSuite) TestPingWithOptions_OnlyRoute() { + client := suite.defaultClusterClient() + route := config.SimpleNodeRoute(config.RandomRoute) + options := options.NewPingOptionsBuilder(). + SetRoute(route) + + result, err := client.PingWithOptions(options) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "PONG", result) // Default response when no message is set +} + +func (suite *GlideTestSuite) TestPingWithOptions_BasicPing() { + client := suite.defaultClusterClient() + route := config.SimpleNodeRoute(config.RandomRoute) + options := options.NewPingOptionsBuilder(). + SetRoute(route). + SetMessage("hello") + + result, err := client.PingWithOptions(options) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "hello", result) +} + +func (suite *GlideTestSuite) TestPingWithOptions_AllNodes() { + client := suite.defaultClusterClient() + route := config.SimpleNodeRoute(config.AllNodes) + options := options.NewPingOptionsBuilder(). + SetRoute(route). + SetMessage("hello") + + result, err := client.PingWithOptions(options) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "hello", result) +} + +func (suite *GlideTestSuite) TestPingWithOptions_InvalidRoute() { + client := suite.defaultClusterClient() + invalidRoute := config.NewByAddressRoute("invalidHost", 9999) + options := options.NewPingOptionsBuilder(). + SetRoute(invalidRoute). + SetMessage("hello") + + result, err := client.PingWithOptions(options) + assert.NotNil(suite.T(), err) + assert.Equal(suite.T(), "", result) +} diff --git a/go/integTest/connection_test.go b/go/integTest/connection_test.go index 22c6b809e8..da0bde260e 100644 --- a/go/integTest/connection_test.go +++ b/go/integTest/connection_test.go @@ -5,6 +5,7 @@ package integTest import ( "github.com/stretchr/testify/assert" "github.com/valkey-io/valkey-glide/go/glide/api" + "github.com/valkey-io/valkey-glide/go/glide/api/errors" ) func (suite *GlideTestSuite) TestStandaloneConnect() { @@ -51,5 +52,5 @@ func (suite *GlideTestSuite) TestConnectWithInvalidAddress() { assert.Nil(suite.T(), client) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.ConnectionError{}, err) + assert.IsType(suite.T(), &errors.ConnectionError{}, err) } diff --git a/go/api/request_routing_config_test.go b/go/integTest/request_routing_config_test.go similarity index 69% rename from go/api/request_routing_config_test.go rename to go/integTest/request_routing_config_test.go index f16b6cfcb7..a9692d241f 100644 --- a/go/api/request_routing_config_test.go +++ b/go/integTest/request_routing_config_test.go @@ -1,30 +1,31 @@ // Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 -package api +package integTest import ( "testing" "github.com/stretchr/testify/assert" + "github.com/valkey-io/valkey-glide/go/glide/api/config" "github.com/valkey-io/valkey-glide/go/glide/protobuf" ) func TestSimpleNodeRoute(t *testing.T) { - config := AllNodes + routeConfig := config.AllNodes expected := &protobuf.Routes{ Value: &protobuf.Routes_SimpleRoutes{ SimpleRoutes: protobuf.SimpleRoutes_AllNodes, }, } - result, err := config.toRoutesProtobuf() + result, err := routeConfig.ToRoutesProtobuf() assert.Equal(t, expected, result) assert.Nil(t, err) } func TestSlotIdRoute(t *testing.T) { - config := NewSlotIdRoute(SlotTypePrimary, int32(100)) + routeConfig := config.NewSlotIdRoute(config.SlotTypePrimary, int32(100)) expected := &protobuf.Routes{ Value: &protobuf.Routes_SlotIdRoute{ SlotIdRoute: &protobuf.SlotIdRoute{ @@ -34,14 +35,14 @@ func TestSlotIdRoute(t *testing.T) { }, } - result, err := config.toRoutesProtobuf() + result, err := routeConfig.ToRoutesProtobuf() assert.Equal(t, expected, result) assert.Nil(t, err) } func TestSlotKeyRoute(t *testing.T) { - config := NewSlotKeyRoute(SlotTypePrimary, "Slot1") + routeConfig := config.NewSlotKeyRoute(config.SlotTypePrimary, "Slot1") expected := &protobuf.Routes{ Value: &protobuf.Routes_SlotKeyRoute{ SlotKeyRoute: &protobuf.SlotKeyRoute{ @@ -51,46 +52,46 @@ func TestSlotKeyRoute(t *testing.T) { }, } - result, err := config.toRoutesProtobuf() + result, err := routeConfig.ToRoutesProtobuf() assert.Equal(t, expected, result) assert.Nil(t, err) } func TestByAddressRoute(t *testing.T) { - config := NewByAddressRoute("localhost", int32(6739)) + routeConfig := config.NewByAddressRoute("localhost", int32(6739)) expected := &protobuf.Routes{ Value: &protobuf.Routes_ByAddressRoute{ ByAddressRoute: &protobuf.ByAddressRoute{Host: "localhost", Port: 6739}, }, } - result, err := config.toRoutesProtobuf() + result, err := routeConfig.ToRoutesProtobuf() assert.Equal(t, expected, result) assert.Nil(t, err) } func TestByAddressRouteWithHost(t *testing.T) { - config, _ := NewByAddressRouteWithHost("localhost:6739") + routeConfig, _ := config.NewByAddressRouteWithHost("localhost:6739") expected := &protobuf.Routes{ Value: &protobuf.Routes_ByAddressRoute{ ByAddressRoute: &protobuf.ByAddressRoute{Host: "localhost", Port: 6739}, }, } - result, err := config.toRoutesProtobuf() + result, err := routeConfig.ToRoutesProtobuf() assert.Equal(t, expected, result) assert.Nil(t, err) } func TestByAddressRoute_MultiplePorts(t *testing.T) { - _, err := NewByAddressRouteWithHost("localhost:6739:6740") + _, err := config.NewByAddressRouteWithHost("localhost:6739:6740") assert.NotNil(t, err) } func TestByAddressRoute_InvalidHost(t *testing.T) { - _, err := NewByAddressRouteWithHost("localhost") + _, err := config.NewByAddressRouteWithHost("localhost") assert.NotNil(t, err) } diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index adc95558a0..69b4eb473c 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -12,6 +12,7 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/valkey-io/valkey-glide/go/glide/api" + "github.com/valkey-io/valkey-glide/go/glide/api/errors" "github.com/valkey-io/valkey-glide/go/glide/api/options" ) @@ -366,17 +367,17 @@ func (suite *GlideTestSuite) TestIncrCommands_TypeError() { res1, err := client.Incr(key) assert.Equal(suite.T(), int64(0), res1) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res2, err := client.IncrBy(key, 10) assert.Equal(suite.T(), int64(0), res2) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res3, err := client.IncrByFloat(key, float64(10.1)) assert.Equal(suite.T(), float64(0), res3) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -454,7 +455,7 @@ func (suite *GlideTestSuite) TestSetRange_existingAndNonExistingKeys() { res, err = client.SetRange(key, math.MaxInt32, "test") assert.Equal(suite.T(), int64(0), res) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -601,23 +602,6 @@ func (suite *GlideTestSuite) TestGetDel_EmptyKey() { }) } -func (suite *GlideTestSuite) TestPing_NoArgument() { - suite.runWithDefaultClients(func(client api.BaseClient) { - result, err := client.Ping() - assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "PONG", result) - }) -} - -func (suite *GlideTestSuite) TestPing_WithArgument() { - suite.runWithDefaultClients(func(client api.BaseClient) { - // Passing "Hello" as the message - result, err := client.PingWithMessage("Hello") - assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "Hello", result) - }) -} - func (suite *GlideTestSuite) TestHSet_WithExistingKey() { suite.runWithDefaultClients(func(client api.BaseClient) { fields := map[string]string{"field1": "value1", "field2": "value2"} @@ -1307,12 +1291,12 @@ func (suite *GlideTestSuite) TestLPushLPop_typeError() { res1, err := client.LPush(key, []string{"value1"}) assert.Equal(suite.T(), int64(0), res1) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res2, err := client.LPopCount(key, 2) assert.Nil(suite.T(), res2) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -1363,13 +1347,13 @@ func (suite *GlideTestSuite) TestLPos_withAndWithoutOptions() { res8, err := client.LPosWithOptions(key, "a", api.NewLPosOptionsBuilder().SetRank(0)) assert.Equal(suite.T(), api.CreateNilInt64Result(), res8) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // invalid maxlen value res9, err := client.LPosWithOptions(key, "a", api.NewLPosOptionsBuilder().SetMaxLen(-1)) assert.Equal(suite.T(), api.CreateNilInt64Result(), res9) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // non-existent key res10, err := client.LPos("non_existent_key", "a") @@ -1382,7 +1366,7 @@ func (suite *GlideTestSuite) TestLPos_withAndWithoutOptions() { res11, err := client.LPos(keyString, "a") assert.Equal(suite.T(), api.CreateNilInt64Result(), res11) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -1406,7 +1390,7 @@ func (suite *GlideTestSuite) TestLPosCount() { res4, err := client.LPosCount(key, "a", int64(-1)) assert.Nil(suite.T(), res4) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // non-existent key res5, err := client.LPosCount("non_existent_key", "a", int64(1)) @@ -1419,7 +1403,7 @@ func (suite *GlideTestSuite) TestLPosCount() { res6, err := client.LPosCount(keyString, "a", int64(1)) assert.Nil(suite.T(), res6) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -1461,7 +1445,7 @@ func (suite *GlideTestSuite) TestRPush() { res2, err := client.RPush(key2, []string{"value1"}) assert.Equal(suite.T(), int64(0), res2) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -1632,7 +1616,7 @@ func (suite *GlideTestSuite) TestSUnionStore() { res11, err := client.SUnionStore(key4, []string{}) assert.Equal(suite.T(), int64(0), res11) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // non-set key _, err = client.Set(stringKey, "value") @@ -1641,7 +1625,7 @@ func (suite *GlideTestSuite) TestSUnionStore() { res12, err := client.SUnionStore(key4, []string{stringKey, key1}) assert.Equal(suite.T(), int64(0), res12) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // overwrite destination when destination is not a set res13, err := client.SUnionStore(stringKey, []string{key1, key3}) @@ -1921,7 +1905,7 @@ func (suite *GlideTestSuite) TestSinterStore() { res10, err := client.SInterStore(key3, []string{}) assert.Equal(suite.T(), int64(0), res10) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // non-set key _, err = client.Set(stringKey, "value") @@ -1930,7 +1914,7 @@ func (suite *GlideTestSuite) TestSinterStore() { res11, err := client.SInterStore(key3, []string{stringKey}) assert.Equal(suite.T(), int64(0), res11) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // overwrite the non-set key res12, err := client.SInterStore(stringKey, []string{key2}) @@ -2070,13 +2054,13 @@ func (suite *GlideTestSuite) TestSMIsMember() { // invalid argument - member list must not be empty _, err4 := client.SMIsMember(key1, []string{}) assert.NotNil(suite.T(), err4) - assert.IsType(suite.T(), &api.RequestError{}, err4) + assert.IsType(suite.T(), &errors.RequestError{}, err4) // source key exists, but it is not a set suite.verifyOK(client.Set(stringKey, "value")) _, err5 := client.SMIsMember(stringKey, []string{"two"}) assert.NotNil(suite.T(), err5) - assert.IsType(suite.T(), &api.RequestError{}, err5) + assert.IsType(suite.T(), &errors.RequestError{}, err5) }) } @@ -2124,13 +2108,13 @@ func (suite *GlideTestSuite) TestSUnion() { // Exceptions with empty keys res6, err := client.SUnion([]string{}) assert.Nil(suite.T(), res6) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // Exception with a non-set key suite.verifyOK(client.Set(nonSetKey, "value")) res7, err := client.SUnion([]string{nonSetKey, key1}) assert.Nil(suite.T(), res7) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2229,7 +2213,7 @@ func (suite *GlideTestSuite) TestSMove() { _, err = client.SMove(stringKey, key1, "_") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2266,7 +2250,7 @@ func (suite *GlideTestSuite) TestSScan() { } else { _, _, err = client.SScan(key1, "-1") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) } // result contains the whole set @@ -2334,7 +2318,7 @@ func (suite *GlideTestSuite) TestSScan() { _, _, err = client.SScan(key2, initialCursor) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2361,7 +2345,7 @@ func (suite *GlideTestSuite) TestLRange() { res4, err := client.LRange(key2, int64(0), int64(1)) assert.Nil(suite.T(), res4) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2394,7 +2378,7 @@ func (suite *GlideTestSuite) TestLIndex() { res5, err := client.LIndex(key2, int64(0)) assert.Equal(suite.T(), api.CreateNilStringResult(), res5) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2425,7 +2409,7 @@ func (suite *GlideTestSuite) TestLTrim() { res4, err := client.LIndex(key2, int64(0)) assert.Equal(suite.T(), api.CreateNilStringResult(), res4) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2452,7 +2436,7 @@ func (suite *GlideTestSuite) TestLLen() { res4, err := client.LLen(key2) assert.Equal(suite.T(), int64(0), res4) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2524,12 +2508,12 @@ func (suite *GlideTestSuite) TestRPopAndRPopCount() { res6, err := client.RPop(key2) assert.Equal(suite.T(), api.CreateNilStringResult(), res6) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res7, err := client.RPopCount(key2, int64(2)) assert.Nil(suite.T(), res7) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2568,7 +2552,7 @@ func (suite *GlideTestSuite) TestLInsert() { res7, err := client.LInsert(key2, api.Before, "value5", "value6") assert.Equal(suite.T(), int64(0), res7) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2595,7 +2579,7 @@ func (suite *GlideTestSuite) TestBLPop() { res4, err := client.BLPop([]string{key}, float64(1.0)) assert.Nil(suite.T(), res4) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2622,7 +2606,7 @@ func (suite *GlideTestSuite) TestBRPop() { res4, err := client.BRPop([]string{key}, float64(1.0)) assert.Nil(suite.T(), res4) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2657,12 +2641,12 @@ func (suite *GlideTestSuite) TestRPushX() { res6, err := client.RPushX(key3, []string{"value1"}) assert.Equal(suite.T(), int64(0), res6) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res7, err := client.RPushX(key2, []string{}) assert.Equal(suite.T(), int64(0), res7) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2697,12 +2681,12 @@ func (suite *GlideTestSuite) TestLPushX() { res6, err := client.LPushX(key3, []string{"value1"}) assert.Equal(suite.T(), int64(0), res6) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res7, err := client.LPushX(key2, []string{}) assert.Equal(suite.T(), int64(0), res7) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2753,12 +2737,12 @@ func (suite *GlideTestSuite) TestLMPopAndLMPopCount() { res7, err := client.LMPop([]string{key3}, api.Left) assert.Nil(suite.T(), res7) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res8, err := client.LMPop([]string{key3}, "Invalid") assert.Nil(suite.T(), res8) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2809,7 +2793,7 @@ func (suite *GlideTestSuite) TestBLMPopAndBLMPopCount() { res7, err := client.BLMPop([]string{key3}, api.Left, float64(0.1)) assert.Nil(suite.T(), res7) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -2820,7 +2804,7 @@ func (suite *GlideTestSuite) TestLSet() { _, err := client.LSet(nonExistentKey, int64(0), "zero") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res2, err := client.LPush(key, []string{"four", "three", "two", "one"}) assert.Nil(suite.T(), err) @@ -2828,7 +2812,7 @@ func (suite *GlideTestSuite) TestLSet() { _, err = client.LSet(key, int64(10), "zero") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) suite.verifyOK(client.LSet(key, int64(0), "zero")) @@ -2901,7 +2885,7 @@ func (suite *GlideTestSuite) TestLMove() { res11, err := client.LMove(nonListKey, key1, api.Left, api.Left) assert.Equal(suite.T(), api.CreateNilStringResult(), res11) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // destination exists but is not a list type key suite.verifyOK(client.Set(nonListKey, "value")) @@ -2909,7 +2893,7 @@ func (suite *GlideTestSuite) TestLMove() { res12, err := client.LMove(key1, nonListKey, api.Left, api.Left) assert.Equal(suite.T(), api.CreateNilStringResult(), res12) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -3896,7 +3880,7 @@ func (suite *GlideTestSuite) TestBLMove() { res11, err := client.BLMove(nonListKey, key1, api.Left, api.Left, float64(0.1)) assert.Equal(suite.T(), api.CreateNilStringResult(), res11) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // destination exists but is not a list type key suite.verifyOK(client.Set(nonListKey, "value")) @@ -3904,7 +3888,7 @@ func (suite *GlideTestSuite) TestBLMove() { res12, err := client.BLMove(key1, nonListKey, api.Left, api.Left, float64(0.1)) assert.Equal(suite.T(), api.CreateNilStringResult(), res12) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4008,7 +3992,7 @@ func (suite *GlideTestSuite) TestRename() { res1, err := client.Rename(key1, "invalidKey") assert.Equal(suite.T(), "", res1) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4221,7 +4205,7 @@ func (suite *GlideTestSuite) TestXAutoClaim() { key2 := uuid.New().String() suite.verifyOK(client.Set(key2, key2)) _, err = client.XAutoClaim(key2, "_", "_", 0, "_") - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4322,11 +4306,11 @@ func (suite *GlideTestSuite) TestXReadGroup() { // error cases: // key does not exist _, err = client.XReadGroup("_", "_", map[string]string{key3: "0"}) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // key is not a stream suite.verifyOK(client.Set(key3, uuid.New().String())) _, err = client.XReadGroup("_", "_", map[string]string{key3: "0"}) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) del, err := client.Del([]string{key3}) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(1), del) @@ -4335,7 +4319,7 @@ func (suite *GlideTestSuite) TestXReadGroup() { assert.NoError(suite.T(), err) assert.NotNil(suite.T(), xadd) _, err = client.XReadGroup("_", "_", map[string]string{key3: "0"}) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // consumer don't exist sendWithCustomCommand( suite, @@ -4392,7 +4376,7 @@ func (suite *GlideTestSuite) TestXRead() { client.Set(key3, "xread") _, err = client.XRead(map[string]string{key1: "0-0", key3: "0-0"}) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // ensure that commands doesn't time out even if timeout > request timeout var testClient api.BaseClient @@ -4453,12 +4437,12 @@ func (suite *GlideTestSuite) TestZAddAndZAddIncr() { _, err = client.ZAdd(key2, membersScoreMap) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // wrong key type for zaddincr _, err = client.ZAddIncr(key2, "one", float64(2)) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // with NX & XX onlyIfExistsOpts := options.NewZAddOptionsBuilder().SetConditionalChange(options.OnlyIfExists) @@ -4543,7 +4527,7 @@ func (suite *GlideTestSuite) TestZincrBy() { _, err = client.ZIncrBy(key2, 0.5, "_") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4584,7 +4568,7 @@ func (suite *GlideTestSuite) TestBZPopMin() { // Attempt to pop from key3 which is not a sorted set _, err = client.BZPopMin([]string{key3}, float64(.5)) if assert.Error(suite.T(), err) { - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) } }) } @@ -4617,7 +4601,7 @@ func (suite *GlideTestSuite) TestZPopMin() { _, err = client.ZPopMin(key2) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4648,7 +4632,7 @@ func (suite *GlideTestSuite) TestZPopMax() { _, err = client.ZPopMax(key2) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4667,7 +4651,7 @@ func (suite *GlideTestSuite) TestZRem() { // no members to remove _, err = client.ZRem(key, []string{}) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) res, err = client.ZRem(key, []string{"one"}) assert.Nil(suite.T(), err) @@ -4684,7 +4668,7 @@ func (suite *GlideTestSuite) TestZRem() { _, err = client.ZRem(key, []string{"value"}) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4944,7 +4928,7 @@ func (suite *GlideTestSuite) TestZRank() { _, err = client.ZRank(stringKey, "value") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4977,7 +4961,7 @@ func (suite *GlideTestSuite) TestZRevRank() { _, err = client.ZRevRank(stringKey, "value") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -5070,10 +5054,10 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { suite.verifyOK(client.Set(key2, "xtrimtest")) _, err = client.XTrim(key2, options.NewXTrimOptionsWithMinId("0-1")) assert.NotNil(t, err) - assert.IsType(t, &api.RequestError{}, err) + assert.IsType(t, &errors.RequestError{}, err) _, err = client.XLen(key2) assert.NotNil(t, err) - assert.IsType(t, &api.RequestError{}, err) + assert.IsType(t, &errors.RequestError{}, err) }) } @@ -5112,7 +5096,7 @@ func (suite *GlideTestSuite) Test_ZScore() { _, err = client.ZScore(key2, "one") assert.NotNil(t, err) - assert.IsType(t, &api.RequestError{}, err) + assert.IsType(t, &errors.RequestError{}, err) }) } @@ -5191,7 +5175,7 @@ func (suite *GlideTestSuite) TestZCount() { ) _, err = client.ZCount(key2, zCountRange) assert.NotNil(t, err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -5240,7 +5224,7 @@ func (suite *GlideTestSuite) Test_XDel() { _, err = client.XDel(key2, []string{streamId3}) assert.NotNil(t, err) - assert.IsType(t, &api.RequestError{}, err) + assert.IsType(t, &errors.RequestError{}, err) }) } @@ -5275,7 +5259,7 @@ func (suite *GlideTestSuite) TestZScan() { if suite.serverVersion >= "8.0.0" { _, _, err = client.ZScan(key1, "-1") assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) } else { resCursor, resCollection, err = client.ZScan(key1, "-1") assert.NoError(suite.T(), err) @@ -5387,18 +5371,18 @@ func (suite *GlideTestSuite) TestZScan() { _, _, err = client.ZScan(stringKey, initialCursor) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) opts = options.NewZScanOptionsBuilder().SetMatch("test").SetCount(1) _, _, err = client.ZScanWithOptions(stringKey, initialCursor, opts) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // Negative count opts = options.NewZScanOptionsBuilder().SetCount(-1) _, _, err = client.ZScanWithOptions(key1, "-1", opts) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -5670,7 +5654,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("invalid-id", "+", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.XPendingWithOptions( key, @@ -5678,7 +5662,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("-", "invalid-id", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // invalid count should return no results detailResult, err = client.XPendingWithOptions( @@ -5695,7 +5679,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { "invalid-group", ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "NOGROUP")) // non-existent key throws a RequestError (NOGROUP) @@ -5704,7 +5688,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { groupName, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "NOGROUP")) _, err = client.XPendingWithOptions( @@ -5713,7 +5697,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "NOGROUP")) // Key exists, but it is not a stream @@ -5723,7 +5707,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { groupName, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "WRONGTYPE")) _, err = client.XPendingWithOptions( @@ -5732,7 +5716,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "WRONGTYPE")) } @@ -5820,7 +5804,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("invalid-id", "+", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.XPendingWithOptions( key, @@ -5828,7 +5812,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("-", "invalid-id", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // invalid count should return no results detailResult, err = client.XPendingWithOptions( @@ -5845,7 +5829,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { "invalid-group", ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "NOGROUP")) // non-existent key throws a RequestError (NOGROUP) @@ -5854,7 +5838,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { groupName, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "NOGROUP")) _, err = client.XPendingWithOptions( @@ -5863,7 +5847,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "NOGROUP")) // Key exists, but it is not a stream @@ -5873,7 +5857,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { groupName, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "WRONGTYPE")) _, err = client.XPendingWithOptions( @@ -5882,7 +5866,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "WRONGTYPE")) } @@ -5911,7 +5895,7 @@ func (suite *GlideTestSuite) TestXGroupCreate_XGroupDestroy() { // Stream not created results in error _, err := client.XGroupCreate(key, group1, id) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // Stream with option to create creates stream & Group opts := options.NewXGroupCreateOptions().SetMakeStream() @@ -5920,7 +5904,7 @@ func (suite *GlideTestSuite) TestXGroupCreate_XGroupDestroy() { // ...and again results in BUSYGROUP error, because group names must be unique _, err = client.XGroupCreate(key, group1, id) assert.ErrorContains(suite.T(), err, "BUSYGROUP") - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // TODO add XGroupDestroy tests there @@ -5931,7 +5915,7 @@ func (suite *GlideTestSuite) TestXGroupCreate_XGroupDestroy() { } else { _, err = client.XGroupCreateWithOptions(key, group2, id, opts) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) } // key is not a stream @@ -5939,7 +5923,7 @@ func (suite *GlideTestSuite) TestXGroupCreate_XGroupDestroy() { suite.verifyOK(client.Set(key, id)) _, err = client.XGroupCreate(key, group1, id) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -6051,17 +6035,6 @@ func (suite *GlideTestSuite) TestRestoreWithOptions() { }) } -func (suite *GlideTestSuite) TestEcho() { - suite.runWithDefaultClients(func(client api.BaseClient) { - // Test 1: Check if Echo command return the message - value := "Hello world" - t := suite.T() - resultEcho, err := client.Echo(value) - assert.Nil(t, err) - assert.Equal(t, value, resultEcho.Value()) - }) -} - func (suite *GlideTestSuite) TestZRemRangeByRank() { suite.runWithDefaultClients(func(client api.BaseClient) { key1 := uuid.New().String() @@ -6106,7 +6079,7 @@ func (suite *GlideTestSuite) TestZRemRangeByRank() { _, err = client.ZRemRangeByRank(stringKey, 0, 10) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -6161,7 +6134,7 @@ func (suite *GlideTestSuite) TestZRemRangeByLex() { *options.NewRangeByLexQuery(options.NewLexBoundary("a", false), options.NewLexBoundary("c", false)), ) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -6217,7 +6190,7 @@ func (suite *GlideTestSuite) TestZRemRangeByScore() { *options.NewRangeByScoreQuery(options.NewScoreBoundary(1.0, false), options.NewScoreBoundary(10.0, true)), ) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -6448,7 +6421,7 @@ func (suite *GlideTestSuite) TestXGroupStreamCommands() { // create a consumer for a group that doesn't exist should result in a NOGROUP error _, err = client.XGroupCreateConsumer(key, "non-existent-group", consumerName) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.True(suite.T(), strings.Contains(err.Error(), "NOGROUP")) // create consumer that already exists should return false @@ -6532,10 +6505,10 @@ func (suite *GlideTestSuite) TestXGroupStreamCommands() { assert.NoError(suite.T(), err) _, err = client.XGroupCreateConsumer(stringKey, groupName, consumerName) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.XGroupDelConsumer(stringKey, groupName, consumerName) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } diff --git a/go/integTest/standalone_commands_test.go b/go/integTest/standalone_commands_test.go index 2d4a0ec31c..54ce4f743b 100644 --- a/go/integTest/standalone_commands_test.go +++ b/go/integTest/standalone_commands_test.go @@ -8,6 +8,8 @@ import ( "github.com/google/uuid" "github.com/valkey-io/valkey-glide/go/glide/api" + "github.com/valkey-io/valkey-glide/go/glide/api/config" + "github.com/valkey-io/valkey-glide/go/glide/api/errors" "github.com/valkey-io/valkey-glide/go/glide/api/options" "github.com/stretchr/testify/assert" @@ -150,7 +152,7 @@ func (suite *GlideTestSuite) TestCustomCommand_invalidCommand() { assert.Nil(suite.T(), result) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) } func (suite *GlideTestSuite) TestCustomCommand_invalidArgs() { @@ -159,7 +161,7 @@ func (suite *GlideTestSuite) TestCustomCommand_invalidArgs() { assert.Nil(suite.T(), result) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) } func (suite *GlideTestSuite) TestCustomCommand_closedClient() { @@ -170,7 +172,7 @@ func (suite *GlideTestSuite) TestCustomCommand_closedClient() { assert.Nil(suite.T(), result) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.ClosingError{}, err) + assert.IsType(suite.T(), &errors.ClosingError{}, err) } func (suite *GlideTestSuite) TestConfigSetAndGet_multipleArgs() { @@ -195,12 +197,12 @@ func (suite *GlideTestSuite) TestConfigSetAndGet_noArgs() { _, err := client.ConfigSet(configMap) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) result2, err := client.ConfigGet([]string{}) assert.Nil(suite.T(), result2) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) } func (suite *GlideTestSuite) TestConfigSetAndGet_invalidArgs() { @@ -210,7 +212,7 @@ func (suite *GlideTestSuite) TestConfigSetAndGet_invalidArgs() { _, err := client.ConfigSet(configMap) assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) result2, err := client.ConfigGet([]string{"time"}) assert.Equal(suite.T(), map[string]string{}, result2) @@ -384,3 +386,55 @@ func (suite *GlideTestSuite) TestSortReadOnlyWithOptions_SuccessfulSortByWeightA assert.Equal(suite.T(), "item1", sortResult[3].Value()) assert.Equal(suite.T(), "item3", sortResult[5].Value()) } + +func (suite *GlideTestSuite) TestPing_NoArgument() { + client := suite.defaultClient() + + result, err := client.Ping() + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "PONG", result) +} + +func (suite *GlideTestSuite) TestEcho() { + client := suite.defaultClient() + // Test 1: Check if Echo command return the message + value := "Hello world" + t := suite.T() + resultEcho, err := client.Echo(value) + assert.Nil(t, err) + assert.Equal(t, value, resultEcho.Value()) +} + +func (suite *GlideTestSuite) TestPing_ClosedClient() { + client := suite.defaultClient() + client.Close() + + result, err := client.Ping() + + assert.NotNil(suite.T(), err) + assert.Equal(suite.T(), "", result) + assert.IsType(suite.T(), &errors.ClosingError{}, err) +} + +func (suite *GlideTestSuite) TestPingWithOptions_CustomMessage() { + client := suite.defaultClient() + options := options.NewPingOptionsBuilder(). + SetMessage("hello") + + result, err := client.PingWithOptions(options) + + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "hello", result) +} + +func (suite *GlideTestSuite) TestPingWithOptions_WithRoute() { + client := suite.defaultClient() + options := options.NewPingOptionsBuilder(). + SetRoute(config.SimpleNodeRoute(config.RandomRoute)) + + result, err := client.PingWithOptions(options) + + assert.NotNil(suite.T(), err) + assert.Equal(suite.T(), "", result) + assert.IsType(suite.T(), &errors.RequestError{}, err) +} From 91806cd388a90361bf9b81c8dc65168a1c13415f Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 22 Jan 2025 11:40:34 +0000 Subject: [PATCH 03/15] Minor changes Signed-off-by: Niharika Bhavaraju --- go/api/errors/errors.go | 15 --------------- go/integTest/cluster_commands_test.go | 6 ------ 2 files changed, 21 deletions(-) diff --git a/go/api/errors/errors.go b/go/api/errors/errors.go index e4331f7dd7..634d6b0688 100644 --- a/go/api/errors/errors.go +++ b/go/api/errors/errors.go @@ -49,21 +49,6 @@ type ClosingError struct { func (e *ClosingError) Error() string { return e.Msg } -// func GoError(cErrorType C.RequestErrorType, cErrorMessage *C.char) error { -// defer C.free_error_message(cErrorMessage) -// msg := C.GoString(cErrorMessage) -// switch cErrorType { -// case C.ExecAbort: -// return &ExecAbortError{msg} -// case C.Timeout: -// return &TimeoutError{msg} -// case C.Disconnect: -// return &DisconnectError{msg} -// default: -// return &RequestError{msg} -// } -// } - func GoError(cErrorType uint32, errorMessage string) error { switch cErrorType { case C.ExecAbort: diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index bf060e020b..a6eee0513c 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -3,7 +3,6 @@ package integTest import ( - "fmt" "strings" "github.com/stretchr/testify/assert" @@ -63,11 +62,6 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { route := config.SimpleNodeRoute(config.AllNodes) result, err := client.CustomCommandWithRoute([]string{"PING"}, route) - assert.Nil(suite.T(), err) - value := result.Value() - - fmt.Printf("Value type: %T\n", value) - if result.IsMultiValue() { responses := value.(map[string]interface{}) assert.Greater(suite.T(), len(responses), 0) From 51884e6df00b86573d60c2925ae616d57b84aa8c Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 22 Jan 2025 12:00:16 +0000 Subject: [PATCH 04/15] Minor lint fix and error fix Signed-off-by: Niharika Bhavaraju --- go/api/glide_cluster_client.go | 6 +++++- go/api/response_handlers.go | 8 +++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index c2f4d03ed4..79e018f8a4 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -5,6 +5,7 @@ package api // #cgo LDFLAGS: -L../target/release -lglide_rs // #include "../lib.h" import "C" + import ( "github.com/valkey-io/valkey-glide/go/glide/api/config" "github.com/valkey-io/valkey-glide/go/glide/api/options" @@ -70,7 +71,10 @@ func (client *glideClusterClient) CustomCommand(args []string) (ClusterValue[int // result.Value().(string): "PONG" // // [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command -func (client *glideClusterClient) CustomCommandWithRoute(args []string, route config.Route) (ClusterValue[interface{}], error) { +func (client *glideClusterClient) CustomCommandWithRoute( + args []string, + route config.Route, +) (ClusterValue[interface{}], error) { res, err := client.executeCommandWithRoute(C.CustomCommand, args, route) if err != nil { return CreateEmptyClusterValue(), err diff --git a/go/api/response_handlers.go b/go/api/response_handlers.go index fc4b0cf20a..875aa41350 100644 --- a/go/api/response_handlers.go +++ b/go/api/response_handlers.go @@ -210,7 +210,7 @@ func handle2DStringArrayResponse(response *C.struct_CommandResponse) ([][]string } res, ok := converted.([][]string) if !ok { - return nil, &RequestError{fmt.Sprintf("unexpected type: %T", converted)} + return nil, &errors.RequestError{fmt.Sprintf("unexpected type: %T", converted)} } return res, nil } @@ -607,7 +607,9 @@ func (node mapConverter[T]) convert(data interface{}) (interface{}, error) { // try direct conversion to T when there is no next converter valueT, ok := value.(T) if !ok { - return nil, &errors.RequestError{fmt.Sprintf("Unexpected type of map element: %T, expected: %v", value, getType[T]())} + return nil, &errors.RequestError{ + fmt.Sprintf("Unexpected type of map element: %T, expected: %v", value, getType[T]()), + } } result[key] = valueT } else { @@ -707,7 +709,7 @@ func handleMapOfArrayOfStringArrayResponse(response *C.struct_CommandResponse) ( } claimedEntries, ok := converted.(map[string][][]string) if !ok { - return nil, &RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} + return nil, &errors.RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} } return claimedEntries, nil From eb60104a60276c477590eb44f7e4b15ed6a766d9 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 22 Jan 2025 12:22:31 +0000 Subject: [PATCH 05/15] Fixed failing tests Signed-off-by: Niharika Bhavaraju --- go/integTest/cluster_commands_test.go | 3 ++- go/integTest/shared_commands_test.go | 30 +++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index a6eee0513c..c7ee85a29b 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -60,7 +60,8 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_InvalidRoute() { func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { client := suite.defaultClusterClient() route := config.SimpleNodeRoute(config.AllNodes) - result, err := client.CustomCommandWithRoute([]string{"PING"}, route) + result, _ := client.CustomCommandWithRoute([]string{"PING"}, route) + value := result.Value() if result.IsMultiValue() { responses := value.(map[string]interface{}) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index 9b7e5e5277..5b259a1b9a 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -1314,11 +1314,11 @@ func (suite *GlideTestSuite) TestHRandField() { key = uuid.NewString() suite.verifyOK(client.Set(key, "HRandField")) _, err = client.HRandField(key) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.HRandFieldWithCount(key, 42) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.HRandFieldWithCountWithValues(key, 42) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -4552,11 +4552,11 @@ func (suite *GlideTestSuite) TestXGroupSetId() { // An error is raised if XGROUP SETID is called with a non-existing key _, err = client.XGroupSetId(uuid.NewString(), group, "1-1") - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // An error is raised if XGROUP SETID is called with a non-existing group _, err = client.XGroupSetId(key, uuid.NewString(), "1-1") - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // Setting the ID to a non-existing ID is allowed suite.verifyOK(client.XGroupSetId(key, group, "99-99")) @@ -4565,7 +4565,7 @@ func (suite *GlideTestSuite) TestXGroupSetId() { key = uuid.NewString() suite.verifyOK(client.Set(key, "xgroup setid")) _, err = client.XGroupSetId(key, group, "1-1") - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } @@ -7106,7 +7106,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { // claim with invalid stream entry IDs _, err = client.XClaimJustId(key, groupName, consumer1, int64(1), []string{"invalid-stream-id"}) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) // claim with empty stream entry IDs returns empty map claimResult, err := client.XClaimJustId(key, groupName, consumer1, int64(1), []string{}) @@ -7117,7 +7117,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { claimOptions := options.NewStreamClaimOptions().SetIdleTime(1) _, err = client.XClaim(stringKey, groupName, consumer1, int64(1), []string{streamid_1.Value()}) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.Contains(suite.T(), err.Error(), "NOGROUP") _, err = client.XClaimWithOptions( @@ -7129,12 +7129,12 @@ func (suite *GlideTestSuite) TestXClaimFailure() { claimOptions, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.Contains(suite.T(), err.Error(), "NOGROUP") _, err = client.XClaimJustId(stringKey, groupName, consumer1, int64(1), []string{streamid_1.Value()}) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.Contains(suite.T(), err.Error(), "NOGROUP") _, err = client.XClaimJustIdWithOptions( @@ -7146,7 +7146,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { claimOptions, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) assert.Contains(suite.T(), err.Error(), "NOGROUP") // key exists, but is not a stream @@ -7154,7 +7154,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { assert.NoError(suite.T(), err) _, err = client.XClaim(stringKey, groupName, consumer1, int64(1), []string{streamid_1.Value()}) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.XClaimWithOptions( stringKey, @@ -7165,11 +7165,11 @@ func (suite *GlideTestSuite) TestXClaimFailure() { claimOptions, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.XClaimJustId(stringKey, groupName, consumer1, int64(1), []string{streamid_1.Value()}) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) _, err = client.XClaimJustIdWithOptions( stringKey, @@ -7180,6 +7180,6 @@ func (suite *GlideTestSuite) TestXClaimFailure() { claimOptions, ) assert.Error(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) + assert.IsType(suite.T(), &errors.RequestError{}, err) }) } From 0fd48d2764fb11e7139ed98b540aae5a7564df84 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 22 Jan 2025 13:21:22 +0000 Subject: [PATCH 06/15] Fixed linting error Signed-off-by: Niharika Bhavaraju --- go/api/base_client.go | 12 +++---- go/api/command_options.go | 10 +++--- go/api/config/request_routing_config.go | 8 ++--- go/api/glide_client.go | 2 +- go/api/response_handlers.go | 44 ++++++++++++------------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/go/api/base_client.go b/go/api/base_client.go index 45fc5a87a9..360adfa17a 100644 --- a/go/api/base_client.go +++ b/go/api/base_client.go @@ -138,7 +138,7 @@ func (client *baseClient) executeCommandWithRoute( if route != nil { routeProto, err := route.ToRoutesProtobuf() if err != nil { - return nil, &errors.RequestError{"ExecuteCommand failed due to invalid route"} + return nil, &errors.RequestError{Msg: "ExecuteCommand failed due to invalid route"} } msg, err := proto.Marshal(routeProto) if err != nil { @@ -359,7 +359,7 @@ func (client *baseClient) LCS(key1 string, key2 string) (string, error) { func (client *baseClient) GetDel(key string) (Result[string], error) { if key == "" { - return CreateNilStringResult(), &errors.RequestError{"key is required"} + return CreateNilStringResult(), &errors.RequestError{Msg: "key is required"} } result, err := client.executeCommand(C.GetDel, []string{key}) @@ -1136,7 +1136,7 @@ func (client *baseClient) LMPop(keys []string, listDirection ListDirection) (map // Check for potential length overflow. if len(keys) > math.MaxInt-2 { - return nil, &errors.RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{Msg: "Length overflow for the provided keys"} } // args slice will have 2 more arguments with the keys provided. @@ -1164,7 +1164,7 @@ func (client *baseClient) LMPopCount( // Check for potential length overflow. if len(keys) > math.MaxInt-4 { - return nil, &errors.RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{Msg: "Length overflow for the provided keys"} } // args slice will have 4 more arguments with the keys provided. @@ -1192,7 +1192,7 @@ func (client *baseClient) BLMPop( // Check for potential length overflow. if len(keys) > math.MaxInt-3 { - return nil, &errors.RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{Msg: "Length overflow for the provided keys"} } // args slice will have 3 more arguments with the keys provided. @@ -1221,7 +1221,7 @@ func (client *baseClient) BLMPopCount( // Check for potential length overflow. if len(keys) > math.MaxInt-5 { - return nil, &errors.RequestError{"Length overflow for the provided keys"} + return nil, &errors.RequestError{Msg: "Length overflow for the provided keys"} } // args slice will have 5 more arguments with the keys provided. diff --git a/go/api/command_options.go b/go/api/command_options.go index 3c1c6c2f85..29065582bf 100644 --- a/go/api/command_options.go +++ b/go/api/command_options.go @@ -64,7 +64,7 @@ func (opts *SetOptions) toArgs() ([]string, error) { case KeepExisting: args = append(args, string(opts.Expiry.Type)) default: - err = &errors.RequestError{"Invalid expiry type"} + err = &errors.RequestError{Msg: "Invalid expiry type"} } } @@ -102,7 +102,7 @@ func (opts *GetExOptions) toArgs() ([]string, error) { case Persist: args = append(args, string(opts.Expiry.Type)) default: - err = &errors.RequestError{"Invalid expiry type"} + err = &errors.RequestError{Msg: "Invalid expiry type"} } } @@ -145,7 +145,7 @@ func (expireCondition ExpireCondition) toString() (string, error) { case NewExpiryLessThanCurrent: return string(NewExpiryLessThanCurrent), nil default: - return "", &errors.RequestError{"Invalid expire condition"} + return "", &errors.RequestError{Msg: "Invalid expire condition"} } } @@ -255,7 +255,7 @@ func (insertPosition InsertPosition) toString() (string, error) { case After: return string(After), nil default: - return "", &errors.RequestError{"Invalid insert position"} + return "", &errors.RequestError{Msg: "Invalid insert position"} } } @@ -276,7 +276,7 @@ func (listDirection ListDirection) toString() (string, error) { case Right: return string(Right), nil default: - return "", &errors.RequestError{"Invalid list direction"} + return "", &errors.RequestError{Msg: "Invalid list direction"} } } diff --git a/go/api/config/request_routing_config.go b/go/api/config/request_routing_config.go index 64f676f084..1d0acc27d3 100644 --- a/go/api/config/request_routing_config.go +++ b/go/api/config/request_routing_config.go @@ -56,7 +56,7 @@ func mapSimpleNodeRoute(simpleNodeRoute SimpleNodeRoute) (protobuf.SimpleRoutes, case RandomRoute: return protobuf.SimpleRoutes_Random, nil default: - return protobuf.SimpleRoutes_Random, &errors.RequestError{"Invalid simple node route"} + return protobuf.SimpleRoutes_Random, &errors.RequestError{Msg: "Invalid simple node route"} } } @@ -77,7 +77,7 @@ func mapSlotType(slotType SlotType) (protobuf.SlotTypes, error) { case SlotTypeReplica: return protobuf.SlotTypes_Replica, nil default: - return protobuf.SlotTypes_Primary, &errors.RequestError{"Invalid slot type"} + return protobuf.SlotTypes_Primary, &errors.RequestError{Msg: "Invalid slot type"} } } @@ -161,7 +161,7 @@ func NewByAddressRouteWithHost(host string) (*ByAddressRoute, error) { split := strings.Split(host, ":") if len(split) != 2 { return nil, &errors.RequestError{ - fmt.Sprintf( + Msg: fmt.Sprintf( "no port provided, or host is not in the expected format 'hostname:port'. Received: %s", host, ), } @@ -170,7 +170,7 @@ func NewByAddressRouteWithHost(host string) (*ByAddressRoute, error) { port, err := strconv.ParseInt(split[1], 10, 32) if err != nil { return nil, &errors.RequestError{ - fmt.Sprintf( + Msg: fmt.Sprintf( "port must be a valid integer. Received: %s", split[1], ), } diff --git a/go/api/glide_client.go b/go/api/glide_client.go index 90bb314b85..7ac20829bf 100644 --- a/go/api/glide_client.go +++ b/go/api/glide_client.go @@ -137,7 +137,7 @@ func (client *glideClient) Ping() (string, error) { // [valkey.io]: https://valkey.io/commands/ping/ func (client *glideClient) PingWithOptions(opts *options.PingOptions) (string, error) { if opts != nil && opts.Route != nil { - return defaultStringResponse, &errors.RequestError{"Route option is only available in cluster mode"} + return defaultStringResponse, &errors.RequestError{Msg: "Route option is only available in cluster mode"} } args, err := opts.ToArgs() if err != nil { diff --git a/go/api/response_handlers.go b/go/api/response_handlers.go index 875aa41350..19116a6d2f 100644 --- a/go/api/response_handlers.go +++ b/go/api/response_handlers.go @@ -21,7 +21,7 @@ func checkResponseType(response *C.struct_CommandResponse, expectedType C.Respon if !isNilable && response == nil { return &errors.RequestError{ - fmt.Sprintf( + Msg: fmt.Sprintf( "Unexpected return type from Valkey: got nil, expected %s", C.GoString(expectedTypeStr), ), @@ -38,7 +38,7 @@ func checkResponseType(response *C.struct_CommandResponse, expectedType C.Respon actualTypeStr := C.get_response_type_string(response.response_type) return &errors.RequestError{ - fmt.Sprintf( + Msg: fmt.Sprintf( "Unexpected return type from Valkey: got %s, expected %s", C.GoString(actualTypeStr), C.GoString(expectedTypeStr), @@ -91,7 +91,7 @@ func parseInterface(response *C.struct_CommandResponse) (interface{}, error) { return parseSet(response) } - return nil, &errors.RequestError{"Unexpected return type from Valkey"} + return nil, &errors.RequestError{Msg: "Unexpected return type from Valkey"} } func parseString(response *C.struct_CommandResponse) (interface{}, error) { @@ -210,7 +210,7 @@ func handle2DStringArrayResponse(response *C.struct_CommandResponse) ([][]string } res, ok := converted.([][]string) if !ok { - return nil, &errors.RequestError{fmt.Sprintf("unexpected type: %T", converted)} + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type: %T", converted)} } return res, nil } @@ -425,7 +425,7 @@ func handleStringDoubleMapResponse(response *C.struct_CommandResponse) (map[stri } result, ok := converted.(map[string]float64) if !ok { - return nil, &errors.RequestError{fmt.Sprintf("unexpected type of map: %T", converted)} + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of map: %T", converted)} } return result, nil } @@ -452,7 +452,7 @@ func handleStringToStringMapResponse(response *C.struct_CommandResponse) (map[st } result, ok := converted.(map[string]string) if !ok { - return nil, &errors.RequestError{fmt.Sprintf("unexpected type of map: %T", converted)} + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of map: %T", converted)} } return result, nil } @@ -489,7 +489,7 @@ func handleStringToStringArrayMapOrNilResponse( return result, nil } - return nil, &errors.RequestError{fmt.Sprintf("unexpected type received: %T", res)} + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type received: %T", res)} } func handleStringSetResponse(response *C.struct_CommandResponse) (map[string]struct{}, error) { @@ -596,7 +596,7 @@ func (node mapConverter[T]) convert(data interface{}) (interface{}, error) { if node.canBeNil { return nil, nil } else { - return nil, &errors.RequestError{fmt.Sprintf("Unexpected type received: nil, expected: map[string]%v", getType[T]())} + return nil, &errors.RequestError{Msg: fmt.Sprintf("Unexpected type received: nil, expected: map[string]%v", getType[T]())} } } result := make(map[string]T) @@ -608,7 +608,7 @@ func (node mapConverter[T]) convert(data interface{}) (interface{}, error) { valueT, ok := value.(T) if !ok { return nil, &errors.RequestError{ - fmt.Sprintf("Unexpected type of map element: %T, expected: %v", value, getType[T]()), + Msg: fmt.Sprintf("Unexpected type of map element: %T, expected: %v", value, getType[T]()), } } result[key] = valueT @@ -626,7 +626,7 @@ func (node mapConverter[T]) convert(data interface{}) (interface{}, error) { // convert to T valueT, ok := val.(T) if !ok { - return nil, &errors.RequestError{fmt.Sprintf("Unexpected type of map element: %T, expected: %v", val, getType[T]())} + return nil, &errors.RequestError{Msg: fmt.Sprintf("Unexpected type of map element: %T, expected: %v", val, getType[T]())} } result[key] = valueT } @@ -646,7 +646,7 @@ func (node arrayConverter[T]) convert(data interface{}) (interface{}, error) { if node.canBeNil { return nil, nil } else { - return nil, &errors.RequestError{fmt.Sprintf("Unexpected type received: nil, expected: []%v", getType[T]())} + return nil, &errors.RequestError{Msg: fmt.Sprintf("Unexpected type received: nil, expected: []%v", getType[T]())} } } arrData := data.([]interface{}) @@ -656,7 +656,7 @@ func (node arrayConverter[T]) convert(data interface{}) (interface{}, error) { valueT, ok := value.(T) if !ok { return nil, &errors.RequestError{ - fmt.Sprintf("Unexpected type of array element: %T, expected: %v", value, getType[T]()), + Msg: fmt.Sprintf("Unexpected type of array element: %T, expected: %v", value, getType[T]()), } } result = append(result, valueT) @@ -672,7 +672,7 @@ func (node arrayConverter[T]) convert(data interface{}) (interface{}, error) { } valueT, ok := val.(T) if !ok { - return nil, &errors.RequestError{fmt.Sprintf("Unexpected type of array element: %T, expected: %v", val, getType[T]())} + return nil, &errors.RequestError{Msg: fmt.Sprintf("Unexpected type of array element: %T, expected: %v", val, getType[T]())} } result = append(result, valueT) } @@ -709,7 +709,7 @@ func handleMapOfArrayOfStringArrayResponse(response *C.struct_CommandResponse) ( } claimedEntries, ok := converted.(map[string][][]string) if !ok { - return nil, &errors.RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of second element: %T", converted)} } return claimedEntries, nil @@ -729,7 +729,7 @@ func handleXAutoClaimResponse(response *C.struct_CommandResponse) (XAutoClaimRes arr := slice.([]interface{}) len := len(arr) if len < 2 || len > 3 { - return null, &errors.RequestError{fmt.Sprintf("Unexpected response array length: %d", len)} + return null, &errors.RequestError{Msg: fmt.Sprintf("Unexpected response array length: %d", len)} } converted, err := mapConverter[[][]string]{ arrayConverter[[]string]{ @@ -746,7 +746,7 @@ func handleXAutoClaimResponse(response *C.struct_CommandResponse) (XAutoClaimRes } claimedEntries, ok := converted.(map[string][][]string) if !ok { - return null, &errors.RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} + return null, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of second element: %T", converted)} } var deletedMessages []string deletedMessages = nil @@ -760,7 +760,7 @@ func handleXAutoClaimResponse(response *C.struct_CommandResponse) (XAutoClaimRes } deletedMessages, ok = converted.([]string) if !ok { - return null, &errors.RequestError{fmt.Sprintf("unexpected type of third element: %T", converted)} + return null, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of third element: %T", converted)} } } return XAutoClaimResponse{arr[0].(string), claimedEntries, deletedMessages}, nil @@ -780,7 +780,7 @@ func handleXAutoClaimJustIdResponse(response *C.struct_CommandResponse) (XAutoCl arr := slice.([]interface{}) len := len(arr) if len < 2 || len > 3 { - return null, &errors.RequestError{fmt.Sprintf("Unexpected response array length: %d", len)} + return null, &errors.RequestError{Msg: fmt.Sprintf("Unexpected response array length: %d", len)} } converted, err := arrayConverter[string]{ nil, @@ -791,7 +791,7 @@ func handleXAutoClaimJustIdResponse(response *C.struct_CommandResponse) (XAutoCl } claimedEntries, ok := converted.([]string) if !ok { - return null, &errors.RequestError{fmt.Sprintf("unexpected type of second element: %T", converted)} + return null, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of second element: %T", converted)} } var deletedMessages []string deletedMessages = nil @@ -805,7 +805,7 @@ func handleXAutoClaimJustIdResponse(response *C.struct_CommandResponse) (XAutoCl } deletedMessages, ok = converted.([]string) if !ok { - return null, &errors.RequestError{fmt.Sprintf("unexpected type of third element: %T", converted)} + return null, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of third element: %T", converted)} } } return XAutoClaimJustIdResponse{arr[0].(string), claimedEntries, deletedMessages}, nil @@ -842,7 +842,7 @@ func handleXReadResponse(response *C.struct_CommandResponse) (map[string]map[str if result, ok := res.(map[string]map[string][][]string); ok { return result, nil } - return nil, &errors.RequestError{fmt.Sprintf("unexpected type received: %T", res)} + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type received: %T", res)} } func handleXReadGroupResponse(response *C.struct_CommandResponse) (map[string]map[string][][]string, error) { @@ -876,7 +876,7 @@ func handleXReadGroupResponse(response *C.struct_CommandResponse) (map[string]ma if result, ok := res.(map[string]map[string][][]string); ok { return result, nil } - return nil, &errors.RequestError{fmt.Sprintf("unexpected type received: %T", res)} + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type received: %T", res)} } func handleXPendingSummaryResponse(response *C.struct_CommandResponse) (XPendingSummary, error) { From 2761f5d1c152c0f9f4e7f744382bf2eecd9934e5 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 22 Jan 2025 13:45:37 +0000 Subject: [PATCH 07/15] Fixed lint error Signed-off-by: Niharika Bhavaraju --- go/api/base_client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/api/base_client.go b/go/api/base_client.go index 360adfa17a..59bd813711 100644 --- a/go/api/base_client.go +++ b/go/api/base_client.go @@ -94,7 +94,7 @@ func createClient(config clientConfiguration) (*baseClient, error) { cErr := cResponse.connection_error_message if cErr != nil { message := C.GoString(cErr) - return nil, &errors.ConnectionError{message} + return nil, &errors.ConnectionError{Msg: message} } return &baseClient{cResponse.conn_ptr}, nil @@ -120,7 +120,7 @@ func (client *baseClient) executeCommandWithRoute( route config.Route, ) (*C.struct_CommandResponse, error) { if client.coreClient == nil { - return nil, &errors.ClosingError{"ExecuteCommand failed. The client is closed."} + return nil, &errors.ClosingError{Msg: "ExecuteCommand failed. The client is closed."} } var cArgsPtr *C.uintptr_t = nil var argLengthsPtr *C.ulong = nil From d6a5c21399b83dd92cd1d100e9512b3efbb1b9e4 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Mon, 27 Jan 2025 08:54:34 +0000 Subject: [PATCH 08/15] Fixed review comments Signed-off-by: Niharika Bhavaraju --- .../connection_management_cluster_commands.go | 4 +- go/api/connection_management_commands.go | 2 +- go/api/glide_client.go | 23 ++----- go/api/glide_cluster_client.go | 61 +++++++++++++++---- go/api/options/ping_options.go | 33 +++++----- go/api/response_types.go | 6 ++ go/integTest/cluster_commands_test.go | 53 ++++++++-------- go/integTest/standalone_commands_test.go | 21 ++++--- 8 files changed, 114 insertions(+), 89 deletions(-) diff --git a/go/api/connection_management_cluster_commands.go b/go/api/connection_management_cluster_commands.go index 7d26674b7d..42183df2b6 100644 --- a/go/api/connection_management_cluster_commands.go +++ b/go/api/connection_management_cluster_commands.go @@ -10,5 +10,7 @@ import "github.com/valkey-io/valkey-glide/go/glide/api/options" // // [valkey.io]: https://valkey.io/commands/#connection type ConnectionManagementClusterCommands interface { - PingWithOptions(pingOptions *options.PingOptions) (string, error) + Ping() (string, error) + + PingWithOptions(pingOptions options.ClusterPingOptions) (ClusterValue[string], error) } diff --git a/go/api/connection_management_commands.go b/go/api/connection_management_commands.go index 924382ad8a..ba9a77ff8b 100644 --- a/go/api/connection_management_commands.go +++ b/go/api/connection_management_commands.go @@ -12,7 +12,7 @@ import "github.com/valkey-io/valkey-glide/go/glide/api/options" type ConnectionManagementCommands interface { Ping() (string, error) - PingWithOptions(pingOptions *options.PingOptions) (string, error) + PingWithOptions(pingOptions options.PingOptions) (string, error) Echo(message string) (Result[string], error) } diff --git a/go/api/glide_client.go b/go/api/glide_client.go index 755d2408ea..06a3b912c2 100644 --- a/go/api/glide_client.go +++ b/go/api/glide_client.go @@ -7,7 +7,6 @@ package api import "C" import ( - "github.com/valkey-io/valkey-glide/go/glide/api/errors" "github.com/valkey-io/valkey-glide/go/glide/api/options" "github.com/valkey-io/valkey-glide/go/glide/utils" ) @@ -196,7 +195,7 @@ func (client *GlideClient) DBSize() (int64, error) { // fmt.Println(result.Value()) // Output: Hello World // // [valkey.io]: https://valkey.io/commands/echo/ -func (client *baseClient) Echo(message string) (Result[string], error) { +func (client *GlideClient) Echo(message string) (Result[string], error) { result, err := client.executeCommand(C.Echo, []string{message}) if err != nil { return CreateNilStringResult(), err @@ -215,12 +214,8 @@ func (client *baseClient) Echo(message string) (Result[string], error) { // result, err := client.Ping() // // [valkey.io]: https://valkey.io/commands/ping/ -func (client *glideClient) Ping() (string, error) { - result, err := client.executeCommand(C.Ping, []string{}) - if err != nil { - return defaultStringResponse, err - } - return handleStringResponse(result) +func (client *GlideClient) Ping() (string, error) { + return client.PingWithOptions(options.PingOptions{}) } // Pings the server. @@ -240,18 +235,10 @@ func (client *glideClient) Ping() (string, error) { // result: "hello" // // [valkey.io]: https://valkey.io/commands/ping/ -func (client *glideClient) PingWithOptions(opts *options.PingOptions) (string, error) { - if opts != nil && opts.Route != nil { - return defaultStringResponse, &errors.RequestError{Msg: "Route option is only available in cluster mode"} - } - args, err := opts.ToArgs() +func (client *GlideClient) PingWithOptions(pingOptions options.PingOptions) (string, error) { + result, err := client.executeCommand(C.Ping, pingOptions.ToArgs()) if err != nil { return defaultStringResponse, err } - result, err := client.executeCommand(C.Ping, append([]string{}, args...)) - if err != nil { - return defaultStringResponse, err - } - return handleStringResponse(result) } diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index d81ecb19df..c075ccb4e1 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -99,7 +99,7 @@ func (client *GlideClusterClient) CustomCommand(args []string) (ClusterValue[int // result.Value().(string): "PONG" // // [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command -func (client *glideClusterClient) CustomCommandWithRoute( +func (client *GlideClusterClient) CustomCommandWithRoute( args []string, route config.Route, ) (ClusterValue[interface{}], error) { @@ -114,6 +114,25 @@ func (client *glideClusterClient) CustomCommandWithRoute( return CreateClusterValue(data), nil } +// Pings the server. +// +// Return value: +// +// Returns "PONG". +// +// For example: +// +// result, err := clusterClient.Ping() +// +// [valkey.io]: https://valkey.io/commands/ping/ +func (client *GlideClusterClient) Ping() (string, error) { + result, err := client.executeCommand(C.Ping, []string{}) + if err != nil { + return defaultStringResponse, err + } + return handleStringResponse(result) +} + // Pings the server. // // Parameters: @@ -126,21 +145,39 @@ func (client *glideClusterClient) CustomCommandWithRoute( // // For example: // -// route := config.SimpleNodeRoute(config.RandomRoute) -// options := options.NewPingOptionsBuilder().SetRoute(route).SetMessage("Hello") -// result, err := client.PingWithOptions(options) -// fmt.Println(result) // Output: "Hello" +// route := config.Route(config.RandomRoute) +// opts := options.ClusterPingOptions{ +// PingOptions: &options.PingOptions{ +// Message: "Hello", +// }, +// Route: &route, +// } +// result, err := clusterClient.PingWithOptions(opts) +// fmt.Println(result.Value()) // Output: Hello // // [valkey.io]: https://valkey.io/commands/ping/ -func (client *glideClusterClient) PingWithOptions(opts *options.PingOptions) (string, error) { - args, err := opts.ToArgs() - if err != nil { - return defaultStringResponse, err + +func (client *GlideClusterClient) PingWithOptions(pingOptions options.ClusterPingOptions) (ClusterValue[string], error) { + if pingOptions.Route == nil { + response, err := client.executeCommand(C.Ping, pingOptions.ToArgs()) + if err != nil { + return CreateEmptyStringClusterValue(), err + } + data, err := handleStringResponse(response) + if err != nil { + return CreateEmptyStringClusterValue(), err + } + return CreateClusterValue(data), nil } - result, err := client.executeCommandWithRoute(C.Ping, args, opts.Route) + + response, err := client.executeCommandWithRoute(C.Ping, pingOptions.ToArgs(), *pingOptions.Route) if err != nil { - return defaultStringResponse, err + return CreateEmptyStringClusterValue(), err } - return handleStringResponse(result) + data, err := handleStringResponse(response) + if err != nil { + return CreateEmptyStringClusterValue(), err + } + return CreateClusterValue(data), nil } diff --git a/go/api/options/ping_options.go b/go/api/options/ping_options.go index 486b12e805..c070b0a499 100644 --- a/go/api/options/ping_options.go +++ b/go/api/options/ping_options.go @@ -7,29 +7,24 @@ import ( ) type PingOptions struct { - message string - Route config.Route + Message string } -func NewPingOptionsBuilder() *PingOptions { - return &PingOptions{} +type ClusterPingOptions struct { + *PingOptions + // Specifies the routing configuration for the command. + // The client will route the command to the nodes defined by *Route*. + // The command will be routed to all primary nodes, unless *Route* is provided. + Route *config.Route } -func (pingOptions *PingOptions) SetMessage(msg string) *PingOptions { - pingOptions.message = msg - return pingOptions -} - -func (pingOptions *PingOptions) SetRoute(route config.Route) *PingOptions { - pingOptions.Route = route - return pingOptions -} - -func (opts *PingOptions) ToArgs() ([]string, error) { +func (opts *PingOptions) ToArgs() []string { + if opts == nil { + return []string{} + } args := []string{} - - if opts.message != "" { - args = append(args, opts.message) + if opts.Message != "" { + args = append(args, opts.Message) } - return args, nil + return args } diff --git a/go/api/response_types.go b/go/api/response_types.go index 84de6aed7f..40e30e00fd 100644 --- a/go/api/response_types.go +++ b/go/api/response_types.go @@ -161,6 +161,12 @@ func CreateEmptyClusterValue() ClusterValue[interface{}] { } } +func CreateEmptyStringClusterValue() ClusterValue[string] { + return ClusterValue[string]{ + value: Result[string]{val: "", isNil: true}, + } +} + // XPendingSummary represents a summary of pending messages in a stream group. // It includes the total number of pending messages, the ID of the first and last pending messages, // and a list of consumer pending messages. diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index c7ee85a29b..1b3e4153dd 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -74,49 +74,46 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { } } -func (suite *GlideTestSuite) TestPingWithOptions_OnlyRoute() { +func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { client := suite.defaultClusterClient() - route := config.SimpleNodeRoute(config.RandomRoute) - options := options.NewPingOptionsBuilder(). - SetRoute(route) - - result, err := client.PingWithOptions(options) - assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "PONG", result) // Default response when no message is set -} - -func (suite *GlideTestSuite) TestPingWithOptions_BasicPing() { - client := suite.defaultClusterClient() - route := config.SimpleNodeRoute(config.RandomRoute) - options := options.NewPingOptionsBuilder(). - SetRoute(route). - SetMessage("hello") + options := options.ClusterPingOptions{ + PingOptions: &options.PingOptions{ + Message: "hello", + }, + Route: nil, + } result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "hello", result) + assert.Equal(suite.T(), "hello", result.Value()) } -func (suite *GlideTestSuite) TestPingWithOptions_AllNodes() { +func (suite *GlideTestSuite) TestPingWithOptions_WithRoute() { client := suite.defaultClusterClient() - route := config.SimpleNodeRoute(config.AllNodes) - options := options.NewPingOptionsBuilder(). - SetRoute(route). - SetMessage("hello") + route := config.Route(config.AllNodes) + options := options.ClusterPingOptions{ + PingOptions: &options.PingOptions{ + Message: "hello", + }, + Route: &route, + } result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "hello", result) + assert.Equal(suite.T(), "hello", result.Value()) } func (suite *GlideTestSuite) TestPingWithOptions_InvalidRoute() { client := suite.defaultClusterClient() - invalidRoute := config.NewByAddressRoute("invalidHost", 9999) - options := options.NewPingOptionsBuilder(). - SetRoute(invalidRoute). - SetMessage("hello") + invalidRoute := config.Route(config.NewByAddressRoute("invalidHost", 9999)) + options := options.ClusterPingOptions{ + PingOptions: &options.PingOptions{ + Message: "hello", + }, + Route: &invalidRoute, + } result, err := client.PingWithOptions(options) assert.NotNil(suite.T(), err) - assert.Equal(suite.T(), "", result) + assert.True(suite.T(), result.IsEmpty()) } diff --git a/go/integTest/standalone_commands_test.go b/go/integTest/standalone_commands_test.go index 69199bc5ef..3685148859 100644 --- a/go/integTest/standalone_commands_test.go +++ b/go/integTest/standalone_commands_test.go @@ -8,7 +8,6 @@ import ( "github.com/google/uuid" "github.com/valkey-io/valkey-glide/go/glide/api" - "github.com/valkey-io/valkey-glide/go/glide/api/config" "github.com/valkey-io/valkey-glide/go/glide/api/errors" "github.com/valkey-io/valkey-glide/go/glide/api/options" @@ -423,25 +422,27 @@ func (suite *GlideTestSuite) TestPing_ClosedClient() { assert.IsType(suite.T(), &errors.ClosingError{}, err) } -func (suite *GlideTestSuite) TestPingWithOptions_CustomMessage() { +func (suite *GlideTestSuite) TestPingWithOptions_WithMessage() { client := suite.defaultClient() - options := options.NewPingOptionsBuilder(). - SetMessage("hello") + options := options.PingOptions{ + Message: "hello", + } result, err := client.PingWithOptions(options) - assert.Nil(suite.T(), err) assert.Equal(suite.T(), "hello", result) } -func (suite *GlideTestSuite) TestPingWithOptions_WithRoute() { +func (suite *GlideTestSuite) TestPingWithOptions_ClosedClient() { client := suite.defaultClient() - options := options.NewPingOptionsBuilder(). - SetRoute(config.SimpleNodeRoute(config.RandomRoute)) + client.Close() - result, err := client.PingWithOptions(options) + options := options.PingOptions{ + Message: "hello", + } + result, err := client.PingWithOptions(options) assert.NotNil(suite.T(), err) assert.Equal(suite.T(), "", result) - assert.IsType(suite.T(), &errors.RequestError{}, err) + assert.IsType(suite.T(), &errors.ClosingError{}, err) } From 2e3d2d7b7a0131b003d0148abcf9112092733033 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Mon, 27 Jan 2025 09:27:57 +0000 Subject: [PATCH 09/15] Minor comments changes Signed-off-by: Niharika Bhavaraju --- go/api/glide_client.go | 2 +- go/api/glide_cluster_client.go | 2 +- go/api/options/ping_options.go | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go/api/glide_client.go b/go/api/glide_client.go index 06a3b912c2..15787f13af 100644 --- a/go/api/glide_client.go +++ b/go/api/glide_client.go @@ -226,7 +226,7 @@ func (client *GlideClient) Ping() (string, error) { // // Return value: // -// Returns "PONG" or the copy of message. +// Returns the copy of message. // // For example: // diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index c075ccb4e1..045ca8eb8b 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -141,7 +141,7 @@ func (client *GlideClusterClient) Ping() (string, error) { // // Return value: // -// Returns "PONG" or the copy of message. +// Returns the copy of message. // // For example: // diff --git a/go/api/options/ping_options.go b/go/api/options/ping_options.go index c070b0a499..dc5c527ff9 100644 --- a/go/api/options/ping_options.go +++ b/go/api/options/ping_options.go @@ -6,15 +6,16 @@ import ( "github.com/valkey-io/valkey-glide/go/glide/api/config" ) +// Optional arguments for `Ping` for standalone client type PingOptions struct { Message string } +// Optional arguments for `Ping` for cluster client type ClusterPingOptions struct { *PingOptions // Specifies the routing configuration for the command. // The client will route the command to the nodes defined by *Route*. - // The command will be routed to all primary nodes, unless *Route* is provided. Route *config.Route } From 6b9a527080456ebc44ea48fac0f06c9103f27392 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Mon, 27 Jan 2025 09:34:04 +0000 Subject: [PATCH 10/15] Fixed indents Signed-off-by: Niharika Bhavaraju --- go/api/glide_client.go | 9 +++++---- go/api/glide_cluster_client.go | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go/api/glide_client.go b/go/api/glide_client.go index 15787f13af..04a34851f7 100644 --- a/go/api/glide_client.go +++ b/go/api/glide_client.go @@ -189,10 +189,10 @@ func (client *GlideClient) DBSize() (int64, error) { // For example: // // result, err := client.Echo("Hello World") -// if err != nil { -// // handle error -// } -// fmt.Println(result.Value()) // Output: Hello World +// if err != nil { +// // handle error +// } +// fmt.Println(result.Value()) // Output: Hello World // // [valkey.io]: https://valkey.io/commands/echo/ func (client *GlideClient) Echo(message string) (Result[string], error) { @@ -212,6 +212,7 @@ func (client *GlideClient) Echo(message string) (Result[string], error) { // For example: // // result, err := client.Ping() +// fmt.Println(result) // Output: PONG // // [valkey.io]: https://valkey.io/commands/ping/ func (client *GlideClient) Ping() (string, error) { diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index 045ca8eb8b..32d672706a 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -123,6 +123,7 @@ func (client *GlideClusterClient) CustomCommandWithRoute( // For example: // // result, err := clusterClient.Ping() +// fmt.Println(result) // Output: PONG // // [valkey.io]: https://valkey.io/commands/ping/ func (client *GlideClusterClient) Ping() (string, error) { From 2ef39293680347951544b8a7cf2e3dbc6c52832d Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Mon, 27 Jan 2025 18:43:35 +0000 Subject: [PATCH 11/15] Fixed Response for Ping Signed-off-by: Niharika Bhavaraju --- .../connection_management_cluster_commands.go | 2 +- go/api/glide_cluster_client.go | 21 +++++++------------ go/api/response_types.go | 6 ------ go/integTest/cluster_commands_test.go | 6 +++--- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/go/api/connection_management_cluster_commands.go b/go/api/connection_management_cluster_commands.go index 42183df2b6..61d524d1b9 100644 --- a/go/api/connection_management_cluster_commands.go +++ b/go/api/connection_management_cluster_commands.go @@ -12,5 +12,5 @@ import "github.com/valkey-io/valkey-glide/go/glide/api/options" type ConnectionManagementClusterCommands interface { Ping() (string, error) - PingWithOptions(pingOptions options.ClusterPingOptions) (ClusterValue[string], error) + PingWithOptions(pingOptions options.ClusterPingOptions) (string, error) } diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index 32d672706a..ab16987395 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -135,6 +135,7 @@ func (client *GlideClusterClient) Ping() (string, error) { } // Pings the server. +// The command will be routed to all primary nodes // // Parameters: // @@ -154,31 +155,23 @@ func (client *GlideClusterClient) Ping() (string, error) { // Route: &route, // } // result, err := clusterClient.PingWithOptions(opts) -// fmt.Println(result.Value()) // Output: Hello +// fmt.Println(result) // Output: Hello // // [valkey.io]: https://valkey.io/commands/ping/ -func (client *GlideClusterClient) PingWithOptions(pingOptions options.ClusterPingOptions) (ClusterValue[string], error) { +func (client *GlideClusterClient) PingWithOptions(pingOptions options.ClusterPingOptions) (string, error) { if pingOptions.Route == nil { response, err := client.executeCommand(C.Ping, pingOptions.ToArgs()) if err != nil { - return CreateEmptyStringClusterValue(), err + return defaultStringResponse, err } - data, err := handleStringResponse(response) - if err != nil { - return CreateEmptyStringClusterValue(), err - } - return CreateClusterValue(data), nil + return handleStringResponse(response) } response, err := client.executeCommandWithRoute(C.Ping, pingOptions.ToArgs(), *pingOptions.Route) if err != nil { - return CreateEmptyStringClusterValue(), err + return defaultStringResponse, err } - data, err := handleStringResponse(response) - if err != nil { - return CreateEmptyStringClusterValue(), err - } - return CreateClusterValue(data), nil + return handleStringResponse(response) } diff --git a/go/api/response_types.go b/go/api/response_types.go index 40e30e00fd..84de6aed7f 100644 --- a/go/api/response_types.go +++ b/go/api/response_types.go @@ -161,12 +161,6 @@ func CreateEmptyClusterValue() ClusterValue[interface{}] { } } -func CreateEmptyStringClusterValue() ClusterValue[string] { - return ClusterValue[string]{ - value: Result[string]{val: "", isNil: true}, - } -} - // XPendingSummary represents a summary of pending messages in a stream group. // It includes the total number of pending messages, the ID of the first and last pending messages, // and a list of consumer pending messages. diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index 1b3e4153dd..30a71d75f2 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -85,7 +85,7 @@ func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "hello", result.Value()) + assert.Equal(suite.T(), "hello", result) } func (suite *GlideTestSuite) TestPingWithOptions_WithRoute() { @@ -100,7 +100,7 @@ func (suite *GlideTestSuite) TestPingWithOptions_WithRoute() { result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "hello", result.Value()) + assert.Equal(suite.T(), "hello", result) } func (suite *GlideTestSuite) TestPingWithOptions_InvalidRoute() { @@ -115,5 +115,5 @@ func (suite *GlideTestSuite) TestPingWithOptions_InvalidRoute() { result, err := client.PingWithOptions(options) assert.NotNil(suite.T(), err) - assert.True(suite.T(), result.IsEmpty()) + assert.Empty(suite.T(), result) } From d7257269bd3282d6e32f813e2debcfcf7963dcd5 Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Tue, 28 Jan 2025 04:05:14 +0000 Subject: [PATCH 12/15] Fixed code review comments Signed-off-by: Niharika Bhavaraju --- go/api/glide_cluster_client.go | 15 +++++++-------- go/integTest/cluster_commands_test.go | 14 +++----------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index ab16987395..ddba16dc4f 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -135,7 +135,7 @@ func (client *GlideClusterClient) Ping() (string, error) { } // Pings the server. -// The command will be routed to all primary nodes +// The command will be routed to all primary nodes, unless `Route` is provided in `pingOptions`. // // Parameters: // @@ -148,17 +148,16 @@ func (client *GlideClusterClient) Ping() (string, error) { // For example: // // route := config.Route(config.RandomRoute) -// opts := options.ClusterPingOptions{ -// PingOptions: &options.PingOptions{ -// Message: "Hello", -// }, -// Route: &route, -// } +// opts := options.ClusterPingOptions{ +// PingOptions: &options.PingOptions{ +// Message: "Hello", +// }, +// Route: &route, +// } // result, err := clusterClient.PingWithOptions(opts) // fmt.Println(result) // Output: Hello // // [valkey.io]: https://valkey.io/commands/ping/ - func (client *GlideClusterClient) PingWithOptions(pingOptions options.ClusterPingOptions) (string, error) { if pingOptions.Route == nil { response, err := client.executeCommand(C.Ping, pingOptions.ToArgs()) diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index 30a71d75f2..3c920c51bf 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -60,18 +60,10 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_InvalidRoute() { func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { client := suite.defaultClusterClient() route := config.SimpleNodeRoute(config.AllNodes) - result, _ := client.CustomCommandWithRoute([]string{"PING"}, route) + result, err := client.CustomCommandWithRoute([]string{"PING"}, route) value := result.Value() - - if result.IsMultiValue() { - responses := value.(map[string]interface{}) - assert.Greater(suite.T(), len(responses), 0) - for _, response := range responses { - assert.Equal(suite.T(), "PONG", response.(string)) - } - } else { - assert.Equal(suite.T(), "PONG", value.(string)) - } + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "PONG", value.(string)) } func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { From a3f6549d81c6d98c046a22f2f5e04a3d92b5017e Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 29 Jan 2025 09:34:54 +0000 Subject: [PATCH 13/15] Fixed review comments and failing tests Signed-off-by: Niharika Bhavaraju --- go/api/glide_cluster_client.go | 134 +------------------------- go/integTest/cluster_commands_test.go | 24 +++-- 2 files changed, 18 insertions(+), 140 deletions(-) diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index 6ca8687ccb..13ef1323af 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -186,8 +186,8 @@ func (client *GlideClusterClient) InfoWithOptions(options ClusterInfoOptions) (C // For example: // // route := config.SimpleNodeRoute(config.RandomRoute) -// result, err := client.CustomCommand([]string{"ping"}, route) -// result.Value().(string): "PONG" +// result, err := client.CustomCommandWithRoute([]string{"ping"}, route) +// result.SingleValue().(string): "PONG" // // [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command func (client *GlideClusterClient) CustomCommandWithRoute( @@ -205,139 +205,11 @@ func (client *GlideClusterClient) CustomCommandWithRoute( return createClusterValue[interface{}](data), nil } -// Gets information and statistics about the server. -// -// The command will be routed to all primary nodes. -// -// See [valkey.io] for details. -// -// Return value: -// -// A map where each address is the key and its corresponding node response is the information for the default sections. -// -// Example: -// -// response, err := clusterClient.Info(opts) -// if err != nil { -// // handle error -// } -// for node, data := range response { -// fmt.Printf("%s node returned %s\n", node, data) -// } -// -// [valkey.io]: https://valkey.io/commands/info/ -func (client *GlideClusterClient) Info() (map[string]string, error) { - result, err := client.executeCommand(C.Info, []string{}) - if err != nil { - return nil, err - } - - return handleStringToStringMapResponse(result) -} - -// Gets information and statistics about the server. -// -// The command will be routed to all primary nodes, unless `route` in [ClusterInfoOptions] is provided. -// -// See [valkey.io] for details. -// -// Parameters: -// -// options - Additional command parameters, see [ClusterInfoOptions] for more details. -// -// Return value: -// -// When specifying a route other than a single node or when route is not given, -// it returns a map where each address is the key and its corresponding node response is the value. -// When a single node route is given, command returns a string containing the information for the sections requested. -// -// Example: -// -// opts := api.ClusterInfoOptions{ -// InfoOptions: &api.InfoOptions{Sections: []api.Section{api.Server}}, -// Route: api.RandomRoute.ToPtr(), -// } -// response, err := clusterClient.InfoWithOptions(opts) -// if err != nil { -// // handle error -// } -// // Command sent to a single random node via RANDOM route, expecting SingleValue result as a `string`. -// fmt.Println(response.SingleValue()) -// -// [valkey.io]: https://valkey.io/commands/info/ -func (client *GlideClusterClient) InfoWithOptions(options ClusterInfoOptions) (ClusterValue[string], error) { - if options.Route == nil { - response, err := client.executeCommand(C.Info, options.toArgs()) - if err != nil { - return createEmptyClusterValue[string](), err - } - data, err := handleStringToStringMapResponse(response) - if err != nil { - return createEmptyClusterValue[string](), err - } - return createClusterMultiValue[string](data), nil - } - response, err := client.executeCommandWithRoute(C.Info, options.toArgs(), *options.Route) - if err != nil { - return createEmptyClusterValue[string](), err - } - if (*options.Route).IsMultiNode() { - data, err := handleStringToStringMapResponse(response) - if err != nil { - return createEmptyClusterValue[string](), err - } - return createClusterMultiValue[string](data), nil - } - data, err := handleStringResponse(response) - if err != nil { - return createEmptyClusterValue[string](), err - } - return createClusterSingleValue[string](data), nil -} - -// CustomCommandWithRoute executes a single command, specified by args, without checking inputs. Every part of the command, -// including the command name and subcommands, should be added as a separate value in args. The returning value depends on -// the executed command. -// -// See [Valkey GLIDE Wiki] for details on the restrictions and limitations of the custom command API. -// -// Parameters: -// -// args - Arguments for the custom command including the command name. -// route - Specifies the routing configuration for the command. The client will route the -// command to the nodes defined by route. -// -// Return value: -// -// The returning value depends on the executed command and route. -// -// For example: -// -// route := config.SimpleNodeRoute(config.RandomRoute) -// result, err := client.CustomCommand([]string{"ping"}, route) -// result.Value().(string): "PONG" -// -// [Valkey GLIDE Wiki]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command -func (client *GlideClusterClient) CustomCommandWithRoute( - args []string, - route config.Route, -) (ClusterValue[interface{}], error) { - res, err := client.executeCommandWithRoute(C.CustomCommand, args, route) - if err != nil { - return CreateEmptyClusterValue(), err - } - data, err := handleInterfaceResponse(res) - if err != nil { - return CreateEmptyClusterValue(), err - } - return CreateClusterValue(data), nil -} - // Pings the server. // // Return value: // -// Returns "PONG". +// Returns "PONG". // // For example: // diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index f1e2714754..5ed6064705 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -107,13 +107,17 @@ func (suite *GlideTestSuite) TestInfoCluster() { } } } + func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Info() { client := suite.defaultClusterClient() route := config.SimpleNodeRoute(config.AllPrimaries) result, err := client.CustomCommandWithRoute([]string{"INFO"}, route) assert.Nil(suite.T(), err) - for _, value := range result.Value().(map[string]interface{}) { - assert.True(suite.T(), strings.Contains(value.(string), "# Stats")) + assert.True(suite.T(), result.IsMultiValue()) + + multiValue := result.MultiValue() + for nodeName, value := range multiValue { + assert.True(suite.T(), strings.Contains(value.(string), "# Stats"), "Node %s info should contain '# Stats'", nodeName) } } @@ -122,7 +126,8 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Echo() { route := config.SimpleNodeRoute(config.RandomRoute) result, err := client.CustomCommandWithRoute([]string{"ECHO", "GO GLIDE GO"}, route) assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "GO GLIDE GO", result.Value().(string)) + assert.True(suite.T(), result.IsSingleValue()) + assert.Equal(suite.T(), "GO GLIDE GO", result.SingleValue().(string)) } func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_InvalidRoute() { @@ -130,16 +135,20 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_InvalidRoute() { invalidRoute := config.NewByAddressRoute("invalidHost", 9999) result, err := client.CustomCommandWithRoute([]string{"PING"}, invalidRoute) assert.NotNil(suite.T(), err) - assert.Equal(suite.T(), api.CreateEmptyClusterValue(), result) + assert.True(suite.T(), result.IsEmpty()) } func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { client := suite.defaultClusterClient() route := config.SimpleNodeRoute(config.AllNodes) result, err := client.CustomCommandWithRoute([]string{"PING"}, route) - value := result.Value() assert.Nil(suite.T(), err) - assert.Equal(suite.T(), "PONG", value.(string)) + assert.True(suite.T(), result.IsMultiValue()) + + multiValue := result.MultiValue() + for nodeName, value := range multiValue { + assert.Equal(suite.T(), "PONG", value.(string), "Node %s should return 'PONG'", nodeName) + } } func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { @@ -150,7 +159,6 @@ func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { }, Route: nil, } - result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "hello", result) @@ -165,7 +173,6 @@ func (suite *GlideTestSuite) TestPingWithOptions_WithRoute() { }, Route: &route, } - result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "hello", result) @@ -180,7 +187,6 @@ func (suite *GlideTestSuite) TestPingWithOptions_InvalidRoute() { }, Route: &invalidRoute, } - result, err := client.PingWithOptions(options) assert.NotNil(suite.T(), err) assert.Empty(suite.T(), result) From 23b0bd332b1960b7de3aca9b72ecc72bbfbd200d Mon Sep 17 00:00:00 2001 From: Niharika Bhavaraju Date: Wed, 29 Jan 2025 10:12:50 +0000 Subject: [PATCH 14/15] Fixed failed tests Signed-off-by: Niharika Bhavaraju --- go/integTest/cluster_commands_test.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index 5ed6064705..3c329e2bdc 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -114,10 +114,9 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_Info() { result, err := client.CustomCommandWithRoute([]string{"INFO"}, route) assert.Nil(suite.T(), err) assert.True(suite.T(), result.IsMultiValue()) - multiValue := result.MultiValue() - for nodeName, value := range multiValue { - assert.True(suite.T(), strings.Contains(value.(string), "# Stats"), "Node %s info should contain '# Stats'", nodeName) + for _, value := range multiValue { + assert.True(suite.T(), strings.Contains(value.(string), "# Stats")) } } @@ -143,12 +142,8 @@ func (suite *GlideTestSuite) TestClusterCustomCommandWithRoute_AllNodes() { route := config.SimpleNodeRoute(config.AllNodes) result, err := client.CustomCommandWithRoute([]string{"PING"}, route) assert.Nil(suite.T(), err) - assert.True(suite.T(), result.IsMultiValue()) - - multiValue := result.MultiValue() - for nodeName, value := range multiValue { - assert.Equal(suite.T(), "PONG", value.(string), "Node %s should return 'PONG'", nodeName) - } + assert.True(suite.T(), result.IsSingleValue()) + assert.Equal(suite.T(), "PONG", result.SingleValue()) } func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { From 2c04be7041ec52ba62804dacd81a1d217304e03b Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Wed, 29 Jan 2025 10:06:04 -0800 Subject: [PATCH 15/15] Update go/api/glide_cluster_client.go Signed-off-by: Yury-Fridlyand --- go/api/glide_cluster_client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index 13ef1323af..17ea2259e0 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -206,6 +206,7 @@ func (client *GlideClusterClient) CustomCommandWithRoute( } // Pings the server. +// The command will be routed to all primary nodes. // // Return value: //