1 package it.com.atlassian.plugins.rest.sample.entities;
2
3 import com.atlassian.plugins.rest.sample.entities.EntityClientServlet;
4 import com.atlassian.plugins.rest.sample.entities.EntityResource;
5 import com.atlassian.plugins.rest.sample.entities.UriBuilder;
6 import com.google.common.io.ByteStreams;
7 import com.sun.jersey.api.client.Client;
8 import org.apache.commons.httpclient.HttpClient;
9 import org.apache.commons.httpclient.methods.PostMethod;
10 import org.apache.commons.httpclient.methods.RequestEntity;
11 import org.apache.commons.httpclient.methods.StringRequestEntity;
12 import org.hamcrest.CoreMatchers;
13 import org.hamcrest.Matchers;
14 import org.junit.Test;
15 import org.junit.matchers.JUnitMatchers;
16
17 import javax.ws.rs.core.MediaType;
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URI;
22 import java.nio.file.Files;
23 import java.nio.file.Path;
24
25 import static com.atlassian.core.util.ClassLoaderUtils.getResourceAsStream;
26 import static com.atlassian.plugins.rest.sample.entities.EntityClientServlet.P_ACCEPT;
27 import static com.atlassian.plugins.rest.sample.entities.EntityClientServlet.P_CONTENT_TYPE;
28 import static com.atlassian.plugins.rest.sample.entities.EntityClientServlet.P_ORANGE;
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assert.assertThat;
32
33
34
35
36 public class EntityTest {
37
38 private static final String SECRET = Long.toString(Double.doubleToLongBits(Math.random()));
39
40 protected File createSecretFile() throws IOException {
41 final Path path = Files.createTempFile("secret-file", ".txt");
42 Files.write(path, SECRET.getBytes());
43 File f = path.toFile();
44 f.deleteOnExit();
45 return f;
46 }
47
48
49
50
51
52 @Test
53 public void testApplesForOranges() {
54 final URI baseUri = UriBuilder.create().path("plugins").path("servlet").path("client").build();
55 final String returned = Client.create().resource(baseUri).queryParam(P_ORANGE, "valencia").get(String.class);
56 assertEquals(
57 "apple-valencia\n" +
58 "Content-Type=application/xml\n" +
59 "Accept=application/xml", returned);
60 }
61
62 @Test
63 public void testApplesForOrangesJson() {
64 final URI baseUri = UriBuilder.create().path("plugins").path("servlet").path("client").build();
65 final String returned = Client.create().resource(baseUri)
66 .queryParam(P_ORANGE, "delfino")
67 .queryParam(P_CONTENT_TYPE, "application/json")
68 .queryParam(P_ACCEPT, "application/json")
69 .get(String.class);
70 assertEquals(
71 "apple-delfino\n" +
72 "Content-Type=application/json\n" +
73 "Accept=application/json", returned);
74 }
75
76 @Test
77 public void testApplesForOrangesDefaultContentTypeAcceptJson() {
78 final URI baseUri = UriBuilder.create().path("plugins").path("servlet").path("client").build();
79 final String returned = Client.create().resource(baseUri)
80 .queryParam(P_ORANGE, "delfino")
81 .queryParam(P_ACCEPT, "application/json")
82 .get(String.class);
83 assertEquals(
84 "apple-delfino\n" +
85 "Content-Type=application/xml\n" +
86 "Accept=application/json", returned);
87 }
88
89 @Test
90 public void testApplesForOrangesExplicitXmlContentTypeAndAccept() {
91 final URI baseUri = UriBuilder.create().path("plugins").path("servlet").path("client").build();
92 final String returned = Client.create().resource(baseUri)
93 .queryParam(P_ORANGE, "delfino")
94 .queryParam(P_CONTENT_TYPE, "application/xml")
95 .queryParam(P_ACCEPT, "application/xml")
96 .get(String.class);
97 assertEquals(
98 "apple-delfino\n" +
99 "Content-Type=application/xml\n" +
100 "Accept=application/xml", returned);
101 }
102
103 @Test
104 public void testApplesForOrangesMissingAcceptHeaderDefaultsToContentType() {
105 final URI baseUri = UriBuilder.create().path("plugins").path("servlet").path("client").build();
106 final String returned = Client.create().resource(baseUri)
107 .queryParam(P_ORANGE, "delfino")
108 .queryParam(P_CONTENT_TYPE, "application/json")
109 .get(String.class);
110 assertEquals(
111 "apple-delfino\n" +
112 "Content-Type=application/json\n" +
113 "Accept=application/json", returned);
114 }
115
116 @Test
117 public void testApplesForOrangesMultipleValidAcceptHeaders() {
118 final URI baseUri = UriBuilder.create().path("plugins").path("servlet").path("client").build();
119 final String returned = Client.create().resource(baseUri)
120 .queryParam(P_ORANGE, "delfino")
121 .queryParam(P_ACCEPT, "application/json")
122 .queryParam(P_ACCEPT, "application/xml")
123 .get(String.class);
124 assertEquals(
125 "apple-delfino\n" +
126 "Content-Type=application/xml\n" +
127 "Accept=application/json,application/xml", returned);
128 }
129
130
131 private PostMethod postToRestEndpoint(String content) throws IOException {
132 RequestEntity re = new StringRequestEntity(content, "application/xml", "us-ascii");
133
134 final URI baseUri = UriBuilder.create().path("rest").path("entity").path("latest").path("fruit").build();
135
136 HttpClient client = new HttpClient();
137
138 PostMethod m = new PostMethod(baseUri.toString());
139
140 m.setRequestHeader("Accept", "application/xml");
141 m.setRequestEntity(re);
142
143 client.executeMethod(m);
144
145 return m;
146 }
147
148 @Test
149 public void testEntityExpansionDoesNotIncludeFileContents() throws IOException {
150 InputStream in = getResourceAsStream("EntityTest-rest-include-external-entity.xml", this.getClass());
151 assertNotNull(in);
152
153 String contents = new String(ByteStreams.toByteArray(in), "us-ascii");
154
155 contents = contents.replace("/etc/passwd", createSecretFile().toURI().toString());
156
157 PostMethod m = postToRestEndpoint(contents);
158
159 String resp = new String(ByteStreams.toByteArray(m.getResponseBodyAsStream()), "us-ascii");
160
161 MediaType mt = MediaType.valueOf(m.getResponseHeader("content-type").getValue());
162
163 assertEquals("The response should be XML",
164 "application/xml",
165 mt.getType() + '/' + mt.getSubtype()
166 );
167 assertThat(resp, CoreMatchers.not(JUnitMatchers.containsString(SECRET)));
168 }
169
170 @Test
171 public void testValidEntitiesAreExpanded() throws IOException {
172 InputStream in = getResourceAsStream("EntityTest-rest-with-amp-entity.xml", this.getClass());
173 assertNotNull(in);
174
175 String contents = new String(ByteStreams.toByteArray(in), "us-ascii");
176
177 PostMethod m = postToRestEndpoint(contents);
178
179 String resp = new String(ByteStreams.toByteArray(m.getResponseBodyAsStream()), "us-ascii");
180
181 MediaType mt = MediaType.valueOf(m.getResponseHeader("content-type").getValue());
182
183 assertEquals("The response should be XML",
184 "application/xml",
185 mt.getType() + '/' + mt.getSubtype()
186 );
187 assertThat(resp, JUnitMatchers.containsString("apple-&"));
188 }
189
190 @Test
191 public void testEntityExpansionDoesNotCauseDenialOfService() throws IOException {
192 InputStream in = getResourceAsStream("EntityTest-rest-billion-laughs.xml", this.getClass());
193 assertNotNull(in);
194
195 String contents = new String(ByteStreams.toByteArray(in), "us-ascii");
196
197 PostMethod m = postToRestEndpoint(contents);
198
199 String resp = new String(ByteStreams.toByteArray(m.getResponseBodyAsStream()), "us-ascii");
200
201
202
203
204
205 assertThat("The response should not indicate a server error",
206 m.getStatusCode(), Matchers.is(400));
207
208
209
210
211
212 assertThat("The response should not indicate a server memory error",
213 resp, CoreMatchers.not(JUnitMatchers.containsString("java.lang.OutOfMemoryError")));
214 }
215
216 @Test
217 public void fruitRetrievedAsXmlObeysJaxbAnnotations() {
218 final URI baseUri = UriBuilder.create().path("rest/entity/1/fruit/jackfruit").build();
219 final String returned = Client.create().resource(baseUri)
220 .accept(MediaType.APPLICATION_XML)
221 .get(String.class);
222
223 assertThat(returned, Matchers.containsString("<jackFruit jaxb-description=\""));
224 }
225
226 @Test
227 public void fruitRetrievedAsJsonObeysJacksonAnnotations() {
228 final URI baseUri = UriBuilder.create().path("rest/entity/1/fruit/jackfruit").build();
229 final String returned = Client.create().resource(baseUri)
230 .accept(MediaType.APPLICATION_JSON)
231 .get(String.class);
232
233 assertThat(returned, Matchers.startsWith("{\"json-description\":\"fresh at"));
234 }
235 }