com.basistech.rosette.api.BasicTest.java Source code

Java tutorial

Introduction

Here is the source code for com.basistech.rosette.api.BasicTest.java

Source

/*
* Copyright 2017 Basis Technology Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.basistech.rosette.api;

import com.basistech.rosette.apimodel.AdmRequest;
import com.basistech.rosette.apimodel.Response;
import com.basistech.rosette.apimodel.SupportedLanguage;
import com.basistech.rosette.apimodel.SupportedLanguagePair;
import com.basistech.rosette.apimodel.SupportedLanguagePairsResponse;
import com.basistech.rosette.apimodel.SupportedLanguagesResponse;
import com.basistech.rosette.apimodel.jackson.ApiModelMixinModule;
import com.basistech.rosette.dm.AnnotatedText;

import com.basistech.util.ISO15924;
import com.basistech.util.LanguageCode;
import com.basistech.util.TextDomain;
import com.basistech.util.TransliterationScheme;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHeaders;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockserver.client.server.MockServerClient;
import org.mockserver.junit.MockServerRule;
import org.mockserver.model.Delay;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import com.fasterxml.jackson.databind.ObjectMapper;

import static com.basistech.rosette.api.common.AbstractRosetteAPI.ENTITIES_SERVICE_PATH;
import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_SIMILARITY_SERVICE_PATH;
import static com.basistech.rosette.api.common.AbstractRosetteAPI.NAME_TRANSLATION_SERVICE_PATH;
import static java.util.concurrent.TimeUnit.SECONDS;

public class BasicTest extends AbstractTest {

    @Rule
    public MockServerRule mockServerRule = new MockServerRule(this, getFreePort());
    private MockServerClient mockServer;
    private HttpRosetteAPI api;

    private static int getFreePort() {
        try (ServerSocket socket = new ServerSocket(0)) {
            serverPort = socket.getLocalPort();
        } catch (IOException e) {
            fail("Failed to allocate a port");
        }
        assertNotEquals(0, serverPort);
        return serverPort;
    }

    @Before
    public void setup() {
        mockServer.reset();
        // for version check call
    }

    // an indirect way to show that connection pooling works
    // with concurrent connections = 1, the time to complete requests becomes serial
    // so: run several requests in threads, assert that they're executed serially
    // then set concurrent connections = 5,
    // run several requests again, showing they're executed in parallel
    @Test
    public void testMultipleConnections() throws IOException, InterruptedException {
        int delayTime = 3;
        int numConnections = 5;

        mockServer
                .when(HttpRequest.request().withMethod("GET").withPath("/rest/v1/info")
                        .withHeader(HttpHeaders.USER_AGENT, HttpRosetteAPI.USER_AGENT_STR))
                .respond(HttpResponse.response().withHeader("Content-Type", "application/json")
                        .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}",
                                StandardCharsets.UTF_8)
                        .withStatusCode(200).withDelay(new Delay(SECONDS, delayTime)));

        // "before" case - send off (numConnections) requests, expect them to run serially
        api = new HttpRosetteAPI.Builder().connectionConcurrency(1)
                .url(String.format("http://localhost:%d/rest/v1", serverPort)).build();

        Date d1 = new Date();

        List<ApiPinger> pingers = new ArrayList<>();
        for (int i = 0; i < numConnections; i++) {
            pingers.add(new ApiPinger(api));
            pingers.get(i).start();
        }

        for (int i = 0; i < numConnections; i++) {
            pingers.get(i).join();
        }

        Date d2 = new Date();

        assert d2.getTime() - d1.getTime() > delayTime * numConnections * 1000; // at least as long as the delay in the request

        api = new HttpRosetteAPI.Builder().connectionConcurrency(numConnections)
                .url(String.format("http://localhost:%d/rest/v1", serverPort)).build();
        d1 = new Date();

        pingers = new ArrayList<>();
        for (int i = 0; i < numConnections; i++) {
            pingers.add(new ApiPinger(api));
            pingers.get(i).start();
        }

        for (int i = 0; i < numConnections; i++) {
            pingers.get(i).join();
        }

        d2 = new Date();

        assert d2.getTime() - d1.getTime() < delayTime * numConnections * 1000; // less than (numConnections) serial requests
        assert d2.getTime() - d1.getTime() > delayTime * 1000; // but at least as long as one
    }

    @Test
    public void testHeaders() throws Exception {
        mockServer
                .when(HttpRequest.request().withMethod("GET").withPath("/rest/v1/ping").withHeader("X-Foo", "Bar")
                        .withHeader(HttpHeaders.USER_AGENT, HttpRosetteAPI.USER_AGENT_STR))
                .respond(HttpResponse.response().withHeader("Content-Type", "application/json")
                        .withHeader("X-RosetteAPI-Concurrency", "5").withStatusCode(200)
                        .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}",
                                StandardCharsets.UTF_8));

        api = new HttpRosetteAPI.Builder().key("foo-key")
                .url(String.format("http://localhost:%d/rest/v1", serverPort)).additionalHeader("X-Foo", "Bar")
                .build();
        api.ping();
    }

    @Test
    public void testAdm() throws Exception {
        try (InputStream reqIns = getClass().getResourceAsStream("/adm-req.json");
                InputStream respIns = getClass().getResourceAsStream("/adm-resp.json")) {
            mockServer.when(HttpRequest.request().withMethod("POST").withPath("/rest/v1/entities"))
                    .respond(HttpResponse.response().withStatusCode(200)
                            .withHeader("Content-Type", "application/json")
                            .withBody(IOUtils.toString(respIns, "UTF-8")));
            api = new HttpRosetteAPI.Builder().key("foo-key")
                    .url(String.format("http://localhost:%d/rest/v1", serverPort)).build();
            AnnotatedText testData = ApiModelMixinModule.setupObjectMapper(new ObjectMapper()).readValue(reqIns,
                    AnnotatedText.class);
            AnnotatedText resp = api.perform(ENTITIES_SERVICE_PATH, AdmRequest.builder().text(testData).build());
            assertEquals("Q100", resp.getEntities().get(0).getEntityId());
        }
    }

    @Test
    public void testExtendedInfo() throws Exception {
        mockServer.when(HttpRequest.request().withMethod("GET").withPath("/rest/v1/ping"))
                .respond(HttpResponse.response().withStatusCode(200).withHeader("Content-Type", "application/json")
                        .withHeader("X-Foo", "Bar").withHeader("X-FooMulti", "Bar1", "Bar2")
                        .withHeader("X-RosetteAPI-Concurrency", "5")
                        .withBody("{\"message\":\"Rosette API at your service\",\"time\":1461788498633}",
                                StandardCharsets.UTF_8));
        api = new HttpRosetteAPI.Builder().key("foo-key")
                .url(String.format("http://localhost:%d/rest/v1", serverPort)).build();
        Response resp = api.ping();
        assertEquals("Bar", resp.getExtendedInformation().get("X-Foo"));
        Set<?> foos = (Set) resp.getExtendedInformation().get("X-FooMulti");
        assertTrue(foos.contains("Bar1"));
        assertTrue(foos.contains("Bar2"));
    }

    private class ApiPinger extends Thread {
        HttpRosetteAPI api1;

        ApiPinger(HttpRosetteAPI api) throws IOException {
            this.api1 = api;
        }

        @Override
        public void run() {
            try {
                api1.info();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Test
    public void testLanguageSupport() throws Exception {
        try (InputStream respIns = getClass().getResourceAsStream("/supported-languages.json")) {
            mockServer
                    .when(HttpRequest.request().withMethod("GET").withPath("/rest/v1/entities/supported-languages"))
                    .respond(HttpResponse.response().withStatusCode(200)
                            .withHeader("Content-Type", "application/json")
                            .withBody(IOUtils.toString(respIns, "UTF-8")));
            api = new HttpRosetteAPI.Builder().key("foo-key")
                    .url(String.format("http://localhost:%d/rest/v1", serverPort)).build();
            SupportedLanguagesResponse resp = api.getSupportedLanguages(ENTITIES_SERVICE_PATH);
            assertEquals(2, resp.getSupportedLanguages().size());
            assertTrue(resp.getSupportedLanguages().contains(
                    SupportedLanguage.builder().language(LanguageCode.ENGLISH).script(ISO15924.Latn).build()));
            assertTrue(resp.getSupportedLanguages().contains(
                    SupportedLanguage.builder().language(LanguageCode.JAPANESE).script(ISO15924.Kana).build()));
        }
    }

    @Test
    public void testNameSimilarityLanguageSupport() throws Exception {
        try (InputStream respIns = getClass().getResourceAsStream("/name-similarity-supported-languages.json")) {
            mockServer
                    .when(HttpRequest.request().withMethod("GET")
                            .withPath("/rest/v1/name-similarity/supported-languages"))
                    .respond(HttpResponse.response().withStatusCode(200)
                            .withHeader("Content-Type", "application/json")
                            .withBody(IOUtils.toString(respIns, "UTF-8")));
            api = new HttpRosetteAPI.Builder().key("foo-key")
                    .url(String.format("http://localhost:%d/rest/v1", serverPort)).build();

            SupportedLanguagePairsResponse resp = api.getSupportedLanguagePairs(NAME_SIMILARITY_SERVICE_PATH);
            assertEquals(2, resp.getSupportedLanguagePairs().size());
            assertTrue(resp.getSupportedLanguagePairs()
                    .contains(SupportedLanguagePair.builder()
                            .source(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, null))
                            .target(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, null)).build()));
            assertTrue(resp.getSupportedLanguagePairs()
                    .contains(SupportedLanguagePair.builder()
                            .source(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, null))
                            .target(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, null)).build()));
        }
    }

    @Test
    public void testNameTranslationLanguageSupport() throws Exception {
        try (InputStream respIns = getClass().getResourceAsStream("/name-translation-supported-languages.json")) {
            mockServer
                    .when(HttpRequest.request().withMethod("GET")
                            .withPath("/rest/v1/name-translation/supported-languages"))
                    .respond(HttpResponse.response().withStatusCode(200)
                            .withHeader("Content-Type", "application/json")
                            .withBody(IOUtils.toString(respIns, "UTF-8")));
            api = new HttpRosetteAPI.Builder().key("foo-key")
                    .url(String.format("http://localhost:%d/rest/v1", serverPort)).build();

            SupportedLanguagePairsResponse resp = api.getSupportedLanguagePairs(NAME_TRANSLATION_SERVICE_PATH);
            assertEquals(2, resp.getSupportedLanguagePairs().size());
            assertTrue(resp.getSupportedLanguagePairs().contains(SupportedLanguagePair.builder()
                    .source(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, TransliterationScheme.NATIVE))
                    .target(new TextDomain(ISO15924.Latn, LanguageCode.ENGLISH, TransliterationScheme.IC))
                    .build()));
            assertTrue(resp.getSupportedLanguagePairs().contains(SupportedLanguagePair.builder()
                    .source(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, TransliterationScheme.NATIVE))
                    .target(new TextDomain(ISO15924.Arab, LanguageCode.ARABIC, TransliterationScheme.NATIVE))
                    .build()));
        }
    }
}