Skip to content

Commit 434e1a1

Browse files
committed
test: try fix test
1 parent 52e6388 commit 434e1a1

File tree

6 files changed

+140
-91
lines changed

6 files changed

+140
-91
lines changed

.github/workflows/reusable_testing.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111

1212
jobs:
1313
run_tests:
14-
runs-on: ubuntu-20.04
14+
runs-on: ubuntu-22.04
1515
steps:
1616
- name: Clone the go-tarantool connector
1717
uses: actions/checkout@v4

.github/workflows/testing.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323

2424
# We could replace it with ubuntu-latest after fixing the bug:
2525
# https://github.com/tarantool/setup-tarantool/issues/37
26-
runs-on: ubuntu-20.04
26+
runs-on: ubuntu-22.04
2727

2828
strategy:
2929
fail-fast: false
@@ -100,9 +100,10 @@ jobs:
100100
run: make deps
101101

102102
- name: Run regression tests
103-
run: |
104-
make test
105-
make testrace
103+
run: make test
104+
105+
- name: Run race tests
106+
run: make testrace
106107

107108
- name: Run fuzzing tests
108109
if: ${{ matrix.fuzzing }}
@@ -116,6 +117,7 @@ jobs:
116117
make coveralls
117118
118119
- name: Check workability of benchmark tests
120+
if: matrix.golang == 'stable'
119121
run: make bench-deps bench DURATION=1x COUNT=1
120122

121123
testing_mac_os:
@@ -270,6 +272,10 @@ jobs:
270272
run: |
271273
cd "${SRCDIR}"
272274
make test
275+
276+
- name: Run race tests
277+
run: |
278+
cd "${SRCDIR}"
273279
make testrace
274280
275281
- name: Run fuzzing tests
@@ -279,6 +285,7 @@ jobs:
279285
make fuzzing TAGS="go_tarantool_decimal_fuzzing"
280286
281287
- name: Check workability of benchmark tests
288+
if: matrix.golang == 'stable'
282289
run: |
283290
cd "${SRCDIR}"
284291
make bench-deps bench DURATION=1x COUNT=1

shutdown_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func testGracefulShutdown(t *testing.T, conn *Connection, inst *test_helpers.Tar
108108
// Wait until server go down.
109109
// Server will go down only when it process all requests from our connection
110110
// (or on timeout).
111-
_, err = inst.Cmd.Process.Wait()
111+
err = inst.Wait()
112112
require.Nil(t, err)
113113
shutdownFinish := time.Now()
114114
shutdownTime := shutdownFinish.Sub(shutdownStart)
@@ -256,7 +256,7 @@ func TestNoGracefulShutdown(t *testing.T) {
256256
require.NotNilf(t, err, "sleep request error")
257257

258258
// Wait until server go down.
259-
_, err = inst.Cmd.Process.Wait()
259+
err = inst.Wait()
260260
require.Nil(t, err)
261261
shutdownFinish := time.Now()
262262
shutdownTime := shutdownFinish.Sub(shutdownStart)
@@ -327,7 +327,7 @@ func TestGracefulShutdownRespectsClose(t *testing.T) {
327327
require.NotNilf(t, err, "sleep request error")
328328

329329
// Wait until server go down.
330-
_, err = inst.Cmd.Process.Wait()
330+
err = inst.Wait()
331331
require.Nil(t, err)
332332
shutdownFinish := time.Now()
333333
shutdownTime := shutdownFinish.Sub(shutdownStart)
@@ -401,7 +401,7 @@ func TestGracefulShutdownNotRacesWithRequestReconnect(t *testing.T) {
401401

402402
// Wait until server go down.
403403
// Server is expected to go down on timeout.
404-
_, err = inst.Cmd.Process.Wait()
404+
err = inst.Wait()
405405
require.Nil(t, err)
406406

407407
// Help test helpers to properly clean up.
@@ -497,7 +497,7 @@ func TestGracefulShutdownCloseConcurrent(t *testing.T) {
497497
srvStop.Wait()
498498
require.Nil(t, sret, "No errors on server SIGTERM")
499499

500-
_, err = inst.Cmd.Process.Wait()
500+
err = inst.Wait()
501501
require.Nil(t, err)
502502

503503
// Help test helpers to properly clean up.
@@ -590,7 +590,7 @@ func TestGracefulShutdownConcurrent(t *testing.T) {
590590
caseWg.Wait()
591591
require.Nil(t, ret, "No errors on concurrent wait")
592592

593-
_, err = inst.Cmd.Process.Wait()
593+
err = inst.Wait()
594594
require.Nil(t, err)
595595

596596
// Help test helpers to properly clean up.

test_helpers/main.go

Lines changed: 119 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"path/filepath"
2222
"regexp"
2323
"strconv"
24+
"sync"
2425
"time"
2526

2627
"github.com/tarantool/go-tarantool/v2"
@@ -75,6 +76,17 @@ type StartOpts struct {
7576
Dialer tarantool.Dialer
7677
}
7778

79+
type statusInstance struct {
80+
result error
81+
isStopping bool
82+
isDone bool
83+
//! wg sync.WaitGroup
84+
// waitMutex is used to prevent several invokes of the "Wait"
85+
// for the same process.
86+
// https://github.com/golang/go/issues/28461
87+
waitMutex sync.Mutex
88+
}
89+
7890
// TarantoolInstance is a data for instance graceful shutdown and cleanup.
7991
type TarantoolInstance struct {
8092
// Cmd is a Tarantool command. Used to kill Tarantool process.
@@ -86,38 +98,57 @@ type TarantoolInstance struct {
8698
// Dialer to check that connection established.
8799
Dialer tarantool.Dialer
88100

89-
done chan error
90-
is_done bool
91-
result error
92-
is_stopping bool
101+
st *statusInstance
93102
}
94103

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-
}
104+
func newTarantoolInstance() TarantoolInstance {
105+
return TarantoolInstance{st: &statusInstance{}}
106+
}
102107

103-
select {
104-
case t.result = <-t.done:
105-
t.is_done = true
106-
return false, t.result
107-
default:
108-
return true, nil
108+
func (t *TarantoolInstance) checkDone() {
109+
if t.st == nil {
110+
panic("TarantoolInstance is not initialized")
111+
}
112+
// t.st.wg.Add(1)
113+
go func() {
114+
// defer t.st.wg.Done()
115+
t.st.waitMutex.Lock()
116+
defer t.st.waitMutex.Unlock()
117+
t.st.result = t.Cmd.Wait()
118+
t.st.isDone = true
119+
if !t.st.isStopping {
120+
log.Printf("Tarantool %q was unexpected terminated: %v", t.Opts.Listen, t.st.result)
121+
}
122+
}()
123+
}
124+
125+
func (t *TarantoolInstance) Wait() error {
126+
if t.st == nil {
127+
panic("TarantoolInstance is not initialized")
109128
}
129+
//! t.st.wg.Wait()
130+
t.st.waitMutex.Lock()
131+
defer t.st.waitMutex.Unlock()
132+
return t.st.result
110133
}
111134

112-
func (t *TarantoolInstance) checkDone() {
113-
t.is_done = false
114-
t.is_stopping = false
115-
t.done = make(chan error, 1)
116-
t.done <- t.Cmd.Wait()
117-
if !t.is_stopping {
118-
_, err := t.Status()
119-
log.Printf("Tarantool was unexpected terminated: %s", err)
135+
func (t *TarantoolInstance) Stop() error {
136+
log.Printf("Stopping Tarantool instance %q", t.Opts.Listen)
137+
t.st.isStopping = true
138+
if t.st.isDone {
139+
log.Printf("Already stopped instance %q with result: %v", t.Opts.Listen, t.st.result)
140+
return nil
141+
}
142+
if t.Cmd != nil && t.Cmd.Process != nil {
143+
log.Printf("Killing Tarantool %q (pid %d)", t.Opts.Listen, t.Cmd.Process.Pid)
144+
if err := t.Cmd.Process.Kill(); err != nil && !t.st.isDone {
145+
return fmt.Errorf("failed to kill tarantool %q (pid %d), got %s",
146+
t.Opts.Listen, t.Cmd.Process.Pid, err)
147+
}
148+
t.Wait()
149+
t.Cmd.Process = nil
120150
}
151+
return nil
121152
}
122153

123154
func isReady(dialer tarantool.Dialer, opts *tarantool.Opts) error {
@@ -232,49 +263,81 @@ func IsTarantoolEE() (bool, error) {
232263
func RestartTarantool(inst *TarantoolInstance) error {
233264
startedInst, err := StartTarantool(inst.Opts)
234265
inst.Cmd.Process = startedInst.Cmd.Process
266+
inst.st = startedInst.st
235267
return err
236268
}
237269

270+
func removeByMask(dir string, masks ...string) error {
271+
for _, mask := range masks {
272+
files, err := filepath.Glob(filepath.Join(dir, mask))
273+
if err != nil {
274+
return err
275+
}
276+
for _, f := range files {
277+
if err = os.Remove(f); err != nil {
278+
return err
279+
}
280+
}
281+
}
282+
return nil
283+
}
284+
285+
func prepareDir(workDir string) (string, error) {
286+
if workDir == "" {
287+
dir, err := os.MkdirTemp("", "work_dir")
288+
if err != nil {
289+
return "", err
290+
}
291+
return dir, nil
292+
}
293+
// Create work_dir.
294+
err := os.MkdirAll(workDir, 0755)
295+
if err != nil {
296+
return "", err
297+
}
298+
299+
// Clean up existing work_dir.
300+
// TODO: Ensure that nested files will be removed.
301+
err = removeByMask(workDir, "*.snap", "*.xlog")
302+
if err != nil {
303+
return "", err
304+
}
305+
return workDir, nil
306+
}
307+
238308
// StartTarantool starts a tarantool instance for tests
239309
// with specifies parameters (refer to StartOpts).
240310
// Process must be stopped with StopTarantool.
241311
func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
242312
// Prepare tarantool command.
243-
var inst TarantoolInstance
244-
var dir string
313+
inst := newTarantoolInstance()
245314
var err error
246315

247316
inst.Dialer = startOpts.Dialer
248-
249-
if startOpts.WorkDir == "" {
250-
dir, err = os.MkdirTemp("", "work_dir")
251-
if err != nil {
252-
return inst, err
253-
}
254-
startOpts.WorkDir = dir
255-
} else {
256-
// Clean up existing work_dir.
257-
err = os.RemoveAll(startOpts.WorkDir)
258-
if err != nil {
259-
return inst, err
260-
}
261-
262-
// Create work_dir.
263-
err = os.Mkdir(startOpts.WorkDir, 0755)
264-
if err != nil {
265-
return inst, err
266-
}
317+
startOpts.WorkDir, err = prepareDir(startOpts.WorkDir)
318+
if err != nil {
319+
return inst, fmt.Errorf("failed prepare working dir %q: %w", startOpts.WorkDir, err)
267320
}
268-
args := []string{}
269321

322+
args := []string{}
270323
if startOpts.InitScript != "" {
324+
if !filepath.IsAbs(startOpts.InitScript) {
325+
cwd, err := os.Getwd()
326+
if err != nil {
327+
return inst, fmt.Errorf("failed to get current working directory: %w", err)
328+
}
329+
startOpts.InitScript = filepath.Join(cwd, startOpts.InitScript)
330+
}
271331
args = append(args, startOpts.InitScript)
272332
}
273333
if startOpts.ConfigFile != "" && startOpts.InstanceName != "" {
274334
args = append(args, "--config", startOpts.ConfigFile)
275335
args = append(args, "--name", startOpts.InstanceName)
276336
}
277337
inst.Cmd = exec.Command(getTarantoolExec(), args...)
338+
inst.Cmd.Dir = startOpts.WorkDir
339+
inst.Cmd.Stdout = os.Stderr //! DEBUG: remove
340+
inst.Cmd.Stderr = os.Stderr //! DEBUG: remove
278341

279342
inst.Cmd.Env = append(
280343
os.Environ(),
@@ -306,7 +369,7 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
306369
// see https://github.com/tarantool/go-tarantool/issues/136
307370
time.Sleep(startOpts.WaitStart)
308371

309-
go inst.checkDone()
372+
inst.checkDone()
310373

311374
opts := tarantool.Opts{
312375
Timeout: 500 * time.Millisecond,
@@ -327,15 +390,16 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
327390
}
328391
}
329392

330-
working, err_st := inst.Status()
331-
if !working || err_st != nil {
393+
if inst.st.isDone && inst.st.result != nil {
332394
StopTarantool(inst)
333-
return TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool: %w", err_st)
395+
return TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool %q: %w",
396+
inst.Opts.Listen, inst.st.result)
334397
}
335398

336399
if err != nil {
337400
StopTarantool(inst)
338-
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool: %w", err)
401+
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool %q: %w",
402+
inst.Opts.Listen, err)
339403
}
340404

341405
return inst, nil
@@ -345,25 +409,9 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
345409
// with StartTarantool. Waits until any resources
346410
// associated with the process is released. If something went wrong, fails.
347411
func StopTarantool(inst TarantoolInstance) {
348-
log.Printf("Stopping Tarantool instance")
349-
inst.is_stopping = true
350-
if inst.Cmd != nil && inst.Cmd.Process != nil {
351-
if err := inst.Cmd.Process.Kill(); err != nil {
352-
is_running, _ := inst.Status()
353-
if is_running {
354-
log.Fatalf("Failed to kill tarantool (pid %d), got %s", inst.Cmd.Process.Pid, err)
355-
}
356-
}
357-
358-
// Wait releases any resources associated with the Process.
359-
if _, err := inst.Cmd.Process.Wait(); err != nil {
360-
is_running, _ := inst.Status()
361-
if is_running {
362-
log.Fatalf("Failed to wait for Tarantool process to exit, got %s", err)
363-
}
364-
}
365-
366-
inst.Cmd.Process = nil
412+
err := inst.Stop()
413+
if err != nil {
414+
log.Fatal(err)
367415
}
368416
}
369417

test_helpers/tcs/prepare.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ func writeConfig(name string, port int) error {
3939

4040
func makeOpts(port int) (test_helpers.StartOpts, error) {
4141
opts := test_helpers.StartOpts{}
42-
dir, err := os.MkdirTemp("", "tcs_dir")
42+
var err error
43+
opts.WorkDir, err = os.MkdirTemp("", "tcs_dir")
4344
if err != nil {
4445
return opts, err
4546
}
46-
opts.ConfigFile = filepath.Join(dir, "config.yaml")
47+
opts.ConfigFile = filepath.Join(opts.WorkDir, "config.yaml")
4748
err = writeConfig(opts.ConfigFile, port)
4849
if err != nil {
4950
return opts, fmt.Errorf("can't save file %q: %w", opts.ConfigFile, err)

0 commit comments

Comments
 (0)