]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
815a467e2721420afbf69704ebe978246a8938f1
[tmp/jakarta-migration.git] /
1 /**
2  * This document is a part of the source code and related artifacts
3  * for CollectionSpace, an open source collections management system
4  * for museums and related institutions:
5  *
6  * http://www.collectionspace.org
7  * http://wiki.collectionspace.org
8  *
9  * Copyright © 2009 Regents of the University of California
10  *
11  * Licensed under the Educational Community License (ECL), Version 2.0.
12  * You may not use this file except in compliance with this License.
13  *
14  * You may obtain a copy of the ECL 2.0 License at
15  *
16  * https://source.collectionspace.org/collection-space/LICENSE.txt
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 package org.collectionspace.services.client.test;
25
26 import java.io.IOException;
27 import java.io.UnsupportedEncodingException;
28 import java.util.ArrayList;
29 import javax.xml.bind.JAXBContext;
30 import javax.xml.bind.Marshaller;
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.MultivaluedMap;
33 import javax.ws.rs.core.Response;
34
35 import org.apache.commons.httpclient.Header;
36 import org.apache.commons.httpclient.HttpClient;
37 import org.apache.commons.httpclient.HttpException;
38 import org.apache.commons.httpclient.HttpMethod;
39 import org.apache.commons.httpclient.HttpStatus;
40 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
41 import org.apache.commons.httpclient.methods.GetMethod;
42 import org.apache.commons.httpclient.methods.PostMethod;
43 import org.apache.commons.httpclient.methods.PutMethod;
44 import org.apache.commons.httpclient.methods.RequestEntity;
45 import org.apache.commons.httpclient.methods.StringRequestEntity;
46
47 import org.collectionspace.services.client.TestServiceClient;
48 import org.collectionspace.services.client.test.ServiceRequestType;
49
50 import org.jboss.resteasy.client.ClientResponse;
51
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 /**
56  * AbstractServiceTest, abstract base class for the client tests to be performed
57  * to test an entity or relation service.
58  *
59  * For Javadoc descriptions of this class's methods, see the ServiceTest interface.
60  */
61 public abstract class AbstractServiceTest implements ServiceTest {
62
63     final Logger logger = LoggerFactory.getLogger(AbstractServiceTest.class);
64
65     private final TestServiceClient serviceClient = new TestServiceClient();
66     protected HttpClient httpClient = new HttpClient();
67
68     // The status code expected to be returned by a test method (where relevant).
69     int EXPECTED_STATUS_CODE = 0;
70     
71     // The generic type of service request being tested (e.g. CREATE, UPDATE, DELETE).
72     //
73     // This makes it possible to check behavior specific to that type of request,
74     // such as the set of valid status codes that may be returned.
75     ServiceRequestType REQUEST_TYPE = ServiceRequestType.NON_EXISTENT;
76
77
78     // ---------------------------------------------------------------
79     // CRUD tests : CREATE tests
80     // ---------------------------------------------------------------
81
82     // Success outcomes
83
84     @Override
85     public abstract void create();
86     
87     protected void setupCreate() {
88         clearSetup();
89         // Expected status code: 201 Created
90         EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode();
91         // Type of service request being tested
92         REQUEST_TYPE = ServiceRequestType.CREATE;
93     }
94
95     @Override
96     public abstract void createMultiple();
97     
98     // No setup required for createMultiple()
99
100     // Failure outcomes
101
102     @Override
103     public void createNull() {
104     }
105     
106     // No setup required for createNull()
107
108     @Override
109     public abstract void createWithMalformedXml();
110
111     protected void setupCreateWithMalformedXml() {
112         clearSetup();
113         // Expected status code: 400 Bad Request
114         EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
115         REQUEST_TYPE = ServiceRequestType.CREATE;
116     }
117
118     @Override
119     public abstract void createWithWrongXmlSchema();
120
121     protected void setupCreateWithWrongXmlSchema() {
122         clearSetup();
123         // Expected status code: 400 Bad Request
124         EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
125         REQUEST_TYPE = ServiceRequestType.CREATE;
126     }
127
128
129     // ---------------------------------------------------------------
130     // CRUD tests : READ tests
131     // ---------------------------------------------------------------
132
133     // Success outcomes
134     
135     @Override
136     public abstract void read();
137
138     protected void setupRead() {
139         clearSetup();
140         // Expected status code: 200 OK
141         EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
142         REQUEST_TYPE = ServiceRequestType.READ;
143     }
144
145     // Failure outcomes
146
147     @Override
148     public abstract void readNonExistent();
149
150     protected void setupReadNonExistent() {
151         clearSetup();
152         // Expected status code: 404 Not Found
153         EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode();
154         REQUEST_TYPE = ServiceRequestType.READ;
155     }
156
157
158     // ---------------------------------------------------------------
159     // CRUD tests : READ (list, or multiple) tests
160     // ---------------------------------------------------------------
161
162     // Success outcomes
163
164     @Override
165     public abstract void readList();
166
167     protected void setupReadList() {
168         clearSetup();
169         // Expected status code: 200 OK
170         EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
171         REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE;
172     }
173
174     // Failure outcomes
175
176     // None tested at present.
177
178
179     // ---------------------------------------------------------------
180     // CRUD tests : UPDATE tests
181     // ---------------------------------------------------------------
182
183     // Success outcomes
184     // ----------------
185
186     @Override
187     public abstract void update();
188
189     protected void setupUpdate() {
190         clearSetup();
191         // Expected status code: 200 OK
192         EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
193         REQUEST_TYPE = ServiceRequestType.UPDATE;
194     }
195
196     // Failure outcomes
197
198     @Override
199     public abstract void updateWithMalformedXml();
200
201     protected void setupUpdateWithMalformedXml() {
202         clearSetup();
203         // Expected status code: 400 Bad Request
204         EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
205         REQUEST_TYPE = ServiceRequestType.UPDATE;
206     }
207
208     @Override
209     public abstract void updateWithWrongXmlSchema();
210
211     protected void setupUpdateWithWrongXmlSchema() {
212         clearSetup();
213         // Expected status code: 400 Bad Request
214         EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
215         REQUEST_TYPE = ServiceRequestType.UPDATE;
216     }
217
218     @Override
219     public abstract void updateNonExistent();
220
221     protected void setupUpdateNonExistent() {
222         clearSetup();
223         // Expected status code: 404 Not Found
224         EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode();
225         REQUEST_TYPE = ServiceRequestType.UPDATE;
226     }
227
228
229     // ---------------------------------------------------------------
230     // CRUD tests : DELETE tests
231     // ---------------------------------------------------------------
232
233     // Success outcomes
234
235     @Override
236     public abstract void delete();
237     
238     protected void setupDelete() {
239         clearSetup();
240         // Expected status code: 200 OK
241         EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
242         REQUEST_TYPE = ServiceRequestType.DELETE;
243     }
244     
245     // Failure outcomes
246     
247     @Override
248     public abstract void deleteNonExistent();
249
250     protected void setupDeleteNonExistent() {
251         clearSetup();
252         // Expected status code: 404 Not Found
253         EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode();
254         REQUEST_TYPE = ServiceRequestType.DELETE;
255     }
256
257
258     // ---------------------------------------------------------------
259     // Abstract utility methods
260     //
261     // Must be implemented by classes that extend
262     // this abstract base class.
263     // ---------------------------------------------------------------
264
265     /**
266      * Returns the URL path component of the service.
267      *
268      * This component will follow directly after the
269      * base path, if any.
270      */
271     protected abstract String getServicePathComponent();
272
273
274     // ---------------------------------------------------------------
275     // Utility methods
276     // ---------------------------------------------------------------
277
278     /**
279      * Reinitializes setup values to guard against unintended reuse
280      * of those values.
281      */
282     protected void clearSetup() {
283         EXPECTED_STATUS_CODE = 0;
284         REQUEST_TYPE = ServiceRequestType.NON_EXISTENT;
285     }
286
287     // @TODO Add Javadoc comments to all methods requiring them, below.
288
289     protected String invalidStatusCodeMessage(ServiceRequestType requestType, int statusCode) {
290         return 
291             "Status code '" + statusCode + "' in response is NOT within the expected set: " +
292             requestType.validStatusCodesAsString();
293     }
294     
295     protected String getServiceRootURL() {
296         return serviceClient.getBaseURL() + getServicePathComponent();
297     }
298
299     protected String getResourceURL(String resourceIdentifier) {
300         return getServiceRootURL() + "/" + resourceIdentifier;
301     }
302
303     protected int submitRequest(HttpMethod method) {
304      int statusCode = 0;
305         try {
306             statusCode = httpClient.executeMethod(method);
307         } catch(HttpException e) {
308             logger.error("Fatal protocol violation: ", e);
309         } catch(IOException e) {
310             logger.error("Fatal transport error: ", e);
311         } catch(Exception e) {
312             logger.error("Unknown exception: ", e);
313         } finally {
314             // Release the connection.
315             method.releaseConnection();
316         }
317         return statusCode;
318     }
319     
320     protected int submitRequest(EntityEnclosingMethod method, RequestEntity entity) {
321         int statusCode = 0;
322         try {
323             method.setRequestEntity(entity);
324             statusCode = httpClient.executeMethod(method);
325         } catch(HttpException e) {
326             logger.error("Fatal protocol violation: ", e);
327         } catch(IOException e) {
328             logger.error("Fatal transport error: ", e);
329         } catch(Exception e) {
330             logger.error("Unknown exception: ", e);
331         } finally {
332             // Release the connection.
333             method.releaseConnection();
334         }
335         return statusCode;
336     }
337     
338     protected StringRequestEntity getXmlEntity(String contents) {
339         if (contents == null) {
340             contents = "";
341         }
342         StringRequestEntity entity = null;
343         final String XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
344         final String XML_CONTENT_TYPE=MediaType.APPLICATION_XML;
345         final String UTF8_CHARSET_NAME = "UTF-8";
346         try {
347             entity =
348                 new StringRequestEntity(XML_DECLARATION + contents, XML_CONTENT_TYPE, UTF8_CHARSET_NAME);
349         } catch (UnsupportedEncodingException e) {
350             logger.error("Unsupported character encoding error: ", e);
351         }
352         return entity;
353     }
354
355     protected String extractId(ClientResponse<Response> res) {
356         MultivaluedMap mvm = res.getMetadata();
357         String uri = (String) ((ArrayList) mvm.get("Location")).get(0);
358         verbose("extractId:uri=" + uri);
359         String[] segments = uri.split("/");
360         String id = segments[segments.length - 1];
361         verbose("id=" + id);
362         return id;
363     }
364
365     protected void verbose(String msg) {
366         if (logger.isDebugEnabled()) {
367             logger.debug(msg);
368         }
369     }
370
371     protected void verbose(String msg, Object o, Class clazz) {
372         try{
373             verbose(msg);
374             JAXBContext jc = JAXBContext.newInstance(clazz);
375             Marshaller m = jc.createMarshaller();
376             m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
377                     Boolean.TRUE);
378             m.marshal(o, System.out);
379         }catch(Exception e){
380             e.printStackTrace();
381         }
382     }
383
384     protected void verboseMap(MultivaluedMap map) {
385         for(Object entry : map.entrySet()){
386             MultivaluedMap.Entry mentry = (MultivaluedMap.Entry) entry;
387             verbose("    name=" + mentry.getKey() + " value=" + mentry.getValue());
388         }
389     }
390
391     protected String createIdentifier() {
392         long identifier = System.currentTimeMillis();
393         return Long.toString(identifier);
394     }
395
396     protected String createNonExistentIdentifier() {
397         return Long.toString(Long.MAX_VALUE);
398     }
399     
400 }
401
402