Skip to content

Commit 823dfbb

Browse files
committed
build: refactor classify/group tRPC tests
1 parent 63a8d69 commit 823dfbb

File tree

5 files changed

+294
-228
lines changed

5 files changed

+294
-228
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.i3863;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
import java.util.Map;
11+
12+
import com.jayway.jsonpath.JsonPath;
13+
import io.jooby.Jooby;
14+
import io.jooby.junit.ServerTest;
15+
import io.jooby.junit.ServerTestRunner;
16+
import io.jooby.trpc.TrpcModule;
17+
18+
public abstract class AbstractTrpcProtocolTest {
19+
20+
/**
21+
* Subclasses must provide the specific JSON engine module (e.g., JacksonModule,
22+
* AvajeJsonbModule).
23+
*/
24+
protected abstract void installJsonEngine(Jooby app);
25+
26+
// Helper to keep test setup DRY
27+
private void setupApp(Jooby app) {
28+
installJsonEngine(app);
29+
app.install(new TrpcModule());
30+
app.mvc(new MovieService_());
31+
}
32+
33+
@ServerTest
34+
void shouldHandleBasicAndMultiArgumentCalls(ServerTestRunner runner) {
35+
runner
36+
.define(this::setupApp)
37+
.ready(
38+
http -> {
39+
// Ping (No Arguments)
40+
http.get(
41+
"/trpc/movies.ping",
42+
rsp -> {
43+
assertThat(rsp.code()).isEqualTo(200);
44+
assertThat(rsp.body().string())
45+
.isEqualToIgnoringNewLines("{\"result\":{\"data\":\"pong\"}}");
46+
});
47+
48+
// GetById (Single Primitive Argument - Seamless)
49+
http.get(
50+
"/trpc/movies.getById?input=1",
51+
rsp -> {
52+
assertThat(rsp.code()).isEqualTo(200);
53+
assertThat(rsp.body().string())
54+
.isEqualToIgnoringNewLines(
55+
"{\"result\":{\"data\":{\"id\":1,\"title\":\"The"
56+
+ " Godfather\",\"year\":1972}}}");
57+
});
58+
59+
// GetById (Not found)
60+
http.get(
61+
"/trpc/movies.getById?input=13",
62+
rsp -> {
63+
assertThat(rsp.code()).isEqualTo(404);
64+
assertThat(rsp.body().string())
65+
.isEqualToIgnoringNewLines(
66+
"""
67+
{"error":{"message":"Movie not found: 13","code":-32004,"data":{"code":"NOT_FOUND","httpStatus":404,"path":"movies.getById"}}}
68+
""");
69+
});
70+
71+
// Search (Multi-Argument Tuple)
72+
http.get(
73+
"/trpc/movies.search?input=[\"Pulp Fiction\", 1994]",
74+
rsp -> {
75+
assertThat(rsp.code()).isEqualTo(200);
76+
assertThat(rsp.body().string())
77+
.isEqualToIgnoringNewLines(
78+
"{\"result\":{\"data\":[{\"id\":2,\"title\":\"Pulp"
79+
+ " Fiction\",\"year\":1994}]}}");
80+
});
81+
82+
// AddReview (Multi-Argument Mutation)
83+
http.postJson(
84+
"/trpc/movies.addReview",
85+
"[\"The Godfather\", 5, \"Amazing\"]",
86+
rsp -> {
87+
var json = rsp.body().string();
88+
assertThat(rsp.code()).isEqualTo(200);
89+
assertThat(JsonPath.<String>read(json, "$.result.data.status"))
90+
.isEqualTo("published");
91+
assertThat(JsonPath.<Integer>read(json, "$.result.data.rating")).isEqualTo(5);
92+
});
93+
});
94+
}
95+
96+
@ServerTest
97+
void shouldHandleSeamlessVsTupleWrappers(ServerTestRunner runner) {
98+
runner
99+
.define(this::setupApp)
100+
.ready(
101+
http -> {
102+
// Create (Strict Seamless Payload for single argument)
103+
http.postJson(
104+
"/trpc/movies.create",
105+
"{\"id\": 1, \"title\": \"The Matrix\", \"year\": 1999}",
106+
rsp -> {
107+
String json = rsp.body().string();
108+
assertThat(rsp.code()).isEqualTo(200);
109+
assertThat(JsonPath.<String>read(json, "$.result.data.title"))
110+
.isEqualTo("The Matrix");
111+
});
112+
113+
// BulkCreate (Single argument that is inherently an array)
114+
http.get(
115+
"/trpc/movies.bulkCreate",
116+
Map.of("input", "[{\"id\": 1, \"title\": \"The Matrix\", \"year\": 1999}]"),
117+
rsp -> {
118+
String json = rsp.body().string();
119+
assertThat(rsp.code()).isEqualTo(200);
120+
assertThat(JsonPath.<String>read(json, "$.result.data[0]"))
121+
.isEqualTo("Created: The Matrix");
122+
});
123+
});
124+
}
125+
126+
@ServerTest
127+
void shouldHandleReactiveAndVoidTypes(ServerTestRunner runner) {
128+
runner
129+
.define(this::setupApp)
130+
.ready(
131+
http -> {
132+
// CreateMono (Reactive Pipeline)
133+
http.postJson(
134+
"/trpc/movies.createMono",
135+
"{\"id\": 1, \"title\": \"The Matrix\", \"year\": 1999}",
136+
rsp -> {
137+
String json = rsp.body().string();
138+
assertThat(rsp.code()).isEqualTo(200);
139+
assertThat(JsonPath.<Integer>read(json, "$.result.data.id")).isEqualTo(1);
140+
});
141+
142+
// ResetIndex (Void return type)
143+
http.post(
144+
"/trpc/movies.resetIndex",
145+
rsp -> {
146+
assertThat(rsp.code()).isEqualTo(200);
147+
assertThat(rsp.body().string()).contains("\"result\"");
148+
});
149+
});
150+
}
151+
152+
@ServerTest
153+
void shouldHandleErrorsAndEdgeCases(ServerTestRunner runner) {
154+
runner
155+
.define(this::setupApp)
156+
.ready(
157+
http -> {
158+
// Error: Type Mismatch
159+
http.postJson(
160+
"/trpc/movies.addReview",
161+
"[\"The Godfather\", \"FIVE_STARS\", \"Amazing\"]",
162+
rsp -> {
163+
String json = rsp.body().string();
164+
assertThat(rsp.code()).isEqualTo(400);
165+
assertThat(JsonPath.<String>read(json, "$.error.data.code"))
166+
.isEqualTo("BAD_REQUEST");
167+
assertThat(JsonPath.<String>read(json, "$.error.message")).isNotEmpty();
168+
});
169+
170+
// Error: Missing Tuple Wrapper (Multi-argument method given a raw string)
171+
http.get(
172+
"/trpc/movies.search?input=\"Pulp Fiction\"",
173+
rsp -> {
174+
String json = rsp.body().string();
175+
assertThat(rsp.code()).isEqualTo(400);
176+
assertThat(JsonPath.<String>read(json, "$.error.message"))
177+
.contains("tRPC input for multiple arguments must be a JSON array (tuple)");
178+
});
179+
180+
// Error: Procedure Not Found (404)
181+
http.get(
182+
"/trpc/movies.doesNotExist",
183+
rsp -> {
184+
String json = rsp.body().string();
185+
assertThat(rsp.code()).isEqualTo(404);
186+
assertThat(JsonPath.<String>read(json, "$.error.data.code"))
187+
.isEqualTo("NOT_FOUND");
188+
});
189+
});
190+
}
191+
192+
@ServerTest
193+
void shouldHandleNullabilityValidation(ServerTestRunner runner) {
194+
runner
195+
.define(this::setupApp)
196+
.ready(
197+
http -> {
198+
// Validating a nullable parameter is accepted (Integer)
199+
http.get(
200+
"/trpc/movies.search?input=[\"The Godfather\", null]",
201+
rsp -> {
202+
assertThat(rsp.code()).isEqualTo(200);
203+
assertThat(rsp.body().string()).contains("\"The Godfather\"");
204+
});
205+
206+
// Validating a required (primitive) parameter rejects null (Seamless path)
207+
http.get(
208+
"/trpc/movies.getById?input=null",
209+
rsp -> {
210+
String json = rsp.body().string();
211+
assertThat(rsp.code()).isEqualTo(400);
212+
assertThat(JsonPath.<String>read(json, "$.error.data.code"))
213+
.isEqualTo("BAD_REQUEST");
214+
});
215+
216+
// Validating MissingValueException (Not enough arguments in the tuple)
217+
http.postJson(
218+
"/trpc/movies.addReview",
219+
"[\"The Godfather\", 5]",
220+
rsp -> {
221+
String json = rsp.body().string();
222+
assertThat(rsp.code()).isEqualTo(400);
223+
assertThat(JsonPath.<String>read(json, "$.error.message"))
224+
.containsIgnoringCase("comment");
225+
});
226+
227+
// Validating explicit null on an Object/POJO
228+
http.postJson(
229+
"/trpc/movies.updateMetadata",
230+
"[1, null]",
231+
rsp -> {
232+
assertThat(rsp.code()).isEqualTo(200);
233+
assertThat(rsp.body().string()).contains("\"result\"");
234+
});
235+
236+
// Delete Movie
237+
http.postJson(
238+
"/trpc/movies.deleteMovie",
239+
"1",
240+
rsp -> {
241+
assertThat(rsp.code()).isEqualTo(200);
242+
assertThat(rsp.body().string()).contains("\"result\"");
243+
});
244+
});
245+
}
246+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.i3863;
7+
8+
import io.jooby.Jooby;
9+
import io.jooby.avaje.jsonb.AvajeJsonbModule;
10+
11+
public class AvajeTrpcProtocolTest extends AbstractTrpcProtocolTest {
12+
@Override
13+
protected void installJsonEngine(Jooby app) {
14+
app.install(new AvajeJsonbModule());
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.i3863;
7+
8+
import io.jooby.Jooby;
9+
import io.jooby.jackson.JacksonModule;
10+
11+
public class Jackson2TrpcProtocolTest extends AbstractTrpcProtocolTest {
12+
@Override
13+
protected void installJsonEngine(Jooby app) {
14+
app.install(new JacksonModule());
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.i3863;
7+
8+
import io.jooby.Jooby;
9+
import io.jooby.jackson3.Jackson3Module;
10+
11+
public class Jackson3TrpcProtocolTest extends AbstractTrpcProtocolTest {
12+
@Override
13+
protected void installJsonEngine(Jooby app) {
14+
app.install(new Jackson3Module());
15+
}
16+
}

0 commit comments

Comments
 (0)