Skip to content

Commit 6fe49f2

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

File tree

6 files changed

+143
-91
lines changed

6 files changed

+143
-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: 122 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,60 @@ 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+
if t.st.isDone {
118+
return
119+
}
120+
t.st.result = t.Cmd.Wait()
121+
t.st.isDone = true
122+
if !t.st.isStopping {
123+
log.Printf("Tarantool %q was unexpected terminated: %v", t.Opts.Listen, t.st.result)
124+
}
125+
}()
126+
}
127+
128+
func (t *TarantoolInstance) Wait() error {
129+
if t.st == nil {
130+
panic("TarantoolInstance is not initialized")
109131
}
132+
//! t.st.wg.Wait()
133+
t.st.waitMutex.Lock()
134+
defer t.st.waitMutex.Unlock()
135+
return t.st.result
110136
}
111137

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)
138+
func (t *TarantoolInstance) Stop() error {
139+
log.Printf("Stopping Tarantool instance %q", t.Opts.Listen)
140+
t.st.isStopping = true
141+
if t.st.isDone {
142+
log.Printf("Already stopped instance %q with result: %v", t.Opts.Listen, t.st.result)
143+
return nil
144+
}
145+
if t.Cmd != nil && t.Cmd.Process != nil {
146+
log.Printf("Killing Tarantool %q (pid %d)", t.Opts.Listen, t.Cmd.Process.Pid)
147+
if err := t.Cmd.Process.Kill(); err != nil && !t.st.isDone {
148+
return fmt.Errorf("failed to kill tarantool %q (pid %d), got %s",
149+
t.Opts.Listen, t.Cmd.Process.Pid, err)
150+
}
151+
t.Wait()
152+
t.Cmd.Process = nil
120153
}
154+
return nil
121155
}
122156

123157
func isReady(dialer tarantool.Dialer, opts *tarantool.Opts) error {
@@ -232,49 +266,81 @@ func IsTarantoolEE() (bool, error) {
232266
func RestartTarantool(inst *TarantoolInstance) error {
233267
startedInst, err := StartTarantool(inst.Opts)
234268
inst.Cmd.Process = startedInst.Cmd.Process
269+
inst.st = startedInst.st
235270
return err
236271
}
237272

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

247319
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-
}
320+
startOpts.WorkDir, err = prepareDir(startOpts.WorkDir)
321+
if err != nil {
322+
return inst, fmt.Errorf("failed prepare working dir %q: %w", startOpts.WorkDir, err)
267323
}
268-
args := []string{}
269324

325+
args := []string{}
270326
if startOpts.InitScript != "" {
327+
if !filepath.IsAbs(startOpts.InitScript) {
328+
cwd, err := os.Getwd()
329+
if err != nil {
330+
return inst, fmt.Errorf("failed to get current working directory: %w", err)
331+
}
332+
startOpts.InitScript = filepath.Join(cwd, startOpts.InitScript)
333+
}
271334
args = append(args, startOpts.InitScript)
272335
}
273336
if startOpts.ConfigFile != "" && startOpts.InstanceName != "" {
274337
args = append(args, "--config", startOpts.ConfigFile)
275338
args = append(args, "--name", startOpts.InstanceName)
276339
}
277340
inst.Cmd = exec.Command(getTarantoolExec(), args...)
341+
inst.Cmd.Dir = startOpts.WorkDir
342+
inst.Cmd.Stdout = os.Stderr //! DEBUG: remove
343+
inst.Cmd.Stderr = os.Stderr //! DEBUG: remove
278344

279345
inst.Cmd.Env = append(
280346
os.Environ(),
@@ -306,7 +372,7 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
306372
// see https://github.com/tarantool/go-tarantool/issues/136
307373
time.Sleep(startOpts.WaitStart)
308374

309-
go inst.checkDone()
375+
inst.checkDone()
310376

311377
opts := tarantool.Opts{
312378
Timeout: 500 * time.Millisecond,
@@ -327,15 +393,16 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
327393
}
328394
}
329395

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

336402
if err != nil {
337403
StopTarantool(inst)
338-
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool: %w", err)
404+
return TarantoolInstance{}, fmt.Errorf("failed to connect Tarantool %q: %w",
405+
inst.Opts.Listen, err)
339406
}
340407

341408
return inst, nil
@@ -345,25 +412,9 @@ func StartTarantool(startOpts StartOpts) (TarantoolInstance, error) {
345412
// with StartTarantool. Waits until any resources
346413
// associated with the process is released. If something went wrong, fails.
347414
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
415+
err := inst.Stop()
416+
if err != nil {
417+
log.Fatal(err)
367418
}
368419
}
369420

0 commit comments

Comments
 (0)