From 4c283f5ca639f01a4e63e2943dd6d86bb6a488eb Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Fri, 9 Jun 2023 13:39:05 +0200 Subject: [PATCH 01/49] added general logic for easydrop core --- src/main/java/de/rwu/easydrop/core/Core.java | 34 ++++++++++++ .../de/rwu/easydrop/core/OfferIdentifier.java | 31 +++++++++++ .../rwu/easydrop/core/OfferProvisioner.java | 24 +++++++++ .../de/rwu/easydrop/core/OfferReviewer.java | 23 ++++++++ .../de/rwu/easydrop/core/OfferUpdater.java | 21 ++++++++ .../java/de/rwu/easydrop/model/Offer.java | 52 +++++++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 src/main/java/de/rwu/easydrop/core/Core.java create mode 100644 src/main/java/de/rwu/easydrop/core/OfferIdentifier.java create mode 100644 src/main/java/de/rwu/easydrop/core/OfferProvisioner.java create mode 100644 src/main/java/de/rwu/easydrop/core/OfferReviewer.java create mode 100644 src/main/java/de/rwu/easydrop/core/OfferUpdater.java create mode 100644 src/main/java/de/rwu/easydrop/model/Offer.java diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java new file mode 100644 index 0000000..b242b44 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -0,0 +1,34 @@ +package de.rwu.easydrop.core; + +import java.util.List; +import de.rwu.easydrop.model.Offer; + +public class Core { + + private OfferIdentifier ident; + private OfferProvisioner provis; + private OfferReviewer review; + private OfferUpdater update; + + + public Core(){ + this.ident = new OfferIdentifier(); + this.provis = new OfferProvisioner(); + this.review = new OfferReviewer(); + this.update = new OfferUpdater(); + + } + + + public void runCore(){ + List identifiedOffers = ident.runIdentifier(); + provis.runProvisioner(identifiedOffers); + List updatingOffers = review.runReviewer(); + update.runUpdater(updatingOffers); + + + + } + + +} diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java new file mode 100644 index 0000000..1d20353 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -0,0 +1,31 @@ +package de.rwu.easydrop.core; + +import de.rwu.easydrop.model.Offer; +import java.util.List; +import java.util.ArrayList; + + + +public class OfferIdentifier { + + + + + public OfferIdentifier() { + + } + + public List runIdentifier() { + /* muss die Kataloge durchforsten nach vergleichbaren Produkten auf mehreren Händlerwebseiten (APIs) + * muss Preisermittler als Abhängigkeit für jeden Katalog aufrufen + * erhält dadurch Liste von Produkten, die auf verschiedenen Plattformen eingestellt werden können, gibt diese Liste zurück + * muss Datenbank nach Produktangeboten durchforsten, ob diese Produkte schon eingestellt wurden vom OfferProvisioner + * wenn ja, muss er die Liste um diese Angebote kürzen + * + */ + return new ArrayList(); + + } + + +} diff --git a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java new file mode 100644 index 0000000..3b6f9bb --- /dev/null +++ b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java @@ -0,0 +1,24 @@ +package de.rwu.easydrop.core; + +import de.rwu.easydrop.model.Offer; + +import java.util.List; + +public class OfferProvisioner { + + public OfferProvisioner(/*OfferWriter for database? */) { + + } + + public void runProvisioner(List offersToProvision) { + /* + * Bekommt vom Identifier eine Liste mit Angeboten, die er einstellen soll auf Zielplattformen + * Stellt Angebote bei der Zielplattform ein + * Schreibt eingestellte Angebote in die Datenbank + */ + + + + } + +} diff --git a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java new file mode 100644 index 0000000..f410f41 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java @@ -0,0 +1,23 @@ +package de.rwu.easydrop.core; + +import de.rwu.easydrop.model.Offer; +import java.util.List; +import java.util.ArrayList; + +public class OfferReviewer { + + public OfferReviewer(/*OfferReader/retriever for database? */){ + + } + + public List runReviewer() { + /* + * Liest eingestellte Angebote in der Datenbank + * Prüft Zielplattformen der SourceProducts, ob diese noch verfügbar sind (Issue#12) bzw. ob sie sich im Preis geändert haben + * Gibt Liste zurück von Offers, die geändert werden müssen, wird übergeben an OfferUpdater mit availability true oder false + */ + return new ArrayList(); + + } + +} diff --git a/src/main/java/de/rwu/easydrop/core/OfferUpdater.java b/src/main/java/de/rwu/easydrop/core/OfferUpdater.java new file mode 100644 index 0000000..33091cb --- /dev/null +++ b/src/main/java/de/rwu/easydrop/core/OfferUpdater.java @@ -0,0 +1,21 @@ +package de.rwu.easydrop.core; + +import java.util.List; +import de.rwu.easydrop.model.Offer; + +public class OfferUpdater { + + public OfferUpdater() { + + } + + public void runUpdater(List offersToUpdate) { + /* + * Bekommt vom OfferReviewer eine Liste mit zu ändernden Offers übergeben. + * Bei availability=false löscht der Updater das Angebot aus der Datenbank und von der Zielplattform. + * Der Updater ändert die geänderten Parameter in der Liste in der Datenbank und in der Zielplattform ab. + * Er ändert das upDate in der Datenbank nach der Änderung. + */ + + } +} diff --git a/src/main/java/de/rwu/easydrop/model/Offer.java b/src/main/java/de/rwu/easydrop/model/Offer.java new file mode 100644 index 0000000..f1772d6 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/model/Offer.java @@ -0,0 +1,52 @@ +package de.rwu.easydrop.model; + +import java.util.Date; + + +import lombok.Data; + +/** + * An Offer. + * + * @since 0.3.0 + */ + +@Data +public class Offer { + /* + * The product that our software buys + */ + Product sourceProduct; + + /* + * The product that our software sells + */ + Product saleProduct; + + /* + * Boolean to check if sourceProduct is still available on source website + */ + boolean availability; + + /* + * Date of the creation of the offer + * NOTE: Use Timestamp? https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html + */ + Date creationDate; + + /* + * Date of last update of the offer on the destination website (API) + */ + Date upDate; + + /* + * Date of last check if offer is still valid + */ + Date checkDate; + + + + + + +} From 9906ede6ec578bf83d0864ebbcc73530c6f748c6 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Fri, 9 Jun 2023 13:41:23 +0200 Subject: [PATCH 02/49] added tests for easydrop core --- src/test/java/de/rwu/easydrop/core/CoreTest.java | 10 ++++++++++ .../java/de/rwu/easydrop/core/OfferIdentifierTest.java | 10 ++++++++++ .../de/rwu/easydrop/core/OfferProvisionerTest.java | 10 ++++++++++ .../java/de/rwu/easydrop/core/OfferReviewerTest.java | 10 ++++++++++ .../java/de/rwu/easydrop/core/OfferUpdaterTest.java | 10 ++++++++++ 5 files changed, 50 insertions(+) create mode 100644 src/test/java/de/rwu/easydrop/core/CoreTest.java create mode 100644 src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java create mode 100644 src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java create mode 100644 src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java create mode 100644 src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java diff --git a/src/test/java/de/rwu/easydrop/core/CoreTest.java b/src/test/java/de/rwu/easydrop/core/CoreTest.java new file mode 100644 index 0000000..b81a7ac --- /dev/null +++ b/src/test/java/de/rwu/easydrop/core/CoreTest.java @@ -0,0 +1,10 @@ +package de.rwu.easydrop.core; + +import org.junit.jupiter.api.Test; + +public class CoreTest { + @Test + void testRunCore() { + + } +} diff --git a/src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java b/src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java new file mode 100644 index 0000000..92d7876 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java @@ -0,0 +1,10 @@ +package de.rwu.easydrop.core; + +import org.junit.jupiter.api.Test; + +public class OfferIdentifierTest { + @Test + void testRunIdentifier() { + + } +} diff --git a/src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java b/src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java new file mode 100644 index 0000000..6b3b26a --- /dev/null +++ b/src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java @@ -0,0 +1,10 @@ +package de.rwu.easydrop.core; + +import org.junit.jupiter.api.Test; + +public class OfferProvisionerTest { + @Test + void testRunProvisioner() { + + } +} diff --git a/src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java b/src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java new file mode 100644 index 0000000..9c03f5c --- /dev/null +++ b/src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java @@ -0,0 +1,10 @@ +package de.rwu.easydrop.core; + +import org.junit.jupiter.api.Test; + +public class OfferReviewerTest { + @Test + void testRunReviewer() { + + } +} diff --git a/src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java b/src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java new file mode 100644 index 0000000..b7e46ae --- /dev/null +++ b/src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java @@ -0,0 +1,10 @@ +package de.rwu.easydrop.core; + +import org.junit.jupiter.api.Test; + +public class OfferUpdaterTest { + @Test + void testRunUpdater() { + + } +} From c89c8974cf1aa054bcd12ace57f1e5252efbaeaa Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Fri, 9 Jun 2023 17:23:28 +0200 Subject: [PATCH 03/49] Wrote OfferIdentifier and updated ProductRetriever --- config/demo.config.properties | 3 +- .../de/rwu/easydrop/core/OfferIdentifier.java | 53 +++++++++++++++++-- .../java/de/rwu/easydrop/model/Offer.java | 10 ---- .../service/retriever/OfferRetriever.java | 14 +++++ .../service/retriever/ProductRetriever.java | 24 +++++++++ 5 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java diff --git a/config/demo.config.properties b/config/demo.config.properties index d3e4d63..13b994e 100644 --- a/config/demo.config.properties +++ b/config/demo.config.properties @@ -2,4 +2,5 @@ AMAZON_API_URL= AMAZON_API_KEY= EBAY_API_URL= -EBAY_API_KEY= \ No newline at end of file +EBAY_API_KEY= +WEBSHOPS=amazon,ebay \ No newline at end of file diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java index 1d20353..bfdbd9c 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -1,6 +1,13 @@ package de.rwu.easydrop.core; import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.service.retriever.OfferRetriever; +import de.rwu.easydrop.service.retriever.ProductRetriever; +import de.rwu.easydrop.util.Config; + +import javax.naming.ConfigurationException; import java.util.List; import java.util.ArrayList; @@ -8,11 +15,14 @@ import java.util.ArrayList; public class OfferIdentifier { + String[] webshops; + OfferRetriever offerRetriever; + ProductRetriever productRetriever; - - public OfferIdentifier() { - + public OfferIdentifier() throws ConfigurationException { + Config config = Config.getInstance(); + this.webshops = config.getProperty("WEBSHOPS").split(","); } public List runIdentifier() { @@ -23,8 +33,43 @@ public class OfferIdentifier { * wenn ja, muss er die Liste um diese Angebote kürzen * */ - return new ArrayList(); + // Just an example here taken from demo.products-config.json; should be generic and configurable either via + // JSON or the database later. + ProductCatalogue catalogue = new ProductCatalogue("Gigabyte GeForce RTX 3060", "Very epic GPU"); + for(String webshop: this.webshops) { + // The product retriever should know what API with which ProductID to query; high-level components should not know about such + // things. + Product product = this.productRetriever.getProductFromDataSource(webshop, catalogue.getProductName()); + if(product != null) { + catalogue.addProduct(product); + } + } + + List identifiedOffers = new ArrayList<>(); + // Here we would call the price function that decides if is feasible to dropship the product and if, at which + // margin + // Offer possibleOffer = GenerateOfferFromCatalogue(catalogue); + // if(possibleOffer != null) { + // identifiedOffers.add(possibleOffer); + // } + + List newOffers = new ArrayList<>(); + List existingOffers = offerRetriever.loadOffers(); + for(Offer identifiedOffer: identifiedOffers) { + boolean isNew = true; + for(Offer existingOffer: existingOffers) { + if(existingOffer.getSourceProduct().getProductId().equals(identifiedOffer.getSourceProduct().getProductId())) { + isNew = false; + break; + } + } + if(isNew) { + newOffers.add(identifiedOffer); + } + } + + return newOffers; } diff --git a/src/main/java/de/rwu/easydrop/model/Offer.java b/src/main/java/de/rwu/easydrop/model/Offer.java index f1772d6..a030146 100644 --- a/src/main/java/de/rwu/easydrop/model/Offer.java +++ b/src/main/java/de/rwu/easydrop/model/Offer.java @@ -23,11 +23,6 @@ public class Offer { */ Product saleProduct; - /* - * Boolean to check if sourceProduct is still available on source website - */ - boolean availability; - /* * Date of the creation of the offer * NOTE: Use Timestamp? https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html @@ -44,9 +39,4 @@ public class Offer { */ Date checkDate; - - - - - } diff --git a/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java new file mode 100644 index 0000000..3571b7d --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java @@ -0,0 +1,14 @@ +package de.rwu.easydrop.service.retriever; + +import de.rwu.easydrop.model.Offer; + +import java.util.ArrayList; +import java.util.List; + +public class OfferRetriever { + + public List loadOffers() { + return new ArrayList<>(); + } + +} diff --git a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java index da842c3..d4e5950 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java @@ -81,4 +81,28 @@ public class ProductRetriever { return product; } + + /** + * Retrieves a product from an API by name of the API so that high-level components do not need to be extended + * with exact function call names if we extend the list of webshops. + * + * @param dataSourceName Data source name, e.g. amazon + * @param productName Product name, translated to the correct product ID for the data source + * @return Product from that data source or null if data source not available + */ + public Product getProductFromDataSource(final String dataSourceName, final String productName) { + switch(dataSourceName.toLowerCase()) { + case "amazon": + // TODO: Translation from productName to productId (Amazon) needed + return getProductFromAmazon(productName); + case "ebay": + // TODO: Translation from productName to productId (eBay) needed + return getProductFromEbay(productName); + case "persistence": + // TODO: Translation from productName to productId (persistence layer) needed + return getProductFromPersistence(productName); + default: + return null; + } + } } From 5e6a2541fa255ca02c52a7cf0e3a65707d622108 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Fri, 9 Jun 2023 17:24:46 +0200 Subject: [PATCH 04/49] Wrote OfferIdentifier and updated ProductRetriever --- src/main/java/de/rwu/easydrop/core/OfferIdentifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java index bfdbd9c..819ea8a 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -20,7 +20,7 @@ public class OfferIdentifier { ProductRetriever productRetriever; - public OfferIdentifier() throws ConfigurationException { + public OfferIdentifier() { Config config = Config.getInstance(); this.webshops = config.getProperty("WEBSHOPS").split(","); } From 5436118829591619f31de35b9e03a0f8cea2d291 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Thu, 15 Jun 2023 18:47:10 +0200 Subject: [PATCH 05/49] Wrote Enum for webshops changed code in respective classes --- .../java/de/rwu/easydrop/core/OfferIdentifier.java | 9 +++------ src/main/java/de/rwu/easydrop/model/Product.java | 7 +++++++ .../easydrop/service/retriever/ProductRetriever.java | 11 ++++------- src/test/java/de/rwu/easydrop/core/CoreTest.java | 2 ++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java index 819ea8a..c52c5d1 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -15,15 +15,12 @@ import java.util.ArrayList; public class OfferIdentifier { - String[] webshops; + OfferRetriever offerRetriever; ProductRetriever productRetriever; - public OfferIdentifier() { - Config config = Config.getInstance(); - this.webshops = config.getProperty("WEBSHOPS").split(","); - } + public OfferIdentifier() {} public List runIdentifier() { /* muss die Kataloge durchforsten nach vergleichbaren Produkten auf mehreren Händlerwebseiten (APIs) @@ -37,7 +34,7 @@ public class OfferIdentifier { // Just an example here taken from demo.products-config.json; should be generic and configurable either via // JSON or the database later. ProductCatalogue catalogue = new ProductCatalogue("Gigabyte GeForce RTX 3060", "Very epic GPU"); - for(String webshop: this.webshops) { + for(Product.webshop webshop: Product.webshop.values()) { // The product retriever should know what API with which ProductID to query; high-level components should not know about such // things. Product product = this.productRetriever.getProductFromDataSource(webshop, catalogue.getProductName()); diff --git a/src/main/java/de/rwu/easydrop/model/Product.java b/src/main/java/de/rwu/easydrop/model/Product.java index 1e5b3b2..c8b70ff 100644 --- a/src/main/java/de/rwu/easydrop/model/Product.java +++ b/src/main/java/de/rwu/easydrop/model/Product.java @@ -10,6 +10,13 @@ import lombok.Data; */ @Data public class Product { + /* + * Constants for data source/destination platforms + */ + public enum webshop{ + AMAZON, EBAY + } + /** * Data source platform, like "Amazon". */ diff --git a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java index d4e5950..8b814f9 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java @@ -90,17 +90,14 @@ public class ProductRetriever { * @param productName Product name, translated to the correct product ID for the data source * @return Product from that data source or null if data source not available */ - public Product getProductFromDataSource(final String dataSourceName, final String productName) { - switch(dataSourceName.toLowerCase()) { - case "amazon": + public Product getProductFromDataSource(Product.webshop dataSourceName, final String productName) { + switch(dataSourceName) { + case AMAZON: // TODO: Translation from productName to productId (Amazon) needed return getProductFromAmazon(productName); - case "ebay": + case EBAY: // TODO: Translation from productName to productId (eBay) needed return getProductFromEbay(productName); - case "persistence": - // TODO: Translation from productName to productId (persistence layer) needed - return getProductFromPersistence(productName); default: return null; } diff --git a/src/test/java/de/rwu/easydrop/core/CoreTest.java b/src/test/java/de/rwu/easydrop/core/CoreTest.java index b81a7ac..55cb64c 100644 --- a/src/test/java/de/rwu/easydrop/core/CoreTest.java +++ b/src/test/java/de/rwu/easydrop/core/CoreTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.Test; public class CoreTest { @Test void testRunCore() { + Core core1=new Core(); + core1.runCore(); } } From 5204cc171090626b788b1b77633baadd8e573e33 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Thu, 15 Jun 2023 18:52:06 +0200 Subject: [PATCH 06/49] Wrote OfferWriter and following classes to save offers to persistence --- .../de/rwu/easydrop/api/dto/OfferDTO.java | 51 +++++++++++++++++++ .../rwu/easydrop/core/OfferProvisioner.java | 30 ++++++++++- .../connector/AbstractOfferPersistence.java | 28 ++++++++++ .../java/de/rwu/easydrop/model/Offer.java | 5 ++ .../easydrop/service/mapping/OfferMapper.java | 50 ++++++++++++++++++ .../service/validation/OfferValidator.java | 32 ++++++++++++ .../easydrop/service/writer/OfferWriter.java | 33 ++++++++++++ 7 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java create mode 100644 src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java create mode 100644 src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java create mode 100644 src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java create mode 100644 src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java diff --git a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java new file mode 100644 index 0000000..ee7d5f4 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java @@ -0,0 +1,51 @@ +package de.rwu.easydrop.api.dto; + +import lombok.Data; +import de.rwu.easydrop.model.Product; +import java.util.Date; + +/* + * Offer data transfer object + */ +@Data +public class OfferDTO { + /** + * Platform internal offer identifier. + */ + private String offerId; + + /* + * The product that our software buys + */ + Product sourceProduct; + + /* + * The product that our software sells + */ + Product saleProduct; + + /* + * Date of the creation of the offer + * NOTE: Use Timestamp? https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html + */ + Date creationDate; + + /* + * Date of last update of the offer on the destination website (API) + */ + Date upDate; + + /* + * Date of last check if offer is still valid + */ + Date checkDate; + + /** + * Creates OfferDTO instance. + * + * @param newOfferId Internal Offer identifier + */ + public OfferDTO(final String newOfferId) { + this.offerId = newOfferId; + } +} diff --git a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java index 3b6f9bb..27aa676 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java @@ -1,13 +1,25 @@ package de.rwu.easydrop.core; -import de.rwu.easydrop.model.Offer; - import java.util.List; +import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.service.retriever.ProductRetriever; +import de.rwu.easydrop.service.writer.OfferWriter; + public class OfferProvisioner { + ProductRetriever productRetriever; + // ProductWriter + AbstractProductPersistence db; + OfferWriter offerWriter; + public OfferProvisioner(/*OfferWriter for database? */) { + //in die Klasse hardcoden, "webshop" nicht verwenden + //oder eine Konstante anlegen die das halten würde (besser skalierbar) + //die Konstante in model anlegen (in Product, Konstante valid origins) + this.offerWriter = new OfferWriter(); } public void runProvisioner(List offersToProvision) { @@ -16,6 +28,20 @@ public class OfferProvisioner { * Stellt Angebote bei der Zielplattform ein * Schreibt eingestellte Angebote in die Datenbank */ + + for(Offer newOffer: offersToProvision){ + // if(newOffer.getSourceProduct().getDataOrigin().equals("ebay")){ + // //put newOffer on amazon + + // } + //else put newOffer on eBay + + // if successfully transmitted + // add to persistence + // "duplicate" the product with dataOrigin new platform and merchant = "me" + offerWriter.writeOfferToPersistence(newOffer); + } + diff --git a/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java b/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java new file mode 100644 index 0000000..4562a6d --- /dev/null +++ b/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java @@ -0,0 +1,28 @@ +package de.rwu.easydrop.data.connector; + +import de.rwu.easydrop.api.dto.OfferDTO; + +public abstract class AbstractOfferPersistence { + /** + * Data origin. + */ + public static final String DATA_ORIGIN = "Persistence"; + + /** + * Writes a ProductDTO to persistence. + * + * @param dto + */ + public abstract void saveOffer(OfferDTO dto); + + /** + * Gets a OfferDTO from persistence. + */ + //@Override + public abstract OfferDTO getOfferDTOById(String OfferId); + + /** + * Deletes all data from persistence. + */ + public abstract void clearData(); +} diff --git a/src/main/java/de/rwu/easydrop/model/Offer.java b/src/main/java/de/rwu/easydrop/model/Offer.java index a030146..174e1d4 100644 --- a/src/main/java/de/rwu/easydrop/model/Offer.java +++ b/src/main/java/de/rwu/easydrop/model/Offer.java @@ -39,4 +39,9 @@ public class Offer { */ Date checkDate; + /* + * ID of the offer + */ + String offerId; + } diff --git a/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java b/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java new file mode 100644 index 0000000..f6aeb73 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java @@ -0,0 +1,50 @@ +package de.rwu.easydrop.service.mapping; + +import de.rwu.easydrop.api.dto.OfferDTO; + +import de.rwu.easydrop.model.Offer; + +/** + * Maps between Offer, OfferDTO and OfferDTO. + * + * @since 0.2.0 + * + * @see Offer + * @see OfferDTO + * @see OfferDTO + */ +public final class OfferMapper { + + /** + * Private constructor to prevent unwanted instantiation. + * + * @throws UnsupportedOperationException always + */ + private OfferMapper() throws UnsupportedOperationException { + throw new UnsupportedOperationException("This is a mapping class, don't instantiate it."); + } + + /** + * Creates a Offer object from a corresponding DTO. + * + * @param dto Offer Data Transfer Object + * @return Offer + */ + public static Offer mapOfferFromDTO(final OfferDTO dto) { + Offer offer = new Offer(); + + return offer; + } + + /** + * Creates an OfferDTO object from a corresponding offer. + * + * @param Offer offer + * @return OfferDTO + */ + public static OfferDTO mapOfferToDTO(final Offer offer) { + OfferDTO dto = new OfferDTO(offer.getOfferId()); + + return dto; + } +} diff --git a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java new file mode 100644 index 0000000..2f466f1 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java @@ -0,0 +1,32 @@ +package de.rwu.easydrop.service.validation; +import java.util.HashSet; +import java.util.Set; + +import de.rwu.easydrop.exception.InvalidProductException; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Offer; + +/** + * Confirms validity of Offer data. + * + * @since 0.2.0 + */ +public class OfferValidator { + /** + * Private constructor to prevent unwanted instantiation. + * + * @throws UnsupportedOperationException always + */ + private OfferValidator() throws UnsupportedOperationException { + throw new UnsupportedOperationException("This is a validator class, don't instantiate it."); + } + /** + * Makes sure an Offer does not contain invalid information. + * + * @param offer the Offer + */ + public static void validate(final Offer offer) {} +} + + + diff --git a/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java b/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java new file mode 100644 index 0000000..8933d55 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java @@ -0,0 +1,33 @@ +package de.rwu.easydrop.service.writer; + +import de.rwu.easydrop.api.dto.OfferDTO; +import de.rwu.easydrop.data.connector.AbstractOfferPersistence; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.service.mapping.OfferMapper; +import de.rwu.easydrop.service.validation.OfferValidator; + +public class OfferWriter { + /** + * Persistence. + */ + private AbstractOfferPersistence persistence; + + /** + * @param newPersistence the persistence to set + */ + public void setPersistence(final AbstractOfferPersistence newPersistence) { + this.persistence = newPersistence; + } + + /** + * Validates and saves product to persistence. + * + * @param product + */ + public void writeOfferToPersistence(final Offer offer) { + OfferValidator.validate(offer); + OfferDTO dto = OfferMapper.mapOfferToDTO(offer); + + persistence.saveOffer(dto); + } +} From fc4f5c6fc6fa0c75798d3ab2f8d84f40fbb02c9b Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Thu, 15 Jun 2023 19:11:30 +0200 Subject: [PATCH 07/49] fixed Tests --- src/main/java/de/rwu/easydrop/core/Core.java | 5 ++++- src/main/java/de/rwu/easydrop/core/OfferIdentifier.java | 7 ++++++- .../de/rwu/easydrop/service/validation/OfferValidator.java | 4 ---- src/test/java/de/rwu/easydrop/core/CoreTest.java | 4 +++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java index b242b44..82af9ef 100644 --- a/src/main/java/de/rwu/easydrop/core/Core.java +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -1,6 +1,9 @@ package de.rwu.easydrop.core; import java.util.List; + +import javax.naming.ConfigurationException; + import de.rwu.easydrop.model.Offer; public class Core { @@ -11,7 +14,7 @@ public class Core { private OfferUpdater update; - public Core(){ + public Core() throws ConfigurationException{ this.ident = new OfferIdentifier(); this.provis = new OfferProvisioner(); this.review = new OfferReviewer(); diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java index c52c5d1..2093052 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -1,5 +1,6 @@ package de.rwu.easydrop.core; +import de.rwu.easydrop.api.client.DataSourceFactory; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; @@ -20,7 +21,11 @@ public class OfferIdentifier { ProductRetriever productRetriever; - public OfferIdentifier() {} + public OfferIdentifier() throws ConfigurationException{ + this.offerRetriever = new OfferRetriever(); + DataSourceFactory dataSourceFactory = new DataSourceFactory(Config.getInstance()); + this.productRetriever= new ProductRetriever(dataSourceFactory); + } public List runIdentifier() { /* muss die Kataloge durchforsten nach vergleichbaren Produkten auf mehreren Händlerwebseiten (APIs) diff --git a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java index 2f466f1..ab6b26e 100644 --- a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java +++ b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java @@ -1,9 +1,5 @@ package de.rwu.easydrop.service.validation; -import java.util.HashSet; -import java.util.Set; -import de.rwu.easydrop.exception.InvalidProductException; -import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.Offer; /** diff --git a/src/test/java/de/rwu/easydrop/core/CoreTest.java b/src/test/java/de/rwu/easydrop/core/CoreTest.java index 55cb64c..5eb429c 100644 --- a/src/test/java/de/rwu/easydrop/core/CoreTest.java +++ b/src/test/java/de/rwu/easydrop/core/CoreTest.java @@ -1,10 +1,12 @@ package de.rwu.easydrop.core; +import javax.naming.ConfigurationException; + import org.junit.jupiter.api.Test; public class CoreTest { @Test - void testRunCore() { + void testRunCore() throws ConfigurationException{ Core core1=new Core(); core1.runCore(); From 4e2d400d0521ee18997a3e8428f0fb7ac5517b57 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Sun, 25 Jun 2023 10:46:16 +0200 Subject: [PATCH 08/49] Implemented Offer Placement in OfferProvisioner --- .../rwu/easydrop/core/OfferProvisioner.java | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java index 27aa676..0209812 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java @@ -1,18 +1,49 @@ package de.rwu.easydrop.core; +import java.io.IOException; import java.util.List; +import de.rwu.easydrop.util.Config; import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.exception.DataWriterException; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.service.retriever.ProductRetriever; import de.rwu.easydrop.service.writer.OfferWriter; +import de.rwu.easydrop.api.client.AmazonSeller; +import de.rwu.easydrop.api.client.EbaySeller; +import de.rwu.easydrop.api.dto.ProductDTO; public class OfferProvisioner { - ProductRetriever productRetriever; + Config config; + ProductRetriever productRetriever; // ProductWriter AbstractProductPersistence db; OfferWriter offerWriter; + AmazonSeller amazonSeller; + EbaySeller ebaySeller; + + private void toSeller(Offer offer) throws IllegalArgumentException { + // TODO dataOrigin should use the webshop enum + if(offer.getSaleProduct().getDataOrigin().toLowerCase().equals("ebay")){ + this.ebaySeller.sellProduct(new ProductDTO( + offer.getSaleProduct().getProductId(), + "Amazon") + ); + + } else if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("Amazon")) { + this.amazonSeller.sellProduct(new ProductDTO( + offer.getSaleProduct().getProductId(), + "eBay") + ); + } + else { + throw new IllegalArgumentException("Unsupported target plattform"); + } + + } + + public OfferProvisioner(/*OfferWriter for database? */) { @@ -20,6 +51,15 @@ public class OfferProvisioner { //oder eine Konstante anlegen die das halten würde (besser skalierbar) //die Konstante in model anlegen (in Product, Konstante valid origins) this.offerWriter = new OfferWriter(); + this.config = Config.getInstance(); + this.amazonSeller = new AmazonSeller( + config.getProperty("AMAZON_API_URL"), + config.getProperty("AMAZON_API_KEY") + ); + this.ebaySeller = new EbaySeller( + config.getProperty("EBAY_API_URL"), + config.getProperty("EBAY_API_KEY") + ); } public void runProvisioner(List offersToProvision) { @@ -28,23 +68,28 @@ public class OfferProvisioner { * Stellt Angebote bei der Zielplattform ein * Schreibt eingestellte Angebote in die Datenbank */ - for(Offer newOffer: offersToProvision){ - // if(newOffer.getSourceProduct().getDataOrigin().equals("ebay")){ - // //put newOffer on amazon - // } - //else put newOffer on eBay - - // if successfully transmitted - // add to persistence - // "duplicate" the product with dataOrigin new platform and merchant = "me" - offerWriter.writeOfferToPersistence(newOffer); + try { + this.toSeller(newOffer); + // if successfully transmitted + // add to persistence + // "duplicate" the product with dataOrigin new platform and merchant = "me" + try { + offerWriter.writeOfferToPersistence(newOffer); + } + catch (Exception e){ + System.out.println("Could not write to persistence"); + } + } catch (IllegalArgumentException e) { + System.out.println( + "Offer could not be placed, " + + newOffer.getSaleProduct().getDataOrigin() + + " is not supported" + ); + } catch (DataWriterException e) { + System.out.println("could not transmit offer"); + } } - - - - } - } From c18f6a7fdcc2525b33f67e3e4a0adcbbeb7e7641 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Sun, 25 Jun 2023 10:47:29 +0200 Subject: [PATCH 09/49] Need DatabaseConnector on SQLite --- .../easydrop/api/client/AbstractDataSource.java | 14 ++++++++++++-- .../easydrop/data/connector/DatabaseConnector.java | 10 ++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java 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 4b58d66..5d410a8 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java @@ -72,13 +72,23 @@ public abstract class AbstractDataSource implements DataSource { + responseCode); } - String line; + + String line; while ((line = reader.readLine()) != null) { response.append(line); } reader.close(); - buildProductDTO(product, response.toString()); + // FIXME: Mock not complete. Data is missing + // FIXME response can be empty + String data; + if (response.toString().isEmpty()){ + data = "{}"; + } + else { + data = response.toString(); + } + buildProductDTO(product, data); } catch (IOException e) { throw new DataSourceException( "Couldn't fulfill " diff --git a/src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java b/src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java new file mode 100644 index 0000000..ce6360a --- /dev/null +++ b/src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java @@ -0,0 +1,10 @@ +package de.rwu.easydrop.data.connector; + +/** + * Allows connecting to a SQLite Database. + * + * TODO implement + */ +public class DatabaseConnector { + +} From f715c76ace1724023551da7051ddbc41d2f276b2 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Mon, 26 Jun 2023 00:21:42 +0200 Subject: [PATCH 10/49] Integrated price function into offer identifier --- src/main/java/de/rwu/easydrop/core/Core.java | 5 +- .../de/rwu/easydrop/core/OfferIdentifier.java | 83 +++++++++---------- .../java/de/rwu/easydrop/core/CoreTest.java | 19 ++++- 3 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java index 82af9ef..d8fcd99 100644 --- a/src/main/java/de/rwu/easydrop/core/Core.java +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -5,6 +5,7 @@ import java.util.List; import javax.naming.ConfigurationException; import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.ProductCatalogue; public class Core { @@ -23,8 +24,8 @@ public class Core { } - public void runCore(){ - List identifiedOffers = ident.runIdentifier(); + public void runCore(List pCats){ + List identifiedOffers = ident.runIdentifier(pCats); provis.runProvisioner(identifiedOffers); List updatingOffers = review.runReviewer(); update.runUpdater(updatingOffers); diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java index 2093052..4f3ee39 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -1,61 +1,63 @@ package de.rwu.easydrop.core; -import de.rwu.easydrop.api.client.DataSourceFactory; -import de.rwu.easydrop.model.Offer; -import de.rwu.easydrop.model.Product; -import de.rwu.easydrop.model.ProductCatalogue; -import de.rwu.easydrop.service.retriever.OfferRetriever; -import de.rwu.easydrop.service.retriever.ProductRetriever; -import de.rwu.easydrop.util.Config; - import javax.naming.ConfigurationException; import java.util.List; import java.util.ArrayList; +import java.util.Date; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.model.ProductPair; +import de.rwu.easydrop.service.retriever.OfferRetriever; +import de.rwu.easydrop.service.processing.OrderManager; +import de.rwu.easydrop.exception.InvalidCatalogueException; public class OfferIdentifier { - + /** + * Logger for main process. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(OfferIdentifier.class); OfferRetriever offerRetriever; - ProductRetriever productRetriever; - public OfferIdentifier() throws ConfigurationException{ this.offerRetriever = new OfferRetriever(); - DataSourceFactory dataSourceFactory = new DataSourceFactory(Config.getInstance()); - this.productRetriever= new ProductRetriever(dataSourceFactory); } - public List runIdentifier() { - /* muss die Kataloge durchforsten nach vergleichbaren Produkten auf mehreren Händlerwebseiten (APIs) - * muss Preisermittler als Abhängigkeit für jeden Katalog aufrufen - * erhält dadurch Liste von Produkten, die auf verschiedenen Plattformen eingestellt werden können, gibt diese Liste zurück - * muss Datenbank nach Produktangeboten durchforsten, ob diese Produkte schon eingestellt wurden vom OfferProvisioner - * wenn ja, muss er die Liste um diese Angebote kürzen - * - */ + public List runIdentifier(List pCats) { + List identifiedOffers = new ArrayList<>(); + // Here we call the price function that decides if is feasible to dropship the product and if, at which + // margin + for (ProductCatalogue pCat : pCats) { + try{ + // Call price finder for all catalogue + ProductPair pair = OrderManager.getHighestMarginProducts(pCat); + Offer possibleOffer = new Offer(); + possibleOffer.setCheckDate(new Date()); + possibleOffer.setSourceProduct(pair.getProduct1()); + possibleOffer.setSaleProduct(pair.getProduct2()); + identifiedOffers.add(possibleOffer); + LOGGER.info( + "Identified offer " + + pair.getProduct1().getProductId() + + " -> " + + pair.getProduct2().getProductId() + ); + // Following fields will be set if offer confirmed + // creationDate, offerId - // Just an example here taken from demo.products-config.json; should be generic and configurable either via - // JSON or the database later. - ProductCatalogue catalogue = new ProductCatalogue("Gigabyte GeForce RTX 3060", "Very epic GPU"); - for(Product.webshop webshop: Product.webshop.values()) { - // The product retriever should know what API with which ProductID to query; high-level components should not know about such - // things. - Product product = this.productRetriever.getProductFromDataSource(webshop, catalogue.getProductName()); - if(product != null) { - catalogue.addProduct(product); + // Following fields will be set if offer needs update + // upDate + } + catch(InvalidCatalogueException e) { + // if no margin, getHighestMarginProducts will throw + System.out.print("product has no margin"); } } - List identifiedOffers = new ArrayList<>(); - // Here we would call the price function that decides if is feasible to dropship the product and if, at which - // margin - // Offer possibleOffer = GenerateOfferFromCatalogue(catalogue); - // if(possibleOffer != null) { - // identifiedOffers.add(possibleOffer); - // } - List newOffers = new ArrayList<>(); List existingOffers = offerRetriever.loadOffers(); for(Offer identifiedOffer: identifiedOffers) { @@ -70,9 +72,6 @@ public class OfferIdentifier { newOffers.add(identifiedOffer); } } - return newOffers; - } - - + } } diff --git a/src/test/java/de/rwu/easydrop/core/CoreTest.java b/src/test/java/de/rwu/easydrop/core/CoreTest.java index 5eb429c..e37170f 100644 --- a/src/test/java/de/rwu/easydrop/core/CoreTest.java +++ b/src/test/java/de/rwu/easydrop/core/CoreTest.java @@ -1,14 +1,31 @@ package de.rwu.easydrop.core; +import java.util.List; import javax.naming.ConfigurationException; import org.junit.jupiter.api.Test; +import de.rwu.easydrop.api.client.DataSourceFactory; + +import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.service.retriever.CatalogueRetriever; +import de.rwu.easydrop.service.retriever.ProductRetriever; +import de.rwu.easydrop.util.Config; +import de.rwu.easydrop.util.ProductsConfig; + public class CoreTest { @Test void testRunCore() throws ConfigurationException{ + Config config = Config.getInstance(); + ProductsConfig pConfig = ProductsConfig.getInstance(); + DataSourceFactory dataSourceFactory = new DataSourceFactory(config); + ProductRetriever retriever = new ProductRetriever(dataSourceFactory); + CatalogueRetriever catRetriever = new CatalogueRetriever(pConfig, retriever); + + catRetriever.loadCatalogues(); + List pCats = catRetriever.getProductCatalogues(); Core core1=new Core(); - core1.runCore(); + core1.runCore(pCats); } } From 399951c43d89596fc2676bfcc730b417bf223cd8 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Mon, 26 Jun 2023 00:34:23 +0200 Subject: [PATCH 11/49] Integrated Core into Main --- src/main/java/de/rwu/easydrop/Main.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/Main.java b/src/main/java/de/rwu/easydrop/Main.java index 87a23a5..c8f4f1e 100644 --- a/src/main/java/de/rwu/easydrop/Main.java +++ b/src/main/java/de/rwu/easydrop/Main.java @@ -9,10 +9,10 @@ import org.slf4j.LoggerFactory; import org.sqlite.SQLiteDataSource; import de.rwu.easydrop.api.client.DataSourceFactory; +import de.rwu.easydrop.core.Core; import de.rwu.easydrop.data.connector.AbstractProductPersistence; import de.rwu.easydrop.data.connector.SQLiteConnector; import de.rwu.easydrop.model.ProductCatalogue; -import de.rwu.easydrop.service.processing.OrderManager; import de.rwu.easydrop.service.retriever.CatalogueRetriever; import de.rwu.easydrop.service.retriever.ProductRetriever; import de.rwu.easydrop.service.writer.CatalogueWriter; @@ -55,11 +55,7 @@ public final class Main { List pCats = catRetriever.getProductCatalogues(); catWriter.writeCatalogues(pCats); - for (ProductCatalogue pCat : pCats) { - String pCatStr = pCat.toString(); - LOGGER.info(pCatStr); - } - - OrderManager.createOrders(pCats); + Core core = new Core(); + core.runCore(pCats); } } From e3377c7b5924085f5ae05c21e7a78a70408d5cad Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Mon, 26 Jun 2023 10:03:03 +0200 Subject: [PATCH 12/49] Did Checkstyle improvements on OfferProv + Ident --- .../de/rwu/easydrop/core/OfferIdentifier.java | 57 +++++++---- .../rwu/easydrop/core/OfferProvisioner.java | 99 ++++++++++--------- 2 files changed, 90 insertions(+), 66 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java index 4f3ee39..b240d0f 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -20,58 +20,73 @@ public class OfferIdentifier { * Logger for main process. */ private static final Logger LOGGER = LoggerFactory.getLogger(OfferIdentifier.class); - - OfferRetriever offerRetriever; - + /** + * OfferRetriever gets the offer from persistence. + */ + private OfferRetriever offerRetriever; + /** + * OfferIdentifier identifies offers that are + * feasible to place on a target platform based on + * their margin. + * @throws ConfigurationException + */ public OfferIdentifier() throws ConfigurationException{ this.offerRetriever = new OfferRetriever(); } - public List runIdentifier(List pCats) { + /** + * runIdentifier calls the price function that decides + * if it is feasible to dropship products and if so, + * at which margin. + * @param pCats + * @return newOffers + */ + public List runIdentifier(final List pCats) { List identifiedOffers = new ArrayList<>(); - // Here we call the price function that decides if is feasible to dropship the product and if, at which - // margin for (ProductCatalogue pCat : pCats) { - try{ + try { // Call price finder for all catalogue - ProductPair pair = OrderManager.getHighestMarginProducts(pCat); + ProductPair pair = OrderManager.getHighestMarginProducts(pCat); Offer possibleOffer = new Offer(); possibleOffer.setCheckDate(new Date()); possibleOffer.setSourceProduct(pair.getProduct1()); possibleOffer.setSaleProduct(pair.getProduct2()); - identifiedOffers.add(possibleOffer); + identifiedOffers.add(possibleOffer); LOGGER.info( - "Identified offer " + - pair.getProduct1().getProductId() + - " -> " + + "Identified offer " + + + pair.getProduct1().getProductId() + + + " -> " + + pair.getProduct2().getProductId() - ); + ); // Following fields will be set if offer confirmed // creationDate, offerId - // Following fields will be set if offer needs update // upDate } - catch(InvalidCatalogueException e) { + catch (InvalidCatalogueException e) { // if no margin, getHighestMarginProducts will throw System.out.print("product has no margin"); } } - List newOffers = new ArrayList<>(); List existingOffers = offerRetriever.loadOffers(); - for(Offer identifiedOffer: identifiedOffers) { + for (Offer identifiedOffer: identifiedOffers) { boolean isNew = true; - for(Offer existingOffer: existingOffers) { - if(existingOffer.getSourceProduct().getProductId().equals(identifiedOffer.getSourceProduct().getProductId())) { + for (Offer existingOffer: existingOffers) { + if ( + existingOffer.getSourceProduct().getProductId(). + equals(identifiedOffer.getSourceProduct().getProductId())) { isNew = false; break; } } - if(isNew) { + if (isNew) { newOffers.add(identifiedOffer); } } return newOffers; - } + } } diff --git a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java index 0209812..bd7c063 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java @@ -1,6 +1,5 @@ package de.rwu.easydrop.core; -import java.io.IOException; import java.util.List; import de.rwu.easydrop.util.Config; @@ -14,61 +13,72 @@ import de.rwu.easydrop.api.client.EbaySeller; import de.rwu.easydrop.api.dto.ProductDTO; public class OfferProvisioner { - - Config config; - ProductRetriever productRetriever; + /** + * Config. + */ + private Config config; + /** + * Gets the products from persistence. + */ + private ProductRetriever productRetriever; // ProductWriter - AbstractProductPersistence db; - OfferWriter offerWriter; - AmazonSeller amazonSeller; - EbaySeller ebaySeller; + /** + * Is the product databank. + */ + private AbstractProductPersistence db; + /** + * Writes offers into persistence. + */ + private OfferWriter offerWriter; - private void toSeller(Offer offer) throws IllegalArgumentException { - // TODO dataOrigin should use the webshop enum - if(offer.getSaleProduct().getDataOrigin().toLowerCase().equals("ebay")){ - this.ebaySeller.sellProduct(new ProductDTO( - offer.getSaleProduct().getProductId(), - "Amazon") - ); + /** + * Is the API for selling products on Amazon. + */ + private AmazonSeller amazonSeller; + /** + * Is the API for selling products on Ebay. + */ + private EbaySeller ebaySeller; - } else if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("Amazon")) { - this.amazonSeller.sellProduct(new ProductDTO( + private void toSeller(final Offer offer) throws IllegalArgumentException { + // TODO dataOrigin should use the webshop enum + if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("ebay")) { + this.ebaySeller.sellProduct(new ProductDTO( offer.getSaleProduct().getProductId(), - "eBay") - ); - } - else { - throw new IllegalArgumentException("Unsupported target plattform"); - } + "Amazon")); + + } else if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("Amazon")) { + this.amazonSeller.sellProduct(new ProductDTO( + offer.getSaleProduct().getProductId(), + "eBay")); + } else { + throw new IllegalArgumentException("Unsupported target plattform"); + } } - + /** + * Is the class for placing orders on a target platform. + */ + public OfferProvisioner(/* OfferWriter for database? */) { - public OfferProvisioner(/*OfferWriter for database? */) { - - //in die Klasse hardcoden, "webshop" nicht verwenden - //oder eine Konstante anlegen die das halten würde (besser skalierbar) - //die Konstante in model anlegen (in Product, Konstante valid origins) this.offerWriter = new OfferWriter(); this.config = Config.getInstance(); this.amazonSeller = new AmazonSeller( - config.getProperty("AMAZON_API_URL"), - config.getProperty("AMAZON_API_KEY") - ); + config.getProperty("AMAZON_API_URL"), + config.getProperty("AMAZON_API_KEY")); this.ebaySeller = new EbaySeller( - config.getProperty("EBAY_API_URL"), - config.getProperty("EBAY_API_KEY") - ); + config.getProperty("EBAY_API_URL"), + config.getProperty("EBAY_API_KEY")); } - public void runProvisioner(List offersToProvision) { - /* - * Bekommt vom Identifier eine Liste mit Angeboten, die er einstellen soll auf Zielplattformen - * Stellt Angebote bei der Zielplattform ein - * Schreibt eingestellte Angebote in die Datenbank - */ - for(Offer newOffer: offersToProvision){ + /** + * Method for placing orders on a target platform. + * @param offersToProvision + */ + public final void runProvisioner(final List offersToProvision) { + + for (Offer newOffer: offersToProvision){ try { this.toSeller(newOffer); @@ -77,10 +87,9 @@ public class OfferProvisioner { // "duplicate" the product with dataOrigin new platform and merchant = "me" try { offerWriter.writeOfferToPersistence(newOffer); - } - catch (Exception e){ + } catch (Exception e) { System.out.println("Could not write to persistence"); - } + } } catch (IllegalArgumentException e) { System.out.println( "Offer could not be placed, " + From 6cd6b779a6a31965e56e1556ed11179fbd925932 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Mon, 26 Jun 2023 12:55:52 +0200 Subject: [PATCH 13/49] More checkstyle improvements on Offer components --- .../java/de/rwu/easydrop/model/Offer.java | 36 +++++++++---------- .../service/validation/OfferValidator.java | 4 +-- .../easydrop/service/writer/OfferWriter.java | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/model/Offer.java b/src/main/java/de/rwu/easydrop/model/Offer.java index 174e1d4..8fae3b7 100644 --- a/src/main/java/de/rwu/easydrop/model/Offer.java +++ b/src/main/java/de/rwu/easydrop/model/Offer.java @@ -13,35 +13,35 @@ import lombok.Data; @Data public class Offer { - /* - * The product that our software buys + /** + * The product that our software buys. */ - Product sourceProduct; + private Product sourceProduct; - /* - * The product that our software sells + /** + * The product that our software sells. */ - Product saleProduct; + private Product saleProduct; - /* - * Date of the creation of the offer + /** + * Date of the creation of the offer. * NOTE: Use Timestamp? https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html */ - Date creationDate; + private Date creationDate; - /* - * Date of last update of the offer on the destination website (API) + /** + * Date of last update of the offer on the destination website (API). */ - Date upDate; + private Date upDate; - /* - * Date of last check if offer is still valid + /** + * Date of last check if offer is still valid. */ - Date checkDate; + private Date checkDate; - /* - * ID of the offer + /** + * ID of the offer. */ - String offerId; + private String offerId; } diff --git a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java index ab6b26e..c3f2257 100644 --- a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java +++ b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java @@ -7,7 +7,7 @@ import de.rwu.easydrop.model.Offer; * * @since 0.2.0 */ -public class OfferValidator { +public final class OfferValidator { /** * Private constructor to prevent unwanted instantiation. * @@ -21,7 +21,7 @@ public class OfferValidator { * * @param offer the Offer */ - public static void validate(final Offer offer) {} + public static void validate(final Offer offer) { } } diff --git a/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java b/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java index 8933d55..6ba6a4c 100644 --- a/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java +++ b/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java @@ -22,7 +22,7 @@ public class OfferWriter { /** * Validates and saves product to persistence. * - * @param product + * @param offer */ public void writeOfferToPersistence(final Offer offer) { OfferValidator.validate(offer); From 37e4970fd6c6046a8fad3c9f54953fd39d84dfc1 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Mon, 26 Jun 2023 15:33:51 +0200 Subject: [PATCH 14/49] Checkstyle improvements Product + OfferProvis --- .../de/rwu/easydrop/core/OfferProvisioner.java | 2 +- .../java/de/rwu/easydrop/model/Product.java | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java index bd7c063..457256a 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java @@ -47,7 +47,7 @@ public class OfferProvisioner { offer.getSaleProduct().getProductId(), "Amazon")); - } else if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("Amazon")) { + } else if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("amazon")) { this.amazonSeller.sellProduct(new ProductDTO( offer.getSaleProduct().getProductId(), "eBay")); diff --git a/src/main/java/de/rwu/easydrop/model/Product.java b/src/main/java/de/rwu/easydrop/model/Product.java index c8b70ff..d484405 100644 --- a/src/main/java/de/rwu/easydrop/model/Product.java +++ b/src/main/java/de/rwu/easydrop/model/Product.java @@ -10,13 +10,19 @@ import lombok.Data; */ @Data public class Product { - /* - * Constants for data source/destination platforms + /** + * Constants for data source/destination platforms. */ - public enum webshop{ - AMAZON, EBAY - } - + public enum Webshop { + /** + * Amazon. + */ + AMAZON, + /**Ebay. + */ + EBAY + } + /** * Data source platform, like "Amazon". */ From da7c4e99794607fa3d9ce6476406a0844745a0b5 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Mon, 26 Jun 2023 21:39:43 +0200 Subject: [PATCH 15/49] added method checkoffer --- .../de/rwu/easydrop/core/OfferReviewer.java | 77 ++++++++++++++++--- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java index f410f41..fb5f962 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java +++ b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java @@ -1,23 +1,80 @@ package de.rwu.easydrop.core; import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Product.webshop; + import java.util.List; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; public class OfferReviewer { - public OfferReviewer(/*OfferReader/retriever for database? */){ + /** + * OfferReviewer. + * @return list of all items that need to be changed + */ + public List checkOffers(/*OfferReader/retriever for database? */) { - } + Connection connection = null; + Statement statement = null; + ResultSet resultSet = null; + List changedProducts = new ArrayList<>(); - public List runReviewer() { - /* - * Liest eingestellte Angebote in der Datenbank - * Prüft Zielplattformen der SourceProducts, ob diese noch verfügbar sind (Issue#12) bzw. ob sie sich im Preis geändert haben - * Gibt Liste zurück von Offers, die geändert werden müssen, wird übergeben an OfferUpdater mit availability true oder false - */ + try { + // Establish the database connection + connection = DriverManager.getConnection("jdbc:sqlite:persistence.db"); + + // Create a SQL statement + statement = connection.createStatement(); + + // Execute the query to retrieve the entries + String query = "SELECT dataOrigin, productId, currentPrice FROM table"; + resultSet = statement.executeQuery(query); + + // Process the retrieved entries + while (resultSet.next()) { + String webshop = resultSet.getString("webshop"); + String dataOrigin = resultSet.getString("data_origin"); + String productId = resultSet.getString("productId"); + double currentPrice = resultSet.getDouble("currentPrice"); + String merchant = resultSet.getString("merchant"); + double deliveryPrice = resultSet.getDouble("delivery_price"); + boolean available = resultSet.getBoolean("available"); + + // Call the API to get the current price + double apiPrice = getPriceFromAPI(productId); + + // Compare the prices + if (currentPrice != apiPrice) { + // Price has changed, create a Product object and add it to the changedProducts list + Product product = new Product(webshop, dataOrigin, productId, currentPrice, + merchant, deliveryPrice, available); + changedProducts.add(product); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + // Close the resources (resultSet, statement, connection) in a finally block + try { + if (resultSet != null) { + resultSet.close(); + } + if (statement != null) { + statement.close(); + } + if (connection != null) { + connection.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } return new ArrayList(); - } - } From 7a19a38aa19b160e530a8734a06b5ebd93c88ae3 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 00:14:02 +0200 Subject: [PATCH 16/49] fixed some issues in method checkOffers --- .../de/rwu/easydrop/core/OfferReviewer.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java index fb5f962..5b698bf 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java +++ b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java @@ -11,19 +11,20 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.Date; public class OfferReviewer { /** - * OfferReviewer. + * Check all Offers and compare them with the API. * @return list of all items that need to be changed */ - public List checkOffers(/*OfferReader/retriever for database? */) { + public List checkOffer(/*OfferReader/retriever for database? */) { Connection connection = null; Statement statement = null; ResultSet resultSet = null; - List changedProducts = new ArrayList<>(); + List changedOffers = new ArrayList<>(); try { // Establish the database connection @@ -33,28 +34,27 @@ public class OfferReviewer { statement = connection.createStatement(); // Execute the query to retrieve the entries - String query = "SELECT dataOrigin, productId, currentPrice FROM table"; + String query = "SELECT sourceProduct, saleProduct, creationDate, upDate, " + + "checkDate, offerId FROM table"; resultSet = statement.executeQuery(query); // Process the retrieved entries while (resultSet.next()) { - String webshop = resultSet.getString("webshop"); - String dataOrigin = resultSet.getString("data_origin"); - String productId = resultSet.getString("productId"); - double currentPrice = resultSet.getDouble("currentPrice"); - String merchant = resultSet.getString("merchant"); - double deliveryPrice = resultSet.getDouble("delivery_price"); - boolean available = resultSet.getBoolean("available"); + Product sourceProduct = (Product) resultSet.getObject("sourceProduct"); + Product saleProduct = (Product) resultSet.getObject("saleProduct"); + java.sql.Date creationDate = resultSet.getDate("creationDate"); + Date updateDate = resultSet.getDate("upDate"); + Date checkDate = resultSet.getDate("checkDate"); + String offerId = resultSet.getString("offerId"); // Call the API to get the current price - double apiPrice = getPriceFromAPI(productId); + double apiPrice = getPriceFromAPI(sourceProduct); // Compare the prices - if (currentPrice != apiPrice) { - // Price has changed, create a Product object and add it to the changedProducts list - Product product = new Product(webshop, dataOrigin, productId, currentPrice, - merchant, deliveryPrice, available); - changedProducts.add(product); + if (saleProduct.getCurrentPrice() != apiPrice) { + // Price has changed, create a Product object and add it to the changedProducts list + Offer offer = new Offer(); + changedOffers.add(offer); } } } catch (SQLException e) { From d0b6178d26edc83b428d747e32b4f208419cd5fd Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 00:14:41 +0200 Subject: [PATCH 17/49] deleted an unused import --- src/main/java/de/rwu/easydrop/core/OfferReviewer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java index 5b698bf..ba9e3d4 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java +++ b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java @@ -2,7 +2,6 @@ package de.rwu.easydrop.core; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.Product; -import de.rwu.easydrop.model.Product.webshop; import java.util.List; import java.sql.Connection; From 22ee3f3d347ee79a8531754c47012af87cdb97e8 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Tue, 27 Jun 2023 00:45:41 +0200 Subject: [PATCH 18/49] Added webshops enum --- src/main/java/de/rwu/easydrop/model/Webshop.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/de/rwu/easydrop/model/Webshop.java diff --git a/src/main/java/de/rwu/easydrop/model/Webshop.java b/src/main/java/de/rwu/easydrop/model/Webshop.java new file mode 100644 index 0000000..b653b39 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/model/Webshop.java @@ -0,0 +1,15 @@ +package de.rwu.easydrop.model; + +/** + * Constants for data source/destination platforms. + */ +public enum Webshop { + /** + * Amazon. + */ + Amazon, + /** + * eBay. + */ + eBay +} From 1e5ee7259496af94464e9d406c81782a722608e1 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 01:48:10 +0200 Subject: [PATCH 19/49] added offerupdater --- .../de/rwu/easydrop/core/OfferReviewer.java | 4 +- .../de/rwu/easydrop/core/OfferUpdater.java | 105 ++++++++++++++++-- 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java index ba9e3d4..e394093 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java +++ b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java @@ -59,7 +59,6 @@ public class OfferReviewer { } catch (SQLException e) { e.printStackTrace(); } finally { - // Close the resources (resultSet, statement, connection) in a finally block try { if (resultSet != null) { resultSet.close(); @@ -76,4 +75,7 @@ public class OfferReviewer { } return new ArrayList(); } + + + } diff --git a/src/main/java/de/rwu/easydrop/core/OfferUpdater.java b/src/main/java/de/rwu/easydrop/core/OfferUpdater.java index 33091cb..27d08a9 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferUpdater.java +++ b/src/main/java/de/rwu/easydrop/core/OfferUpdater.java @@ -1,21 +1,110 @@ package de.rwu.easydrop.core; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.util.List; import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; + public class OfferUpdater { + /** + * a. + */ public OfferUpdater() { + OfferReviewer offerReviewer = new OfferReviewer(); + List changedOffers = offerReviewer.checkOffer(); } - - public void runUpdater(List offersToUpdate) { - /* - * Bekommt vom OfferReviewer eine Liste mit zu ändernden Offers übergeben. - * Bei availability=false löscht der Updater das Angebot aus der Datenbank und von der Zielplattform. - * Der Updater ändert die geänderten Parameter in der Liste in der Datenbank und in der Zielplattform ab. - * Er ändert das upDate in der Datenbank nach der Änderung. - */ + /** + * A. + * @param offersToUpdate + */ + public void runUpdater(final List offersToUpdate) { + Connection connection = null; + PreparedStatement deleteStatement = null; + PreparedStatement insertStatement = null; + + try { + // Establish the database connection + connection = DriverManager.getConnection("jdbc:sqlite:persistence.db"); + + // Disable auto-commit to perform a transaction + connection.setAutoCommit(false); + + // Prepare the DELETE statement to remove the existing entries + String deleteQuery = "DELETE FROM your_table WHERE product_id = ?"; + deleteStatement = connection.prepareStatement(deleteQuery); + + // Prepare the INSERT statement to add the new entries + String insertQuery = "INSERT INTO your_table (product_id, product_name, price)" + + "VALUES (?, ?, ?)"; + insertStatement = connection.prepareStatement(insertQuery); + + // Retrieve the existing entries from the database + List existingProducts = retrieveExistingProducts(connection); + + // Delete the existing entries that are not present in the changedProducts list + for (Product existingProduct : existingProducts) { + if (!changedOffers.(existingProduct)) { + deleteStatement.setString(1, existingProduct.getProductId()); + deleteStatement.executeUpdate(); + } + } + + // Insert the new entries or update the existing entries + for (Product changedOffers : offersToUpdate) { + if (existingProducts.contains(changedOffers)) { + // Update the existing entry with the new data + // You need to modify the update query and statement based on your requirements + // Here's an example of updating the price of an existing entry + String updateQuery = "UPDATE table SET currentPrice = ? WHERE offerId = ?"; + PreparedStatement updateStatement = connection.prepareStatement(updateQuery); + updateStatement.setDouble(1, changedOffers.getCurrentPrice()); + updateStatement.setString(2, changedOffers.getProductId()); + updateStatement.executeUpdate(); + updateStatement.close(); + } else { + // Insert the new entry + insertStatement.setString(1, changedOffers.getProductId()); + insertStatement.setString(2, changedOffers.getMerchant()); + insertStatement.setDouble(3, changedOffers.getCurrentPrice()); + insertStatement.executeUpdate(); + } + } + + // Commit the transaction + connection.commit(); + } catch (SQLException e) { + // Rollback the transaction in case of an exception + if (connection != null) { + try { + connection.rollback(); + } catch (SQLException rollbackException) { + rollbackException.printStackTrace(); + } + } + e.printStackTrace(); + } finally { + // Close the resources (deleteStatement, insertStatement, connection) in a finally block + try { + if (deleteStatement != null) { + deleteStatement.close(); + } + if (insertStatement != null) { + insertStatement.close(); + } + if (connection != null) { + connection.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } } } +} + From 463932f8e9db11086944f5e99c96f53241f4d4cb Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Tue, 27 Jun 2023 02:56:28 +0200 Subject: [PATCH 20/49] Webshops refactoring + checkstyle --- .../api/client/AbstractDataSource.java | 17 +++---- .../api/client/AbstractDataWriter.java | 5 +- .../api/client/AmazonProductDataSource.java | 5 +- .../easydrop/api/client/AmazonPurchaser.java | 6 ++- .../rwu/easydrop/api/client/AmazonSeller.java | 6 ++- .../api/client/EbayItemDataSource.java | 5 +- .../easydrop/api/client/EbayPurchaser.java | 6 ++- .../rwu/easydrop/api/client/EbaySeller.java | 6 ++- .../de/rwu/easydrop/api/dto/OfferDTO.java | 33 ++++++------- .../de/rwu/easydrop/api/dto/ProductDTO.java | 7 +-- src/main/java/de/rwu/easydrop/core/Core.java | 39 ++++++++------- .../de/rwu/easydrop/core/OfferIdentifier.java | 35 +++++--------- .../rwu/easydrop/core/OfferProvisioner.java | 47 +++++++------------ .../de/rwu/easydrop/core/package-info.java | 6 +++ .../connector/AbstractOfferPersistence.java | 15 +++--- .../data/connector/SQLiteConnector.java | 18 ++++--- .../java/de/rwu/easydrop/model/Product.java | 15 +----- .../java/de/rwu/easydrop/model/Webshop.java | 22 +++++++-- .../easydrop/service/mapping/OfferMapper.java | 3 +- .../service/retriever/CatalogueRetriever.java | 12 +---- .../service/retriever/OfferRetriever.java | 9 ---- .../service/retriever/ProductRetriever.java | 33 ++++++------- .../service/validation/ProductValidator.java | 21 --------- .../de/rwu/easydrop/util/ProductsConfig.java | 5 +- 24 files changed, 168 insertions(+), 208 deletions(-) create mode 100644 src/main/java/de/rwu/easydrop/core/package-info.java 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 5d410a8..bfdad1a 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/AbstractDataSource.java @@ -9,6 +9,7 @@ import java.net.URL; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.DataSourceException; +import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.util.FormattingUtil; /** @@ -23,7 +24,7 @@ public abstract class AbstractDataSource implements DataSource { * * @return Data source name */ - protected abstract String getDataOrigin(); + protected abstract Webshop getDataOrigin(); /** * Returns the data source's API key. @@ -48,7 +49,7 @@ public abstract class AbstractDataSource implements DataSource { public ProductDTO getProductDTOById(final String productIdentifier) throws IllegalArgumentException { StringBuilder response = new StringBuilder(); - String dataOrigin = getDataOrigin(); + Webshop dataOrigin = getDataOrigin(); String apiKey = getApiKey(); ProductDTO product = new ProductDTO(productIdentifier, dataOrigin); @@ -72,20 +73,16 @@ public abstract class AbstractDataSource implements DataSource { + responseCode); } - - String line; + String line; while ((line = reader.readLine()) != null) { response.append(line); } reader.close(); - // FIXME: Mock not complete. Data is missing - // FIXME response can be empty String data; - if (response.toString().isEmpty()){ - data = "{}"; - } - else { + if (response.toString().isEmpty()) { + data = "{}"; + } else { data = response.toString(); } buildProductDTO(product, data); diff --git a/src/main/java/de/rwu/easydrop/api/client/AbstractDataWriter.java b/src/main/java/de/rwu/easydrop/api/client/AbstractDataWriter.java index fd7a615..6357230 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AbstractDataWriter.java +++ b/src/main/java/de/rwu/easydrop/api/client/AbstractDataWriter.java @@ -7,6 +7,7 @@ import java.net.URL; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.DataWriterException; +import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.util.FormattingUtil; /** @@ -28,7 +29,7 @@ public abstract class AbstractDataWriter { * * @return Data target API name */ - protected abstract String getDataTarget(); + protected abstract Webshop getDataTarget(); /** * Creates an URL object to connect to the API with. @@ -47,7 +48,7 @@ public abstract class AbstractDataWriter { */ protected void sendPutRequest(final ProductDTO dto, final String apiType) { String apiKey = getApiKey(); - String dataTarget = getDataTarget(); + Webshop dataTarget = getDataTarget(); if (!dataTarget.equals(dto.getDataOrigin())) { throw new DataWriterException( 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 83b758d..404398c 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java @@ -8,6 +8,7 @@ import com.jayway.jsonpath.PathNotFoundException; import com.jayway.jsonpath.ReadContext; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.model.Webshop; /** * Interface to an Amazon data source. @@ -18,7 +19,7 @@ public final class AmazonProductDataSource extends AbstractDataSource { /** * Name of this data source. */ - private static final String DATA_ORIGIN = "Amazon"; + private static final Webshop DATA_ORIGIN = Webshop.Amazon; /** * Base URL to the Amazon data source. */ @@ -82,7 +83,7 @@ public final class AmazonProductDataSource extends AbstractDataSource { } @Override - protected String getDataOrigin() { + protected Webshop getDataOrigin() { return DATA_ORIGIN; } diff --git a/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java b/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java index 283ed61..d1dc75c 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java @@ -3,6 +3,8 @@ package de.rwu.easydrop.api.client; import java.net.MalformedURLException; import java.net.URL; +import de.rwu.easydrop.model.Webshop; + /** * Sends a buy request to the Amazon API. * @@ -12,7 +14,7 @@ public final class AmazonPurchaser extends AbstractPurchaser { /** * Name of this data source. */ - private static final String DATA_TARGET = "Amazon"; + private static final Webshop DATA_TARGET = Webshop.Amazon; /** * Base URL to the Amazon Purchase API. */ @@ -61,7 +63,7 @@ public final class AmazonPurchaser extends AbstractPurchaser { } @Override - protected String getDataTarget() { + protected Webshop getDataTarget() { return DATA_TARGET; } } diff --git a/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java b/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java index 8a47d51..7b33138 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java @@ -3,6 +3,8 @@ package de.rwu.easydrop.api.client; import java.net.MalformedURLException; import java.net.URL; +import de.rwu.easydrop.model.Webshop; + /** * Sends a sell request to the Amazon API. * @@ -12,7 +14,7 @@ public final class AmazonSeller extends AbstractSeller { /** * Name of this data source. */ - private static final String DATA_TARGET = "Amazon"; + private static final Webshop DATA_TARGET = Webshop.Amazon; /** * Base URL to the Amazon Purchase API. */ @@ -61,7 +63,7 @@ public final class AmazonSeller extends AbstractSeller { } @Override - protected String getDataTarget() { + protected Webshop getDataTarget() { return DATA_TARGET; } } 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 171b8b9..5e62394 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java @@ -8,6 +8,7 @@ import com.jayway.jsonpath.PathNotFoundException; import com.jayway.jsonpath.ReadContext; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.model.Webshop; /** * Interface to an eBay data source. @@ -18,7 +19,7 @@ public final class EbayItemDataSource extends AbstractDataSource { /** * Name of this data source. */ - private static final String DATA_ORIGIN = "eBay"; + private static final Webshop DATA_ORIGIN = Webshop.eBay; /** * Base URL to the eBay data source. */ @@ -77,7 +78,7 @@ public final class EbayItemDataSource extends AbstractDataSource { } @Override - protected String getDataOrigin() { + protected Webshop getDataOrigin() { return DATA_ORIGIN; } diff --git a/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java b/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java index d9f69f8..ebaf121 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java @@ -3,6 +3,8 @@ package de.rwu.easydrop.api.client; import java.net.MalformedURLException; import java.net.URL; +import de.rwu.easydrop.model.Webshop; + /** * Sends a buy request to the eBay API. * @@ -12,7 +14,7 @@ public final class EbayPurchaser extends AbstractPurchaser { /** * Name of this data source. */ - private static final String DATA_TARGET = "eBay"; + private static final Webshop DATA_TARGET = Webshop.eBay; /** * Base URL to the eBay Purchase API. */ @@ -46,7 +48,7 @@ public final class EbayPurchaser extends AbstractPurchaser { } @Override - protected String getDataTarget() { + protected Webshop getDataTarget() { return DATA_TARGET; } } diff --git a/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java b/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java index 805ee5d..55835ec 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java @@ -3,6 +3,8 @@ package de.rwu.easydrop.api.client; import java.net.MalformedURLException; import java.net.URL; +import de.rwu.easydrop.model.Webshop; + /** * Sends a sell request to the eBay API. * @@ -12,7 +14,7 @@ public final class EbaySeller extends AbstractSeller { /** * Name of this data source. */ - private static final String DATA_TARGET = "eBay"; + private static final Webshop DATA_TARGET = Webshop.eBay; /** * Base URL to the eBay Purchase API. */ @@ -46,7 +48,7 @@ public final class EbaySeller extends AbstractSeller { } @Override - protected String getDataTarget() { + protected Webshop getDataTarget() { return DATA_TARGET; } } diff --git a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java index ee7d5f4..c2d680f 100644 --- a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java +++ b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java @@ -14,36 +14,37 @@ public class OfferDTO { */ private String offerId; - /* - * The product that our software buys + /** + * The product that our software buys. */ - Product sourceProduct; + private Product sourceProduct; - /* - * The product that our software sells + /** + * The product that our software sells. */ - Product saleProduct; + private Product saleProduct; - /* + /** * Date of the creation of the offer - * NOTE: Use Timestamp? https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html + * NOTE: Use Timestamp? + * https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html */ - Date creationDate; + private Date creationDate; - /* - * Date of last update of the offer on the destination website (API) + /** + * Date of last update of the offer on the destination website (API). */ - Date upDate; + private Date upDate; - /* - * Date of last check if offer is still valid + /** + * Date of last check if offer is still valid. */ - Date checkDate; + private Date checkDate; /** * Creates OfferDTO instance. * - * @param newOfferId Internal Offer identifier + * @param newOfferId Internal Offer identifier */ public OfferDTO(final String newOfferId) { this.offerId = newOfferId; diff --git a/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java b/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java index f6beb85..7d7ea70 100644 --- a/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java +++ b/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java @@ -1,5 +1,6 @@ package de.rwu.easydrop.api.dto; +import de.rwu.easydrop.model.Webshop; import lombok.Data; /** @@ -10,9 +11,9 @@ import lombok.Data; @Data public class ProductDTO { /** - * Data source platform, like "Amazon". + * Data source platform, like Amazon. */ - private String dataOrigin; + private Webshop dataOrigin; /** * Platform internal product identifier. @@ -45,7 +46,7 @@ public class ProductDTO { * @param newProductId Internal Product indetifier * @param newDataOrigin Data Origin */ - public ProductDTO(final String newProductId, final String newDataOrigin) { + public ProductDTO(final String newProductId, final Webshop newDataOrigin) { this.productId = newProductId; this.dataOrigin = newDataOrigin; } diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java index d8fcd99..ce7e63b 100644 --- a/src/main/java/de/rwu/easydrop/core/Core.java +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -7,32 +7,39 @@ import javax.naming.ConfigurationException; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.ProductCatalogue; +/** + * The application core. + * + * @since 0.3.0 + */ public class Core { - + /** + * Offer identifier. + */ private OfferIdentifier ident; + /** + * Offer provisioner. + */ private OfferProvisioner provis; - private OfferReviewer review; - private OfferUpdater update; - - public Core() throws ConfigurationException{ + /** + * Constructor. + * + * @throws ConfigurationException + */ + public Core() throws ConfigurationException { this.ident = new OfferIdentifier(); this.provis = new OfferProvisioner(); - this.review = new OfferReviewer(); - this.update = new OfferUpdater(); } - - public void runCore(List pCats){ + /** + * Runs the core. + * + * @param pCats + */ + public void runCore(final List pCats) { List identifiedOffers = ident.runIdentifier(pCats); provis.runProvisioner(identifiedOffers); - List updatingOffers = review.runReviewer(); - update.runUpdater(updatingOffers); - - - } - - } diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java index b240d0f..99d4b23 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java @@ -14,7 +14,6 @@ import de.rwu.easydrop.service.retriever.OfferRetriever; import de.rwu.easydrop.service.processing.OrderManager; import de.rwu.easydrop.exception.InvalidCatalogueException; - public class OfferIdentifier { /** * Logger for main process. @@ -24,13 +23,15 @@ public class OfferIdentifier { * OfferRetriever gets the offer from persistence. */ private OfferRetriever offerRetriever; + /** * OfferIdentifier identifies offers that are * feasible to place on a target platform based on * their margin. + * * @throws ConfigurationException */ - public OfferIdentifier() throws ConfigurationException{ + public OfferIdentifier() throws ConfigurationException { this.offerRetriever = new OfferRetriever(); } @@ -38,6 +39,7 @@ public class OfferIdentifier { * runIdentifier calls the price function that decides * if it is feasible to dropship products and if so, * at which margin. + * * @param pCats * @return newOffers */ @@ -53,36 +55,25 @@ public class OfferIdentifier { possibleOffer.setSaleProduct(pair.getProduct2()); identifiedOffers.add(possibleOffer); LOGGER.info( - "Identified offer " - + - pair.getProduct1().getProductId() - + - " -> " - + - pair.getProduct2().getProductId() - ); + "Identified offer " + + + pair.getProduct1().getProductId() + + + " -> " + + + pair.getProduct2().getProductId()); // Following fields will be set if offer confirmed // creationDate, offerId // Following fields will be set if offer needs update // upDate - } - catch (InvalidCatalogueException e) { + } catch (InvalidCatalogueException e) { // if no margin, getHighestMarginProducts will throw System.out.print("product has no margin"); } } List newOffers = new ArrayList<>(); - List existingOffers = offerRetriever.loadOffers(); - for (Offer identifiedOffer: identifiedOffers) { + for (Offer identifiedOffer : identifiedOffers) { boolean isNew = true; - for (Offer existingOffer: existingOffers) { - if ( - existingOffer.getSourceProduct().getProductId(). - equals(identifiedOffer.getSourceProduct().getProductId())) { - isNew = false; - break; - } - } if (isNew) { newOffers.add(identifiedOffer); } diff --git a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java index 457256a..0f318bd 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java @@ -2,33 +2,23 @@ package de.rwu.easydrop.core; import java.util.List; -import de.rwu.easydrop.util.Config; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; -import de.rwu.easydrop.exception.DataWriterException; -import de.rwu.easydrop.model.Offer; -import de.rwu.easydrop.service.retriever.ProductRetriever; -import de.rwu.easydrop.service.writer.OfferWriter; import de.rwu.easydrop.api.client.AmazonSeller; import de.rwu.easydrop.api.client.EbaySeller; -import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.exception.DataWriterException; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Webshop; +import de.rwu.easydrop.service.mapping.ProductMapper; +import de.rwu.easydrop.service.writer.OfferWriter; +import de.rwu.easydrop.util.Config; public class OfferProvisioner { /** * Config. */ private Config config; - /** - * Gets the products from persistence. - */ - private ProductRetriever productRetriever; - // ProductWriter - /** - * Is the product databank. - */ - private AbstractProductPersistence db; /** * Writes offers into persistence. - */ + */ private OfferWriter offerWriter; /** @@ -41,16 +31,11 @@ public class OfferProvisioner { private EbaySeller ebaySeller; private void toSeller(final Offer offer) throws IllegalArgumentException { - // TODO dataOrigin should use the webshop enum - if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("ebay")) { - this.ebaySeller.sellProduct(new ProductDTO( - offer.getSaleProduct().getProductId(), - "Amazon")); + if (offer.getSaleProduct().getDataOrigin() == Webshop.eBay) { + this.ebaySeller.sellProduct(ProductMapper.mapProductToDTO(offer.getSaleProduct())); - } else if (offer.getSaleProduct().getDataOrigin().toLowerCase().equals("amazon")) { - this.amazonSeller.sellProduct(new ProductDTO( - offer.getSaleProduct().getProductId(), - "eBay")); + } else if (offer.getSaleProduct().getDataOrigin().equals(Webshop.Amazon)) { + this.amazonSeller.sellProduct(ProductMapper.mapProductToDTO(offer.getSaleProduct())); } else { throw new IllegalArgumentException("Unsupported target plattform"); } @@ -74,11 +59,12 @@ public class OfferProvisioner { /** * Method for placing orders on a target platform. + * * @param offersToProvision */ public final void runProvisioner(final List offersToProvision) { - for (Offer newOffer: offersToProvision){ + for (Offer newOffer : offersToProvision) { try { this.toSeller(newOffer); @@ -92,10 +78,9 @@ public class OfferProvisioner { } } catch (IllegalArgumentException e) { System.out.println( - "Offer could not be placed, " + - newOffer.getSaleProduct().getDataOrigin() + - " is not supported" - ); + "Offer could not be placed, " + + newOffer.getSaleProduct().getDataOrigin() + + " is not supported"); } catch (DataWriterException e) { System.out.println("could not transmit offer"); } diff --git a/src/main/java/de/rwu/easydrop/core/package-info.java b/src/main/java/de/rwu/easydrop/core/package-info.java new file mode 100644 index 0000000..c0963c1 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/core/package-info.java @@ -0,0 +1,6 @@ +/** + * EasyDrop's core. + * + * @since 0.3.0 + */ +package de.rwu.easydrop.core; diff --git a/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java b/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java index 4562a6d..5f4bbeb 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java +++ b/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java @@ -2,12 +2,7 @@ package de.rwu.easydrop.data.connector; import de.rwu.easydrop.api.dto.OfferDTO; -public abstract class AbstractOfferPersistence { - /** - * Data origin. - */ - public static final String DATA_ORIGIN = "Persistence"; - +public abstract class AbstractOfferPersistence { /** * Writes a ProductDTO to persistence. * @@ -17,12 +12,14 @@ public abstract class AbstractOfferPersistence { /** * Gets a OfferDTO from persistence. + * + * @param offerId + * @return Offer data transfer object */ - //@Override - public abstract OfferDTO getOfferDTOById(String OfferId); + public abstract OfferDTO getOfferDTOById(String offerId); /** * Deletes all data from persistence. */ - public abstract void clearData(); + public abstract void clearData(); } diff --git a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java index 6947c5d..43bb4fe 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java +++ b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java @@ -11,6 +11,7 @@ import org.sqlite.SQLiteDataSource; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.PersistenceException; +import de.rwu.easydrop.model.Webshop; /** * Allows connecting to a SQLite Database. @@ -18,11 +19,6 @@ import de.rwu.easydrop.exception.PersistenceException; * @since 0.2.0 */ public final class SQLiteConnector extends AbstractProductPersistence { - /** - * Data origin. - */ - private static final String DATA_ORIGIN = "SQLite"; - /** * SQLite Database. */ @@ -95,7 +91,7 @@ public final class SQLiteConnector extends AbstractProductPersistence { PreparedStatement statement = connection.prepareStatement(query)) { int index = 0; - statement.setString(++index, dto.getDataOrigin()); + statement.setString(++index, dto.getDataOrigin().toString()); statement.setString(++index, dto.getProductId()); statement.setDouble(++index, dto.getCurrentPrice()); statement.setString(++index, dto.getMerchant()); @@ -120,8 +116,9 @@ public final class SQLiteConnector extends AbstractProductPersistence { try (ResultSet resultSet = statement.executeQuery()) { if (resultSet.next()) { - dto = new ProductDTO(resultSet.getString("productId"), - resultSet.getString("dataOrigin")); + Webshop newShop = Webshop.fromString(resultSet.getString("dataOrigin")); + + dto = new ProductDTO(resultSet.getString("productId"), newShop); dto.setCurrentPrice(resultSet.getDouble("currentPrice")); dto.setMerchant(resultSet.getString("merchant")); dto.setDeliveryPrice(resultSet.getDouble("deliveryPrice")); @@ -149,8 +146,9 @@ public final class SQLiteConnector extends AbstractProductPersistence { } @Override - protected String getDataOrigin() { - return DATA_ORIGIN; + protected Webshop getDataOrigin() { + throw new UnsupportedOperationException( + this.getClass().getName() + " doesn't support getDataOrigin"); } @Override diff --git a/src/main/java/de/rwu/easydrop/model/Product.java b/src/main/java/de/rwu/easydrop/model/Product.java index d484405..7e84311 100644 --- a/src/main/java/de/rwu/easydrop/model/Product.java +++ b/src/main/java/de/rwu/easydrop/model/Product.java @@ -10,23 +10,10 @@ import lombok.Data; */ @Data public class Product { - /** - * Constants for data source/destination platforms. - */ - public enum Webshop { - /** - * Amazon. - */ - AMAZON, - /**Ebay. - */ - EBAY - } - /** * Data source platform, like "Amazon". */ - private String dataOrigin; + private Webshop dataOrigin; /** * Platform internal product identifier. diff --git a/src/main/java/de/rwu/easydrop/model/Webshop.java b/src/main/java/de/rwu/easydrop/model/Webshop.java index b653b39..c4852b6 100644 --- a/src/main/java/de/rwu/easydrop/model/Webshop.java +++ b/src/main/java/de/rwu/easydrop/model/Webshop.java @@ -5,11 +5,27 @@ package de.rwu.easydrop.model; */ public enum Webshop { /** - * Amazon. + * Amazon Product API. */ Amazon, /** - * eBay. + * eBay Item API. */ - eBay + eBay; + + /** + * Attempts to derive a webshop value from a string. + * + * @param str String + * @return webshop + * @throws IllegalArgumentException + */ + public static Webshop fromString(final String str) { + for (Webshop shop : Webshop.values()) { + if (shop.toString().equalsIgnoreCase(str)) { + return shop; + } + } + throw new IllegalArgumentException(String.format("No webshop called {} found", str)); + } } diff --git a/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java b/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java index f6aeb73..a83a148 100644 --- a/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java +++ b/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java @@ -11,7 +11,6 @@ import de.rwu.easydrop.model.Offer; * * @see Offer * @see OfferDTO - * @see OfferDTO */ public final class OfferMapper { @@ -39,7 +38,7 @@ public final class OfferMapper { /** * Creates an OfferDTO object from a corresponding offer. * - * @param Offer offer + * @param offer * @return OfferDTO */ public static OfferDTO mapOfferToDTO(final Offer offer) { diff --git a/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java index 64bb8c0..c299412 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java @@ -5,7 +5,6 @@ import java.util.List; import javax.naming.ConfigurationException; -import de.rwu.easydrop.exception.InvalidProductException; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; import de.rwu.easydrop.util.ProductsConfig; @@ -58,16 +57,9 @@ public class CatalogueRetriever { for (Product product : pCat.getProducts()) { Product newProduct = new Product(); - newProduct.setDataOrigin(product.getDataOrigin()); - newProduct.setProductId(product.getProductId()); - if (newProduct.getDataOrigin().equals("Amazon")) { - newProduct = productRetriever.getProductFromAmazon(product.getProductId()); - } else if (newProduct.getDataOrigin().equals("eBay")) { - newProduct = productRetriever.getProductFromEbay(product.getProductId()); - } else { - throw new InvalidProductException("Product data origin is invalid"); - } + newProduct = productRetriever.getProductFromWebshop(product.getDataOrigin(), + product.getProductId()); newProductCatalogue.addProduct(newProduct); } diff --git a/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java index 3571b7d..5488b29 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java @@ -1,14 +1,5 @@ package de.rwu.easydrop.service.retriever; -import de.rwu.easydrop.model.Offer; - -import java.util.ArrayList; -import java.util.List; - public class OfferRetriever { - public List loadOffers() { - return new ArrayList<>(); - } - } diff --git a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java index 8b814f9..ddbe4b1 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java @@ -6,6 +6,7 @@ import de.rwu.easydrop.api.client.EbayItemDataSource; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.data.connector.AbstractProductPersistence; import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.service.mapping.ProductMapper; import de.rwu.easydrop.service.validation.ProductValidator; @@ -21,9 +22,9 @@ public class ProductRetriever { private DataSourceFactory dataSourceFactory; /** - * @param newDataSourceFactory the dataSourceFactory to set + * @param newDataSourceFactory the WebshopFactory to set */ - public void setDataSourceFactory(final DataSourceFactory newDataSourceFactory) { + public void setWebshopFactory(final DataSourceFactory newDataSourceFactory) { this.dataSourceFactory = newDataSourceFactory; } @@ -31,7 +32,7 @@ public class ProductRetriever { * @param newDataSourceFactory */ public ProductRetriever(final DataSourceFactory newDataSourceFactory) { - this.setDataSourceFactory(newDataSourceFactory); + this.setWebshopFactory(newDataSourceFactory); } /** @@ -83,23 +84,23 @@ public class ProductRetriever { } /** - * Retrieves a product from an API by name of the API so that high-level components do not need to be extended + * Retrieves a product from an API by name of the API so that high-level + * components do not need to be extended * with exact function call names if we extend the list of webshops. * - * @param dataSourceName Data source name, e.g. amazon - * @param productName Product name, translated to the correct product ID for the data source + * @param shop Data source name, e.g. Amazon + * @param productIdentifier Product name, translated to the correct product ID + * for the data source * @return Product from that data source or null if data source not available */ - public Product getProductFromDataSource(Product.webshop dataSourceName, final String productName) { - switch(dataSourceName) { - case AMAZON: - // TODO: Translation from productName to productId (Amazon) needed - return getProductFromAmazon(productName); - case EBAY: - // TODO: Translation from productName to productId (eBay) needed - return getProductFromEbay(productName); - default: - return null; + public Product getProductFromWebshop(final Webshop shop, final String productIdentifier) { + switch (shop) { + case Amazon: + return getProductFromAmazon(productIdentifier); + case eBay: + return getProductFromEbay(productIdentifier); + default: + return null; } } } diff --git a/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java b/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java index fc48377..f74f054 100644 --- a/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java +++ b/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java @@ -1,8 +1,5 @@ package de.rwu.easydrop.service.validation; -import java.util.HashSet; -import java.util.Set; - import de.rwu.easydrop.exception.InvalidProductException; import de.rwu.easydrop.model.Product; @@ -31,26 +28,8 @@ public final class ProductValidator { if (product.getCurrentPrice() == 0.00) { throw new InvalidProductException("Current price cannot be 0.00"); } - if (!isInValidDataOrigins(product.getDataOrigin())) { - throw new InvalidProductException("Unknown data source"); - } if (product.getProductId().equals("")) { throw new InvalidProductException("Product ID cannot be empty"); } } - - /** - * Checks whether a dataOrigin is within the set of valid ones. - * - * @param dataOrigin like "Amazon" - * @return true if valid - */ - public static boolean isInValidDataOrigins(final String dataOrigin) { - Set validOrigins = new HashSet<>(); - - validOrigins.add("Amazon"); - validOrigins.add("eBay"); - - return validOrigins.contains(dataOrigin); - } } diff --git a/src/main/java/de/rwu/easydrop/util/ProductsConfig.java b/src/main/java/de/rwu/easydrop/util/ProductsConfig.java index b69777f..2295a45 100644 --- a/src/main/java/de/rwu/easydrop/util/ProductsConfig.java +++ b/src/main/java/de/rwu/easydrop/util/ProductsConfig.java @@ -13,6 +13,7 @@ import com.jayway.jsonpath.JsonPathException; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.model.Webshop; /** * Reads the user-specified catalogue of products. @@ -122,8 +123,8 @@ public final class ProductsConfig { ArrayList> identifiers = JsonPath.read(jsonIdentifiers, "$"); for (HashMap product : identifiers) { - String dataOrigin = product.keySet().iterator().next(); - String identifier = product.get(dataOrigin).toString(); + Webshop dataOrigin = Webshop.fromString(product.keySet().iterator().next()); + String identifier = product.get(dataOrigin.toString()).toString(); Product newProduct = new Product(); newProduct.setDataOrigin(dataOrigin); From 956223bea7a524669ad72f4010e82862794aeea0 Mon Sep 17 00:00:00 2001 From: Leonie Eitze Date: Tue, 27 Jun 2023 02:56:48 +0200 Subject: [PATCH 21/49] Updated tests accordingly --- .../api/client/AbstractDataWriterTest.java | 28 ++++--------- .../api/client/AbstractPurchaserTest.java | 5 ++- .../api/client/AbstractSellerTest.java | 5 ++- .../client/AmazonProductDataSourceTest.java | 29 ++++++------- .../api/client/AmazonPurchaserTest.java | 8 ++-- .../easydrop/api/client/AmazonSellerTest.java | 6 ++- .../api/client/DataSourceFactoryTest.java | 18 ++++---- .../api/client/EbayItemDataSourceTest.java | 17 ++++---- .../api/client/EbayPurchaserTest.java | 6 ++- .../easydrop/api/client/EbaySellerTest.java | 6 ++- .../rwu/easydrop/api/dto/ProductDTOTest.java | 12 +++--- .../java/de/rwu/easydrop/core/CoreTest.java | 27 ------------ .../data/connector/SQLiteConnectorTest.java | 27 ++++-------- .../easydrop/model/ProductCatalogueTest.java | 16 ++++---- .../de/rwu/easydrop/model/ProductTest.java | 12 +++--- .../service/mapping/ProductMapperTest.java | 7 ++-- .../retriever/CatalogueRetrieverTest.java | 41 ++++--------------- .../retriever/ProductRetrieverTest.java | 19 +++++---- .../validation/ProductValidatorTest.java | 41 ++----------------- .../service/writer/CatalogueWriterTest.java | 11 ++--- .../service/writer/ProductWriterTest.java | 5 ++- 21 files changed, 126 insertions(+), 220 deletions(-) diff --git a/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java b/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java index edc8ad8..97b007e 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java @@ -21,6 +21,7 @@ import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.DataWriterException; +import de.rwu.easydrop.model.Webshop; class AbstractDataWriterTest { private static String demoProductId = "whateverId"; @@ -42,8 +43,8 @@ class AbstractDataWriterTest { } @Override - protected String getDataTarget() { - return "Test"; + protected Webshop getDataTarget() { + return Webshop.Amazon; } @Override @@ -53,21 +54,10 @@ class AbstractDataWriterTest { }; } - @Test - void sendPutRequest_wrongDataSource_throwsException() { - ProductDTO dto = new ProductDTO(demoProductId, "Amazon"); - - DataWriterException e = assertThrows(DataWriterException.class, () -> { - writer.sendPutRequest(dto, "testApiType"); - }); - - assertEquals("Product data source and target testApiType API are incompatible.", e.getMessage()); - } - @Test void sendPutRequest_badResponseCode_throwsException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO(demoProductId, "Test"); + ProductDTO dto = new ProductDTO(demoProductId, Webshop.Amazon); // Set up Mocks AbstractDataWriter mockWriter = mock(AbstractDataWriter.class); @@ -79,13 +69,13 @@ class AbstractDataWriterTest { writer.sendPutRequest(dto, "Sales"); }); - assertEquals("Test Sales API responded with error code 400", e.getMessage()); + assertEquals("Amazon Sales API responded with error code 400", e.getMessage()); } @Test void sendPutRequest_ioException_throwsException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO(demoProductId, "Test"); + ProductDTO dto = new ProductDTO(demoProductId, Webshop.Amazon); // Set up Mocks AbstractDataWriter mockWriter = mock(AbstractDataWriter.class); @@ -96,13 +86,13 @@ class AbstractDataWriterTest { writer.sendPutRequest(dto, "testApiType"); }); - assertEquals("Couldn't fulfill Test API request", e.getMessage()); + assertEquals("Couldn't fulfill Amazon API request", e.getMessage()); } @Test void sendPutRequest_successfulRequest() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO(demoProductId, "test"); + ProductDTO dto = new ProductDTO(demoProductId, Webshop.Amazon); // Set up Mocks AbstractDataWriter mockWriter = mock(AbstractDataWriter.class); @@ -112,7 +102,7 @@ class AbstractDataWriterTest { HttpURLConnection mockConnection = mock(HttpURLConnection.class); when(mockURL.openConnection()).thenReturn(mockConnection); when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - when(mockWriter.getDataTarget()).thenReturn("test"); + when(mockWriter.getDataTarget()).thenReturn(Webshop.Amazon); assertDoesNotThrow(() -> { mockWriter.sendPutRequest(dto, "Purchase"); diff --git a/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java b/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java index f252264..0a62b8e 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java @@ -13,6 +13,7 @@ import java.net.URL; import org.junit.jupiter.api.Test; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.model.Webshop; class AbstractPurchaserTest { private AbstractPurchaser mockPurchaser = mock(AbstractPurchaser.class); @@ -20,7 +21,7 @@ class AbstractPurchaserTest { @Test void purchaseProduct_CorrectApiTypeInException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO("12345", "test"); + ProductDTO dto = new ProductDTO("12345", Webshop.Amazon); // Set up mocks URL mockURL = mock(URL.class); @@ -29,7 +30,7 @@ class AbstractPurchaserTest { HttpURLConnection mockConnection = mock(HttpURLConnection.class); when(mockURL.openConnection()).thenReturn(mockConnection); when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - when(mockPurchaser.getDataTarget()).thenReturn("test"); + when(mockPurchaser.getDataTarget()).thenReturn(Webshop.Amazon); assertDoesNotThrow(() -> { mockPurchaser.purchaseProduct(dto); diff --git a/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java b/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java index eb7e595..e907a37 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java @@ -13,6 +13,7 @@ import java.net.URL; import org.junit.jupiter.api.Test; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.model.Webshop; class AbstractSellerTest { private AbstractSeller mockSeller = mock(AbstractSeller.class); @@ -20,7 +21,7 @@ class AbstractSellerTest { @Test void purchaseProduct_CorrectApiTypeInException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO("12345", "test"); + ProductDTO dto = new ProductDTO("12345", Webshop.Amazon); // Set up mocks URL mockURL = mock(URL.class); @@ -29,7 +30,7 @@ class AbstractSellerTest { HttpURLConnection mockConnection = mock(HttpURLConnection.class); when(mockURL.openConnection()).thenReturn(mockConnection); when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - when(mockSeller.getDataTarget()).thenReturn("test"); + when(mockSeller.getDataTarget()).thenReturn(Webshop.Amazon); assertDoesNotThrow(() -> { mockSeller.sellProduct(dto); 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 938413d..7735bd9 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java @@ -21,6 +21,7 @@ import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.DataSourceException; +import de.rwu.easydrop.model.Webshop; class AmazonProductDataSourceTest { @@ -28,7 +29,7 @@ class AmazonProductDataSourceTest { private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static String demoDataOrigin = "Amazon"; + private static Webshop demoDataOrigin = Webshop.Amazon; private static String demoProductId = "whateverId"; @BeforeEach @@ -138,7 +139,7 @@ class AmazonProductDataSourceTest { // Verify the product DTO properties assertEquals(demoProductId, result.getProductId()); - assertEquals("Amazon", result.getDataOrigin()); + assertEquals(Webshop.Amazon, result.getDataOrigin()); assertEquals(true, result.isAvailable()); assertEquals(10.0, result.getCurrentPrice()); assertEquals(2.5, result.getDeliveryPrice()); @@ -149,18 +150,18 @@ class AmazonProductDataSourceTest { void testGetProductDTOById_failedRequest() throws IOException { // Set up the test environment - AmazonProductDataSource dataSource = mock(AmazonProductDataSource.class); + AmazonProductDataSource DataSource = mock(AmazonProductDataSource.class); URL mockURL = mock(URL.class); - when(dataSource.getDataOrigin()).thenReturn(demoDataOrigin); - when(dataSource.createApiUrl(demoProductId)).thenReturn(mockURL); - when(dataSource.getProductDTOById(demoProductId)).thenCallRealMethod(); + when(DataSource.getDataOrigin()).thenReturn(demoDataOrigin); + when(DataSource.createApiUrl(demoProductId)).thenReturn(mockURL); + when(DataSource.getProductDTOById(demoProductId)).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(demoProductId); + DataSource.getProductDTOById(demoProductId); }); // Verify the exception message @@ -170,12 +171,12 @@ class AmazonProductDataSourceTest { @Test void testGetProductDTOById_ioException() throws IOException { // Set up the test environment - AmazonProductDataSource dataSource = mock(AmazonProductDataSource.class); + AmazonProductDataSource DataSource = mock(AmazonProductDataSource.class); URL mockURL = mock(URL.class); - when(dataSource.getDataOrigin()).thenReturn(demoDataOrigin); - when(dataSource.createApiUrl(demoProductId)).thenReturn(mockURL); - when(dataSource.getProductDTOById(demoProductId)).thenCallRealMethod(); - when(dataSource.buildProductDTO(any(), anyString())).thenCallRealMethod(); + when(DataSource.getDataOrigin()).thenReturn(demoDataOrigin); + when(DataSource.createApiUrl(demoProductId)).thenReturn(mockURL); + when(DataSource.getProductDTOById(demoProductId)).thenCallRealMethod(); + when(DataSource.buildProductDTO(any(), anyString())).thenCallRealMethod(); HttpURLConnection mockConnection = mock(HttpURLConnection.class); when(mockURL.openConnection()).thenReturn(mockConnection); when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); @@ -183,7 +184,7 @@ class AmazonProductDataSourceTest { // Invoke the method and verify the exception DataSourceException exception = assertThrows(DataSourceException.class, () -> { - dataSource.getProductDTOById(demoProductId); + DataSource.getProductDTOById(demoProductId); }); // Verify the exception message @@ -192,7 +193,7 @@ class AmazonProductDataSourceTest { @Test void getDataOrigin_ReturnsExpectedDataOrigin() { - String dataOrigin = demoDataSource.getDataOrigin(); + Webshop dataOrigin = demoDataSource.getDataOrigin(); assertEquals(demoDataOrigin, dataOrigin); } diff --git a/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java b/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java index ec1e1d6..1386e97 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java @@ -1,7 +1,6 @@ package de.rwu.easydrop.api.client; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import java.lang.reflect.Field; import java.net.MalformedURLException; @@ -12,15 +11,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; -import de.rwu.easydrop.api.dto.ProductDTO; -import de.rwu.easydrop.exception.DataWriterException; +import de.rwu.easydrop.model.Webshop; class AmazonPurchaserTest { private AmazonPurchaser demoPurchaser; private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static String demoDataTarget = "Amazon"; + private static Webshop demoDataTarget = Webshop.Amazon; @BeforeEach void setup() { @@ -72,7 +70,7 @@ class AmazonPurchaserTest { @Test void getDataTarget_ReturnsExpectedDataOrigin() { - String dataTarget = demoPurchaser.getDataTarget(); + Webshop dataTarget = demoPurchaser.getDataTarget(); assertEquals(demoDataTarget, dataTarget); } diff --git a/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java b/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java index 06176cc..4ff6d55 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java @@ -11,12 +11,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; +import de.rwu.easydrop.model.Webshop; + class AmazonSellerTest { private AmazonSeller demoSeller; private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static String demoDataTarget = "Amazon"; + private static Webshop demoDataTarget = Webshop.Amazon; @BeforeEach void setup() { @@ -68,7 +70,7 @@ class AmazonSellerTest { @Test void getDataTarget_ReturnsExpectedDataOrigin() { - String dataTarget = demoSeller.getDataTarget(); + Webshop dataTarget = demoSeller.getDataTarget(); assertEquals(demoDataTarget, dataTarget); } diff --git a/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java b/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java index f1c85b0..5196c8b 100644 --- a/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java @@ -21,7 +21,7 @@ class DataSourceFactoryTest { @Mock private Config config; - private DataSourceFactory dataSourceFactory; + private DataSourceFactory DataSourceFactory; @BeforeEach void setUp() throws ConfigurationException { @@ -30,31 +30,31 @@ class DataSourceFactoryTest { 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); + DataSourceFactory = new DataSourceFactory(config); } @Test void createAmazonProductDataSource_ReturnsAmazonProductDataSource() { // Act - AmazonProductDataSource dataSource = dataSourceFactory.createAmazonProductDataSource(); + AmazonProductDataSource DataSource = DataSourceFactory.createAmazonProductDataSource(); // Assert - assertEquals("amazon-api-key", dataSource.getApiKey()); + assertEquals("amazon-api-key", DataSource.getApiKey()); } @Test void createEbayItemDataSource_ReturnsEbayItemDataSource() { // Act - EbayItemDataSource dataSource = dataSourceFactory.createEbayItemDataSource(); + EbayItemDataSource DataSource = DataSourceFactory.createEbayItemDataSource(); // Assert - assertEquals("ebay-api-key", dataSource.getApiKey()); + assertEquals("ebay-api-key", DataSource.getApiKey()); } @Test void createProductPersistenceDataSource_NullPersistence() { PersistenceException exception = assertThrows(PersistenceException.class, () -> { - dataSourceFactory.createProductPersistenceDataSource(); + DataSourceFactory.createProductPersistenceDataSource(); }); assertEquals("Persistence is not set", exception.getMessage()); @@ -62,8 +62,8 @@ class DataSourceFactoryTest { @Test void createProductPersistenceDataSource_WorkingPersistence() { - dataSourceFactory.setPersistence(new SQLiteConnector(new SQLiteDataSource())); + DataSourceFactory.setPersistence(new SQLiteConnector(new SQLiteDataSource())); - assertDoesNotThrow(() -> dataSourceFactory.createProductPersistenceDataSource()); + assertDoesNotThrow(() -> DataSourceFactory.createProductPersistenceDataSource()); } } 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 9a6ed45..a311c73 100644 --- a/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java @@ -19,13 +19,14 @@ import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.DataSourceException; +import de.rwu.easydrop.model.Webshop; class EbayItemDataSourceTest { private EbayItemDataSource demoDataSource; private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static String demoDataOrigin = "eBay"; + private static Webshop demoDataOrigin = Webshop.eBay; private static String demoQuery = "iPhone"; @BeforeEach @@ -82,7 +83,7 @@ class EbayItemDataSourceTest { ProductDTO result = demoDataSource.buildProductDTO(product, json); - assertEquals("eBay", result.getDataOrigin()); + assertEquals(Webshop.eBay, result.getDataOrigin()); assertEquals(false, result.isAvailable()); // Default value for boolean assertEquals(0.0, result.getCurrentPrice()); // Default value for double assertEquals(0.0, result.getDeliveryPrice()); // Default value for double @@ -91,7 +92,7 @@ class EbayItemDataSourceTest { @Test void getDataOrigin_ReturnsExpectedDataOrigin() { - String dataOrigin = demoDataSource.getDataOrigin(); + Webshop dataOrigin = demoDataSource.getDataOrigin(); assertEquals(demoDataOrigin, dataOrigin); } @@ -105,18 +106,18 @@ class EbayItemDataSourceTest { void testGetProductDTOById_failedRequest() throws IOException { // Set up the test environment - EbayItemDataSource dataSource = mock(EbayItemDataSource.class); + 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(); + 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); + DataSource.getProductDTOById(demoQuery); }); // Verify the exception message diff --git a/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java b/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java index 238e2c5..2b2104c 100644 --- a/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java @@ -11,12 +11,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; +import de.rwu.easydrop.model.Webshop; + class EbayPurchaserTest { private EbayPurchaser demoPurchaser; private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static String demoDataTarget = "eBay"; + private static Webshop demoDataTarget = Webshop.eBay; @BeforeEach void setup() { @@ -65,7 +67,7 @@ class EbayPurchaserTest { @Test void getDataTarget_ReturnsExpectedDataOrigin() { - String dataTarget = demoPurchaser.getDataTarget(); + Webshop dataTarget = demoPurchaser.getDataTarget(); assertEquals(demoDataTarget, dataTarget); } diff --git a/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java b/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java index 978aa63..0fe0df0 100644 --- a/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java @@ -11,12 +11,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; +import de.rwu.easydrop.model.Webshop; + class EbaySellerTest { private EbaySeller demoSeller; private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static String demoDataTarget = "eBay"; + private static Webshop demoDataTarget = Webshop.eBay; @BeforeEach void setup() { @@ -65,7 +67,7 @@ class EbaySellerTest { @Test void getDataTarget_ReturnsExpectedDataOrigin() { - String dataTarget = demoSeller.getDataTarget(); + Webshop dataTarget = demoSeller.getDataTarget(); assertEquals(demoDataTarget, dataTarget); } diff --git a/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java b/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java index 1e16d7c..647babb 100644 --- a/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java +++ b/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java @@ -6,13 +6,15 @@ import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.Test; +import de.rwu.easydrop.model.Webshop; + class ProductDTOTest { @Test void constructor_SetsProductIdAndDataOrigin() { // Arrange String productId = "12345"; - String dataOrigin = "Amazon"; + Webshop dataOrigin = Webshop.Amazon; // Act ProductDTO productDTO = new ProductDTO(productId, dataOrigin); @@ -25,19 +27,19 @@ class ProductDTOTest { @Test void gettersAndSetters_WorkAsExpected() { // Arrange - ProductDTO productDTO = new ProductDTO("12345", "Amazon"); + ProductDTO productDTO = new ProductDTO("12345", Webshop.Amazon); // Act and Assert assertEquals("12345", productDTO.getProductId()); - assertEquals("Amazon", productDTO.getDataOrigin()); + assertEquals(Webshop.Amazon, productDTO.getDataOrigin()); // Modify fields productDTO.setProductId("54321"); - productDTO.setDataOrigin("eBay"); + productDTO.setDataOrigin(Webshop.eBay); // Assert assertEquals("54321", productDTO.getProductId()); - assertEquals("eBay", productDTO.getDataOrigin()); + assertEquals(Webshop.eBay, productDTO.getDataOrigin()); } @Test diff --git a/src/test/java/de/rwu/easydrop/core/CoreTest.java b/src/test/java/de/rwu/easydrop/core/CoreTest.java index e37170f..bf62c6d 100644 --- a/src/test/java/de/rwu/easydrop/core/CoreTest.java +++ b/src/test/java/de/rwu/easydrop/core/CoreTest.java @@ -1,31 +1,4 @@ package de.rwu.easydrop.core; -import java.util.List; -import javax.naming.ConfigurationException; - -import org.junit.jupiter.api.Test; - -import de.rwu.easydrop.api.client.DataSourceFactory; - -import de.rwu.easydrop.model.ProductCatalogue; -import de.rwu.easydrop.service.retriever.CatalogueRetriever; -import de.rwu.easydrop.service.retriever.ProductRetriever; -import de.rwu.easydrop.util.Config; -import de.rwu.easydrop.util.ProductsConfig; - public class CoreTest { - @Test - void testRunCore() throws ConfigurationException{ - Config config = Config.getInstance(); - ProductsConfig pConfig = ProductsConfig.getInstance(); - DataSourceFactory dataSourceFactory = new DataSourceFactory(config); - ProductRetriever retriever = new ProductRetriever(dataSourceFactory); - CatalogueRetriever catRetriever = new CatalogueRetriever(pConfig, retriever); - - catRetriever.loadCatalogues(); - List pCats = catRetriever.getProductCatalogues(); - Core core1=new Core(); - core1.runCore(pCats); - - } } diff --git a/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java b/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java index 2e54299..9c513db 100644 --- a/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java +++ b/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java @@ -22,6 +22,7 @@ import org.sqlite.SQLiteDataSource; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.PersistenceException; +import de.rwu.easydrop.model.Webshop; @TestInstance(Lifecycle.PER_CLASS) class SQLiteConnectorTest { @@ -45,8 +46,8 @@ class SQLiteConnectorTest { void saveProduct_ValidProduct_SuccessfullySaved() { // Arrange sqliteConnector.clearData(); - ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, "Amazon"); - ProductDTO.setDataOrigin("Amazon"); + ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.Amazon); + ProductDTO.setDataOrigin(Webshop.Amazon); ProductDTO.setProductId(TEST_PRODUCT_ID); ProductDTO.setCurrentPrice(9.99); ProductDTO.setMerchant("Sample Merchant"); @@ -59,7 +60,7 @@ class SQLiteConnectorTest { // Assert ProductDTO savedProductDTO = sqliteConnector.getProductDTOById(TEST_PRODUCT_ID); assertNotNull(savedProductDTO); - assertEquals("Amazon", savedProductDTO.getDataOrigin()); + assertEquals(Webshop.Amazon, savedProductDTO.getDataOrigin()); assertEquals(TEST_PRODUCT_ID, savedProductDTO.getProductId()); assertEquals(9.99, savedProductDTO.getCurrentPrice()); assertEquals("Sample Merchant", savedProductDTO.getMerchant()); @@ -78,7 +79,7 @@ class SQLiteConnectorTest { // Assert assertNotNull(ProductDTO); - assertEquals("Amazon", ProductDTO.getDataOrigin()); + assertEquals(Webshop.Amazon, ProductDTO.getDataOrigin()); assertEquals(TEST_PRODUCT_ID, ProductDTO.getProductId()); assertEquals(9.99, ProductDTO.getCurrentPrice()); assertEquals("Sample Merchant", ProductDTO.getMerchant()); @@ -113,7 +114,7 @@ class SQLiteConnectorTest { @Test void saveProduct_ThrowsPersistenceException_OnSQLException() throws SQLException { // Arrange - ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, "Amazon"); + ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.Amazon); sqliteConnector.setDb(mockDataSource); doThrow(SQLException.class).when(mockDataSource).getConnection(); @@ -143,7 +144,7 @@ class SQLiteConnectorTest { } private void insertSampleProduct() { - ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, "Amazon"); + ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.Amazon); ProductDTO.setCurrentPrice(9.99); ProductDTO.setMerchant("Sample Merchant"); ProductDTO.setDeliveryPrice(2.50); @@ -151,18 +152,6 @@ class SQLiteConnectorTest { sqliteConnector.saveProduct(ProductDTO); } - @Test - void getDataOrigin_ReturnsCorrectDataOrigin() { - // Arrange - SQLiteConnector connector = new SQLiteConnector(new SQLiteDataSource()); - - // Act - String dataOrigin = connector.getDataOrigin(); - - // Assert - assertEquals("SQLite", dataOrigin); - } - @Test void getApiKey_UnsupportedOperationExceptionThrown() { // Arrange @@ -176,7 +165,7 @@ class SQLiteConnectorTest { void buildProductDTO_UnsupportedOperationExceptionThrown() { // Arrange SQLiteConnector connector = new SQLiteConnector(new SQLiteDataSource()); - ProductDTO product = new ProductDTO("ASIN123", "Amazon"); + ProductDTO product = new ProductDTO("ASIN123", Webshop.Amazon); String json = "{\"productId\":\"ASIN123\",\"dataOrigin\":\"Amazon\"}"; // Act and Assert diff --git a/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java b/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java index c13dcfe..c83f84f 100644 --- a/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java +++ b/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java @@ -19,7 +19,7 @@ class ProductCatalogueTest { Product product = new Product(); product.setProductId("12345"); product.setMerchant("AmazonSeller"); - product.setDataOrigin("Amazon"); + product.setDataOrigin(Webshop.Amazon); productCatalogue.addProduct(product); List products = productCatalogue.getProducts(); @@ -32,13 +32,13 @@ class ProductCatalogueTest { Product product1 = new Product(); product1.setProductId("12345"); product1.setMerchant("AmazonSeller"); - product1.setDataOrigin("Amazon"); + product1.setDataOrigin(Webshop.Amazon); productCatalogue.addProduct(product1); Product product2 = new Product(); product2.setProductId("54321"); product2.setMerchant("eBaySeller"); - product2.setDataOrigin("eBay"); + product2.setDataOrigin(Webshop.eBay); productCatalogue.addProduct(product2); productCatalogue.removeProduct(product1); @@ -53,13 +53,13 @@ class ProductCatalogueTest { Product product1 = new Product(); product1.setProductId("12345"); product1.setMerchant("AmazonSeller"); - product1.setDataOrigin("Amazon"); + product1.setDataOrigin(Webshop.Amazon); productCatalogue.addProduct(product1); Product product2 = new Product(); product2.setProductId("54321"); - product2.setMerchant("eBay"); - product2.setDataOrigin("eBay"); + product2.setMerchant("ebayMerchant"); + product2.setDataOrigin(Webshop.eBay); productCatalogue.addProduct(product2); productCatalogue.clearProducts(); @@ -73,13 +73,13 @@ class ProductCatalogueTest { Product product1 = new Product(); product1.setProductId("12345"); product1.setMerchant("AmazonSeller"); - product1.setDataOrigin("Amazon"); + product1.setDataOrigin(Webshop.Amazon); productCatalogue.addProduct(product1); Product product2 = new Product(); product2.setProductId("54321"); product2.setMerchant("eBaySeller"); - product2.setDataOrigin("eBay"); + product2.setDataOrigin(Webshop.eBay); productCatalogue.addProduct(product2); String expectedString = "Product Catalogue: GPU\n" + diff --git a/src/test/java/de/rwu/easydrop/model/ProductTest.java b/src/test/java/de/rwu/easydrop/model/ProductTest.java index cf79119..2c5c1c2 100644 --- a/src/test/java/de/rwu/easydrop/model/ProductTest.java +++ b/src/test/java/de/rwu/easydrop/model/ProductTest.java @@ -10,7 +10,7 @@ class ProductTest { @Test void testToString1() { Product product1 = new Product(); - product1.setDataOrigin("Amazon"); + product1.setDataOrigin(Webshop.Amazon); product1.setProductId("12345"); product1.setMerchant("Merchant A"); product1.setCurrentPrice(19.99); @@ -25,7 +25,7 @@ class ProductTest { @Test void testToString2() { Product product2 = new Product(); - product2.setDataOrigin("eBay"); + product2.setDataOrigin(Webshop.eBay); product2.setProductId("67890"); product2.setMerchant("Merchant B"); product2.setCurrentPrice(9.99); @@ -41,7 +41,7 @@ class ProductTest { void gettersAndSetters_WorkAsExpected() { // Arrange Product product = new Product(); - product.setDataOrigin("Amazon"); + product.setDataOrigin(Webshop.Amazon); product.setProductId("12345"); product.setCurrentPrice(9.99); product.setMerchant("Example Merchant"); @@ -49,7 +49,7 @@ class ProductTest { product.setAvailable(true); // Act and Assert - assertEquals("Amazon", product.getDataOrigin()); + assertEquals(Webshop.Amazon, product.getDataOrigin()); assertEquals("12345", product.getProductId()); assertEquals(9.99, product.getCurrentPrice()); assertEquals("Example Merchant", product.getMerchant()); @@ -57,7 +57,7 @@ class ProductTest { assertTrue(product.isAvailable()); // Modify fields - product.setDataOrigin("eBay"); + product.setDataOrigin(Webshop.eBay); product.setProductId("54321"); product.setCurrentPrice(19.99); product.setMerchant("New Merchant"); @@ -65,7 +65,7 @@ class ProductTest { product.setAvailable(false); // Assert - assertEquals("eBay", product.getDataOrigin()); + assertEquals(Webshop.eBay, product.getDataOrigin()); assertEquals("54321", product.getProductId()); assertEquals(19.99, product.getCurrentPrice()); assertEquals("New Merchant", product.getMerchant()); diff --git a/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java b/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java index 6239dbf..9212a24 100644 --- a/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java +++ b/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; class ProductMapperTest { @Test @@ -47,7 +48,7 @@ class ProductMapperTest { } private ProductDTO createProductDTO() { - ProductDTO dto = new ProductDTO("12345", "Amazon"); + ProductDTO dto = new ProductDTO("12345", Webshop.Amazon); dto.setAvailable(true); dto.setCurrentPrice(9.99); dto.setDeliveryPrice(2.50); @@ -60,7 +61,7 @@ class ProductMapperTest { // Arrange Product product = new Product(); product.setProductId("12345"); - product.setDataOrigin("Amazon"); + product.setDataOrigin(Webshop.Amazon); product.setAvailable(true); product.setCurrentPrice(9.99); product.setDeliveryPrice(2.50); @@ -71,7 +72,7 @@ class ProductMapperTest { // Assert assertEquals("12345", dto.getProductId()); - assertEquals("Amazon", dto.getDataOrigin()); + assertEquals(Webshop.Amazon, dto.getDataOrigin()); assertTrue(dto.isAvailable()); assertEquals(9.99, dto.getCurrentPrice()); assertEquals(2.50, dto.getDeliveryPrice()); diff --git a/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java index acaca80..edd772a 100644 --- a/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java +++ b/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java @@ -1,7 +1,6 @@ package de.rwu.easydrop.service.retriever; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -14,9 +13,9 @@ import javax.naming.ConfigurationException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import de.rwu.easydrop.exception.InvalidProductException; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.util.ProductsConfig; class CatalogueRetrieverTest { @@ -39,20 +38,20 @@ class CatalogueRetrieverTest { // Create a sample product catalogue with two products ProductCatalogue productCatalogue = new ProductCatalogue("Catalogue 1", "Sample catalogue"); Product product1 = new Product(); - product1.setDataOrigin("Amazon"); + product1.setDataOrigin(Webshop.Amazon); product1.setProductId("ASIN1"); productCatalogue.addProduct(product1); Product product2 = new Product(); - product2.setDataOrigin("eBay"); + product2.setDataOrigin(Webshop.eBay); product2.setProductId("ProductID2"); productCatalogue.addProduct(product2); productCatalogues.add(productCatalogue); // Mock the methods when(productsConfig.getProductCatalogues()).thenReturn(productCatalogues); - when(productRetriever.getProductFromAmazon("ASIN1")).thenReturn(product1); - when(productRetriever.getProductFromEbay("ProductID2")).thenReturn(product2); + when(productRetriever.getProductFromWebshop(Webshop.Amazon, "ASIN1")).thenReturn(product1); + when(productRetriever.getProductFromWebshop(Webshop.eBay, "ProductID2")).thenReturn(product2); // Act catalogueRetriever.loadCatalogues(); @@ -71,33 +70,7 @@ class CatalogueRetrieverTest { // Verify the method invocations verify(productsConfig).loadConfig(); - verify(productRetriever).getProductFromAmazon("ASIN1"); - verify(productRetriever).getProductFromEbay("ProductID2"); - } - - @Test - void loadCatalogues_ValidConfig_CataloguesLoaded_InvalidProduct() throws ConfigurationException { - // Arrange - List productCatalogues = new ArrayList<>(); - - // Create a sample product catalogue - ProductCatalogue productCatalogue = new ProductCatalogue("Catalogue 1", "Sample catalogue"); - - Product product = new Product(); - product.setDataOrigin(""); - product.setProductId("ProductID1"); - productCatalogue.addProduct(product); - productCatalogues.add(productCatalogue); - - // Mock the methods - when(productsConfig.getProductCatalogues()).thenReturn(productCatalogues); - when(productRetriever.getProductFromAmazon("ProductID1")).thenReturn(product); - - // Act and Assert - InvalidProductException exception = assertThrows(InvalidProductException.class, () -> { - catalogueRetriever.loadCatalogues(); - }); - - assertEquals("Product data origin is invalid", exception.getMessage()); + verify(productRetriever).getProductFromWebshop(Webshop.Amazon, "ASIN1"); + verify(productRetriever).getProductFromWebshop(Webshop.eBay, "ProductID2"); } } diff --git a/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java index 32afecc..5fee30f 100644 --- a/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java +++ b/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java @@ -19,13 +19,14 @@ import de.rwu.easydrop.api.client.EbayItemDataSource; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.data.connector.AbstractProductPersistence; import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.util.Config; class ProductRetrieverTest { @Mock private Config config; @Mock - private DataSourceFactory dataSourceFactory; + private DataSourceFactory DataSourceFactory; @Mock private AmazonProductDataSource amazonDataSource; @Mock @@ -44,19 +45,19 @@ class ProductRetrieverTest { MockitoAnnotations.openMocks(this); when(config.getProperty("AMAZON_API_URL")).thenReturn("https://api.amazon.com"); when(config.getProperty("AMAZON_API_KEY")).thenReturn("amazon-api-key"); - dataSourceFactory.setConfig(config); - productRetriever = new ProductRetriever(dataSourceFactory); + DataSourceFactory.setConfig(config); + productRetriever = new ProductRetriever(DataSourceFactory); } @Test void getProductFromAmazon_ReturnsProduct() { // Arrange String asin = "B01234ABC"; - when(dataSourceFactory.createAmazonProductDataSource()).thenReturn(amazonDataSource); + when(DataSourceFactory.createAmazonProductDataSource()).thenReturn(amazonDataSource); when(amazonDataSource.getProductDTOById(asin)).thenReturn(productDTO); when(productDTO.getProductId()).thenReturn(asin); when(productDTO.getCurrentPrice()).thenReturn(9.99); - when(productDTO.getDataOrigin()).thenReturn("Amazon"); + when(productDTO.getDataOrigin()).thenReturn(Webshop.Amazon); // Act Product result = productRetriever.getProductFromAmazon(asin); @@ -72,11 +73,11 @@ class ProductRetrieverTest { void getProductFromEbay_ReturnsProduct() { // Arrange String productQuery = "MySearchQuery"; - when(dataSourceFactory.createEbayItemDataSource()).thenReturn(ebayDataSource); + when(DataSourceFactory.createEbayItemDataSource()).thenReturn(ebayDataSource); when(ebayDataSource.getProductDTOById(productQuery)).thenReturn(productDTO); when(productDTO.getProductId()).thenReturn(productQuery); when(productDTO.getCurrentPrice()).thenReturn(9.99); - when(productDTO.getDataOrigin()).thenReturn("eBay"); + when(productDTO.getDataOrigin()).thenReturn(Webshop.eBay); // Act Product result = productRetriever.getProductFromEbay(productQuery); @@ -92,11 +93,11 @@ class ProductRetrieverTest { void getProductFromPersistence_ValidProductId_ReturnsProduct() { // Arrange String productId = "123"; - when(dataSourceFactory.createProductPersistenceDataSource()).thenReturn(persistence); + when(DataSourceFactory.createProductPersistenceDataSource()).thenReturn(persistence); when(persistence.getProductDTOById(productId)).thenReturn(productDTO); when(productDTO.getProductId()).thenReturn(productId); when(productDTO.getCurrentPrice()).thenReturn(9.99); - when(productDTO.getDataOrigin()).thenReturn("Amazon"); + when(productDTO.getDataOrigin()).thenReturn(Webshop.Amazon); // Act Product result = productRetriever.getProductFromPersistence(productId); diff --git a/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java index 7827bbb..1ad2f6b 100644 --- a/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java +++ b/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java @@ -1,7 +1,6 @@ package de.rwu.easydrop.service.validation; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -16,6 +15,7 @@ import org.junit.jupiter.params.provider.MethodSource; import de.rwu.easydrop.exception.InvalidProductException; import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; class ProductValidatorTest { @@ -38,37 +38,13 @@ class ProductValidatorTest { // Arrange Product product = new Product(); product.setCurrentPrice(9.99); - product.setDataOrigin("Amazon"); + product.setDataOrigin(Webshop.Amazon); product.setProductId("12345"); // Act and Assert assertDoesNotThrow(() -> ProductValidator.validate(product)); } - @Test - void isInValidDataOrigins_ValidDataOrigin_ReturnsTrue() { - // Arrange - String dataOrigin = "Amazon"; - - // Act - boolean result = ProductValidator.isInValidDataOrigins(dataOrigin); - - // Assert - assertTrue(result); - } - - @Test - void isInValidDataOrigins_InvalidDataOrigin_ReturnsFalse() { - // Arrange - String dataOrigin = "UnknownOrigin"; - - // Act - boolean result = ProductValidator.isInValidDataOrigins(dataOrigin); - - // Assert - assertFalse(result); - } - @ParameterizedTest @MethodSource("invalidProductProvider") void validate_InvalidProduct_ThrowsInvalidProductException(Product product) { @@ -79,22 +55,13 @@ class ProductValidatorTest { static Stream invalidProductProvider() { return Stream.of( createProductWithZeroPrice(), - createProductWithUnknownDataOrigin(), createProductWithEmptyProductId()); } private static Product createProductWithZeroPrice() { Product product = new Product(); product.setCurrentPrice(0.00); - product.setDataOrigin("Amazon"); - product.setProductId("12345"); - return product; - } - - private static Product createProductWithUnknownDataOrigin() { - Product product = new Product(); - product.setCurrentPrice(9.99); - product.setDataOrigin("UnknownOrigin"); + product.setDataOrigin(Webshop.Amazon); product.setProductId("12345"); return product; } @@ -102,7 +69,7 @@ class ProductValidatorTest { private static Product createProductWithEmptyProductId() { Product product = new Product(); product.setCurrentPrice(9.99); - product.setDataOrigin("Amazon"); + product.setDataOrigin(Webshop.Amazon); product.setProductId(""); return product; } diff --git a/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java index 71fdff5..c590733 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java @@ -16,6 +16,7 @@ import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.data.connector.AbstractProductPersistence; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.model.Webshop; class CatalogueWriterTest { @@ -46,12 +47,12 @@ class CatalogueWriterTest { List catalogues = new ArrayList<>(); ProductCatalogue catalogue1 = new ProductCatalogue("Catalogue 1", "Sample catalogue 1"); - catalogue1.addProduct(createSampleProduct("Amazon", "ID 1")); - catalogue1.addProduct(createSampleProduct("eBay", "ID 2")); + catalogue1.addProduct(createSampleProduct(Webshop.Amazon, "ID 1")); + catalogue1.addProduct(createSampleProduct(Webshop.eBay, "ID 2")); ProductCatalogue catalogue2 = new ProductCatalogue("Catalogue 2", "Sample catalogue 2"); - catalogue2.addProduct(createSampleProduct("Amazon", "ID 3")); - catalogue2.addProduct(createSampleProduct("eBay", "ID 4")); + catalogue2.addProduct(createSampleProduct(Webshop.Amazon, "ID 3")); + catalogue2.addProduct(createSampleProduct(Webshop.eBay, "ID 4")); catalogues.add(catalogue1); catalogues.add(catalogue2); @@ -59,7 +60,7 @@ class CatalogueWriterTest { return catalogues; } - private Product createSampleProduct(String dataOrigin, String productId) { + private Product createSampleProduct(Webshop dataOrigin, String productId) { Product product = new Product(); product.setDataOrigin(dataOrigin); product.setProductId(productId); diff --git a/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java index aab0cdd..e2bd870 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java @@ -12,6 +12,7 @@ import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.data.connector.AbstractProductPersistence; import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; class ProductWriterTest { @@ -32,7 +33,7 @@ class ProductWriterTest { // Arrange Product product = new Product(); product.setProductId("12345"); - product.setDataOrigin("Amazon"); + product.setDataOrigin(Webshop.Amazon); product.setCurrentPrice(9.99); // Act @@ -47,7 +48,7 @@ class ProductWriterTest { // Arrange Product product = new Product(); product.setProductId(""); - product.setDataOrigin("Amazon"); + product.setDataOrigin(Webshop.Amazon); // Act and Assert assertThrows(Exception.class, () -> productWriter.writeProductToPersistence(product)); From d01c4d0b1d520c6b8bddbe49829fffe474a59543 Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Tue, 27 Jun 2023 05:23:43 +0200 Subject: [PATCH 22/49] Connected application components --- src/main/java/de/rwu/easydrop/Main.java | 35 +----- .../api/client/AmazonProductDataSource.java | 2 + .../api/client/DataSourceFactory.java | 26 ---- .../api/client/EbayItemDataSource.java | 2 + .../de/rwu/easydrop/api/dto/OfferDTO.java | 37 ++---- .../de/rwu/easydrop/api/dto/ProductDTO.java | 5 + src/main/java/de/rwu/easydrop/core/Core.java | 64 +++++++--- .../de/rwu/easydrop/core/OfferIdentifier.java | 83 ------------- .../de/rwu/easydrop/core/OfferReviewer.java | 81 ------------ .../de/rwu/easydrop/core/OfferUpdater.java | 110 ----------------- .../connector/AbstractProductPersistence.java | 34 ------ ...ce.java => OfferPersistenceInterface.java} | 8 +- .../ProductPersistenceInterface.java | 30 +++++ .../data/connector/SQLiteConnector.java | 115 ++++++++++++++---- .../exception/InvalidOfferException.java | 22 ++++ .../java/de/rwu/easydrop/model/Offer.java | 32 ++--- .../java/de/rwu/easydrop/model/Product.java | 5 + .../rwu/easydrop/model/ProductCatalogue.java | 2 +- .../easydrop/service/mapping/OfferMapper.java | 11 +- .../service/mapping/ProductMapper.java | 2 + ...OrderManager.java => OfferIdentifier.java} | 54 ++++---- .../processing}/OfferProvisioner.java | 48 +++----- .../service/retriever/CatalogueRetriever.java | 13 +- .../service/retriever/OfferRetriever.java | 37 +++++- .../service/retriever/ProductRetriever.java | 21 ++-- .../service/validation/OfferValidator.java | 19 ++- .../service/writer/CatalogueWriter.java | 8 +- .../easydrop/service/writer/OfferWriter.java | 10 +- .../service/writer/ProductWriter.java | 8 +- .../de/rwu/easydrop/util/FormattingUtil.java | 10 ++ .../java/de/rwu/easydrop/util/Timestamp.java | 29 +++++ 31 files changed, 402 insertions(+), 561 deletions(-) delete mode 100644 src/main/java/de/rwu/easydrop/core/OfferIdentifier.java delete mode 100644 src/main/java/de/rwu/easydrop/core/OfferReviewer.java delete mode 100644 src/main/java/de/rwu/easydrop/core/OfferUpdater.java delete mode 100644 src/main/java/de/rwu/easydrop/data/connector/AbstractProductPersistence.java rename src/main/java/de/rwu/easydrop/data/connector/{AbstractOfferPersistence.java => OfferPersistenceInterface.java} (64%) create mode 100644 src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java create mode 100644 src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java rename src/main/java/de/rwu/easydrop/service/processing/{OrderManager.java => OfferIdentifier.java} (64%) rename src/main/java/de/rwu/easydrop/{core => service/processing}/OfferProvisioner.java (57%) create mode 100644 src/main/java/de/rwu/easydrop/util/Timestamp.java diff --git a/src/main/java/de/rwu/easydrop/Main.java b/src/main/java/de/rwu/easydrop/Main.java index c8f4f1e..db1fedb 100644 --- a/src/main/java/de/rwu/easydrop/Main.java +++ b/src/main/java/de/rwu/easydrop/Main.java @@ -1,23 +1,8 @@ package de.rwu.easydrop; -import java.util.List; - import javax.naming.ConfigurationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sqlite.SQLiteDataSource; - -import de.rwu.easydrop.api.client.DataSourceFactory; import de.rwu.easydrop.core.Core; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; -import de.rwu.easydrop.data.connector.SQLiteConnector; -import de.rwu.easydrop.model.ProductCatalogue; -import de.rwu.easydrop.service.retriever.CatalogueRetriever; -import de.rwu.easydrop.service.retriever.ProductRetriever; -import de.rwu.easydrop.service.writer.CatalogueWriter; -import de.rwu.easydrop.util.Config; -import de.rwu.easydrop.util.ProductsConfig; /** * Kickoff point for the service. @@ -25,11 +10,6 @@ import de.rwu.easydrop.util.ProductsConfig; * @since 0.1.0 */ public final class Main { - /** - * Logger for main process. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); - /** * Prevents unwanted instantiation. */ @@ -43,19 +23,6 @@ public final class Main { * @param args */ public static void main(final String[] args) throws ConfigurationException { - Config config = Config.getInstance(); - ProductsConfig pConfig = ProductsConfig.getInstance(); - DataSourceFactory dataSourceFactory = new DataSourceFactory(config); - ProductRetriever retriever = new ProductRetriever(dataSourceFactory); - CatalogueRetriever catRetriever = new CatalogueRetriever(pConfig, retriever); - AbstractProductPersistence db = new SQLiteConnector(new SQLiteDataSource()); - CatalogueWriter catWriter = new CatalogueWriter(db); - - catRetriever.loadCatalogues(); - List pCats = catRetriever.getProductCatalogues(); - catWriter.writeCatalogues(pCats); - - Core core = new Core(); - core.runCore(pCats); + Core.run(); } } 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 404398c..06c806e 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java @@ -9,6 +9,7 @@ import com.jayway.jsonpath.ReadContext; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.model.Webshop; +import de.rwu.easydrop.util.Timestamp; /** * Interface to an Amazon data source. @@ -61,6 +62,7 @@ public final class AmazonProductDataSource extends AbstractDataSource { product.setDeliveryPrice( ctx.read(root + "shippingOptions[0].shippingCost.value.amount", double.class)); product.setMerchant(ctx.read(root + "merchant.name", String.class)); + product.setLastUpdate(Timestamp.now()); } catch (PathNotFoundException e) { // Pass, allow incomplete ProductDTO to pass for later validation } diff --git a/src/main/java/de/rwu/easydrop/api/client/DataSourceFactory.java b/src/main/java/de/rwu/easydrop/api/client/DataSourceFactory.java index 490466c..ba79ab5 100644 --- a/src/main/java/de/rwu/easydrop/api/client/DataSourceFactory.java +++ b/src/main/java/de/rwu/easydrop/api/client/DataSourceFactory.java @@ -2,8 +2,6 @@ package de.rwu.easydrop.api.client; import javax.naming.ConfigurationException; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; -import de.rwu.easydrop.exception.PersistenceException; import de.rwu.easydrop.util.Config; /** @@ -17,17 +15,6 @@ public class DataSourceFactory { * The data source config. */ private Config config; - /** - * Persistence interface. - */ - private AbstractProductPersistence persistence = null; - - /** - * @param newPersistence the persistence to set - */ - public void setPersistence(final AbstractProductPersistence newPersistence) { - this.persistence = newPersistence; - } /** * @param newConfig the config to set @@ -65,17 +52,4 @@ public class DataSourceFactory { String apiKey = config.getProperty("EBAY_API_KEY"); return new EbayItemDataSource(apiUrl, apiKey); } - - /** - * Creates a persistence data source. - * - * @return ProductPersistenceInterface - */ - public AbstractProductPersistence createProductPersistenceDataSource() { - if (persistence == null) { - throw new PersistenceException("Persistence is not set"); - } - - return persistence; - } } 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 5e62394..0b1ed40 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java @@ -9,6 +9,7 @@ import com.jayway.jsonpath.ReadContext; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.model.Webshop; +import de.rwu.easydrop.util.Timestamp; /** * Interface to an eBay data source. @@ -70,6 +71,7 @@ public final class EbayItemDataSource extends AbstractDataSource { product.setDeliveryPrice( ctx.read(root + "shippingOptions[0].shippingCost.value", double.class)); product.setMerchant(ctx.read(root + "seller.username", String.class)); + product.setLastUpdate(Timestamp.now()); } catch (PathNotFoundException e) { // Pass, allow incomplete ProductDTO to pass for later validation } diff --git a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java index c2d680f..8ffd6a8 100644 --- a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java +++ b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java @@ -1,52 +1,31 @@ package de.rwu.easydrop.api.dto; import lombok.Data; -import de.rwu.easydrop.model.Product; -import java.util.Date; /* - * Offer data transfer object + * Offer data transfer object. + * + * @since 0.3.0 */ @Data public class OfferDTO { /** - * Platform internal offer identifier. + * ID of the offer, built from identifiers of the source platforms. */ private String offerId; /** * The product that our software buys. */ - private Product sourceProduct; + private ProductDTO sourceProduct; /** * The product that our software sells. */ - private Product saleProduct; + private ProductDTO targetProduct; /** - * Date of the creation of the offer - * NOTE: Use Timestamp? - * https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html + * Date of last update of the offer. */ - private Date creationDate; - - /** - * Date of last update of the offer on the destination website (API). - */ - private Date upDate; - - /** - * Date of last check if offer is still valid. - */ - private Date checkDate; - - /** - * Creates OfferDTO instance. - * - * @param newOfferId Internal Offer identifier - */ - public OfferDTO(final String newOfferId) { - this.offerId = newOfferId; - } + private String lastUpdate; } diff --git a/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java b/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java index 7d7ea70..00956b1 100644 --- a/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java +++ b/src/main/java/de/rwu/easydrop/api/dto/ProductDTO.java @@ -40,6 +40,11 @@ public class ProductDTO { */ private boolean available; + /** + * Last update from API. + */ + private String lastUpdate; + /** * Creates ProductDTO instance. * diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java index ce7e63b..3403b00 100644 --- a/src/main/java/de/rwu/easydrop/core/Core.java +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -4,42 +4,74 @@ import java.util.List; import javax.naming.ConfigurationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sqlite.SQLiteDataSource; + +import de.rwu.easydrop.api.client.DataSourceFactory; +import de.rwu.easydrop.data.connector.OfferPersistenceInterface; +import de.rwu.easydrop.data.connector.ProductPersistenceInterface; +import de.rwu.easydrop.data.connector.SQLiteConnector; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.service.processing.OfferIdentifier; +import de.rwu.easydrop.service.processing.OfferProvisioner; +import de.rwu.easydrop.service.retriever.CatalogueRetriever; +import de.rwu.easydrop.service.retriever.ProductRetriever; +import de.rwu.easydrop.service.writer.CatalogueWriter; +import de.rwu.easydrop.util.Config; +import de.rwu.easydrop.util.ProductsConfig; /** * The application core. * * @since 0.3.0 */ -public class Core { +public final class Core { /** - * Offer identifier. + * Logging instance. */ - private OfferIdentifier ident; - /** - * Offer provisioner. - */ - private OfferProvisioner provis; + private static final Logger LOGGER = LoggerFactory.getLogger(Core.class); /** - * Constructor. - * - * @throws ConfigurationException + * Hidden Constructor. */ - public Core() throws ConfigurationException { - this.ident = new OfferIdentifier(); - this.provis = new OfferProvisioner(); - + private Core() { + // Hidden constructor } /** * Runs the core. * - * @param pCats + * @throws ConfigurationException */ - public void runCore(final List pCats) { + public static void run() throws ConfigurationException { + LOGGER.info("Loading config..."); + Config config = Config.getInstance(); + ProductsConfig pConfig = ProductsConfig.getInstance(); + + LOGGER.info("Preparing..."); + DataSourceFactory dataSourceFactory = new DataSourceFactory(config); + ProductPersistenceInterface pdb = new SQLiteConnector(new SQLiteDataSource()); + OfferPersistenceInterface odb = new SQLiteConnector(new SQLiteDataSource()); + ProductRetriever retriever = new ProductRetriever(dataSourceFactory, pdb); + CatalogueRetriever catRetriever = new CatalogueRetriever(pConfig, retriever); + CatalogueWriter catWriter = new CatalogueWriter(pdb); + + LOGGER.info("Loading catalogues"); + catRetriever.loadCatalogues(); + List pCats = catRetriever.getProductCatalogues(); + catWriter.writeCatalogues(pCats); + + LOGGER.info("Creating offers"); + OfferIdentifier ident = new OfferIdentifier(); List identifiedOffers = ident.runIdentifier(pCats); + OfferProvisioner provis = new OfferProvisioner(odb); provis.runProvisioner(identifiedOffers); + + // LOGGER.info("Creating transactions"); + // TODO: Transactions + + LOGGER.info("Done!"); } } diff --git a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java deleted file mode 100644 index 99d4b23..0000000 --- a/src/main/java/de/rwu/easydrop/core/OfferIdentifier.java +++ /dev/null @@ -1,83 +0,0 @@ -package de.rwu.easydrop.core; - -import javax.naming.ConfigurationException; -import java.util.List; -import java.util.ArrayList; -import java.util.Date; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import de.rwu.easydrop.model.Offer; -import de.rwu.easydrop.model.ProductCatalogue; -import de.rwu.easydrop.model.ProductPair; -import de.rwu.easydrop.service.retriever.OfferRetriever; -import de.rwu.easydrop.service.processing.OrderManager; -import de.rwu.easydrop.exception.InvalidCatalogueException; - -public class OfferIdentifier { - /** - * Logger for main process. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(OfferIdentifier.class); - /** - * OfferRetriever gets the offer from persistence. - */ - private OfferRetriever offerRetriever; - - /** - * OfferIdentifier identifies offers that are - * feasible to place on a target platform based on - * their margin. - * - * @throws ConfigurationException - */ - public OfferIdentifier() throws ConfigurationException { - this.offerRetriever = new OfferRetriever(); - } - - /** - * runIdentifier calls the price function that decides - * if it is feasible to dropship products and if so, - * at which margin. - * - * @param pCats - * @return newOffers - */ - public List runIdentifier(final List pCats) { - List identifiedOffers = new ArrayList<>(); - for (ProductCatalogue pCat : pCats) { - try { - // Call price finder for all catalogue - ProductPair pair = OrderManager.getHighestMarginProducts(pCat); - Offer possibleOffer = new Offer(); - possibleOffer.setCheckDate(new Date()); - possibleOffer.setSourceProduct(pair.getProduct1()); - possibleOffer.setSaleProduct(pair.getProduct2()); - identifiedOffers.add(possibleOffer); - LOGGER.info( - "Identified offer " - + - pair.getProduct1().getProductId() - + - " -> " - + - pair.getProduct2().getProductId()); - // Following fields will be set if offer confirmed - // creationDate, offerId - // Following fields will be set if offer needs update - // upDate - } catch (InvalidCatalogueException e) { - // if no margin, getHighestMarginProducts will throw - System.out.print("product has no margin"); - } - } - List newOffers = new ArrayList<>(); - for (Offer identifiedOffer : identifiedOffers) { - boolean isNew = true; - if (isNew) { - newOffers.add(identifiedOffer); - } - } - return newOffers; - } -} diff --git a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java b/src/main/java/de/rwu/easydrop/core/OfferReviewer.java deleted file mode 100644 index e394093..0000000 --- a/src/main/java/de/rwu/easydrop/core/OfferReviewer.java +++ /dev/null @@ -1,81 +0,0 @@ -package de.rwu.easydrop.core; - -import de.rwu.easydrop.model.Offer; -import de.rwu.easydrop.model.Product; - -import java.util.List; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Date; - -public class OfferReviewer { - - /** - * Check all Offers and compare them with the API. - * @return list of all items that need to be changed - */ - public List checkOffer(/*OfferReader/retriever for database? */) { - - Connection connection = null; - Statement statement = null; - ResultSet resultSet = null; - List changedOffers = new ArrayList<>(); - - try { - // Establish the database connection - connection = DriverManager.getConnection("jdbc:sqlite:persistence.db"); - - // Create a SQL statement - statement = connection.createStatement(); - - // Execute the query to retrieve the entries - String query = "SELECT sourceProduct, saleProduct, creationDate, upDate, " - + "checkDate, offerId FROM table"; - resultSet = statement.executeQuery(query); - - // Process the retrieved entries - while (resultSet.next()) { - Product sourceProduct = (Product) resultSet.getObject("sourceProduct"); - Product saleProduct = (Product) resultSet.getObject("saleProduct"); - java.sql.Date creationDate = resultSet.getDate("creationDate"); - Date updateDate = resultSet.getDate("upDate"); - Date checkDate = resultSet.getDate("checkDate"); - String offerId = resultSet.getString("offerId"); - - // Call the API to get the current price - double apiPrice = getPriceFromAPI(sourceProduct); - - // Compare the prices - if (saleProduct.getCurrentPrice() != apiPrice) { - // Price has changed, create a Product object and add it to the changedProducts list - Offer offer = new Offer(); - changedOffers.add(offer); - } - } - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if (resultSet != null) { - resultSet.close(); - } - if (statement != null) { - statement.close(); - } - if (connection != null) { - connection.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - return new ArrayList(); - } - - - -} diff --git a/src/main/java/de/rwu/easydrop/core/OfferUpdater.java b/src/main/java/de/rwu/easydrop/core/OfferUpdater.java deleted file mode 100644 index 27d08a9..0000000 --- a/src/main/java/de/rwu/easydrop/core/OfferUpdater.java +++ /dev/null @@ -1,110 +0,0 @@ -package de.rwu.easydrop.core; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; -import de.rwu.easydrop.model.Offer; -import de.rwu.easydrop.model.Product; - - -public class OfferUpdater { - - /** - * a. - */ - public OfferUpdater() { - - OfferReviewer offerReviewer = new OfferReviewer(); - List changedOffers = offerReviewer.checkOffer(); - } - - /** - * A. - * @param offersToUpdate - */ - public void runUpdater(final List offersToUpdate) { - Connection connection = null; - PreparedStatement deleteStatement = null; - PreparedStatement insertStatement = null; - - try { - // Establish the database connection - connection = DriverManager.getConnection("jdbc:sqlite:persistence.db"); - - // Disable auto-commit to perform a transaction - connection.setAutoCommit(false); - - // Prepare the DELETE statement to remove the existing entries - String deleteQuery = "DELETE FROM your_table WHERE product_id = ?"; - deleteStatement = connection.prepareStatement(deleteQuery); - - // Prepare the INSERT statement to add the new entries - String insertQuery = "INSERT INTO your_table (product_id, product_name, price)" - + "VALUES (?, ?, ?)"; - insertStatement = connection.prepareStatement(insertQuery); - - // Retrieve the existing entries from the database - List existingProducts = retrieveExistingProducts(connection); - - // Delete the existing entries that are not present in the changedProducts list - for (Product existingProduct : existingProducts) { - if (!changedOffers.(existingProduct)) { - deleteStatement.setString(1, existingProduct.getProductId()); - deleteStatement.executeUpdate(); - } - } - - // Insert the new entries or update the existing entries - for (Product changedOffers : offersToUpdate) { - if (existingProducts.contains(changedOffers)) { - // Update the existing entry with the new data - // You need to modify the update query and statement based on your requirements - // Here's an example of updating the price of an existing entry - String updateQuery = "UPDATE table SET currentPrice = ? WHERE offerId = ?"; - PreparedStatement updateStatement = connection.prepareStatement(updateQuery); - updateStatement.setDouble(1, changedOffers.getCurrentPrice()); - updateStatement.setString(2, changedOffers.getProductId()); - updateStatement.executeUpdate(); - updateStatement.close(); - } else { - // Insert the new entry - insertStatement.setString(1, changedOffers.getProductId()); - insertStatement.setString(2, changedOffers.getMerchant()); - insertStatement.setDouble(3, changedOffers.getCurrentPrice()); - insertStatement.executeUpdate(); - } - } - - // Commit the transaction - connection.commit(); - } catch (SQLException e) { - // Rollback the transaction in case of an exception - if (connection != null) { - try { - connection.rollback(); - } catch (SQLException rollbackException) { - rollbackException.printStackTrace(); - } - } - e.printStackTrace(); - } finally { - // Close the resources (deleteStatement, insertStatement, connection) in a finally block - try { - if (deleteStatement != null) { - deleteStatement.close(); - } - if (insertStatement != null) { - insertStatement.close(); - } - if (connection != null) { - connection.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } -} -} - diff --git a/src/main/java/de/rwu/easydrop/data/connector/AbstractProductPersistence.java b/src/main/java/de/rwu/easydrop/data/connector/AbstractProductPersistence.java deleted file mode 100644 index 6a302dc..0000000 --- a/src/main/java/de/rwu/easydrop/data/connector/AbstractProductPersistence.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.rwu.easydrop.data.connector; - -import de.rwu.easydrop.api.client.AbstractDataSource; -import de.rwu.easydrop.api.dto.ProductDTO; - -/** - * Allows connecting to a persistent product data store. - * - * @since 0.2.0 - */ -public abstract class AbstractProductPersistence extends AbstractDataSource { - /** - * Data origin. - */ - public static final String DATA_ORIGIN = "Persistence"; - - /** - * Writes a ProductDTO to persistence. - * - * @param dto - */ - public abstract void saveProduct(ProductDTO dto); - - /** - * Gets a ProductDTO from persistence. - */ - @Override - public abstract ProductDTO getProductDTOById(String productId); - - /** - * Deletes all data from persistence. - */ - public abstract void clearData(); -} diff --git a/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java b/src/main/java/de/rwu/easydrop/data/connector/OfferPersistenceInterface.java similarity index 64% rename from src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java rename to src/main/java/de/rwu/easydrop/data/connector/OfferPersistenceInterface.java index 5f4bbeb..5d2284b 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/AbstractOfferPersistence.java +++ b/src/main/java/de/rwu/easydrop/data/connector/OfferPersistenceInterface.java @@ -2,13 +2,13 @@ package de.rwu.easydrop.data.connector; import de.rwu.easydrop.api.dto.OfferDTO; -public abstract class AbstractOfferPersistence { +public interface OfferPersistenceInterface { /** * Writes a ProductDTO to persistence. * * @param dto */ - public abstract void saveOffer(OfferDTO dto); + void writeOffer(OfferDTO dto); /** * Gets a OfferDTO from persistence. @@ -16,10 +16,10 @@ public abstract class AbstractOfferPersistence { * @param offerId * @return Offer data transfer object */ - public abstract OfferDTO getOfferDTOById(String offerId); + OfferDTO getOfferDTOById(String offerId); /** * Deletes all data from persistence. */ - public abstract void clearData(); + void clearData(); } diff --git a/src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java b/src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java new file mode 100644 index 0000000..b5a1c1a --- /dev/null +++ b/src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java @@ -0,0 +1,30 @@ +package de.rwu.easydrop.data.connector; + +import de.rwu.easydrop.api.dto.ProductDTO; + +/** + * Allows connecting to a persistent product data store. + * + * @since 0.2.0 + */ +public interface ProductPersistenceInterface { + /** + * Writes a ProductDTO to persistence. + * + * @param dto + */ + void writeProduct(ProductDTO dto); + + /** + * Gets a ProductDTO from persistence. + * + * @param productId Product identifier + * @return Product data transfer object + */ + ProductDTO getProductDTOById(String productId); + + /** + * Deletes all data from persistence. + */ + void clearData(); +} diff --git a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java index 43bb4fe..ba43d53 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java +++ b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java @@ -1,6 +1,5 @@ package de.rwu.easydrop.data.connector; -import java.net.URL; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -9,6 +8,7 @@ import java.sql.Statement; import org.sqlite.SQLiteDataSource; +import de.rwu.easydrop.api.dto.OfferDTO; import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.PersistenceException; import de.rwu.easydrop.model.Webshop; @@ -18,7 +18,8 @@ import de.rwu.easydrop.model.Webshop; * * @since 0.2.0 */ -public final class SQLiteConnector extends AbstractProductPersistence { +public final class SQLiteConnector implements + ProductPersistenceInterface, OfferPersistenceInterface { /** * SQLite Database. */ @@ -53,8 +54,8 @@ public final class SQLiteConnector extends AbstractProductPersistence { Connection connection = db.getConnection(); // Execute SQL statements to create tables - Statement statement = connection.createStatement(); - statement.execute( + Statement createProducts = connection.createStatement(); + createProducts.execute( "CREATE TABLE IF NOT EXISTS products (" + "dataOrigin TEXT, " + "productId TEXT, " @@ -62,12 +63,29 @@ public final class SQLiteConnector extends AbstractProductPersistence { + "merchant TEXT, " + "deliveryPrice REAL, " + "available INT, " - + "lastupdate TEXT, " + + "lastUpdate TEXT, " + "UNIQUE(productId, dataOrigin) ON CONFLICT REPLACE" + ")"); - // Close the statement and connection - statement.close(); + // Close the statement + createProducts.close(); + + Statement createOffers = connection.createStatement(); + createOffers.execute( + "CREATE TABLE IF NOT EXISTS offers (" + + "offerId TEXT, " + + "sourceWebshop TEXT, " + + "sourceId TEXT," + + "sourcePrice REAL, " + + "targetWebshop TEXT, " + + "targetId TEXT, " + + "targetPrice REAL, " + + "lastUpdate TEXT, " + + "UNIQUE(offerId) ON CONFLICT REPLACE" + + ")"); + createOffers.close(); + + // Close the connection connection.close(); } catch (SQLException e) { throw new PersistenceException("Something went wrong while initializing SQLite DB", e); @@ -79,12 +97,12 @@ public final class SQLiteConnector extends AbstractProductPersistence { * * @param dto */ - public void saveProduct(final ProductDTO dto) { + public void writeProduct(final ProductDTO dto) { String query = "INSERT INTO products (" + "dataOrigin, productId, currentPrice, merchant, " - + "deliveryPrice, available, lastupdate" + + "deliveryPrice, available, lastUpdate" + ") VALUES (" - + "?, ?, ?, ?, ?, ?, datetime('now', 'localtime')" + + "?, ?, ?, ?, ?, ?, ?" + ")"; try (Connection connection = db.getConnection(); @@ -97,6 +115,7 @@ public final class SQLiteConnector extends AbstractProductPersistence { statement.setString(++index, dto.getMerchant()); statement.setDouble(++index, dto.getDeliveryPrice()); statement.setBoolean(++index, dto.isAvailable()); + statement.setString(++index, dto.getLastUpdate()); statement.executeUpdate(); } catch (SQLException e) { @@ -138,7 +157,7 @@ public final class SQLiteConnector extends AbstractProductPersistence { public void clearData() { try (Connection connection = db.getConnection(); Statement statement = connection.createStatement()) { - String query = "DELETE FROM products"; + String query = "DELETE FROM products; DELETE FROM offers;"; statement.executeUpdate(query); } catch (SQLException e) { throw new PersistenceException("Something went wrong while clearing the database", e); @@ -146,26 +165,68 @@ public final class SQLiteConnector extends AbstractProductPersistence { } @Override - protected Webshop getDataOrigin() { - throw new UnsupportedOperationException( - this.getClass().getName() + " doesn't support getDataOrigin"); + public void writeOffer(final OfferDTO dto) { + String query = "INSERT INTO offers (" + + "offerId, " + + "sourceWebshop, sourceId, sourcePrice, " + + "targetWebshop, targetId, targetPrice, " + + "lastUpdate" + + ") VALUES (" + + "?, ?, ?, ?, ?, ?, ?, ?" + + ")"; + + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + int index = 0; + ProductDTO sourceProduct = dto.getSourceProduct(); + ProductDTO targetProduct = dto.getTargetProduct(); + + statement.setString(++index, dto.getOfferId()); + statement.setString(++index, sourceProduct.getProductId()); + statement.setString(++index, sourceProduct.getDataOrigin().toString()); + statement.setDouble(++index, sourceProduct.getCurrentPrice()); + statement.setString(++index, targetProduct.getProductId()); + statement.setString(++index, targetProduct.getDataOrigin().toString()); + statement.setDouble(++index, targetProduct.getCurrentPrice()); + statement.setString(++index, dto.getLastUpdate()); + + statement.executeUpdate(); + } catch (SQLException e) { + throw new PersistenceException("Something went wrong while saving to SQLite", e); + } } @Override - protected String getApiKey() { - throw new UnsupportedOperationException( - this.getClass().getName() + " doesn't support getApiKey"); - } + public OfferDTO getOfferDTOById(final String offerId) { + String query = "SELECT * FROM offers WHERE offerId = ?"; + OfferDTO dto = null; - @Override - protected ProductDTO buildProductDTO(final ProductDTO product, final String json) { - throw new UnsupportedOperationException( - this.getClass().getName() + " doesn't support buildProductDTO"); - } + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { - @Override - protected URL createApiUrl(final String productIdentifier) { - throw new UnsupportedOperationException( - this.getClass().getName() + " doesn't support createApiUrl"); + statement.setString(1, offerId); + + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + dto = new OfferDTO(); + ProductDTO srcProduct = new ProductDTO( + resultSet.getString("sourceId"), + Webshop.fromString(resultSet.getString("sourceWebshop"))); + srcProduct.setCurrentPrice(resultSet.getDouble("sourcePrice")); + ProductDTO targetProduct = new ProductDTO( + resultSet.getString("targetId"), + Webshop.fromString(resultSet.getString("targetWebshop"))); + srcProduct.setCurrentPrice(resultSet.getDouble("targetPrice")); + dto.setOfferId(resultSet.getString("offerId")); + dto.setSourceProduct(srcProduct); + dto.setTargetProduct(targetProduct); + dto.setLastUpdate(resultSet.getString("lastUpdate")); + } + } + } catch (SQLException e) { + throw new PersistenceException("Something went wrong while reading from SQLite", e); + } + + return dto; } } diff --git a/src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java b/src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java new file mode 100644 index 0000000..f4d2c0b --- /dev/null +++ b/src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java @@ -0,0 +1,22 @@ +package de.rwu.easydrop.exception; + +public class InvalidOfferException extends RuntimeException { + /** + * Throws an exception that signifies the data of an Offer are invalid. + * + * @param message + */ + public InvalidOfferException(final String message) { + super(message); + } + + /** + * Throws an exception that signifies the data of an Offer are invalid. + * + * @param message + * @param cause + */ + public InvalidOfferException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/de/rwu/easydrop/model/Offer.java b/src/main/java/de/rwu/easydrop/model/Offer.java index 8fae3b7..b2e3577 100644 --- a/src/main/java/de/rwu/easydrop/model/Offer.java +++ b/src/main/java/de/rwu/easydrop/model/Offer.java @@ -1,8 +1,5 @@ package de.rwu.easydrop.model; -import java.util.Date; - - import lombok.Data; /** @@ -10,9 +7,13 @@ import lombok.Data; * * @since 0.3.0 */ - @Data public class Offer { + /** + * ID of the offer, built from identifiers of the source platforms. + */ + private String offerId; + /** * The product that our software buys. */ @@ -21,27 +22,10 @@ public class Offer { /** * The product that our software sells. */ - private Product saleProduct; + private Product targetProduct; /** - * Date of the creation of the offer. - * NOTE: Use Timestamp? https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html + * Date of last update of the offer. */ - private Date creationDate; - - /** - * Date of last update of the offer on the destination website (API). - */ - private Date upDate; - - /** - * Date of last check if offer is still valid. - */ - private Date checkDate; - - /** - * ID of the offer. - */ - private String offerId; - + private String lastUpdate; } diff --git a/src/main/java/de/rwu/easydrop/model/Product.java b/src/main/java/de/rwu/easydrop/model/Product.java index 7e84311..dd412dd 100644 --- a/src/main/java/de/rwu/easydrop/model/Product.java +++ b/src/main/java/de/rwu/easydrop/model/Product.java @@ -40,6 +40,11 @@ public class Product { */ private boolean available; + /** + * Last update from API. + */ + private String lastUpdate; + @Override public final String toString() { return "Product: [" diff --git a/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java b/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java index 97f31dc..2e91d1c 100644 --- a/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java +++ b/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java @@ -68,7 +68,7 @@ public class ProductCatalogue { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("Product Catalogue: ").append(productName).append("\n"); + sb.append("Catalogue Name: ").append(productName).append("\n"); sb.append("Description: ").append(description).append("\n"); sb.append("Products:\n"); for (Product product : products) { diff --git a/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java b/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java index a83a148..aa98afe 100644 --- a/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java +++ b/src/main/java/de/rwu/easydrop/service/mapping/OfferMapper.java @@ -1,7 +1,6 @@ package de.rwu.easydrop.service.mapping; import de.rwu.easydrop.api.dto.OfferDTO; - import de.rwu.easydrop.model.Offer; /** @@ -31,6 +30,10 @@ public final class OfferMapper { */ public static Offer mapOfferFromDTO(final OfferDTO dto) { Offer offer = new Offer(); + offer.setOfferId(dto.getOfferId()); + offer.setSourceProduct(ProductMapper.mapProductFromDTO(dto.getSourceProduct())); + offer.setTargetProduct(ProductMapper.mapProductFromDTO(dto.getTargetProduct())); + offer.setLastUpdate(dto.getLastUpdate()); return offer; } @@ -42,7 +45,11 @@ public final class OfferMapper { * @return OfferDTO */ public static OfferDTO mapOfferToDTO(final Offer offer) { - OfferDTO dto = new OfferDTO(offer.getOfferId()); + OfferDTO dto = new OfferDTO(); + dto.setOfferId(offer.getOfferId()); + dto.setSourceProduct(ProductMapper.mapProductToDTO(offer.getSourceProduct())); + dto.setTargetProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); + dto.setLastUpdate(offer.getLastUpdate()); return dto; } diff --git a/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java b/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java index 123080a..6ada1b4 100644 --- a/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java +++ b/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java @@ -39,6 +39,7 @@ public final class ProductMapper { product.setDeliveryPrice(dto.getDeliveryPrice()); product.setMerchant(dto.getMerchant()); product.setProductId(dto.getProductId()); + product.setLastUpdate(dto.getLastUpdate()); return product; } @@ -56,6 +57,7 @@ public final class ProductMapper { dto.setCurrentPrice(product.getCurrentPrice()); dto.setDeliveryPrice(product.getDeliveryPrice()); dto.setMerchant(product.getMerchant()); + dto.setLastUpdate(product.getLastUpdate()); return dto; } diff --git a/src/main/java/de/rwu/easydrop/service/processing/OrderManager.java b/src/main/java/de/rwu/easydrop/service/processing/OfferIdentifier.java similarity index 64% rename from src/main/java/de/rwu/easydrop/service/processing/OrderManager.java rename to src/main/java/de/rwu/easydrop/service/processing/OfferIdentifier.java index d841505..629d594 100644 --- a/src/main/java/de/rwu/easydrop/service/processing/OrderManager.java +++ b/src/main/java/de/rwu/easydrop/service/processing/OfferIdentifier.java @@ -1,56 +1,56 @@ package de.rwu.easydrop.service.processing; +import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.rwu.easydrop.exception.InvalidCatalogueException; +import de.rwu.easydrop.exception.InvalidOfferException; +import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; import de.rwu.easydrop.model.ProductPair; import de.rwu.easydrop.util.FormattingUtil; +import de.rwu.easydrop.util.Timestamp; -/** - * Creates dropshipping orders based on price margin. - * - * @since 0.3.0 - */ -public final class OrderManager { - +public class OfferIdentifier { /** - * Temporary logging instance. + * Logging instance. */ - private static final Logger LOGGER = LoggerFactory.getLogger(OrderManager.class); + private static final Logger LOGGER = LoggerFactory.getLogger(OfferIdentifier.class); /** - * Private constructor to prevent unwanted instantiation. + * runIdentifier calls the price function that decides + * if it is feasible to dropship products. * - * @throws UnsupportedOperationException always + * @param pCats Product catalogues + * @return Identified offers */ - private OrderManager() throws UnsupportedOperationException { - throw new UnsupportedOperationException("This is a stateless class, don't instantiate it."); - } - - /** - * Creates orders for products with sufficient margin. - * - * @param pCats Product Catalogues - */ - public static void createOrders(final List pCats) { + public List runIdentifier(final List pCats) { + List identifiedOffers = new ArrayList<>(); for (ProductCatalogue pCat : pCats) { - ProductPair pair = getHighestMarginProducts(pCat); - // #12: Create actual orders/transactions, remove logger + // Call price finder for all catalogue + ProductPair pair = getHighestMarginProducts(pCat); + Offer possibleOffer = new Offer(); + possibleOffer.setLastUpdate(Timestamp.now()); + possibleOffer.setSourceProduct(pair.getProduct1()); + possibleOffer.setTargetProduct(pair.getProduct2()); + identifiedOffers.add(possibleOffer); + double margin = pair.getProduct2().getCurrentPrice() - pair.getProduct1().getCurrentPrice(); String marginFormatted = FormattingUtil.formatEuro(margin); - LOGGER.info("{}: Margin {} ({} to {})", + LOGGER.info("\n Identified Offer: {} ({} to {}) with margin {} ", pCat.getProductName(), - marginFormatted, pair.getProduct1().getDataOrigin(), - pair.getProduct2().getDataOrigin()); + pair.getProduct2().getDataOrigin(), + marginFormatted); } + + return identifiedOffers; } /** @@ -79,7 +79,7 @@ public final class OrderManager { } if (cheapestProduct.getCurrentPrice() == mostExpensiveProduct.getCurrentPrice()) { - throw new InvalidCatalogueException("Price margin is zero!"); + throw new InvalidOfferException("Price margin is zero!"); } return new ProductPair(cheapestProduct, mostExpensiveProduct); diff --git a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java similarity index 57% rename from src/main/java/de/rwu/easydrop/core/OfferProvisioner.java rename to src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java index 0f318bd..d6801c7 100644 --- a/src/main/java/de/rwu/easydrop/core/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java @@ -1,15 +1,16 @@ -package de.rwu.easydrop.core; +package de.rwu.easydrop.service.processing; import java.util.List; import de.rwu.easydrop.api.client.AmazonSeller; import de.rwu.easydrop.api.client.EbaySeller; -import de.rwu.easydrop.exception.DataWriterException; +import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.service.mapping.ProductMapper; import de.rwu.easydrop.service.writer.OfferWriter; import de.rwu.easydrop.util.Config; +import de.rwu.easydrop.util.FormattingUtil; public class OfferProvisioner { /** @@ -31,11 +32,11 @@ public class OfferProvisioner { private EbaySeller ebaySeller; private void toSeller(final Offer offer) throws IllegalArgumentException { - if (offer.getSaleProduct().getDataOrigin() == Webshop.eBay) { - this.ebaySeller.sellProduct(ProductMapper.mapProductToDTO(offer.getSaleProduct())); + if (offer.getTargetProduct().getDataOrigin() == Webshop.eBay) { + this.ebaySeller.sellProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); - } else if (offer.getSaleProduct().getDataOrigin().equals(Webshop.Amazon)) { - this.amazonSeller.sellProduct(ProductMapper.mapProductToDTO(offer.getSaleProduct())); + } else if (offer.getTargetProduct().getDataOrigin().equals(Webshop.Amazon)) { + this.amazonSeller.sellProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); } else { throw new IllegalArgumentException("Unsupported target plattform"); } @@ -44,10 +45,11 @@ public class OfferProvisioner { /** * Is the class for placing orders on a target platform. + * + * @param db Persistence Interface */ - public OfferProvisioner(/* OfferWriter for database? */) { - - this.offerWriter = new OfferWriter(); + public OfferProvisioner(final OfferPersistenceInterface db) { + this.offerWriter = new OfferWriter(db); this.config = Config.getInstance(); this.amazonSeller = new AmazonSeller( config.getProperty("AMAZON_API_URL"), @@ -63,27 +65,17 @@ public class OfferProvisioner { * @param offersToProvision */ public final void runProvisioner(final List offersToProvision) { - for (Offer newOffer : offersToProvision) { + String newOfferId = FormattingUtil.removeSpaces( + newOffer.getSourceProduct().getDataOrigin().toString() + + newOffer.getTargetProduct().getDataOrigin().toString() + + "_" + + newOffer.getSourceProduct().getProductId() + + newOffer.getTargetProduct().getProductId()); - try { - this.toSeller(newOffer); - // if successfully transmitted - // add to persistence - // "duplicate" the product with dataOrigin new platform and merchant = "me" - try { - offerWriter.writeOfferToPersistence(newOffer); - } catch (Exception e) { - System.out.println("Could not write to persistence"); - } - } catch (IllegalArgumentException e) { - System.out.println( - "Offer could not be placed, " - + newOffer.getSaleProduct().getDataOrigin() - + " is not supported"); - } catch (DataWriterException e) { - System.out.println("could not transmit offer"); - } + this.toSeller(newOffer); + newOffer.setOfferId(newOfferId); + offerWriter.writeOfferToPersistence(newOffer); } } } diff --git a/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java index c299412..9af6436 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java @@ -5,6 +5,9 @@ import java.util.List; import javax.naming.ConfigurationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; import de.rwu.easydrop.util.ProductsConfig; @@ -17,6 +20,11 @@ import lombok.Data; */ @Data public class CatalogueRetriever { + /** + * Logging instance. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CatalogueRetriever.class); + /** * User-configured products. */ @@ -56,15 +64,14 @@ public class CatalogueRetriever { pCat.getProductName(), pCat.getDescription()); for (Product product : pCat.getProducts()) { - Product newProduct = new Product(); - - newProduct = productRetriever.getProductFromWebshop(product.getDataOrigin(), + Product newProduct = productRetriever.getProductFromWebshop(product.getDataOrigin(), product.getProductId()); newProductCatalogue.addProduct(newProduct); } productCatalogues.add(newProductCatalogue); + LOGGER.info("\nLoaded Catalogue: \n" + newProductCatalogue.toString()); } } } diff --git a/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java index 5488b29..4cef58d 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/OfferRetriever.java @@ -1,5 +1,40 @@ package de.rwu.easydrop.service.retriever; -public class OfferRetriever { +import de.rwu.easydrop.api.dto.OfferDTO; +import de.rwu.easydrop.data.connector.OfferPersistenceInterface; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.service.mapping.OfferMapper; +/** + * Retrieves offer information from different sources. + * + * @since 0.3.0 + */ +public class OfferRetriever { + /** + * Persistence interface. + */ + private OfferPersistenceInterface persistence; + + /** + * Creates an Offer Retriever. + * + * @param db Persistence Interface + */ + public OfferRetriever(final OfferPersistenceInterface db) { + this.persistence = db; + } + + /** + * Retrieves an offer from persistence. + * + * @param offerId + * @return Offer from persistence + */ + public Offer getOfferFromPersistence(final String offerId) { + OfferPersistenceInterface src = persistence; + + OfferDTO dto = src.getOfferDTOById(offerId); + return OfferMapper.mapOfferFromDTO(dto); + } } diff --git a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java index ddbe4b1..cd5cb30 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java @@ -4,7 +4,7 @@ import de.rwu.easydrop.api.client.AmazonProductDataSource; import de.rwu.easydrop.api.client.DataSourceFactory; import de.rwu.easydrop.api.client.EbayItemDataSource; import de.rwu.easydrop.api.dto.ProductDTO; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.data.connector.ProductPersistenceInterface; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.service.mapping.ProductMapper; @@ -20,19 +20,20 @@ public class ProductRetriever { * Data source factory. */ private DataSourceFactory dataSourceFactory; - /** - * @param newDataSourceFactory the WebshopFactory to set + * Persistence interface. */ - public void setWebshopFactory(final DataSourceFactory newDataSourceFactory) { - this.dataSourceFactory = newDataSourceFactory; - } + private ProductPersistenceInterface persistence; /** * @param newDataSourceFactory + * @param newPersistence */ - public ProductRetriever(final DataSourceFactory newDataSourceFactory) { - this.setWebshopFactory(newDataSourceFactory); + public ProductRetriever( + final DataSourceFactory newDataSourceFactory, + final ProductPersistenceInterface newPersistence) { + this.dataSourceFactory = newDataSourceFactory; + this.persistence = newPersistence; } /** @@ -74,9 +75,7 @@ public class ProductRetriever { * @return Product from persistence */ public Product getProductFromPersistence(final String productId) { - AbstractProductPersistence src = dataSourceFactory.createProductPersistenceDataSource(); - - ProductDTO dto = src.getProductDTOById(productId); + ProductDTO dto = persistence.getProductDTOById(productId); Product product = ProductMapper.mapProductFromDTO(dto); ProductValidator.validate(product); diff --git a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java index c3f2257..82fbd89 100644 --- a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java +++ b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java @@ -1,5 +1,6 @@ package de.rwu.easydrop.service.validation; +import de.rwu.easydrop.exception.InvalidOfferException; import de.rwu.easydrop.model.Offer; /** @@ -8,7 +9,7 @@ import de.rwu.easydrop.model.Offer; * @since 0.2.0 */ public final class OfferValidator { - /** + /** * Private constructor to prevent unwanted instantiation. * * @throws UnsupportedOperationException always @@ -16,13 +17,19 @@ public final class OfferValidator { private OfferValidator() throws UnsupportedOperationException { throw new UnsupportedOperationException("This is a validator class, don't instantiate it."); } - /** + + /** * Makes sure an Offer does not contain invalid information. * * @param offer the Offer */ - public static void validate(final Offer offer) { } + public static void validate(final Offer offer) { + try { + if (offer.getOfferId().equals("")) { + throw new InvalidOfferException("Offer ID cannot be empty"); + } + } catch (NullPointerException e) { + throw new InvalidOfferException("Required information is missing in the offer", e); + } + } } - - - diff --git a/src/main/java/de/rwu/easydrop/service/writer/CatalogueWriter.java b/src/main/java/de/rwu/easydrop/service/writer/CatalogueWriter.java index a1cf486..c243f60 100644 --- a/src/main/java/de/rwu/easydrop/service/writer/CatalogueWriter.java +++ b/src/main/java/de/rwu/easydrop/service/writer/CatalogueWriter.java @@ -3,7 +3,7 @@ package de.rwu.easydrop.service.writer; import java.util.List; import de.rwu.easydrop.api.dto.ProductDTO; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.data.connector.ProductPersistenceInterface; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; import de.rwu.easydrop.service.mapping.ProductMapper; @@ -18,14 +18,14 @@ public final class CatalogueWriter { /** * Holds a persistence reference. */ - private AbstractProductPersistence persistence; + private ProductPersistenceInterface persistence; /** * Creates new instance. * * @param newPersistence */ - public CatalogueWriter(final AbstractProductPersistence newPersistence) { + public CatalogueWriter(final ProductPersistenceInterface newPersistence) { persistence = newPersistence; } @@ -40,7 +40,7 @@ public final class CatalogueWriter { ProductValidator.validate(product); ProductDTO dto = ProductMapper.mapProductToDTO(product); - persistence.saveProduct(dto); + persistence.writeProduct(dto); } } } diff --git a/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java b/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java index 6ba6a4c..ba43912 100644 --- a/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java +++ b/src/main/java/de/rwu/easydrop/service/writer/OfferWriter.java @@ -1,21 +1,20 @@ package de.rwu.easydrop.service.writer; import de.rwu.easydrop.api.dto.OfferDTO; -import de.rwu.easydrop.data.connector.AbstractOfferPersistence; +import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.service.mapping.OfferMapper; -import de.rwu.easydrop.service.validation.OfferValidator; public class OfferWriter { /** * Persistence. */ - private AbstractOfferPersistence persistence; + private OfferPersistenceInterface persistence; /** * @param newPersistence the persistence to set */ - public void setPersistence(final AbstractOfferPersistence newPersistence) { + public OfferWriter(final OfferPersistenceInterface newPersistence) { this.persistence = newPersistence; } @@ -25,9 +24,8 @@ public class OfferWriter { * @param offer */ public void writeOfferToPersistence(final Offer offer) { - OfferValidator.validate(offer); OfferDTO dto = OfferMapper.mapOfferToDTO(offer); - persistence.saveOffer(dto); + persistence.writeOffer(dto); } } diff --git a/src/main/java/de/rwu/easydrop/service/writer/ProductWriter.java b/src/main/java/de/rwu/easydrop/service/writer/ProductWriter.java index d1be850..79d8114 100644 --- a/src/main/java/de/rwu/easydrop/service/writer/ProductWriter.java +++ b/src/main/java/de/rwu/easydrop/service/writer/ProductWriter.java @@ -1,7 +1,7 @@ package de.rwu.easydrop.service.writer; import de.rwu.easydrop.api.dto.ProductDTO; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.data.connector.ProductPersistenceInterface; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.service.mapping.ProductMapper; import de.rwu.easydrop.service.validation.ProductValidator; @@ -15,12 +15,12 @@ public class ProductWriter { /** * Persistence. */ - private AbstractProductPersistence persistence; + private ProductPersistenceInterface persistence; /** * @param newPersistence the persistence to set */ - public void setPersistence(final AbstractProductPersistence newPersistence) { + public ProductWriter(final ProductPersistenceInterface newPersistence) { this.persistence = newPersistence; } @@ -33,6 +33,6 @@ public class ProductWriter { ProductValidator.validate(product); ProductDTO dto = ProductMapper.mapProductToDTO(product); - persistence.saveProduct(dto); + persistence.writeProduct(dto); } } diff --git a/src/main/java/de/rwu/easydrop/util/FormattingUtil.java b/src/main/java/de/rwu/easydrop/util/FormattingUtil.java index e8ea662..544e729 100644 --- a/src/main/java/de/rwu/easydrop/util/FormattingUtil.java +++ b/src/main/java/de/rwu/easydrop/util/FormattingUtil.java @@ -37,4 +37,14 @@ public final class FormattingUtil { public static String urlEncode(final String str) { return str.replace(" ", "+"); } + + /** + * Removes spaces from target string. + * + * @param str String + * @return Space-less string + */ + public static String removeSpaces(final String str) { + return str.replace(" ", ""); + } } diff --git a/src/main/java/de/rwu/easydrop/util/Timestamp.java b/src/main/java/de/rwu/easydrop/util/Timestamp.java new file mode 100644 index 0000000..a087982 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/util/Timestamp.java @@ -0,0 +1,29 @@ +package de.rwu.easydrop.util; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Serves as a timestamp source. + * + * @since 0.3.0 + */ +public abstract class Timestamp { + /** + * Hidden constructor. + */ + private Timestamp() { + // Don't instantiate me! + } + + /** + * Returns a formatted time string. + * + * @return String such as "2023-01-01 00:00:00" + */ + public static String now() { + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return now.format(formatter); + } +} From 9927b8f95936aaccf5f44de4298f97bba0b4d61f Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Tue, 27 Jun 2023 06:45:00 +0200 Subject: [PATCH 23/49] SonarLint fixes --- config/demo.products-config.json | 4 +- .../api/client/AmazonProductDataSource.java | 2 +- .../easydrop/api/client/AmazonPurchaser.java | 2 +- .../rwu/easydrop/api/client/AmazonSeller.java | 2 +- .../api/client/EbayItemDataSource.java | 2 +- .../easydrop/api/client/EbayPurchaser.java | 2 +- .../rwu/easydrop/api/client/EbaySeller.java | 2 +- src/main/java/de/rwu/easydrop/core/Core.java | 4 +- .../data/connector/DatabaseConnector.java | 10 ----- .../data/connector/SQLiteConnector.java | 45 ++++++++++++++----- .../rwu/easydrop/model/ProductCatalogue.java | 6 +-- .../java/de/rwu/easydrop/model/Webshop.java | 6 +-- .../service/processing/OfferProvisioner.java | 4 +- .../service/retriever/CatalogueRetriever.java | 4 +- .../service/retriever/ProductRetriever.java | 4 +- .../java/de/rwu/easydrop/util/Timestamp.java | 2 +- 16 files changed, 59 insertions(+), 42 deletions(-) delete mode 100644 src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java diff --git a/config/demo.products-config.json b/config/demo.products-config.json index 2aa9058..84a4f91 100644 --- a/config/demo.products-config.json +++ b/config/demo.products-config.json @@ -5,10 +5,10 @@ "description": "Very epic GPU", "identifiers": [ { - "Amazon": "B096Y2TYKV" + "AMAZON": "B096Y2TYKV" }, { - "eBay": "Gigabyte GeForce RTX 3060" + "EBAY": "Gigabyte GeForce RTX 3060" } ] } 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 06c806e..64d40ee 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonProductDataSource.java @@ -20,7 +20,7 @@ public final class AmazonProductDataSource extends AbstractDataSource { /** * Name of this data source. */ - private static final Webshop DATA_ORIGIN = Webshop.Amazon; + private static final Webshop DATA_ORIGIN = Webshop.AMAZON; /** * Base URL to the Amazon data source. */ diff --git a/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java b/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java index d1dc75c..af96ede 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonPurchaser.java @@ -14,7 +14,7 @@ public final class AmazonPurchaser extends AbstractPurchaser { /** * Name of this data source. */ - private static final Webshop DATA_TARGET = Webshop.Amazon; + private static final Webshop DATA_TARGET = Webshop.AMAZON; /** * Base URL to the Amazon Purchase API. */ diff --git a/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java b/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java index 7b33138..42ab6c6 100644 --- a/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java +++ b/src/main/java/de/rwu/easydrop/api/client/AmazonSeller.java @@ -14,7 +14,7 @@ public final class AmazonSeller extends AbstractSeller { /** * Name of this data source. */ - private static final Webshop DATA_TARGET = Webshop.Amazon; + private static final Webshop DATA_TARGET = Webshop.AMAZON; /** * Base URL to the Amazon Purchase API. */ 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 0b1ed40..f7a205a 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbayItemDataSource.java @@ -20,7 +20,7 @@ public final class EbayItemDataSource extends AbstractDataSource { /** * Name of this data source. */ - private static final Webshop DATA_ORIGIN = Webshop.eBay; + private static final Webshop DATA_ORIGIN = Webshop.EBAY; /** * Base URL to the eBay data source. */ diff --git a/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java b/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java index ebaf121..67fc08e 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbayPurchaser.java @@ -14,7 +14,7 @@ public final class EbayPurchaser extends AbstractPurchaser { /** * Name of this data source. */ - private static final Webshop DATA_TARGET = Webshop.eBay; + private static final Webshop DATA_TARGET = Webshop.EBAY; /** * Base URL to the eBay Purchase API. */ diff --git a/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java b/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java index 55835ec..c09a852 100644 --- a/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java +++ b/src/main/java/de/rwu/easydrop/api/client/EbaySeller.java @@ -14,7 +14,7 @@ public final class EbaySeller extends AbstractSeller { /** * Name of this data source. */ - private static final Webshop DATA_TARGET = Webshop.eBay; + private static final Webshop DATA_TARGET = Webshop.EBAY; /** * Base URL to the eBay Purchase API. */ diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java index 3403b00..a33c14e 100644 --- a/src/main/java/de/rwu/easydrop/core/Core.java +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -69,8 +69,8 @@ public final class Core { OfferProvisioner provis = new OfferProvisioner(odb); provis.runProvisioner(identifiedOffers); - // LOGGER.info("Creating transactions"); - // TODO: Transactions + LOGGER.info("Creating transactions"); + // Transaction logic! LOGGER.info("Done!"); } diff --git a/src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java b/src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java deleted file mode 100644 index ce6360a..0000000 --- a/src/main/java/de/rwu/easydrop/data/connector/DatabaseConnector.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.rwu.easydrop.data.connector; - -/** - * Allows connecting to a SQLite Database. - * - * TODO implement - */ -public class DatabaseConnector { - -} diff --git a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java index ba43d53..4a9e492 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java +++ b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java @@ -36,6 +36,10 @@ public final class SQLiteConnector implements * Path to SQLite db file. */ private static final String PERSISTENCE_PATH = "jdbc:sqlite:persistence.db"; + /** + * Name of 'lastUpdate' column. + */ + private static final String LAST_UPDATE_COL_NAME = "lastUpdate"; /** * Creates instance. @@ -123,13 +127,19 @@ public final class SQLiteConnector implements } } - @Override + /** + * Gets a ProductDTO by identifier. + * + * @param productId + * @return DTO + */ public ProductDTO getProductDTOById(final String productId) { String query = "SELECT * FROM products WHERE productId = ?"; ProductDTO dto = null; - try (Connection connection = db.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { + try { + Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query); statement.setString(1, productId); @@ -142,10 +152,11 @@ public final class SQLiteConnector implements dto.setMerchant(resultSet.getString("merchant")); dto.setDeliveryPrice(resultSet.getDouble("deliveryPrice")); dto.setAvailable(resultSet.getBoolean("available")); + dto.setLastUpdate(resultSet.getString(LAST_UPDATE_COL_NAME)); } } } catch (SQLException e) { - throw new PersistenceException("Something went wrong while reading from SQLite", e); + throw new PersistenceException("Something went wrong while reading from SQLite"); } return dto; @@ -153,24 +164,33 @@ public final class SQLiteConnector implements /** * Deletes all data from persistence. + * + * @throws SQLException */ public void clearData() { try (Connection connection = db.getConnection(); Statement statement = connection.createStatement()) { - String query = "DELETE FROM products; DELETE FROM offers;"; - statement.executeUpdate(query); + + String productsQuery = "DELETE FROM products;"; + String offersQuery = "DELETE FROM offers;"; + statement.executeUpdate(productsQuery); + statement.executeUpdate(offersQuery); } catch (SQLException e) { throw new PersistenceException("Something went wrong while clearing the database", e); } } - @Override + /** + * Writes an offer to persistence. + * + * @param dto OfferDTO + */ public void writeOffer(final OfferDTO dto) { String query = "INSERT INTO offers (" + "offerId, " + "sourceWebshop, sourceId, sourcePrice, " + "targetWebshop, targetId, targetPrice, " - + "lastUpdate" + + LAST_UPDATE_COL_NAME + ") VALUES (" + "?, ?, ?, ?, ?, ?, ?, ?" + ")"; @@ -196,7 +216,12 @@ public final class SQLiteConnector implements } } - @Override + /** + * Gets an OfferDTO by identifier. + * + * @param offerId + * @return OfferDTO + */ public OfferDTO getOfferDTOById(final String offerId) { String query = "SELECT * FROM offers WHERE offerId = ?"; OfferDTO dto = null; @@ -220,7 +245,7 @@ public final class SQLiteConnector implements dto.setOfferId(resultSet.getString("offerId")); dto.setSourceProduct(srcProduct); dto.setTargetProduct(targetProduct); - dto.setLastUpdate(resultSet.getString("lastUpdate")); + dto.setLastUpdate(resultSet.getString(LAST_UPDATE_COL_NAME)); } } } catch (SQLException e) { diff --git a/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java b/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java index 2e91d1c..e907bcc 100644 --- a/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java +++ b/src/main/java/de/rwu/easydrop/model/ProductCatalogue.java @@ -68,11 +68,11 @@ public class ProductCatalogue { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("Catalogue Name: ").append(productName).append("\n"); - sb.append("Description: ").append(description).append("\n"); + sb.append(String.format("Catalogue Name: %s%n", productName)); + sb.append(String.format("Description: %s%n", description)); sb.append("Products:\n"); for (Product product : products) { - sb.append(product.toString()).append("\n"); + sb.append(String.format("%s%n", product.toString())); } return sb.toString(); } diff --git a/src/main/java/de/rwu/easydrop/model/Webshop.java b/src/main/java/de/rwu/easydrop/model/Webshop.java index c4852b6..bab281e 100644 --- a/src/main/java/de/rwu/easydrop/model/Webshop.java +++ b/src/main/java/de/rwu/easydrop/model/Webshop.java @@ -7,11 +7,11 @@ public enum Webshop { /** * Amazon Product API. */ - Amazon, + AMAZON, /** * eBay Item API. */ - eBay; + EBAY; /** * Attempts to derive a webshop value from a string. @@ -26,6 +26,6 @@ public enum Webshop { return shop; } } - throw new IllegalArgumentException(String.format("No webshop called {} found", str)); + throw new IllegalArgumentException(String.format("No webshop called %s found", str)); } } diff --git a/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java index d6801c7..5c1847e 100644 --- a/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java @@ -32,10 +32,10 @@ public class OfferProvisioner { private EbaySeller ebaySeller; private void toSeller(final Offer offer) throws IllegalArgumentException { - if (offer.getTargetProduct().getDataOrigin() == Webshop.eBay) { + if (offer.getTargetProduct().getDataOrigin() == Webshop.EBAY) { this.ebaySeller.sellProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); - } else if (offer.getTargetProduct().getDataOrigin().equals(Webshop.Amazon)) { + } else if (offer.getTargetProduct().getDataOrigin().equals(Webshop.AMAZON)) { this.amazonSeller.sellProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); } else { throw new IllegalArgumentException("Unsupported target plattform"); diff --git a/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java index 9af6436..44c32a3 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/CatalogueRetriever.java @@ -71,7 +71,9 @@ public class CatalogueRetriever { } productCatalogues.add(newProductCatalogue); - LOGGER.info("\nLoaded Catalogue: \n" + newProductCatalogue.toString()); + String catString = String.format( + "%nLoaded Catalogue: %n%s", newProductCatalogue.toString()); + LOGGER.info(catString); } } } diff --git a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java index cd5cb30..8e42ea3 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java @@ -94,9 +94,9 @@ public class ProductRetriever { */ public Product getProductFromWebshop(final Webshop shop, final String productIdentifier) { switch (shop) { - case Amazon: + case AMAZON: return getProductFromAmazon(productIdentifier); - case eBay: + case EBAY: return getProductFromEbay(productIdentifier); default: return null; diff --git a/src/main/java/de/rwu/easydrop/util/Timestamp.java b/src/main/java/de/rwu/easydrop/util/Timestamp.java index a087982..1532c96 100644 --- a/src/main/java/de/rwu/easydrop/util/Timestamp.java +++ b/src/main/java/de/rwu/easydrop/util/Timestamp.java @@ -8,7 +8,7 @@ import java.time.format.DateTimeFormatter; * * @since 0.3.0 */ -public abstract class Timestamp { +public final class Timestamp { /** * Hidden constructor. */ From f2993a19a888c24aa68c0ad2b0417317bc12047a Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Tue, 27 Jun 2023 06:45:25 +0200 Subject: [PATCH 24/49] Updated test cases --- .../api/client/AbstractDataWriterTest.java | 14 +- .../api/client/AbstractPurchaserTest.java | 4 +- .../api/client/AbstractSellerTest.java | 4 +- .../client/AmazonProductDataSourceTest.java | 8 +- .../api/client/AmazonPurchaserTest.java | 2 +- .../easydrop/api/client/AmazonSellerTest.java | 2 +- .../api/client/DataSourceFactoryTest.java | 21 --- .../api/client/EbayItemDataSourceTest.java | 6 +- .../api/client/EbayPurchaserTest.java | 2 +- .../easydrop/api/client/EbaySellerTest.java | 2 +- .../rwu/easydrop/api/dto/ProductDTOTest.java | 10 +- .../easydrop/core/OfferIdentifierTest.java | 10 -- .../easydrop/core/OfferProvisionerTest.java | 10 -- .../rwu/easydrop/core/OfferReviewerTest.java | 10 -- .../rwu/easydrop/core/OfferUpdaterTest.java | 10 -- .../data/connector/SQLiteConnectorTest.java | 65 ++------- .../easydrop/model/ProductCatalogueTest.java | 29 ++-- .../de/rwu/easydrop/model/ProductTest.java | 16 +-- .../service/mapping/ProductMapperTest.java | 6 +- .../service/processing/OrderManagerTest.java | 130 ------------------ .../retriever/CatalogueRetrieverTest.java | 12 +- .../retriever/ProductRetrieverTest.java | 21 ++- .../validation/ProductValidatorTest.java | 6 +- .../service/writer/CatalogueWriterTest.java | 14 +- .../service/writer/ProductWriterTest.java | 13 +- .../test.malformed.products-config.json | 4 +- src/test/resources/test.products-config.json | 4 +- 27 files changed, 104 insertions(+), 331 deletions(-) delete mode 100644 src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java delete mode 100644 src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java delete mode 100644 src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java delete mode 100644 src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java delete mode 100644 src/test/java/de/rwu/easydrop/service/processing/OrderManagerTest.java diff --git a/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java b/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java index 97b007e..78c610f 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java @@ -44,7 +44,7 @@ class AbstractDataWriterTest { @Override protected Webshop getDataTarget() { - return Webshop.Amazon; + return Webshop.AMAZON; } @Override @@ -57,7 +57,7 @@ class AbstractDataWriterTest { @Test void sendPutRequest_badResponseCode_throwsException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO(demoProductId, Webshop.Amazon); + ProductDTO dto = new ProductDTO(demoProductId, Webshop.AMAZON); // Set up Mocks AbstractDataWriter mockWriter = mock(AbstractDataWriter.class); @@ -69,13 +69,13 @@ class AbstractDataWriterTest { writer.sendPutRequest(dto, "Sales"); }); - assertEquals("Amazon Sales API responded with error code 400", e.getMessage()); + assertEquals("AMAZON Sales API responded with error code 400", e.getMessage()); } @Test void sendPutRequest_ioException_throwsException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO(demoProductId, Webshop.Amazon); + ProductDTO dto = new ProductDTO(demoProductId, Webshop.AMAZON); // Set up Mocks AbstractDataWriter mockWriter = mock(AbstractDataWriter.class); @@ -86,13 +86,13 @@ class AbstractDataWriterTest { writer.sendPutRequest(dto, "testApiType"); }); - assertEquals("Couldn't fulfill Amazon API request", e.getMessage()); + assertEquals("Couldn't fulfill AMAZON API request", e.getMessage()); } @Test void sendPutRequest_successfulRequest() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO(demoProductId, Webshop.Amazon); + ProductDTO dto = new ProductDTO(demoProductId, Webshop.AMAZON); // Set up Mocks AbstractDataWriter mockWriter = mock(AbstractDataWriter.class); @@ -102,7 +102,7 @@ class AbstractDataWriterTest { HttpURLConnection mockConnection = mock(HttpURLConnection.class); when(mockURL.openConnection()).thenReturn(mockConnection); when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - when(mockWriter.getDataTarget()).thenReturn(Webshop.Amazon); + when(mockWriter.getDataTarget()).thenReturn(Webshop.AMAZON); assertDoesNotThrow(() -> { mockWriter.sendPutRequest(dto, "Purchase"); diff --git a/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java b/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java index 0a62b8e..3bc169a 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AbstractPurchaserTest.java @@ -21,7 +21,7 @@ class AbstractPurchaserTest { @Test void purchaseProduct_CorrectApiTypeInException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO("12345", Webshop.Amazon); + ProductDTO dto = new ProductDTO("12345", Webshop.AMAZON); // Set up mocks URL mockURL = mock(URL.class); @@ -30,7 +30,7 @@ class AbstractPurchaserTest { HttpURLConnection mockConnection = mock(HttpURLConnection.class); when(mockURL.openConnection()).thenReturn(mockConnection); when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - when(mockPurchaser.getDataTarget()).thenReturn(Webshop.Amazon); + when(mockPurchaser.getDataTarget()).thenReturn(Webshop.AMAZON); assertDoesNotThrow(() -> { mockPurchaser.purchaseProduct(dto); diff --git a/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java b/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java index e907a37..aa3c299 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AbstractSellerTest.java @@ -21,7 +21,7 @@ class AbstractSellerTest { @Test void purchaseProduct_CorrectApiTypeInException() throws IOException { // Set up DTO - ProductDTO dto = new ProductDTO("12345", Webshop.Amazon); + ProductDTO dto = new ProductDTO("12345", Webshop.AMAZON); // Set up mocks URL mockURL = mock(URL.class); @@ -30,7 +30,7 @@ class AbstractSellerTest { HttpURLConnection mockConnection = mock(HttpURLConnection.class); when(mockURL.openConnection()).thenReturn(mockConnection); when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - when(mockSeller.getDataTarget()).thenReturn(Webshop.Amazon); + when(mockSeller.getDataTarget()).thenReturn(Webshop.AMAZON); assertDoesNotThrow(() -> { mockSeller.sellProduct(dto); 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 7735bd9..ba3bfa9 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java @@ -29,7 +29,7 @@ class AmazonProductDataSourceTest { private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static Webshop demoDataOrigin = Webshop.Amazon; + private static Webshop demoDataOrigin = Webshop.AMAZON; private static String demoProductId = "whateverId"; @BeforeEach @@ -139,7 +139,7 @@ class AmazonProductDataSourceTest { // Verify the product DTO properties assertEquals(demoProductId, result.getProductId()); - assertEquals(Webshop.Amazon, result.getDataOrigin()); + assertEquals(Webshop.AMAZON, result.getDataOrigin()); assertEquals(true, result.isAvailable()); assertEquals(10.0, result.getCurrentPrice()); assertEquals(2.5, result.getDeliveryPrice()); @@ -165,7 +165,7 @@ class AmazonProductDataSourceTest { }); // Verify the exception message - assertEquals("Nothing found: Amazon API responded with error code 404", exception.getMessage()); + assertEquals("Nothing found: AMAZON API responded with error code 404", exception.getMessage()); } @Test @@ -188,7 +188,7 @@ class AmazonProductDataSourceTest { }); // Verify the exception message - assertEquals("Couldn't fulfill Amazon API request", exception.getMessage()); + assertEquals("Couldn't fulfill AMAZON API request", exception.getMessage()); } @Test diff --git a/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java b/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java index 1386e97..788fe5e 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonPurchaserTest.java @@ -18,7 +18,7 @@ class AmazonPurchaserTest { private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static Webshop demoDataTarget = Webshop.Amazon; + private static Webshop demoDataTarget = Webshop.AMAZON; @BeforeEach void setup() { diff --git a/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java b/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java index 4ff6d55..d63d89c 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonSellerTest.java @@ -18,7 +18,7 @@ class AmazonSellerTest { private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static Webshop demoDataTarget = Webshop.Amazon; + private static Webshop demoDataTarget = Webshop.AMAZON; @BeforeEach void setup() { diff --git a/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java b/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java index 5196c8b..c152e5f 100644 --- a/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/DataSourceFactoryTest.java @@ -1,8 +1,6 @@ package de.rwu.easydrop.api.client; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; import javax.naming.ConfigurationException; @@ -11,10 +9,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.sqlite.SQLiteDataSource; -import de.rwu.easydrop.data.connector.SQLiteConnector; -import de.rwu.easydrop.exception.PersistenceException; import de.rwu.easydrop.util.Config; class DataSourceFactoryTest { @@ -50,20 +45,4 @@ class DataSourceFactoryTest { // Assert assertEquals("ebay-api-key", DataSource.getApiKey()); } - - @Test - void createProductPersistenceDataSource_NullPersistence() { - PersistenceException exception = assertThrows(PersistenceException.class, () -> { - DataSourceFactory.createProductPersistenceDataSource(); - }); - - assertEquals("Persistence is not set", exception.getMessage()); - } - - @Test - void createProductPersistenceDataSource_WorkingPersistence() { - DataSourceFactory.setPersistence(new SQLiteConnector(new SQLiteDataSource())); - - assertDoesNotThrow(() -> DataSourceFactory.createProductPersistenceDataSource()); - } } 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 a311c73..1615b44 100644 --- a/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/EbayItemDataSourceTest.java @@ -26,7 +26,7 @@ class EbayItemDataSourceTest { private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static Webshop demoDataOrigin = Webshop.eBay; + private static Webshop demoDataOrigin = Webshop.EBAY; private static String demoQuery = "iPhone"; @BeforeEach @@ -83,7 +83,7 @@ class EbayItemDataSourceTest { ProductDTO result = demoDataSource.buildProductDTO(product, json); - assertEquals(Webshop.eBay, result.getDataOrigin()); + assertEquals(Webshop.EBAY, result.getDataOrigin()); assertEquals(false, result.isAvailable()); // Default value for boolean assertEquals(0.0, result.getCurrentPrice()); // Default value for double assertEquals(0.0, result.getDeliveryPrice()); // Default value for double @@ -121,6 +121,6 @@ class EbayItemDataSourceTest { }); // Verify the exception message - assertEquals("Nothing found: eBay API responded with error code 404", exception.getMessage()); + assertEquals("Nothing found: EBAY API responded with error code 404", exception.getMessage()); } } diff --git a/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java b/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java index 2b2104c..d303e0b 100644 --- a/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/EbayPurchaserTest.java @@ -18,7 +18,7 @@ class EbayPurchaserTest { private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static Webshop demoDataTarget = Webshop.eBay; + private static Webshop demoDataTarget = Webshop.EBAY; @BeforeEach void setup() { diff --git a/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java b/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java index 0fe0df0..e9f38ac 100644 --- a/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/EbaySellerTest.java @@ -18,7 +18,7 @@ class EbaySellerTest { private static String demoApiKey = "my-api-key"; private static String demoApiUrl = "https://www.example.com/api"; - private static Webshop demoDataTarget = Webshop.eBay; + private static Webshop demoDataTarget = Webshop.EBAY; @BeforeEach void setup() { diff --git a/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java b/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java index 647babb..3c19d29 100644 --- a/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java +++ b/src/test/java/de/rwu/easydrop/api/dto/ProductDTOTest.java @@ -14,7 +14,7 @@ class ProductDTOTest { void constructor_SetsProductIdAndDataOrigin() { // Arrange String productId = "12345"; - Webshop dataOrigin = Webshop.Amazon; + Webshop dataOrigin = Webshop.AMAZON; // Act ProductDTO productDTO = new ProductDTO(productId, dataOrigin); @@ -27,19 +27,19 @@ class ProductDTOTest { @Test void gettersAndSetters_WorkAsExpected() { // Arrange - ProductDTO productDTO = new ProductDTO("12345", Webshop.Amazon); + ProductDTO productDTO = new ProductDTO("12345", Webshop.AMAZON); // Act and Assert assertEquals("12345", productDTO.getProductId()); - assertEquals(Webshop.Amazon, productDTO.getDataOrigin()); + assertEquals(Webshop.AMAZON, productDTO.getDataOrigin()); // Modify fields productDTO.setProductId("54321"); - productDTO.setDataOrigin(Webshop.eBay); + productDTO.setDataOrigin(Webshop.EBAY); // Assert assertEquals("54321", productDTO.getProductId()); - assertEquals(Webshop.eBay, productDTO.getDataOrigin()); + assertEquals(Webshop.EBAY, productDTO.getDataOrigin()); } @Test diff --git a/src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java b/src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java deleted file mode 100644 index 92d7876..0000000 --- a/src/test/java/de/rwu/easydrop/core/OfferIdentifierTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.rwu.easydrop.core; - -import org.junit.jupiter.api.Test; - -public class OfferIdentifierTest { - @Test - void testRunIdentifier() { - - } -} diff --git a/src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java b/src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java deleted file mode 100644 index 6b3b26a..0000000 --- a/src/test/java/de/rwu/easydrop/core/OfferProvisionerTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.rwu.easydrop.core; - -import org.junit.jupiter.api.Test; - -public class OfferProvisionerTest { - @Test - void testRunProvisioner() { - - } -} diff --git a/src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java b/src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java deleted file mode 100644 index 9c03f5c..0000000 --- a/src/test/java/de/rwu/easydrop/core/OfferReviewerTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.rwu.easydrop.core; - -import org.junit.jupiter.api.Test; - -public class OfferReviewerTest { - @Test - void testRunReviewer() { - - } -} diff --git a/src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java b/src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java deleted file mode 100644 index b7e46ae..0000000 --- a/src/test/java/de/rwu/easydrop/core/OfferUpdaterTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.rwu.easydrop.core; - -import org.junit.jupiter.api.Test; - -public class OfferUpdaterTest { - @Test - void testRunUpdater() { - - } -} diff --git a/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java b/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java index 9c513db..3dcfd84 100644 --- a/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java +++ b/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java @@ -11,11 +11,8 @@ import static org.mockito.Mockito.doThrow; import java.sql.SQLException; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.TestInstance.Lifecycle; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.sqlite.SQLiteDataSource; @@ -24,30 +21,24 @@ import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.exception.PersistenceException; import de.rwu.easydrop.model.Webshop; -@TestInstance(Lifecycle.PER_CLASS) class SQLiteConnectorTest { private static final String TEST_PRODUCT_ID = "12345"; - private SQLiteConnector sqliteConnector; + private SQLiteConnector sqliteConnector = new SQLiteConnector(new SQLiteDataSource()); @Mock private SQLiteDataSource mockDataSource; - @BeforeAll - public void setup() { - sqliteConnector = new SQLiteConnector(new SQLiteDataSource()); - } - @BeforeEach - public void clearDatabase() { + public void prepare() { MockitoAnnotations.openMocks(this); } @Test - void saveProduct_ValidProduct_SuccessfullySaved() { + void writeProduct_ValidProduct_SuccessfullySaved() { // Arrange sqliteConnector.clearData(); - ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.Amazon); - ProductDTO.setDataOrigin(Webshop.Amazon); + ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.AMAZON); + ProductDTO.setDataOrigin(Webshop.AMAZON); ProductDTO.setProductId(TEST_PRODUCT_ID); ProductDTO.setCurrentPrice(9.99); ProductDTO.setMerchant("Sample Merchant"); @@ -55,12 +46,12 @@ class SQLiteConnectorTest { ProductDTO.setAvailable(true); // Act - assertDoesNotThrow(() -> sqliteConnector.saveProduct(ProductDTO)); + assertDoesNotThrow(() -> sqliteConnector.writeProduct(ProductDTO)); // Assert ProductDTO savedProductDTO = sqliteConnector.getProductDTOById(TEST_PRODUCT_ID); assertNotNull(savedProductDTO); - assertEquals(Webshop.Amazon, savedProductDTO.getDataOrigin()); + assertEquals(Webshop.AMAZON, savedProductDTO.getDataOrigin()); assertEquals(TEST_PRODUCT_ID, savedProductDTO.getProductId()); assertEquals(9.99, savedProductDTO.getCurrentPrice()); assertEquals("Sample Merchant", savedProductDTO.getMerchant()); @@ -79,7 +70,7 @@ class SQLiteConnectorTest { // Assert assertNotNull(ProductDTO); - assertEquals(Webshop.Amazon, ProductDTO.getDataOrigin()); + assertEquals(Webshop.AMAZON, ProductDTO.getDataOrigin()); assertEquals(TEST_PRODUCT_ID, ProductDTO.getProductId()); assertEquals(9.99, ProductDTO.getCurrentPrice()); assertEquals("Sample Merchant", ProductDTO.getMerchant()); @@ -112,14 +103,14 @@ class SQLiteConnectorTest { } @Test - void saveProduct_ThrowsPersistenceException_OnSQLException() throws SQLException { + void writeProduct_ThrowsPersistenceException_OnSQLException() throws SQLException { // Arrange - ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.Amazon); + ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.AMAZON); sqliteConnector.setDb(mockDataSource); doThrow(SQLException.class).when(mockDataSource).getConnection(); // Act and Assert - assertThrows(PersistenceException.class, () -> sqliteConnector.saveProduct(ProductDTO)); + assertThrows(PersistenceException.class, () -> sqliteConnector.writeProduct(ProductDTO)); } @Test @@ -144,41 +135,11 @@ class SQLiteConnectorTest { } private void insertSampleProduct() { - ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.Amazon); + ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.AMAZON); ProductDTO.setCurrentPrice(9.99); ProductDTO.setMerchant("Sample Merchant"); ProductDTO.setDeliveryPrice(2.50); ProductDTO.setAvailable(true); - sqliteConnector.saveProduct(ProductDTO); - } - - @Test - void getApiKey_UnsupportedOperationExceptionThrown() { - // Arrange - SQLiteConnector connector = new SQLiteConnector(new SQLiteDataSource()); - - // Act and Assert - assertThrows(UnsupportedOperationException.class, connector::getApiKey); - } - - @Test - void buildProductDTO_UnsupportedOperationExceptionThrown() { - // Arrange - SQLiteConnector connector = new SQLiteConnector(new SQLiteDataSource()); - ProductDTO product = new ProductDTO("ASIN123", Webshop.Amazon); - String json = "{\"productId\":\"ASIN123\",\"dataOrigin\":\"Amazon\"}"; - - // Act and Assert - assertThrows(UnsupportedOperationException.class, () -> connector.buildProductDTO(product, json)); - } - - @Test - void createApiUrl_UnsupportedOperationExceptionThrown() { - // Arrange - SQLiteConnector connector = new SQLiteConnector(new SQLiteDataSource()); - String productIdentifier = "ASIN123"; - - // Act and Assert - assertThrows(UnsupportedOperationException.class, () -> connector.createApiUrl(productIdentifier)); + sqliteConnector.writeProduct(ProductDTO); } } diff --git a/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java b/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java index c83f84f..ebdcab4 100644 --- a/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java +++ b/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java @@ -1,5 +1,7 @@ package de.rwu.easydrop.model; +import static org.mockito.Mockito.description; + import java.util.List; import org.junit.jupiter.api.Assertions; @@ -19,7 +21,7 @@ class ProductCatalogueTest { Product product = new Product(); product.setProductId("12345"); product.setMerchant("AmazonSeller"); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); productCatalogue.addProduct(product); List products = productCatalogue.getProducts(); @@ -32,13 +34,13 @@ class ProductCatalogueTest { Product product1 = new Product(); product1.setProductId("12345"); product1.setMerchant("AmazonSeller"); - product1.setDataOrigin(Webshop.Amazon); + product1.setDataOrigin(Webshop.AMAZON); productCatalogue.addProduct(product1); Product product2 = new Product(); product2.setProductId("54321"); product2.setMerchant("eBaySeller"); - product2.setDataOrigin(Webshop.eBay); + product2.setDataOrigin(Webshop.EBAY); productCatalogue.addProduct(product2); productCatalogue.removeProduct(product1); @@ -53,13 +55,13 @@ class ProductCatalogueTest { Product product1 = new Product(); product1.setProductId("12345"); product1.setMerchant("AmazonSeller"); - product1.setDataOrigin(Webshop.Amazon); + product1.setDataOrigin(Webshop.AMAZON); productCatalogue.addProduct(product1); Product product2 = new Product(); product2.setProductId("54321"); product2.setMerchant("ebayMerchant"); - product2.setDataOrigin(Webshop.eBay); + product2.setDataOrigin(Webshop.EBAY); productCatalogue.addProduct(product2); productCatalogue.clearProducts(); @@ -73,20 +75,23 @@ class ProductCatalogueTest { Product product1 = new Product(); product1.setProductId("12345"); product1.setMerchant("AmazonSeller"); - product1.setDataOrigin(Webshop.Amazon); + product1.setDataOrigin(Webshop.AMAZON); productCatalogue.addProduct(product1); Product product2 = new Product(); product2.setProductId("54321"); product2.setMerchant("eBaySeller"); - product2.setDataOrigin(Webshop.eBay); + product2.setDataOrigin(Webshop.EBAY); productCatalogue.addProduct(product2); - String expectedString = "Product Catalogue: GPU\n" + - "Description: Graphics Processing Units\n" + - "Products:\n" + - "Product: [12345 from AmazonSeller (Amazon) at 0,00 Euro (available: no)]\n" + - "Product: [54321 from eBaySeller (eBay) at 0,00 Euro (available: no)]\n"; + StringBuilder sb = new StringBuilder(); + sb.append(String.format("Catalogue Name: %s%n", "GPU")); + sb.append(String.format("Description: %s%n", "Graphics Processing Units")); + sb.append("Products:\n"); + sb.append(String.format("%s%n", product1.toString())); + sb.append(String.format("%s%n", product2.toString())); + + String expectedString = sb.toString(); Assertions.assertEquals(expectedString, productCatalogue.toString()); } diff --git a/src/test/java/de/rwu/easydrop/model/ProductTest.java b/src/test/java/de/rwu/easydrop/model/ProductTest.java index 2c5c1c2..10c8278 100644 --- a/src/test/java/de/rwu/easydrop/model/ProductTest.java +++ b/src/test/java/de/rwu/easydrop/model/ProductTest.java @@ -10,13 +10,13 @@ class ProductTest { @Test void testToString1() { Product product1 = new Product(); - product1.setDataOrigin(Webshop.Amazon); + product1.setDataOrigin(Webshop.AMAZON); product1.setProductId("12345"); product1.setMerchant("Merchant A"); product1.setCurrentPrice(19.99); product1.setAvailable(true); - String expectedString1 = "Product: [12345 from Merchant A (Amazon) at 19,99 Euro (available: yes)]"; + String expectedString1 = "Product: [12345 from Merchant A (AMAZON) at 19,99 Euro (available: yes)]"; String result1 = product1.toString(); assertEquals(expectedString1, result1); @@ -25,13 +25,13 @@ class ProductTest { @Test void testToString2() { Product product2 = new Product(); - product2.setDataOrigin(Webshop.eBay); + product2.setDataOrigin(Webshop.EBAY); product2.setProductId("67890"); product2.setMerchant("Merchant B"); product2.setCurrentPrice(9.99); product2.setAvailable(false); - String expectedString2 = "Product: [67890 from Merchant B (eBay) at 9,99 Euro (available: no)]"; + String expectedString2 = "Product: [67890 from Merchant B (EBAY) at 9,99 Euro (available: no)]"; String result2 = product2.toString(); assertEquals(expectedString2, result2); @@ -41,7 +41,7 @@ class ProductTest { void gettersAndSetters_WorkAsExpected() { // Arrange Product product = new Product(); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); product.setProductId("12345"); product.setCurrentPrice(9.99); product.setMerchant("Example Merchant"); @@ -49,7 +49,7 @@ class ProductTest { product.setAvailable(true); // Act and Assert - assertEquals(Webshop.Amazon, product.getDataOrigin()); + assertEquals(Webshop.AMAZON, product.getDataOrigin()); assertEquals("12345", product.getProductId()); assertEquals(9.99, product.getCurrentPrice()); assertEquals("Example Merchant", product.getMerchant()); @@ -57,7 +57,7 @@ class ProductTest { assertTrue(product.isAvailable()); // Modify fields - product.setDataOrigin(Webshop.eBay); + product.setDataOrigin(Webshop.EBAY); product.setProductId("54321"); product.setCurrentPrice(19.99); product.setMerchant("New Merchant"); @@ -65,7 +65,7 @@ class ProductTest { product.setAvailable(false); // Assert - assertEquals(Webshop.eBay, product.getDataOrigin()); + assertEquals(Webshop.EBAY, product.getDataOrigin()); assertEquals("54321", product.getProductId()); assertEquals(19.99, product.getCurrentPrice()); assertEquals("New Merchant", product.getMerchant()); diff --git a/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java b/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java index 9212a24..70bae6e 100644 --- a/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java +++ b/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java @@ -48,7 +48,7 @@ class ProductMapperTest { } private ProductDTO createProductDTO() { - ProductDTO dto = new ProductDTO("12345", Webshop.Amazon); + ProductDTO dto = new ProductDTO("12345", Webshop.AMAZON); dto.setAvailable(true); dto.setCurrentPrice(9.99); dto.setDeliveryPrice(2.50); @@ -61,7 +61,7 @@ class ProductMapperTest { // Arrange Product product = new Product(); product.setProductId("12345"); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); product.setAvailable(true); product.setCurrentPrice(9.99); product.setDeliveryPrice(2.50); @@ -72,7 +72,7 @@ class ProductMapperTest { // Assert assertEquals("12345", dto.getProductId()); - assertEquals(Webshop.Amazon, dto.getDataOrigin()); + assertEquals(Webshop.AMAZON, dto.getDataOrigin()); assertTrue(dto.isAvailable()); assertEquals(9.99, dto.getCurrentPrice()); assertEquals(2.50, dto.getDeliveryPrice()); diff --git a/src/test/java/de/rwu/easydrop/service/processing/OrderManagerTest.java b/src/test/java/de/rwu/easydrop/service/processing/OrderManagerTest.java deleted file mode 100644 index 2ffb76a..0000000 --- a/src/test/java/de/rwu/easydrop/service/processing/OrderManagerTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package de.rwu.easydrop.service.processing; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -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.junit.jupiter.api.Assertions.assertTrue; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.Test; - -import de.rwu.easydrop.exception.InvalidCatalogueException; -import de.rwu.easydrop.model.Product; -import de.rwu.easydrop.model.ProductCatalogue; -import de.rwu.easydrop.model.ProductPair; - -class OrderManagerTest { - - @Test - void testConstructorIsPrivate() - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { - // Check for private constructor - Constructor constructor = OrderManager.class.getDeclaredConstructor(); - assertTrue(Modifier.isPrivate(constructor.getModifiers())); - - // Make sure exception is thrown when instantiating - constructor.setAccessible(true); - assertThrows(InvocationTargetException.class, () -> { - constructor.newInstance(); - }); - } - - @Test - void testCreateOrders_ValidCatalogues_OrdersCreated() { - // Arrange - List catalogues = createSampleCatalogues(); - - // Act - assertDoesNotThrow(() -> { - OrderManager.createOrders(catalogues); - }); - } - - @Test - void testGetHighestMarginProducts_ValidCatalogue_CheapestAndMostExpensiveProductsReturned() { - // Arrange - ProductCatalogue catalogue = createSampleCatalogue(); - - // Act - ProductPair pair = OrderManager.getHighestMarginProducts(catalogue); - - // Assert - assertNotNull(pair); - assertNotNull(pair.getProduct1()); - assertNotNull(pair.getProduct2()); - assertEquals("Product2", pair.getProduct1().getProductId()); - assertEquals("Product3", pair.getProduct2().getProductId()); - } - - @Test - void testGetHighestMarginProducts_InvalidCatalogue_ThrowsInvalidCatalogueException() { - // Arrange - ProductCatalogue catalogue = new ProductCatalogue("Catalogue1", "Sample catalogue"); - catalogue.addProduct(new Product()); - // The catalogue has only one product, which is invalid - - // Act & Assert - Exception e = assertThrows(InvalidCatalogueException.class, - () -> OrderManager.getHighestMarginProducts(catalogue)); - - assertEquals("Product Catalogue holds less than 2 products!", e.getMessage()); - } - - @Test - void testGetHighestMarginProducts_InvalidCatalogue_NoMargin() { - // Arrange - ProductCatalogue catalogue = new ProductCatalogue("Catalogue1", "Sample catalogue"); - catalogue.addProduct(new Product()); - catalogue.addProduct(new Product()); - // The catalogue has only one product, which is invalid - - // Act & Assert - Exception e = assertThrows(InvalidCatalogueException.class, - () -> OrderManager.getHighestMarginProducts(catalogue)); - - assertEquals("Price margin is zero!", e.getMessage()); - } - - private List createSampleCatalogues() { - List catalogues = new ArrayList<>(); - - ProductCatalogue catalogue1 = createSampleCatalogue(); - catalogues.add(catalogue1); - - ProductCatalogue catalogue2 = new ProductCatalogue("Catalogue2", "Sample catalogue 2"); - Product product4 = new Product(); - product4.setProductId("Product4"); - product4.setCurrentPrice(6.78); - catalogue2.addProduct(product4); - Product product5 = new Product(); - product5.setProductId("Product5"); - product5.setCurrentPrice(7.89); - catalogue2.addProduct(product5); - catalogues.add(catalogue2); - - return catalogues; - } - - private ProductCatalogue createSampleCatalogue() { - ProductCatalogue catalogue = new ProductCatalogue("Catalogue1", "Sample catalogue"); - Product product1 = new Product(); - product1.setProductId("Product1"); - product1.setCurrentPrice(1.23); - catalogue.addProduct(product1); - Product product2 = new Product(); - product2.setProductId("Product2"); - product2.setCurrentPrice(0.89); - catalogue.addProduct(product2); - Product product3 = new Product(); - product3.setProductId("Product3"); - product3.setCurrentPrice(4.56); - catalogue.addProduct(product3); - return catalogue; - } -} diff --git a/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java index edd772a..b13c571 100644 --- a/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java +++ b/src/test/java/de/rwu/easydrop/service/retriever/CatalogueRetrieverTest.java @@ -38,20 +38,20 @@ class CatalogueRetrieverTest { // Create a sample product catalogue with two products ProductCatalogue productCatalogue = new ProductCatalogue("Catalogue 1", "Sample catalogue"); Product product1 = new Product(); - product1.setDataOrigin(Webshop.Amazon); + product1.setDataOrigin(Webshop.AMAZON); product1.setProductId("ASIN1"); productCatalogue.addProduct(product1); Product product2 = new Product(); - product2.setDataOrigin(Webshop.eBay); + product2.setDataOrigin(Webshop.EBAY); product2.setProductId("ProductID2"); productCatalogue.addProduct(product2); productCatalogues.add(productCatalogue); // Mock the methods when(productsConfig.getProductCatalogues()).thenReturn(productCatalogues); - when(productRetriever.getProductFromWebshop(Webshop.Amazon, "ASIN1")).thenReturn(product1); - when(productRetriever.getProductFromWebshop(Webshop.eBay, "ProductID2")).thenReturn(product2); + when(productRetriever.getProductFromWebshop(Webshop.AMAZON, "ASIN1")).thenReturn(product1); + when(productRetriever.getProductFromWebshop(Webshop.EBAY, "ProductID2")).thenReturn(product2); // Act catalogueRetriever.loadCatalogues(); @@ -70,7 +70,7 @@ class CatalogueRetrieverTest { // Verify the method invocations verify(productsConfig).loadConfig(); - verify(productRetriever).getProductFromWebshop(Webshop.Amazon, "ASIN1"); - verify(productRetriever).getProductFromWebshop(Webshop.eBay, "ProductID2"); + verify(productRetriever).getProductFromWebshop(Webshop.AMAZON, "ASIN1"); + verify(productRetriever).getProductFromWebshop(Webshop.EBAY, "ProductID2"); } } diff --git a/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java index 5fee30f..da42da6 100644 --- a/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java +++ b/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java @@ -17,7 +17,7 @@ import de.rwu.easydrop.api.client.AmazonProductDataSource; import de.rwu.easydrop.api.client.DataSourceFactory; import de.rwu.easydrop.api.client.EbayItemDataSource; import de.rwu.easydrop.api.dto.ProductDTO; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.data.connector.ProductPersistenceInterface; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.util.Config; @@ -26,7 +26,7 @@ class ProductRetrieverTest { @Mock private Config config; @Mock - private DataSourceFactory DataSourceFactory; + private DataSourceFactory dataSourceFactory; @Mock private AmazonProductDataSource amazonDataSource; @Mock @@ -36,7 +36,7 @@ class ProductRetrieverTest { @Mock private Product product; @Mock - private AbstractProductPersistence persistence; + private ProductPersistenceInterface persistence; private ProductRetriever productRetriever; @@ -45,19 +45,19 @@ class ProductRetrieverTest { MockitoAnnotations.openMocks(this); when(config.getProperty("AMAZON_API_URL")).thenReturn("https://api.amazon.com"); when(config.getProperty("AMAZON_API_KEY")).thenReturn("amazon-api-key"); - DataSourceFactory.setConfig(config); - productRetriever = new ProductRetriever(DataSourceFactory); + dataSourceFactory.setConfig(config); + productRetriever = new ProductRetriever(dataSourceFactory, persistence); } @Test void getProductFromAmazon_ReturnsProduct() { // Arrange String asin = "B01234ABC"; - when(DataSourceFactory.createAmazonProductDataSource()).thenReturn(amazonDataSource); + when(dataSourceFactory.createAmazonProductDataSource()).thenReturn(amazonDataSource); when(amazonDataSource.getProductDTOById(asin)).thenReturn(productDTO); when(productDTO.getProductId()).thenReturn(asin); when(productDTO.getCurrentPrice()).thenReturn(9.99); - when(productDTO.getDataOrigin()).thenReturn(Webshop.Amazon); + when(productDTO.getDataOrigin()).thenReturn(Webshop.AMAZON); // Act Product result = productRetriever.getProductFromAmazon(asin); @@ -73,11 +73,11 @@ class ProductRetrieverTest { void getProductFromEbay_ReturnsProduct() { // Arrange String productQuery = "MySearchQuery"; - when(DataSourceFactory.createEbayItemDataSource()).thenReturn(ebayDataSource); + when(dataSourceFactory.createEbayItemDataSource()).thenReturn(ebayDataSource); when(ebayDataSource.getProductDTOById(productQuery)).thenReturn(productDTO); when(productDTO.getProductId()).thenReturn(productQuery); when(productDTO.getCurrentPrice()).thenReturn(9.99); - when(productDTO.getDataOrigin()).thenReturn(Webshop.eBay); + when(productDTO.getDataOrigin()).thenReturn(Webshop.EBAY); // Act Product result = productRetriever.getProductFromEbay(productQuery); @@ -93,11 +93,10 @@ class ProductRetrieverTest { void getProductFromPersistence_ValidProductId_ReturnsProduct() { // Arrange String productId = "123"; - when(DataSourceFactory.createProductPersistenceDataSource()).thenReturn(persistence); when(persistence.getProductDTOById(productId)).thenReturn(productDTO); when(productDTO.getProductId()).thenReturn(productId); when(productDTO.getCurrentPrice()).thenReturn(9.99); - when(productDTO.getDataOrigin()).thenReturn(Webshop.Amazon); + when(productDTO.getDataOrigin()).thenReturn(Webshop.AMAZON); // Act Product result = productRetriever.getProductFromPersistence(productId); diff --git a/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java index 1ad2f6b..4058ea7 100644 --- a/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java +++ b/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java @@ -38,7 +38,7 @@ class ProductValidatorTest { // Arrange Product product = new Product(); product.setCurrentPrice(9.99); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); product.setProductId("12345"); // Act and Assert @@ -61,7 +61,7 @@ class ProductValidatorTest { private static Product createProductWithZeroPrice() { Product product = new Product(); product.setCurrentPrice(0.00); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); product.setProductId("12345"); return product; } @@ -69,7 +69,7 @@ class ProductValidatorTest { private static Product createProductWithEmptyProductId() { Product product = new Product(); product.setCurrentPrice(9.99); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); product.setProductId(""); return product; } diff --git a/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java index c590733..22eb73b 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/CatalogueWriterTest.java @@ -13,7 +13,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.ProductDTO; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.data.connector.ProductPersistenceInterface; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.ProductCatalogue; import de.rwu.easydrop.model.Webshop; @@ -21,7 +21,7 @@ import de.rwu.easydrop.model.Webshop; class CatalogueWriterTest { @Mock - private AbstractProductPersistence persistenceMock; + private ProductPersistenceInterface persistenceMock; private CatalogueWriter catalogueWriter; @@ -40,19 +40,19 @@ class CatalogueWriterTest { catalogueWriter.writeCatalogues(catalogues); // Assert - verify(persistenceMock, times(4)).saveProduct(any(ProductDTO.class)); + verify(persistenceMock, times(4)).writeProduct(any(ProductDTO.class)); } private List createSampleCatalogues() { List catalogues = new ArrayList<>(); ProductCatalogue catalogue1 = new ProductCatalogue("Catalogue 1", "Sample catalogue 1"); - catalogue1.addProduct(createSampleProduct(Webshop.Amazon, "ID 1")); - catalogue1.addProduct(createSampleProduct(Webshop.eBay, "ID 2")); + catalogue1.addProduct(createSampleProduct(Webshop.AMAZON, "ID 1")); + catalogue1.addProduct(createSampleProduct(Webshop.EBAY, "ID 2")); ProductCatalogue catalogue2 = new ProductCatalogue("Catalogue 2", "Sample catalogue 2"); - catalogue2.addProduct(createSampleProduct(Webshop.Amazon, "ID 3")); - catalogue2.addProduct(createSampleProduct(Webshop.eBay, "ID 4")); + catalogue2.addProduct(createSampleProduct(Webshop.AMAZON, "ID 3")); + catalogue2.addProduct(createSampleProduct(Webshop.EBAY, "ID 4")); catalogues.add(catalogue1); catalogues.add(catalogue2); diff --git a/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java index e2bd870..60f9198 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/ProductWriterTest.java @@ -10,22 +10,21 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.ProductDTO; -import de.rwu.easydrop.data.connector.AbstractProductPersistence; +import de.rwu.easydrop.data.connector.ProductPersistenceInterface; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.Webshop; class ProductWriterTest { @Mock - private AbstractProductPersistence persistence; + private ProductPersistenceInterface persistence; private ProductWriter productWriter; @BeforeEach public void setup() { MockitoAnnotations.openMocks(this); - productWriter = new ProductWriter(); - productWriter.setPersistence(persistence); + productWriter = new ProductWriter(persistence); } @Test @@ -33,14 +32,14 @@ class ProductWriterTest { // Arrange Product product = new Product(); product.setProductId("12345"); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); product.setCurrentPrice(9.99); // Act productWriter.writeProductToPersistence(product); // Assert - Mockito.verify(persistence).saveProduct(any(ProductDTO.class)); + Mockito.verify(persistence).writeProduct(any(ProductDTO.class)); } @Test @@ -48,7 +47,7 @@ class ProductWriterTest { // Arrange Product product = new Product(); product.setProductId(""); - product.setDataOrigin(Webshop.Amazon); + product.setDataOrigin(Webshop.AMAZON); // Act and Assert assertThrows(Exception.class, () -> productWriter.writeProductToPersistence(product)); diff --git a/src/test/resources/test.malformed.products-config.json b/src/test/resources/test.malformed.products-config.json index 00d0092..1d7c6fe 100644 --- a/src/test/resources/test.malformed.products-config.json +++ b/src/test/resources/test.malformed.products-config.json @@ -5,10 +5,10 @@ description: "Integration Testing Product", "identifiers": [ { - "Amazon": "DEMO-AMAZON-001" + "AMAZON": "DEMO-AMAZON-001" }, { - "eBay": "DEMO-EBAY-001" + "EBAY": "DEMO-EBAY-001" } ] ] diff --git a/src/test/resources/test.products-config.json b/src/test/resources/test.products-config.json index 44262c8..c48cfc6 100644 --- a/src/test/resources/test.products-config.json +++ b/src/test/resources/test.products-config.json @@ -5,10 +5,10 @@ "description": "Integration Testing Product", "identifiers": [ { - "Amazon": "DEMO-AMAZON-001" + "AMAZON": "DEMO-AMAZON-001" }, { - "eBay": "DEMO-EBAY-001" + "EBAY": "DEMO-EBAY-001" } ] } From d80f5cf00c0fed366629546c526a2091211721dc Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 15:56:21 +0200 Subject: [PATCH 25/49] created test class "OfferRetrieverTest" --- .../service/retriever/OfferRetrieverTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java diff --git a/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java new file mode 100644 index 0000000..f29059a --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java @@ -0,0 +1,85 @@ +package de.rwu.easydrop.service.retriever; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +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.api.client.AmazonProductDataSource; +import de.rwu.easydrop.api.client.DataSourceFactory; +import de.rwu.easydrop.api.client.EbayItemDataSource; +import de.rwu.easydrop.api.dto.OfferDTO; +import de.rwu.easydrop.data.connector.OfferPersistenceInterface; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.util.Config; + + + + +class OfferRetrieverTest { + + @Mock + private Config config; + @Mock + private DataSourceFactory dataSourceFactory; + @Mock + private AmazonProductDataSource amazonDataSource; + @Mock + private EbayItemDataSource ebayDataSource; + @Mock + private OfferDTO offerDTO; + @Mock + private Offer offer; + @Mock + private OfferPersistenceInterface persistence; + + private OfferRetriever offerRetriever; + + @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"); + dataSourceFactory.setConfig(config); + offerRetriever = new OfferRetriever(persistence); + } + + @Test + void getOfferFromPersistence(){ + //Arrange + String offerId = "187"; + String lastUpdate = "2023-01-01"; + when(persistence.getOfferDTOById(offerId)).thenReturn(offerDTO); + when(offerDTO.getOfferId()).thenReturn(offerId); + when(offerDTO.getLastUpdate()).thenReturn(lastUpdate); + + //Act + Offer result = offerRetriever.getOfferFromPersistence(offerId); + + //Assert + assertEquals(offerId, result.getOfferId()); + assertEquals(lastUpdate, result.getLastUpdate()); + + //Verify + verify(persistence, times(1)).getOfferDTOById(offerId); + + } + + + + + + + + + + + +} From e0f30e4710e0b1b139f5e21a86110a76e7f77d25 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 15:58:10 +0200 Subject: [PATCH 26/49] created test getOfferFromPersistence --- src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java b/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java index ebdcab4..df78e3e 100644 --- a/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java +++ b/src/test/java/de/rwu/easydrop/model/ProductCatalogueTest.java @@ -1,6 +1,6 @@ package de.rwu.easydrop.model; -import static org.mockito.Mockito.description; + import java.util.List; From 09cfb6adfab4983d8e6e5ac1f9df99b67407b6b6 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 16:14:55 +0200 Subject: [PATCH 27/49] created product mock object --- .../easydrop/service/retriever/OfferRetrieverTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java index f29059a..d994e46 100644 --- a/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java +++ b/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java @@ -1,6 +1,7 @@ package de.rwu.easydrop.service.retriever; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -16,6 +17,7 @@ import de.rwu.easydrop.api.client.AmazonProductDataSource; import de.rwu.easydrop.api.client.DataSourceFactory; import de.rwu.easydrop.api.client.EbayItemDataSource; import de.rwu.easydrop.api.dto.OfferDTO; +import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.util.Config; @@ -53,6 +55,12 @@ class OfferRetrieverTest { @Test void getOfferFromPersistence(){ + + // a mock ProductDTO object to return from the offerDTO mock + ProductDTO productDTO = mock(ProductDTO.class); + when(productDTO.isAvailable()).thenReturn(false); + + //Arrange String offerId = "187"; String lastUpdate = "2023-01-01"; From b1233922bdcf10fd74680303f68a065e8447d479 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 16:20:25 +0200 Subject: [PATCH 28/49] offerdto instance erstellt --- src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java index 8ffd6a8..479c052 100644 --- a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java +++ b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java @@ -28,4 +28,14 @@ public class OfferDTO { * Date of last update of the offer. */ private String lastUpdate; + + /** + * Creates OfferDTO instance. + * @param newofferId + * @param newLastUpdate + */ + public OfferDTO(final String newofferId, final String newLastUpdate){ + this.offerId = newofferId; + this.lastUpdate = newLastUpdate; + } } From 6ca2027123527eeb2bcec4c84e666613df0ef48c Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 16:41:25 +0200 Subject: [PATCH 29/49] fixed test "getOfferFromPersistence" --- .../service/retriever/OfferRetrieverTest.java | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java index d994e46..aa95f42 100644 --- a/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java +++ b/src/test/java/de/rwu/easydrop/service/retriever/OfferRetrieverTest.java @@ -23,8 +23,6 @@ import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.util.Config; - - class OfferRetrieverTest { @Mock @@ -56,10 +54,9 @@ class OfferRetrieverTest { @Test void getOfferFromPersistence(){ - // a mock ProductDTO object to return from the offerDTO mock + //Mock ProductDTO object to return from the offerDTO mock ProductDTO productDTO = mock(ProductDTO.class); - when(productDTO.isAvailable()).thenReturn(false); - + when(productDTO.isAvailable()).thenReturn(true); //Arrange String offerId = "187"; @@ -67,6 +64,8 @@ class OfferRetrieverTest { when(persistence.getOfferDTOById(offerId)).thenReturn(offerDTO); when(offerDTO.getOfferId()).thenReturn(offerId); when(offerDTO.getLastUpdate()).thenReturn(lastUpdate); + when(offerDTO.getSourceProduct()).thenReturn(productDTO); + when(offerDTO.getTargetProduct()).thenReturn(productDTO); //Act Offer result = offerRetriever.getOfferFromPersistence(offerId); @@ -80,14 +79,4 @@ class OfferRetrieverTest { } - - - - - - - - - - } From 19c796b457f2df7c2586674232ada5e5ba7aa36b Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Tue, 27 Jun 2023 16:41:55 +0200 Subject: [PATCH 30/49] #75 Added transaction base classes --- .../rwu/easydrop/api/dto/TransactionDTO.java | 28 ++++++++++ .../de/rwu/easydrop/model/Transaction.java | 30 +++++++++++ .../service/mapping/TransactionMapper.java | 54 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 src/main/java/de/rwu/easydrop/api/dto/TransactionDTO.java create mode 100644 src/main/java/de/rwu/easydrop/model/Transaction.java create mode 100644 src/main/java/de/rwu/easydrop/service/mapping/TransactionMapper.java diff --git a/src/main/java/de/rwu/easydrop/api/dto/TransactionDTO.java b/src/main/java/de/rwu/easydrop/api/dto/TransactionDTO.java new file mode 100644 index 0000000..630b2ce --- /dev/null +++ b/src/main/java/de/rwu/easydrop/api/dto/TransactionDTO.java @@ -0,0 +1,28 @@ +package de.rwu.easydrop.api.dto; + +import lombok.Data; + +/** + * Transaction data transfer object. + * + * @since 0.3.0 + */ +@Data +public class TransactionDTO { + /** + * Offer ID. + */ + private String offerId; + /** + * Sales volume. + */ + private double volume; + /** + * Earnings (volume - cost). + */ + private double earnings; + /** + * Transaction timestamp. + */ + private String transactionTime; +} diff --git a/src/main/java/de/rwu/easydrop/model/Transaction.java b/src/main/java/de/rwu/easydrop/model/Transaction.java new file mode 100644 index 0000000..a8236fb --- /dev/null +++ b/src/main/java/de/rwu/easydrop/model/Transaction.java @@ -0,0 +1,30 @@ +package de.rwu.easydrop.model; + +import lombok.Data; + +/** + * A transaction. + * + * @since 0.3.0 + */ +@Data +public class Transaction { + /** + * Offer ID. + * + * @see Offer + */ + private String offerId; + /** + * Sales volume. + */ + private double volume; + /** + * Earnings (volume - cost). + */ + private double earnings; + /** + * Transaction timestamp. + */ + private String transactionTime; +} diff --git a/src/main/java/de/rwu/easydrop/service/mapping/TransactionMapper.java b/src/main/java/de/rwu/easydrop/service/mapping/TransactionMapper.java new file mode 100644 index 0000000..47c68f5 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/mapping/TransactionMapper.java @@ -0,0 +1,54 @@ +package de.rwu.easydrop.service.mapping; + +import de.rwu.easydrop.api.dto.TransactionDTO; +import de.rwu.easydrop.model.Transaction; + +/** + * Maps transaction DTOs and objects. + * + * @since 0.3.0 + */ +public final class TransactionMapper { + /** + * Private constructor to prevent unwanted instantiation. + * + * @throws UnsupportedOperationException always + */ + private TransactionMapper() throws UnsupportedOperationException { + throw new UnsupportedOperationException("This is a mapping class, don't instantiate it."); + } + + /** + * Creates a Transaction object from a corresponding DTO. + * + * @param dto Transaction Data Transfer Object + * @return Product + */ + public static Transaction mapTXFromDTO(final TransactionDTO dto) { + Transaction tx = new Transaction(); + + tx.setOfferId(dto.getOfferId()); + tx.setVolume(dto.getVolume()); + tx.setEarnings(dto.getEarnings()); + tx.setTransactionTime(dto.getTransactionTime()); + + return tx; + } + + /** + * Creates a ProductDTO object from a corresponding Product. + * + * @param tx Transaction + * @return TransactionDTO + */ + public static TransactionDTO mapTXToDTO(final Transaction tx) { + TransactionDTO dto = new TransactionDTO(); + + dto.setOfferId(tx.getOfferId()); + dto.setVolume(tx.getVolume()); + dto.setEarnings(tx.getEarnings()); + dto.setTransactionTime(tx.getTransactionTime()); + + return dto; + } +} From b551f03d160dffc21e61858686d2f86f090d2529 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 16:42:49 +0200 Subject: [PATCH 31/49] fixed checkstyle problems --- src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java index 479c052..8dc04d0 100644 --- a/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java +++ b/src/main/java/de/rwu/easydrop/api/dto/OfferDTO.java @@ -29,13 +29,5 @@ public class OfferDTO { */ private String lastUpdate; - /** - * Creates OfferDTO instance. - * @param newofferId - * @param newLastUpdate - */ - public OfferDTO(final String newofferId, final String newLastUpdate){ - this.offerId = newofferId; - this.lastUpdate = newLastUpdate; - } + } From f9ea1f65ca3a7d68803d074385e6367d85f76a13 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 17:19:32 +0200 Subject: [PATCH 32/49] created test test for writeOffer --- .../service/writer/OfferWriterTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java diff --git a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java new file mode 100644 index 0000000..2d966bd --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java @@ -0,0 +1,62 @@ +package de.rwu.easydrop.service.writer; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import javax.sound.sampled.AudioFileFormat.Type; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import de.rwu.easydrop.api.dto.OfferDTO; +import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.data.connector.OfferPersistenceInterface; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; + +public class OfferWriterTest { + + @Mock + private OfferDTO offerDTO; + @Mock + private OfferPersistenceInterface persistence; + + private OfferWriter offerWriter; + + @BeforeEach + public void setup() { + MockitoAnnotations.openMocks(this); + offerWriter = new OfferWriter(persistence); + } + + + + + @Test + void writeOfferToPersistence_InvalidProduct_ThrowsException() { + //Arrange + Offer offer = new Offer(); + offer.setOfferId(""); + offer.setLastUpdate(""); + + //Act and Assert + assertThrows(Exception.class, () -> offerWriter.writeOfferToPersistence(offer)); + } + + + + + + + + + + +} From 23c8a8c95a94ce71cce2b753e625478487357591 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 17:23:05 +0200 Subject: [PATCH 33/49] created test write offer with validproduct --- .../service/writer/OfferWriterTest.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java index 2d966bd..ef2d367 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java @@ -36,9 +36,6 @@ public class OfferWriterTest { offerWriter = new OfferWriter(persistence); } - - - @Test void writeOfferToPersistence_InvalidProduct_ThrowsException() { //Arrange @@ -50,6 +47,30 @@ public class OfferWriterTest { assertThrows(Exception.class, () -> offerWriter.writeOfferToPersistence(offer)); } + @Test + void writeOfferToPresistence_ValidProduct_CallsSaveProduct(){ + + // Arrange + Product product = new Product(); + product.setProductId("12345"); + product.setDataOrigin(Webshop.AMAZON); + product.setCurrentPrice(9.99); + + // Arrange + Offer offer = new Offer(); + offer.setOfferId("26876"); + offer.setLastUpdate("2022-12-25"); + offer.setSourceProduct(product); + offer.setTargetProduct(product); + + // Act + offerWriter.writeOfferToPersistence(offer); + + // Assert + Mockito.verify(persistence).writeOffer(any(OfferDTO.class)); + + } + From 1b30e29d145b90fdeacc9ad813166816efb4c0c7 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 17:23:36 +0200 Subject: [PATCH 34/49] created test for writeOffer with valid product --- .../java/de/rwu/easydrop/service/writer/OfferWriterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java index ef2d367..1cbe974 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java @@ -47,7 +47,7 @@ public class OfferWriterTest { assertThrows(Exception.class, () -> offerWriter.writeOfferToPersistence(offer)); } - @Test + @Test void writeOfferToPresistence_ValidProduct_CallsSaveProduct(){ // Arrange From af000158fd19c60ca0de67487cca56cf39ac4d3e Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 17:24:32 +0200 Subject: [PATCH 35/49] deleted unnecessary imports --- .../de/rwu/easydrop/service/writer/OfferWriterTest.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java index 1cbe974..70bf52a 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java @@ -1,12 +1,8 @@ package de.rwu.easydrop.service.writer; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.junit.jupiter.api.Assertions.assertThrows; -import javax.sound.sampled.AudioFileFormat.Type; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -15,7 +11,6 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import de.rwu.easydrop.api.dto.OfferDTO; -import de.rwu.easydrop.api.dto.ProductDTO; import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.Product; From 41acb18dcbd0d5d760a5a471b95c2ef090063d6f Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 17:26:14 +0200 Subject: [PATCH 36/49] new class for offer validator test --- .../rwu/easydrop/service/validation/OfferValidatorTest.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java diff --git a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java new file mode 100644 index 0000000..f2d4a4b --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java @@ -0,0 +1,5 @@ +package de.rwu.easydrop.service.validation; + +public class OfferValidatorTest { + +} From 0b403d73eab80e6952c9f0edd0bc13ca6eb46588 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 17:54:37 +0200 Subject: [PATCH 37/49] class OfferValidatorTest and test validate created --- .../service/validation/OfferValidatorTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java index f2d4a4b..e7d5b39 100644 --- a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java +++ b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java @@ -1,5 +1,23 @@ package de.rwu.easydrop.service.validation; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +import de.rwu.easydrop.model.Offer; + + public class OfferValidatorTest { + + @Test + void validate_Offer_ValidProduct_NoExceptionThrown() { + // Arrange + Offer offer = new Offer(); + offer.setOfferId("3672"); + offer.setLastUpdate("2021-02-03"); + + // Act and Assert + assertDoesNotThrow(() -> OfferValidator.validate(offer)); + } } From 0eb0f903c6fbd8e7896687e208265b3f755dea34 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 18:10:25 +0200 Subject: [PATCH 38/49] added invalid offerexception test --- .../service/validation/OfferValidatorTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java index e7d5b39..f83c24e 100644 --- a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java +++ b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java @@ -1,9 +1,13 @@ package de.rwu.easydrop.service.validation; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import de.rwu.easydrop.exception.InvalidOfferException; import de.rwu.easydrop.model.Offer; @@ -19,5 +23,13 @@ public class OfferValidatorTest { // Act and Assert assertDoesNotThrow(() -> OfferValidator.validate(offer)); } + + @ParameterizedTest + @MethodSource("invalidOffer") + void validate_InvalidOffer_ThrowsInvalidOfferException(Offer offer) { + // Act and Assert + assertThrows(InvalidOfferException.class, () -> OfferValidator.validate(offer)); + } + } From 7056d34688fde4b2fe4baad758d12786949084b4 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 18:32:15 +0200 Subject: [PATCH 39/49] added ParameterizedTest for offer validator --- .../service/validation/OfferValidator.java | 3 +++ .../validation/OfferValidatorTest.java | 24 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java index 82fbd89..edf5491 100644 --- a/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java +++ b/src/main/java/de/rwu/easydrop/service/validation/OfferValidator.java @@ -28,6 +28,9 @@ public final class OfferValidator { if (offer.getOfferId().equals("")) { throw new InvalidOfferException("Offer ID cannot be empty"); } + if (offer.getLastUpdate().equals("")) { + throw new InvalidOfferException("LastUpdate cannot be empty"); + } } catch (NullPointerException e) { throw new InvalidOfferException("Required information is missing in the offer", e); } diff --git a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java index f83c24e..bb16c4b 100644 --- a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java +++ b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java @@ -3,6 +3,8 @@ package de.rwu.easydrop.service.validation; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.stream.Stream; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -25,11 +27,31 @@ public class OfferValidatorTest { } @ParameterizedTest - @MethodSource("invalidOffer") + @MethodSource("invalidOfferProvider") void validate_InvalidOffer_ThrowsInvalidOfferException(Offer offer) { // Act and Assert assertThrows(InvalidOfferException.class, () -> OfferValidator.validate(offer)); + } + static Stream invalidOfferProvider() { + return Stream.of( + createOfferWithEmptylastUpdate(), + createOfferWithEmptyId()); + } + + private static Offer createOfferWithEmptylastUpdate() { + Offer offer = new Offer(); + offer.setOfferId("3729798"); + offer.setLastUpdate(""); + return offer; + } + + private static Offer createOfferWithEmptyId() { + Offer offer = new Offer(); + offer.setOfferId(""); + offer.setLastUpdate("8798476"); + return offer; + } } From 0151ceb00c3e21d4205c35eb0879b73c2eb748ce Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 18:35:58 +0200 Subject: [PATCH 40/49] offermapper test added --- .../de/rwu/easydrop/service/mapping/OfferMapperTest.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java diff --git a/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java b/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java new file mode 100644 index 0000000..02bfb7f --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java @@ -0,0 +1,5 @@ +package de.rwu.easydrop.service.mapping; + +public class OfferMapperTest { + +} From d05ea47e726137a1ed1a5ebbd87015808d4ab4c7 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 19:44:30 +0200 Subject: [PATCH 41/49] created mapOffer test --- .../service/mapping/OfferMapperTest.java | 60 ++++++++++++++++++- .../validation/OfferValidatorTest.java | 2 +- .../service/writer/OfferWriterTest.java | 2 +- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java b/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java index 02bfb7f..099d63c 100644 --- a/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java +++ b/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java @@ -1,5 +1,63 @@ package de.rwu.easydrop.service.mapping; -public class OfferMapperTest { +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import org.junit.jupiter.api.Test; + +import de.rwu.easydrop.api.dto.OfferDTO; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; + +class OfferMapperTest { + + @Test + void testConstructorIsPrivate() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + // Check for private constructor + Constructor constructor = OfferMapper.class.getDeclaredConstructor(); + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + + // Make sure exception is thrown when instantiating + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, () -> { + constructor.newInstance(); + }); + } + + + @Test + void mapOfferToDTO() { + // Arrange + Product product = new Product(); + product.setProductId("12345"); + product.setDataOrigin(Webshop.AMAZON); + product.setAvailable(true); + product.setCurrentPrice(9.99); + product.setDeliveryPrice(2.50); + product.setMerchant("Seller1"); + + Offer offer = new Offer(); + offer.setOfferId("68735"); + offer.setLastUpdate("2020-07-07"); + offer.setSourceProduct(product); + offer.setTargetProduct(product); + + // Act + OfferDTO dto = OfferMapper.mapOfferToDTO(offer); + + // Assert + assertEquals("68735", dto.getOfferId()); + assertEquals("2020-07-07", dto.getLastUpdate()); + + } + + } diff --git a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java index bb16c4b..5982b83 100644 --- a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java +++ b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java @@ -13,7 +13,7 @@ import de.rwu.easydrop.exception.InvalidOfferException; import de.rwu.easydrop.model.Offer; -public class OfferValidatorTest { +class OfferValidatorTest { @Test void validate_Offer_ValidProduct_NoExceptionThrown() { diff --git a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java index 70bf52a..62ef077 100644 --- a/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java +++ b/src/test/java/de/rwu/easydrop/service/writer/OfferWriterTest.java @@ -16,7 +16,7 @@ import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.Product; import de.rwu.easydrop.model.Webshop; -public class OfferWriterTest { +class OfferWriterTest { @Mock private OfferDTO offerDTO; From 9a9dfe92604a48b4fc105e3140862e623025ce00 Mon Sep 17 00:00:00 2001 From: Alexander Maier Date: Tue, 27 Jun 2023 19:54:58 +0200 Subject: [PATCH 42/49] checkstyle + added new folder for processing tests --- .../de/rwu/easydrop/service/mapping/OfferMapperTest.java | 1 - .../rwu/easydrop/service/processing/OfferIdentifierTest.java | 5 +++++ .../easydrop/service/processing/OfferProvisionerTest.java | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java create mode 100644 src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java diff --git a/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java b/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java index 099d63c..178588d 100644 --- a/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java +++ b/src/test/java/de/rwu/easydrop/service/mapping/OfferMapperTest.java @@ -59,5 +59,4 @@ class OfferMapperTest { } - } diff --git a/src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java b/src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java new file mode 100644 index 0000000..cde6ca6 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java @@ -0,0 +1,5 @@ +package de.rwu.easydrop.service.processing; + +public class OfferIdentifierTest { + +} diff --git a/src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java b/src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java new file mode 100644 index 0000000..c3f2fd9 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java @@ -0,0 +1,5 @@ +package de.rwu.easydrop.service.processing; + +public class OfferProvisionerTest { + +} From a2337ed3ad31ad2bccd81b17d40988bf38d20d31 Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Wed, 28 Jun 2023 00:38:02 +0200 Subject: [PATCH 43/49] #75 Added transaction logic --- src/main/java/de/rwu/easydrop/core/Core.java | 13 +- .../connector/OfferPersistenceInterface.java | 25 +- .../ProductPersistenceInterface.java | 4 +- .../data/connector/SQLiteConnector.java | 244 ++++++++++++++++-- .../TransactionPersistenceInterface.java | 32 +++ .../exception/InvalidOfferException.java | 5 + .../InvalidTransactionException.java | 27 ++ .../processing/TransactionHandler.java | 47 ++++ .../validation/TransactionValidator.java | 42 +++ .../service/writer/TransactionWriter.java | 33 +++ 10 files changed, 439 insertions(+), 33 deletions(-) create mode 100644 src/main/java/de/rwu/easydrop/data/connector/TransactionPersistenceInterface.java create mode 100644 src/main/java/de/rwu/easydrop/exception/InvalidTransactionException.java create mode 100644 src/main/java/de/rwu/easydrop/service/processing/TransactionHandler.java create mode 100644 src/main/java/de/rwu/easydrop/service/validation/TransactionValidator.java create mode 100644 src/main/java/de/rwu/easydrop/service/writer/TransactionWriter.java diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java index a33c14e..6e6111b 100644 --- a/src/main/java/de/rwu/easydrop/core/Core.java +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -9,13 +9,17 @@ import org.slf4j.LoggerFactory; import org.sqlite.SQLiteDataSource; import de.rwu.easydrop.api.client.DataSourceFactory; +import de.rwu.easydrop.api.dto.OfferDTO; import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.data.connector.ProductPersistenceInterface; import de.rwu.easydrop.data.connector.SQLiteConnector; +import de.rwu.easydrop.data.connector.TransactionPersistenceInterface; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.service.mapping.OfferMapper; import de.rwu.easydrop.service.processing.OfferIdentifier; import de.rwu.easydrop.service.processing.OfferProvisioner; +import de.rwu.easydrop.service.processing.TransactionHandler; import de.rwu.easydrop.service.retriever.CatalogueRetriever; import de.rwu.easydrop.service.retriever.ProductRetriever; import de.rwu.easydrop.service.writer.CatalogueWriter; @@ -57,6 +61,7 @@ public final class Core { ProductRetriever retriever = new ProductRetriever(dataSourceFactory, pdb); CatalogueRetriever catRetriever = new CatalogueRetriever(pConfig, retriever); CatalogueWriter catWriter = new CatalogueWriter(pdb); + TransactionPersistenceInterface tpi = new SQLiteConnector(new SQLiteDataSource()); LOGGER.info("Loading catalogues"); catRetriever.loadCatalogues(); @@ -70,8 +75,12 @@ public final class Core { provis.runProvisioner(identifiedOffers); LOGGER.info("Creating transactions"); - // Transaction logic! + TransactionHandler txHandler = new TransactionHandler(tpi); + for (OfferDTO o : odb.getOffers()) { + txHandler.turnOfferToTransaction(OfferMapper.mapOfferFromDTO(o)); + } - LOGGER.info("Done!"); + tpi.outputTransactionsToLog(); + tpi.outputSummaryToLog(); } } diff --git a/src/main/java/de/rwu/easydrop/data/connector/OfferPersistenceInterface.java b/src/main/java/de/rwu/easydrop/data/connector/OfferPersistenceInterface.java index 5d2284b..d0f04d8 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/OfferPersistenceInterface.java +++ b/src/main/java/de/rwu/easydrop/data/connector/OfferPersistenceInterface.java @@ -1,7 +1,14 @@ package de.rwu.easydrop.data.connector; +import java.util.List; + import de.rwu.easydrop.api.dto.OfferDTO; +/** + * Interface to offer persistence. + * + * @since 0.3.0 + */ public interface OfferPersistenceInterface { /** * Writes a ProductDTO to persistence. @@ -19,7 +26,21 @@ public interface OfferPersistenceInterface { OfferDTO getOfferDTOById(String offerId); /** - * Deletes all data from persistence. + * Gets all offerDTOs from persistence. + * + * @return offerDTOs */ - void clearData(); + List getOffers(); + + /** + * Deletes all offer data from persistence. + */ + void clearOfferData(); + + /** + * Deletes an offer from persistence. + * + * @param offerId + */ + void deleteOfferById(String offerId); } diff --git a/src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java b/src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java index b5a1c1a..45ec2bd 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java +++ b/src/main/java/de/rwu/easydrop/data/connector/ProductPersistenceInterface.java @@ -24,7 +24,7 @@ public interface ProductPersistenceInterface { ProductDTO getProductDTOById(String productId); /** - * Deletes all data from persistence. + * Deletes all product data from persistence. */ - void clearData(); + void clearProductData(); } diff --git a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java index 4a9e492..c38d63b 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java +++ b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java @@ -5,13 +5,19 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sqlite.SQLiteDataSource; import de.rwu.easydrop.api.dto.OfferDTO; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.api.dto.TransactionDTO; import de.rwu.easydrop.exception.PersistenceException; import de.rwu.easydrop.model.Webshop; +import de.rwu.easydrop.util.FormattingUtil; /** * Allows connecting to a SQLite Database. @@ -19,7 +25,18 @@ import de.rwu.easydrop.model.Webshop; * @since 0.2.0 */ public final class SQLiteConnector implements - ProductPersistenceInterface, OfferPersistenceInterface { + ProductPersistenceInterface, OfferPersistenceInterface, + TransactionPersistenceInterface { + /** + * Base for calculating percentages. + */ + private static final int PERCENT = 100; + + /** + * Logging instance. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(SQLiteConnector.class); + /** * SQLite Database. */ @@ -41,6 +58,11 @@ public final class SQLiteConnector implements */ private static final String LAST_UPDATE_COL_NAME = "lastUpdate"; + /** + * Name of 'offerId' column. + */ + private static final String OFFERID_COL_NAME = "offerId"; + /** * Creates instance. * @@ -89,6 +111,16 @@ public final class SQLiteConnector implements + ")"); createOffers.close(); + Statement createTransactions = connection.createStatement(); + createTransactions.execute( + "CREATE TABLE IF NOT EXISTS transactions (" + + "offerId TEXT, " + + "earnings REAL, " + + "volume REAL, " + + "transactionTime TEXT" + + ")"); + createTransactions.close(); + // Close the connection connection.close(); } catch (SQLException e) { @@ -105,7 +137,7 @@ public final class SQLiteConnector implements String query = "INSERT INTO products (" + "dataOrigin, productId, currentPrice, merchant, " + "deliveryPrice, available, lastUpdate" - + ") VALUES (" + + ") VALUES ( " + "?, ?, ?, ?, ?, ?, ?" + ")"; @@ -123,7 +155,8 @@ public final class SQLiteConnector implements statement.executeUpdate(); } catch (SQLException e) { - throw new PersistenceException("Something went wrong while saving to SQLite", e); + throw new PersistenceException( + "Something went wrong while saving product to SQLite", e); } } @@ -156,7 +189,8 @@ public final class SQLiteConnector implements } } } catch (SQLException e) { - throw new PersistenceException("Something went wrong while reading from SQLite"); + throw new PersistenceException( + "Something went wrong while reading product from SQLite"); } return dto; @@ -168,16 +202,9 @@ public final class SQLiteConnector implements * @throws SQLException */ public void clearData() { - try (Connection connection = db.getConnection(); - Statement statement = connection.createStatement()) { - - String productsQuery = "DELETE FROM products;"; - String offersQuery = "DELETE FROM offers;"; - statement.executeUpdate(productsQuery); - statement.executeUpdate(offersQuery); - } catch (SQLException e) { - throw new PersistenceException("Something went wrong while clearing the database", e); - } + clearProductData(); + clearOfferData(); + clearTXData(); } /** @@ -202,17 +229,18 @@ public final class SQLiteConnector implements ProductDTO targetProduct = dto.getTargetProduct(); statement.setString(++index, dto.getOfferId()); - statement.setString(++index, sourceProduct.getProductId()); statement.setString(++index, sourceProduct.getDataOrigin().toString()); + statement.setString(++index, sourceProduct.getProductId()); statement.setDouble(++index, sourceProduct.getCurrentPrice()); - statement.setString(++index, targetProduct.getProductId()); statement.setString(++index, targetProduct.getDataOrigin().toString()); + statement.setString(++index, targetProduct.getProductId()); statement.setDouble(++index, targetProduct.getCurrentPrice()); statement.setString(++index, dto.getLastUpdate()); statement.executeUpdate(); } catch (SQLException e) { - throw new PersistenceException("Something went wrong while saving to SQLite", e); + throw new PersistenceException( + "Something went wrong while saving offer to SQLite", e); } } @@ -234,24 +262,186 @@ public final class SQLiteConnector implements try (ResultSet resultSet = statement.executeQuery()) { if (resultSet.next()) { dto = new OfferDTO(); - ProductDTO srcProduct = new ProductDTO( - resultSet.getString("sourceId"), - Webshop.fromString(resultSet.getString("sourceWebshop"))); - srcProduct.setCurrentPrice(resultSet.getDouble("sourcePrice")); - ProductDTO targetProduct = new ProductDTO( - resultSet.getString("targetId"), - Webshop.fromString(resultSet.getString("targetWebshop"))); - srcProduct.setCurrentPrice(resultSet.getDouble("targetPrice")); - dto.setOfferId(resultSet.getString("offerId")); + ProductDTO srcProduct = getProductDTOById(resultSet.getString("sourceId")); + ProductDTO targetProduct = getProductDTOById(resultSet.getString("targetId")); + dto.setOfferId(resultSet.getString(OFFERID_COL_NAME)); dto.setSourceProduct(srcProduct); dto.setTargetProduct(targetProduct); dto.setLastUpdate(resultSet.getString(LAST_UPDATE_COL_NAME)); } } } catch (SQLException e) { - throw new PersistenceException("Something went wrong while reading from SQLite", e); + throw new PersistenceException( + "Something went wrong while reading offer from SQLite", e); } return dto; } + + @Override + public void writeTX(final TransactionDTO dto) { + String query = "INSERT INTO transactions (" + + "offerId, volume, earnings, transactionTime" + + ") VALUES (" + + "?, ?, ?, ?" + + ")"; + + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + int index = 0; + + statement.setString(++index, dto.getOfferId()); + statement.setDouble(++index, dto.getVolume()); + statement.setDouble(++index, dto.getEarnings()); + statement.setString(++index, dto.getTransactionTime()); + + statement.executeUpdate(); + } catch (SQLException e) { + throw new PersistenceException( + "Something went wrong while saving transaction to SQLite", e); + } + } + + @Override + public void outputTransactionsToLog() { + String query = "SELECT * FROM transactions t " + + "LEFT JOIN offers o ON t.offerId = o.offerId " + + "ORDER BY transactionTime ASC"; + StringBuilder sb = new StringBuilder(); + int index = 0; + sb.append("Transaction History:"); + + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + sb.append("\n"); + sb.append(String.format("%3d", ++index)); + sb.append(String.format(" - %s - ", resultSet.getString("transactionTime"))); + sb.append(String.format("+%s (%s) - %s", + FormattingUtil.formatEuro(resultSet.getDouble("earnings")), + FormattingUtil.formatEuro(resultSet.getDouble("volume")), + resultSet.getString(OFFERID_COL_NAME))); + } + } + } catch (SQLException e) { + throw new PersistenceException( + "Something went wrong while reading transaction from SQLite", e); + } + + String logString = sb.toString(); + LOGGER.info(logString); + } + + @Override + public void outputSummaryToLog() { + String query = "SELECT SUM(earnings) AS earnings, SUM(volume) AS volume FROM transactions;"; + StringBuilder sb = new StringBuilder(); + sb.append("Summary:\n"); + + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + double earnings = resultSet.getDouble("earnings"); + double volume = resultSet.getDouble("volume"); + String avgMargin = String.valueOf( + Math.round(earnings / volume * PERCENT)) + "%"; + + String earningsFormatted = FormattingUtil.formatEuro(earnings); + String volumeFormatted = FormattingUtil.formatEuro(volume); + + sb.append(String.format("Total earnings: %s, ", earningsFormatted)); + sb.append(String.format("total volume: %s ", volumeFormatted)); + sb.append(String.format("(average margin %s)", avgMargin)); + } + } + } catch (SQLException e) { + throw new PersistenceException( + "Something went wrong while reading transaction summary from SQLite", e); + } + + String logString = sb.toString(); + LOGGER.info(logString); + } + + @Override + public void clearTXData() { + flushTable("transactions"); + } + + @Override + public void clearOfferData() { + flushTable("offers"); + } + + @Override + public void clearProductData() { + flushTable("products"); + } + + /** + * Flushes all data from the specified table. + * + * @param table + */ + private void flushTable(final String table) { + try (Connection connection = db.getConnection(); + Statement statement = connection.createStatement()) { + if (table.matches("[\\w]+")) { + String query = "DELETE FROM " + table + ";"; + statement.executeUpdate(query); + } else { + throw new PersistenceException("Table name contains illegal characters"); + } + } catch (SQLException e) { + throw new PersistenceException("Something went wrong while clearing the database", e); + } + } + + @Override + public void deleteOfferById(final String offerId) { + String query = "DELETE FROM offers WHERE offerID = ?;"; + + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + statement.setString(1, offerId); + + statement.executeUpdate(); + } catch (SQLException e) { + throw new PersistenceException( + "Something went wrong while deleting offer from SQLite", e); + } + } + + @Override + public List getOffers() { + List list = new ArrayList<>(); + String query = "SELECT * FROM offers"; + + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + OfferDTO dto = new OfferDTO(); + ProductDTO srcProduct = getProductDTOById(resultSet.getString("sourceId")); + ProductDTO targetProduct = getProductDTOById(resultSet.getString("targetId")); + dto.setOfferId(resultSet.getString(OFFERID_COL_NAME)); + dto.setSourceProduct(srcProduct); + dto.setTargetProduct(targetProduct); + dto.setLastUpdate(resultSet.getString(LAST_UPDATE_COL_NAME)); + + list.add(dto); + } + } + } catch (SQLException e) { + throw new PersistenceException( + "Something went wrong while reading offers from SQLite", e); + } + + return list; + } } diff --git a/src/main/java/de/rwu/easydrop/data/connector/TransactionPersistenceInterface.java b/src/main/java/de/rwu/easydrop/data/connector/TransactionPersistenceInterface.java new file mode 100644 index 0000000..8a930a3 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/data/connector/TransactionPersistenceInterface.java @@ -0,0 +1,32 @@ +package de.rwu.easydrop.data.connector; + +import de.rwu.easydrop.api.dto.TransactionDTO; + +/** + * Persistence interface for transactions. + * + * @since 0.3.0 + */ +public interface TransactionPersistenceInterface { + /** + * Writes a ProductDTO to persistence. + * + * @param dto + */ + void writeTX(TransactionDTO dto); + + /** + * Writes transactions to log. + */ + void outputTransactionsToLog(); + + /** + * Writes transaction summary (total volume and earnings) to log. + */ + void outputSummaryToLog(); + + /** + * Deletes all transaction data from persistence. + */ + void clearTXData(); +} diff --git a/src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java b/src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java index f4d2c0b..aefe676 100644 --- a/src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java +++ b/src/main/java/de/rwu/easydrop/exception/InvalidOfferException.java @@ -1,5 +1,10 @@ package de.rwu.easydrop.exception; +/** + * Exception that signifies the data of an Offer are invalid. + * + * @since 0.3.0 + */ public class InvalidOfferException extends RuntimeException { /** * Throws an exception that signifies the data of an Offer are invalid. diff --git a/src/main/java/de/rwu/easydrop/exception/InvalidTransactionException.java b/src/main/java/de/rwu/easydrop/exception/InvalidTransactionException.java new file mode 100644 index 0000000..66442a4 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/exception/InvalidTransactionException.java @@ -0,0 +1,27 @@ +package de.rwu.easydrop.exception; + +/** + * Exception that signifies the data of a Transaction are invalid. + * + * @since 0.3.0 + */ +public class InvalidTransactionException extends RuntimeException { + /** + * Throws an exception that signifies the data of an Offer are invalid. + * + * @param message + */ + public InvalidTransactionException(final String message) { + super(message); + } + + /** + * Throws an exception that signifies the data of an Offer are invalid. + * + * @param message + * @param cause + */ + public InvalidTransactionException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/de/rwu/easydrop/service/processing/TransactionHandler.java b/src/main/java/de/rwu/easydrop/service/processing/TransactionHandler.java new file mode 100644 index 0000000..928625c --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/processing/TransactionHandler.java @@ -0,0 +1,47 @@ +package de.rwu.easydrop.service.processing; + +import de.rwu.easydrop.api.dto.TransactionDTO; +import de.rwu.easydrop.data.connector.TransactionPersistenceInterface; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Transaction; +import de.rwu.easydrop.service.mapping.TransactionMapper; +import de.rwu.easydrop.util.Timestamp; + +/** + * Handles transactions. + * + * @since 0.3.0 + */ +public class TransactionHandler { + /** + * Transaction persistence. + */ + private TransactionPersistenceInterface txPersistence; + + /** + * Creates new transaction handler. + * + * @param txdb transaction persistence + */ + public TransactionHandler(final TransactionPersistenceInterface txdb) { + this.txPersistence = txdb; + } + + /** + * Creates transaction from offer. + * + * @param offer Offer + */ + public void turnOfferToTransaction(final Offer offer) { + Transaction tx = new Transaction(); + tx.setOfferId(offer.getOfferId()); + tx.setVolume(offer.getTargetProduct().getCurrentPrice()); + tx.setEarnings(offer.getTargetProduct().getCurrentPrice() + - offer.getSourceProduct().getCurrentPrice()); + tx.setTransactionTime(Timestamp.now()); + + // Write transaction to persistence + TransactionDTO txDTO = TransactionMapper.mapTXToDTO(tx); + txPersistence.writeTX(txDTO); + } +} diff --git a/src/main/java/de/rwu/easydrop/service/validation/TransactionValidator.java b/src/main/java/de/rwu/easydrop/service/validation/TransactionValidator.java new file mode 100644 index 0000000..b73e435 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/validation/TransactionValidator.java @@ -0,0 +1,42 @@ +package de.rwu.easydrop.service.validation; + +import de.rwu.easydrop.exception.InvalidTransactionException; +import de.rwu.easydrop.model.Transaction; + +/** + * Validates transactions. + * + * @since 0.3.0 + */ +public final class TransactionValidator { + /** + * Private constructor to prevent unwanted instantiation. + * + * @throws UnsupportedOperationException always + */ + private TransactionValidator() throws UnsupportedOperationException { + throw new UnsupportedOperationException("This is a validator class, don't instantiate it."); + } + + /** + * Makes sure a transaction does not contain invalid information. + * + * @param tx the Transaction + */ + public static void validate(final Transaction tx) { + try { + if (tx.getOfferId().equals("")) { + throw new InvalidTransactionException("Offer ID cannot be empty"); + } + if (tx.getEarnings() == 0) { + throw new InvalidTransactionException("Earnings can't be zero"); + } + if (tx.getVolume() == 0) { + throw new InvalidTransactionException("Volume can't be zero"); + } + } catch (NullPointerException e) { + throw new InvalidTransactionException( + "Required information is missing in the transaction", e); + } + } +} diff --git a/src/main/java/de/rwu/easydrop/service/writer/TransactionWriter.java b/src/main/java/de/rwu/easydrop/service/writer/TransactionWriter.java new file mode 100644 index 0000000..ff649c0 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/service/writer/TransactionWriter.java @@ -0,0 +1,33 @@ +package de.rwu.easydrop.service.writer; + +import de.rwu.easydrop.api.dto.TransactionDTO; +import de.rwu.easydrop.data.connector.TransactionPersistenceInterface; +import de.rwu.easydrop.model.Transaction; +import de.rwu.easydrop.service.mapping.TransactionMapper; +import de.rwu.easydrop.service.validation.TransactionValidator; + +public class TransactionWriter { + /** + * Persistence. + */ + private TransactionPersistenceInterface persistence; + + /** + * @param newPersistence the persistence to set + */ + public TransactionWriter(final TransactionPersistenceInterface newPersistence) { + this.persistence = newPersistence; + } + + /** + * Validates and saves a transaction to persistence. + * + * @param tx Transaction + */ + public void writeTXToPersistence(final Transaction tx) { + TransactionDTO dto = TransactionMapper.mapTXToDTO(tx); + TransactionValidator.validate(tx); + + persistence.writeTX(dto); + } +} From bced347354fa3c94ef48501dcda77480a82d3f87 Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Wed, 28 Jun 2023 00:38:15 +0200 Subject: [PATCH 44/49] Added persistence to local mapping --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index fe6a261..e9048c1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,3 +9,4 @@ services: image: easydrop:0.3.0-SNAPSHOT volumes: - ./config:/config + - ./persistence.db:/persistence.db From 187db7e6f501ad48de19c6396acb77503ba5e995 Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Wed, 28 Jun 2023 00:44:07 +0200 Subject: [PATCH 45/49] Patched potential security risk --- .../data/connector/SQLiteConnector.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java index c38d63b..fff1cc8 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java +++ b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java @@ -369,33 +369,28 @@ public final class SQLiteConnector implements @Override public void clearTXData() { - flushTable("transactions"); + runDeletionQuery("DELETE FROM transactions;"); } @Override public void clearOfferData() { - flushTable("offers"); + runDeletionQuery("DELETE FROM offers;"); } @Override public void clearProductData() { - flushTable("products"); + runDeletionQuery("DELETE FROM products;"); } /** - * Flushes all data from the specified table. + * Flushes all data using the specified query. * - * @param table + * @param query */ - private void flushTable(final String table) { + private void runDeletionQuery(final String query) { try (Connection connection = db.getConnection(); Statement statement = connection.createStatement()) { - if (table.matches("[\\w]+")) { - String query = "DELETE FROM " + table + ";"; - statement.executeUpdate(query); - } else { - throw new PersistenceException("Table name contains illegal characters"); - } + statement.executeUpdate(query); } catch (SQLException e) { throw new PersistenceException("Something went wrong while clearing the database", e); } From 0613e261e15cedd5a13dd99c09e98977d7fe0394 Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Wed, 28 Jun 2023 02:56:54 +0200 Subject: [PATCH 46/49] Added abstraction layer to move out config --- .../easydrop/api/client/PurchaserFactory.java | 55 +++++++++++++++++++ .../easydrop/api/client/SellerFactory.java | 55 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/main/java/de/rwu/easydrop/api/client/PurchaserFactory.java create mode 100644 src/main/java/de/rwu/easydrop/api/client/SellerFactory.java diff --git a/src/main/java/de/rwu/easydrop/api/client/PurchaserFactory.java b/src/main/java/de/rwu/easydrop/api/client/PurchaserFactory.java new file mode 100644 index 0000000..24242e4 --- /dev/null +++ b/src/main/java/de/rwu/easydrop/api/client/PurchaserFactory.java @@ -0,0 +1,55 @@ +package de.rwu.easydrop.api.client; + +import javax.naming.ConfigurationException; + +import de.rwu.easydrop.util.Config; + +/** + * Factory for Buyer API accessors. + * + * @since 0.3.0 + */ +public class PurchaserFactory { + + /** + * 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 PurchaserFactory(final Config newConfig) throws ConfigurationException { + this.setConfig(newConfig); + } + + /** + * Creates an Amazon purchaser. + * + * @return AmazonPurchaser + */ + public AmazonPurchaser createAmazonPurchaser() { + String apiUrl = config.getProperty("AMAZON_API_URL"); + String apiKey = config.getProperty("AMAZON_API_KEY"); + return new AmazonPurchaser(apiUrl, apiKey); + } + + /** + * Creates an eBay purchaser. + * + * @return EbayPurchaser + */ + public EbayPurchaser createEbayPurchaser() { + String apiUrl = config.getProperty("EBAY_API_URL"); + String apiKey = config.getProperty("EBAY_API_KEY"); + return new EbayPurchaser(apiUrl, apiKey); + } +} diff --git a/src/main/java/de/rwu/easydrop/api/client/SellerFactory.java b/src/main/java/de/rwu/easydrop/api/client/SellerFactory.java new file mode 100644 index 0000000..df64a3f --- /dev/null +++ b/src/main/java/de/rwu/easydrop/api/client/SellerFactory.java @@ -0,0 +1,55 @@ +package de.rwu.easydrop.api.client; + +import javax.naming.ConfigurationException; + +import de.rwu.easydrop.util.Config; + +/** + * Factory for Sales API accessors. + * + * @since 0.3.0 + */ +public class SellerFactory { + + /** + * 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 SellerFactory(final Config newConfig) throws ConfigurationException { + this.setConfig(newConfig); + } + + /** + * Creates an Amazon Seller. + * + * @return AmazonSeller + */ + public AmazonSeller createAmazonSeller() { + String apiUrl = config.getProperty("AMAZON_API_URL"); + String apiKey = config.getProperty("AMAZON_API_KEY"); + return new AmazonSeller(apiUrl, apiKey); + } + + /** + * Creates an eBay Seller. + * + * @return EbaySeller + */ + public EbaySeller createEbaySeller() { + String apiUrl = config.getProperty("EBAY_API_URL"); + String apiKey = config.getProperty("EBAY_API_KEY"); + return new EbaySeller(apiUrl, apiKey); + } +} From 6fe29e4319d4a10cf187495dadd96484147e4aaf Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Wed, 28 Jun 2023 02:57:13 +0200 Subject: [PATCH 47/49] Added missing buy logic --- src/main/java/de/rwu/easydrop/core/Core.java | 26 ++++--- .../data/connector/SQLiteConnector.java | 7 +- .../service/processing/OfferProvisioner.java | 69 +++++++++++++++---- 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/core/Core.java b/src/main/java/de/rwu/easydrop/core/Core.java index 6e6111b..45f01ef 100644 --- a/src/main/java/de/rwu/easydrop/core/Core.java +++ b/src/main/java/de/rwu/easydrop/core/Core.java @@ -9,6 +9,8 @@ import org.slf4j.LoggerFactory; import org.sqlite.SQLiteDataSource; import de.rwu.easydrop.api.client.DataSourceFactory; +import de.rwu.easydrop.api.client.PurchaserFactory; +import de.rwu.easydrop.api.client.SellerFactory; import de.rwu.easydrop.api.dto.OfferDTO; import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.data.connector.ProductPersistenceInterface; @@ -56,12 +58,16 @@ public final class Core { LOGGER.info("Preparing..."); DataSourceFactory dataSourceFactory = new DataSourceFactory(config); - ProductPersistenceInterface pdb = new SQLiteConnector(new SQLiteDataSource()); - OfferPersistenceInterface odb = new SQLiteConnector(new SQLiteDataSource()); - ProductRetriever retriever = new ProductRetriever(dataSourceFactory, pdb); + SellerFactory sellerFactory = new SellerFactory(config); + PurchaserFactory purchaserFactory = new PurchaserFactory(config); + + ProductPersistenceInterface productDB = new SQLiteConnector(new SQLiteDataSource()); + OfferPersistenceInterface offerDB = new SQLiteConnector(new SQLiteDataSource()); + TransactionPersistenceInterface txDB = new SQLiteConnector(new SQLiteDataSource()); + + ProductRetriever retriever = new ProductRetriever(dataSourceFactory, productDB); CatalogueRetriever catRetriever = new CatalogueRetriever(pConfig, retriever); - CatalogueWriter catWriter = new CatalogueWriter(pdb); - TransactionPersistenceInterface tpi = new SQLiteConnector(new SQLiteDataSource()); + CatalogueWriter catWriter = new CatalogueWriter(productDB); LOGGER.info("Loading catalogues"); catRetriever.loadCatalogues(); @@ -70,17 +76,17 @@ public final class Core { LOGGER.info("Creating offers"); OfferIdentifier ident = new OfferIdentifier(); + OfferProvisioner provis = new OfferProvisioner(offerDB, sellerFactory, purchaserFactory); List identifiedOffers = ident.runIdentifier(pCats); - OfferProvisioner provis = new OfferProvisioner(odb); provis.runProvisioner(identifiedOffers); LOGGER.info("Creating transactions"); - TransactionHandler txHandler = new TransactionHandler(tpi); - for (OfferDTO o : odb.getOffers()) { + TransactionHandler txHandler = new TransactionHandler(txDB); + for (OfferDTO o : offerDB.getOffers()) { txHandler.turnOfferToTransaction(OfferMapper.mapOfferFromDTO(o)); } - tpi.outputTransactionsToLog(); - tpi.outputSummaryToLog(); + txDB.outputTransactionsToLog(); + txDB.outputSummaryToLog(); } } diff --git a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java index fff1cc8..3b110b5 100644 --- a/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java +++ b/src/main/java/de/rwu/easydrop/data/connector/SQLiteConnector.java @@ -319,9 +319,12 @@ public final class SQLiteConnector implements sb.append("\n"); sb.append(String.format("%3d", ++index)); sb.append(String.format(" - %s - ", resultSet.getString("transactionTime"))); - sb.append(String.format("+%s (%s) - %s", + sb.append(String.format("+%s (%s) - ", FormattingUtil.formatEuro(resultSet.getDouble("earnings")), - FormattingUtil.formatEuro(resultSet.getDouble("volume")), + FormattingUtil.formatEuro(resultSet.getDouble("volume")))); + sb.append(String.format("[%s to %s] %s", + resultSet.getString("sourceWebshop"), + resultSet.getString("targetWebshop"), resultSet.getString(OFFERID_COL_NAME))); } } diff --git a/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java index 5c1847e..384fdc7 100644 --- a/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java @@ -2,21 +2,27 @@ package de.rwu.easydrop.service.processing; import java.util.List; +import de.rwu.easydrop.api.client.AmazonPurchaser; import de.rwu.easydrop.api.client.AmazonSeller; +import de.rwu.easydrop.api.client.EbayPurchaser; import de.rwu.easydrop.api.client.EbaySeller; +import de.rwu.easydrop.api.client.PurchaserFactory; +import de.rwu.easydrop.api.client.SellerFactory; import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.model.Offer; import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.service.mapping.ProductMapper; import de.rwu.easydrop.service.writer.OfferWriter; -import de.rwu.easydrop.util.Config; import de.rwu.easydrop.util.FormattingUtil; +import lombok.Data; +/** + * Offer provisioner. + * + * @since 0.3.0 + */ +@Data public class OfferProvisioner { - /** - * Config. - */ - private Config config; /** * Writes offers into persistence. */ @@ -30,7 +36,20 @@ public class OfferProvisioner { * Is the API for selling products on Ebay. */ private EbaySeller ebaySeller; + /** + * Is the API for buying products on Amazon. + */ + private AmazonPurchaser amazonPurchaser; + /** + * Is the API for buying products on Ebay. + */ + private EbayPurchaser ebayPurchaser; + /** + * Puts up the sell order. + * + * @param offer + */ private void toSeller(final Offer offer) throws IllegalArgumentException { if (offer.getTargetProduct().getDataOrigin() == Webshop.EBAY) { this.ebaySeller.sellProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); @@ -43,20 +62,41 @@ public class OfferProvisioner { } + /** + * Puts up the buy order. + * + * @param offer + */ + private void toBuyer(final Offer offer) throws IllegalArgumentException { + if (offer.getSourceProduct().getDataOrigin() == Webshop.EBAY) { + this.ebayPurchaser.purchaseProduct( + ProductMapper.mapProductToDTO(offer.getSourceProduct())); + + } else if (offer.getTargetProduct().getDataOrigin().equals(Webshop.AMAZON)) { + this.amazonPurchaser.purchaseProduct( + ProductMapper.mapProductToDTO(offer.getSourceProduct())); + } else { + throw new IllegalArgumentException("Unsupported target plattform"); + } + + } + /** * Is the class for placing orders on a target platform. * - * @param db Persistence Interface + * @param db Persistence Interface + * @param newSellerFactory Seller Factory + * @param newPurchaserFactory Purchaser Factory */ - public OfferProvisioner(final OfferPersistenceInterface db) { + public OfferProvisioner( + final OfferPersistenceInterface db, + final SellerFactory newSellerFactory, + final PurchaserFactory newPurchaserFactory) { this.offerWriter = new OfferWriter(db); - this.config = Config.getInstance(); - this.amazonSeller = new AmazonSeller( - config.getProperty("AMAZON_API_URL"), - config.getProperty("AMAZON_API_KEY")); - this.ebaySeller = new EbaySeller( - config.getProperty("EBAY_API_URL"), - config.getProperty("EBAY_API_KEY")); + this.ebaySeller = newSellerFactory.createEbaySeller(); + this.amazonSeller = newSellerFactory.createAmazonSeller(); + this.ebayPurchaser = newPurchaserFactory.createEbayPurchaser(); + this.amazonPurchaser = newPurchaserFactory.createAmazonPurchaser(); } /** @@ -74,6 +114,7 @@ public class OfferProvisioner { + newOffer.getTargetProduct().getProductId()); this.toSeller(newOffer); + this.toBuyer(newOffer); newOffer.setOfferId(newOfferId); offerWriter.writeOfferToPersistence(newOffer); } From f32b7fc1c7904bc251467bb76e0cc40284273f06 Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Wed, 28 Jun 2023 04:31:15 +0200 Subject: [PATCH 48/49] Cleanup --- .../service/processing/OfferIdentifier.java | 32 +++++++++++-------- .../service/processing/OfferProvisioner.java | 27 ++++++---------- .../service/retriever/ProductRetriever.java | 12 +++---- 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/main/java/de/rwu/easydrop/service/processing/OfferIdentifier.java b/src/main/java/de/rwu/easydrop/service/processing/OfferIdentifier.java index 629d594..52e8357 100644 --- a/src/main/java/de/rwu/easydrop/service/processing/OfferIdentifier.java +++ b/src/main/java/de/rwu/easydrop/service/processing/OfferIdentifier.java @@ -33,21 +33,25 @@ public class OfferIdentifier { for (ProductCatalogue pCat : pCats) { // Call price finder for all catalogue - ProductPair pair = getHighestMarginProducts(pCat); - Offer possibleOffer = new Offer(); - possibleOffer.setLastUpdate(Timestamp.now()); - possibleOffer.setSourceProduct(pair.getProduct1()); - possibleOffer.setTargetProduct(pair.getProduct2()); - identifiedOffers.add(possibleOffer); + try { + ProductPair pair = getHighestMarginProducts(pCat); + Offer possibleOffer = new Offer(); + possibleOffer.setLastUpdate(Timestamp.now()); + possibleOffer.setSourceProduct(pair.getProduct1()); + possibleOffer.setTargetProduct(pair.getProduct2()); + identifiedOffers.add(possibleOffer); - double margin = pair.getProduct2().getCurrentPrice() - - pair.getProduct1().getCurrentPrice(); - String marginFormatted = FormattingUtil.formatEuro(margin); - LOGGER.info("\n Identified Offer: {} ({} to {}) with margin {} ", - pCat.getProductName(), - pair.getProduct1().getDataOrigin(), - pair.getProduct2().getDataOrigin(), - marginFormatted); + double margin = pair.getProduct2().getCurrentPrice() + - pair.getProduct1().getCurrentPrice(); + String marginFormatted = FormattingUtil.formatEuro(margin); + LOGGER.info("\n Identified Offer: {} ({} to {}) with margin {} ", + pCat.getProductName(), + pair.getProduct1().getDataOrigin(), + pair.getProduct2().getDataOrigin(), + marginFormatted); + } catch (InvalidOfferException e) { + // Don't include offer if deemed invalid + } } return identifiedOffers; diff --git a/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java index 384fdc7..de6e4eb 100644 --- a/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java +++ b/src/main/java/de/rwu/easydrop/service/processing/OfferProvisioner.java @@ -10,7 +10,6 @@ import de.rwu.easydrop.api.client.PurchaserFactory; import de.rwu.easydrop.api.client.SellerFactory; import de.rwu.easydrop.data.connector.OfferPersistenceInterface; import de.rwu.easydrop.model.Offer; -import de.rwu.easydrop.model.Webshop; import de.rwu.easydrop.service.mapping.ProductMapper; import de.rwu.easydrop.service.writer.OfferWriter; import de.rwu.easydrop.util.FormattingUtil; @@ -51,15 +50,13 @@ public class OfferProvisioner { * @param offer */ private void toSeller(final Offer offer) throws IllegalArgumentException { - if (offer.getTargetProduct().getDataOrigin() == Webshop.EBAY) { - this.ebaySeller.sellProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); - - } else if (offer.getTargetProduct().getDataOrigin().equals(Webshop.AMAZON)) { - this.amazonSeller.sellProduct(ProductMapper.mapProductToDTO(offer.getTargetProduct())); - } else { - throw new IllegalArgumentException("Unsupported target plattform"); + switch (offer.getTargetProduct().getDataOrigin()) { + case EBAY -> this.ebaySeller.sellProduct( + ProductMapper.mapProductToDTO(offer.getTargetProduct())); + case AMAZON -> this.amazonSeller.sellProduct( + ProductMapper.mapProductToDTO(offer.getTargetProduct())); + default -> throw new IllegalArgumentException("Unsupported source plattform"); } - } /** @@ -68,17 +65,13 @@ public class OfferProvisioner { * @param offer */ private void toBuyer(final Offer offer) throws IllegalArgumentException { - if (offer.getSourceProduct().getDataOrigin() == Webshop.EBAY) { - this.ebayPurchaser.purchaseProduct( + switch (offer.getSourceProduct().getDataOrigin()) { + case EBAY -> ebayPurchaser.purchaseProduct( ProductMapper.mapProductToDTO(offer.getSourceProduct())); - - } else if (offer.getTargetProduct().getDataOrigin().equals(Webshop.AMAZON)) { - this.amazonPurchaser.purchaseProduct( + case AMAZON -> amazonPurchaser.purchaseProduct( ProductMapper.mapProductToDTO(offer.getSourceProduct())); - } else { - throw new IllegalArgumentException("Unsupported target plattform"); + default -> throw new IllegalArgumentException("Unsupported target plattform"); } - } /** diff --git a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java index 8e42ea3..e2b4d5f 100644 --- a/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java +++ b/src/main/java/de/rwu/easydrop/service/retriever/ProductRetriever.java @@ -93,13 +93,9 @@ public class ProductRetriever { * @return Product from that data source or null if data source not available */ public Product getProductFromWebshop(final Webshop shop, final String productIdentifier) { - switch (shop) { - case AMAZON: - return getProductFromAmazon(productIdentifier); - case EBAY: - return getProductFromEbay(productIdentifier); - default: - return null; - } + return switch (shop) { + case AMAZON -> getProductFromAmazon(productIdentifier); + case EBAY -> getProductFromEbay(productIdentifier); + }; } } From 44c9e0d9e4c2c3a5347e564b8e683dd809a4c109 Mon Sep 17 00:00:00 2001 From: Marvin Scham Date: Wed, 28 Jun 2023 04:31:26 +0200 Subject: [PATCH 49/49] Added and rewrote tests --- .../api/client/AbstractDataWriterTest.java | 11 + .../client/AmazonProductDataSourceTest.java | 27 +++ .../api/client/PurchaserFactoryTest.java | 63 ++++++ .../api/client/SellerFactoryTest.java | 63 ++++++ .../java/de/rwu/easydrop/core/CoreTest.java | 4 - .../data/connector/SQLiteConnectorTest.java | 194 +++++++++++++++++- .../exception/InvalidOfferExceptionTest.java | 61 ++++++ .../InvalidTransactionExceptionTest.java | 61 ++++++ .../rwu/easydrop/model/ProductPairTest.java | 25 +++ .../de/rwu/easydrop/model/WebshopTest.java | 23 +++ .../mapping/TransactionMapperTest.java | 71 +++++++ .../processing/OfferIdentifierTest.java | 175 +++++++++++++++- .../processing/OfferProvisionerTest.java | 104 +++++++++- .../processing/TransactionHandlerTest.java | 50 +++++ .../retriever/ProductRetrieverTest.java | 47 +++++ .../validation/OfferValidatorTest.java | 37 +++- .../validation/TransactionValidatorTest.java | 70 +++++++ .../service/writer/TransactionWriterTest.java | 63 ++++++ .../rwu/easydrop/util/FormattingUtilTest.java | 14 ++ 19 files changed, 1145 insertions(+), 18 deletions(-) create mode 100644 src/test/java/de/rwu/easydrop/api/client/PurchaserFactoryTest.java create mode 100644 src/test/java/de/rwu/easydrop/api/client/SellerFactoryTest.java delete mode 100644 src/test/java/de/rwu/easydrop/core/CoreTest.java create mode 100644 src/test/java/de/rwu/easydrop/exception/InvalidOfferExceptionTest.java create mode 100644 src/test/java/de/rwu/easydrop/exception/InvalidTransactionExceptionTest.java create mode 100644 src/test/java/de/rwu/easydrop/model/ProductPairTest.java create mode 100644 src/test/java/de/rwu/easydrop/model/WebshopTest.java create mode 100644 src/test/java/de/rwu/easydrop/service/mapping/TransactionMapperTest.java create mode 100644 src/test/java/de/rwu/easydrop/service/processing/TransactionHandlerTest.java create mode 100644 src/test/java/de/rwu/easydrop/service/validation/TransactionValidatorTest.java create mode 100644 src/test/java/de/rwu/easydrop/service/writer/TransactionWriterTest.java diff --git a/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java b/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java index 78c610f..f7a2443 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AbstractDataWriterTest.java @@ -108,4 +108,15 @@ class AbstractDataWriterTest { mockWriter.sendPutRequest(dto, "Purchase"); }); } + + @Test + void sendPutRequest_wrongDataTarget() { + ProductDTO dto = new ProductDTO(demoProductId, Webshop.EBAY); + + DataWriterException e = assertThrows(DataWriterException.class, () -> { + writer.sendPutRequest(dto, demoProductId); + }); + + assertEquals("Product data source and target whateverId API are incompatible.", e.getMessage()); + } } 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 ba3bfa9..14667b3 100644 --- a/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java +++ b/src/test/java/de/rwu/easydrop/api/client/AmazonProductDataSourceTest.java @@ -168,6 +168,33 @@ class AmazonProductDataSourceTest { assertEquals("Nothing found: AMAZON API responded with error code 404", exception.getMessage()); } + @Test + void testGetProductDTOById_emptyResponse() throws IOException { + // Set up the test environment + String mockResponse = ""; + + AmazonProductDataSource dataSource = mock(AmazonProductDataSource.class); + URL mockURL = mock(URL.class); + when(dataSource.createApiUrl(demoProductId)).thenReturn(mockURL); + when(dataSource.buildProductDTO(any(), anyString())).thenCallRealMethod(); + HttpURLConnection mockConnection = mock(HttpURLConnection.class); + when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + when(mockConnection.getInputStream()).thenReturn(new ByteArrayInputStream(mockResponse.getBytes())); + when(dataSource.getProductDTOById(demoProductId)).thenCallRealMethod(); + + // Invoke the method + ProductDTO result = dataSource.getProductDTOById(demoProductId); + + // Verify the product DTO properties + assertEquals(demoProductId, result.getProductId()); + assertEquals(Webshop.AMAZON, result.getDataOrigin()); + assertEquals(false, result.isAvailable()); + assertEquals(0.0, result.getCurrentPrice()); + assertEquals(0.0, result.getDeliveryPrice()); + assertEquals(null, result.getMerchant()); + } + @Test void testGetProductDTOById_ioException() throws IOException { // Set up the test environment diff --git a/src/test/java/de/rwu/easydrop/api/client/PurchaserFactoryTest.java b/src/test/java/de/rwu/easydrop/api/client/PurchaserFactoryTest.java new file mode 100644 index 0000000..c14285f --- /dev/null +++ b/src/test/java/de/rwu/easydrop/api/client/PurchaserFactoryTest.java @@ -0,0 +1,63 @@ +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.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 PurchaserFactoryTest { + + @Mock + private Config mockConfig; + + private PurchaserFactory purchaserFactory; + + @BeforeEach + void setUp() throws ConfigurationException { + MockitoAnnotations.openMocks(this); + purchaserFactory = new PurchaserFactory(mockConfig); + purchaserFactory.setConfig(mockConfig); + } + + @Test + void createAmazonPurchaser_ValidConfig_ReturnsAmazonPurchaser() { + // Arrange + String amazonApiUrl = "amazon_api_url"; + String amazonApiKey = "amazon_api_key"; + + when(mockConfig.getProperty("AMAZON_API_URL")).thenReturn(amazonApiUrl); + when(mockConfig.getProperty("AMAZON_API_KEY")).thenReturn(amazonApiKey); + + // Act + AmazonPurchaser amazonPurchaser = purchaserFactory.createAmazonPurchaser(); + + // Assert + assertNotNull(amazonPurchaser); + assertEquals(amazonApiKey, amazonPurchaser.getApiKey()); + } + + @Test + void createEbayPurchaser_ValidConfig_ReturnsEbayPurchaser() { + // Arrange + String ebayApiUrl = "ebay_api_url"; + String ebayApiKey = "ebay_api_key"; + + when(mockConfig.getProperty("EBAY_API_URL")).thenReturn(ebayApiUrl); + when(mockConfig.getProperty("EBAY_API_KEY")).thenReturn(ebayApiKey); + + // Act + EbayPurchaser ebayPurchaser = purchaserFactory.createEbayPurchaser(); + + // Assert + assertNotNull(ebayPurchaser); + assertEquals(ebayApiKey, ebayPurchaser.getApiKey()); + } +} diff --git a/src/test/java/de/rwu/easydrop/api/client/SellerFactoryTest.java b/src/test/java/de/rwu/easydrop/api/client/SellerFactoryTest.java new file mode 100644 index 0000000..c3c27ee --- /dev/null +++ b/src/test/java/de/rwu/easydrop/api/client/SellerFactoryTest.java @@ -0,0 +1,63 @@ +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.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 SellerFactoryTest { + + @Mock + private Config mockConfig; + + private SellerFactory sellerFactory; + + @BeforeEach + void setUp() throws ConfigurationException { + MockitoAnnotations.openMocks(this); + sellerFactory = new SellerFactory(mockConfig); + sellerFactory.setConfig(mockConfig); + } + + @Test + void createAmazonSeller_ValidConfig_ReturnsAmazonSeller() { + // Arrange + String amazonApiUrl = "amazon_api_url"; + String amazonApiKey = "amazon_api_key"; + + when(mockConfig.getProperty("AMAZON_API_URL")).thenReturn(amazonApiUrl); + when(mockConfig.getProperty("AMAZON_API_KEY")).thenReturn(amazonApiKey); + + // Act + AmazonSeller amazonSeller = sellerFactory.createAmazonSeller(); + + // Assert + assertNotNull(amazonSeller); + assertEquals(amazonApiKey, amazonSeller.getApiKey()); + } + + @Test + void createEbaySeller_ValidConfig_ReturnsEbaySeller() { + // Arrange + String ebayApiUrl = "ebay_api_url"; + String ebayApiKey = "ebay_api_key"; + + when(mockConfig.getProperty("EBAY_API_URL")).thenReturn(ebayApiUrl); + when(mockConfig.getProperty("EBAY_API_KEY")).thenReturn(ebayApiKey); + + // Act + EbaySeller ebaySeller = sellerFactory.createEbaySeller(); + + // Assert + assertNotNull(ebaySeller); + assertEquals(ebayApiKey, ebaySeller.getApiKey()); + } +} diff --git a/src/test/java/de/rwu/easydrop/core/CoreTest.java b/src/test/java/de/rwu/easydrop/core/CoreTest.java deleted file mode 100644 index bf62c6d..0000000 --- a/src/test/java/de/rwu/easydrop/core/CoreTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package de.rwu.easydrop.core; - -public class CoreTest { -} diff --git a/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java b/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java index 3dcfd84..68ee485 100644 --- a/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java +++ b/src/test/java/de/rwu/easydrop/data/connector/SQLiteConnectorTest.java @@ -8,7 +8,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import org.junit.jupiter.api.BeforeEach; @@ -17,13 +21,23 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.sqlite.SQLiteDataSource; +import de.rwu.easydrop.api.dto.OfferDTO; import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.api.dto.TransactionDTO; import de.rwu.easydrop.exception.PersistenceException; import de.rwu.easydrop.model.Webshop; class SQLiteConnectorTest { private static final String TEST_PRODUCT_ID = "12345"; private SQLiteConnector sqliteConnector = new SQLiteConnector(new SQLiteDataSource()); + @Mock + private Connection connection; + + @Mock + private PreparedStatement statement; + + @Mock + private ResultSet resultSet; @Mock private SQLiteDataSource mockDataSource; @@ -135,11 +149,179 @@ class SQLiteConnectorTest { } private void insertSampleProduct() { - ProductDTO ProductDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.AMAZON); - ProductDTO.setCurrentPrice(9.99); - ProductDTO.setMerchant("Sample Merchant"); - ProductDTO.setDeliveryPrice(2.50); - ProductDTO.setAvailable(true); - sqliteConnector.writeProduct(ProductDTO); + ProductDTO productDTO = new ProductDTO(TEST_PRODUCT_ID, Webshop.AMAZON); + productDTO.setCurrentPrice(9.99); + productDTO.setMerchant("Sample Merchant"); + productDTO.setDeliveryPrice(2.50); + productDTO.setAvailable(true); + sqliteConnector.writeProduct(productDTO); + } + + private void insertSampleOffer() { + ProductDTO p1 = new ProductDTO("p1", Webshop.AMAZON); + p1.setCurrentPrice(123f); + + ProductDTO p2 = new ProductDTO("p2", Webshop.EBAY); + p2.setCurrentPrice(234f); + + OfferDTO dto = new OfferDTO(); + dto.setOfferId("123"); + dto.setLastUpdate("2020-01-01 00:00:00"); + dto.setSourceProduct(p1); + dto.setTargetProduct(p2); + sqliteConnector.writeOffer(dto); + } + + private void insertSampleTransaction() { + TransactionDTO dto = new TransactionDTO(); + dto.setOfferId("123"); + dto.setEarnings(12f); + dto.setVolume(123f); + dto.setTransactionTime("2020-01-01 00:00:00"); + sqliteConnector.writeTX(dto); + } + + @Test + void outputTransactionsToLog_NothingThrown() { + insertSampleTransaction(); + + assertDoesNotThrow(() -> { + sqliteConnector.outputTransactionsToLog(); + }); + } + + @Test + void outputSummaryToLog_NothingThrown() { + insertSampleTransaction(); + + assertDoesNotThrow(() -> { + sqliteConnector.outputSummaryToLog(); + }); + } + + @Test + void outputTransactionsToLog_ThrowsPersistenceException_OnSQLException() throws SQLException { + // Arrange + sqliteConnector.setDb(mockDataSource); + doThrow(SQLException.class).when(mockDataSource).getConnection(); + + // Act and Assert + PersistenceException e = assertThrows(PersistenceException.class, + () -> sqliteConnector.outputTransactionsToLog()); + assertEquals("Something went wrong while reading transaction from SQLite", e.getMessage()); + } + + @Test + void outputSummaryToLog_ThrowsPersistenceException_OnSQLException() throws SQLException { + // Arrange + sqliteConnector.setDb(mockDataSource); + doThrow(SQLException.class).when(mockDataSource).getConnection(); + + // Act and Assert + PersistenceException e = assertThrows(PersistenceException.class, + () -> sqliteConnector.outputSummaryToLog()); + assertEquals("Something went wrong while reading transaction summary from SQLite", e.getMessage()); + } + + @Test + void deleteOfferById_SuccessfulDelete() { + // Arrange + sqliteConnector.clearData(); + insertSampleOffer(); + + // Make sure it's there + assertEquals(1, sqliteConnector.getOffers().size()); + + // Act + sqliteConnector.deleteOfferById("123"); + + // Assert + assertEquals(0, sqliteConnector.getOffers().size()); + } + + @Test + void deleteOfferById_ThrowsPersistenceException_OnSQLException() throws SQLException { + sqliteConnector.setDb(mockDataSource); + doThrow(SQLException.class).when(mockDataSource).getConnection(); + + // Act and Assert + PersistenceException e = assertThrows(PersistenceException.class, + () -> sqliteConnector.deleteOfferById("123")); + assertEquals("Something went wrong while deleting offer from SQLite", e.getMessage()); + } + + @Test + void getOffers_ReturnsCorrectValues() { + sqliteConnector.clearData(); + assertEquals(0, sqliteConnector.getOffers().size()); + + insertSampleOffer(); + + assertEquals(1, sqliteConnector.getOffers().size()); + } + + @Test + void getOffers_ThrowsPersistenceException_OnSQLException() throws SQLException { + sqliteConnector.setDb(mockDataSource); + doThrow(SQLException.class).when(mockDataSource).getConnection(); + + // Act and Assert + PersistenceException e = assertThrows(PersistenceException.class, + () -> sqliteConnector.getOffers()); + assertEquals("Something went wrong while reading offers from SQLite", e.getMessage()); + } + + @Test + void writeOffer_ValidDTO_DataSavedToDatabase() throws SQLException { + // Arrange + OfferDTO offerDTO = new OfferDTO(); + offerDTO.setOfferId("123"); + offerDTO.setSourceProduct(new ProductDTO(TEST_PRODUCT_ID, Webshop.AMAZON)); + offerDTO.setTargetProduct(new ProductDTO(TEST_PRODUCT_ID, Webshop.AMAZON)); + + String expectedQuery = "INSERT INTO offers (offerId, sourceWebshop, sourceId, sourcePrice, " + + "targetWebshop, targetId, targetPrice, lastupdate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + + when(connection.prepareStatement(expectedQuery)).thenReturn(statement); + + // Act + assertDoesNotThrow(() -> sqliteConnector.writeOffer(offerDTO)); + } + + @Test + void writeTX_NothingThrown() { + TransactionDTO dto = new TransactionDTO(); + + assertDoesNotThrow(() -> { + sqliteConnector.writeTX(dto); + }); + } + + @Test + void writeTX_ThrowsPersistenceException_OnSQLException() throws SQLException { + // Arrange + sqliteConnector.setDb(mockDataSource); + doThrow(SQLException.class).when(mockDataSource).getConnection(); + TransactionDTO dto = new TransactionDTO(); + + // Act and Assert + PersistenceException e = assertThrows(PersistenceException.class, + () -> sqliteConnector.writeTX(dto)); + assertEquals("Something went wrong while saving transaction to SQLite", e.getMessage()); + } + + @Test + void getOfferDTOById_OfferExists_ReturnsProductDTO() { + // Arrange + sqliteConnector.clearData(); + insertSampleOffer(); + + // Act + OfferDTO offerDTO = sqliteConnector.getOfferDTOById("123"); + + // Assert + assertNotNull(offerDTO); + assertEquals("123", offerDTO.getOfferId()); + assertEquals("2020-01-01 00:00:00", offerDTO.getLastUpdate()); } } diff --git a/src/test/java/de/rwu/easydrop/exception/InvalidOfferExceptionTest.java b/src/test/java/de/rwu/easydrop/exception/InvalidOfferExceptionTest.java new file mode 100644 index 0000000..1dfd268 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/exception/InvalidOfferExceptionTest.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 InvalidOfferExceptionTest { + + @Test + void constructor_WithMessage_SetsMessage() { + // Arrange + String message = "Invalid Offer data"; + + // Act + InvalidOfferException exception = new InvalidOfferException(message); + + // Assert + assertEquals(message, exception.getMessage()); + } + + @Test + void constructor_WithMessageAndCause_SetsMessageAndCause() { + // Arrange + String message = "Invalid Offer data"; + Throwable cause = new IllegalArgumentException("Invalid argument"); + + // Act + InvalidOfferException exception = new InvalidOfferException(message, cause); + + // Assert + assertEquals(message, exception.getMessage()); + assertEquals(cause, exception.getCause()); + } + + @Test + void constructor_WithNullMessage_SetsNullMessage() { + // Act + InvalidOfferException exception = new InvalidOfferException(null); + + // Assert + assertEquals(null, exception.getMessage()); + } + + @Test + void constructor_WithNullCause_SetsNullCause() { + // Act + InvalidOfferException exception = new InvalidOfferException("Invalid Offer data", null); + + // Assert + assertEquals(null, exception.getCause()); + } + + @Test + void throw_InvalidOfferException() { + // Act and Assert + assertThrows(InvalidOfferException.class, () -> { + throw new InvalidOfferException("Invalid Offer data"); + }); + } +} diff --git a/src/test/java/de/rwu/easydrop/exception/InvalidTransactionExceptionTest.java b/src/test/java/de/rwu/easydrop/exception/InvalidTransactionExceptionTest.java new file mode 100644 index 0000000..32e4971 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/exception/InvalidTransactionExceptionTest.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 InvalidTransactionExceptionTest { + + @Test + void constructor_WithMessage_SetsMessage() { + // Arrange + String message = "Invalid Transaction data"; + + // Act + InvalidTransactionException exception = new InvalidTransactionException(message); + + // Assert + assertEquals(message, exception.getMessage()); + } + + @Test + void constructor_WithMessageAndCause_SetsMessageAndCause() { + // Arrange + String message = "Invalid Transaction data"; + Throwable cause = new IllegalArgumentException("Invalid argument"); + + // Act + InvalidTransactionException exception = new InvalidTransactionException(message, cause); + + // Assert + assertEquals(message, exception.getMessage()); + assertEquals(cause, exception.getCause()); + } + + @Test + void constructor_WithNullMessage_SetsNullMessage() { + // Act + InvalidTransactionException exception = new InvalidTransactionException(null); + + // Assert + assertEquals(null, exception.getMessage()); + } + + @Test + void constructor_WithNullCause_SetsNullCause() { + // Act + InvalidTransactionException exception = new InvalidTransactionException("Invalid Transaction data", null); + + // Assert + assertEquals(null, exception.getCause()); + } + + @Test + void throw_InvalidTransactionException() { + // Act and Assert + assertThrows(InvalidTransactionException.class, () -> { + throw new InvalidTransactionException("Invalid Transaction data"); + }); + } +} diff --git a/src/test/java/de/rwu/easydrop/model/ProductPairTest.java b/src/test/java/de/rwu/easydrop/model/ProductPairTest.java new file mode 100644 index 0000000..b562918 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/model/ProductPairTest.java @@ -0,0 +1,25 @@ +package de.rwu.easydrop.model; + +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; + +class ProductPairTest { + + @Test + void constructor_TwoProducts_ProductsInitializedCorrectly() { + // Arrange + Product product1 = new Product(); + product1.setProductId("123"); + + Product product2 = new Product(); + product2.setProductId("234"); + + // Act + ProductPair pair = new ProductPair(product1, product2); + + // Assert + assertSame(product1, pair.getProduct1()); + assertSame(product2, pair.getProduct2()); + } +} diff --git a/src/test/java/de/rwu/easydrop/model/WebshopTest.java b/src/test/java/de/rwu/easydrop/model/WebshopTest.java new file mode 100644 index 0000000..6e40870 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/model/WebshopTest.java @@ -0,0 +1,23 @@ +package de.rwu.easydrop.model; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class WebshopTest { + + @Test + void testFromString_returnsIntendedConstant() { + Webshop testShop = Webshop.fromString("Amazon"); + + assertEquals(Webshop.AMAZON, testShop); + } + + @Test + void testFromString_invalidShop() { + assertThrows(IllegalArgumentException.class, () -> { + Webshop.fromString("thisdoesnotexist"); + }); + } +} diff --git a/src/test/java/de/rwu/easydrop/service/mapping/TransactionMapperTest.java b/src/test/java/de/rwu/easydrop/service/mapping/TransactionMapperTest.java new file mode 100644 index 0000000..79de525 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/mapping/TransactionMapperTest.java @@ -0,0 +1,71 @@ +package de.rwu.easydrop.service.mapping; + +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.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import org.junit.jupiter.api.Test; + +import de.rwu.easydrop.api.dto.TransactionDTO; +import de.rwu.easydrop.model.Transaction; + +class TransactionMapperTest { + @Test + void testConstructorIsPrivate() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + // Check for private constructor + Constructor constructor = TransactionMapper.class.getDeclaredConstructor(); + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + + // Make sure exception is thrown when instantiating + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, () -> { + constructor.newInstance(); + }); + } + + @Test + void mapTXFromDTO_WithValidTransactionDTO_ReturnsTransaction() { + // Arrange + TransactionDTO transactionDTO = new TransactionDTO(); + transactionDTO.setOfferId("123"); + transactionDTO.setVolume(10.0); + transactionDTO.setEarnings(5.0); + transactionDTO.setTransactionTime("2023-06-25 03:26:59"); + + // Act + Transaction transaction = TransactionMapper.mapTXFromDTO(transactionDTO); + + // Assert + assertNotNull(transaction); + assertEquals(transactionDTO.getOfferId(), transaction.getOfferId()); + assertEquals(transactionDTO.getVolume(), transaction.getVolume()); + assertEquals(transactionDTO.getEarnings(), transaction.getEarnings()); + assertEquals(transactionDTO.getTransactionTime(), transaction.getTransactionTime()); + } + + @Test + void mapTXToDTO_WithValidTransaction_ReturnsTransactionDTO() { + // Arrange + Transaction transaction = new Transaction(); + transaction.setOfferId("123"); + transaction.setVolume(10.0); + transaction.setEarnings(5.0); + transaction.setTransactionTime("2023-06-25 03:26:59"); + + // Act + TransactionDTO transactionDTO = TransactionMapper.mapTXToDTO(transaction); + + // Assert + assertNotNull(transactionDTO); + assertEquals(transaction.getOfferId(), transactionDTO.getOfferId()); + assertEquals(transaction.getVolume(), transactionDTO.getVolume()); + assertEquals(transaction.getEarnings(), transactionDTO.getEarnings()); + assertEquals(transaction.getTransactionTime(), transactionDTO.getTransactionTime()); + } +} diff --git a/src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java b/src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java index cde6ca6..466bd56 100644 --- a/src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java +++ b/src/test/java/de/rwu/easydrop/service/processing/OfferIdentifierTest.java @@ -1,5 +1,176 @@ package de.rwu.easydrop.service.processing; -public class OfferIdentifierTest { - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import de.rwu.easydrop.exception.InvalidCatalogueException; +import de.rwu.easydrop.exception.InvalidOfferException; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.ProductCatalogue; +import de.rwu.easydrop.model.ProductPair; + +class OfferIdentifierTest { + + @Mock + private ProductCatalogue mockProductCatalogue; + + private OfferIdentifier offerIdentifier; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + + offerIdentifier = new OfferIdentifier(); + } + + @Test + void runIdentifier_WithValidProductCatalogues_IdentifiesOffers() { + // Arrange + List productCatalogues = new ArrayList<>(); + ProductCatalogue productCatalogue1 = new ProductCatalogue("Catalogue1", "desc"); + ProductCatalogue productCatalogue2 = new ProductCatalogue("Catalogue2", "desc"); + + Product product1 = new Product(); + product1.setCurrentPrice(100.0); + Product product2 = new Product(); + product2.setCurrentPrice(200.0); + Product product3 = new Product(); + product3.setCurrentPrice(300.0); + Product product4 = new Product(); + product4.setCurrentPrice(400.0); + + productCatalogue1.addProduct(product1); + productCatalogue1.addProduct(product2); + productCatalogue2.addProduct(product3); + productCatalogue2.addProduct(product4); + + productCatalogues.add(productCatalogue1); + productCatalogues.add(productCatalogue2); + + // Act + List identifiedOffers = offerIdentifier.runIdentifier(productCatalogues); + + // Assert + assertEquals(2, identifiedOffers.size()); + assertNotNull(identifiedOffers.get(0).getSourceProduct()); + assertNotNull(identifiedOffers.get(0).getTargetProduct()); + assertNotNull(identifiedOffers.get(1).getSourceProduct()); + assertNotNull(identifiedOffers.get(1).getTargetProduct()); + } + + @Test + void runIdentifier_WithOneGoodOneBadCatalogue_BadOneIsntIncluded() { + // Arrange + List productCatalogues = new ArrayList<>(); + ProductCatalogue productCatalogue1 = new ProductCatalogue("Catalogue1", "desc"); + ProductCatalogue productCatalogue2 = new ProductCatalogue("Catalogue2", "desc"); + + Product product1 = new Product(); + product1.setCurrentPrice(100.0); + Product product2 = new Product(); + product2.setCurrentPrice(200.0); + Product product3 = new Product(); + product3.setCurrentPrice(300.0); + Product product4 = new Product(); + product4.setCurrentPrice(300.0); + + productCatalogue1.addProduct(product1); + productCatalogue1.addProduct(product2); + productCatalogue2.addProduct(product3); + productCatalogue2.addProduct(product4); + + productCatalogues.add(productCatalogue1); + productCatalogues.add(productCatalogue2); + + // Act + List identifiedOffers = offerIdentifier.runIdentifier(productCatalogues); + + // Assert + assertEquals(1, identifiedOffers.size()); // Only 1 passed + } + + @Test + void getHighestMarginProducts_WithValidProductCatalogue_ReturnsProductPair() { + // Arrange + ProductCatalogue productCatalogue = new ProductCatalogue("TestCatalogue", "desc"); + Product product1 = new Product(); + product1.setCurrentPrice(100.0); + Product product2 = new Product(); + product2.setCurrentPrice(200.0); + productCatalogue.addProduct(product1); + productCatalogue.addProduct(product2); + + // Act + ProductPair productPair = OfferIdentifier.getHighestMarginProducts(productCatalogue); + + // Assert + assertNotNull(productPair); + assertNotNull(productPair.getProduct1()); + assertNotNull(productPair.getProduct2()); + assertNotEquals(productPair.getProduct1(), productPair.getProduct2()); + } + + @Test + void getHighestMarginProducts_SecondProductCheaper() { + // Arrange + ProductCatalogue productCatalogue = new ProductCatalogue("TestCatalogue", "desc"); + Product product1 = new Product(); + product1.setCurrentPrice(200.0); + Product product2 = new Product(); + product2.setCurrentPrice(100.0); + productCatalogue.addProduct(product1); + productCatalogue.addProduct(product2); + + // Act + ProductPair productPair = OfferIdentifier.getHighestMarginProducts(productCatalogue); + + // Assert + assertNotNull(productPair); + assertNotNull(productPair.getProduct1()); + assertNotNull(productPair.getProduct2()); + assertNotEquals(productPair.getProduct1(), productPair.getProduct2()); + } + + @Test + void getHighestMarginProducts_WithCatalogueSizeLessThan2_ThrowsInvalidCatalogueException() { + // Arrange + ProductCatalogue productCatalogue = new ProductCatalogue("SmallCatalogue", "desc"); + + // Act and Assert + assertThrows(InvalidCatalogueException.class, () -> { + OfferIdentifier.getHighestMarginProducts(productCatalogue); + }); + } + + @Test + void getHighestMarginProducts_WithZeroPriceMargin_ThrowsInvalidOfferException() { + // Arrange + ProductCatalogue productCatalogue = new ProductCatalogue("name", "desc"); + Product product1 = new Product(); + product1.setCurrentPrice(200.0); + + Product product2 = new Product(); + product2.setCurrentPrice(200.0); + + productCatalogue.getProducts().add(product1); + productCatalogue.getProducts().add(product2); + + // Act and Assert + InvalidOfferException e = assertThrows(InvalidOfferException.class, () -> { + OfferIdentifier.getHighestMarginProducts(productCatalogue); + }); + + assertEquals("Price margin is zero!", e.getMessage()); + } } diff --git a/src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java b/src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java index c3f2fd9..3b3df76 100644 --- a/src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java +++ b/src/test/java/de/rwu/easydrop/service/processing/OfferProvisionerTest.java @@ -1,5 +1,105 @@ package de.rwu.easydrop.service.processing; -public class OfferProvisionerTest { - +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import de.rwu.easydrop.api.client.AmazonPurchaser; +import de.rwu.easydrop.api.client.AmazonSeller; +import de.rwu.easydrop.api.client.EbayPurchaser; +import de.rwu.easydrop.api.client.EbaySeller; +import de.rwu.easydrop.api.client.PurchaserFactory; +import de.rwu.easydrop.api.client.SellerFactory; +import de.rwu.easydrop.data.connector.OfferPersistenceInterface; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Webshop; +import de.rwu.easydrop.service.writer.OfferWriter; + +class OfferProvisionerTest { + + @Mock + private OfferPersistenceInterface mockPersistence; + + @Mock + private SellerFactory mockSellerFactory; + + @Mock + private PurchaserFactory mockPurchaserFactory; + + @Mock + private OfferWriter mockOfferWriter; + + @Mock + private AmazonSeller mockAmazonSeller; + + @Mock + private EbaySeller mockEbaySeller; + + @Mock + private AmazonPurchaser mockAmazonPurchaser; + + @Mock + private EbayPurchaser mockEbayPurchaser; + + private OfferProvisioner offerProvisioner; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + + when(mockSellerFactory.createAmazonSeller()).thenReturn(mockAmazonSeller); + when(mockSellerFactory.createEbaySeller()).thenReturn(mockEbaySeller); + when(mockPurchaserFactory.createAmazonPurchaser()).thenReturn(mockAmazonPurchaser); + when(mockPurchaserFactory.createEbayPurchaser()).thenReturn(mockEbayPurchaser); + + offerProvisioner = new OfferProvisioner(mockPersistence, mockSellerFactory, mockPurchaserFactory); + offerProvisioner.setOfferWriter(mockOfferWriter); + } + + @Test + void runProvisioner_WithValidOffers_PlacesOrders() { + // Arrange + List offers = new ArrayList<>(); + Offer offer1 = createOffer(Webshop.AMAZON, "ASIN123", Webshop.EBAY, "12345"); + Offer offer2 = createOffer(Webshop.EBAY, "54321", Webshop.AMAZON, "ASIN456"); + offers.add(offer1); + offers.add(offer2); + + // Act + offerProvisioner.runProvisioner(offers); + + // Assert + verify(mockAmazonSeller, times(1)).sellProduct(any()); + verify(mockEbaySeller, times(1)).sellProduct(any()); + verify(mockAmazonPurchaser, times(1)).purchaseProduct(any()); + verify(mockEbayPurchaser, times(1)).purchaseProduct(any()); + verify(mockOfferWriter, times(2)).writeOfferToPersistence(any()); + } + + private Offer createOffer(Webshop sourceWebshop, String sourceProductId, Webshop targetWebshop, + String targetProductId) { + Product sourceProduct = new Product(); + sourceProduct.setDataOrigin(sourceWebshop); + sourceProduct.setProductId(sourceProductId); + + Product targetProduct = new Product(); + targetProduct.setDataOrigin(targetWebshop); + targetProduct.setProductId(targetProductId); + + Offer offer = new Offer(); + offer.setSourceProduct(sourceProduct); + offer.setTargetProduct(targetProduct); + + return offer; + } } diff --git a/src/test/java/de/rwu/easydrop/service/processing/TransactionHandlerTest.java b/src/test/java/de/rwu/easydrop/service/processing/TransactionHandlerTest.java new file mode 100644 index 0000000..4527551 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/processing/TransactionHandlerTest.java @@ -0,0 +1,50 @@ +package de.rwu.easydrop.service.processing; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import de.rwu.easydrop.api.dto.TransactionDTO; +import de.rwu.easydrop.data.connector.TransactionPersistenceInterface; +import de.rwu.easydrop.model.Offer; +import de.rwu.easydrop.model.Product; +import de.rwu.easydrop.model.Transaction; +import de.rwu.easydrop.service.mapping.TransactionMapper; + +class TransactionHandlerTest { + + @Mock + private TransactionPersistenceInterface mockPersistence; + + public TransactionHandlerTest() { + MockitoAnnotations.openMocks(this); + } + + @Test + void turnOfferToTransaction_ValidOffer_TransactionCreatedAndWrittenToPersistence() { + // Arrange + Offer offer = new Offer(); + Product product = new Product(); + offer.setSourceProduct(product); + offer.setTargetProduct(product); + + TransactionHandler handler = new TransactionHandler(mockPersistence); + + // Act + handler.turnOfferToTransaction(offer); + + // Assert + ArgumentCaptor transactionDtoCaptor = ArgumentCaptor.forClass(TransactionDTO.class); + verify(mockPersistence, times(1)).writeTX(transactionDtoCaptor.capture()); + + TransactionDTO capturedTransactionDto = transactionDtoCaptor.getValue(); + Transaction capturedTransaction = TransactionMapper.mapTXFromDTO(capturedTransactionDto); + + assertEquals(offer.getOfferId(), capturedTransaction.getOfferId()); + } +} diff --git a/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java b/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java index da42da6..5d0a2db 100644 --- a/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java +++ b/src/test/java/de/rwu/easydrop/service/retriever/ProductRetrieverTest.java @@ -2,6 +2,8 @@ package de.rwu.easydrop.service.retriever; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -108,4 +110,49 @@ class ProductRetrieverTest { // Verify the interactions verify(persistence, times(1)).getProductDTOById(productId); } + + @Test + void getProductFromWebshop_ValidAmazonWebshop_ReturnsProduct() { + // Arrange + String productIdentifier = "ASIN1"; + ProductDTO dto = new ProductDTO(productIdentifier, Webshop.AMAZON); + dto.setCurrentPrice(1.23); + AmazonProductDataSource dataSource = mock(AmazonProductDataSource.class); + Product expectedProduct = new Product(); + expectedProduct.setProductId(productIdentifier); + expectedProduct.setDataOrigin(Webshop.AMAZON); + expectedProduct.setCurrentPrice(1.23); + when(dataSource.getProductDTOById(productIdentifier)).thenReturn(dto); + when(dataSourceFactory.createAmazonProductDataSource()).thenReturn(dataSource); + + // Act + Product actualProduct = productRetriever.getProductFromWebshop(Webshop.AMAZON, productIdentifier); + + // Assert + assertEquals(expectedProduct, actualProduct); + verify(dataSourceFactory).createAmazonProductDataSource(); + verify(dataSource).getProductDTOById(productIdentifier); + } + + @Test + void getProductFromWebshop_ValidEbayWebshop_ReturnsProduct() { + // Arrange + String productIdentifier = "ASIN1"; + ProductDTO dto = new ProductDTO(productIdentifier, Webshop.EBAY); + dto.setCurrentPrice(1.23); + Product expectedProduct = new Product(); + expectedProduct.setProductId(productIdentifier); + expectedProduct.setDataOrigin(Webshop.EBAY); + expectedProduct.setCurrentPrice(1.23); + when(ebayDataSource.getProductDTOById(productIdentifier)).thenReturn(dto); + when(dataSourceFactory.createEbayItemDataSource()).thenReturn(ebayDataSource); + + // Act + Product actualProduct = productRetriever.getProductFromWebshop(Webshop.EBAY, productIdentifier); + + // Assert + assertEquals(expectedProduct, actualProduct); + verify(dataSourceFactory).createEbayItemDataSource(); + verify(ebayDataSource).getProductDTOById(productIdentifier); + } } diff --git a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java index 5982b83..d9271de 100644 --- a/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java +++ b/src/test/java/de/rwu/easydrop/service/validation/OfferValidatorTest.java @@ -1,8 +1,13 @@ package de.rwu.easydrop.service.validation; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -12,8 +17,20 @@ import org.junit.jupiter.params.provider.MethodSource; import de.rwu.easydrop.exception.InvalidOfferException; import de.rwu.easydrop.model.Offer; - class OfferValidatorTest { + @Test + void testConstructorIsPrivate() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + // Check for private constructor + Constructor constructor = OfferValidator.class.getDeclaredConstructor(); + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + + // Make sure exception is thrown when instantiating + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, () -> { + constructor.newInstance(); + }); + } @Test void validate_Offer_ValidProduct_NoExceptionThrown() { @@ -26,6 +43,18 @@ class OfferValidatorTest { assertDoesNotThrow(() -> OfferValidator.validate(offer)); } + @Test + void validate_Offer_NullPointer() { + // Arrange + Offer offer = new Offer(); + + InvalidOfferException e = assertThrows(InvalidOfferException.class, () -> { + OfferValidator.validate(offer); + }); + + assertEquals("Required information is missing in the offer", e.getMessage()); + } + @ParameterizedTest @MethodSource("invalidOfferProvider") void validate_InvalidOffer_ThrowsInvalidOfferException(Offer offer) { @@ -36,8 +65,8 @@ class OfferValidatorTest { static Stream invalidOfferProvider() { return Stream.of( - createOfferWithEmptylastUpdate(), - createOfferWithEmptyId()); + createOfferWithEmptylastUpdate(), + createOfferWithEmptyId()); } private static Offer createOfferWithEmptylastUpdate() { @@ -53,5 +82,5 @@ class OfferValidatorTest { offer.setLastUpdate("8798476"); return offer; } - + } diff --git a/src/test/java/de/rwu/easydrop/service/validation/TransactionValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/TransactionValidatorTest.java new file mode 100644 index 0000000..939379e --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/validation/TransactionValidatorTest.java @@ -0,0 +1,70 @@ +package de.rwu.easydrop.service.validation; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import org.junit.jupiter.api.Test; + +import de.rwu.easydrop.exception.InvalidTransactionException; +import de.rwu.easydrop.model.Transaction; + +class TransactionValidatorTest { + @Test + void testConstructorIsPrivate() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + // Check for private constructor + Constructor constructor = TransactionValidator.class + .getDeclaredConstructor(); + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + + // Make sure exception is thrown when instantiating + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, () -> { + constructor.newInstance(); + }); + } + + @Test + void validate_ValidTransaction_NoExceptionThrown() { + // Arrange + Transaction transaction = new Transaction(); + transaction.setOfferId("123"); + transaction.setVolume(123f); + transaction.setEarnings(12.23); + transaction.setTransactionTime("2020-01-01 00:00:00"); + + // Act & Assert + assertDoesNotThrow(() -> TransactionValidator.validate(transaction)); + } + + @Test + void validate_InvalidTransaction_InvalidTransactionExceptionThrown() { + // Arrange + Transaction tx1 = new Transaction(); + tx1.setOfferId(""); // Set an empty Offer ID to make it invalid + Transaction tx2 = new Transaction(); + tx2.setOfferId("123"); + Transaction tx3 = new Transaction(); + tx3.setOfferId("123"); + tx3.setEarnings(123f); + + // Act & Assert + assertThrows(InvalidTransactionException.class, () -> TransactionValidator.validate(tx1)); + assertThrows(InvalidTransactionException.class, () -> TransactionValidator.validate(tx2)); + assertThrows(InvalidTransactionException.class, () -> TransactionValidator.validate(tx3)); + } + + @Test + void validate_NullTransaction_InvalidTransactionExceptionThrown() { + // Arrange + Transaction transaction = null; + + // Act & Assert + assertThrows(InvalidTransactionException.class, () -> TransactionValidator.validate(transaction)); + } +} diff --git a/src/test/java/de/rwu/easydrop/service/writer/TransactionWriterTest.java b/src/test/java/de/rwu/easydrop/service/writer/TransactionWriterTest.java new file mode 100644 index 0000000..ef9dd48 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/writer/TransactionWriterTest.java @@ -0,0 +1,63 @@ +package de.rwu.easydrop.service.writer; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import de.rwu.easydrop.api.dto.TransactionDTO; +import de.rwu.easydrop.data.connector.TransactionPersistenceInterface; +import de.rwu.easydrop.exception.InvalidTransactionException; +import de.rwu.easydrop.model.Transaction; +import de.rwu.easydrop.service.mapping.TransactionMapper; + +class TransactionWriterTest { + + @Mock + private TransactionPersistenceInterface persistence; + + private TransactionWriter writer; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + writer = new TransactionWriter(persistence); + } + + @Test + void writeTXToPersistence_ValidTransaction_TransactionSaved() { + // Arrange + Transaction transaction = new Transaction(); + transaction.setOfferId("123"); + transaction.setVolume(123f); + transaction.setEarnings(12.23); + transaction.setTransactionTime("2020-01-01 00:00:00"); + + TransactionDTO expectedDTO = TransactionMapper.mapTXToDTO(transaction); + + // Act + writer.writeTXToPersistence(transaction); + + // Assert + verify(persistence).writeTX(expectedDTO); + } + + @Test + void writeTXToPersistence_InvalidTransaction_ValidationExceptionThrown() { + // Arrange + Transaction transaction = new Transaction(); + transaction.setVolume(123f); + transaction.setEarnings(12.23); + transaction.setTransactionTime("2020-01-01 00:00:00"); + + // Act & Assert + assertThrows(InvalidTransactionException.class, () -> writer.writeTXToPersistence(transaction)); + + // Verify that persistence.writeTX is not called + verifyNoInteractions(persistence); + } +} diff --git a/src/test/java/de/rwu/easydrop/util/FormattingUtilTest.java b/src/test/java/de/rwu/easydrop/util/FormattingUtilTest.java index 4b1dfa1..cd1d9b9 100644 --- a/src/test/java/de/rwu/easydrop/util/FormattingUtilTest.java +++ b/src/test/java/de/rwu/easydrop/util/FormattingUtilTest.java @@ -1,5 +1,6 @@ package de.rwu.easydrop.util; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -55,4 +56,17 @@ class FormattingUtilTest { Assertions.assertEquals(expectedFormattedAmount, formattedAmount); } + + @Test + void testRemoveSpaces_RemovesAllSpaces() { + String test1 = FormattingUtil.removeSpaces("this is a test"); + String test2 = FormattingUtil.removeSpaces("another test"); + String test3 = FormattingUtil.removeSpaces(" daring today, aren't we? "); + String test4 = FormattingUtil.removeSpaces("hehe"); + + assertEquals("thisisatest", test1); + assertEquals("anothertest", test2); + assertEquals("daringtoday,aren'twe?", test3); + assertEquals("hehe", test4); + } }