package uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.healthmap; import org.joda.time.DateTime; import org.junit.Test; import uk.ac.ox.zoo.seeg.abraid.mp.common.web.JsonParserException; import uk.ac.ox.zoo.seeg.abraid.mp.common.web.WebServiceClient; import uk.ac.ox.zoo.seeg.abraid.mp.common.web.WebServiceClientException; import uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.healthmap.domain.HealthMapAlert; import uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.healthmap.domain.HealthMapLocation; import java.util.List; import static com.googlecode.catchexception.CatchException.catchException; import static com.googlecode.catchexception.CatchException.caughtException; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * Tests the HealthMapWebService class. * * Copyright (c) 2014 University of Oxford */ public class HealthMapWebServiceTest { @Test public void successfulHealthMapCall() { // Arrange DateTime startDate = new DateTime("2014-01-06T10:01:02+0000"); DateTime endDate = new DateTime("2014-01-07T13:10:59+0000"); String startDateUrl = "2014-01-06%2010:01:02%2B0000"; String endDateUrl = "2014-01-07%2013:10:59%2B0000"; // Real location with 2 alerts String jsonLocation1 = "{" + "\"country\": \"China\"," + "\"place_name\": \"Shenzhen, Guangdong, China\"," + "\"lat\": \"22.545540\"," + "\"lng\": \"114.068298\"," + "\"geonameid\": \"1795565\"," + "\"place_basic_type\": \"p\"," + "\"place_id\": \"733\"," + "\"country_id\": \"155\"," + "\"alerts\": [" + // Alert 1 "{" + "\"feed\": \"Food and Agriculture Org\"," + "\"reviewed\": \"\"," + "\"disease_ids\": [" + "\"271\"" + "]," + "\"diseases\": [" + "\"Avian Influenza H7N9\"" + "]," + "\"species_ids\": [" + "\"132\"" + "]," + "\"species\": [" + "\"Humans\"" + "]," + "\"disease\": \"Avian Influenza H7N9\"," + "\"summary\": \"Confirmed Influenza - Avian in Guangdong Sheng, China - human\"," + "\"date\": \"2014-01-07 00:00:00-0500\"," + "\"formatted_date\": \" 7 January 2014 00:00:00 EST\"," + "\"link\": \"http://healthmap.org/ln.php?2161280\"," + "\"descr\": \"\"," + "\"rating\": {" + "\"count\": \"1\"," + "\"rating\": \"4.0000\"" + "}," + "\"species_name\": \"Humans\"," + "\"dup_count\": \"0\"," + "\"summary_es\": \"Confirmado Influenza - aviar en Guangdong Sheng, China - humana\"," + "\"summary_fr\": \"Confirmé de grippe - Grippe dans le Guangdong Sheng, Chine - humaine\"," + "\"summary_ru\": \"Подтвержденным гриппом - Птичий в Guangdong Sheng, Китай - человеческий\"," + "\"summary_zh\": \"确认流感 - 禽流感在广东盛,中国 - 人类\"," + "\"summary_pt\": \"Influenza Confirmado - Aviária em Guangdong Sheng, China - humano\"," + "\"summary_ar\": \"أكد الأنفلونزا - الطيور فى قوانغدونغ شنغ، الصين - الإنسان\"," + "\"summary_vi\": \"Xác nhận cúm - cúm gia cầm ở Quảng Đông Sheng, Trung Quốc - con người\"," + "\"place_category\": []," + "\"original_url\": \"http://empres-i.fao.org/empres-i/2/obd?idOutbreak=182133&rss=t\"," + "\"disease_id\": \"271\"," + "\"feed_id\": \"10\"," + "\"feed_lang\": \"zh\"" + "}," + // Alert 2 "{" + "\"feed\": \"Google News\"," + "\"reviewed\": \"\"," + "\"disease_ids\": [" + "\"271\"" + "]," + "\"diseases\": [" + "\"Avian Influenza H7N9\"" + "]," + "\"species_ids\": [" + "\"132\"" + "]," + "\"species\": [" + "\"Humans\"" + "]," + "\"disease\": \"Avian Influenza H7N9\"," + "\"summary\": \"Two New Cases Of Human H7N9 Infections Reported In China - RTT News\"," + "\"date\": \"2014-01-06 16:07:33-0500\"," + "\"formatted_date\": \" 6 January 2014 16:07:33 EST\"," + "\"link\": \"http://healthmap.org/ln.php?2155089\"," + "\"descr\": \"The United Nations World Health Organization (WHO) revealed Monday that China's " + "National Health and Family Planning Commission had notified it in mid-December of two new laboratory" + "-confirmed cases of human infection with avian influenza A(H7N9) \"," + "\"rating\": {" + "\"count\": 0," + "\"rating\": 4" + "}," + "\"species_name\": \"Humans\"," + "\"dup_count\": \"0\"," + "\"place_category\": []," + "\"original_url\": \"http://news.google.com/news/url?sa=t&fd=R&usg=AFQjCNFduJXlyPpcRmF2wzssn6vgeH6dIw&" + "url=http://www.rttnews.com/2247181/two-new-cases-of-human-h7n9-infections-reported-in-china.aspx?type" + "%3Dmsgn%26utm_source%3Dgoogle%26utm_campaign%3Dsitemap\"," + "\"disease_id\": \"271\"," + "\"feed_id\": \"4\"" + "}" + "]" + "}"; // Location with a mixture of real and dummy data (2 alerts) String jsonLocation2 = "{" + "\"country\": null," + "\"place_name\": \"Lenvik, Troms, Norway\"," + "\"lng\": \"17.987391\"," + "\"geonameid\": \"undefined\"," + "\"place_basic_type\": \"\"," + "\"place_id\": null," + "\"country_id\": \"107\"," + "\"alerts\": [" + // Alert 1 "{" + "\"feed\": \"HM Community News Reports\"," + "\"disease\": \"Meningitis\"," + "\"summary\": \"Konstaterte smittsom hjernehinnebetennelse på 2-åring -Folkebladet.no\"," + "\"link\": \"unknown\"," + "\"descr\": \"Dubøroppgraderenettleserendin\"," + "\"rating\": {" + "\"count\": 0," + "\"rating\": 3" + "}," + "\"species_name\": \"Humans\"," + "\"dup_count\": \"0\"," + "\"cc\": \"1\"," + "\"summary_es\": \"Konstaterte smittsom hjernehinnebetennelse på 2-Aring-Folkebladet.no\"," + "\"summary_fr\": \"Konstaterte smittsom hjernehinnebetennelse på 2 Aring-Folkebladet.no\"," + "\"summary_ru\": \"Konstaterte smittsom hjernehinnebetennelse PA 2-Aring-Folkebladet.no\"," + "\"summary_zh\": \"Konstaterte smittsom hjernehinnebetennelsePå2-ARING-Folkebladet.no\"," + "\"summary_pt\": \"Konstaterte smittsom hjernehinnebetennelse på 2-Aring-Folkebladet.no\"," + "\"summary_ar\": \"Konstaterte smittsom hjernehinnebetennelse PA 2-åring-Folkebladet.no\"," + "\"summary_vi\": \"Konstaterte smittsom hjernehinnebetennelse på 2 aring-Folkebladet.no\"," + "\"place_category\": []," + "\"original_url\": \"http://www.folkebladet.no/nyheter/article8911579.ece\"," + "\"disease_id\": \"84\"," + "\"feed_id\": \"20\"" + "}," + // Alert 2 (reviewed and commented, with multiple diseases) "{" + "\"feed\": \"ABRAID PubMed\"," + "\"reviewed\": \"2014-12-03 14:27:57-0500\"," + "\"disease_ids\": [\"80\"," + "\"124\"]," + "\"diseases\": [\"Malaria\"," + "\"Schistosomiasis\"]," + "\"species_ids\": [\"132\"," + "\"132\"]," + "\"species\": [\"Humans\"," + "\"Humans\"]," + "\"disease\": \"Malaria\"," + "\"summary\": \"Concomitant infection by Plasmodium falciparum and Schistosoma haematobium among school children in a rural area of Senegal.\"," + "\"date\": \"2010-03-06 00:00:00-0500\"," + "\"formatted_date\": \" 6 March 2010 00:00:00 EST\"," + "\"link\": \"http:\\/\\/healthmap.org\\/ln.php?2576498\"," + "\"descr\": \"Malaria is endemic in lowland and coastal regions of Papua New Guinea (PNG)...\"," + "\"rating\": {" + "\"count\": 0," + "\"rating\": 3" + "}," + "\"comment\": \"s h, p f, p m, \"," + "\"species_name\": \"Humans\"," + "\"dup_count\": \"0\"," + "\"place_category\": [\"Imported Case\"]," + "\"original_url\": \"http:\\/\\/www.ncbi.nlm.nih.gov\\/pubmed\\/21129869\"," + "\"disease_id\": \"80\"," + "\"feed_id\": \"172\"" + "}" + "]" + "}"; String json = "[" + jsonLocation1 + "," + jsonLocation2 + "]"; String url = getHealthMapBaseUrl() + addStartDate(startDateUrl) + addEndDate(endDateUrl); WebServiceClient client = getMockWebServiceClient(url, json); HealthMapWebService webService = getHealthMapWebService(client); // Act List<HealthMapLocation> healthMapLocations = webService.sendRequest(startDate, endDate); // Assert assertThat(healthMapLocations).hasSize(2); HealthMapLocation location1 = healthMapLocations.get(0); assertThat(location1.getCountry()).isEqualTo("China"); assertThat(location1.getCountryId()).isEqualTo(155); assertThat(location1.getGeoNameId()).isEqualTo(1795565); assertThat(location1.getLatitude()).isEqualTo(22.54554); assertThat(location1.getLongitude()).isEqualTo(114.068298); assertThat(location1.getPlaceBasicType()).isEqualTo("p"); assertThat(location1.getPlaceName()).isEqualTo("Shenzhen, Guangdong, China"); assertThat(location1.getAlerts()).hasSize(2); HealthMapAlert location1Alert1 = location1.getAlerts().get(0); assertThat(location1Alert1.getAlertId()).isEqualTo(2161280); assertThatDatesAreEqual(location1Alert1.getDate(), new DateTime("2014-01-07T05:00:00+0000")); assertThat(location1Alert1.getDescription()).isNull(); assertThat(location1Alert1.getDiseases()).containsExactly("Avian Influenza H7N9"); assertThat(location1Alert1.getFeed()).isEqualTo("Food and Agriculture Org"); assertThat(location1Alert1.getLink()).isEqualTo("http://healthmap.org/ln.php?2161280"); assertThat(location1Alert1.getOriginalUrl()).isEqualTo("http://empres-i.fao.org/empres-i/2/obd?idOutbreak=" + "182133&rss=t"); assertThat(location1Alert1.getSummary()).isEqualTo("Confirmed Influenza - Avian in Guangdong Sheng, China -" + " human"); assertThat(location1Alert1.getDiseaseIds()).containsExactly(271); assertThat(location1Alert1.getFeedId()).isEqualTo(10); assertThat(location1Alert1.getFeedLanguage()).isEqualTo("zh"); HealthMapAlert location1Alert2 = location1.getAlerts().get(1); assertThat(location1Alert2.getAlertId()).isEqualTo(2155089); assertThatDatesAreEqual(location1Alert2.getDate(), new DateTime("2014-01-06T21:07:33+0000")); assertThat(location1Alert2.getDescription()).isEqualTo("The United Nations World Health Organization (WHO) " + "revealed Monday that China's National Health and Family Planning Commission had notified it in " + "mid-December of two new laboratory-confirmed cases of human infection with avian influenza A(H7N9)"); assertThat(location1Alert2.getDiseases()).containsExactly("Avian Influenza H7N9"); assertThat(location1Alert2.getFeed()).isEqualTo("Google News"); assertThat(location1Alert2.getLink()).isEqualTo("http://healthmap.org/ln.php?2155089"); assertThat(location1Alert2.getOriginalUrl()).isEqualTo("http://news.google.com/news/url?sa=t&fd=R&usg=AFQjCN" + "FduJXlyPpcRmF2wzssn6vgeH6dIw&url=http://www.rttnews.com/2247181/two-new-cases-of-human-h7n9-infect" + "ions-reported-in-china.aspx?type%3Dmsgn%26utm_source%3Dgoogle%26utm_campaign%3Dsitemap"); assertThat(location1Alert2.getSummary()).isEqualTo("Two New Cases Of Human H7N9 Infections Reported In China" + " - RTT News"); assertThat(location1Alert2.getDiseaseIds()).containsExactly(271); assertThat(location1Alert2.getFeedId()).isEqualTo(4); assertThat(location1Alert2.getFeedLanguage()).isNull(); HealthMapLocation location2 = healthMapLocations.get(1); assertThat(location2.getCountry()).isNull(); assertThat(location2.getCountryId()).isEqualTo(107); assertThat(location2.getGeoNameId()).isNull(); assertThat(location2.getLatitude()).isNull(); assertThat(location2.getLongitude()).isEqualTo(17.987391); assertThat(location2.getPlaceBasicType()).isNull(); assertThat(location2.getPlaceName()).isEqualTo("Lenvik, Troms, Norway"); assertThat(location2.getAlerts()).hasSize(2); HealthMapAlert location2Alert1 = location2.getAlerts().get(0); assertThat(location2Alert1.getAlertId()).isNull(); assertThat(location2Alert1.getDate()).isNull(); assertThat(location2Alert1.getReviewed()).isNull(); assertThat(location2Alert1.getDescription()).isEqualTo("Dubøroppgraderenettleserendin"); assertThat(location2Alert1.getDiseases()).containsExactly("Meningitis"); assertThat(location2Alert1.getFeed()).isEqualTo("HM Community News Reports"); assertThat(location2Alert1.getLink()).isEqualTo("unknown"); assertThat(location2Alert1.getOriginalUrl()).isEqualTo("http://www.folkebladet.no/nyheter/article8911579.ece"); assertThat(location2Alert1.getSummary()).isEqualTo("Konstaterte smittsom hjernehinnebetennelse på 2-åring " + "-Folkebladet.no"); assertThat(location2Alert1.getDiseaseIds()).containsExactly(84); assertThat(location2Alert1.getFeedId()).isEqualTo(20); assertThat(location2Alert1.getFeedLanguage()).isNull(); assertThat(location2Alert1.getPlaceCategories()).isEmpty(); HealthMapAlert location2Alert2 = location2.getAlerts().get(1); assertThat(location2Alert2.getAlertId()).isEqualTo(2576498); assertThatDatesAreEqual(location2Alert2.getDate(), new DateTime("2010-03-06T00:00:00-0500")); assertThatDatesAreEqual(location2Alert2.getReviewed(), new DateTime("2014-12-03T14:27:57-0500")); assertThat(location2Alert2.getDescription()).isEqualTo("Malaria is endemic in lowland and coastal regions of " + "Papua New Guinea (PNG)..."); assertThat(location2Alert2.getDiseases()).containsExactly("Malaria", "Schistosomiasis"); assertThat(location2Alert2.getDiseaseIds()).containsExactly(80, 124); assertThat(location2Alert2.getFeed()).isEqualTo("ABRAID PubMed"); assertThat(location2Alert2.getLink()).isEqualTo("http://healthmap.org/ln.php?2576498"); assertThat(location2Alert2.getOriginalUrl()).isEqualTo("http://www.ncbi.nlm.nih.gov/pubmed/21129869"); assertThat(location2Alert2.getSummary()).isEqualTo("Concomitant infection by Plasmodium falciparum and " + "Schistosoma haematobium among school children in a rural area of Senegal."); assertThat(location2Alert2.getFeedId()).isEqualTo(172); assertThat(location2Alert2.getFeedLanguage()).isNull(); assertThat(location2Alert2.getComment()).isEqualTo("s h, p f, p m,"); assertThat(location2Alert2.getSplitComment()).containsOnly("sh", "pf", "pm"); assertThat(location2Alert2.getPlaceCategories()).containsExactly("Imported Case"); } @Test public void healthMapReturnsNoResults() { // Arrange DateTime startDate = new DateTime("2014-01-06T00:00:00+0000"); String startDateUrl = "2014-01-06%2000:00:00%2B0000"; String json = "[]"; String url = getHealthMapBaseUrl() + addStartDate(startDateUrl); WebServiceClient client = getMockWebServiceClient(url, json); HealthMapWebService webService = getHealthMapWebService(client); // Act List<HealthMapLocation> healthMapLocations = webService.sendRequest(startDate, null); // Assert assertThat(healthMapLocations).hasSize(0); } @Test public void webServiceClientThrewException() { // Arrange String url = getHealthMapBaseUrl(); WebServiceClient client = mock(WebServiceClient.class); //noinspection unchecked when(client.makeGetRequest(url)).thenThrow(WebServiceClientException.class); HealthMapWebService webService = getHealthMapWebService(client); // Act catchException(webService).sendRequest(null, null); // Assert assertThat(caughtException()).isInstanceOf(WebServiceClientException.class); } @Test public void invalidJsonReturnedByGeoNames() { // Arrange String json = "this is invalid JSON"; String url = getHealthMapBaseUrl(); WebServiceClient client = getMockWebServiceClient(url, json); HealthMapWebService webService = getHealthMapWebService(client); // Act catchException(webService).sendRequest(null, null); // Assert assertThat(caughtException()).isInstanceOf(JsonParserException.class); } @Test public void setDefaultStartDateValid() { // Arrange DateTime startDate = new DateTime("2014-04-21T14:29:03+0000"); String startDateString = "2014-04-21 15:29:03+0100"; // Act HealthMapWebService webService = new HealthMapWebService(null); webService.setDefaultStartDate(startDateString); // Assert assertThatDatesAreEqual(webService.getDefaultStartDate(), startDate); } @Test public void setDefaultStartDateInvalid() { // Arrange String startDateString = "2014-04-21 15:29:03"; // Act HealthMapWebService webService = new HealthMapWebService(null); catchException(webService).setDefaultStartDate(startDateString); // Assert assertThat(caughtException()).isInstanceOf(RuntimeException.class); } @Test public void parseHealthMapJsonContainingMultipleDiseases() { String alertJson = "[{" + "\"alerts\": [" + "{" + "\"feed\": \"HM Community News Reports\"," + "\"disease\": \"This disease should be ignored\"," + "\"disease_id\": \"999\"," + "\"diseases\": [\"Meningitis\", \"Leishmaniasis\", \"Hookworm\"]," + "\"disease_ids\": [84, \"invalid\", \"64\"]" + "}" + "]" + "}]"; HealthMapWebService webService = getHealthMapWebService(null); List<HealthMapLocation> locations = webService.parseJson(alertJson); assertThat(locations).hasSize(1); assertThat(locations.get(0).getAlerts()).hasSize(1); assertThat(locations.get(0).getAlerts()).hasSize(1); HealthMapAlert alert = locations.get(0).getAlerts().get(0); assertThat(alert.getDiseases()).containsExactly("Meningitis", "Leishmaniasis", "Hookworm"); assertThat(alert.getDiseaseIds()).containsExactly(84, null, 64); } private String getHealthMapBaseUrl() { return "http://healthmap.org/HMapi.php?auth=testauthcode&striphtml=false"; } private String addStartDate(String startDateString) { return "&sdate=" + startDateString; } private String addEndDate(String endDateString) { return "&edate=" + endDateString; } private HealthMapWebService getHealthMapWebService(WebServiceClient client) { HealthMapWebService webService = new HealthMapWebService(client); webService.setRootUrl("http://healthmap.org/HMapi.php"); webService.setAuthorizationCode("testauthcode"); webService.setAuthorizationParameterName("auth"); webService.setStartDateParameterName("sdate"); webService.setEndDateParameterName("edate"); webService.setStripHtmlParameterName("striphtml"); webService.setStripHtml(false); return webService; } private WebServiceClient getMockWebServiceClient(String url, String json) { WebServiceClient client = mock(WebServiceClient.class); when(client.makeGetRequest(url)).thenReturn(json); return client; } private void assertThatDatesAreEqual(DateTime date1, DateTime date2) { // This ensures that timezone differences are ignored assertThat(date1.toLocalDateTime()).isEqualTo(date2.toLocalDateTime()); } }