#37 Added eBay data src, updated context + tests
This commit is contained in:
@@ -8,6 +8,7 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import de.rwu.easydrop.api.dto.ProductDTO;
|
import de.rwu.easydrop.api.dto.ProductDTO;
|
||||||
|
import de.rwu.easydrop.exception.DataSourceException;
|
||||||
import de.rwu.easydrop.util.FormattingUtil;
|
import de.rwu.easydrop.util.FormattingUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +39,7 @@ public abstract class AbstractDataSource implements DataSource {
|
|||||||
* @param json Product data
|
* @param json Product data
|
||||||
* @return Finished ProductDTO
|
* @return Finished ProductDTO
|
||||||
*/
|
*/
|
||||||
public abstract ProductDTO buildProductDTO(ProductDTO product, String json);
|
protected abstract ProductDTO buildProductDTO(ProductDTO product, String json);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridable standard implementation.
|
* Overridable standard implementation.
|
||||||
@@ -64,7 +65,7 @@ public abstract class AbstractDataSource implements DataSource {
|
|||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException(
|
throw new DataSourceException(
|
||||||
"Nothing found: "
|
"Nothing found: "
|
||||||
+ dataOrigin
|
+ dataOrigin
|
||||||
+ " API responded with error code "
|
+ " API responded with error code "
|
||||||
@@ -79,7 +80,7 @@ public abstract class AbstractDataSource implements DataSource {
|
|||||||
|
|
||||||
buildProductDTO(product, response.toString());
|
buildProductDTO(product, response.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalArgumentException(
|
throw new DataSourceException(
|
||||||
"Couldn't fulfill "
|
"Couldn't fulfill "
|
||||||
+ dataOrigin
|
+ dataOrigin
|
||||||
+ " API request");
|
+ " API request");
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public final class AmazonProductDataSource extends AbstractDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProductDTO buildProductDTO(final ProductDTO product, final String json) {
|
protected ProductDTO buildProductDTO(final ProductDTO product, final String json) {
|
||||||
String root = "$.featuredOffer.";
|
String root = "$.featuredOffer.";
|
||||||
ReadContext ctx = JsonPath.parse(json);
|
ReadContext ctx = JsonPath.parse(json);
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ public final class AmazonProductDataSource extends AbstractDataSource {
|
|||||||
* @param productId ASIN
|
* @param productId ASIN
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public URL createApiUrl(final String productId) throws MalformedURLException {
|
protected URL createApiUrl(final String productId) throws MalformedURLException {
|
||||||
return new URL(baseUrl
|
return new URL(baseUrl
|
||||||
+ "/products/2020-08-26/products/"
|
+ "/products/2020-08-26/products/"
|
||||||
+ productId
|
+ productId
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ public final class EbayItemDataSource extends AbstractDataSource {
|
|||||||
* @param searchQuery Exact product name or other valid identifier.
|
* @param searchQuery Exact product name or other valid identifier.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public URL createApiUrl(final String searchQuery) throws MalformedURLException {
|
protected URL createApiUrl(final String searchQuery) throws MalformedURLException {
|
||||||
return new URL(baseUrl
|
return new URL(baseUrl
|
||||||
+ "/buy/browse/v1/item_summary/search?q="
|
+ "/buy/browse/v1/item_summary/search?q="
|
||||||
+ searchQuery
|
+ searchQuery
|
||||||
@@ -57,7 +57,7 @@ public final class EbayItemDataSource extends AbstractDataSource {
|
|||||||
* @param json Product data
|
* @param json Product data
|
||||||
* @return Finished ProductDTO
|
* @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].";
|
String root = "$.itemSummaries[0].";
|
||||||
ReadContext ctx = JsonPath.parse(json);
|
ReadContext ctx = JsonPath.parse(json);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Contains EasyDrop-related custom exceptions.
|
||||||
|
*
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
package de.rwu.easydrop.exception;
|
||||||
@@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import de.rwu.easydrop.api.dto.ProductDTO;
|
import de.rwu.easydrop.api.dto.ProductDTO;
|
||||||
|
import de.rwu.easydrop.exception.DataSourceException;
|
||||||
|
|
||||||
class AmazonProductDataSourceTest {
|
class AmazonProductDataSourceTest {
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ class AmazonProductDataSourceTest {
|
|||||||
when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_NOT_FOUND);
|
when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_NOT_FOUND);
|
||||||
|
|
||||||
// Invoke the method and verify the exception
|
// Invoke the method and verify the exception
|
||||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
DataSourceException exception = assertThrows(DataSourceException.class, () -> {
|
||||||
dataSource.getProductDTOById(demoProductId);
|
dataSource.getProductDTOById(demoProductId);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -181,7 +182,7 @@ class AmazonProductDataSourceTest {
|
|||||||
when(mockConnection.getInputStream()).thenThrow(new IOException());
|
when(mockConnection.getInputStream()).thenThrow(new IOException());
|
||||||
|
|
||||||
// Invoke the method and verify the exception
|
// Invoke the method and verify the exception
|
||||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
DataSourceException exception = assertThrows(DataSourceException.class, () -> {
|
||||||
dataSource.getProductDTOById(demoProductId);
|
dataSource.getProductDTOById(demoProductId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
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.lang.reflect.Field;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
@@ -12,10 +17,8 @@ import org.junit.jupiter.api.BeforeEach;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.MockitoAnnotations;
|
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.api.dto.ProductDTO;
|
||||||
|
import de.rwu.easydrop.exception.DataSourceException;
|
||||||
|
|
||||||
class EbayItemDataSourceTest {
|
class EbayItemDataSourceTest {
|
||||||
private EbayItemDataSource demoDataSource;
|
private EbayItemDataSource demoDataSource;
|
||||||
@@ -51,8 +54,7 @@ class EbayItemDataSourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createApiUrl_ValidSearchQuery_ReturnsValidUrl() throws MalformedURLException {
|
void createApiUrl_ValidSearchQuery_ReturnsValidUrl() throws MalformedURLException {
|
||||||
String searchQuery = demoQuery;
|
URL apiUrl = demoDataSource.createApiUrl(demoQuery);
|
||||||
URL apiUrl = demoDataSource.createApiUrl(searchQuery);
|
|
||||||
|
|
||||||
assertNotNull(apiUrl);
|
assertNotNull(apiUrl);
|
||||||
assertEquals("https://www.example.com/api/buy/browse/v1/item_summary/search?q=iPhone&limit=1&offset=0",
|
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();
|
String apiKey = demoDataSource.getApiKey();
|
||||||
assertEquals(demoApiKey, apiKey);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user