Skip to content

Commit b4e5e76

Browse files
committed
test: add unit tests for Service (75.6% coverage)
1 parent fa2fee4 commit b4e5e76

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed

internal/tunnel/service_test.go

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package tunnel
2+
3+
import (
4+
"context"
5+
"strings"
6+
"testing"
7+
)
8+
9+
// MockProvider implements Provider interface for testing purposes.
10+
type MockProvider struct {
11+
connectedCalled bool
12+
connectPort int
13+
closeCalled bool
14+
}
15+
16+
// implement Provider interface
17+
func (m *MockProvider) Connect(ctx context.Context, localPort int) (string, error) {
18+
m.connectedCalled = true
19+
m.connectPort = localPort
20+
return "https://abc123.example.com", nil
21+
}
22+
23+
func (m *MockProvider) Close() error {
24+
m.closeCalled = true
25+
return nil
26+
}
27+
28+
func (m *MockProvider) IsConnected() bool {
29+
return m.connectedCalled && !m.closeCalled
30+
}
31+
32+
func (m *MockProvider) PublicURL() string {
33+
return "https://abc123.example.com"
34+
}
35+
36+
func (m *MockProvider) Name() string {
37+
return "MockProvider"
38+
}
39+
40+
// NewService creates a service with the MockProvider for testing.
41+
func TestNewService(t *testing.T) {
42+
mockProvider := &MockProvider{}
43+
svc := NewService(mockProvider)
44+
45+
if svc == nil {
46+
t.Fatal("Service should not be nil")
47+
}
48+
}
49+
50+
func TestService_Start(t *testing.T) {
51+
mock := &MockProvider{}
52+
53+
svc := NewService(mock)
54+
ctx := context.Background()
55+
port := 3000
56+
err := svc.Start(ctx, port)
57+
if err != nil {
58+
t.Fatalf("Start() error = %v, want nil", err)
59+
}
60+
61+
// check mock.Connect was called
62+
if !mock.connectedCalled {
63+
t.Error("provider.Connect was not called")
64+
}
65+
66+
// check port is correct
67+
if mock.connectPort != port {
68+
t.Errorf("connectPort = %d, want %d", port, mock.connectPort)
69+
}
70+
71+
// Check Ready() channel is closed
72+
select {
73+
case <-svc.Ready():
74+
// Ok! channel is closed
75+
default:
76+
t.Error("ready channel should be closed after Start()")
77+
}
78+
79+
}
80+
81+
func TestService_PublicURL(t *testing.T) {
82+
mock := &MockProvider{}
83+
svc := NewService(mock)
84+
85+
url := svc.PublicURL()
86+
if url != mock.PublicURL() {
87+
t.Errorf("Expected %s, got %s", mock.PublicURL(), svc.PublicURL())
88+
}
89+
}
90+
91+
func TestService_Ready(t *testing.T) {
92+
mock := &MockProvider{}
93+
svc := NewService(mock)
94+
95+
// Test before Start (Read channel not closed)
96+
select {
97+
case <-svc.Ready():
98+
t.Error("ready before even `Start` is called!")
99+
default:
100+
// alright
101+
}
102+
103+
ctx := context.Background()
104+
105+
// Test after Start (Ready channel closed)
106+
err := svc.Start(ctx, 3000)
107+
if err != nil {
108+
t.Errorf("expected nil got %v", err)
109+
}
110+
111+
select {
112+
case <-svc.Ready():
113+
// closed as expected
114+
default:
115+
// error if channel is not closed to send ready signal
116+
t.Error("ready channel should have been closed")
117+
}
118+
}
119+
120+
func TestService_Close(t *testing.T) {
121+
mock := &MockProvider{}
122+
123+
svc := NewService(mock)
124+
125+
// before calling Close
126+
if mock.closeCalled {
127+
t.Error("provider should not be closed yet")
128+
}
129+
130+
err := svc.Close()
131+
if err != nil {
132+
t.Errorf("Close() error = %v, want nil", err)
133+
}
134+
135+
if !mock.closeCalled {
136+
t.Error("provider.Close() was not called")
137+
}
138+
}
139+
140+
func TestService_StartTwice(t *testing.T) {
141+
mock := &MockProvider{}
142+
svc := NewService(mock)
143+
144+
ctx := context.Background()
145+
146+
// First Start - should succeed
147+
err := svc.Start(ctx, 3000)
148+
149+
if err != nil {
150+
t.Fatalf("First Start() error = %v, want nil", err)
151+
}
152+
153+
err = svc.Start(ctx, 3000)
154+
if err == nil {
155+
t.Fatalf("Second start shall cause error")
156+
}
157+
158+
if !strings.Contains(err.Error(), "already started") {
159+
t.Error("already started error shall be returned")
160+
}
161+
}

0 commit comments

Comments
 (0)