Skip to content

Commit 52bb9f7

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

File tree

4 files changed

+353
-7
lines changed

4 files changed

+353
-7
lines changed

test_helpers/main.go

Lines changed: 80 additions & 7 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
@@ -77,6 +85,32 @@ type TarantoolInstance struct {
7785

7886
// Dialer to check that connection established.
7987
Dialer tarantool.Dialer
88+
89+
done chan error
90+
is_done bool
91+
result error
92+
}
93+
94+
// Status checks if Tarantool instance is still running.
95+
// Return true if it is running, false if it is not.
96+
// If instance was exit and error is nil - process completed success with zero status code.
97+
func (t *TarantoolInstance) Status() (bool, error) {
98+
if t.is_done {
99+
return false, t.result
100+
}
101+
102+
select {
103+
case t.result = <-t.done:
104+
t.is_done = true
105+
return false, t.result
106+
default:
107+
return true, nil
108+
}
109+
}
110+
111+
func (t *TarantoolInstance) checkDone() {
112+
t.done = make(chan error, 1)
113+
t.done <- t.Cmd.Wait()
80114
}
81115

82116
func isReady(dialer tarantool.Dialer, opts *tarantool.Opts) error {
@@ -108,7 +142,7 @@ var (
108142
)
109143

110144
func init() {
111-
tarantoolVersionRegexp = regexp.MustCompile(`Tarantool (?:Enterprise )?(\d+)\.(\d+)\.(\d+).*`)
145+
tarantoolVersionRegexp = regexp.MustCompile(`Tarantool (Enterprise )?(\d+)\.(\d+)\.(\d+).*`)
112146
}
113147

114148
// atoiUint64 parses string to uint64.
@@ -145,15 +179,15 @@ func IsTarantoolVersionLess(majorMin uint64, minorMin uint64, patchMin uint64) (
145179
return true, fmt.Errorf("failed to parse output %q", out)
146180
}
147181

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

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

156-
if patch, err = atoiUint64(parsed[3]); err != nil {
190+
if patch, err = atoiUint64(parsed[4]); err != nil {
157191
return true, fmt.Errorf("failed to parse patch from output %q: %w", out, err)
158192
}
159193

@@ -166,6 +200,21 @@ func IsTarantoolVersionLess(majorMin uint64, minorMin uint64, patchMin uint64) (
166200
}
167201
}
168202

203+
// IsTarantoolEE checks if Tarantool is Enterprise edition.
204+
func IsTarantoolEE() (bool, error) {
205+
out, err := exec.Command(getTarantoolExec(), "--version").Output()
206+
if err != nil {
207+
return true, err
208+
}
209+
210+
parsed := tarantoolVersionRegexp.FindStringSubmatch(string(out))
211+
if parsed == nil {
212+
return true, fmt.Errorf("failed to parse output %q", out)
213+
}
214+
215+
return parsed[1] != "", nil
216+
}
217+
169218
// RestartTarantool restarts a tarantool instance for tests
170219
// with specifies parameters (refer to StartOpts)
171220
// which were specified in inst parameter.
@@ -211,6 +260,7 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
211260
}
212261

213262
inst.Cmd = exec.Command(getTarantoolExec(), startOpts.InitScript)
263+
inst.Cmd.Dir = startOpts.WorkDir
214264

215265
inst.Cmd.Env = append(
216266
os.Environ(),
@@ -219,6 +269,11 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
219269
fmt.Sprintf("TEST_TNT_MEMTX_USE_MVCC_ENGINE=%t", startOpts.MemtxUseMvccEngine),
220270
fmt.Sprintf("TEST_TNT_AUTH_TYPE=%s", startOpts.Auth),
221271
)
272+
if startOpts.ConfigFile != "" && startOpts.InstanceName != "" {
273+
inst.Cmd.Env = append(inst.Cmd.Env, fmt.Sprintf("TT_CONFIG=%s", startOpts.ConfigFile))
274+
inst.Cmd.Env = append(inst.Cmd.Env,
275+
fmt.Sprintf("TT_INSTANCE_NAME=%s", startOpts.InstanceName))
276+
}
222277

223278
// Copy SSL certificates.
224279
if startOpts.SslCertsDir != "" {
@@ -242,6 +297,8 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
242297
// see https://github.com/tarantool/go-tarantool/issues/136
243298
time.Sleep(startOpts.WaitStart)
244299

300+
go inst.checkDone()
301+
245302
opts := tarantool.Opts{
246303
Timeout: 500 * time.Millisecond,
247304
SkipSchema: true,
@@ -261,7 +318,17 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
261318
}
262319
}
263320

264-
return inst, err
321+
if err != nil {
322+
StopTarantool(inst)
323+
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool: %w", err)
324+
}
325+
326+
working, err := inst.Status()
327+
if !working || err != nil {
328+
StopTarantool(inst)
329+
return TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool: %w", err)
330+
}
331+
return inst, nil
265332
}
266333

267334
// StopTarantool stops a tarantool instance started
@@ -270,12 +337,18 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
270337
func StopTarantool(inst TarantoolInstance) {
271338
if inst.Cmd != nil && inst.Cmd.Process != nil {
272339
if err := inst.Cmd.Process.Kill(); err != nil {
273-
log.Fatalf("Failed to kill tarantool (pid %d), got %s", inst.Cmd.Process.Pid, err)
340+
is_running, _ := inst.Status()
341+
if is_running {
342+
log.Fatalf("Failed to kill tarantool (pid %d), got %s", inst.Cmd.Process.Pid, err)
343+
}
274344
}
275345

276346
// Wait releases any resources associated with the Process.
277347
if _, err := inst.Cmd.Process.Wait(); err != nil {
278-
log.Fatalf("Failed to wait for Tarantool process to exit, got %s", err)
348+
is_running, _ := inst.Status()
349+
if is_running {
350+
log.Fatalf("Failed to wait for Tarantool process to exit, got %s", err)
351+
}
279352
}
280353

281354
inst.Cmd.Process = nil

test_helpers/tcs/prepare.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package tcs
2+
3+
import (
4+
_ "embed"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"time"
9+
10+
"github.com/tarantool/go-tarantool/v2"
11+
"github.com/tarantool/go-tarantool/v2/test_helpers"
12+
)
13+
14+
const (
15+
waitTimeout = 500 * time.Millisecond
16+
connectRetry = 3
17+
TcsUser = "client"
18+
TcsPassword = "secret"
19+
)
20+
21+
//go:embed testdata/config.yaml
22+
var tcsConfig []byte
23+
24+
func makeOpts(port int) (test_helpers.StartOpts, error) {
25+
opts := test_helpers.StartOpts{}
26+
dir, err := os.MkdirTemp("", "tcs_dir")
27+
if err != nil {
28+
return opts, err
29+
}
30+
os.WriteFile(filepath.Join(dir, "config.yaml"), tcsConfig, 0644)
31+
32+
address := fmt.Sprintf("localhost:%d", port)
33+
34+
opts = test_helpers.StartOpts{
35+
ConfigFile: "config.yaml",
36+
WorkDir: dir,
37+
WaitStart: waitTimeout,
38+
ConnectRetry: connectRetry,
39+
RetryTimeout: waitTimeout,
40+
InstanceName: "master",
41+
Listen: address,
42+
Dialer: tarantool.NetDialer{
43+
Address: address,
44+
User: TcsUser,
45+
Password: TcsPassword,
46+
},
47+
}
48+
return opts, nil
49+
}

0 commit comments

Comments
 (0)