Skip to content

Commit 89c6ebe

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

File tree

4 files changed

+362
-7
lines changed

4 files changed

+362
-7
lines changed

test_helpers/main.go

Lines changed: 88 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,38 @@ 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+
is_stopping bool
93+
}
94+
95+
// Status checks if Tarantool instance is still running.
96+
// Return true if it is running, false if it is not.
97+
// If instance was exit and error is nil - process completed success with zero status code.
98+
func (t *TarantoolInstance) Status() (bool, error) {
99+
if t.is_done {
100+
return false, t.result
101+
}
102+
103+
select {
104+
case t.result = <-t.done:
105+
t.is_done = true
106+
return false, t.result
107+
default:
108+
return true, nil
109+
}
110+
}
111+
112+
func (t *TarantoolInstance) checkDone() {
113+
t.is_stopping = false
114+
t.done = make(chan error, 1)
115+
t.done <- t.Cmd.Wait()
116+
if !t.is_stopping {
117+
_, err := t.Status()
118+
log.Printf("Tarantool was unexpected terminated: %s", err)
119+
}
80120
}
81121

82122
func isReady(dialer tarantool.Dialer, opts *tarantool.Opts) error {
@@ -108,7 +148,7 @@ var (
108148
)
109149

110150
func init() {
111-
tarantoolVersionRegexp = regexp.MustCompile(`Tarantool (?:Enterprise )?(\d+)\.(\d+)\.(\d+).*`)
151+
tarantoolVersionRegexp = regexp.MustCompile(`Tarantool (Enterprise )?(\d+)\.(\d+)\.(\d+).*`)
112152
}
113153

114154
// atoiUint64 parses string to uint64.
@@ -145,15 +185,15 @@ func IsTarantoolVersionLess(majorMin uint64, minorMin uint64, patchMin uint64) (
145185
return true, fmt.Errorf("failed to parse output %q", out)
146186
}
147187

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

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

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

@@ -166,6 +206,21 @@ func IsTarantoolVersionLess(majorMin uint64, minorMin uint64, patchMin uint64) (
166206
}
167207
}
168208

209+
// IsTarantoolEE checks if Tarantool is Enterprise edition.
210+
func IsTarantoolEE() (bool, error) {
211+
out, err := exec.Command(getTarantoolExec(), "--version").Output()
212+
if err != nil {
213+
return true, err
214+
}
215+
216+
parsed := tarantoolVersionRegexp.FindStringSubmatch(string(out))
217+
if parsed == nil {
218+
return true, fmt.Errorf("failed to parse output %q", out)
219+
}
220+
221+
return parsed[1] != "", nil
222+
}
223+
169224
// RestartTarantool restarts a tarantool instance for tests
170225
// with specifies parameters (refer to StartOpts)
171226
// which were specified in inst parameter.
@@ -211,6 +266,7 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
211266
}
212267

213268
inst.Cmd = exec.Command(getTarantoolExec(), startOpts.InitScript)
269+
inst.Cmd.Dir = startOpts.WorkDir
214270

215271
inst.Cmd.Env = append(
216272
os.Environ(),
@@ -219,6 +275,11 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
219275
fmt.Sprintf("TEST_TNT_MEMTX_USE_MVCC_ENGINE=%t", startOpts.MemtxUseMvccEngine),
220276
fmt.Sprintf("TEST_TNT_AUTH_TYPE=%s", startOpts.Auth),
221277
)
278+
if startOpts.ConfigFile != "" && startOpts.InstanceName != "" {
279+
inst.Cmd.Env = append(inst.Cmd.Env, fmt.Sprintf("TT_CONFIG=%s", startOpts.ConfigFile))
280+
inst.Cmd.Env = append(inst.Cmd.Env,
281+
fmt.Sprintf("TT_INSTANCE_NAME=%s", startOpts.InstanceName))
282+
}
222283

223284
// Copy SSL certificates.
224285
if startOpts.SslCertsDir != "" {
@@ -242,6 +303,8 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
242303
// see https://github.com/tarantool/go-tarantool/issues/136
243304
time.Sleep(startOpts.WaitStart)
244305

306+
go inst.checkDone()
307+
245308
opts := tarantool.Opts{
246309
Timeout: 500 * time.Millisecond,
247310
SkipSchema: true,
@@ -261,21 +324,39 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
261324
}
262325
}
263326

264-
return inst, err
327+
working, err_st := inst.Status()
328+
if !working || err_st != nil {
329+
StopTarantool(inst)
330+
return TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool: %w", err_st)
331+
}
332+
333+
if err != nil {
334+
StopTarantool(inst)
335+
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool: %w", err)
336+
}
337+
338+
return inst, nil
265339
}
266340

267341
// StopTarantool stops a tarantool instance started
268342
// with StartTarantool. Waits until any resources
269343
// associated with the process is released. If something went wrong, fails.
270344
func StopTarantool(inst TarantoolInstance) {
345+
inst.is_stopping = true
271346
if inst.Cmd != nil && inst.Cmd.Process != nil {
272347
if err := inst.Cmd.Process.Kill(); err != nil {
273-
log.Fatalf("Failed to kill tarantool (pid %d), got %s", inst.Cmd.Process.Pid, err)
348+
is_running, _ := inst.Status()
349+
if is_running {
350+
log.Fatalf("Failed to kill tarantool (pid %d), got %s", inst.Cmd.Process.Pid, err)
351+
}
274352
}
275353

276354
// Wait releases any resources associated with the Process.
277355
if _, err := inst.Cmd.Process.Wait(); err != nil {
278-
log.Fatalf("Failed to wait for Tarantool process to exit, got %s", err)
356+
is_running, _ := inst.Status()
357+
if is_running {
358+
log.Fatalf("Failed to wait for Tarantool process to exit, got %s", err)
359+
}
279360
}
280361

281362
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)