Skip to content

Commit dcb8950

Browse files
committed
bring in all the methods to send params and headers to a SSE connection
1 parent 83a7c73 commit dcb8950

File tree

13 files changed

+432
-56
lines changed

13 files changed

+432
-56
lines changed

unirest-bdd-tests/src/test/java/BehaviorTests/HeaderAsserts.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ public String getValue() {
156156
return value;
157157
}
158158

159+
@Override
160+
public String toString(){
161+
return value;
162+
}
163+
159164
public HeaderValue assertHasParam(String name) {
160165
TestUtil.assertMultiMap(params)
161166
.as("Header Param")

unirest-bdd-tests/src/test/java/BehaviorTests/MockServer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ private static Optional<String> simpleResponse(Context context) {
271271
private static void jsonResponse(Context c){
272272
jsonResponse(c, false);
273273
}
274+
275+
274276
private static void jsonResponse(Context c, Boolean compress) {
275277
if(retryTimes > 0){
276278
if(retrySeconds != null) {
@@ -395,5 +397,13 @@ public static final class Sse {
395397
public static void sendComment(String comment) {
396398
TestSSEConsumer.sendComment(comment);
397399
}
400+
401+
public static void sendEvent(String content) {
402+
TestSSEConsumer.sendEvent(content);
403+
}
404+
405+
public static RequestCapture lastRequest() {
406+
return TestSSEConsumer.getLastRequest();
407+
}
398408
}
399409
}

unirest-bdd-tests/src/test/java/BehaviorTests/SSETest.java

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,109 @@
2626
package BehaviorTests;
2727

2828

29-
import kong.unirest.core.Unirest;
29+
import kong.unirest.core.SseRequest;
30+
import org.junit.jupiter.api.BeforeEach;
3031
import org.junit.jupiter.api.Test;
3132

33+
import java.util.List;
34+
import java.util.Map;
35+
import java.util.function.Supplier;
36+
37+
import static kong.unirest.core.Unirest.sse;
3238
import static org.assertj.core.api.Assertions.assertThat;
3339
import static org.junit.jupiter.api.Assertions.assertTrue;
3440

3541
public class SSETest extends BddTest {
3642

43+
TestListener listener;
44+
45+
@BeforeEach
46+
public void setUp() {
47+
super.setUp();
48+
listener = new TestListener();
49+
}
50+
3751
@Test
38-
void basicConnection() throws Exception {
39-
var tl = new TestListener();
52+
void basicConnection() {
53+
runWith(sse(MockServer.SSE), listener);
54+
55+
MockServer.Sse.sendComment("hey1");
56+
MockServer.Sse.sendEvent("Whats Happening?");
4057

41-
TestUtil.run(() -> {
42-
var future = Unirest.sse(MockServer.SSE).connect(tl);
58+
sleep(500);
4359

44-
TestUtil.blockUntil(future::isDone);
45-
});
60+
listener.assertHasEvent("connect", "Welcome to Server Side Events")
61+
.assertHasComment("hey1")
62+
.assertHasEvent("message", "Whats Happening?");
63+
}
4664

47-
Thread.sleep(1000);
65+
@Test
66+
void queryParams(){
67+
runWith(sse(MockServer.SSE)
68+
.queryString("foo", "bar")
69+
.queryString(Map.of("fruit", "apple", "number", 1))
70+
.queryString("droid", List.of("C3PO", "R2D2")), listener);
4871

49-
MockServer.Sse.sendComment("hey1");
50-
MockServer.Sse.sendComment("hey2");
72+
MockServer.Sse.lastRequest()
73+
.assertParam("foo", "bar")
74+
.assertParam("fruit", "apple")
75+
.assertParam("number", "1")
76+
.assertParam("droid", "C3PO")
77+
.assertParam("droid", "R2D2");
78+
}
5179

52-
Thread.sleep(1000);
80+
@Test
81+
void headers(){
82+
runWith(sse(MockServer.SSE)
83+
.header("foo", "bar")
84+
.header("qux", "zip")
85+
.headerReplace("qux", "ok")
86+
.headers(Map.of("fruit", "apple", "number", "1"))
87+
.cookie("snack", "snickerdoodle")
88+
, listener);
89+
90+
MockServer.Sse.lastRequest()
91+
.assertHeader("Accept", "text/event-stream")
92+
.assertHeader("foo", "bar")
93+
.assertHeader("qux", "ok")
94+
.assertHeader("number", "1")
95+
.assertHeader("fruit", "apple")
96+
.assertCookie("snack", "snickerdoodle");
97+
98+
}
99+
100+
@Test
101+
void canReplaceTheDefaultAcceptsHeader(){
102+
runWith(sse(MockServer.SSE)
103+
.header("Accept", "application/json")
104+
, listener);
105+
106+
MockServer.Sse.lastRequest()
107+
.assertHeader("Accept", "application/json");
108+
}
53109

54-
tl.assertHasComment("hey1");
55-
tl.assertHasComment("hey2");
110+
private static void runWith(SseRequest sse, TestListener tl) {
111+
try {
112+
var t = new Thread(() -> {
113+
var future = sse.connect(tl);
114+
while(!future.isDone()){
115+
// waitin'
116+
}
117+
});
118+
t.start();
119+
120+
Thread.sleep(500);
121+
}catch (Exception e){
122+
throw new RuntimeException(e);
123+
}
124+
}
56125

126+
private void sleep(int i) {
127+
try {
128+
Thread.sleep(i);
129+
} catch (InterruptedException e) {
130+
throw new RuntimeException(e);
131+
}
57132
}
58133

59134
}

unirest-bdd-tests/src/test/java/BehaviorTests/TestListener.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,24 @@
3636

3737
public class TestListener implements SseListener {
3838
private final List<String> comments = Collections.synchronizedList(new ArrayList<>());
39+
private final List<Event> events = Collections.synchronizedList(new ArrayList<>());
3940

40-
void assertHasComment(String comment) {
41+
TestListener assertHasComment(String comment) {
4142
assertThat(comments)
4243
.contains(comment);
44+
return this;
45+
}
46+
47+
public TestListener assertHasEvent(String event, String content) {
48+
assertThat(events)
49+
.contains(new Event("", event, content));
50+
return this;
4351
}
4452

4553

4654
@Override
4755
public void onEvent(Event event) {
48-
56+
events.add(event);
4957
}
5058

5159
@Override

unirest-bdd-tests/src/test/java/BehaviorTests/TestSSEConsumer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,23 @@
3333

3434
public class TestSSEConsumer implements Consumer<SseClient> {
3535
private static final Queue<SseClient> clients = new ConcurrentLinkedDeque<>();
36+
private static RequestCapture lastRequest;
37+
38+
public static RequestCapture getLastRequest() {
39+
return lastRequest;
40+
}
3641

3742
public static void sendComment(String message) {
3843
clients.forEach(c -> c.sendComment(message));
3944
}
4045

46+
public static void sendEvent(String data) {
47+
clients.forEach(c -> c.sendEvent(data));
48+
}
49+
4150
@Override
4251
public void accept(SseClient client) {
52+
lastRequest = new RequestCapture(client.ctx());
4353
client.keepAlive();
4454
client.sendEvent("connect", "Welcome to Server Side Events");
4555
clients.add(client);

unirest-bdd-tests/src/test/java/BehaviorTests/TestUtil.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import java.util.HashMap;
4848
import java.util.Map;
4949
import java.util.function.Consumer;
50-
import java.util.function.Supplier;
5150

5251
import static org.assertj.core.api.Fail.fail;
5352
import static org.mockito.ArgumentMatchers.any;
@@ -61,13 +60,6 @@ class TestUtil {
6160
om.registerModule(new GuavaModule());
6261
}
6362

64-
public static Thread run(Runnable runnable){
65-
var t = new Thread(runnable);
66-
t.start();
67-
return t;
68-
}
69-
70-
7163
public static <T> T readValue(String body, Class<T> as) {
7264
try {
7365
return om.readValue(body, as);
@@ -168,12 +160,6 @@ public static <K, V> MultimapAssert<K, V> assertMultiMap(final Multimap<K, V> ac
168160
return org.assertj.guava.api.Assertions.assertThat(actual);
169161
}
170162

171-
public static void blockUntil(Supplier<Boolean> condition) {
172-
while(!condition.get()){
173-
// waitin'
174-
}
175-
}
176-
177163
public static final class Matchers {
178164
public static Consumer<HeaderAsserts.HeaderValue> isBase64Encoded() {
179165
return h -> {

unirest/src/main/java/kong/unirest/core/ContentType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public class ContentType {
5656
public static final ContentType TEXT_HTML = create("text/html", ISO_8859_1);
5757
public static final ContentType TEXT_PLAIN = create("text/plain", ISO_8859_1);
5858
public static final ContentType TEXT_XML = create("text/xml", ISO_8859_1);
59+
public static final ContentType EVENT_STREAMS = create("text/event-stream", StandardCharsets.UTF_8);
5960
public static final ContentType WILDCARD = create("*/*");
6061

6162
private final String mimeType;

unirest/src/main/java/kong/unirest/core/SseRequest.java

Lines changed: 113 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,124 @@
2525

2626
package kong.unirest.core;
2727

28-
import java.util.Objects;
28+
import java.util.Collection;
29+
import java.util.Map;
2930
import java.util.concurrent.CompletableFuture;
3031

31-
public class SseRequest {
32-
private final Config config;
33-
private final Path url;
34-
protected Headers headers = new Headers();
32+
public interface SseRequest {
33+
/**
34+
* add a route param that replaces the matching {name}
35+
* For example routeParam("name", "fred") will replace {name} in
36+
* https://localhost/users/{user}
37+
* to
38+
* https://localhost/users/fred
39+
*
40+
* @param name the name of the param (do not include curly braces {}
41+
* @param value the value to replace the placeholder with
42+
* @return this request builder
43+
*/
44+
SseRequest routeParam(String name, String value);
3545

46+
/**
47+
* add a route param map that replaces the matching {name}
48+
* For example routeParam(Map.of("name", "fred")) will replace {name} in
49+
* https://localhost/users/{user}
50+
* to
51+
* https://localhost/users/fred
52+
*
53+
* @param params a map of path params
54+
* @return this request builder
55+
*/
56+
SseRequest routeParam(Map<String, Object> params);
3657

37-
public SseRequest(Config config, String url) {
38-
Objects.requireNonNull(config, "Config cannot be null");
39-
Objects.requireNonNull(url, "URL cannot be null");
58+
/**
59+
* Basic auth credentials
60+
* @param username the username
61+
* @param password the password
62+
* @return this request builder
63+
*/
64+
SseRequest basicAuth(String username, String password);
4065

41-
this.config = config;
42-
this.url = new Path(url, config.getDefaultBaseUrl());
43-
headers.putAll(config.getDefaultHeaders());
44-
}
66+
/**
67+
* The Accept header to send (e.g. application/json
68+
* @param value a valid mime type for the Accept header
69+
* @return this request builder
70+
*/
71+
SseRequest accept(String value);
4572

46-
public CompletableFuture<Void> connect(SseListener listener) {
47-
return config.getClient().sse(this, listener);
48-
}
73+
/**
74+
* Add a http header, HTTP supports multiple of the same header. This will continue to append new values
75+
* @param name name of the header
76+
* @param value value for the header
77+
* @return this request builder
78+
*/
79+
SseRequest header(String name, String value);
4980

50-
public Path getPath() {
51-
return url;
52-
}
81+
/**
82+
* Replace a header value or add it if it doesn't exist
83+
* @param name name of the header
84+
* @param value value for the header
85+
* @return this request builder
86+
*/
87+
SseRequest headerReplace(String name, String value);
88+
89+
/**
90+
* Add headers as a map
91+
* @param headerMap a map of headers
92+
* @return this request builder
93+
*/
94+
SseRequest headers(Map<String, String> headerMap);
95+
96+
/**
97+
* Add a simple cookie header
98+
* @param name the name of the cookie
99+
* @param value the value of the cookie
100+
* @return this request builder
101+
*/
102+
SseRequest cookie(String name, String value);
103+
104+
/**
105+
* Add a simple cookie header
106+
* @param cookie a cookie
107+
* @return this request builder
108+
*/
109+
SseRequest cookie(Cookie cookie);
110+
111+
/**
112+
* Add a collection of cookie headers
113+
* @param cookies a cookie
114+
* @return this request builder
115+
*/
116+
SseRequest cookie(Collection<Cookie> cookies);
117+
118+
/**
119+
* add a query param to the url. The value will be URL-Encoded
120+
* @param name the name of the param
121+
* @param value the value of the param
122+
* @return this request builder
123+
*/
124+
SseRequest queryString(String name, Object value);
125+
126+
/**
127+
* Add multiple param with the same param name.
128+
* queryString("name", Arrays.asList("bob", "linda")) will result in
129+
* ?name=bob&amp;name=linda
130+
* @param name the name of the param
131+
* @param value a collection of values
132+
* @return this request builder
133+
*/
134+
SseRequest queryString(String name, Collection<?> value);
135+
136+
/**
137+
* Add query params as a map of name value pairs
138+
* @param parameters a map of params
139+
* @return this request builder
140+
*/
141+
SseRequest queryString(Map<String, Object> parameters);
142+
143+
Headers getHeaders();
144+
145+
String getUrl();
146+
147+
CompletableFuture<Void> connect(SseListener listener);
53148
}

0 commit comments

Comments
 (0)