Java tutorial
/* * Copyright (C) 2014 Murray Cumming * * This file is part of android-glom * * android-glom is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * android-glom is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with android-glom. If not, see <http://www.gnu.org/licenses/>. */ package com.murrayc.galaxyzoo.app.provider.test; import android.app.Instrumentation; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.util.MalformedJsonException; import com.murrayc.galaxyzoo.app.LoginUtils; import com.murrayc.galaxyzoo.app.Utils; import com.murrayc.galaxyzoo.app.provider.Config; import com.murrayc.galaxyzoo.app.provider.HttpUtils; import com.murrayc.galaxyzoo.app.provider.client.ZooniverseClient; import com.squareup.okhttp.HttpUrl; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import okio.Buffer; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; public class ZooniverseClientTest { private static final String TEST_GROUP_ID = "551453e12f0eef21f2000001"; @Before public void setUp() throws IOException { } @After public void tearDown() { } @Test public void testMoreItems() throws IOException, InterruptedException, ZooniverseClient.RequestMoreItemsException { final MockWebServer server = new MockWebServer(); final String strResponse = getStringFromStream(MoreItemsJsonParserTest.class.getClassLoader() .getResourceAsStream("test_more_items_response.json")); assertNotNull(strResponse); server.enqueue(new MockResponse().setBody(strResponse)); server.start(); final ZooniverseClient client = createZooniverseClient(server); final int COUNT = 5; final List<ZooniverseClient.Subject> subjects = client.requestMoreItemsSync(COUNT); assertNotNull(subjects); assertTrue(subjects.size() == COUNT); final ZooniverseClient.Subject subject = subjects.get(0); assertNotNull(subject); assertNotNull(subject.getSubjectId()); assertEquals(subject.getSubjectId(), "5500684569736d5964271400"); assertNotNull(subject.getZooniverseId()); assertEquals(subject.getZooniverseId(), "AGZ00081ls"); assertNotNull(subject.getGroupId()); assertEquals(subject.getGroupId(), TEST_GROUP_ID); assertNotNull(subject.getLocationStandard()); assertEquals(subject.getLocationStandard(), "http://www.galaxyzoo.org.s3.amazonaws.com/subjects/standard/goods_full_n_27820_standard.jpg"); assertNotNull(subject.getLocationThumbnail()); assertEquals(subject.getLocationThumbnail(), "http://www.galaxyzoo.org.s3.amazonaws.com/subjects/thumbnail/goods_full_n_27820_thumbnail.jpg"); assertNotNull(subject.getLocationInverted()); assertEquals(subject.getLocationInverted(), "http://www.galaxyzoo.org.s3.amazonaws.com/subjects/inverted/goods_full_n_27820_inverted.jpg"); //Test what the server received: assertEquals(1, server.getRequestCount()); final RecordedRequest request = server.takeRequest(); assertEquals("GET", request.getMethod()); //ZooniverseClient uses one of several possible group IDs at random: //See com.murrayc.galaxyzoo.app.provider.Config final String possiblePath1 = "/groups/" + TEST_GROUP_ID + "/subjects?limit=5"; final String possiblePath2 = "/groups/" + Config.SUBJECT_GROUP_ID_GAMA_09 + "/subjects?limit=5"; final String possiblePath3 = "/groups/" + Config.SUBJECT_GROUP_ID_SDSS_LOST_SET + "/subjects?limit=5"; final String possiblePath4 = "/groups/" + Config.SUBJECT_GROUP_ID_ILLUSTRIS + "/subjects?limit=5"; //TODO: Can we use this? // assertThat(request.getPath(), anyOf(is(possiblePath1), is(possiblePath2))); final String path = request.getPath(); assertTrue(path.equals(possiblePath1) || path.equals(possiblePath2) || path.equals(possiblePath3) || path.equals(possiblePath4)); server.shutdown(); } @Test public void testLoginWithSuccess() throws IOException, InterruptedException, ZooniverseClient.LoginException { final MockWebServer server = new MockWebServer(); final String strResponse = getStringFromStream(MoreItemsJsonParserTest.class.getClassLoader() .getResourceAsStream("test_login_response_success.json")); assertNotNull(strResponse); server.enqueue(new MockResponse().setBody(strResponse)); server.start(); final ZooniverseClient client = createZooniverseClient(server); final LoginUtils.LoginResult result = client.loginSync("testusername", "testpassword"); assertNotNull(result); assertTrue(result.getSuccess()); assertEquals(result.getApiKey(), "testapikey"); //Test what the server received: assertEquals(1, server.getRequestCount()); final RecordedRequest request = server.takeRequest(); assertEquals("POST", request.getMethod()); assertEquals("/login", request.getPath()); assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type")); final Buffer contents = request.getBody(); final String strContents = contents.readUtf8(); assertEquals("username=testusername&password=testpassword", strContents); server.shutdown(); } @Test public void testLoginWithFailure() throws IOException { final MockWebServer server = new MockWebServer(); //On failure, the server's response code is HTTP_OK, //but it has a "success: false" parameter. final MockResponse response = new MockResponse(); response.setResponseCode(HttpURLConnection.HTTP_OK); response.setBody("test nonsense failure message"); server.enqueue(response); server.start(); final ZooniverseClient client = createZooniverseClient(server); try { final LoginUtils.LoginResult result = client.loginSync("testusername", "testpassword"); assertNotNull(result); assertFalse(result.getSuccess()); } catch (final ZooniverseClient.LoginException e) { assertTrue(e.getCause() instanceof MalformedJsonException); } server.shutdown(); } @Test public void testLoginWithBadResponseContent() throws IOException { final MockWebServer server = new MockWebServer(); server.enqueue(new MockResponse().setBody("test bad login response")); server.start(); final ZooniverseClient client = createZooniverseClient(server); try { final LoginUtils.LoginResult result = client.loginSync("testusername", "testpassword"); assertNotNull(result); assertFalse(result.getSuccess()); } catch (final ZooniverseClient.LoginException e) { assertTrue(e.getCause() instanceof IOException); } server.shutdown(); } @Test public void testMoreItemsWithBadResponseContent() throws IOException { final MockWebServer server = new MockWebServer(); server.enqueue(new MockResponse().setBody("some nonsense to try to break things {")); server.start(); final ZooniverseClient client = createZooniverseClient(server); //Mostly we want to check that it doesn't crash on a bad HTTP response. try { final List<ZooniverseClient.Subject> subjects = client.requestMoreItemsSync(5); assertTrue((subjects == null) || (subjects.isEmpty())); } catch (final ZooniverseClient.RequestMoreItemsException e) { final Throwable cause = e.getCause(); if (cause != null) { assertTrue(e.getCause() instanceof IOException); } } server.shutdown(); } @Test public void testMoreItemsWithBadResponseCode() throws IOException { final MockWebServer server = new MockWebServer(); final MockResponse response = new MockResponse(); response.setResponseCode(HttpURLConnection.HTTP_NOT_FOUND); response.setBody("test nonsense failure message"); server.enqueue(response); server.start(); final ZooniverseClient client = createZooniverseClient(server); //Mostly we want to check that it doesn't crash on a bad HTTP response. try { final List<ZooniverseClient.Subject> subjects = client.requestMoreItemsSync(5); assertTrue((subjects == null) || (subjects.isEmpty())); } catch (final ZooniverseClient.RequestMoreItemsException e) { assertTrue(e.getCause() instanceof ExecutionException); } server.shutdown(); } @Test public void testUploadWithSuccess() throws IOException, InterruptedException, ZooniverseClient.UploadException { final MockWebServer server = new MockWebServer(); final MockResponse response = new MockResponse(); response.setResponseCode(HttpURLConnection.HTTP_CREATED); response.setBody("TODO"); server.enqueue(response); server.start(); final ZooniverseClient client = createZooniverseClient(server); //SyncAdapter.doUploadSync() adds an "interface" parameter too, //but we are testing a more generic API here: final List<HttpUtils.NameValuePair> values = new ArrayList<>(); values.add(new HttpUtils.NameValuePair("classification[subject_ids][]", "504e4a38c499611ea6010c6a")); values.add(new HttpUtils.NameValuePair("classification[favorite][]", "true")); values.add(new HttpUtils.NameValuePair("classification[annotations][0][sloan-0]", "a-0")); values.add(new HttpUtils.NameValuePair("classification[annotations][1][sloan-7]", "a-1")); values.add(new HttpUtils.NameValuePair("classification[annotations][2][sloan-5]", "a-0")); values.add(new HttpUtils.NameValuePair("classification[annotations][3][sloan-6]", "x-5")); final boolean result = client.uploadClassificationSync("testAuthName", "testAuthApiKey", TEST_GROUP_ID, values); assertTrue(result); assertEquals(1, server.getRequestCount()); //This is really just a regression test, //so we notice if something changes unexpectedly: final RecordedRequest request = server.takeRequest(); assertEquals("POST", request.getMethod()); assertEquals("/workflows/" + TEST_GROUP_ID + "/classifications", request.getPath()); assertNotNull(request.getHeader("Authorization")); assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type")); final Buffer contents = request.getBody(); final String strContents = contents.readUtf8(); assertEquals( "classification%5Bsubject_ids%5D%5B%5D=504e4a38c499611ea6010c6a&classification%5Bfavorite%5D%5B%5D=true&classification%5Bannotations%5D%5B0%5D%5Bsloan-0%5D=a-0&classification%5Bannotations%5D%5B1%5D%5Bsloan-7%5D=a-1&classification%5Bannotations%5D%5B2%5D%5Bsloan-5%5D=a-0&classification%5Bannotations%5D%5B3%5D%5Bsloan-6%5D=x-5", strContents); server.shutdown(); } @Test public void testUploadWithFailure() throws IOException { final MockWebServer server = new MockWebServer(); final MockResponse response = new MockResponse(); response.setResponseCode(HttpURLConnection.HTTP_UNAUTHORIZED); response.setBody("test nonsense failure message"); server.enqueue(response); server.start(); final ZooniverseClient client = createZooniverseClient(server); final List<HttpUtils.NameValuePair> values = new ArrayList<>(); values.add(new HttpUtils.NameValuePair("test nonsense", "12345")); try { final boolean result = client.uploadClassificationSync("testAuthName", "testAuthApiKey", TEST_GROUP_ID, values); assertFalse(result); } catch (final ZooniverseClient.UploadException e) { //This is (at least with okhttp.mockwebserver) a normal //event if the upload was refused via an error response code. assertTrue(e.getCause() instanceof IOException); } server.shutdown(); } private static ZooniverseClient createZooniverseClient(final MockWebServer server) { final HttpUrl mockUrl = server.url("/"); final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); final Context context = instrumentation.getTargetContext(); return new ZooniverseClient(context, mockUrl.toString()); } private static String getStringFromStream(final InputStream input) throws IOException { //Don't bother with try/catch because we are in a test case anyway. final InputStreamReader isr = new InputStreamReader(input, Utils.STRING_ENCODING); final BufferedReader bufferedReader = new BufferedReader(isr); final StringBuilder sb = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { sb.append(line).append("\n"); } bufferedReader.close(); isr.close(); return sb.toString(); } }