Skip to content

Commit d0adcb6

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

File tree

6 files changed

+136
-91
lines changed

6 files changed

+136
-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: 115 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"path/filepath"
2222
"regexp"
2323
"strconv"
24+
"sync"
25+
"sync/atomic"
2426
"time"
2527

2628
"github.com/tarantool/go-tarantool/v2"
@@ -75,6 +77,13 @@ type StartOpts struct {
7577
Dialer tarantool.Dialer
7678
}
7779

80+
type statusInstance struct {
81+
result error
82+
is_stopping bool
83+
is_done atomic.Bool
84+
wg sync.WaitGroup
85+
}
86+
7887
// TarantoolInstance is a data for instance graceful shutdown and cleanup.
7988
type TarantoolInstance struct {
8089
// Cmd is a Tarantool command. Used to kill Tarantool process.
@@ -86,38 +95,56 @@ type TarantoolInstance struct {
8695
// Dialer to check that connection established.
8796
Dialer tarantool.Dialer
8897

89-
done chan error
90-
is_done bool
91-
result error
92-
is_stopping bool
98+
st *statusInstance
9399
}
94100

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-
}
101+
func newTarantoolInstance() TarantoolInstance {
102+
return TarantoolInstance{st: &statusInstance{}}
103+
}
102104

103-
select {
104-
case t.result = <-t.done:
105-
t.is_done = true
106-
return false, t.result
107-
default:
108-
return true, nil
105+
func (t *TarantoolInstance) checkDone() {
106+
if t.st == nil {
107+
panic("TarantoolInstance is not initialized")
108+
}
109+
t.st.wg.Add(1)
110+
go func() {
111+
defer t.st.wg.Done()
112+
t.st.result = t.Cmd.Wait()
113+
t.st.is_done.Store(true)
114+
if !t.st.is_stopping {
115+
log.Printf("Tarantool %q was unexpected terminated: %v", t.Opts.Listen, t.st.result)
116+
}
117+
}()
118+
}
119+
120+
func (t *TarantoolInstance) Wait() error {
121+
if t.st == nil {
122+
panic("TarantoolInstance is not initialized")
123+
}
124+
t.st.wg.Wait()
125+
if t.st.is_stopping {
126+
return nil
109127
}
128+
return t.st.result
110129
}
111130

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)
131+
func (t *TarantoolInstance) Stop() error {
132+
log.Printf("Stopping Tarantool instance %q", t.Opts.Listen)
133+
t.st.is_stopping = true
134+
if t.st.is_done.Load() {
135+
log.Printf("Already stopped instance %q with result %v", t.Opts.Listen, t.st.result)
136+
return nil
137+
}
138+
if t.Cmd != nil && t.Cmd.Process != nil {
139+
log.Printf("Killing Tarantool %q (pid %d)", t.Opts.Listen, t.Cmd.Process.Pid)
140+
if err := t.Cmd.Process.Kill(); err != nil && !t.st.is_done.Load() {
141+
return fmt.Errorf("failed to kill tarantool %q (pid %d), got %s",
142+
t.Opts.Listen, t.Cmd.Process.Pid, err)
143+
}
144+
t.Wait()
145+
t.Cmd.Process = nil
120146
}
147+
return nil
121148
}
122149

123150
func isReady(dialer tarantool.Dialer, opts *tarantool.Opts) error {
@@ -232,49 +259,81 @@ func IsTarantoolEE() (bool, error) {
232259
func RestartTarantool(inst *TarantoolInstance) error {
233260
startedInst, err := StartTarantool(inst.Opts)
234261
inst.Cmd.Process = startedInst.Cmd.Process
262+
inst.st = startedInst.st
235263
return err
236264
}
237265

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

247312
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-
}
313+
startOpts.WorkDir, err = prepareDir(startOpts.WorkDir)
314+
if err != nil {
315+
return inst, fmt.Errorf("failed prepare working dir %q: %w", startOpts.WorkDir, err)
267316
}
268-
args := []string{}
269317

318+
args := []string{}
270319
if startOpts.InitScript != "" {
320+
if !filepath.IsAbs(startOpts.InitScript) {
321+
cwd, err := os.Getwd()
322+
if err != nil {
323+
return inst, fmt.Errorf("failed to get current working directory: %w", err)
324+
}
325+
startOpts.InitScript = filepath.Join(cwd, startOpts.InitScript)
326+
}
271327
args = append(args, startOpts.InitScript)
272328
}
273329
if startOpts.ConfigFile != "" && startOpts.InstanceName != "" {
274330
args = append(args, "--config", startOpts.ConfigFile)
275331
args = append(args, "--name", startOpts.InstanceName)
276332
}
277333
inst.Cmd = exec.Command(getTarantoolExec(), args...)
334+
inst.Cmd.Dir = startOpts.WorkDir
335+
inst.Cmd.Stdout = os.Stderr //! DEBUG: remove
336+
inst.Cmd.Stderr = os.Stderr //! DEBUG: remove
278337

279338
inst.Cmd.Env = append(
280339
os.Environ(),
@@ -306,7 +365,7 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
306365
// see https://github.com/tarantool/go-tarantool/issues/136
307366
time.Sleep(startOpts.WaitStart)
308367

309-
go inst.checkDone()
368+
inst.checkDone()
310369

311370
opts := tarantool.Opts{
312371
Timeout: 500 * time.Millisecond,
@@ -327,15 +386,16 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
327386
}
328387
}
329388

330-
working, err_st := inst.Status()
331-
if !working || err_st != nil {
389+
if inst.st.is_done.Load() && inst.st.result != nil {
332390
StopTarantool(inst)
333-
return TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool: %w", err_st)
391+
return TarantoolInstance{}, fmt.Errorf("unexpected terminated Tarantool %q: %w",
392+
inst.Opts.Listen, inst.st.result)
334393
}
335394

336395
if err != nil {
337396
StopTarantool(inst)
338-
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool: %w", err)
397+
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool %q: %w",
398+
inst.Opts.Listen, err)
339399
}
340400

341401
return inst, nil
@@ -345,25 +405,9 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
345405
// with StartTarantool. Waits until any resources
346406
// associated with the process is released. If something went wrong, fails.
347407
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
408+
err := inst.Stop()
409+
if err != nil {
410+
log.Fatal(err)
367411
}
368412
}
369413

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)