Skip to content

Commit 5c90dfe

Browse files
committed
Add unit test for response validation
Adapt Makefile to also run unit tests with `make test`
1 parent c6708fe commit 5c90dfe

File tree

4 files changed

+269
-3
lines changed

4 files changed

+269
-3
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ jobs:
2020
- name: Build
2121
run: make build
2222

23-
- name: Run tests against mock handler
23+
- name: Run tests
2424
run: make test

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ mock-handler:
1919
go build -o $(MOCK_HANDLER_BIN) ./cmd/mock-handler
2020

2121
test:
22+
@echo "Running runner unit tests..."
23+
go test ./runner/...
2224
@echo "Running conformance tests with mock handler..."
2325
$(RUNNER_BIN) -handler $(MOCK_HANDLER_BIN)
2426

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ make runner
5656

5757
### Testing the Runner
5858

59-
Build and test the runner using the mock handler:
59+
Build and test the runner:
6060

6161
```bash
6262
# Build both runner and mock handler
6363
make build
6464

65-
# Run the test runner against the mock handler
65+
# Run runner unit tests and integration tests with mock handler
6666
make test
6767
```

runner/runner_test.go

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
package runner
2+
3+
import (
4+
"encoding/json"
5+
"strings"
6+
"testing"
7+
)
8+
9+
func TestValidateResponse(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
testCaseJSON string
13+
responseJSON string
14+
wantErr bool
15+
wantErrMsg string
16+
}{
17+
{
18+
name: "success with boolean result",
19+
testCaseJSON: `{
20+
"id": "1",
21+
"expected": {"result": true}
22+
}`,
23+
responseJSON: `{
24+
"id": "1",
25+
"result": true
26+
}`,
27+
wantErr: false,
28+
},
29+
{
30+
name: "success with null result explicit",
31+
testCaseJSON: `{
32+
"id": "2",
33+
"expected": {}
34+
}`,
35+
responseJSON: `{
36+
"id": "2",
37+
"result": null
38+
}`,
39+
wantErr: false,
40+
},
41+
{
42+
name: "success with null result omitted",
43+
testCaseJSON: `{
44+
"id": "3",
45+
"expected": {}
46+
}`,
47+
responseJSON: `{
48+
"id": "3"
49+
}`,
50+
wantErr: false,
51+
},
52+
{
53+
name: "error exact match",
54+
testCaseJSON: `{
55+
"id": "4",
56+
"expected": {
57+
"error": {
58+
"code": {
59+
"type": "type",
60+
"member": "MEMBER"
61+
}
62+
}
63+
}
64+
}`,
65+
responseJSON: `{
66+
"id": "4",
67+
"result": null,
68+
"error": {
69+
"code": {
70+
"type": "type",
71+
"member": "MEMBER"
72+
}
73+
}
74+
}`,
75+
wantErr: false,
76+
},
77+
{
78+
name: "error type mismatch",
79+
testCaseJSON: `{
80+
"id": "5",
81+
"expected": {
82+
"error": {
83+
"code": {
84+
"type": "type",
85+
"member": "MEMBER"
86+
}
87+
}
88+
}
89+
}`,
90+
responseJSON: `{
91+
"id": "5",
92+
"error": {
93+
"code": {
94+
"type": "different_type",
95+
"member": "MEMBER"
96+
}
97+
}
98+
}`,
99+
wantErr: true,
100+
wantErrMsg: "expected error type",
101+
},
102+
{
103+
name: "error member mismatch",
104+
testCaseJSON: `{
105+
"id": "6",
106+
"expected": {
107+
"error": {
108+
"code": {
109+
"type": "type",
110+
"member": "MEMBER"
111+
}
112+
}
113+
}
114+
}`,
115+
responseJSON: `{
116+
"id": "6",
117+
"error": {
118+
"code": {
119+
"type": "type",
120+
"member": "DIFFERENT_MEMBER"
121+
}
122+
}
123+
}`,
124+
wantErr: true,
125+
wantErrMsg: "expected error member",
126+
},
127+
{
128+
name: "expected success got error",
129+
testCaseJSON: `{
130+
"id": "7",
131+
"expected": {"result": true}
132+
}`,
133+
responseJSON: `{
134+
"id": "7",
135+
"result": null,
136+
"error": {
137+
"code": {
138+
"type": "type",
139+
"member": "MEMBER"
140+
}
141+
}
142+
}`,
143+
wantErr: true,
144+
wantErrMsg: "expected success with no error",
145+
},
146+
{
147+
name: "expected error got success",
148+
testCaseJSON: `{
149+
"id": "8",
150+
"expected": {
151+
"error": {
152+
"code": {
153+
"type": "type",
154+
"member": "MEMBER"
155+
}
156+
}
157+
}
158+
}`,
159+
responseJSON: `{
160+
"id": "8",
161+
"result": true
162+
}`,
163+
wantErr: true,
164+
wantErrMsg: "expected error",
165+
},
166+
{
167+
name: "result value mismatch",
168+
testCaseJSON: `{
169+
"id": "9",
170+
"expected": {"result": true}
171+
}`,
172+
responseJSON: `{
173+
"id": "9",
174+
"result": false
175+
}`,
176+
wantErr: true,
177+
wantErrMsg: "result mismatch",
178+
},
179+
{
180+
name: "response ID mismatch",
181+
testCaseJSON: `{
182+
"id": "10",
183+
"expected": {"result": true}
184+
}`,
185+
responseJSON: `{
186+
"id": "99",
187+
"result": true
188+
}`,
189+
wantErr: true,
190+
wantErrMsg: "response ID mismatch",
191+
},
192+
{
193+
name: "protocol violation with result not null when error present",
194+
testCaseJSON: `{
195+
"id": "11",
196+
"expected": {
197+
"error": {
198+
"code": {
199+
"type": "type",
200+
"member": "MEMBER"
201+
}
202+
}
203+
}
204+
}`,
205+
responseJSON: `{
206+
"id": "11",
207+
"result": true,
208+
"error": {
209+
"code": {
210+
"type": "type",
211+
"member": "MEMBER"
212+
}
213+
}
214+
}`,
215+
wantErr: true,
216+
wantErrMsg: "expected result to be null or omitted when error is present",
217+
},
218+
{
219+
name: "error generic without code",
220+
testCaseJSON: `{
221+
"id": "12",
222+
"expected": {
223+
"error": {}
224+
}
225+
}`,
226+
responseJSON: `{
227+
"id": "12",
228+
"result": null,
229+
"error": {}
230+
}`,
231+
wantErr: false,
232+
},
233+
}
234+
235+
for _, tt := range tests {
236+
t.Run(tt.name, func(t *testing.T) {
237+
var testCase TestCase
238+
if err := json.Unmarshal([]byte(tt.testCaseJSON), &testCase); err != nil {
239+
t.Fatalf("failed to unmarshal test case: %v", err)
240+
}
241+
242+
var response Response
243+
if err := json.Unmarshal([]byte(tt.responseJSON), &response); err != nil {
244+
t.Fatalf("failed to unmarshal response: %v", err)
245+
}
246+
247+
err := validateResponse(testCase, &response)
248+
249+
if tt.wantErr {
250+
if err == nil {
251+
t.Errorf("expected error containing %q, got nil", tt.wantErrMsg)
252+
return
253+
}
254+
if !strings.Contains(strings.ToLower(err.Error()), strings.ToLower(tt.wantErrMsg)) {
255+
t.Errorf("expected error containing %q, got %q", tt.wantErrMsg, err.Error())
256+
}
257+
} else {
258+
if err != nil {
259+
t.Errorf("expected no error, got: %v", err)
260+
}
261+
}
262+
})
263+
}
264+
}

0 commit comments

Comments
 (0)