com.murrayc.galaxyzoo.app.provider.test.ZooniverseClientTest.java Source code

Java tutorial

Introduction

Here is the source code for com.murrayc.galaxyzoo.app.provider.test.ZooniverseClientTest.java

Source

/*
 * 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();
    }
}