From ff8f5f2c1a6bb430f0fcc92905bf10a1dd2dad6f Mon Sep 17 00:00:00 2001 From: Tour Date: Thu, 4 Dec 2025 20:14:28 +0100 Subject: [PATCH] Fix mock tests --- .../java/auctiora/AuctionMonitorProducer.java | 2 +- .../java/auctiora/AuctionMonitorResource.java | 664 +++++++++--------- src/main/java/auctiora/DatabaseService.java | 43 +- .../java/auctiora/ImageProcessingService.java | 7 +- .../java/auctiora/NotificationService.java | 8 +- .../java/auctiora/ObjectDetectionService.java | 8 +- src/test/java/auctiora/IntegrationTest.java | 42 +- 7 files changed, 408 insertions(+), 366 deletions(-) diff --git a/src/main/java/auctiora/AuctionMonitorProducer.java b/src/main/java/auctiora/AuctionMonitorProducer.java index a970e0c..7945dc2 100644 --- a/src/main/java/auctiora/AuctionMonitorProducer.java +++ b/src/main/java/auctiora/AuctionMonitorProducer.java @@ -24,7 +24,7 @@ public class AuctionMonitorProducer { @ConfigProperty(name = "auction.database.path") String dbPath) throws SQLException { LOG.infof("Initializing DatabaseService with path: %s", dbPath); - DatabaseService db = new DatabaseService(dbPath); + var db = new DatabaseService(dbPath); db.ensureSchema(); return db; } diff --git a/src/main/java/auctiora/AuctionMonitorResource.java b/src/main/java/auctiora/AuctionMonitorResource.java index 06c98da..f01e143 100644 --- a/src/main/java/auctiora/AuctionMonitorResource.java +++ b/src/main/java/auctiora/AuctionMonitorResource.java @@ -20,343 +20,343 @@ import java.util.Map; @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class AuctionMonitorResource { - - private static final Logger LOG = Logger.getLogger(AuctionMonitorResource.class); - - @Inject - DatabaseService db; - - @Inject - QuarkusWorkflowScheduler scheduler; - - @Inject - NotificationService notifier; - - @Inject - RateLimitedHttpClient httpClient; - - /** - * GET /api/monitor/status - * Returns current monitoring status - */ - @GET - @Path("/status") - public Response getStatus() { - try { - Map status = new HashMap<>(); - status.put("running", true); - status.put("auctions", db.getAllAuctions().size()); - status.put("lots", db.getAllLots().size()); - status.put("images", db.getImageCount()); - - // Count closing soon - int closingSoon = 0; - for (var lot : db.getAllLots()) { - if (lot.closingTime() != null && lot.minutesUntilClose() < 30) { - closingSoon++; - } + + private static final Logger LOG = Logger.getLogger(AuctionMonitorResource.class); + + @Inject + DatabaseService db; + + @Inject + QuarkusWorkflowScheduler scheduler; + + @Inject + NotificationService notifier; + + @Inject + RateLimitedHttpClient httpClient; + + /** + * GET /api/monitor/status + * Returns current monitoring status + */ + @GET + @Path("/status") + public Response getStatus() { + try { + Map status = new HashMap<>(); + status.put("running", true); + status.put("auctions", db.getAllAuctions().size()); + status.put("lots", db.getAllLots().size()); + status.put("images", db.getImageCount()); + + // Count closing soon + var closingSoon = 0; + for (var lot : db.getAllLots()) { + if (lot.closingTime() != null && lot.minutesUntilClose() < 30) { + closingSoon++; } - status.put("closingSoon", closingSoon); - - return Response.ok(status).build(); - - } catch (Exception e) { - LOG.error("Failed to get status", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * GET /api/monitor/statistics - * Returns detailed statistics - */ - @GET - @Path("/statistics") - public Response getStatistics() { - try { - Map stats = new HashMap<>(); - - var auctions = db.getAllAuctions(); - var lots = db.getAllLots(); - - stats.put("totalAuctions", auctions.size()); - stats.put("totalLots", lots.size()); - stats.put("totalImages", db.getImageCount()); - - // Lot statistics - int activeLots = 0; - int lotsWithBids = 0; - double totalBids = 0; - - for (var lot : lots) { - if (lot.closingTime() != null && lot.minutesUntilClose() > 0) { - activeLots++; - } - if (lot.currentBid() > 0) { - lotsWithBids++; - totalBids += lot.currentBid(); - } + } + status.put("closingSoon", closingSoon); + + return Response.ok(status).build(); + + } catch (Exception e) { + LOG.error("Failed to get status", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * GET /api/monitor/statistics + * Returns detailed statistics + */ + @GET + @Path("/statistics") + public Response getStatistics() { + try { + Map stats = new HashMap<>(); + + var auctions = db.getAllAuctions(); + var lots = db.getAllLots(); + + stats.put("totalAuctions", auctions.size()); + stats.put("totalLots", lots.size()); + stats.put("totalImages", db.getImageCount()); + + // Lot statistics + var activeLots = 0; + var lotsWithBids = 0; + double totalBids = 0; + + for (var lot : lots) { + if (lot.closingTime() != null && lot.minutesUntilClose() > 0) { + activeLots++; } - - stats.put("activeLots", activeLots); - stats.put("lotsWithBids", lotsWithBids); - stats.put("totalBidValue", String.format("€%.2f", totalBids)); - stats.put("averageBid", lotsWithBids > 0 ? String.format("€%.2f", totalBids / lotsWithBids) : "€0.00"); - - return Response.ok(stats).build(); - - } catch (Exception e) { - LOG.error("Failed to get statistics", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * POST /api/monitor/trigger/scraper-import - * Manually trigger scraper import workflow - */ - @POST - @Path("/trigger/scraper-import") - public Response triggerScraperImport() { - try { - scheduler.importScraperData(); - return Response.ok(Map.of("message", "Scraper import triggered successfully")).build(); - } catch (Exception e) { - LOG.error("Failed to trigger scraper import", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * POST /api/monitor/trigger/image-processing - * Manually trigger image processing workflow - */ - @POST - @Path("/trigger/image-processing") - public Response triggerImageProcessing() { - try { - scheduler.processImages(); - return Response.ok(Map.of("message", "Image processing triggered successfully")).build(); - } catch (Exception e) { - LOG.error("Failed to trigger image processing", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * POST /api/monitor/trigger/bid-monitoring - * Manually trigger bid monitoring workflow - */ - @POST - @Path("/trigger/bid-monitoring") - public Response triggerBidMonitoring() { - try { - scheduler.monitorBids(); - return Response.ok(Map.of("message", "Bid monitoring triggered successfully")).build(); - } catch (Exception e) { - LOG.error("Failed to trigger bid monitoring", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * POST /api/monitor/trigger/closing-alerts - * Manually trigger closing alerts workflow - */ - @POST - @Path("/trigger/closing-alerts") - public Response triggerClosingAlerts() { - try { - scheduler.checkClosingTimes(); - return Response.ok(Map.of("message", "Closing alerts triggered successfully")).build(); - } catch (Exception e) { - LOG.error("Failed to trigger closing alerts", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * GET /api/monitor/auctions - * Returns list of all auctions - */ - @GET - @Path("/auctions") - public Response getAuctions(@QueryParam("country") String country) { - try { - var auctions = country != null && !country.isEmpty() - ? db.getAuctionsByCountry(country) - : db.getAllAuctions(); - - return Response.ok(auctions).build(); - } catch (Exception e) { - LOG.error("Failed to get auctions", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * GET /api/monitor/lots - * Returns list of active lots - */ - @GET - @Path("/lots") - public Response getActiveLots() { - try { - var lots = db.getActiveLots(); - return Response.ok(lots).build(); - } catch (Exception e) { - LOG.error("Failed to get lots", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * GET /api/monitor/lots/closing-soon - * Returns lots closing within specified minutes (default 30) - */ - @GET - @Path("/lots/closing-soon") - public Response getLotsClosingSoon(@QueryParam("minutes") @DefaultValue("30") int minutes) { - try { - var allLots = db.getActiveLots(); - var closingSoon = allLots.stream() - .filter(lot -> lot.closingTime() != null && lot.minutesUntilClose() < minutes) - .toList(); - - return Response.ok(closingSoon).build(); - } catch (Exception e) { - LOG.error("Failed to get closing lots", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * GET /api/monitor/lots/{lotId}/images - * Returns images for a specific lot - */ - @GET - @Path("/lots/{lotId}/images") - public Response getLotImages(@PathParam("lotId") int lotId) { - try { - var images = db.getImagesForLot(lotId); - return Response.ok(images).build(); - } catch (Exception e) { - LOG.error("Failed to get lot images", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * POST /api/monitor/test-notification - * Send a test notification - */ - @POST - @Path("/test-notification") - public Response sendTestNotification(Map request) { - try { - String message = request.getOrDefault("message", "Test notification from Auction Monitor"); - String title = request.getOrDefault("title", "Test Notification"); - int priority = Integer.parseInt(request.getOrDefault("priority", "0")); - - notifier.sendNotification(message, title, priority); - - return Response.ok(Map.of("message", "Test notification sent successfully")).build(); - } catch (Exception e) { - LOG.error("Failed to send test notification", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * GET /api/monitor/rate-limit/stats - * Returns HTTP rate limiting statistics for all hosts - */ - @GET - @Path("/rate-limit/stats") - public Response getRateLimitStats() { - try { - var stats = httpClient.getAllStats(); - - Map response = new HashMap<>(); - response.put("hosts", stats.size()); - - Map hostStats = new HashMap<>(); - for (var entry : stats.entrySet()) { - var stat = entry.getValue(); - hostStats.put(entry.getKey(), Map.of( + if (lot.currentBid() > 0) { + lotsWithBids++; + totalBids += lot.currentBid(); + } + } + + stats.put("activeLots", activeLots); + stats.put("lotsWithBids", lotsWithBids); + stats.put("totalBidValue", String.format("€%.2f", totalBids)); + stats.put("averageBid", lotsWithBids > 0 ? String.format("€%.2f", totalBids / lotsWithBids) : "€0.00"); + + return Response.ok(stats).build(); + + } catch (Exception e) { + LOG.error("Failed to get statistics", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * POST /api/monitor/trigger/scraper-import + * Manually trigger scraper import workflow + */ + @POST + @Path("/trigger/scraper-import") + public Response triggerScraperImport() { + try { + scheduler.importScraperData(); + return Response.ok(Map.of("message", "Scraper import triggered successfully")).build(); + } catch (Exception e) { + LOG.error("Failed to trigger scraper import", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * POST /api/monitor/trigger/image-processing + * Manually trigger image processing workflow + */ + @POST + @Path("/trigger/image-processing") + public Response triggerImageProcessing() { + try { + scheduler.processImages(); + return Response.ok(Map.of("message", "Image processing triggered successfully")).build(); + } catch (Exception e) { + LOG.error("Failed to trigger image processing", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * POST /api/monitor/trigger/bid-monitoring + * Manually trigger bid monitoring workflow + */ + @POST + @Path("/trigger/bid-monitoring") + public Response triggerBidMonitoring() { + try { + scheduler.monitorBids(); + return Response.ok(Map.of("message", "Bid monitoring triggered successfully")).build(); + } catch (Exception e) { + LOG.error("Failed to trigger bid monitoring", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * POST /api/monitor/trigger/closing-alerts + * Manually trigger closing alerts workflow + */ + @POST + @Path("/trigger/closing-alerts") + public Response triggerClosingAlerts() { + try { + scheduler.checkClosingTimes(); + return Response.ok(Map.of("message", "Closing alerts triggered successfully")).build(); + } catch (Exception e) { + LOG.error("Failed to trigger closing alerts", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * GET /api/monitor/auctions + * Returns list of all auctions + */ + @GET + @Path("/auctions") + public Response getAuctions(@QueryParam("country") String country) { + try { + var auctions = country != null && !country.isEmpty() + ? db.getAuctionsByCountry(country) + : db.getAllAuctions(); + + return Response.ok(auctions).build(); + } catch (Exception e) { + LOG.error("Failed to get auctions", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * GET /api/monitor/lots + * Returns list of active lots + */ + @GET + @Path("/lots") + public Response getActiveLots() { + try { + var lots = db.getActiveLots(); + return Response.ok(lots).build(); + } catch (Exception e) { + LOG.error("Failed to get lots", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * GET /api/monitor/lots/closing-soon + * Returns lots closing within specified minutes (default 30) + */ + @GET + @Path("/lots/closing-soon") + public Response getLotsClosingSoon(@QueryParam("minutes") @DefaultValue("30") int minutes) { + try { + var allLots = db.getActiveLots(); + var closingSoon = allLots.stream() + .filter(lot -> lot.closingTime() != null && lot.minutesUntilClose() < minutes) + .toList(); + + return Response.ok(closingSoon).build(); + } catch (Exception e) { + LOG.error("Failed to get closing lots", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * GET /api/monitor/lots/{lotId}/images + * Returns images for a specific lot + */ + @GET + @Path("/lots/{lotId}/images") + public Response getLotImages(@PathParam("lotId") int lotId) { + try { + var images = db.getImagesForLot(lotId); + return Response.ok(images).build(); + } catch (Exception e) { + LOG.error("Failed to get lot images", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * POST /api/monitor/test-notification + * Send a test notification + */ + @POST + @Path("/test-notification") + public Response sendTestNotification(Map request) { + try { + var message = request.getOrDefault("message", "Test notification from Auction Monitor"); + var title = request.getOrDefault("title", "Test Notification"); + var priority = Integer.parseInt(request.getOrDefault("priority", "0")); + + notifier.sendNotification(message, title, priority); + + return Response.ok(Map.of("message", "Test notification sent successfully")).build(); + } catch (Exception e) { + LOG.error("Failed to send test notification", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * GET /api/monitor/rate-limit/stats + * Returns HTTP rate limiting statistics for all hosts + */ + @GET + @Path("/rate-limit/stats") + public Response getRateLimitStats() { + try { + var stats = httpClient.getAllStats(); + + Map response = new HashMap<>(); + response.put("hosts", stats.size()); + + Map hostStats = new HashMap<>(); + for (var entry : stats.entrySet()) { + var stat = entry.getValue(); + hostStats.put(entry.getKey(), Map.of( "totalRequests", stat.getTotalRequests(), "successfulRequests", stat.getSuccessfulRequests(), "failedRequests", stat.getFailedRequests(), "rateLimitedRequests", stat.getRateLimitedRequests(), "averageDurationMs", stat.getAverageDurationMs() - )); - } - response.put("statistics", hostStats); - - return Response.ok(response).build(); - - } catch (Exception e) { - LOG.error("Failed to get rate limit stats", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } - - /** - * GET /api/monitor/rate-limit/stats/{host} - * Returns HTTP rate limiting statistics for a specific host - */ - @GET - @Path("/rate-limit/stats/{host}") - public Response getRateLimitStatsForHost(@PathParam("host") String host) { - try { - var stat = httpClient.getStats(host); - - if (stat == null) { - return Response.status(Response.Status.NOT_FOUND) - .entity(Map.of("error", "No statistics found for host: " + host)) - .build(); - } - - Map response = Map.of( - "host", stat.getHost(), - "totalRequests", stat.getTotalRequests(), - "successfulRequests", stat.getSuccessfulRequests(), - "failedRequests", stat.getFailedRequests(), - "rateLimitedRequests", stat.getRateLimitedRequests(), - "averageDurationMs", stat.getAverageDurationMs() - ); - - return Response.ok(response).build(); - - } catch (Exception e) { - LOG.error("Failed to get rate limit stats for host", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } + )); + } + response.put("statistics", hostStats); + + return Response.ok(response).build(); + + } catch (Exception e) { + LOG.error("Failed to get rate limit stats", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } + + /** + * GET /api/monitor/rate-limit/stats/{host} + * Returns HTTP rate limiting statistics for a specific host + */ + @GET + @Path("/rate-limit/stats/{host}") + public Response getRateLimitStatsForHost(@PathParam("host") String host) { + try { + var stat = httpClient.getStats(host); + + if (stat == null) { + return Response.status(Response.Status.NOT_FOUND) + .entity(Map.of("error", "No statistics found for host: " + host)) + .build(); + } + + Map response = Map.of( + "host", stat.getHost(), + "totalRequests", stat.getTotalRequests(), + "successfulRequests", stat.getSuccessfulRequests(), + "failedRequests", stat.getFailedRequests(), + "rateLimitedRequests", stat.getRateLimitedRequests(), + "averageDurationMs", stat.getAverageDurationMs() + ); + + return Response.ok(response).build(); + + } catch (Exception e) { + LOG.error("Failed to get rate limit stats for host", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(Map.of("error", e.getMessage())) + .build(); + } + } } diff --git a/src/main/java/auctiora/DatabaseService.java b/src/main/java/auctiora/DatabaseService.java index dbafd8d..94303bc 100644 --- a/src/main/java/auctiora/DatabaseService.java +++ b/src/main/java/auctiora/DatabaseService.java @@ -1,6 +1,10 @@ package auctiora; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; import lombok.extern.slf4j.Slf4j; +import org.eclipse.microprofile.config.inject.ConfigProperty; + import java.io.Console; import java.sql.DriverManager; import java.sql.SQLException; @@ -16,9 +20,9 @@ import java.util.List; */ @Slf4j public class DatabaseService { - + private final String url; - + DatabaseService(String dbPath) { this.url = "jdbc:sqlite:" + dbPath; } @@ -43,7 +47,7 @@ public class DatabaseService { closing_time TEXT, discovered_at INTEGER )"""); - + // Lots table (populated by external scraper) stmt.execute(""" CREATE TABLE IF NOT EXISTS lots ( @@ -62,7 +66,7 @@ public class DatabaseService { closing_notified INTEGER DEFAULT 0, FOREIGN KEY (sale_id) REFERENCES auctions(auction_id) )"""); - + // Images table (populated by this process) stmt.execute(""" CREATE TABLE IF NOT EXISTS images ( @@ -74,13 +78,40 @@ public class DatabaseService { processed_at INTEGER, FOREIGN KEY (lot_id) REFERENCES lots(lot_id) )"""); - + + // Migrate existing tables to add missing columns + migrateSchema(stmt); + // Indexes for performance stmt.execute("CREATE INDEX IF NOT EXISTS idx_auctions_country ON auctions(country)"); stmt.execute("CREATE INDEX IF NOT EXISTS idx_lots_sale_id ON lots(sale_id)"); stmt.execute("CREATE INDEX IF NOT EXISTS idx_images_lot_id ON images(lot_id)"); } } + + /** + * Migrates existing database schema to add new columns. + * SQLite doesn't support DROP COLUMN, so we add columns with ALTER TABLE ADD COLUMN. + */ + private void migrateSchema(java.sql.Statement stmt) throws SQLException { + // Check if country column exists in auctions table + try (var rs = stmt.executeQuery("PRAGMA table_info(auctions)")) { + boolean hasCountry = false; + while (rs.next()) { + if ("country".equals(rs.getString("name"))) { + hasCountry = true; + break; + } + } + if (!hasCountry) { + log.info("Migrating schema: Adding 'country' column to auctions table"); + stmt.execute("ALTER TABLE auctions ADD COLUMN country TEXT"); + } + } catch (SQLException e) { + // Table might not exist yet, which is fine + log.debug("Could not check auctions table schema: " + e.getMessage()); + } + } /** * Inserts or updates an auction record (typically called by external scraper) @@ -355,7 +386,7 @@ public class DatabaseService { } } catch (SQLException e) { // Table might not exist in scraper format - that's ok - IO.println("ℹ️ Scraper auction table not found or incompatible schema"); + log.info("ℹ️ Scraper auction table not found or incompatible schema"); } return imported; diff --git a/src/main/java/auctiora/ImageProcessingService.java b/src/main/java/auctiora/ImageProcessingService.java index 9053535..7b65eb1 100644 --- a/src/main/java/auctiora/ImageProcessingService.java +++ b/src/main/java/auctiora/ImageProcessingService.java @@ -1,5 +1,8 @@ package auctiora; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.nio.file.Files; @@ -16,11 +19,11 @@ import java.util.List; */ @Slf4j class ImageProcessingService { - + private final RateLimitedHttpClient httpClient; private final DatabaseService db; private final ObjectDetectionService detector; - + ImageProcessingService(DatabaseService db, ObjectDetectionService detector, RateLimitedHttpClient httpClient) { this.httpClient = httpClient; this.db = db; diff --git a/src/main/java/auctiora/NotificationService.java b/src/main/java/auctiora/NotificationService.java index 8f9fc86..da0acfa 100644 --- a/src/main/java/auctiora/NotificationService.java +++ b/src/main/java/auctiora/NotificationService.java @@ -1,5 +1,9 @@ package auctiora; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.eclipse.microprofile.config.inject.ConfigProperty; + import javax.mail.*; import javax.mail.internet.*; import lombok.extern.slf4j.Slf4j; @@ -9,9 +13,9 @@ import java.util.Properties; @Slf4j public class NotificationService { - + private final Config config; - + public NotificationService(String cfg) { this.config = Config.parse(cfg); } diff --git a/src/main/java/auctiora/ObjectDetectionService.java b/src/main/java/auctiora/ObjectDetectionService.java index 746973d..64ce683 100644 --- a/src/main/java/auctiora/ObjectDetectionService.java +++ b/src/main/java/auctiora/ObjectDetectionService.java @@ -1,5 +1,9 @@ package auctiora; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.eclipse.microprofile.config.inject.ConfigProperty; + import lombok.extern.slf4j.Slf4j; import org.opencv.core.Mat; import org.opencv.core.Scalar; @@ -29,11 +33,11 @@ import static org.opencv.dnn.Dnn.DNN_TARGET_CPU; */ @Slf4j public class ObjectDetectionService { - + private final Net net; private final List classNames; private final boolean enabled; - + ObjectDetectionService(String cfgPath, String weightsPath, String classNamesPath) throws IOException { // Check if model files exist var cfgFile = Paths.get(cfgPath); diff --git a/src/test/java/auctiora/IntegrationTest.java b/src/test/java/auctiora/IntegrationTest.java index 95e5df0..4df7579 100644 --- a/src/test/java/auctiora/IntegrationTest.java +++ b/src/test/java/auctiora/IntegrationTest.java @@ -47,8 +47,8 @@ class IntegrationTest { "non_existent.weights", "non_existent.txt" ); - - RateLimitedHttpClient httpClient = new RateLimitedHttpClient(); + + var httpClient = new RateLimitedHttpClient(); imageProcessor = new ImageProcessingService(db, detector, httpClient); monitor = new TroostwijkMonitor( @@ -170,8 +170,8 @@ class IntegrationTest { db.updateLotCurrentBid(updatedLot); // Send notification - String message = String.format("Nieuw bod op kavel %d: €%.2f (was €%.2f)", - lot.lotId(), 2000.00, 1500.00); + var message = String.format("Nieuw bod op kavel %d: €%.2f (was €%.2f)", + lot.lotId(), 2000.00, 1500.00); assertDoesNotThrow(() -> notifier.sendNotification(message, "Kavel bieding update", 0) @@ -212,7 +212,7 @@ class IntegrationTest { assertTrue(closingSoon.minutesUntilClose() < 5); // Send high-priority notification - String message = "Kavel " + closingSoon.lotId() + " sluit binnen 5 min."; + var message = "Kavel " + closingSoon.lotId() + " sluit binnen 5 min."; assertDoesNotThrow(() -> notifier.sendNotification(message, "Lot nearing closure", 1) ); @@ -281,7 +281,7 @@ class IntegrationTest { assertDoesNotThrow(() -> monitor.processPendingImages()); // Verify database integrity - int imageCount = db.getImageCount(); + var imageCount = db.getImageCount(); assertTrue(imageCount >= 0); } @@ -348,11 +348,11 @@ class IntegrationTest { assertTrue(allLabels.contains("excavator") || allLabels.contains("machinery")); // Simulate value estimation notification - String message = String.format( + var message = String.format( "Lot contains: %s\nEstimated value: €%,.2f", String.join(", ", allLabels), lot.currentBid() - ); + ); assertDoesNotThrow(() -> notifier.sendNotification(message, "Object Detected", 0) @@ -363,9 +363,9 @@ class IntegrationTest { @Order(9) @DisplayName("Integration: Handle rapid concurrent updates") void testConcurrentOperations() throws InterruptedException, SQLException { - Thread auctionThread = new Thread(() -> { + var auctionThread = new Thread(() -> { try { - for (int i = 0; i < 10; i++) { + for (var i = 0; i < 10; i++) { db.upsertAuction(new AuctionInfo( 60000 + i, "Concurrent Auction " + i, "Test, NL", "Test", "NL", "https://example.com/60" + i, "A1", 5, null @@ -375,10 +375,10 @@ class IntegrationTest { fail("Auction thread failed: " + e.getMessage()); } }); - - Thread lotThread = new Thread(() -> { + + var lotThread = new Thread(() -> { try { - for (int i = 0; i < 10; i++) { + for (var i = 0; i < 10; i++) { db.upsertLot(new Lot( 60000 + i, 70000 + i, "Concurrent Lot " + i, "Desc", "", "", 0, "Cat", 100.0 * i, "EUR", "https://example.com/70" + i, null, false @@ -397,14 +397,14 @@ class IntegrationTest { // Verify all were inserted var auctions = db.getAllAuctions(); var lots = db.getAllLots(); - - long auctionCount = auctions.stream() - .filter(a -> a.auctionId() >= 60000 && a.auctionId() < 60010) - .count(); - - long lotCount = lots.stream() - .filter(l -> l.lotId() >= 70000 && l.lotId() < 70010) - .count(); + + var auctionCount = auctions.stream() + .filter(a -> a.auctionId() >= 60000 && a.auctionId() < 60010) + .count(); + + var lotCount = lots.stream() + .filter(l -> l.lotId() >= 70000 && l.lotId() < 70010) + .count(); assertEquals(10, auctionCount); assertEquals(10, lotCount);