From 6aa8c3bd486d557dff15e2667441a579d3c967a6 Mon Sep 17 00:00:00 2001 From: Bagas Date: Wed, 15 Jul 2026 12:23:33 +0700 Subject: [PATCH] fix: race condition test --- .../session/interaction/interaction_test.go | 4 -- internal/session/lifecycle/lifecycle_test.go | 47 +++++++++++++++++++ internal/transport/http_test.go | 3 +- internal/transport/https_test.go | 3 +- internal/transport/tcp_test.go | 3 +- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/internal/session/interaction/interaction_test.go b/internal/session/interaction/interaction_test.go index 679ec8a..8b6f15b 100644 --- a/internal/session/interaction/interaction_test.go +++ b/internal/session/interaction/interaction_test.go @@ -1922,10 +1922,6 @@ func TestInteraction_Start_ProtocolSelection(t *testing.T) { time.Sleep(50 * time.Millisecond) i := mockInteraction.(*interaction) - if i.program != nil { - assert.NotNil(t, i.program, "program should be initialized") - } - i.Stop() mockConfig.AssertExpectations(t) diff --git a/internal/session/lifecycle/lifecycle_test.go b/internal/session/lifecycle/lifecycle_test.go index 3f07d69..e16fd48 100644 --- a/internal/session/lifecycle/lifecycle_test.go +++ b/internal/session/lifecycle/lifecycle_test.go @@ -5,6 +5,7 @@ import ( "errors" "io" "net" + "sync" "testing" "tunnel_pls/internal/types" @@ -308,3 +309,49 @@ func TestLifecycle_Close(t *testing.T) { }) } } + +func TestLifecycle_ConcurrentClose(t *testing.T) { + mockSSHConn := &MockSSHConn{} + mockSSHConn.On("Close").Return(nil) + + mockForwarder := &MockForwarder{} + mockForwarder.On("TunnelType").Return(types.TunnelTypeHTTP) + + mockSlug := &MockSlug{} + mockSlug.On("String").Return("test-slug") + + mockPort := &MockPort{} + + mockSessionRegistry := &MockSessionRegistry{} + mockSessionRegistry.On("Remove", mock.Anything).Return() + + mockSSHChannel := &MockSSHChannel{} + mockSSHChannel.On("Close").Return(nil) + + mockLifecycle := New(mockSSHConn, mockForwarder, mockSlug, mockPort, mockSessionRegistry, "mas-fuad") + mockLifecycle.SetStatus(types.SessionStatusRUNNING) + err := mockLifecycle.SetChannel(mockSSHChannel) + assert.NoError(t, err) + + const numGoroutines = 10 + var wg sync.WaitGroup + errChan := make(chan error, numGoroutines) + + for i := 0; i < numGoroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + err := mockLifecycle.Close() + errChan <- err + }() + } + + wg.Wait() + close(errChan) + + for err := range errChan { + assert.NoError(t, err) + } + + assert.False(t, mockLifecycle.IsActive()) +} diff --git a/internal/transport/http_test.go b/internal/transport/http_test.go index cd3cf68..847931c 100644 --- a/internal/transport/http_test.go +++ b/internal/transport/http_test.go @@ -55,8 +55,7 @@ func TestHTTPServer_Serve(t *testing.T) { go func() { time.Sleep(100 * time.Millisecond) - err = listener.Close() - assert.NoError(t, err) + _ = listener.Close() }() err = srv.Serve(listener) diff --git a/internal/transport/https_test.go b/internal/transport/https_test.go index 6081d97..42bbe72 100644 --- a/internal/transport/https_test.go +++ b/internal/transport/https_test.go @@ -63,8 +63,7 @@ func TestHTTPSServer_Serve(t *testing.T) { go func() { time.Sleep(100 * time.Millisecond) - err = listener.Close() - assert.NoError(t, err) + _ = listener.Close() }() err = srv.Serve(listener) diff --git a/internal/transport/tcp_test.go b/internal/transport/tcp_test.go index c4c4963..761b902 100644 --- a/internal/transport/tcp_test.go +++ b/internal/transport/tcp_test.go @@ -45,8 +45,7 @@ func TestTCPServer_Serve(t *testing.T) { go func() { time.Sleep(100 * time.Millisecond) - err = listener.Close() - assert.NoError(t, err) + _ = listener.Close() }() err = srv.Serve(listener)