Skip to content

Commit 9258c33

Browse files
committed
tests: add helpers for TcS
Simple helpers to make easy create tests required Taranatool centralized configuration storage.
1 parent 5368646 commit 9258c33

File tree

4 files changed

+161
-4
lines changed

4 files changed

+161
-4
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.20
44

55
require (
66
github.com/google/uuid v1.3.0
7+
github.com/mitchellh/mapstructure v1.5.0
78
github.com/shopspring/decimal v1.3.1
89
github.com/stretchr/testify v1.9.0
910
github.com/tarantool/go-iproto v1.1.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
33
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
44
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
55
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
6+
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
7+
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
68
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
79
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
810
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=

test_helpers/main.go

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ type StartOpts struct {
3333
// InitScript is a Lua script for tarantool to run on start.
3434
InitScript string
3535

36+
// ConfigFile is a path to a configuration file for a Tarantool instance.
37+
// Required in pair with InstanceName.
38+
ConfigFile string
39+
40+
// InstanceName is a name of an instance to run.
41+
// Required in pair with ConfigFile.
42+
InstanceName string
43+
3644
// Listen is box.cfg listen parameter for tarantool.
3745
// Use this address to connect to tarantool after configuration.
3846
// https://www.tarantool.io/en/doc/latest/reference/configuration/#cfg-basic-listen
@@ -108,7 +116,7 @@ var (
108116
)
109117

110118
func init() {
111-
tarantoolVersionRegexp = regexp.MustCompile(`Tarantool (?:Enterprise )?(\d+)\.(\d+)\.(\d+).*`)
119+
tarantoolVersionRegexp = regexp.MustCompile(`Tarantool (Enterprise )?(\d+)\.(\d+)\.(\d+).*`)
112120
}
113121

114122
// atoiUint64 parses string to uint64.
@@ -145,15 +153,58 @@ func IsTarantoolVersionLess(majorMin uint64, minorMin uint64, patchMin uint64) (
145153
return true, fmt.Errorf("failed to parse output %q", out)
146154
}
147155

148-
if major, err = atoiUint64(parsed[1]); err != nil {
156+
if major, err = atoiUint64(parsed[2]); err != nil {
149157
return true, fmt.Errorf("failed to parse major from output %q: %w", out, err)
150158
}
151159

152-
if minor, err = atoiUint64(parsed[2]); err != nil {
160+
if minor, err = atoiUint64(parsed[3]); err != nil {
153161
return true, fmt.Errorf("failed to parse minor from output %q: %w", out, err)
154162
}
155163

156-
if patch, err = atoiUint64(parsed[3]); err != nil {
164+
if patch, err = atoiUint64(parsed[4]); err != nil {
165+
return true, fmt.Errorf("failed to parse patch from output %q: %w", out, err)
166+
}
167+
168+
if major != majorMin {
169+
return major < majorMin, nil
170+
} else if minor != minorMin {
171+
return minor < minorMin, nil
172+
} else {
173+
return patch < patchMin, nil
174+
}
175+
}
176+
177+
// IsTarantoolEEVersionLess checks if tarantool is Enterprise and version is less
178+
// than passed <major.minor.patch>. Returns error if failed
179+
// to extract version.
180+
func IsTarantoolEEVersionLess(majorMin uint64, minorMin uint64, patchMin uint64) (bool, error) {
181+
var major, minor, patch uint64
182+
183+
out, err := exec.Command(getTarantoolExec(), "--version").Output()
184+
185+
if err != nil {
186+
return true, err
187+
}
188+
189+
parsed := tarantoolVersionRegexp.FindStringSubmatch(string(out))
190+
191+
if parsed == nil {
192+
return true, fmt.Errorf("failed to parse output %q", out)
193+
}
194+
195+
if parsed[1] == "" {
196+
return true, nil
197+
}
198+
199+
if major, err = atoiUint64(parsed[2]); err != nil {
200+
return true, fmt.Errorf("failed to parse major from output %q: %w", out, err)
201+
}
202+
203+
if minor, err = atoiUint64(parsed[3]); err != nil {
204+
return true, fmt.Errorf("failed to parse minor from output %q: %w", out, err)
205+
}
206+
207+
if patch, err = atoiUint64(parsed[4]); err != nil {
157208
return true, fmt.Errorf("failed to parse patch from output %q: %w", out, err)
158209
}
159210

@@ -219,6 +270,11 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
219270
fmt.Sprintf("TEST_TNT_MEMTX_USE_MVCC_ENGINE=%t", startOpts.MemtxUseMvccEngine),
220271
fmt.Sprintf("TEST_TNT_AUTH_TYPE=%s", startOpts.Auth),
221272
)
273+
if startOpts.ConfigFile != "" && startOpts.InstanceName != "" {
274+
inst.Cmd.Env = append(inst.Cmd.Env, fmt.Sprintf("TT_CONFIG=%s", startOpts.ConfigFile))
275+
inst.Cmd.Env = append(inst.Cmd.Env,
276+
fmt.Sprintf("TT_INSTANCE_NAME=%s", startOpts.InstanceName))
277+
}
222278

223279
// Copy SSL certificates.
224280
if startOpts.SslCertsDir != "" {

test_helpers/tcs/tcs.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package tcs
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
8+
"github.com/mitchellh/mapstructure"
9+
"github.com/tarantool/go-tarantool/v2"
10+
"github.com/tarantool/go-tarantool/v2/test_helpers"
11+
)
12+
13+
type Tcs struct {
14+
// conn Connection interface for interacting with Tarantool.
15+
doer tarantool.Doer
16+
}
17+
18+
// GetResponse is a response of a get request.
19+
type GetResponse struct {
20+
Data []struct {
21+
Path string
22+
Value string
23+
ModRevision int64 `mapstructure:"mod_revision"`
24+
}
25+
}
26+
27+
// StartTcs starts a Tarantool centralized configuration storage.
28+
// Returns a Tcs instance and a cleanup function.
29+
func StartTcs(opts test_helpers.StartOpts) (Tcs, func()) {
30+
if less, err := test_helpers.IsTarantoolEEVersionLess(3, 3, 0); less || err != nil {
31+
log.Fatal("Tarantool EE 3.3+ required", err)
32+
}
33+
need_clean := opts.WorkDir == ""
34+
35+
inst, err := test_helpers.StartTarantool(opts)
36+
if err != nil {
37+
log.Fatalf("Failed to start Tarantool config instance: %v", err)
38+
}
39+
conn, err := tarantool.Connect(context.Background(), inst.Dialer, tarantool.Opts{})
40+
if err != nil {
41+
log.Fatal("Can't connect to Tarantool config instance")
42+
return Tcs{}, nil
43+
}
44+
45+
return Tcs{conn}, func() {
46+
conn.Close()
47+
if need_clean {
48+
test_helpers.StopTarantoolWithCleanup(inst)
49+
} else {
50+
test_helpers.StopTarantool(inst)
51+
}
52+
}
53+
54+
}
55+
56+
// Put implements "config.storage.put" method.
57+
func (t *Tcs) Put(ctx context.Context, path string, value string) error {
58+
req := tarantool.NewCallRequest("config.storage.put").
59+
Args([]any{path, value}).
60+
Context(ctx)
61+
if _, err := t.doer.Do(req).GetResponse(); err != nil {
62+
return fmt.Errorf("failed save data to tarantool: %w", err)
63+
}
64+
return nil
65+
}
66+
67+
// delete implements "config.storage.delete" method.
68+
func (t *Tcs) Delete(ctx context.Context, path string) error {
69+
req := tarantool.NewCallRequest("config.storage.delete").
70+
Args([]any{path}).
71+
Context(ctx)
72+
if _, err := t.doer.Do(req).GetResponse(); err != nil {
73+
return fmt.Errorf("failed delete data from tarantool: %w", err)
74+
}
75+
return nil
76+
}
77+
78+
// get implements "config.storage.get" method.
79+
func (t *Tcs) Get(ctx context.Context, path string) (GetResponse, error) {
80+
req := tarantool.NewCallRequest("config.storage.get").
81+
Args([]any{path}).
82+
Context(ctx)
83+
84+
resp := GetResponse{}
85+
result, err := t.doer.Do(req).Get()
86+
if err != nil {
87+
return resp, fmt.Errorf("failed to fetch data from tarantool: %w", err)
88+
}
89+
90+
if len(result) != 1 {
91+
return resp, fmt.Errorf("unexpected response from tarantool: %q", result)
92+
}
93+
if err := mapstructure.Decode(result[0], &resp); err != nil {
94+
return resp, fmt.Errorf("failed to map response from tarantool: %q", result[0])
95+
}
96+
97+
return resp, nil
98+
}

0 commit comments

Comments
 (0)