Skip to content

Commit 5d9ad18

Browse files
author
Maksim Konovalov
committed
feature/box: first box and box.info implementation
I implemented the box interface for tarantool with a small number of fields, which in the future can be supplemented
1 parent 8cf8673 commit 5d9ad18

File tree

6 files changed

+179
-0
lines changed

6 files changed

+179
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
1616
- Methods that are implemented but not included in the pooler interface (#395).
1717
- Implemented stringer methods for pool.Role (#405).
1818
- Support the IPROTO_INSERT_ARROW request (#399).
19+
- A simple implementation of using the box interface was written (#410).
1920

2021
### Changed
2122

box/box.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package box
2+
3+
import (
4+
"github.com/tarantool/go-tarantool/v2"
5+
)
6+
7+
// Box defines an interface for interacting with a Tarantool instance.
8+
// It includes the Info method, which retrieves instance information.
9+
type Box interface {
10+
Info() (Info, error) // Retrieves detailed information about the Tarantool instance.
11+
}
12+
13+
// box is a concrete implementation of the Box interface.
14+
// It holds a connection to the Tarantool instance via the Doer interface.
15+
type box struct {
16+
conn tarantool.Doer // Connection interface for interacting with Tarantool.
17+
}
18+
19+
// By returns a new instance of the box structure, which implements the Box interface.
20+
func By(conn tarantool.Doer) Box {
21+
return &box{
22+
conn: conn, // Assigns the provided Tarantool connection.
23+
}
24+
}

box/box_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package box_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
"github.com/tarantool/go-tarantool/v2/box"
8+
)
9+
10+
func TestBy(t *testing.T) {
11+
// We expect a panic because we are passing a nil connection (nil Doer) to the By function.
12+
// The library does not control this zone, and the nil connection would cause a runtime error
13+
// when we attempt to call methods (like Info) on it.
14+
// This test ensures that such an invalid state is correctly handled by causing a panic,
15+
// as it's outside of the library's responsibility.
16+
require.Panics(t, func() {
17+
// Create a box instance with a nil connection. This should lead to a panic later.
18+
b := box.By(nil)
19+
20+
// Ensure the box instance is not nil (which it shouldn't be), but this is not meaningful
21+
// since we will panic when we call the Info method with the nil connection.
22+
require.NotNil(t, b)
23+
24+
// Calling Info on a box with a nil connection will result in a panic, since the underlying
25+
// connection (Doer) cannot perform the requested action (it's nil).
26+
_, _ = b.Info()
27+
})
28+
}

box/info.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package box
2+
3+
import "github.com/tarantool/go-tarantool/v2"
4+
5+
// ClusterInfo represents information about the cluster.
6+
// It contains the unique identifier (UUID) of the cluster.
7+
type ClusterInfo struct {
8+
UUID string `msgpack:"uuid"`
9+
}
10+
11+
// Info represents detailed information about the Tarantool instance.
12+
// It includes version, node ID, read-only status, process ID, cluster information, and more.
13+
type Info struct {
14+
// The Version of the Tarantool instance.
15+
Version string `msgpack:"version"`
16+
// The node ID (nullable).
17+
ID *int `msgpack:"id"`
18+
// Read-only (RO) status of the instance.
19+
RO bool `msgpack:"ro"`
20+
// UUID - Unique identifier of the instance.
21+
UUID string `msgpack:"uuid"`
22+
// Process ID of the instance.
23+
PID int `msgpack:"pid"`
24+
// Status - Current status of the instance (e.g., running, unconfigured).
25+
Status string `msgpack:"status"`
26+
// LSN - Log sequence number of the instance.
27+
LSN uint64 `msgpack:"lsn"`
28+
// Cluster information, including cluster UUID.
29+
Cluster ClusterInfo `msgpack:"cluster"`
30+
}
31+
32+
// Info retrieves the current information of the Tarantool instance.
33+
// It calls the "box.info" function and parses the result into the Info structure.
34+
func (b *box) Info() (Info, error) {
35+
var info Info
36+
37+
// Call "box.info" to get instance information from Tarantool.
38+
fut := b.conn.Do(tarantool.NewCallRequest("box.info"))
39+
40+
// Parse the result into the Info structure.
41+
err := fut.GetTyped(&[]interface{}{&info})
42+
if err != nil {
43+
return Info{}, err
44+
}
45+
46+
// Return the parsed info and any potential error.
47+
return info, err
48+
}

box/tarantool_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package box_test
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
"testing"
8+
"time"
9+
10+
"github.com/google/uuid"
11+
"github.com/stretchr/testify/require"
12+
"github.com/tarantool/go-tarantool/v2"
13+
"github.com/tarantool/go-tarantool/v2/box"
14+
"github.com/tarantool/go-tarantool/v2/test_helpers"
15+
)
16+
17+
var server = "127.0.0.1:3013"
18+
var dialer = tarantool.NetDialer{
19+
Address: server,
20+
User: "test",
21+
Password: "test",
22+
}
23+
24+
func TestBox_Info(t *testing.T) {
25+
ctx := context.TODO()
26+
27+
conn, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
28+
require.NoError(t, err)
29+
30+
info, err := box.By(conn).Info()
31+
require.NoError(t, err)
32+
33+
// check all fields run correctly
34+
_, err = uuid.Parse(info.UUID)
35+
require.NoErrorf(t, err, "validate instance uuid is valid")
36+
37+
require.NotEmpty(t, info.Version)
38+
// check that pid parsed correctly
39+
require.NotEqual(t, info.PID, 0)
40+
41+
}
42+
43+
func runTestMain(m *testing.M) int {
44+
instance, err := test_helpers.StartTarantool(test_helpers.StartOpts{
45+
Dialer: dialer,
46+
InitScript: "testdata/config.lua",
47+
Listen: server,
48+
WaitStart: 100 * time.Millisecond,
49+
ConnectRetry: 10,
50+
RetryTimeout: 500 * time.Millisecond,
51+
})
52+
defer test_helpers.StopTarantoolWithCleanup(instance)
53+
54+
if err != nil {
55+
log.Printf("Failed to prepare test Tarantool: %s", err)
56+
return 1
57+
}
58+
59+
return m.Run()
60+
}
61+
62+
func TestMain(m *testing.M) {
63+
code := runTestMain(m)
64+
os.Exit(code)
65+
}

box/testdata/config.lua

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- Do not set listen for now so connector won't be
2+
-- able to send requests until everything is configured.
3+
box.cfg{
4+
work_dir = os.getenv("TEST_TNT_WORK_DIR"),
5+
}
6+
7+
box.schema.user.create('test', { password = 'test' , if_not_exists = true })
8+
box.schema.user.grant('test', 'execute', 'universe', nil, { if_not_exists = true })
9+
10+
-- Set listen only when every other thing is configured.
11+
box.cfg{
12+
listen = os.getenv("TEST_TNT_LISTEN"),
13+
}

0 commit comments

Comments
 (0)