From 00e3c0266b7974bd73860e85c6f6e0585d46c7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20Mag=C3=A1n?= Date: Fri, 11 Dec 2015 14:54:08 +0100 Subject: [PATCH 1/7] Update JaCoCo --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b0bd29d..bd35d41 100644 --- a/pom.xml +++ b/pom.xml @@ -443,7 +443,7 @@ org.jacoco jacoco-maven-plugin - 0.7.2.201409121644 + 0.7.5.201505241946 From ec89975eee682ce2d0c99c6752820bdf1f81576b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20Mag=C3=A1n?= Date: Wed, 23 Dec 2015 12:56:25 +0100 Subject: [PATCH 2/7] Escape HTML in open fields --- .../fiware/apps/marketplace/bo/impl/DescriptionBoImpl.java | 6 +++++- .../org/fiware/apps/marketplace/bo/impl/StoreBoImpl.java | 6 +++++- .../fiware/apps/marketplace/helpers/OfferingResolver.java | 4 +++- .../org/fiware/apps/marketplace/model/PriceComponent.java | 3 ++- .../java/org/fiware/apps/marketplace/model/PricePlan.java | 6 ++++-- .../java/org/fiware/apps/marketplace/rdf/RdfHelper.java | 3 ++- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImpl.java b/src/main/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImpl.java index 563b728..e6337f0 100644 --- a/src/main/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImpl.java +++ b/src/main/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImpl.java @@ -70,6 +70,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.util.HtmlUtils; import com.hp.hpl.jena.shared.JenaException; @@ -121,6 +122,9 @@ public void save(String storeName, Description description) // Set the name based on the display name description.setName(NameGenerator.getURLName(description.getDisplayName())); + // Escape HTML + description.setComment(HtmlUtils.htmlEscape(description.getComment())); + // Exception is risen if the description is not valid descriptionValidator.validateNewDescription(description); @@ -275,7 +279,7 @@ private void update(String storeName, String descriptionName, Description update } if (updatedDescription.getComment() != null) { - descriptionToBeUpdated.setComment(updatedDescription.getComment()); + descriptionToBeUpdated.setComment(HtmlUtils.htmlEscape(updatedDescription.getComment())); } // If the action is automatically performed by the system, last editor field diff --git a/src/main/java/org/fiware/apps/marketplace/bo/impl/StoreBoImpl.java b/src/main/java/org/fiware/apps/marketplace/bo/impl/StoreBoImpl.java index bf7e2d5..4ca9f10 100644 --- a/src/main/java/org/fiware/apps/marketplace/bo/impl/StoreBoImpl.java +++ b/src/main/java/org/fiware/apps/marketplace/bo/impl/StoreBoImpl.java @@ -61,6 +61,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.util.HtmlUtils; @Service("storeBo") public class StoreBoImpl implements StoreBo{ @@ -183,6 +184,9 @@ public void save(Store store) throws NotAuthorizedException, // Set default name based on the display name store.setName(NameGenerator.getURLName(store.getDisplayName())); + // Escape HTML + store.setComment(HtmlUtils.htmlEscape(store.getComment())); + // Set average score to zero store.setAverageScore(0); @@ -231,7 +235,7 @@ public void update(String storeName, Store updatedStore) throws NotAuthorizedExc } if (updatedStore.getComment() != null) { - storeToBeUpdate.setComment(updatedStore.getComment()); + storeToBeUpdate.setComment(HtmlUtils.htmlEscape(updatedStore.getComment())); } if (updatedStore.getDisplayName() != null) { diff --git a/src/main/java/org/fiware/apps/marketplace/helpers/OfferingResolver.java b/src/main/java/org/fiware/apps/marketplace/helpers/OfferingResolver.java index 3ba7601..82127f1 100644 --- a/src/main/java/org/fiware/apps/marketplace/helpers/OfferingResolver.java +++ b/src/main/java/org/fiware/apps/marketplace/helpers/OfferingResolver.java @@ -64,6 +64,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.util.HtmlUtils; import com.hp.hpl.jena.shared.JenaException; @@ -112,7 +113,8 @@ private String generateExceptionMessage(RdfHelper rdfHelper, String offeringUri, */ private String cleanRdfUrl(String url) { // Remove '<' from the beginning and '>' from the end - return url != null ? url.substring(1, url.length() - 1) : ""; + // Additionally, the URL is escaped in case it contains HTML... + return url != null ? HtmlUtils.htmlEscape(url.substring(1, url.length() - 1)) : ""; } diff --git a/src/main/java/org/fiware/apps/marketplace/model/PriceComponent.java b/src/main/java/org/fiware/apps/marketplace/model/PriceComponent.java index 07e7a97..54e158a 100644 --- a/src/main/java/org/fiware/apps/marketplace/model/PriceComponent.java +++ b/src/main/java/org/fiware/apps/marketplace/model/PriceComponent.java @@ -50,6 +50,7 @@ import org.fiware.apps.marketplace.exceptions.ParseException; import org.jboss.resteasy.annotations.providers.jaxb.IgnoreMediaTypes; +import org.springframework.web.util.HtmlUtils; @Entity @Table(name = "price_components") @@ -142,7 +143,7 @@ public PriceComponent(Map> rawPriceComponent, PricePlan pri * @return The first element as String. If the list is empty or null, an empty string is returned */ private static String getFirstStringFromObjectList(List list) { - return (list == null || list.isEmpty()) ? "" : (String) list.get(0); + return HtmlUtils.htmlEscape((list == null || list.isEmpty()) ? "" : (String) list.get(0)); } @Id diff --git a/src/main/java/org/fiware/apps/marketplace/model/PricePlan.java b/src/main/java/org/fiware/apps/marketplace/model/PricePlan.java index 28bdab9..242de1d 100644 --- a/src/main/java/org/fiware/apps/marketplace/model/PricePlan.java +++ b/src/main/java/org/fiware/apps/marketplace/model/PricePlan.java @@ -56,6 +56,7 @@ import org.codehaus.jackson.annotate.JsonProperty; import org.fiware.apps.marketplace.exceptions.ParseException; import org.jboss.resteasy.annotations.providers.jaxb.IgnoreMediaTypes; +import org.springframework.web.util.HtmlUtils; @Entity @Table(name = "price_plans") @@ -92,9 +93,10 @@ public PricePlan(Map> rawPricePlan, Offering offering) thro " contains a price plan without title"); } - this.title = title; + this.title = HtmlUtils.htmlEscape(title); List ppDescriptions = rawPricePlan.get("description"); - this.comment = (ppDescriptions != null && ppDescriptions.size() == 1) ? (String) ppDescriptions.get(0) : ""; + this.comment = (ppDescriptions != null && ppDescriptions.size() == 1) ? + HtmlUtils.htmlEscape((String) ppDescriptions.get(0)) : ""; this.offering = offering; this.priceComponents = new HashSet<>(); } diff --git a/src/main/java/org/fiware/apps/marketplace/rdf/RdfHelper.java b/src/main/java/org/fiware/apps/marketplace/rdf/RdfHelper.java index c9ca7c4..20d9b86 100644 --- a/src/main/java/org/fiware/apps/marketplace/rdf/RdfHelper.java +++ b/src/main/java/org/fiware/apps/marketplace/rdf/RdfHelper.java @@ -42,6 +42,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.web.util.HtmlUtils; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; @@ -154,7 +155,7 @@ public List queryLiterals(String query, String queriedVar) { List solutions = this.query(query); for (QuerySolution solution: solutions) { - literals.add(solution.getLiteral(queriedVar).getLexicalForm()); + literals.add(HtmlUtils.htmlEscape(solution.getLiteral(queriedVar).getLexicalForm())); } return literals; From 593ea9878750b26c4806379b83f2de7fbcce1d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20Mag=C3=A1n?= Date: Wed, 23 Dec 2015 12:58:56 +0100 Subject: [PATCH 3/7] Show escaped HTML as HTML in forms --- src/main/webapp/WEB-INF/functions.tld | 22 +++++++++++++++++++ .../views/descriptions/create-scripts.jsp | 3 ++- .../views/descriptions/detail-scripts.jsp | 9 ++++---- .../WEB-INF/views/stores/detail-scripts.jsp | 9 ++++---- .../WEB-INF/views/stores/form-scripts.jsp | 9 ++++---- 5 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 src/main/webapp/WEB-INF/functions.tld diff --git a/src/main/webapp/WEB-INF/functions.tld b/src/main/webapp/WEB-INF/functions.tld new file mode 100644 index 0000000..efccf10 --- /dev/null +++ b/src/main/webapp/WEB-INF/functions.tld @@ -0,0 +1,22 @@ + + + + Custom Functions + 1.0 + http://fiware.org/functions + + + escapeJS + org.apache.commons.lang3.StringEscapeUtils + java.lang.String escapeEcmaScript(java.lang.String) + + + unescapeHTML + org.apache.commons.lang3.StringEscapeUtils + java.lang.String unescapeHtml4(java.lang.String) + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/views/descriptions/create-scripts.jsp b/src/main/webapp/WEB-INF/views/descriptions/create-scripts.jsp index c9e502a..9be490c 100644 --- a/src/main/webapp/WEB-INF/views/descriptions/create-scripts.jsp +++ b/src/main/webapp/WEB-INF/views/descriptions/create-scripts.jsp @@ -1,4 +1,5 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="util" uri="http://fiware.org/functions" %> @@ -7,7 +8,7 @@ diff --git a/src/main/webapp/WEB-INF/views/descriptions/detail-scripts.jsp b/src/main/webapp/WEB-INF/views/descriptions/detail-scripts.jsp index 3209d49..0e47c64 100644 --- a/src/main/webapp/WEB-INF/views/descriptions/detail-scripts.jsp +++ b/src/main/webapp/WEB-INF/views/descriptions/detail-scripts.jsp @@ -1,4 +1,5 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="util" uri="http://fiware.org/functions" %> @@ -7,7 +8,7 @@ @@ -15,9 +16,9 @@ diff --git a/src/main/webapp/WEB-INF/views/stores/detail-scripts.jsp b/src/main/webapp/WEB-INF/views/stores/detail-scripts.jsp index e29cf22..c4a7a85 100644 --- a/src/main/webapp/WEB-INF/views/stores/detail-scripts.jsp +++ b/src/main/webapp/WEB-INF/views/stores/detail-scripts.jsp @@ -1,4 +1,5 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="util" uri="http://fiware.org/functions" %> @@ -24,7 +25,7 @@ @@ -32,9 +33,9 @@ diff --git a/src/main/webapp/WEB-INF/views/stores/form-scripts.jsp b/src/main/webapp/WEB-INF/views/stores/form-scripts.jsp index 3fe7822..241c2d2 100644 --- a/src/main/webapp/WEB-INF/views/stores/form-scripts.jsp +++ b/src/main/webapp/WEB-INF/views/stores/form-scripts.jsp @@ -1,4 +1,5 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="util" uri="http://fiware.org/functions" %> @@ -6,7 +7,7 @@ @@ -14,9 +15,9 @@ \ No newline at end of file From 3cc9f224d0e63ee2833657634998d78c5a062153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20Mag=C3=A1n?= Date: Wed, 23 Dec 2015 17:10:48 +0100 Subject: [PATCH 4/7] Fix tests --- .../fiware/apps/marketplace/helpers/OfferingResolverTest.java | 2 +- src/test/java/org/fiware/apps/marketplace/it/AbstractIT.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java b/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java index 5e3fd84..40509c2 100644 --- a/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java +++ b/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java @@ -334,7 +334,7 @@ public void testSimpleDescription() throws Exception { String pricePlanTitle = "price plan"; String pricePlanDesc = "a description for the price plan"; String priceComponentTitle = "price component"; - String priceComponentCurrency = "EUR (€)"; + String priceComponentCurrency = "EUR"; String priceComponentUnit = "bytes/month"; float priceComponentValue = 1.23F; diff --git a/src/test/java/org/fiware/apps/marketplace/it/AbstractIT.java b/src/test/java/org/fiware/apps/marketplace/it/AbstractIT.java index 9d2bac9..24da66b 100644 --- a/src/test/java/org/fiware/apps/marketplace/it/AbstractIT.java +++ b/src/test/java/org/fiware/apps/marketplace/it/AbstractIT.java @@ -206,7 +206,7 @@ private void initOfferings() { "https://store.lab.fiware.org/media/CoNWeT__CKANStarterKit__1.2/logo-ckan_170x80.png"); SECOND_OFFERING.setDescription("Offering composed of several mashable application components that compose " + "the base tools/examples for making application mashups using WireCloud and CKAN. Those resources " - + "can be used for example for showing data coming from CKAN's dataset inside the Map Viewer widget " + + "can be used for example for showing data coming from CKAN's dataset inside the Map Viewer widget " + "or inside a graph widget or for browsing data inside a table widget."); SECOND_OFFERING.setPricePlans(pricePlansOff2); SECOND_OFFERING.setServices(servicesOff2); From 7d6bdfe982472827b1fd365bb9de86afab6c7999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20Mag=C3=A1n?= Date: Wed, 23 Dec 2015 18:11:05 +0100 Subject: [PATCH 5/7] Add tests to check that the HTML is escaped when creating/editing stores --- .../marketplace/bo/impl/StoreBoImplTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/test/java/org/fiware/apps/marketplace/bo/impl/StoreBoImplTest.java b/src/test/java/org/fiware/apps/marketplace/bo/impl/StoreBoImplTest.java index 574fc1e..cc7b982 100644 --- a/src/test/java/org/fiware/apps/marketplace/bo/impl/StoreBoImplTest.java +++ b/src/test/java/org/fiware/apps/marketplace/bo/impl/StoreBoImplTest.java @@ -61,10 +61,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.mockito.InOrder; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.util.HtmlUtils; public class StoreBoImplTest { @@ -206,6 +208,26 @@ public void testSaveWithoutImage() { testSave(false); } + @Test + public void testHtmlIsEscapedWhenCreating() throws Exception { + + String html = ""; + + Store store = mock(Store.class); + when(store.getName()).thenReturn(NAME); + when(store.getDisplayName()).thenReturn(DISPLAY_NAME); + when(store.getComment()).thenReturn(html); + when(storeAuthMock.canCreate(store)).thenReturn(true); + + InOrder order = inOrder(store, storeDaoMock); + + storeBo.save(store); + + order.verify(store).setComment(HtmlUtils.htmlEscape(html)); + order.verify(storeDaoMock).save(store); + + } + /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////// UPDATE //////////////////////////////////////// @@ -324,6 +346,10 @@ private void testUpdateStoreField(Store updatedStore) { // Assert that last modifier has changed assertThat(store.getLasteditor()).isEqualTo(user); + + // Check that the store has been modified in the data base + verify(storeDaoMock).update(store); + } catch (Exception ex) { // It's not supposed to happen fail("Exception " + ex + " is not supposed to happen"); @@ -358,6 +384,33 @@ public void testUpdateStoreImage() { testUpdateStoreField(newStore); } + @Test + public void testHtmlIsEscapedWhenUpdating() throws Exception { + + + String html = ""; + + Store updatedStore = mock(Store.class); + when(updatedStore.getComment()).thenReturn(html); + + Store storeToBeUpdated = mock(Store.class); + + // Mock + doReturn(storeToBeUpdated).when(storeDaoMock).findByName(NAME); + when(storeAuthMock.canUpdate(storeToBeUpdated)).thenReturn(true); + + InOrder order = inOrder(storeToBeUpdated, storeDaoMock); + + // Call the method + storeBo.update(NAME, updatedStore); + + // Verify that the html has been escaped before inserting it + // in the database + order.verify(storeToBeUpdated).setComment(HtmlUtils.htmlEscape(html)); + order.verify(storeDaoMock).update(storeToBeUpdated); + + } + /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////// DELETE //////////////////////////////////////// From 904068dc36169876141420111b1e00f437b86ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20Mag=C3=A1n?= Date: Fri, 8 Jan 2016 15:11:03 +0100 Subject: [PATCH 6/7] Tests to check that the descriptions comments are escaped --- .../bo/impl/DescriptionBoImplTest.java | 247 ++++++++++++++---- 1 file changed, 198 insertions(+), 49 deletions(-) diff --git a/src/test/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImplTest.java b/src/test/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImplTest.java index 7559fc6..1be361c 100644 --- a/src/test/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImplTest.java +++ b/src/test/java/org/fiware/apps/marketplace/bo/impl/DescriptionBoImplTest.java @@ -68,11 +68,13 @@ import org.hibernate.SessionFactory; import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.springframework.web.util.HtmlUtils; import com.hp.hpl.jena.shared.JenaException; @@ -109,6 +111,7 @@ public void setUp() { } private Description generateDescription(List offerings) { + Description description = new Description(); // description.setName(DESCRIPTION_NAME); description.setDisplayName(DESCRIPTION_DISPLAY_NAME); @@ -119,8 +122,10 @@ private Description generateDescription(List offerings) { return description; } - private Offering generateOffering(String url, Description describedIn, String name, String displayName, - String description, String imageUrl, String version) { + private Offering generateOffering(String url, Description describedIn, + String name, String displayName, String description, String imageUrl, + String version) { + Offering offering = new Offering(); offering.setUri(url); offering.setDescribedIn(describedIn); @@ -137,6 +142,7 @@ private Offering generateOffering(String url, Description describedIn, String na } private Category generateCategory(String categoryName) { + Category category = new Category(); category.setName(categoryName); category.setServices(new HashSet()); @@ -145,6 +151,7 @@ private Category generateCategory(String categoryName) { } private Service generateService(String uri) { + Service service = new Service(); service.setUri(uri); service.setCategories(new HashSet()); @@ -178,7 +185,9 @@ private void testSaveException(Description description) throws Exception { @Test public void testSaveNotAuthorized() throws Exception { + try { + Description description = generateDescription(new ArrayList()); when(descriptionAuthMock.canCreate(description)).thenReturn(false); @@ -187,8 +196,11 @@ public void testSaveNotAuthorized() throws Exception { // If the exception is not risen, the method is not properly working failBecauseExceptionWasNotThrown(NotAuthorizedException.class); + } catch (NotAuthorizedException ex) { - assertThat(ex.getMessage()).isEqualTo(String.format(NOT_AUTHORIZED_BASE, "create description")); + + assertThat(ex.getMessage()).isEqualTo( + String.format(NOT_AUTHORIZED_BASE, "create description")); } } @@ -196,8 +208,9 @@ public void testSaveNotAuthorized() throws Exception { public void testSaveInvalidDescription() throws Exception { Description description = generateDescription(new ArrayList()); - doThrow(new ValidationException("a field", "invalid")).when(descriptionValidatorMock) - .validateNewDescription(description); + doThrow(new ValidationException("a field", "invalid")) + .when(descriptionValidatorMock) + .validateNewDescription(description); when(descriptionAuthMock.canCreate(description)).thenReturn(true); // Call the method and check that DAO is not called @@ -218,10 +231,12 @@ private void testSave(Description description, Exception indexerException) { when(storeDaoMock.findByName(STORE_NAME)).thenReturn(store); when(descriptionAuthMock.canCreate(description)).thenReturn(true); when(descriptionDaoMock.findByNameAndStore(STORE_NAME, NAME)) - .thenReturn(descriptionWithId); + .thenReturn(descriptionWithId); if (indexerException != null) { - doThrow(indexerException).when(rdfIndexerMock).indexOrUpdateService(description); + + doThrow(indexerException).when(rdfIndexerMock) + .indexOrUpdateService(description); } descriptionBo.save(STORE_NAME, description); @@ -264,8 +279,9 @@ private void testSave(Description description, Exception indexerException) { // It should not happen } - // When an exception is thrown rollback is done so the Store is not updated with - // the new description + // When an exception is thrown rollback is done so the Store + // is not updated with the new description + } else { fail("Exception not expected", e); } @@ -277,6 +293,7 @@ private void testSave(Description description, Exception indexerException) { @Test public void testSaveDescriptionNoParsingErros() { + Description description = generateDescription(new ArrayList()); // Save & check @@ -285,6 +302,7 @@ public void testSaveDescriptionNoParsingErros() { @Test public void testSaveDescriptionMalformedUrlException() { + Description description = generateDescription(new ArrayList()); // Save & check @@ -294,12 +312,41 @@ public void testSaveDescriptionMalformedUrlException() { @Test public void testSaveDescriptionJenaException() { + Description description = generateDescription(new ArrayList()); // Save & check testSave(description, new JenaException()); } + + @Test + public void testHtmlIsEscapedWhenCreating() throws Exception { + + Description descriptionWithId = mock(Description.class); + when(descriptionDaoMock.findByNameAndStore(STORE_NAME, NAME)) + .thenReturn(descriptionWithId); + + Store store = mock(Store.class); + when(storeDaoMock.findByName(STORE_NAME)).thenReturn(store); + + String html = ""; + + Description description = mock(Description.class); + when(description.getName()).thenReturn(NAME); + when(description.getDisplayName()).thenReturn(DESCRIPTION_DISPLAY_NAME); + when(description.getComment()).thenReturn(html); + when(descriptionAuthMock.canCreate(description)).thenReturn(true); + + + InOrder order = inOrder(description, storeDaoMock); + + descriptionBo.save(STORE_NAME, description); + + order.verify(description).setComment(HtmlUtils.htmlEscape(html)); + order.verify(storeDaoMock).update(store); + + } /////////////////////////////////////////////////////////////////////////////////////// @@ -313,7 +360,9 @@ private void testUpdateException(String storeName, String descriptionName, try { descriptionBo.update(storeName, descriptionName, updatedDescription); fail("Exception expected"); + } catch (Exception e) { + verify(descriptionDaoMock, never()).update(any(Description.class)); throw e; } @@ -339,8 +388,10 @@ public void testUpdateNotValid() throws Exception { Description updatedDescription = mock(Description.class); // Configure mocks - doReturn(descriptionToUpdate).when(descriptionDaoMock).findByNameAndStore(STORE_NAME, NAME); - doThrow(new ValidationException("a field", "not valid")).when(descriptionValidatorMock) + doReturn(descriptionToUpdate).when(descriptionDaoMock) + .findByNameAndStore(STORE_NAME, NAME); + doThrow(new ValidationException("a field", "not valid")) + .when(descriptionValidatorMock) .validateUpdatedDescription(descriptionToUpdate, updatedDescription); when(descriptionAuthMock.canUpdate(descriptionToUpdate)).thenReturn(true); @@ -350,13 +401,17 @@ public void testUpdateNotValid() throws Exception { @Test public void testUpdateNotAuthorized() throws Exception { + try { + Description descriptionToUpdate = mock(Description.class); Description updatedDescription = mock(Description.class); // Configure mocks - doReturn(descriptionToUpdate).when(descriptionDaoMock).findByNameAndStore(STORE_NAME, NAME); - when(descriptionAuthMock.canUpdate(descriptionToUpdate)).thenReturn(false); + doReturn(descriptionToUpdate).when(descriptionDaoMock) + .findByNameAndStore(STORE_NAME, NAME); + when(descriptionAuthMock.canUpdate(descriptionToUpdate)) + .thenReturn(false); // Execute the function an check that DAO has not been called testUpdateException(STORE_NAME, NAME, updatedDescription); @@ -365,11 +420,14 @@ public void testUpdateNotAuthorized() throws Exception { failBecauseExceptionWasNotThrown(NotAuthorizedException.class); } catch (NotAuthorizedException ex) { - assertThat(ex.getMessage()).isEqualTo(String.format(NOT_AUTHORIZED_BASE, "update description")); + + assertThat(ex.getMessage()).isEqualTo(String.format( + NOT_AUTHORIZED_BASE, "update description")); } } private void testUpdateDescriptionField(Description newDescription) { + try { User user = mock(User.class); @@ -378,8 +436,10 @@ private void testUpdateDescriptionField(Description newDescription) { // Mock doReturn(user).when(userBoMock).getCurrentUser(); - doReturn(description).when(descriptionDaoMock).findByNameAndStore(STORE_NAME, NAME); - when(descriptionAuthMock.canUpdate(description)).thenReturn(true); + doReturn(description).when(descriptionDaoMock) + .findByNameAndStore(STORE_NAME, NAME); + when(descriptionAuthMock.canUpdate(description)) + .thenReturn(true); // Get the String previousName = description.getName(); @@ -394,10 +454,12 @@ private void testUpdateDescriptionField(Description newDescription) { assertThat(description.getName()).isEqualTo(previousName); // New values - String newStoreName = newDescription.getName() != null ? newDescription.getName() : description.getName(); + String newStoreName = newDescription.getName() != null ? + newDescription.getName() : description.getName(); assertThat(description.getName()).isEqualTo(newStoreName); - String newStoreUrl = newDescription.getUrl() != null ? newDescription.getUrl() : description.getUrl(); + String newStoreUrl = newDescription.getUrl() != null ? + newDescription.getUrl() : description.getUrl(); assertThat(description.getUrl()).isEqualTo(newStoreUrl); String newStoreDescription = newDescription.getComment() != null ? @@ -405,7 +467,7 @@ private void testUpdateDescriptionField(Description newDescription) { assertThat(description.getComment()).isEqualTo(newStoreDescription); } catch (Exception ex) { - ex.printStackTrace(); + // It's not supposed to happen fail("Exception " + ex + " is not supposed to happen"); } @@ -413,22 +475,28 @@ private void testUpdateDescriptionField(Description newDescription) { @Test public void testUpdateDescriptionName() { + Description newDescription = new Description(); newDescription.setDisplayName("new_name"); + testUpdateDescriptionField(newDescription); } @Test public void testUpdateDescriptionUrl() { + Description newDescription = new Description(); newDescription.setUrl(DESCRIPTION_URL + "a"); + testUpdateDescriptionField(newDescription); } @Test public void testUpdateDescriptionDescription() { + Description newDescription = new Description(); newDescription.setComment("New Description"); + testUpdateDescriptionField(newDescription); } @@ -452,8 +520,9 @@ private void testUpdateDescriptionURL(String storedOfferingURI, String newOfferi // Create the description stored in the Database Description storedDescription = generateDescription(new ArrayList()); - Offering storedOffering = generateOffering(storedOfferingURI, storedDescription, "offering-1", - "Offering 1", "Example Description", "http://marketplace.com/link_to_img.jpg", "1.0"); + Offering storedOffering = generateOffering(storedOfferingURI, + storedDescription, "offering-1", "Offering 1", "Example Description", + "http://marketplace.com/link_to_img.jpg", "1.0"); storedOffering.setId(1); // Stored offerings contain an ID storedDescription.addOffering(storedOffering); @@ -462,17 +531,21 @@ private void testUpdateDescriptionURL(String storedOfferingURI, String newOfferi Description updatedDescription = generateDescription(new ArrayList()); // Descriptions returned by offeringResolver when the updatedDescription is parsed - Offering newOffering = generateOffering(newOfferingURI, storedDescription, "cool-offering", - "Cool Offering", "New Description", "http://marketplace.com/link_to_new_img.jpg", "1.2"); + Offering newOffering = generateOffering(newOfferingURI, storedDescription, + "cool-offering", "Cool Offering", "New Description", + "http://marketplace.com/link_to_new_img.jpg", "1.2"); List newOfferings = new ArrayList(); newOfferings.add(newOffering); // Configure the mocks - doReturn(storedDescription).when(descriptionDaoMock).findByNameAndStore(STORE_NAME, NAME); - when(descriptionAuthMock.canUpdate(storedDescription)).thenReturn(true); // User can update - when(offeringResolverMock.resolveOfferingsFromServiceDescription(storedDescription)) - .thenReturn(newOfferings); + doReturn(storedDescription).when(descriptionDaoMock) + .findByNameAndStore(STORE_NAME, NAME); + when(descriptionAuthMock.canUpdate(storedDescription)) + .thenReturn(true); // User can update + when(offeringResolverMock + .resolveOfferingsFromServiceDescription(storedDescription)) + .thenReturn(newOfferings); // Call the method descriptionBo.update(STORE_NAME, NAME, updatedDescription); @@ -494,20 +567,25 @@ private void testUpdateDescriptionURL(String storedOfferingURI, String newOfferi compareOfferings(updatedOffering, newOffering); } catch (Exception ex) { + fail("Exception not expected", ex); } } @Test public void testUpdateDescriptionOfferingExist() throws Exception { + String offeringURI = "http://store.lab.fiware.org/OFFERING_URI"; + testUpdateDescriptionURL(offeringURI, offeringURI); } @Test public void testUpdateDescriptionOfferingNotExist() throws Exception { + String storedOfferingURI = "http://store.lab.fiware.org/OFFERING_URI"; String newOfferingURI = "http://store.lab.fiware.org/NEW_OFFERING_URI"; + testUpdateDescriptionURL(storedOfferingURI, newOfferingURI); } @@ -522,11 +600,13 @@ public void testUpdateComplexOffering() throws Exception { Description storedDescription = generateDescription(new ArrayList()); // Create the offering that will be included into the description - Offering storedOffering = generateOffering(repeatedOfferingURI, storedDescription, "offering-1", - "Offering 1", "Example Description", "http://marketplace.com/link_to_img.jpg", "1.0"); + Offering storedOffering = generateOffering(repeatedOfferingURI, storedDescription, + "offering-1", "Offering 1", "Example Description", + "http://marketplace.com/link_to_img.jpg", "1.0"); storedOffering.setId(1); // Stored offerings contains an ID - // Add two categories... One should be deleted because it won't be included in the new offerings + // Add two categories... One should be deleted because it won't + // be included in the new offerings final Category catA = generateCategory("CATEGORY_A"); final Category catB = generateCategory("CATEGORY_B"); Set categoriesOldOffering = new HashSet(); @@ -534,7 +614,8 @@ public void testUpdateComplexOffering() throws Exception { categoriesOldOffering.add(catB); storedOffering.setCategories(categoriesOldOffering); - // Add two services... One should be deleted because it won't be included in the new offerings + // Add two services... One should be deleted because it won't + // be included in the new offerings final Service serA = generateService("uri1"); final Service serB = generateService("uri2"); Set servicesOldOffering = new HashSet(); @@ -549,10 +630,12 @@ public void testUpdateComplexOffering() throws Exception { Description updatedDescription = generateDescription(new ArrayList()); // Offerings contained in the new URL - Offering repeatedOffering = generateOffering(repeatedOfferingURI, storedDescription, "cool-offering", - "Cool Offering", "New Description", "http://marketplace.com/link_to_new_img.jpg", "1.2"); - Offering newOffering = generateOffering(nonRepeatedOfferingURI, storedDescription, "my-new-offering", - "My New Offering", "New Description 2", "http://marketplace.com/link_to_new_img2.jpg", "1.1"); + Offering repeatedOffering = generateOffering(repeatedOfferingURI, storedDescription, + "cool-offering", "Cool Offering", "New Description", + "http://marketplace.com/link_to_new_img.jpg", "1.2"); + Offering newOffering = generateOffering(nonRepeatedOfferingURI, storedDescription, + "my-new-offering", "My New Offering", "New Description 2", + "http://marketplace.com/link_to_new_img2.jpg", "1.1"); // Set one price plan for the repeated offering PricePlan pricePlan = new PricePlan(); @@ -647,9 +730,12 @@ private void testUpdateRdfError(Exception indexerException) { try { // Configure mocks - doReturn(storedDescription).when(descriptionDaoMock).findByNameAndStore(STORE_NAME, NAME); - when(descriptionAuthMock.canUpdate(storedDescription)).thenReturn(true); // User can update - doThrow(indexerException).when(rdfIndexerMock).indexOrUpdateService(storedDescription); + doReturn(storedDescription).when(descriptionDaoMock) + .findByNameAndStore(STORE_NAME, NAME); + when(descriptionAuthMock.canUpdate(storedDescription)) + .thenReturn(true); // User can update + doThrow(indexerException).when(rdfIndexerMock) + .indexOrUpdateService(storedDescription); // Call the method descriptionBo.update(STORE_NAME, NAME, updatedDescription); @@ -677,26 +763,57 @@ private void testUpdateRdfError(Exception indexerException) { assertThat(ex.getMessage()).isEqualTo(expectedMessage); } catch (Exception ex) { + fail("Exception not expected", ex); } } @Test public void testUpdateJenaException() { + testUpdateRdfError(new JenaException()); } @Test public void testUpdateMalformedURLException() { + testUpdateRdfError(new MalformedURLException()); } + @Test + public void testHtmlIsEscapedWhenUpdating() throws Exception { + + String html = ""; + + Description updatedDescription = mock(Description.class); + when(updatedDescription.getComment()).thenReturn(html); + + Description descriptionToBeUpdated = mock(Description.class); + + // Mock + doReturn(descriptionToBeUpdated).when(descriptionDaoMock) + .findByNameAndStore(STORE_NAME, NAME); + when(descriptionAuthMock.canUpdate(descriptionToBeUpdated)) + .thenReturn(true); + + InOrder order = inOrder(descriptionToBeUpdated, descriptionDaoMock); + + // Call the method + descriptionBo.update(STORE_NAME, NAME, updatedDescription); + + // Verify that the html has been escaped before inserting it + // in the database + order.verify(descriptionToBeUpdated).setComment(HtmlUtils.htmlEscape(html)); + order.verify(descriptionDaoMock).update(descriptionToBeUpdated); + + } /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////// DELETE //////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// - private void testDeleteException(String storeName, String descriptionName) throws Exception { + private void testDeleteException(String storeName, + String descriptionName) throws Exception { Store store = mock(Store.class); doReturn(store).when(storeDaoMock).findByName(storeName); @@ -716,8 +833,10 @@ private void testDeleteException(String storeName, String descriptionName) throw } private void testDeleteDescriptionNotFoundException(Exception ex) throws Exception { + String storeName = "store"; String descriptionName = "description"; + doThrow(ex).when(descriptionDaoMock).findByNameAndStore(storeName, descriptionName); testDeleteException(storeName, descriptionName); @@ -725,21 +844,26 @@ private void testDeleteDescriptionNotFoundException(Exception ex) throws Excepti @Test(expected=DescriptionNotFoundException.class) public void testDeleteDescriptionDescriptionNotFoundException() throws Exception { + testDeleteDescriptionNotFoundException(new DescriptionNotFoundException("descriptionNotFound")); } @Test(expected=StoreNotFoundException.class) public void testDeleteDescriptionStoreNotFoundException() throws Exception { + testDeleteDescriptionNotFoundException(new StoreNotFoundException("descriptionNotFound")); } @Test public void testDeleteNotAuthorizedException() throws Exception { + try { + Description description = mock(Description.class); String storeName = "store"; String descriptionName = "description"; + doReturn(description).when(descriptionDaoMock).findByNameAndStore(storeName, descriptionName); when(descriptionAuthMock.canGet(description)).thenReturn(true); when(descriptionAuthMock.canDelete(description)).thenReturn(false); @@ -748,8 +872,11 @@ public void testDeleteNotAuthorizedException() throws Exception { // If the exception is not risen, the method is not properly working failBecauseExceptionWasNotThrown(NotAuthorizedException.class); + } catch (NotAuthorizedException ex) { - assertThat(ex.getMessage()).isEqualTo(String.format(NOT_AUTHORIZED_BASE, "delete description")); + + assertThat(ex.getMessage()).isEqualTo(String.format( + NOT_AUTHORIZED_BASE, "delete description")); } @@ -761,7 +888,8 @@ public void testDelete() throws Exception { Description description = new Description(); Store store = mock(Store.class); - Offering offering = generateOffering("uri1", description, "offering1", "Offering 1", "DESC", "uri2", "1.0"); + Offering offering = generateOffering("uri1", description, "offering1", + "Offering 1", "DESC", "uri2", "1.0"); // Add two categories... One should be deleted because it won't be included in other offerings final Category catA = generateCategory("CATEGORY_A"); @@ -786,7 +914,8 @@ public void testDelete() throws Exception { String storeName = "store"; String descriptionName = "description"; doReturn(store).when(storeDaoMock).findByName(storeName); - when(descriptionDaoMock.findByNameAndStore(storeName, descriptionName)).thenReturn(description); + when(descriptionDaoMock.findByNameAndStore(storeName, descriptionName)) + .thenReturn(description); when(descriptionAuthMock.canGet(description)).thenReturn(true); when(descriptionAuthMock.canDelete(description)).thenReturn(true); @@ -834,6 +963,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable { /////////////////////////////////////////////////////////////////////////////////////// private void testFindByNameNotFoundException(Exception ex) throws Exception { + String storeName = "store"; String descriptionName = "description"; doThrow(ex).when(descriptionDaoMock).findByNameAndStore(storeName, descriptionName); @@ -843,32 +973,38 @@ private void testFindByNameNotFoundException(Exception ex) throws Exception { @Test(expected=DescriptionNotFoundException.class) public void testFindByNameDescriptionNotFoundException() throws Exception { + testFindByNameNotFoundException(new DescriptionNotFoundException("description not found")); } @Test(expected=StoreNotFoundException.class) public void testFindByNameStorenNotFoundException() throws Exception { + testFindByNameNotFoundException(new StoreNotFoundException("store not found")); } private void testFindByStoreAndName(boolean authorized) throws Exception { + String storeName = "store"; String descriptionName = "descriptionName"; Description description = mock(Description.class); // Set up mocks - when(descriptionDaoMock.findByNameAndStore(storeName, descriptionName)).thenReturn(description); + when(descriptionDaoMock.findByNameAndStore(storeName, descriptionName)) + .thenReturn(description); when(descriptionAuthMock.canGet(description)).thenReturn(authorized); // Call the function try { - Description returnedDescription = descriptionBo.findByNameAndStore(storeName, descriptionName); + Description returnedDescription = descriptionBo + .findByNameAndStore(storeName, descriptionName); // If an exception is risen, this check is not executed assertThat(returnedDescription).isEqualTo(description); + } catch (Exception ex) { throw ex; } @@ -878,17 +1014,23 @@ private void testFindByStoreAndName(boolean authorized) throws Exception { public void testFinByNameNotAuthorized() throws Exception{ try { + testFindByStoreAndName(false); + // If the exception is not risen, the method is not properly working failBecauseExceptionWasNotThrown(NotAuthorizedException.class); + } catch (NotAuthorizedException ex) { - assertThat(ex.getMessage()).isEqualTo(String.format(NOT_AUTHORIZED_BASE, "find description")); + + assertThat(ex.getMessage()).isEqualTo(String.format( + NOT_AUTHORIZED_BASE, "find description")); } } @Test public void testFindByName() throws Exception { + testFindByStoreAndName(true); } @@ -899,13 +1041,16 @@ public void testFindByName() throws Exception { @Test(expected=DescriptionNotFoundException.class) public void testFindByIDDescriptionNotFoundException() throws Exception { + int id = 2; - doThrow(new DescriptionNotFoundException("not found")).when(descriptionDaoMock).findById(id); + doThrow(new DescriptionNotFoundException("not found")) + .when(descriptionDaoMock).findById(id); descriptionBo.findById(id); } private void testFindById(boolean authorized) throws Exception { + int id = 2; Description description = mock(Description.class); @@ -929,10 +1074,14 @@ private void testFindById(boolean authorized) throws Exception { public void testFinByIdNotAuthorized() throws Exception{ try { + testFindById(false); + // If the exception is not risen, the method is not properly working failBecauseExceptionWasNotThrown(NotAuthorizedException.class); + } catch (NotAuthorizedException ex) { + assertThat(ex.getMessage()).isEqualTo(String.format(NOT_AUTHORIZED_BASE, "find description")); } @@ -940,6 +1089,7 @@ public void testFinByIdNotAuthorized() throws Exception{ @Test public void testFindById() throws Exception { + testFindById(true); } @@ -981,7 +1131,6 @@ public void testGetCurrentUserDescriptions() throws Exception { @Test public void testGetAllDescriptions() throws Exception { - @SuppressWarnings("unchecked") List descriptions = mock(List.class); @@ -1059,6 +1208,7 @@ public void testGetDescriptionsPageNotAuthorized() throws Exception { failBecauseExceptionWasNotThrown(NotAuthorizedException.class); } catch (NotAuthorizedException ex) { + // Check exception message assertThat(ex.getMessage()).isEqualTo(String.format(NOT_AUTHORIZED_BASE, "list descriptions")); } @@ -1072,7 +1222,6 @@ public void testGetDescriptionsPageNotAuthorized() throws Exception { @Test public void testGetStoreDescriptions() throws Exception { - @SuppressWarnings("unchecked") List descriptions = mock(List.class); Store store = mock(Store.class); @@ -1112,6 +1261,7 @@ public void testGetStoreDescriptionsNotAuthorized() throws Exception { failBecauseExceptionWasNotThrown(NotAuthorizedException.class); } catch (NotAuthorizedException ex) { + // Check exception message assertThat(ex.getMessage()).isEqualTo(String.format(NOT_AUTHORIZED_BASE, "list descriptions in store " + storeName)); @@ -1126,7 +1276,6 @@ public void testGetStoreDescriptionsNotAuthorized() throws Exception { @Test public void testGetStoreDescriptionspAGE() throws Exception { - @SuppressWarnings("unchecked") List descriptions = mock(List.class); Store store = mock(Store.class); From d0ed6f391ac2dca90cb3047b4cbab7412a1e2ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20Mag=C3=A1n?= Date: Fri, 8 Jan 2016 16:34:40 +0100 Subject: [PATCH 7/7] Test to check that URIs are escaped --- .../helpers/OfferingResolverTest.java | 72 ++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java b/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java index 40509c2..de77db5 100644 --- a/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java +++ b/src/test/java/org/fiware/apps/marketplace/helpers/OfferingResolverTest.java @@ -63,6 +63,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.web.util.HtmlUtils; import com.hp.hpl.jena.shared.JenaException; @@ -77,6 +78,7 @@ public class OfferingResolverTest { @Before public void setUp() { + MockitoAnnotations.initMocks(this); this.offeringResolver = spy(offeringResolver); @@ -102,11 +104,13 @@ private void checkOfferingBasic(Offering offering, String offeringName, String t } private void checkPricePlan(PricePlan pricePlan, String title, String description) { + assertThat(pricePlan.getTitle()).isEqualTo(title); assertThat(pricePlan.getComment()).isEqualTo(description); } private void checkService(Service service, String title, String description) { + assertThat(service.getDisplayName()).isEqualTo(title); assertThat(service.getComment()).isEqualTo(description); } @@ -128,6 +132,7 @@ private void checkPricePlanInSet(Set pricePlans, String title, String } private void checkServiceInSet(Set services, String displayName, String description) { + boolean found = false; Iterator iterator = services.iterator(); @@ -142,8 +147,9 @@ private void checkServiceInSet(Set services, String displayName, String assertThat(found).isTrue(); } - private void checkPriceComponent(PriceComponent priceComponent, String currency, String title, String unit, - float value) { + private void checkPriceComponent(PriceComponent priceComponent, String currency, + String title, String unit, float value) { + assertThat(priceComponent.getCurrency()).isEqualTo(currency); assertThat(priceComponent.getTitle()).isEqualTo(title); assertThat(priceComponent.getUnit()).isEqualTo(unit); @@ -252,6 +258,7 @@ private void initPricePlan(String offeringUri, String title, String description, } private void initPricePlan(String offeringUri, String title, String description) { + initPricePlan(offeringUri, title, description, new ArrayList()); } @@ -267,17 +274,22 @@ private void initService(String offeringUri, String serviceUri, String title, St servicesUris.add(contexServiceUri); try { + if (existingService) { + Service service = new Service(); service.setDisplayName(title); service.setComment(description); service.setUri(serviceUri); Set classifications = new HashSet<>(); service.setCategories(classifications); + when(serviceBoMock.findByURI(serviceUri)).thenReturn(service); + } else { doThrow(new ServiceNotFoundException("service not found")).when(serviceBoMock).findByURI(serviceUri); } + } catch (ServiceNotFoundException e) { fail("Exception not expected", e); // Not expected... @@ -439,6 +451,7 @@ public void testDescriptionWithTwoOfferings() { public void testOfferingWithTwoPricePlans() { try { + String offeringTitle = "cool offering"; String offeringUri = "https://store.lab.fiware.org/offerings/offering1"; String offeringDesc = "a very long long description for the best offering"; @@ -473,7 +486,9 @@ public void testOfferingWithTwoPricePlans() { } private void testOfferingWithTwoServices(boolean existingService) { + try { + String offeringTitle = "cool offering"; String offeringUri = "https://store.lab.fiware.org/offerings/offering1"; String offeringDesc = "a very long long description for the best offering"; @@ -523,6 +538,7 @@ private void testOfferingWithTwoClassifications(List classifications, boolean existingClassification) { try { + String offeringTitle = "cool offering"; String offeringUri = "https://store.lab.fiware.org/offerings/offering1"; String offeringDesc = "a very long long description for the best offering"; @@ -566,6 +582,7 @@ private void testOfferingWithTwoClassifications(List classifications, @Test public void testOfferingTwoClassificationsDiffClassificationsNonExisting() { + // displayName == name String classification1 = "class1"; String classification2 = "class2"; @@ -579,6 +596,7 @@ public void testOfferingTwoClassificationsDiffClassificationsNonExisting() { @Test public void testOfferingTwoClassificationsDiffClassificationsExisting() { + // displayName == name String classification1 = "class1"; String classification2 = "class2"; @@ -592,6 +610,7 @@ public void testOfferingTwoClassificationsDiffClassificationsExisting() { @Test public void testOfferingTwoClassificationsSameClassificationsNonExisting() { + // displayName == name String classification = "class1"; @@ -604,6 +623,7 @@ public void testOfferingTwoClassificationsSameClassificationsNonExisting() { @Test public void testOfferingTwoClassificationsSameClassificationsExisting() { + // displayName == name String classification = "class1"; @@ -615,6 +635,7 @@ public void testOfferingTwoClassificationsSameClassificationsExisting() { } private void testException(Exception exception, String expectedMessage) { + // Configure mock try { doThrow(exception).when(offeringResolver).getRdfHelper(any(Description.class)); @@ -634,16 +655,19 @@ private void testException(Exception exception, String expectedMessage) { @Test public void testUSDLNotFound() { + testException(new FileNotFoundException(), "The file does not exist"); } @Test public void testHostUnreachable() { + testException(new ConnectException(), "The host cannot be reached"); } @Test public void testInvalidRDF() { + testException(new JenaException(), "The file does not contains a valid USDL file"); } @@ -667,22 +691,28 @@ private void testOfferingInvalid(String url, String title, String version, Strin @Test public void testOfferingNameNotFound() { + String url = "http://fiware.org"; + testOfferingInvalid(url, "", "", "", "", "Name for entity " + url + " cannot be retrieved"); } @Test public void testOfferingVersionNotFound() { + String url = "http://fiware.org"; String offeringName = "Offering Name"; + testOfferingInvalid(url, offeringName, "", "", "", "Version for offering " + offeringName + " cannot be retrieved"); } @Test public void testOfferingImageURLNotFound() { + String url = "http://fiware.org"; String offeringName = "Offering Name"; + testOfferingInvalid(url, offeringName, "1.0", "", "", "Image URL for offering " + offeringName + " cannot be retrieved"); } @@ -718,12 +748,14 @@ private void testOfferingPricePlanInvalid(Map> pricePlan, S @Test public void testOfferingPricePlanNameNotIncluded() { + testOfferingPricePlanInvalid(new HashMap>(), "Offering %s contains a price plan " + "without title"); } @Test public void testOfferingPricePlanNameEmpty() { + // Configure price plan Map> pricePlan = new HashMap>(); List titles = new ArrayList<>(); @@ -735,6 +767,7 @@ public void testOfferingPricePlanNameEmpty() { @Test public void testOfferingPricePlanNameBlank() { + // Configure price plan Map> pricePlan = new HashMap>(); List titles = new ArrayList<>(); @@ -746,6 +779,7 @@ public void testOfferingPricePlanNameBlank() { } private void testOfferingPriceComponentInvalid(Map> priceComponent, String message) { + // Configure price plan Map> pricePlan = new HashMap>(); @@ -763,12 +797,14 @@ private void testOfferingPriceComponentInvalid(Map> priceCo @Test public void testOfferingPriceComponentLabelMissing() { + testOfferingPriceComponentInvalid(new HashMap>(), "Offering %s contains a price " + "component without title"); } @Test public void testOfferingPriceComponentLabelEmpty() { + // Configure price component Map> priceComponent = new HashMap<>(); List labels = new ArrayList<>(); @@ -780,6 +816,7 @@ public void testOfferingPriceComponentLabelEmpty() { @Test public void testOfferingPriceComponentLabelBkank() { + Map> priceComponent = new HashMap<>(); List labels = new ArrayList<>(); labels.add(""); @@ -791,6 +828,7 @@ public void testOfferingPriceComponentLabelBkank() { @Test public void testOfferingPriceComponentSpecificationMissing() { + Map> priceComponent = new HashMap<>(); List labels = new ArrayList<>(); labels.add("a"); @@ -803,6 +841,7 @@ public void testOfferingPriceComponentSpecificationMissing() { @Test public void testOfferingPriceComponentSpecificationEmpty() { + Map> priceComponent = new HashMap<>(); List labels = new ArrayList<>(); labels.add("a"); @@ -837,18 +876,21 @@ private void testOfferingPriceComponentInvalidSpecification(List currenc @Test public void testOfferingPriceComponentCurrencyMissing() { + testOfferingPriceComponentInvalidSpecification(null, null, null, "Offering %s contains a price component without currency"); } @Test public void testOfferingPriceComponentEmptyCurrency() { + testOfferingPriceComponentInvalidSpecification(new ArrayList<>(), null, null, "Offering %s contains a price component without currency"); } @Test public void testOfferingPriceComponentBlankCurrency() { + List currencies = new ArrayList<>(); currencies.add(""); @@ -858,6 +900,7 @@ public void testOfferingPriceComponentBlankCurrency() { @Test public void testOfferingPriceComponentMissingUnit() { + List currencies = new ArrayList<>(); currencies.add("EUR"); @@ -867,6 +910,7 @@ public void testOfferingPriceComponentMissingUnit() { @Test public void testOfferingPriceComponentEmptyUnit() { + List currencies = new ArrayList<>(); currencies.add("EUR"); @@ -876,6 +920,7 @@ public void testOfferingPriceComponentEmptyUnit() { @Test public void testOfferingPriceComponentBlankUnit() { + List currencies = new ArrayList<>(); currencies.add("EUR"); List units = new ArrayList<>(); @@ -887,6 +932,7 @@ public void testOfferingPriceComponentBlankUnit() { @Test public void testOfferingPriceComponentValueMissing() { + List currencies = new ArrayList<>(); currencies.add("EUR"); List units = new ArrayList<>(); @@ -898,6 +944,7 @@ public void testOfferingPriceComponentValueMissing() { @Test public void testOfferingPriceComponentValueEmpty() { + List currencies = new ArrayList<>(); currencies.add("EUR"); List units = new ArrayList<>(); @@ -909,6 +956,7 @@ public void testOfferingPriceComponentValueEmpty() { @Test public void testOfferingPriceComponentValueBlank() { + List currencies = new ArrayList<>(); currencies.add("EUR"); List units = new ArrayList<>(); @@ -922,6 +970,7 @@ public void testOfferingPriceComponentValueBlank() { @Test public void testOfferingPriceComponentInvalidValue() { + List currencies = new ArrayList<>(); currencies.add("EUR"); List units = new ArrayList<>(); @@ -948,4 +997,23 @@ public void testEmptyDescription() { assertThat(ex.getMessage()).isEqualTo("Offerings URLs cannot be retrieved"); } } + + @Test + public void testUrisAreEscaped() throws ParseException { + + String offeringUri = ""; + + initOffering(offeringUri, "offering", "desc", "1.0", + "https://store.lab.fiware.org/static/img1.png", + "http://store.lab.fiware.org/offering/user/offering/1.0"); + + Description description = mock(Description.class); + when(description.getUrl()).thenReturn(DESCRIPTION_URI); + + List offerings = offeringResolver.resolveOfferingsFromServiceDescription(description); + + assertThat(offerings).hasSize(1); + assertThat(offerings.get(0).getUri()).isEqualTo(HtmlUtils.htmlEscape(offeringUri)); + + } }