Skip to content

Commit

Permalink
feature/box: first box and box.info implementation
Browse files Browse the repository at this point in the history
I implemented the box interface for tarantool with a small number of fields, which in the future can be supplemented
  • Loading branch information
Maksim Konovalov committed Oct 19, 2024
1 parent 8cf8673 commit ddbfd7b
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
- Methods that are implemented but not included in the pooler interface (#395).
- Implemented stringer methods for pool.Role (#405).
- Support the IPROTO_INSERT_ARROW request (#399).
- A simple implementation of using the box interface was written (#410).

### Changed

Expand Down
24 changes: 24 additions & 0 deletions box/box.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package box

import (
"github.com/tarantool/go-tarantool/v2"
)

// Box defines an interface for interacting with a Tarantool instance.
// It includes the Info method, which retrieves instance information.
type Box interface {
Info() (Info, error) // Retrieves detailed information about the Tarantool instance.
}

// box is a concrete implementation of the Box interface.
// It holds a connection to the Tarantool instance via the Doer interface.
type box struct {
conn tarantool.Doer // Connection interface for interacting with Tarantool.
}

// By returns a new instance of the box structure, which implements the Box interface.
func By(conn tarantool.Doer) Box {
return &box{
conn: conn, // Assigns the provided Tarantool connection.
}
}
27 changes: 27 additions & 0 deletions box/box_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package box_test

import (
"testing"

"github.com/stretchr/testify/require"
"github.com/tarantool/go-tarantool/v2/box"
)

func TestBy(t *testing.T) {
// We expect a panic because we are passing a nil connection (nil Doer) to the By function.
// The library does not control this zone, and the nil connection would cause a runtime error
// when we attempt to call methods (like Info) on it. This test ensures that such an invalid state

Check failure on line 13 in box/box_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

the line is 102 characters long, which exceeds the maximum of 100 characters. (lll)
// is correctly handled by causing a panic, as it's outside of the library's responsibility.
require.Panics(t, func() {
// Create a box instance with a nil connection. This should lead to a panic later.
b := box.By(nil)

// Ensure the box instance is not nil (which it shouldn't be), but this is not meaningful
// since we will panic when we call the Info method with the nil connection.
require.NotNil(t, b)

// Calling Info on a box with a nil connection will result in a panic, since the underlying
// connection (Doer) cannot perform the requested action (it's nil).
_, _ = b.Info()
})
}
40 changes: 40 additions & 0 deletions box/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package box

import "github.com/tarantool/go-tarantool/v2"

// ClusterInfo represents information about the cluster.
// It contains the unique identifier (UUID) of the cluster.
type ClusterInfo struct {
UUID string `msgpack:"uuid"`
}

// Info represents detailed information about the Tarantool instance.
// It includes version, node ID, read-only status, process ID, cluster information, and more.
type Info struct {
Version string `msgpack:"version"` // The version of the Tarantool instance.
ID *int `msgpack:"id"` // The node ID (nullable).
RO bool `msgpack:"ro"` // Read-only status of the instance.
UUID string `msgpack:"uuid"` // Unique identifier of the instance.
PID int `msgpack:"pid"` // Process ID of the instance.
Status string `msgpack:"status"` // Current status of the instance (e.g., running, unconfigured).

Check failure on line 19 in box/info.go

View workflow job for this annotation

GitHub Actions / golangci-lint

the line is 108 characters long, which exceeds the maximum of 100 characters. (lll)
Lsn uint64 `msgpack:"lsn"` // Log sequence number of the instance.
Cluster ClusterInfo `msgpack:"cluster"` // Cluster information, including cluster UUID.
}

// Info retrieves the current information of the Tarantool instance.
// It calls the "box.info" function and parses the result into the Info structure.
func (b *box) Info() (Info, error) {
var info Info

// Call "box.info" to get instance information from Tarantool.
fut := b.conn.Do(tarantool.NewCallRequest("box.info"))

// Parse the result into the Info structure.
err := fut.GetTyped(&[]interface{}{&info})
if err != nil {
return Info{}, err
}

// Return the parsed info and any potential error.
return info, err
}
73 changes: 73 additions & 0 deletions box/tarantool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package box_test

import (
"context"
"log"
"os"
"testing"
"time"

"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/tarantool/go-tarantool/v2"
"github.com/tarantool/go-tarantool/v2/box"
"github.com/tarantool/go-tarantool/v2/test_helpers"
)

var server = "127.0.0.1:3014"
var dialer = tarantool.NetDialer{
Address: server,
User: "test",
Password: "test",
}

func validateUUID(t *testing.T, u string) {
var err error

_, err = uuid.Parse(u)

require.NoError(t, err)
}

func TestBox_Info(t *testing.T) {
ctx := context.TODO()

conn, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
require.NoError(t, err)

info, err := box.By(conn).Info()
require.NoError(t, err)

// check all fields run correctly
validateUUID(t, info.UUID)
validateUUID(t, info.Cluster.UUID)

require.NotEmpty(t, info.Version)
// check that pid parsed correctly
require.NotEqual(t, info.PID, 0)

}

func runTestMain(m *testing.M) int {
instance, err := test_helpers.StartTarantool(test_helpers.StartOpts{
Dialer: dialer,
InitScript: "config.lua",
Listen: server,
WaitStart: 100 * time.Millisecond,
ConnectRetry: 10,
RetryTimeout: 500 * time.Millisecond,
})
defer test_helpers.StopTarantoolWithCleanup(instance)

if err != nil {
log.Printf("Failed to prepare test Tarantool: %s", err)
return 1
}

return m.Run()
}

func TestMain(m *testing.M) {
code := runTestMain(m)
os.Exit(code)
}

0 comments on commit ddbfd7b

Please sign in to comment.