Skip to content

Commit 2c6b182

Browse files
authored
Merge pull request #13 from appsome/feature/7-unit-tests
test: Add comprehensive backend unit tests (Issue #7)
2 parents 6d7d254 + f1f43d3 commit 2c6b182

17 files changed

Lines changed: 4816 additions & 3 deletions

server/actions_test.go

Lines changed: 508 additions & 0 deletions
Large diffs are not rendered by default.

server/bridge_client_test.go

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/mattermost/mattermost/server/public/plugin/plugintest"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestNewBridgeClient(t *testing.T) {
14+
api := &plugintest.API{}
15+
client := NewBridgeClient("http://localhost:3002", api)
16+
17+
assert.NotNil(t, client)
18+
assert.Equal(t, "http://localhost:3002", client.baseURL)
19+
assert.NotNil(t, client.httpClient)
20+
}
21+
22+
func TestCreateSession_Success(t *testing.T) {
23+
// Create test server
24+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
25+
assert.Equal(t, "/api/sessions", r.URL.Path)
26+
assert.Equal(t, "POST", r.Method)
27+
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
28+
29+
// Verify request body
30+
var reqBody CreateSessionRequest
31+
json.NewDecoder(r.Body).Decode(&reqBody)
32+
assert.Equal(t, "/test/project", reqBody.ProjectPath)
33+
assert.Equal(t, "user123", reqBody.MattermostUserID)
34+
assert.Equal(t, "channel123", reqBody.MattermostChannelID)
35+
36+
// Send response
37+
w.WriteHeader(http.StatusCreated)
38+
response := map[string]interface{}{
39+
"session": map[string]interface{}{
40+
"id": "session123",
41+
"projectPath": "/test/project",
42+
"mattermostUserId": "user123",
43+
"mattermostChannelId": "channel123",
44+
"status": "active",
45+
"createdAt": 1234567890,
46+
"updatedAt": 1234567890,
47+
},
48+
}
49+
json.NewEncoder(w).Encode(response)
50+
}))
51+
defer server.Close()
52+
53+
api := &plugintest.API{}
54+
client := NewBridgeClient(server.URL, api)
55+
56+
session, err := client.CreateSession("/test/project", "user123", "channel123")
57+
58+
assert.NoError(t, err)
59+
assert.NotNil(t, session)
60+
assert.Equal(t, "session123", session.ID)
61+
assert.Equal(t, "/test/project", session.ProjectPath)
62+
assert.Equal(t, "user123", session.MattermostUserID)
63+
assert.Equal(t, "channel123", session.MattermostChannelID)
64+
assert.Equal(t, "active", session.Status)
65+
}
66+
67+
func TestCreateSession_Error(t *testing.T) {
68+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
69+
w.WriteHeader(http.StatusBadRequest)
70+
w.Write([]byte("Invalid project path"))
71+
}))
72+
defer server.Close()
73+
74+
api := &plugintest.API{}
75+
client := NewBridgeClient(server.URL, api)
76+
77+
session, err := client.CreateSession("", "user123", "channel123")
78+
79+
assert.Error(t, err)
80+
assert.Nil(t, session)
81+
assert.Contains(t, err.Error(), "400")
82+
}
83+
84+
func TestSendMessage_Success(t *testing.T) {
85+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
86+
assert.Equal(t, "/api/sessions/session123/message", r.URL.Path)
87+
assert.Equal(t, "POST", r.Method)
88+
89+
var reqBody SendMessageRequest
90+
json.NewDecoder(r.Body).Decode(&reqBody)
91+
assert.Equal(t, "Hello Claude", reqBody.Message)
92+
93+
w.WriteHeader(http.StatusOK)
94+
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
95+
}))
96+
defer server.Close()
97+
98+
api := &plugintest.API{}
99+
client := NewBridgeClient(server.URL, api)
100+
101+
err := client.SendMessage("session123", "Hello Claude")
102+
103+
assert.NoError(t, err)
104+
}
105+
106+
func TestSendMessage_Error(t *testing.T) {
107+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
108+
w.WriteHeader(http.StatusNotFound)
109+
w.Write([]byte("Session not found"))
110+
}))
111+
defer server.Close()
112+
113+
api := &plugintest.API{}
114+
client := NewBridgeClient(server.URL, api)
115+
116+
err := client.SendMessage("invalid", "test")
117+
118+
assert.Error(t, err)
119+
assert.Contains(t, err.Error(), "404")
120+
}
121+
122+
func TestGetMessages_Success(t *testing.T) {
123+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
124+
assert.Equal(t, "/api/sessions/session123/messages", r.URL.Path)
125+
assert.Equal(t, "10", r.URL.Query().Get("limit"))
126+
127+
w.WriteHeader(http.StatusOK)
128+
response := map[string]interface{}{
129+
"messages": []map[string]interface{}{
130+
{
131+
"id": 1,
132+
"sessionId": "session123",
133+
"role": "user",
134+
"content": "Hello",
135+
"timestamp": 1234567890,
136+
},
137+
{
138+
"id": 2,
139+
"sessionId": "session123",
140+
"role": "assistant",
141+
"content": "Hi there!",
142+
"timestamp": 1234567900,
143+
},
144+
},
145+
}
146+
json.NewEncoder(w).Encode(response)
147+
}))
148+
defer server.Close()
149+
150+
api := &plugintest.API{}
151+
client := NewBridgeClient(server.URL, api)
152+
153+
messages, err := client.GetMessages("session123", 10)
154+
155+
assert.NoError(t, err)
156+
assert.Len(t, messages, 2)
157+
assert.Equal(t, "Hello", messages[0].Content)
158+
assert.Equal(t, "Hi there!", messages[1].Content)
159+
}
160+
161+
func TestGetSession_Success(t *testing.T) {
162+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
163+
assert.Equal(t, "/api/sessions/session123", r.URL.Path)
164+
165+
pid := 12345
166+
w.WriteHeader(http.StatusOK)
167+
response := map[string]interface{}{
168+
"session": map[string]interface{}{
169+
"id": "session123",
170+
"projectPath": "/test/project",
171+
"mattermostUserId": "user123",
172+
"mattermostChannelId": "channel123",
173+
"cliPid": pid,
174+
"status": "active",
175+
"createdAt": 1234567890,
176+
"updatedAt": 1234567900,
177+
},
178+
}
179+
json.NewEncoder(w).Encode(response)
180+
}))
181+
defer server.Close()
182+
183+
api := &plugintest.API{}
184+
client := NewBridgeClient(server.URL, api)
185+
186+
session, err := client.GetSession("session123")
187+
188+
assert.NoError(t, err)
189+
assert.NotNil(t, session)
190+
assert.Equal(t, "session123", session.ID)
191+
assert.Equal(t, "active", session.Status)
192+
assert.NotNil(t, session.CLIPid)
193+
assert.Equal(t, 12345, *session.CLIPid)
194+
}
195+
196+
func TestDeleteSession_Success(t *testing.T) {
197+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
198+
assert.Equal(t, "/api/sessions/session123", r.URL.Path)
199+
assert.Equal(t, "DELETE", r.Method)
200+
201+
w.WriteHeader(http.StatusOK)
202+
json.NewEncoder(w).Encode(map[string]string{"status": "deleted"})
203+
}))
204+
defer server.Close()
205+
206+
api := &plugintest.API{}
207+
client := NewBridgeClient(server.URL, api)
208+
209+
err := client.DeleteSession("session123")
210+
211+
assert.NoError(t, err)
212+
}
213+
214+
func TestSendContext_Success(t *testing.T) {
215+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
216+
assert.Equal(t, "/api/sessions/session123/context", r.URL.Path)
217+
assert.Equal(t, "POST", r.Method)
218+
219+
var reqBody ContextRequest
220+
json.NewDecoder(r.Body).Decode(&reqBody)
221+
assert.Equal(t, "thread", reqBody.Source)
222+
assert.Equal(t, "Thread context content", reqBody.Content)
223+
assert.Equal(t, "summarize", reqBody.Action)
224+
225+
w.WriteHeader(http.StatusOK)
226+
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
227+
}))
228+
defer server.Close()
229+
230+
api := &plugintest.API{}
231+
client := NewBridgeClient(server.URL, api)
232+
233+
contextReq := &ContextRequest{
234+
Source: "thread",
235+
Content: "Thread context content",
236+
Action: "summarize",
237+
Metadata: &ContextMetadata{
238+
ChannelName: "test-channel",
239+
MessageCount: 5,
240+
},
241+
}
242+
243+
err := client.SendContext("session123", contextReq)
244+
245+
assert.NoError(t, err)
246+
}
247+
248+
func TestApproveChange_Success(t *testing.T) {
249+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
250+
assert.Equal(t, "/api/sessions/session123/approve", r.URL.Path)
251+
252+
var reqBody map[string]string
253+
json.NewDecoder(r.Body).Decode(&reqBody)
254+
assert.Equal(t, "change456", reqBody["changeId"])
255+
256+
w.WriteHeader(http.StatusOK)
257+
json.NewEncoder(w).Encode(map[string]string{"status": "approved"})
258+
}))
259+
defer server.Close()
260+
261+
api := &plugintest.API{}
262+
client := NewBridgeClient(server.URL, api)
263+
264+
err := client.ApproveChange("session123", "change456")
265+
266+
assert.NoError(t, err)
267+
}
268+
269+
func TestRejectChange_Success(t *testing.T) {
270+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
271+
assert.Equal(t, "/api/sessions/session123/reject", r.URL.Path)
272+
273+
var reqBody map[string]string
274+
json.NewDecoder(r.Body).Decode(&reqBody)
275+
assert.Equal(t, "change456", reqBody["changeId"])
276+
277+
w.WriteHeader(http.StatusOK)
278+
json.NewEncoder(w).Encode(map[string]string{"status": "rejected"})
279+
}))
280+
defer server.Close()
281+
282+
api := &plugintest.API{}
283+
client := NewBridgeClient(server.URL, api)
284+
285+
err := client.RejectChange("session123", "change456")
286+
287+
assert.NoError(t, err)
288+
}
289+
290+
func TestModifyChange_Success(t *testing.T) {
291+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
292+
assert.Equal(t, "/api/sessions/session123/modify", r.URL.Path)
293+
294+
var reqBody map[string]string
295+
json.NewDecoder(r.Body).Decode(&reqBody)
296+
assert.Equal(t, "change456", reqBody["changeId"])
297+
assert.Equal(t, "Add more tests", reqBody["instructions"])
298+
299+
w.WriteHeader(http.StatusOK)
300+
json.NewEncoder(w).Encode(map[string]string{"status": "modified"})
301+
}))
302+
defer server.Close()
303+
304+
api := &plugintest.API{}
305+
client := NewBridgeClient(server.URL, api)
306+
307+
err := client.ModifyChange("session123", "change456", "Add more tests")
308+
309+
assert.NoError(t, err)
310+
}
311+
312+
func TestGetFileContent_Success(t *testing.T) {
313+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
314+
assert.Equal(t, "/api/sessions/session123/file", r.URL.Path)
315+
316+
var reqBody map[string]string
317+
json.NewDecoder(r.Body).Decode(&reqBody)
318+
assert.Equal(t, "src/main.go", reqBody["filename"])
319+
320+
w.WriteHeader(http.StatusOK)
321+
response := map[string]string{
322+
"content": "package main\n\nfunc main() {}\n",
323+
}
324+
json.NewEncoder(w).Encode(response)
325+
}))
326+
defer server.Close()
327+
328+
api := &plugintest.API{}
329+
client := NewBridgeClient(server.URL, api)
330+
331+
content, err := client.GetFileContent("session123", "src/main.go")
332+
333+
assert.NoError(t, err)
334+
assert.Contains(t, content, "package main")
335+
assert.Contains(t, content, "func main")
336+
}

server/cli_process.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ func (pm *ProcessManager) GetRunningCount() int {
346346

347347
// GetAllProcesses returns a slice of all running processes
348348
func (pm *ProcessManager) GetAllProcesses() []*CLIProcess {
349-
var processes []*CLIProcess
349+
processes := []*CLIProcess{}
350350
pm.processes.Range(func(key, value interface{}) bool {
351351
process := value.(*CLIProcess)
352352
select {

0 commit comments

Comments
 (0)