Skip to content

Commit

Permalink
Fix merge conflict
Browse files Browse the repository at this point in the history
Signed-off-by: EdricCua <[email protected]>
  • Loading branch information
EdricCua committed Jan 30, 2025
2 parents 88b9bf1 + b4e28e2 commit 2b45648
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/scale-shr-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:

jobs:
hello-world:
runs-on: [self-hosted, linux, ARM64]
runs-on: [self-hosted, linux, ARM64, ephemeral]
steps:
- name: print Hello World
run: echo "Hello World"
21 changes: 21 additions & 0 deletions go/api/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6849,3 +6849,24 @@ func (client *baseClient) BitFieldRO(key string, commands []options.BitFieldROCo
}
return handleIntOrNilArrayResponse(result)
}

// Returns the server time.
//
// Return value:
// The current server time as a String array with two elements:
// A UNIX TIME and the amount of microseconds already elapsed in the current second.
// The returned array is in a [UNIX TIME, Microseconds already elapsed] format.
//
// For example:
//
// result, err := client.Time()
// result: [{1737051660} {994688}]
//
// [valkey.io]: https://valkey.io/commands/time/
func (client *baseClient) Time() ([]string, error) {
result, err := client.executeCommand(C.Time, []string{})
if err != nil {
return nil, err
}
return handleStringArrayResponse(result)
}
32 changes: 32 additions & 0 deletions go/api/glide_cluster_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,38 @@ func (client *GlideClusterClient) PingWithOptions(pingOptions options.ClusterPin
return handleStringResponse(response)
}

// Returns the server time.
// The command will be routed to a random node, unless Route in opts is provided.
//
// See [valkey.io] for details.
//
// Parameters:
//
// options - The TimeOptions type.
//
// Return value:
//
// The current server time as a String array with two elements: A UNIX TIME and the amount
// of microseconds already elapsed in the current second.
// The returned array is in a [UNIX TIME, Microseconds already elapsed] format.
//
// Example:
//
// route := config.Route(config.RandomRoute)
// opts := options.ClusterTimeOptions{
// Route: &route,
// }
// fmt.Println(clusterResponse.SingleValue()) // Output: [1737994354 547816]
//
// [valkey.io]: https://valkey.io/commands/time/
func (client *GlideClusterClient) TimeWithOptions(opts options.RouteOption) (ClusterValue[[]string], error) {
result, err := client.executeCommandWithRoute(C.Time, []string{}, opts.Route)
if err != nil {
return createEmptyClusterValue[[]string](), err
}
return handleTimeClusterResponse(result)
}

// Returns the number of keys in the database.
//
// Return value:
Expand Down
50 changes: 50 additions & 0 deletions go/api/response_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1003,3 +1003,53 @@ func handleXPendingDetailResponse(response *C.struct_CommandResponse) ([]XPendin

return pendingDetails, nil
}

func handleRawStringArrayMapResponse(response *C.struct_CommandResponse) (map[string][]string, error) {
defer C.free_command_response(response)
typeErr := checkResponseType(response, C.Map, false)
if typeErr != nil {
return nil, typeErr
}

data, err := parseMap(response)
if err != nil {
return nil, err
}

result, err := mapConverter[[]string]{
next: arrayConverter[string]{},
canBeNil: false,
}.convert(data)
if err != nil {
return nil, err
}
mapResult, ok := result.(map[string][]string)
if !ok {
return nil, &errors.RequestError{Msg: "Unexpected conversion result type"}
}

return mapResult, nil
}

func handleTimeClusterResponse(response *C.struct_CommandResponse) (ClusterValue[[]string], error) {
// Handle multi-node response
if err := checkResponseType(response, C.Map, true); err == nil {
mapData, err := handleRawStringArrayMapResponse(response)
if err != nil {
return createEmptyClusterValue[[]string](), err
}
multiNodeTimes := make(map[string][]string)
for nodeName, nodeTimes := range mapData {
multiNodeTimes[nodeName] = nodeTimes
}

return createClusterMultiValue(multiNodeTimes), nil
}

// Handle single node response
data, err := handleStringArrayResponse(response)
if err != nil {
return createEmptyClusterValue[[]string](), err
}
return createClusterSingleValue(data), nil
}
2 changes: 2 additions & 0 deletions go/api/server_management_cluster_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ type ServerManagementClusterCommands interface {

InfoWithOptions(options ClusterInfoOptions) (ClusterValue[string], error)

TimeWithOptions(routeOption options.RouteOption) (ClusterValue[[]string], error)

DBSizeWithOptions(routeOption options.RouteOption) (int64, error)
}
2 changes: 2 additions & 0 deletions go/api/server_management_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ type ServerManagementCommands interface {
InfoWithOptions(options InfoOptions) (string, error)

DBSize() (int64, error)

Time() ([]string, error)
}
58 changes: 58 additions & 0 deletions go/integTest/cluster_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,64 @@ func (suite *GlideTestSuite) TestPingWithOptions_InvalidRoute() {
assert.Empty(suite.T(), result)
}

func (suite *GlideTestSuite) TestTimeWithoutRoute() {
client := suite.defaultClusterClient()
options := options.RouteOption{Route: nil}
result, err := client.TimeWithOptions(options)
assert.NoError(suite.T(), err)
assert.NotNil(suite.T(), result)
assert.False(suite.T(), result.IsEmpty())
assert.True(suite.T(), result.IsSingleValue())
assert.NotEmpty(suite.T(), result.SingleValue())
assert.IsType(suite.T(), "", result.SingleValue()[0])
assert.Equal(suite.T(), 2, len(result.SingleValue()))
}

func (suite *GlideTestSuite) TestTimeWithAllNodesRoute() {
client := suite.defaultClusterClient()
route := config.Route(config.AllNodes)
options := options.RouteOption{Route: route}
result, err := client.TimeWithOptions(options)
assert.NoError(suite.T(), err)
assert.NotNil(suite.T(), result)
assert.False(suite.T(), result.IsEmpty())
assert.True(suite.T(), result.IsMultiValue())

multiValue := result.MultiValue()
assert.Greater(suite.T(), len(multiValue), 1)

for nodeName, timeStrings := range multiValue {
assert.NotEmpty(suite.T(), timeStrings, "Node %s should have time values", nodeName)
for _, timeStr := range timeStrings {
assert.IsType(suite.T(), "", timeStr)
}
}
}

func (suite *GlideTestSuite) TestTimeWithRandomRoute() {
client := suite.defaultClusterClient()
route := config.Route(config.RandomRoute)
options := options.RouteOption{Route: route}
result, err := client.TimeWithOptions(options)
assert.NoError(suite.T(), err)
assert.NotNil(suite.T(), result)
assert.False(suite.T(), result.IsEmpty())
assert.True(suite.T(), result.IsSingleValue())
assert.NotEmpty(suite.T(), result.SingleValue())
assert.IsType(suite.T(), "", result.SingleValue()[0])
assert.Equal(suite.T(), 2, len(result.SingleValue()))
}

func (suite *GlideTestSuite) TestTimeWithInvalidRoute() {
client := suite.defaultClusterClient()
invalidRoute := config.Route(config.NewByAddressRoute("invalidHost", 9999))
options := options.RouteOption{Route: invalidRoute}
result, err := client.TimeWithOptions(options)
assert.NotNil(suite.T(), err)
assert.True(suite.T(), result.IsEmpty())
assert.Empty(suite.T(), result.SingleValue())
}

func (suite *GlideTestSuite) TestDBSizeRandomRoute() {
client := suite.defaultClusterClient()
route := config.Route(config.RandomRoute)
Expand Down
33 changes: 33 additions & 0 deletions go/integTest/standalone_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ package integTest

import (
"fmt"
"strconv"
"strings"
"time"

"github.com/google/uuid"
"github.com/valkey-io/valkey-glide/go/glide/api"
Expand Down Expand Up @@ -483,3 +485,34 @@ func (suite *GlideTestSuite) TestPingWithOptions_ClosedClient() {
assert.Equal(suite.T(), "", result)
assert.IsType(suite.T(), &errors.ClosingError{}, err)
}

func (suite *GlideTestSuite) TestTime_Success() {
client := suite.defaultClient()
results, err := client.Time()

assert.Nil(suite.T(), err)
assert.Len(suite.T(), results, 2)

now := time.Now().Unix() - 1

timestamp, err := strconv.ParseInt(results[0], 10, 64)
assert.Nil(suite.T(), err)
assert.Greater(suite.T(), timestamp, now)

microseconds, err := strconv.ParseInt(results[1], 10, 64)
assert.Nil(suite.T(), err)
assert.Less(suite.T(), microseconds, int64(1000000))
}

func (suite *GlideTestSuite) TestTime_Error() {
client := suite.defaultClient()

// Disconnect the client or simulate an error condition
client.Close()

results, err := client.Time()

assert.NotNil(suite.T(), err)
assert.Nil(suite.T(), results)
assert.IsType(suite.T(), &errors.ClosingError{}, err)
}

0 comments on commit 2b45648

Please sign in to comment.