package io.nextop.test; import android.test.InstrumentationTestCase; import android.util.Log; import com.google.common.io.ByteStreams; import com.google.common.net.HttpHeaders; import com.google.common.net.MediaType; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import io.nextop.*; import io.nextop.util.HexBytes; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.TimeUnit; public class NextopTest extends InstrumentationTestCase { Nextop nextop; @Override protected void setUp() throws Exception { super.setUp(); nextop = Nextop.create(getInstrumentation().getContext()).start(); } @Override protected void tearDown() throws Exception { super.tearDown(); nextop = nextop.stop(); } public void testRandomSendReceive() { assertNotNull(nextop); assertNotNull(nextop.getAuth()); final long timeoutMs = 6000; final int n = 64; Random r = new Random(); final Route.Method[] methods = new Route.Method[]{ Route.Method.POST }; final MediaType[] responseTypes = new MediaType[]{ MediaType.JSON_UTF_8, // FIXME go through all the types for WireValue send/receive // FIXME some are broken // MediaType.PLAIN_TEXT_UTF_8, // MediaType.APPLICATION_BINARY, // MediaType.JPEG, // MediaType.PNG, // MediaType.WEBP }; Route.Via via = Route.Via.valueOf("http://tests.nextop.io"); for (int i = 0; i < n; ++i) { // methods Route.Method method = methods[r.nextInt(methods.length)]; MediaType responseType = responseTypes[r.nextInt(responseTypes.length)]; WireValue responseBody = createRandomResponseBody(r, responseType); int responseCode = 200; Map<WireValue, WireValue> content = new HashMap<WireValue, WireValue>(4); { Map<WireValue, WireValue> responseHeaders = new HashMap<WireValue, WireValue>(4); responseHeaders.put(WireValue.of(HttpHeaders.CONTENT_TYPE), WireValue.of(responseType.toString())); Map<WireValue, WireValue> response = new HashMap<WireValue, WireValue>(4); response.put(WireValue.of("code"), WireValue.of(responseCode)); response.put(WireValue.of("headers"), WireValue.of(responseHeaders)); // send the response body as a string TODO response.put(WireValue.of("body"), WireValue.of(responseBody.toString())); content.put(WireValue.of("response"), WireValue.of(response)); } Message request = Message.newBuilder() .setRoute(Route.create(Route.Target.create(method, Path.valueOf("/")), via)) .setContent(WireValue.of(content)) .build(); Log.i("NextopTest", String.format("Send %s", request)); Message response; response = nextop.send(request) .timeout(timeoutMs, TimeUnit.MILLISECONDS) .toBlocking().single(); MediaType actualResponseType = MediaType.parse(response.headers.get(WireValue.of(HttpHeaders.CONTENT_TYPE)).asString()); assertEquals(responseCode, response.getCode()); assertTrue(String.format("%s <> %s", responseType, actualResponseType), actualResponseType.is(responseType)); // isSend that the response parsing worked correctly assertEquals(String.format("%s <> %s", responseBody.toDebugString(), response.getContent().toDebugString()), responseBody, response.getContent()); } } private WireValue createRandomResponseBody(Random r, MediaType responseType) { if (responseType.is(MediaType.JSON_UTF_8)) { return WireValue.of(randomJson(r, 2)); } if (responseType.is(MediaType.APPLICATION_BINARY)) { return WireValue.of(randomBytes(r, 128)); } if (responseType.is(MediaType.JPEG)) { EncodedImage image; try { image = EncodedImage.jpeg(ByteStreams.toByteArray(getInstrumentation().getContext().getAssets().open("flora.jpg"))); } catch (IOException e) { throw new IllegalStateException(e); } return WireValue.of(image); } if (responseType.is(MediaType.PNG)) { EncodedImage image; try { image = EncodedImage.jpeg(ByteStreams.toByteArray(getInstrumentation().getContext().getAssets().open("flora.png"))); } catch (IOException e) { throw new IllegalStateException(e); } return WireValue.of(image); } if (responseType.is(MediaType.WEBP)) { EncodedImage image; try { image = EncodedImage.jpeg(ByteStreams.toByteArray(getInstrumentation().getContext().getAssets().open("flora.webp"))); } catch (IOException e) { throw new IllegalStateException(e); } return WireValue.of(image); } // default: plain text return WireValue.of(randomString(r, 128)); } /** from WireValueTest */ private static JsonElement randomJson(Random r, int d) { return randomJson(r, d, 0); } private static JsonElement randomJson(Random r, int d, int u) { // list, map, long, double, string, bool int min, max; if (0 == u) { min = 4; max = 13; } else if (0 < d) { min = 0; max = 14; } else { min = 0; max = 4; } switch (min + r.nextInt(max - min)) { case 0: { int m = r.nextInt(16); byte[] bytes = new byte[m]; r.nextBytes(bytes); return new JsonPrimitive(HexBytes.toString(bytes)); } case 1: return new JsonPrimitive(r.nextLong()); case 2: return new JsonPrimitive(r.nextDouble()); case 3: return new JsonPrimitive(r.nextBoolean()); case 4: case 5: case 6: case 7: case 8: { int n = r.nextInt(16); JsonArray array = new JsonArray(); for (int i = 0; i < n; ++i) { array.add(randomJson(r, d - 1, u + 1)); } return array; } case 9: case 10: case 11: case 12: case 13: { int n = r.nextInt(16); JsonObject object = new JsonObject(); for (int i = 0; i < n; ++i) { int m = r.nextInt(32); byte[] keyBytes = new byte[m]; r.nextBytes(keyBytes); String key = HexBytes.toString(keyBytes); object.add(key, randomJson(r, d - 1, u + 1)); } return object; } default: throw new IllegalStateException(); } } private static byte[] randomBytes(Random r, int m) { int n = r.nextInt(2 * m); byte[] bytes = new byte[n]; r.nextBytes(bytes); return bytes; } /** includes the full range of Unicode code points */ private static String randomString(Random r, int m) { int n = r.nextInt(2 * m); char[] cs = new char[n]; for (int i = 0; i < n; ++i) { cs[i] = (char) r.nextInt((int) Character.MAX_VALUE); } return new String(cs); } }