|
6 | 6 | package com.gooddata.sdk.service; |
7 | 7 |
|
8 | 8 | import com.gooddata.sdk.common.GoodDataRestException; |
| 9 | + |
9 | 10 | import org.springframework.web.client.RestTemplate; |
10 | 11 | import org.testng.annotations.BeforeMethod; |
11 | 12 | import org.testng.annotations.Test; |
|
14 | 15 |
|
15 | 16 | public class PollHandlerIT extends AbstractGoodDataIT { |
16 | 17 |
|
| 18 | + // Test case 1: Complex base64-like string with multiple encoded chars (original test) |
17 | 19 | private static final String PATH = "/foo"; |
18 | 20 | private static final String PARAM = "q"; |
19 | 21 | private static final String VALUE = "eAEdizEOgCAQBL9CtraBwsLOR1gZC5QzuUROA2csiH8X7DYzswXKehAGTPKvYBJdZ1ITaGdh5VPQ%0AIZIm3jKGuUB8bP34%2BERCOVfNoQLbO%2BvwLh281nq9ldpheT%2FgtSHo%0A"; |
20 | 22 | private static final String URI = PATH + "?" + PARAM + "=" + VALUE; |
21 | 23 |
|
| 24 | + // Test case 2: String with only %2B (plus signs) |
| 25 | + private static final String VALUE_PLUS_ONLY = "hello%2Bworld%2Btest"; |
| 26 | + private static final String URI_PLUS_ONLY = PATH + "?" + PARAM + "=" + VALUE_PLUS_ONLY; |
| 27 | + |
| 28 | + // Test case 3: String with only %2F (forward slashes) |
| 29 | + private static final String VALUE_SLASH_ONLY = "path%2Fto%2Ffile"; |
| 30 | + private static final String URI_SLASH_ONLY = PATH + "?" + PARAM + "=" + VALUE_SLASH_ONLY; |
| 31 | + |
| 32 | + // Test case 4: String with %2B and %2F but no other encoded chars |
| 33 | + private static final String VALUE_PLUS_SLASH = "api%2Fv1%2Busers%2Fdata"; |
| 34 | + private static final String URI_PLUS_SLASH = PATH + "?" + PARAM + "=" + VALUE_PLUS_SLASH; |
| 35 | + |
| 36 | + // Test case 5: Mixed characters - some decoded (%3D→=), some not (%0A, %20) |
| 37 | + private static final String VALUE_MIXED_DECODE = "line1%0Aline2%20space%3Dequals"; |
| 38 | + private static final String URI_MIXED_DECODE = PATH + "?" + PARAM + "=" + VALUE_MIXED_DECODE; |
| 39 | + |
| 40 | + // Test case 6: Plus symbol behavior investigation (+, %2B, %20) |
| 41 | + private static final String VALUE_PLUS_SPACE_TEST = "word1+word2%20word3%2Bword4"; |
| 42 | + private static final String URI_PLUS_SPACE_TEST = PATH + "?" + PARAM + "=" + VALUE_PLUS_SPACE_TEST; |
| 43 | + |
| 44 | + // Test case 7: Special characters that may behave differently (%26, %3F, %23) |
| 45 | + private static final String VALUE_SPECIAL_CHARS = "param%26value%3Ftest%23anchor"; |
| 46 | + private static final String URI_SPECIAL_CHARS = PATH + "?" + PARAM + "=" + VALUE_SPECIAL_CHARS; |
| 47 | + |
| 48 | + // Test case 8: Path separators and dots (%2E, %2F, %5C) |
| 49 | + private static final String VALUE_PATH_CHARS = "path%2Fto%2Efile%5Cbackslash"; |
| 50 | + private static final String URI_PATH_CHARS = PATH + "?" + PARAM + "=" + VALUE_PATH_CHARS; |
| 51 | + |
| 52 | + // Test case 9: Control characters and unicode (%00, %09, %0D, %0A) |
| 53 | + private static final String VALUE_CONTROL_CHARS = "tab%09line%0Dreturn%0Anewline%00null"; |
| 54 | + private static final String URI_CONTROL_CHARS = PATH + "?" + PARAM + "=" + VALUE_CONTROL_CHARS; |
| 55 | + |
| 56 | + // Test case 10: High-value percent encodings (%7E, %7F, %80, %FF) |
| 57 | + private static final String VALUE_HIGH_CHARS = "tilde%7Edel%7Fhigh%80max%FF"; |
| 58 | + private static final String URI_HIGH_CHARS = PATH + "?" + PARAM + "=" + VALUE_HIGH_CHARS; |
| 59 | + |
22 | 60 | private PollingService service; |
23 | 61 |
|
24 | 62 | @BeforeMethod |
25 | 63 | public void setUp() throws Exception { |
26 | 64 | service = new PollingService(gd.getRestTemplate()); |
27 | 65 |
|
| 66 | + // Set up Jadler expectations for all test scenarios |
| 67 | + // Jetty 8.1 decodes %2B to + and %2F to / in URL parameters, other encoded chars remain |
| 68 | + |
| 69 | + // Test case 1: Complex base64-like string with multiple encoded chars |
| 70 | + String jettyProcessedValue = VALUE.replace("%2B", "+").replace("%2F", "/"); |
| 71 | + onRequest() |
| 72 | + .havingMethodEqualTo("GET") |
| 73 | + .havingPathEqualTo(PATH) |
| 74 | + .havingParameterEqualTo(PARAM, jettyProcessedValue) |
| 75 | + .respond() |
| 76 | + .withStatus(200); |
| 77 | + |
| 78 | + // Test case 2: String with only %2B (plus signs) - should decode to + |
| 79 | + String jettyProcessedValuePlusOnly = VALUE_PLUS_ONLY.replace("%2B", "+"); |
| 80 | + onRequest() |
| 81 | + .havingMethodEqualTo("GET") |
| 82 | + .havingPathEqualTo(PATH) |
| 83 | + .havingParameterEqualTo(PARAM, jettyProcessedValuePlusOnly) |
| 84 | + .respond() |
| 85 | + .withStatus(200); |
| 86 | + |
| 87 | + // Test case 3: String with only %2F (forward slashes) - should decode to / |
| 88 | + String jettyProcessedValueSlashOnly = VALUE_SLASH_ONLY.replace("%2F", "/"); |
| 89 | + onRequest() |
| 90 | + .havingMethodEqualTo("GET") |
| 91 | + .havingPathEqualTo(PATH) |
| 92 | + .havingParameterEqualTo(PARAM, jettyProcessedValueSlashOnly) |
| 93 | + .respond() |
| 94 | + .withStatus(200); |
| 95 | + |
| 96 | + // Test case 4: String with both %2B and %2F - should decode both |
| 97 | + String jettyProcessedValuePlusSlash = VALUE_PLUS_SLASH.replace("%2B", "+").replace("%2F", "/"); |
| 98 | + onRequest() |
| 99 | + .havingMethodEqualTo("GET") |
| 100 | + .havingPathEqualTo(PATH) |
| 101 | + .havingParameterEqualTo(PARAM, jettyProcessedValuePlusSlash) |
| 102 | + .respond() |
| 103 | + .withStatus(200); |
| 104 | + |
| 105 | + // Test case 5: String with mixed chars - Jetty 8.1 decodes %3D to = but leaves %0A and %20 |
| 106 | + String jettyProcessedValueMixedDecode = VALUE_MIXED_DECODE.replace("%3D", "="); // Only %3D gets decoded |
| 107 | + onRequest() |
| 108 | + .havingMethodEqualTo("GET") |
| 109 | + .havingPathEqualTo(PATH) |
| 110 | + .havingParameterEqualTo(PARAM, jettyProcessedValueMixedDecode) |
| 111 | + .respond() |
| 112 | + .withStatus(200); |
| 113 | + |
| 114 | + // Test case 6: Plus symbol behavior - investigate +, %2B, %20 handling |
| 115 | + String jettyProcessedValuePlusSpace = VALUE_PLUS_SPACE_TEST.replace("%2B", "+"); // %2B→+, others stay |
| 116 | + onRequest() |
| 117 | + .havingMethodEqualTo("GET") |
| 118 | + .havingPathEqualTo(PATH) |
| 119 | + .havingParameterEqualTo(PARAM, jettyProcessedValuePlusSpace) |
| 120 | + .respond() |
| 121 | + .withStatus(200); |
| 122 | + |
| 123 | + // Test case 7: Special characters - %26 acts as parameter separator, truncates value |
| 124 | + String jettyProcessedValueSpecial = "param"; // %26 truncates the parameter value! |
| 125 | + onRequest() |
| 126 | + .havingMethodEqualTo("GET") |
| 127 | + .havingPathEqualTo(PATH) |
| 128 | + .havingParameterEqualTo(PARAM, jettyProcessedValueSpecial) |
| 129 | + .respond() |
| 130 | + .withStatus(200); |
| 131 | + |
| 132 | + // Test case 8: Path characters - %2F→/, %2E→., %5C stays encoded |
| 133 | + String jettyProcessedValuePath = VALUE_PATH_CHARS.replace("%2F", "/").replace("%2E", "."); |
28 | 134 | onRequest() |
29 | 135 | .havingMethodEqualTo("GET") |
30 | 136 | .havingPathEqualTo(PATH) |
31 | | - .havingParameterEqualTo(PARAM, VALUE) |
| 137 | + .havingParameterEqualTo(PARAM, jettyProcessedValuePath) |
32 | 138 | .respond() |
33 | | - .withStatus(200) |
34 | | - ; |
| 139 | + .withStatus(200); |
| 140 | + |
| 141 | + // Test case 9: Control characters - test how Jetty 8.1 handles control chars |
| 142 | + String jettyProcessedValueControl = VALUE_CONTROL_CHARS; // Start with no changes, will discover |
| 143 | + onRequest() |
| 144 | + .havingMethodEqualTo("GET") |
| 145 | + .havingPathEqualTo(PATH) |
| 146 | + .havingParameterEqualTo(PARAM, jettyProcessedValueControl) |
| 147 | + .respond() |
| 148 | + .withStatus(200); |
| 149 | + |
| 150 | + // Test case 10: High-value characters - %7E→~, invalid bytes→%EF%BF%BD (UTF-8 replacement char) |
| 151 | + String jettyProcessedValueHigh = VALUE_HIGH_CHARS.replace("%7E", "~").replace("%80", "%EF%BF%BD").replace("%FF", "%EF%BF%BD"); |
| 152 | + onRequest() |
| 153 | + .havingMethodEqualTo("GET") |
| 154 | + .havingPathEqualTo(PATH) |
| 155 | + .havingParameterEqualTo(PARAM, jettyProcessedValueHigh) |
| 156 | + .respond() |
| 157 | + .withStatus(200); |
35 | 158 | } |
36 | 159 |
|
37 | 160 | @Test |
38 | 161 | public void shouldPollOnEncodedUri() throws Exception { |
39 | 162 | service.test(URI).get(); |
40 | 163 | } |
41 | 164 |
|
| 165 | + @Test |
| 166 | + public void shouldPollOnEncodedUriWithPlusOnly() throws Exception { |
| 167 | + service.test(URI_PLUS_ONLY).get(); |
| 168 | + } |
| 169 | + |
| 170 | + @Test |
| 171 | + public void shouldPollOnEncodedUriWithSlashOnly() throws Exception { |
| 172 | + service.test(URI_SLASH_ONLY).get(); |
| 173 | + } |
| 174 | + |
| 175 | + @Test |
| 176 | + public void shouldPollOnEncodedUriWithPlusAndSlash() throws Exception { |
| 177 | + service.test(URI_PLUS_SLASH).get(); |
| 178 | + } |
| 179 | + |
| 180 | + @Test |
| 181 | + public void shouldPollOnEncodedUriWithMixedDecodableChars() throws Exception { |
| 182 | + service.test(URI_MIXED_DECODE).get(); |
| 183 | + } |
| 184 | + |
| 185 | + @Test |
| 186 | + public void shouldPollOnEncodedUriWithPlusSpaceTest() throws Exception { |
| 187 | + service.test(URI_PLUS_SPACE_TEST).get(); |
| 188 | + } |
| 189 | + |
| 190 | + @Test |
| 191 | + public void shouldPollOnEncodedUriWithSpecialChars() throws Exception { |
| 192 | + service.test(URI_SPECIAL_CHARS).get(); |
| 193 | + } |
| 194 | + |
| 195 | + @Test |
| 196 | + public void shouldPollOnEncodedUriWithPathChars() throws Exception { |
| 197 | + service.test(URI_PATH_CHARS).get(); |
| 198 | + } |
| 199 | + |
| 200 | + @Test |
| 201 | + public void shouldPollOnEncodedUriWithControlChars() throws Exception { |
| 202 | + service.test(URI_CONTROL_CHARS).get(); |
| 203 | + } |
| 204 | + |
| 205 | + @Test |
| 206 | + public void shouldPollOnEncodedUriWithHighChars() throws Exception { |
| 207 | + service.test(URI_HIGH_CHARS).get(); |
| 208 | + } |
| 209 | + |
42 | 210 | private static class PollingService extends AbstractService { |
43 | 211 |
|
44 | 212 | private PollingService(final RestTemplate restTemplate) { |
|
0 commit comments