View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.testing.framework;
29  
30  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.BODY;
31  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.CONTENT_TYPE;
32  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.HEADERS;
33  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.METHOD;
34  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.NAME;
35  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.PATH;
36  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.QUERY;
37  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.REQUEST;
38  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.RESPONSE;
39  import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.STATUS;
40  import static org.hamcrest.MatcherAssert.assertThat;
41  
42  import java.util.HashMap;
43  import java.util.HashSet;
44  import java.util.Map;
45  import java.util.Set;
46  
47  import org.apache.hc.core5.http.ContentType;
48  import org.hamcrest.BaseMatcher;
49  import org.hamcrest.Description;
50  import org.hamcrest.Matcher;
51  import org.junit.jupiter.api.Assertions;
52  import org.junit.jupiter.api.Test;
53  import org.mockito.ArgumentMatchers;
54  import org.mockito.Mockito;
55  
56  public class TestTestingFramework {
57  
58      @Test
59      public void ensureDefaultMapsUnmodifiable() throws Exception {
60          assertUnmodifiable(TestingFramework.DEFAULT_REQUEST_QUERY);
61          assertUnmodifiable(TestingFramework.DEFAULT_RESPONSE_HEADERS);
62      }
63  
64      private void assertUnmodifiable(final Map<String, String> map) {
65          final String aKey = (String) map.keySet().toArray()[0];
66          Assertions.assertThrows(UnsupportedOperationException.class, () -> map.remove(aKey));
67      }
68  
69      private TestingFramework newWebServerTestingFramework(final ClientTestingAdapter adapter)
70              throws TestingFrameworkException {
71          final TestingFramework framework = new TestingFramework(adapter);
72          // get rid of the default tests.
73          framework.deleteTests();
74  
75          return framework;
76      }
77  
78      private TestingFramework newWebServerTestingFramework() throws TestingFrameworkException {
79          return newWebServerTestingFramework(null); // null adapter
80      }
81  
82      @Test
83      public void runTestsWithoutSettingAdapterThrows() throws Exception {
84          final TestingFramework framework = newWebServerTestingFramework();
85          Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
86      }
87  
88      @Test
89      public void nullAdapterThrows() throws Exception {
90          final ClientTestingAdapter adapter = null;
91  
92          final TestingFramework framework = newWebServerTestingFramework(adapter);
93          Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
94      }
95  
96      @Test
97      public void nullSetAdapterThrows() throws Exception {
98          final ClientTestingAdapter adapter = null;
99  
100         final TestingFramework framework = newWebServerTestingFramework(adapter);
101         framework.setAdapter(adapter);
102         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
103     }
104 
105     @Test
106     public void goodAdapterWithConstructor() throws Exception {
107         final ClientTestingAdapter adapter = Mockito.mock(ClientTestingAdapter.class);
108 
109         // Have isRequestSupported() return false so no test will run.
110         Mockito.when(adapter.isRequestSupported(ArgumentMatchers.anyMap()))
111                      .thenReturn(false);
112 
113         final TestingFramework framework = newWebServerTestingFramework(adapter);
114 
115         framework.runTests();
116 
117         // since there are no tests, callMethod should not be called.
118         verifyCallMethodNeverCalled(adapter);
119     }
120 
121     private void verifyCallMethodNeverCalled(final ClientTestingAdapter adapter) throws Exception {
122         Mockito.verify(adapter, Mockito.never()).execute(ArgumentMatchers.anyString(), ArgumentMatchers.anyMap(),
123                        ArgumentMatchers.any(TestingFrameworkRequestHandler.class), ArgumentMatchers.anyMap());
124     }
125 
126     private TestingFramework newFrameworkAndSetAdapter(final ClientTestingAdapter adapter)
127             throws TestingFrameworkException {
128         final TestingFramework framework = new TestingFramework();
129         framework.setAdapter(adapter);
130 
131         // get rid of the default tests.
132         framework.deleteTests();
133 
134         return framework;
135     }
136 
137     @Test
138     public void goodAdapterWithSetter() throws Exception {
139         final ClientTestingAdapter adapter = Mockito.mock(ClientTestingAdapter.class);
140 
141         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
142 
143         framework.runTests();
144 
145         // since there are no tests, callMethod should not be called.
146         verifyCallMethodNeverCalled(adapter);
147     }
148 
149     @Test
150     public void addTest() throws Exception {
151         final TestingFrameworkRequestHandler mockRequestHandler = Mockito.mock(TestingFrameworkRequestHandler.class);
152 
153         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
154             @Override
155             public Map<String, Object> execute(
156                                    final String defaultURI,
157                                    final Map<String, Object> request,
158                                    final TestingFrameworkRequestHandler requestHandler,
159                                    final Map<String, Object> responseExpectations) throws TestingFrameworkException {
160                 assertThat(defaultURI, matchesDefaultURI());
161 
162                 Assertions.assertNotNull(request, "request should not be null");
163 
164                 // The request should be equal to the default request.
165                 final Map<String, Object> defaultRequest = new FrameworkTest().initRequest();
166                 Assertions.assertEquals(defaultRequest, request, "The request does not match the default");
167 
168                 Assertions.assertSame(mockRequestHandler, requestHandler, "The request handler should have been passed to the adapter");
169 
170                 // The responseExpectations should be equal to the default.
171                 final Map<String, Object> defaultResponseExpectations = new FrameworkTest().initResponseExpectations();
172                 Assertions.assertEquals(defaultResponseExpectations, responseExpectations, "The responseExpectations do not match the defaults");
173 
174                 final Map<String, Object> response = new HashMap<>();
175                 response.put(STATUS, responseExpectations.get(STATUS));
176                 response.put(BODY, responseExpectations.get(BODY));
177                 response.put(CONTENT_TYPE, responseExpectations.get(CONTENT_TYPE));
178                 response.put(HEADERS, responseExpectations.get(HEADERS));
179                 return response;
180             }
181         };
182 
183         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
184         framework.setRequestHandler(mockRequestHandler);
185 
186         framework.addTest();
187 
188         framework.runTests();
189 
190         // assertNothingThrown() should have been called.
191         Mockito.verify(mockRequestHandler).assertNothingThrown();
192     }
193 
194     private Matcher<String> matchesDefaultURI() {
195         final Matcher<String> matcher = new BaseMatcher<String>() {
196             private final String regex = "http://localhost:\\d+/";
197 
198             @Override
199             public boolean matches(final Object o) {
200                 return ((String) o).matches(regex);
201             }
202 
203             @Override
204             public void describeTo(final Description description) {
205                 description.appendText("matches regex=" + regex);
206             }
207         };
208 
209         return matcher;
210     }
211 
212     @Test
213     public void statusCheck() throws Exception {
214         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
215             @Override
216             public Map<String, Object> execute(
217                                    final String defaultURI,
218                                    final Map<String, Object> request,
219                                    final TestingFrameworkRequestHandler requestHandler,
220                                    final Map<String, Object> responseExpectations) {
221 
222                 Assertions.assertEquals(200, responseExpectations.get(STATUS));
223 
224                 // return a different status than expected.
225                 final Map<String, Object> response = new HashMap<>();
226                 response.put(STATUS, 201);
227                 return response;
228             }
229         };
230 
231         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
232 
233         framework.addTest();
234 
235         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
236     }
237 
238     private Map<String, Object> alreadyCheckedResponse() {
239         // return an indication that the response has already been checked.
240         final Map<String, Object> response = new HashMap<>();
241         response.put(STATUS, TestingFramework.ALREADY_CHECKED);
242         response.put(BODY, TestingFramework.ALREADY_CHECKED);
243         response.put(CONTENT_TYPE, TestingFramework.ALREADY_CHECKED);
244         response.put(HEADERS, TestingFramework.ALREADY_CHECKED);
245         return response;
246     }
247 
248     @Test
249     public void responseAlreadyChecked() throws Exception {
250             final ClientTestingAdapter adapter = new ClientTestingAdapter() {
251             @Override
252             public Map<String, Object> execute(
253                                    final String defaultURI,
254                                    final Map<String, Object> request,
255                                    final TestingFrameworkRequestHandler requestHandler,
256                                    final Map<String, Object> responseExpectations) {
257 
258                 return alreadyCheckedResponse();
259             }
260         };
261 
262         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
263 
264         framework.addTest();
265 
266         framework.runTests();
267     }
268 
269     @Test
270     public void bodyCheck() throws Exception {
271         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
272             @Override
273             public Map<String, Object> execute(
274                                    final String defaultURI,
275                                    final Map<String, Object> request,
276                                    final TestingFrameworkRequestHandler requestHandler,
277                                    final Map<String, Object> responseExpectations) {
278 
279                 Assertions.assertEquals(TestingFramework.DEFAULT_RESPONSE_BODY, responseExpectations.get(BODY));
280 
281                 final Map<String, Object> response = new HashMap<>();
282                 response.put(STATUS, TestingFramework.ALREADY_CHECKED);
283 
284                 // return a different body than expected.
285                 response.put(BODY, TestingFramework.DEFAULT_RESPONSE_BODY + "junk");
286                 return response;
287             }
288         };
289 
290         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
291 
292         framework.addTest();
293 
294         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
295     }
296 
297     @Test
298     public void responseContentTypeCheck() throws Exception {
299        final ClientTestingAdapter adapter = new ClientTestingAdapter() {
300             @Override
301             public Map<String, Object> execute(
302                                    final String defaultURI,
303                                    final Map<String, Object> request,
304                                    final TestingFrameworkRequestHandler requestHandler,
305                                    final Map<String, Object> responseExpectations) {
306 
307                 Assertions.assertEquals(TestingFramework.DEFAULT_RESPONSE_CONTENT_TYPE, responseExpectations.get(CONTENT_TYPE));
308 
309                 final Map<String, Object> response = new HashMap<>();
310                 response.put(STATUS, TestingFramework.ALREADY_CHECKED);
311                 response.put(HEADERS, TestingFramework.ALREADY_CHECKED);
312 
313                 // return the expected body
314                 response.put(BODY, TestingFramework.DEFAULT_RESPONSE_BODY);
315                 // return a different content type than expected.
316                 response.put(CONTENT_TYPE, ContentType.DEFAULT_TEXT);
317                 return response;
318             }
319         };
320 
321         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
322 
323         framework.addTest();
324 
325         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
326     }
327 
328     @Test
329     public void deepcopy() throws Exception {
330         // save a copy of the headers to make sure they haven't changed at the end of this test.
331         @SuppressWarnings("unchecked")
332         final Map<String, String> headersCopy = (Map<String, String>) TestingFramework.deepcopy(TestingFramework.DEFAULT_RESPONSE_HEADERS);
333         Assertions.assertEquals(TestingFramework.DEFAULT_RESPONSE_HEADERS, headersCopy);
334 
335         final Map<String, Object> deepMap = new HashMap<>();
336         deepMap.put(HEADERS, TestingFramework.DEFAULT_RESPONSE_HEADERS);
337 
338         @SuppressWarnings("unchecked")
339         final Map<String, Object> deepMapCopy = (Map<String, Object>) TestingFramework.deepcopy(deepMap);
340         Assertions.assertEquals(deepMap, deepMapCopy);
341 
342         @SuppressWarnings("unchecked")
343         final Map<String, String> headersMap = (Map<String, String>) deepMapCopy.get(HEADERS);
344         Assertions.assertEquals(headersCopy, headersMap);
345 
346         // now make sure the default headers have not changed for some unexpected reason.
347         Assertions.assertEquals(TestingFramework.DEFAULT_RESPONSE_HEADERS, headersCopy);
348     }
349 
350     @Test
351     public void removedHeaderCheck() throws Exception {
352         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
353             @Override
354             public Map<String, Object> execute(
355                                    final String defaultURI,
356                                    final Map<String, Object> request,
357                                    final TestingFrameworkRequestHandler requestHandler,
358                                    final Map<String, Object> responseExpectations) {
359 
360                 Assertions.assertEquals(TestingFramework.DEFAULT_RESPONSE_HEADERS, responseExpectations.get(HEADERS));
361 
362                 @SuppressWarnings("unchecked")
363                 final Map<String, String> headersCopy = (Map<String, String>) deepcopy(responseExpectations.get(HEADERS));
364 
365                 // remove a header to force an error
366                 final String headerName = (String) headersCopy.keySet().toArray()[0];
367                 headersCopy.remove(headerName);
368 
369                 final Map<String, Object> response = new HashMap<>();
370                 response.put(STATUS, TestingFramework.ALREADY_CHECKED);
371                 response.put(BODY, TestingFramework.ALREADY_CHECKED);
372 
373                 // return different headers than expected.
374                 response.put(HEADERS, headersCopy);
375                 return response;
376             }
377         };
378 
379         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
380 
381         framework.addTest();
382 
383         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
384     }
385 
386     @Test
387     public void changedHeaderCheck() throws Exception {
388         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
389             @Override
390             public Map<String, Object> execute(
391                                    final String defaultURI,
392                                    final Map<String, Object> request,
393                                    final TestingFrameworkRequestHandler requestHandler,
394                                    final Map<String, Object> responseExpectations) {
395 
396                 Assertions.assertEquals(TestingFramework.DEFAULT_RESPONSE_HEADERS, responseExpectations.get(HEADERS));
397 
398                 @SuppressWarnings("unchecked")
399                 final Map<String, String> headersCopy = (Map<String, String>) deepcopy(responseExpectations.get(HEADERS));
400 
401                 // change a header to force an error
402                 final String headerName = (String) headersCopy.keySet().toArray()[0];
403                 headersCopy.put(headerName, headersCopy.get(headerName) + "junk");
404 
405                 final Map<String, Object> response = new HashMap<>();
406                 response.put(STATUS, TestingFramework.ALREADY_CHECKED);
407                 response.put(BODY, TestingFramework.ALREADY_CHECKED);
408 
409                 // return different headers than expected.
410                 response.put(HEADERS, headersCopy);
411                 return response;
412             }
413         };
414 
415         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
416 
417         framework.addTest();
418 
419         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
420     }
421 
422     private Object deepcopy(final Object obj) {
423         try {
424             return TestingFramework.deepcopy(obj);
425         } catch (final Exception e) {
426             Assertions.fail("deepcopy failed: " + e.getMessage());
427             return null;
428         }
429     }
430 
431     @Test
432     public void requestMethodUnexpected() throws Exception {
433         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
434             @Override
435             public Map<String, Object> execute(
436                     final String defaultURI,
437                     final Map<String, Object> request,
438                     final TestingFrameworkRequestHandler requestHandler,
439                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
440                 // change the request from what is expected.
441                 Assertions.assertEquals("GET", request.get(METHOD));
442                 request.put(METHOD, "POST");
443                 return super.execute(defaultURI, request, requestHandler, responseExpectations);
444             }
445         };
446 
447         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
448 
449         final Map<String, Object> test = new HashMap<>();
450         final Map<String, Object> request = new HashMap<>();
451         test.put(REQUEST, request);
452         request.put(NAME, "MyName");
453 
454         framework.addTest(test);
455 
456         final TestingFrameworkException exception = Assertions.assertThrows(TestingFrameworkException.class, () ->
457                 framework.runTests());
458         // make sure the HTTP Client name is in the message.
459         final String message = exception.getMessage();
460         final ClientPOJOAdapter pojoAdapter = adapter.getClientPOJOAdapter();
461         final String httpClientName = pojoAdapter == null ?
462                 TestingFrameworkException.NO_HTTP_CLIENT :
463                 pojoAdapter.getClientName();
464         Assertions.assertTrue(message.contains(httpClientName), "Message should contain httpClientName of " + httpClientName + "; message=" + message);
465 
466         Assertions.assertTrue(message.contains("MyName"), "Message should contain the test. message=" + message);
467     }
468 
469     @Test
470     public void status201() throws Exception {
471         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter();
472 
473         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
474 
475         final Map<String, Object> test = new HashMap<>();
476         final Map<String, Object> response = new HashMap<>();
477         test.put(RESPONSE, response);
478         response.put(STATUS, 201);
479 
480         framework.addTest(test);
481 
482         framework.runTests();
483     }
484 
485     @Test
486     public void deepcopyOfTest() throws Exception {
487         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
488 
489             @Override
490             public Map<String, Object> execute(
491                     final String defaultURI,
492                     final Map<String, Object> request,
493                     final TestingFrameworkRequestHandler requestHandler,
494                     final Map<String, Object> responseExpectations)
495                        throws TestingFrameworkException {
496                 Assertions.assertEquals(201, responseExpectations.get(STATUS));
497                 return alreadyCheckedResponse();
498             }
499         };
500 
501         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
502 
503         final Map<String, Object> test = new HashMap<>();
504         final Map<String, Object> response = new HashMap<>();
505         test.put(RESPONSE, response);
506         response.put(STATUS, 201);
507 
508         framework.addTest(test);
509 
510         // Make sure the framework makes a copy of the test for itself.
511         // This put should be ignored by the framework.
512         response.put(STATUS, 300);
513 
514         framework.runTests();
515     }
516 
517     @Test
518     public void removeParameter() throws Exception {
519         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
520             @Override
521             public Map<String, Object> execute(
522                     final String defaultURI,
523                     final Map<String, Object> request,
524                     final TestingFrameworkRequestHandler requestHandler,
525                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
526                 // change the request from what is expected.
527                 @SuppressWarnings("unchecked")
528                 final Map<String, String> query = (Map<String, String>) request.get(QUERY);
529                 Assertions.assertTrue(query.containsKey("p1"));
530                 query.remove("p1");
531                 return super.execute(defaultURI, request, requestHandler, responseExpectations);
532             }
533         };
534 
535         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
536 
537         framework.addTest();
538 
539         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
540     }
541 
542     @Test
543     public void changeParameter() throws Exception {
544         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
545             @Override
546             public Map<String, Object> execute(
547                     final String defaultURI,
548                     final Map<String, Object> request,
549                     final TestingFrameworkRequestHandler requestHandler,
550                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
551                 // change the request from what is expected.
552                 @SuppressWarnings("unchecked")
553                 final Map<String, String> query = (Map<String, String>) request.get(QUERY);
554                 Assertions.assertTrue(query.containsKey("p1"));
555                 query.put("p1", query.get("p1") + "junk");
556                 return super.execute(defaultURI, request, requestHandler, responseExpectations);
557             }
558         };
559 
560         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
561 
562         framework.addTest();
563 
564         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
565     }
566 
567     @Test
568     public void removeHeader() throws Exception {
569         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
570             @Override
571             public Map<String, Object> execute(
572                     final String defaultURI,
573                     final Map<String, Object> request,
574                     final TestingFrameworkRequestHandler requestHandler,
575                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
576                 // change the request from what is expected.
577                 @SuppressWarnings("unchecked")
578                 final Map<String, String> headers = (Map<String, String>) request.get(HEADERS);
579                 Assertions.assertTrue(headers.containsKey("header1"));
580                 headers.remove("header1");
581                 return super.execute(defaultURI, request, requestHandler, responseExpectations);
582             }
583         };
584 
585         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
586 
587         framework.addTest();
588 
589         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
590     }
591 
592     @Test
593     public void changeHeader() throws Exception {
594         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
595             @Override
596             public Map<String, Object> execute(
597                     final String defaultURI,
598                     final Map<String, Object> request,
599                     final TestingFrameworkRequestHandler requestHandler,
600                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
601                 // change the request from what is expected.
602                 @SuppressWarnings("unchecked")
603                 final Map<String, String> headers = (Map<String, String>) request.get(HEADERS);
604                 Assertions.assertTrue(headers.containsKey("header1"));
605                 headers.put("header1", headers.get("header1") + "junk");
606                 return super.execute(defaultURI, request, requestHandler, responseExpectations);
607             }
608         };
609 
610         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
611 
612         framework.addTest();
613 
614         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
615     }
616 
617     @Test
618     public void changeBody() throws Exception {
619         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
620             @Override
621             public Map<String, Object> execute(
622                     final String defaultURI,
623                     final Map<String, Object> request,
624                     final TestingFrameworkRequestHandler requestHandler,
625                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
626                 // change the request from what is expected.
627                 final String body = (String) request.get(BODY);
628                 Assertions.assertNotNull(body);
629                 request.put(BODY, request.get(BODY) + "junk");
630                 return super.execute(defaultURI, request, requestHandler, responseExpectations);
631             }
632         };
633 
634         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
635 
636         framework.addTest();
637 
638         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
639     }
640 
641     @Test
642     public void changeContentType() throws Exception {
643         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
644             @Override
645             public Map<String, Object> execute(
646                     final String defaultURI,
647                     final Map<String, Object> request,
648                     final TestingFrameworkRequestHandler requestHandler,
649                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
650                 // change the request from what is expected.
651                 final String contentType = (String) request.get(CONTENT_TYPE);
652                 Assertions.assertNotNull(contentType);
653                 request.put(CONTENT_TYPE, request.get(CONTENT_TYPE) + "junk");
654                 return super.execute(defaultURI, request, requestHandler, responseExpectations);
655             }
656         };
657 
658         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
659 
660         framework.addTest();
661 
662         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
663     }
664 
665     @Test
666     public void changeResponseExpectationsFails() throws Exception {
667         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
668             @Override
669             public Map<String, Object> execute(
670                     final String defaultURI,
671                     final Map<String, Object> request,
672                     final TestingFrameworkRequestHandler requestHandler,
673                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
674 
675                 /*
676                  * The adapter should change the responseExpectations in the modifyResponseExpectations()
677                  * method before they are sent to the request handler.  The expectations should not
678                  * be changed here.
679                  */
680                 // the next command should throw.
681                 responseExpectations.put(STATUS, 201);
682                 return null;
683             }
684         };
685 
686         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
687 
688         framework.addTest();
689 
690         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
691     }
692 
693     @Test
694     public void changeResponseStatus() throws Exception {
695         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
696             @Override
697             public Map<String, Object> execute(
698                     final String defaultURI,
699                     final Map<String, Object> request,
700                     final TestingFrameworkRequestHandler requestHandler,
701                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
702                 // change the responseExpectations from what is expected.  The change should be ignored
703                 // by the request handler, and a 200 should actually be returned.
704                 Assertions.assertEquals(200, responseExpectations.get(STATUS));
705 
706                 // The next line is needed because we have to make a copy of the responseExpectations.
707                 // It is an unmodifiable map.
708                 final Map<String, Object> tempResponseExpectations = new HashMap<>(responseExpectations);
709                 tempResponseExpectations.put(STATUS, 201);
710                 final Map<String, Object> response = super.execute(defaultURI, request, requestHandler, tempResponseExpectations);
711                 Assertions.assertEquals(200,  response.get(STATUS));
712 
713                 return response;
714             }
715         };
716 
717         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
718 
719         framework.addTest();
720 
721         framework.runTests();
722     }
723 
724     @Test
725     public void modifyRequestCalled() throws Exception {
726         final TestingFrameworkRequestHandler mockRequestHandler = Mockito.mock(TestingFrameworkRequestHandler.class);
727         final String UNLIKELY_ITEM = "something_unlikely_to_be_in_a_real_request";
728 
729         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
730             @Override
731             public Map<String, Object> execute(
732                                    final String defaultURI,
733                                    final Map<String, Object> request,
734                                    final TestingFrameworkRequestHandler requestHandler,
735                                    final Map<String, Object> responseExpectations) throws TestingFrameworkException {
736                 // make sure the modifyRequest method was called by seeing if the request was modified.
737                 Assertions.assertTrue(request.containsKey(UNLIKELY_ITEM), "modifyRequest should have been called.");
738 
739                 final Map<String, Object> response = new HashMap<>();
740                 response.put(STATUS, responseExpectations.get(STATUS));
741                 response.put(BODY, responseExpectations.get(BODY));
742                 response.put(CONTENT_TYPE, responseExpectations.get(CONTENT_TYPE));
743                 response.put(HEADERS, responseExpectations.get(HEADERS));
744                 return response;
745             }
746 
747             @Override
748             public Map<String, Object> modifyRequest(final Map<String, Object> request) {
749                 // let the adapter change the request if needed.
750                 request.put(UNLIKELY_ITEM, new Object());
751                 return super.modifyRequest(request);
752             }
753         };
754 
755         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
756         framework.setRequestHandler(mockRequestHandler);
757 
758         framework.addTest();
759 
760         framework.runTests();
761 
762         // assertNothingThrown() should have been called.
763         Mockito.verify(mockRequestHandler).assertNothingThrown();
764     }
765 
766     @Test
767     public void modifyResponseExpectationsCalled() throws Exception {
768         final TestingFrameworkRequestHandler mockRequestHandler = Mockito.mock(TestingFrameworkRequestHandler.class);
769         final String UNLIKELY_ITEM = "something_unlikely_to_be_in_a_real_response";
770 
771         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
772             @Override
773             public Map<String, Object> execute(
774                                    final String defaultURI,
775                                    final Map<String, Object> request,
776                                    final TestingFrameworkRequestHandler requestHandler,
777                                    final Map<String, Object> responseExpectations) throws TestingFrameworkException {
778                 // make sure the modifyRequest method was called by seeing if the request was modified.
779                 Assertions.assertTrue(responseExpectations.containsKey(UNLIKELY_ITEM), "modifyResponseExpectations should have been called.");
780 
781                 final Map<String, Object> response = new HashMap<>();
782                 response.put(STATUS, responseExpectations.get(STATUS));
783                 response.put(BODY, responseExpectations.get(BODY));
784                 response.put(CONTENT_TYPE, responseExpectations.get(CONTENT_TYPE));
785                 response.put(HEADERS, responseExpectations.get(HEADERS));
786                 return response;
787             }
788 
789             @Override
790             public Map<String, Object> modifyResponseExpectations(
791                     final Map<String, Object> request,
792                     final Map<String, Object> responseExpectations) {
793                 // let the adapter change the request if needed.
794                 responseExpectations.put(UNLIKELY_ITEM, new Object());
795                 return super.modifyResponseExpectations(request, responseExpectations);
796             }
797         };
798 
799         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
800         framework.setRequestHandler(mockRequestHandler);
801 
802         framework.addTest();
803 
804         framework.runTests();
805 
806         // assertNothingThrown() should have been called.
807         Mockito.verify(mockRequestHandler).assertNothingThrown();
808     }
809 
810     @Test
811     public void adapterDoesNotSupport() throws Exception {
812 
813         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
814             @Override
815             public Map<String, Object> execute(
816                                    final String defaultURI,
817                                    final Map<String, Object> request,
818                                    final TestingFrameworkRequestHandler requestHandler,
819                                    final Map<String, Object> responseExpectations) throws TestingFrameworkException {
820 
821                 Assertions.fail("callMethod should not have been called");
822                 return null;
823             }
824 
825             @Override
826             public boolean isRequestSupported(final Map<String, Object> request) {
827                 return false;
828             }
829         };
830 
831         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
832 
833         framework.addTest();
834 
835         framework.runTests();
836     }
837 
838     @Test
839     public void defaultTestsWithMockedAdapter() throws Exception {
840         final Set<String> calledMethodSet = new HashSet<>();
841 
842         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
843             @Override
844             public Map<String, Object> execute(
845                                    final String defaultURI,
846                                    final Map<String, Object> request,
847                                    final TestingFrameworkRequestHandler requestHandler,
848                                    final Map<String, Object> responseExpectations) throws TestingFrameworkException {
849 
850                 calledMethodSet.add((String) request.get(METHOD));
851                 return alreadyCheckedResponse();
852             }
853         };
854 
855         // create the framework without deleting the default tests.
856         final TestingFramework framework = new TestingFramework();
857         framework.setAdapter(adapter);
858 
859         framework.runTests();
860 
861         for (final String method : TestingFramework.ALL_METHODS) {
862             Assertions.assertTrue(calledMethodSet.contains(method), "Method not in default tests.  method=" + method);
863         }
864     }
865 
866     @Test
867     public void defaultTests() throws Exception {
868         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter();
869 
870         // create the framework without deleting the default tests.
871         final TestingFramework framework = new TestingFramework();
872         framework.setAdapter(adapter);
873 
874         framework.runTests();
875 
876     }
877 
878     @Test
879     public void addTestNoMocks() throws TestingFrameworkException {
880 
881         final TestingFramework framework = new TestingFramework(new ClassicTestClientTestingAdapter());
882 
883 //      The following test could be constructed in Groovy/Spock like this:
884 //
885 //      HttpServerTestingFramework.ALL_METHODS.each { method ->
886 //          framework.addTest(
887 //                              request: [
888 //                                  path: '/stuff',
889 //                                  method:method,
890 //                                  query: [param : 'something'],
891 //                                  headers: [header1:'stuff', header2:'more-stuff'],
892 //                                  contentType: 'text/plain; charset=us-ascii',
893 //                                  body: 'What is the meaning of life?',
894 //                              ],
895 //                              response: [
896 //                                  status:201,
897 //                                  headers: [header3:'header_stuff',],
898 //                                  contentType: 'text/html; charset=us-ascii',
899 //                                  body: responseBody,
900 //                              ],
901 //          )
902 
903         final Map<String, Object> test = new HashMap<>();
904 
905         // Add request.
906         final Map<String, Object> request = new HashMap<>();
907         test.put(REQUEST, request);
908 
909         request.put(PATH, "stuff");
910 
911         final Map<String, Object> queryMap = new HashMap<>();
912         request.put(QUERY, queryMap);
913 
914         queryMap.put("param", "something");
915 
916         final Map<String, Object> requestHeadersMap = new HashMap<>();
917         request.put(HEADERS, requestHeadersMap);
918 
919         requestHeadersMap.put("header1", "stuff");
920         requestHeadersMap.put("header2", "more-stuff");
921 
922         request.put(CONTENT_TYPE, "text/plain; charset=us-ascii");
923         request.put(BODY, "What is the meaning of life?");
924 
925         // Response
926         final Map<String, Object> response = new HashMap<>();
927         test.put(RESPONSE, response);
928 
929         response.put(STATUS, 201);
930 
931         final Map<String, Object> responseHeadersMap = new HashMap<>();
932         response.put(HEADERS, responseHeadersMap);
933 
934         responseHeadersMap.put("header3", "header_stuff");
935 
936         response.put(CONTENT_TYPE, "text/html; charset=us-ascii");
937         response.put(BODY, "<HTML>42</HTML>");
938 
939         for (final String method : TestingFramework.ALL_METHODS) {
940             request.put(METHOD, method);
941 
942             framework.addTest(test);
943         }
944         framework.runTests();
945     }
946 
947     @Test
948     public void nulls() throws TestingFrameworkException {
949 
950         final TestingFramework framework = new TestingFramework(new ClassicTestClientTestingAdapter());
951 
952 //      The following test could be constructed in Groovy/Spock like this:
953 //
954 //      WebServerTestingFramework.ALL_METHODS.each { method ->
955 //           framework.addTest(
956 //                              request: [
957 //                                  path: null,
958 //                                  method:method,
959 //                                  query: null,
960 //                                  headers: null,
961 //                                  contentType: null,
962 //                                  body: null,
963 //                              ],
964 //                              response: [
965 //                                  status:null,
966 //                                  headers: null,
967 //                                  contentType: null,
968 //                                  body: null,
969 //                              ],
970 //          )
971 
972         final Map<String, Object> test = new HashMap<>();
973 
974         // Add request.
975         final Map<String, Object> request = new HashMap<>();
976         test.put(REQUEST, request);
977 
978         request.put(PATH, null);
979 
980         request.put(QUERY, null);
981 
982 
983         request.put(HEADERS, null);
984 
985         request.put(CONTENT_TYPE, null);
986         request.put(BODY, null);
987 
988         // Response
989         final Map<String, Object> response = new HashMap<>();
990         test.put(RESPONSE, response);
991 
992         response.put(STATUS, null);
993 
994         response.put(HEADERS, null);
995 
996         response.put(CONTENT_TYPE, null);
997         response.put(BODY, null);
998 
999         for (final String method : TestingFramework.ALL_METHODS) {
1000             request.put(METHOD, method);
1001 
1002             framework.addTest(test);
1003         }
1004         framework.runTests();
1005     }
1006 
1007     @Test
1008     public void parameterInPath() throws Exception {
1009         final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
1010             @Override
1011             public Map<String, Object> execute(final String defaultURI, final Map<String, Object> request,
1012                     final TestingFrameworkRequestHandler requestHandler,
1013                     final Map<String, Object> responseExpectations) throws TestingFrameworkException {
1014                 @SuppressWarnings("unchecked")
1015                 final Map<String, String> query = (Map<String, String>) request.get(QUERY);
1016                 Assertions.assertTrue(query.containsKey("stuffParm"), "Parameters appended to the path should have been put in the query.");
1017 
1018                 Assertions.assertTrue(query.containsKey("stuffParm2"));
1019                 Assertions.assertEquals("stuff", query.get("stuffParm"));
1020                 Assertions.assertEquals("stuff2", query.get("stuffParm2"));
1021 
1022                 Assertions.assertEquals("/stuff", request.get(PATH));
1023                 return alreadyCheckedResponse();
1024             }
1025         };
1026 
1027         final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
1028 
1029         final Map<String, Object> test = new HashMap<>();
1030 
1031         // Add request.
1032         final Map<String, Object> request = new HashMap<>();
1033         test.put(REQUEST, request);
1034 
1035         request.put(PATH, "/stuff?stuffParm=stuff&stuffParm2=stuff2");
1036 
1037         framework.addTest(test);
1038 
1039         framework.runTests();
1040     }
1041 
1042 }