diff --git a/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java b/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java index 9d1df1c..7751c10 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java @@ -8,6 +8,7 @@ import java.net.MalformedURLException; import java.net.URL; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.exception.DataSourceException; import de.rwu.easydrop.util.FormattingUtil; /** @@ -38,7 +39,7 @@ public abstract class AbstractDataSource implements DataSource { * @param json Product data * @return Finished ProductDTO */ - public abstract ProductDTO buildProductDTO(ProductDTO product, String json); + protected abstract ProductDTO buildProductDTO(ProductDTO product, String json); /** * Overridable standard implementation. @@ -64,7 +65,7 @@ public abstract class AbstractDataSource implements DataSource { if (responseCode == HttpURLConnection.HTTP_OK) { reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); } else { - throw new IllegalArgumentException( + throw new DataSourceException( "Nothing found: " + dataOrigin + " API responded with error code " @@ -79,7 +80,7 @@ public abstract class AbstractDataSource implements DataSource { buildProductDTO(product, response.toString()); } catch (IOException e) { - throw new IllegalArgumentException( + throw new DataSourceException( "Couldn't fulfill " + dataOrigin + " API request"); diff --git a/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java b/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java index 5654765..83b758d 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java @@ -48,7 +48,7 @@ public final class AmazonProductDataSource extends AbstractDataSource { } @Override - public ProductDTO buildProductDTO(final ProductDTO product, final String json) { + protected ProductDTO buildProductDTO(final ProductDTO product, final String json) { String root = "$.featuredOffer."; ReadContext ctx = JsonPath.parse(json); @@ -71,7 +71,7 @@ public final class AmazonProductDataSource extends AbstractDataSource { * @param productId ASIN */ @Override - public URL createApiUrl(final String productId) throws MalformedURLException { + protected URL createApiUrl(final String productId) throws MalformedURLException { return new URL(baseUrl + "/products/2020-08-26/products/" + productId diff --git a/src/main/java/de/rwu/easydrop/api/client/DataSourceFactory.java b/src/main/java/de/rwu/easydrop/api/client/DataSourceFactory.java new file mode 100644 index 0000000..ba79ab5 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/api/client/DataSourceFactory.java @@ -0,0 +1,55 @@ +package de.rwu.easydrop.api.client; + +import javax.naming.ConfigurationException; + +import de.rwu.easydrop.util.Config; + +/** + * Factory for Data Sources. + * + * @since 0.2.0 + */ +public class DataSourceFactory { + + /** + * The data source config. + */ + private Config config; + + /** + * @param newConfig the config to set + */ + public void setConfig(final Config newConfig) throws ConfigurationException { + this.config = newConfig; + this.config.loadConfig(); + } + + /** + * @param newConfig + */ + public DataSourceFactory(final Config newConfig) throws ConfigurationException { + this.setConfig(newConfig); + } + + /** + * Creates an Amazon Product Data Source. + * + * @return AmazonProductDataSource + */ + public AmazonProductDataSource createAmazonProductDataSource() { + String apiUrl = config.getProperty("AMAZON_API_URL"); + String apiKey = config.getProperty("AMAZON_API_KEY"); + return new AmazonProductDataSource(apiUrl, apiKey); + } + + /** + * Creates an eBay Item Data Source. + * + * @return EbayItemDataSource + */ + public EbayItemDataSource createEbayItemDataSource() { + String apiUrl = config.getProperty("EBAY_API_URL"); + String apiKey = config.getProperty("EBAY_API_KEY"); + return new EbayItemDataSource(apiUrl, apiKey); + } +} diff --git a/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java b/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java index ee998dc..171b8b9 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java @@ -43,7 +43,7 @@ public final class EbayItemDataSource extends AbstractDataSource { * @param searchQuery Exact product name or other valid identifier. */ @Override - public URL createApiUrl(final String searchQuery) throws MalformedURLException { + protected URL createApiUrl(final String searchQuery) throws MalformedURLException { return new URL(baseUrl + "/buy/browse/v1/item_summary/search?q=" + searchQuery @@ -57,7 +57,7 @@ public final class EbayItemDataSource extends AbstractDataSource { * @param json Product data * @return Finished ProductDTO */ - public ProductDTO buildProductDTO(final ProductDTO product, final String json) { + protected ProductDTO buildProductDTO(final ProductDTO product, final String json) { String root = "$.itemSummaries[0]."; ReadContext ctx = JsonPath.parse(json); diff --git a/src/main/java/de/rwu/easydrop/exception/DataSourceException.java b/src/main/java/de/rwu/easydrop/exception/DataSourceException.java new file mode 100644 index 0000000..0bca4d8 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/exception/DataSourceException.java @@ -0,0 +1,27 @@ +package de.rwu.easydrop.exception; + +/** + * Exception that signifies the data of a Product are invalid. + * + * @since 0.2.0 + */ +public class DataSourceException extends RuntimeException { + /** + * Throws an exception that signifies the data of a Product are invalid. + * + * @param message + */ + public DataSourceException(final String message) { + super(message); + } + + /** + * Throws an exception that signifies the data of a Product are invalid. + * + * @param message + * @param cause + */ + public DataSourceException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/de/rwu/easydrop/exception/InvalidProductException.java b/src/main/java/de/rwu/easydrop/exception/InvalidProductException.java new file mode 100644 index 0000000..d42ba39 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/exception/InvalidProductException.java @@ -0,0 +1,27 @@ +package de.rwu.easydrop.exception; + +/** + * Exception that signifies the data of a Product are invalid. + * + * @since 0.2.0 + */ +public class InvalidProductException extends RuntimeException { + /** + * Throws an exception that signifies the data of a Product are invalid. + * + * @param message + */ + public InvalidProductException(final String message) { + super(message); + } + + /** + * Throws an exception that signifies the data of a Product are invalid. + * + * @param message + * @param cause + */ + public InvalidProductException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/de/rwu/easydrop/exception/package-info.java b/src/main/java/de/rwu/easydrop/exception/package-info.java new file mode 100644 index 0000000..327d7d1 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/exception/package-info.java @@ -0,0 +1,6 @@ +/** + * Contains EasyDrop-related custom exceptions. + * + * @since 0.2.0 + */ +package de.rwu.easydrop.exception; diff --git a/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java b/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java index 22c388a..938413d 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.exception.DataSourceException; class AmazonProductDataSourceTest { @@ -158,7 +159,7 @@ class AmazonProductDataSourceTest { when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_NOT_FOUND); // Invoke the method and verify the exception - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + DataSourceException exception = assertThrows(DataSourceException.class, () -> { dataSource.getProductDTOById(demoProductId); }); @@ -181,7 +182,7 @@ class AmazonProductDataSourceTest { when(mockConnection.getInputStream()).thenThrow(new IOException()); // Invoke the method and verify the exception - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + DataSourceException exception = assertThrows(DataSourceException.class, () -> { dataSource.getProductDTOById(demoProductId); }); diff --git a/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java b/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java new file mode 100644 index 0000000..c84df2a --- /dev/null +++ b/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java @@ -0,0 +1,48 @@ +package de.rwu.easydrop.api.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +import javax.naming.ConfigurationException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import de.rwu.easydrop.util.Config; + +class DataSourceFactoryTest { + @Mock + private Config config; + + private DataSourceFactory dataSourceFactory; + + @BeforeEach + void setUp() throws ConfigurationException { + MockitoAnnotations.openMocks(this); + when(config.getProperty("AMAZON_API_URL")).thenReturn("https://api.amazon.com"); + when(config.getProperty("AMAZON_API_KEY")).thenReturn("amazon-api-key"); + when(config.getProperty("EBAY_API_URL")).thenReturn("https://api.ebay.com"); + when(config.getProperty("EBAY_API_KEY")).thenReturn("ebay-api-key"); + dataSourceFactory = new DataSourceFactory(config); + } + + @Test + void createAmazonProductDataSource_ReturnsAmazonProductDataSource() { + // Act + AmazonProductDataSource dataSource = dataSourceFactory.createAmazonProductDataSource(); + + // Assert + assertEquals("amazon-api-key", dataSource.getApiKey()); + } + + @Test + void createEbayItemDataSource_ReturnsEbayItemDataSource() { + // Act + EbayItemDataSource dataSource = dataSourceFactory.createEbayItemDataSource(); + + // Assert + assertEquals("ebay-api-key", dataSource.getApiKey()); + } +} diff --git a/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java b/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java index 27bcd78..9a6ed45 100644 --- a/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java @@ -2,8 +2,13 @@ package de.rwu.easydrop.api.client; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.io.IOException; import java.lang.reflect.Field; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; @@ -12,10 +17,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.ReadContext; - import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.exception.DataSourceException; class EbayItemDataSourceTest { private EbayItemDataSource demoDataSource; @@ -51,8 +54,7 @@ class EbayItemDataSourceTest { @Test void createApiUrl_ValidSearchQuery_ReturnsValidUrl() throws MalformedURLException { - String searchQuery = demoQuery; - URL apiUrl = demoDataSource.createApiUrl(searchQuery); + URL apiUrl = demoDataSource.createApiUrl(demoQuery); assertNotNull(apiUrl); assertEquals("https://www.example.com/api/buy/browse/v1/item_summary/search?q=iPhone&limit=1&offset=0", @@ -98,4 +100,26 @@ class EbayItemDataSourceTest { String apiKey = demoDataSource.getApiKey(); assertEquals(demoApiKey, apiKey); } + + @Test + void testGetProductDTOById_failedRequest() throws IOException { + // Set up the test environment + + EbayItemDataSource dataSource = mock(EbayItemDataSource.class); + URL mockURL = mock(URL.class); + when(dataSource.getDataOrigin()).thenReturn(demoDataOrigin); + when(dataSource.createApiUrl(demoQuery)).thenReturn(mockURL); + when(dataSource.getProductDTOById(demoQuery)).thenCallRealMethod(); + HttpURLConnection mockConnection = mock(HttpURLConnection.class); + when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_NOT_FOUND); + + // Invoke the method and verify the exception + DataSourceException exception = assertThrows(DataSourceException.class, () -> { + dataSource.getProductDTOById(demoQuery); + }); + + // Verify the exception message + assertEquals("Nothing found: eBay API responded with error code 404", exception.getMessage()); + } } diff --git a/src/test/java/de/rwu/easydrop/exception/DataSourceExceptionTest.java b/src/test/java/de/rwu/easydrop/exception/DataSourceExceptionTest.java new file mode 100644 index 0000000..930e1bc --- /dev/null +++ b/src/test/java/de/rwu/easydrop/exception/DataSourceExceptionTest.java @@ -0,0 +1,61 @@ +package de.rwu.easydrop.exception; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class DataSourceExceptionTest { + + @Test + void constructor_WithMessage_SetsMessage() { + // Arrange + String message = "Data source error"; + + // Act + DataSourceException exception = new DataSourceException(message); + + // Assert + assertEquals(message, exception.getMessage()); + } + + @Test + void constructor_WithMessageAndCause_SetsMessageAndCause() { + // Arrange + String message = "Data source error"; + Throwable cause = new IllegalArgumentException("Invalid argument"); + + // Act + DataSourceException exception = new DataSourceException(message, cause); + + // Assert + assertEquals(message, exception.getMessage()); + assertEquals(cause, exception.getCause()); + } + + @Test + void constructor_WithNullMessage_SetsNullMessage() { + // Act + DataSourceException exception = new DataSourceException(null); + + // Assert + assertEquals(null, exception.getMessage()); + } + + @Test + void constructor_WithNullCause_SetsNullCause() { + // Act + DataSourceException exception = new DataSourceException("Data source error", null); + + // Assert + assertEquals(null, exception.getCause()); + } + + @Test + void throw_DataSourceException() { + // Act and Assert + assertThrows(DataSourceException.class, () -> { + throw new DataSourceException("Data source error"); + }); + } +} diff --git a/src/test/java/de/rwu/easydrop/exception/InvalidProductExceptionTest.java b/src/test/java/de/rwu/easydrop/exception/InvalidProductExceptionTest.java new file mode 100644 index 0000000..478e8e3 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/exception/InvalidProductExceptionTest.java @@ -0,0 +1,61 @@ +package de.rwu.easydrop.exception; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class InvalidProductExceptionTest { + + @Test + void constructor_WithMessage_SetsMessage() { + // Arrange + String message = "Invalid product data"; + + // Act + InvalidProductException exception = new InvalidProductException(message); + + // Assert + assertEquals(message, exception.getMessage()); + } + + @Test + void constructor_WithMessageAndCause_SetsMessageAndCause() { + // Arrange + String message = "Invalid product data"; + Throwable cause = new IllegalArgumentException("Invalid argument"); + + // Act + InvalidProductException exception = new InvalidProductException(message, cause); + + // Assert + assertEquals(message, exception.getMessage()); + assertEquals(cause, exception.getCause()); + } + + @Test + void constructor_WithNullMessage_SetsNullMessage() { + // Act + InvalidProductException exception = new InvalidProductException(null); + + // Assert + assertEquals(null, exception.getMessage()); + } + + @Test + void constructor_WithNullCause_SetsNullCause() { + // Act + InvalidProductException exception = new InvalidProductException("Invalid product data", null); + + // Assert + assertEquals(null, exception.getCause()); + } + + @Test + void throw_InvalidProductException() { + // Act and Assert + assertThrows(InvalidProductException.class, () -> { + throw new InvalidProductException("Invalid product data"); + }); + } +}