diff --git a/pom.xml b/pom.xml index 1d5c73b..09fed80 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ true target/jacoco-report/jacoco.xml - **/domain/**, **/config/**, **/*Exception.java, **/entity/** + **/domain/**, **/config/**, **/*Exception.java, **/entity/**, **/test/java/** @@ -105,6 +105,11 @@ quarkus-jacoco test + + io.quarkus + quarkus-junit5-mockito + test + diff --git a/src/main/java/nl/veenm/jobfindr/repository/EventRepository.java b/src/main/java/nl/veenm/jobfindr/repository/EventRepository.java index 5411e64..ee31559 100644 --- a/src/main/java/nl/veenm/jobfindr/repository/EventRepository.java +++ b/src/main/java/nl/veenm/jobfindr/repository/EventRepository.java @@ -3,10 +3,8 @@ package nl.veenm.jobfindr.repository; import io.quarkus.hibernate.orm.panache.PanacheRepository; import jakarta.enterprise.context.ApplicationScoped; import nl.veenm.jobfindr.domain.Event; -import nl.veenm.jobfindr.domain.VacatureDetail; @ApplicationScoped public class EventRepository implements PanacheRepository { - } diff --git a/src/main/java/nl/veenm/jobfindr/repository/VacatureDetailRepository.java b/src/main/java/nl/veenm/jobfindr/repository/VacatureDetailRepository.java index f1eb101..6fa6f7b 100644 --- a/src/main/java/nl/veenm/jobfindr/repository/VacatureDetailRepository.java +++ b/src/main/java/nl/veenm/jobfindr/repository/VacatureDetailRepository.java @@ -6,6 +6,5 @@ import nl.veenm.jobfindr.domain.VacatureDetail; @ApplicationScoped public class VacatureDetailRepository implements PanacheRepository { - } diff --git a/src/main/java/nl/veenm/jobfindr/repository/VacatureRepository.java b/src/main/java/nl/veenm/jobfindr/repository/VacatureRepository.java index 2aa5d12..738272a 100644 --- a/src/main/java/nl/veenm/jobfindr/repository/VacatureRepository.java +++ b/src/main/java/nl/veenm/jobfindr/repository/VacatureRepository.java @@ -4,15 +4,8 @@ import io.quarkus.hibernate.orm.panache.PanacheRepository; import jakarta.enterprise.context.ApplicationScoped; import nl.veenm.jobfindr.domain.Vacature; -import java.time.LocalDate; -import java.util.List; - @ApplicationScoped public class VacatureRepository implements PanacheRepository { - - public List findByDate(LocalDate date) { - return list("datum", date); - } } diff --git a/src/main/java/nl/veenm/jobfindr/resources/VacatureResource.java b/src/main/java/nl/veenm/jobfindr/resources/VacatureResource.java index 8c29b8b..d09c6a7 100644 --- a/src/main/java/nl/veenm/jobfindr/resources/VacatureResource.java +++ b/src/main/java/nl/veenm/jobfindr/resources/VacatureResource.java @@ -13,9 +13,13 @@ import java.util.List; @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class VacatureResource { - private static final org.jboss.logging.Logger logger = Logger.getLogger(VacatureService.class); + private static final org.jboss.logging.Logger logger = Logger.getLogger(VacatureResource.class); @Inject + public VacatureResource(VacatureService vacatureService) { + this.vacatureService = vacatureService; + } + VacatureService vacatureService; @GET @@ -25,7 +29,7 @@ public class VacatureResource { return vacatureService.getNewVacatures(); } - @GET + @PATCH @Path("/test") public void testEmails(){ logger.info("testEmails"); diff --git a/src/main/java/nl/veenm/jobfindr/services/EmailService.java b/src/main/java/nl/veenm/jobfindr/services/EmailService.java index 28b6a63..aecbc33 100644 --- a/src/main/java/nl/veenm/jobfindr/services/EmailService.java +++ b/src/main/java/nl/veenm/jobfindr/services/EmailService.java @@ -15,6 +15,11 @@ import java.util.List; public class EmailService { @Inject + public EmailService(Mailer mailer, EventService eventService) { + this.mailer = mailer; + this.eventService = eventService; + } + EventService eventService; private final String className = this.getClass().getSimpleName(); @@ -23,11 +28,8 @@ public class EmailService { private final Mailer mailer; - public EmailService(Mailer mailer) { - this.mailer = mailer; - } - public void stuurVacatureEmail(String recipient, List vacatures) { + String methodName = "stuurVacatureEmail"; // Bouw de HTML-inhoud van de e-mail StringBuilder emailBody = new StringBuilder(); emailBody.append("") @@ -76,12 +78,12 @@ public class EmailService { // Verstuur de e-mail met HTML-inhoud log.info("Sending email to " + recipient); - eventService.logInfo(className, "stuurVacatureEmail", "Sending email to " + recipient); + eventService.logInfo(className, methodName, "Sending email to " + recipient); try{ mailer.send(Mail.withHtml(recipient, subject, emailBody.toString())); - eventService.logSucces(className, "stuurVacatureEmail", "Email sent"); + eventService.logSucces(className, methodName, "Email sent"); } catch (Exception e) { - eventService.logError(className, "stuurVacatureEmail", "Sending email failed", e); + eventService.logError(className, methodName, "Sending email failed", e); } diff --git a/src/main/java/nl/veenm/jobfindr/services/VacatureService.java b/src/main/java/nl/veenm/jobfindr/services/VacatureService.java index 19f89e3..f99e435 100644 --- a/src/main/java/nl/veenm/jobfindr/services/VacatureService.java +++ b/src/main/java/nl/veenm/jobfindr/services/VacatureService.java @@ -18,21 +18,25 @@ import java.util.List; @ApplicationScoped public class VacatureService { - @Inject ScraperService scraperService; - @Inject EventService eventService; - @Inject EmailService emailService; - @Inject VacatureRepository vacatureRepository; - @Inject VacatureDetailRepository vacatureDetailRepository; + @Inject + public VacatureService(ScraperService scraperService, EventService eventService, EmailService emailService, VacatureRepository vacatureRepository, VacatureDetailRepository vacatureDetailRepository) { + this.scraperService = scraperService; + this.eventService = eventService; + this.emailService = emailService; + this.vacatureRepository = vacatureRepository; + this.vacatureDetailRepository = vacatureDetailRepository; + } + private static final Logger logger = Logger.getLogger(VacatureService.class); private final String className = this.getClass().getSimpleName(); @@ -46,8 +50,9 @@ public class VacatureService { @Transactional public void checkAndSendNewVacatures() { + String methodName = "checkAndSendNewVacatures"; logger.info("Checking for new vacatures"); - eventService.logInfo(className, "checkAndSendNewVacatures", "Checking for new vacatures"); + eventService.logInfo(className, methodName, "Checking for new vacatures"); LocalDate today = LocalDate.now(); List todayVacatures = getVacatures(); @@ -55,7 +60,7 @@ public class VacatureService { try { scraperService.getVacatureDetails(todayVacature); } catch (IOException e) { - eventService.logError(className, "checkAndSendNewVacatures", "checkAndSendNewVacatures failed", e); + eventService.logError(className, methodName, "checkAndSendNewVacatures failed", e); } }); @@ -76,10 +81,10 @@ public class VacatureService { emailService.stuurVacatureEmail("danthefranken@gmail.com", todayVacatures); emailService.stuurVacatureEmail("vanveenmel11@gmail.com", todayVacatures); logger.info("Nieuwe vacatures verstuurd en opgeslagen."); - eventService.logSucces(className, "checkAndSendNewVacatures", "Nieuwe vacatures verstuurd en opgeslagen."); + eventService.logSucces(className, methodName, "Nieuwe vacatures verstuurd en opgeslagen."); } else { logger.info("Geen nieuwe vacatures gevonden."); - eventService.logInfo(className, "checkAndSendNewVacatures", "Geen nieuwe vacatures gevonden."); + eventService.logInfo(className, methodName, "Geen nieuwe vacatures gevonden."); } } @@ -95,7 +100,7 @@ public class VacatureService { try { todayVacatures.addAll(scraperService.scrapeVacatures(url)); } catch (IOException e) { - throw new RuntimeException(e); + eventService.logError(className, "getVacatures", "getVacatures failed", e); } }); return todayVacatures; @@ -116,21 +121,22 @@ public class VacatureService { @Scheduled(cron = "0 0 0 * * ?") @Transactional public void cleanVacatures() { + String methodName = "cleanVacatures"; logger.info("Cleaning vacatures"); - eventService.logInfo(className, "cleanVacatures", "Cleaning vacatures"); + eventService.logInfo(className, methodName, "Cleaning vacatures"); getAllVacatures().forEach(vacature -> { var date = vacature.getClosingDate(); var today = LocalDate.now(); if (date.isBefore(today)) { logger.info("Deleting vacature " + vacature.getTitel()); - eventService.logInfo(className, "cleanVacatures", "Deleting vacature " + vacature.getTitel()); + eventService.logInfo(className, methodName, "Deleting vacature " + vacature.getTitel()); vacatureDetailRepository.delete(vacature.getDetail()); vacatureRepository.delete(vacature); } }); logger.info("Cleaning vacatures done"); - eventService.logSucces(className, "cleanVacatures", "Cleaning vacatures done"); + eventService.logSucces(className, methodName, "Cleaning vacatures done"); } } diff --git a/src/main/java/nl/veenm/jobfindr/util/EventService.java b/src/main/java/nl/veenm/jobfindr/util/EventService.java index 24291c5..7e1bb3c 100644 --- a/src/main/java/nl/veenm/jobfindr/util/EventService.java +++ b/src/main/java/nl/veenm/jobfindr/util/EventService.java @@ -13,6 +13,10 @@ import java.time.Instant; public class EventService { @Inject + public EventService(EventRepository eventRepository) { + this.eventRepository = eventRepository; + } + EventRepository eventRepository; @Transactional diff --git a/src/test/java/nl/veenm/jobfindr/resources/VacatureResourceTest.java b/src/test/java/nl/veenm/jobfindr/resources/VacatureResourceTest.java new file mode 100644 index 0000000..d3137d1 --- /dev/null +++ b/src/test/java/nl/veenm/jobfindr/resources/VacatureResourceTest.java @@ -0,0 +1,63 @@ +package nl.veenm.jobfindr.resources; + +import nl.veenm.jobfindr.domain.Vacature; +import nl.veenm.jobfindr.services.VacatureService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class VacatureResourceTest { + + @Mock + VacatureService vacatureService; + + @InjectMocks + VacatureResource vacatureResource; + + @Test + void getNewVacatures_ReturnsListFromService() { + List expectedVacatures = List.of(new Vacature(), new Vacature()); + when(vacatureService.getNewVacatures()).thenReturn(expectedVacatures); + + List result = vacatureResource.getNewVacatures(); + + assertEquals(2, result.size()); + assertEquals(expectedVacatures, result); + verify(vacatureService).getNewVacatures(); + } + + @Test + void testEmails_CallsCheckAndSendNewVacatures() { + vacatureResource.testEmails(); + + verify(vacatureService).checkAndSendNewVacatures(); + } + + @Test + void getAllVacatures_ReturnsListFromService() { + List expectedVacatures = List.of(new Vacature()); + when(vacatureService.getAllVacatures()).thenReturn(expectedVacatures); + + List result = vacatureResource.getAllVacatures(); + + assertEquals(1, result.size()); + assertEquals(expectedVacatures, result); + verify(vacatureService).getAllVacatures(); + } + + @Test + void cleanVacatures_CallsCleanVacaturesOnService() { + vacatureResource.cleanVacatures(); + + verify(vacatureService).cleanVacatures(); + } +} \ No newline at end of file diff --git a/src/test/java/nl/veenm/jobfindr/scrapers/ScraperServiceTest.java b/src/test/java/nl/veenm/jobfindr/scrapers/ScraperServiceTest.java new file mode 100644 index 0000000..9474c08 --- /dev/null +++ b/src/test/java/nl/veenm/jobfindr/scrapers/ScraperServiceTest.java @@ -0,0 +1,103 @@ +package nl.veenm.jobfindr.scrapers; + +import nl.veenm.jobfindr.domain.Vacature; +import org.jsoup.Connection; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class ScraperServiceTest { + + @InjectMocks + ScraperService scraperService; + + @Test + void getVacatureDetails_HaaltBeschrijvingEnDatumOp() throws IOException { + String detailHtml = "" + + "
0,8 FTE
" + + "
Sluitingsdatum: 15-04-2026
" + + ""; + Document mockDocument = Jsoup.parse(detailHtml); + + Connection mockConnection = mock(Connection.class); + when(mockConnection.get()).thenReturn(mockDocument); + + Vacature vacature = new Vacature("Test", "https://fake-url.com", "Apeldoorn"); + + try (MockedStatic mockedJsoup = mockStatic(Jsoup.class)) { + mockedJsoup.when(() -> Jsoup.connect("https://fake-url.com")).thenReturn(mockConnection); + + scraperService.getVacatureDetails(vacature); + + assertEquals("0,8 FTE
Sluitingsdatum: 15-04-2026
", vacature.getDescription()); + assertEquals(LocalDate.of(2026, 4, 15), vacature.getClosingDate()); + } + } + + @Test + void scrapeVacatures_HaaltLijstOpEnFiltertOnbekendeLocaties() throws IOException { + String listHtml = "" + + "
" + + "
" + + "
Docent Geschiedenis
" + + " Link" + + "
" + + "
Apeldoorn
" + + "
" + + "
" + + "
" + + "
Docent Wiskunde
" + + " Link" + + "
" + + "
" + + ""; + + String detailHtml = "
Sluitingsdatum: 01-05-2026
"; + String mainUrl = "https://www.meesterbaan.nl/zoeken"; + + // FIX: We parsen de HTML nu hier, buiten het bereik van de mock! + Document listDocument = Jsoup.parse(listHtml); + Document detailDocument = Jsoup.parse(detailHtml); + + try (MockedStatic mockedJsoup = mockStatic(Jsoup.class)) { + mockedJsoup.when(() -> Jsoup.connect(anyString())).thenAnswer(invocation -> { + String url = invocation.getArgument(0); + Connection connection = mock(Connection.class); + + // We geven nu direct de kant-en-klare Document objecten terug + if (url.equals(mainUrl)) { + when(connection.get()).thenReturn(listDocument); + } else { + when(connection.get()).thenReturn(detailDocument); + } + return connection; + }); + + // Act + List results = scraperService.scrapeVacatures(mainUrl); + + // Assert + assertEquals(1, results.size()); + + Vacature v = results.getFirst(); + assertEquals("Docent Geschiedenis", v.getTitel()); + assertEquals("https://www.meesterbaan.nl/vacature/123", v.getUrl()); + assertEquals("Apeldoorn", v.getLocatie()); + assertEquals("Sluitingsdatum: 01-05-2026
", v.getDescription()); + assertEquals(LocalDate.of(2026, 5, 1), v.getClosingDate()); + } + } +} \ No newline at end of file diff --git a/src/test/java/nl/veenm/jobfindr/services/EmailServiceTest.java b/src/test/java/nl/veenm/jobfindr/services/EmailServiceTest.java new file mode 100644 index 0000000..ca2e551 --- /dev/null +++ b/src/test/java/nl/veenm/jobfindr/services/EmailServiceTest.java @@ -0,0 +1,78 @@ +package nl.veenm.jobfindr.services; + +import io.quarkus.mailer.Mail; +import io.quarkus.mailer.Mailer; +import nl.veenm.jobfindr.domain.Vacature; +import nl.veenm.jobfindr.util.EventService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class EmailServiceTest { + + @Mock + EventService eventService; + + @Mock + Mailer mailer; + + @InjectMocks + EmailService emailService; + + @Captor + ArgumentCaptor mailCaptor; + + @Test + void stuurVacatureEmail_VerstuurtEmailEnLogtSucces() { + Vacature vacature = mock(Vacature.class); + when(vacature.getTitel()).thenReturn("Java Developer"); + when(vacature.getDescription()).thenReturn("Mooie Quarkus rol"); + when(vacature.getUrl()).thenReturn("https://example.com/vacature/1"); + + emailService.stuurVacatureEmail("henk@example.com", List.of(vacature)); + + verify(eventService).logInfo("EmailService", "stuurVacatureEmail", "Sending email to henk@example.com"); + + verify(mailer).send(mailCaptor.capture()); + Mail capturedMail = mailCaptor.getValue(); + + assertEquals(1, capturedMail.getTo().size()); + assertEquals("henk@example.com", capturedMail.getTo().getFirst()); + + LocalDateTime now = LocalDateTime.now(); + String expectedDate = now.getDayOfMonth() + "-" + now.getMonthValue() + "-" + now.getYear(); + assertEquals("[" + expectedDate + "] Nieuwe vacatures gevonden", capturedMail.getSubject()); + + String htmlBody = capturedMail.getHtml(); + assertTrue(htmlBody.contains("Lieve Danthe")); + assertTrue(htmlBody.contains("Java Developer")); + assertTrue(htmlBody.contains("Mooie Quarkus rol")); + assertTrue(htmlBody.contains("https://example.com/vacature/1")); + + verify(eventService).logSucces("EmailService", "stuurVacatureEmail", "Email sent"); + } + + @Test + void stuurVacatureEmail_LogtErrorBijException() { + RuntimeException exception = new RuntimeException("Mail server down"); + doThrow(exception).when(mailer).send(any(Mail.class)); + + emailService.stuurVacatureEmail("henk@example.com", List.of()); + + verify(eventService).logInfo("EmailService", "stuurVacatureEmail", "Sending email to henk@example.com"); + verify(eventService).logError("EmailService", "stuurVacatureEmail", "Sending email failed", exception); + } +} \ No newline at end of file diff --git a/src/test/java/nl/veenm/jobfindr/services/VacatureServiceTest.java b/src/test/java/nl/veenm/jobfindr/services/VacatureServiceTest.java new file mode 100644 index 0000000..d1bc2a7 --- /dev/null +++ b/src/test/java/nl/veenm/jobfindr/services/VacatureServiceTest.java @@ -0,0 +1,189 @@ +package nl.veenm.jobfindr.services; + +import io.quarkus.hibernate.orm.panache.PanacheQuery; +import nl.veenm.jobfindr.domain.Vacature; +import nl.veenm.jobfindr.domain.VacatureDetail; +import nl.veenm.jobfindr.repository.VacatureDetailRepository; +import nl.veenm.jobfindr.repository.VacatureRepository; +import nl.veenm.jobfindr.scrapers.ScraperService; +import nl.veenm.jobfindr.util.EventService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class VacatureServiceTest { + + @Mock + ScraperService scraperService; + + @Mock + EventService eventService; + + @Mock + EmailService emailService; + + @Mock + VacatureRepository vacatureRepository; + + @Mock + VacatureDetailRepository vacatureDetailRepository; + + @InjectMocks + VacatureService vacatureService; + + @Captor + ArgumentCaptor emailCaptor; + + @Captor + ArgumentCaptor> listCaptor; + + @Test + void getNewVacatures() throws IOException { + Vacature v1 = new Vacature(); + when(scraperService.scrapeVacatures(anyString())).thenReturn(List.of(v1)); + + List result = vacatureService.getNewVacatures(); + + assertEquals(2, result.size()); + + // Geen eq() nodig omdat we exacte waarden doorgeven zonder matchers + verify(eventService).logInfo(VacatureService.class.getName(), "getServices", "getServices aangeroepen"); + + // Afvangen in plaats van eq() + verify(emailService).stuurVacatureEmail(emailCaptor.capture(), listCaptor.capture()); + assertEquals("vanveenmel11@gmail.com", emailCaptor.getValue()); + } + + @Test + @SuppressWarnings("unchecked") + void checkAndSendNewVacatures_WithNewVacatures() throws IOException { + Vacature newVacature = new Vacature(); + newVacature.setUrl("url1"); + + Vacature existingVacature = new Vacature(); + existingVacature.setUrl("url2"); + + when(scraperService.scrapeVacatures(anyString())).thenReturn(List.of(newVacature, existingVacature)); + + PanacheQuery query = mock(PanacheQuery.class); + when(vacatureRepository.findAll()).thenReturn(query); + when(query.stream()).thenReturn(Stream.of(existingVacature)); + + vacatureService.checkAndSendNewVacatures(); + + verify(scraperService, times(4)).getVacatureDetails(any(Vacature.class)); + verify(vacatureRepository, times(2)).persist(any(Vacature.class)); + + verify(emailService, times(2)).stuurVacatureEmail(emailCaptor.capture(), listCaptor.capture()); + assertEquals("vanveenmel11@gmail.com", emailCaptor.getValue()); + + verify(eventService).logSucces("VacatureService", "checkAndSendNewVacatures", "Nieuwe vacatures verstuurd en opgeslagen."); + } + + @Test + @SuppressWarnings("unchecked") + void checkAndSendNewVacatures_NoNewVacatures() throws IOException { + Vacature existingVacature = new Vacature(); + existingVacature.setUrl("url1"); + + when(scraperService.scrapeVacatures(anyString())).thenReturn(List.of(existingVacature)); + + PanacheQuery query = mock(PanacheQuery.class); + when(vacatureRepository.findAll()).thenReturn(query); + when(query.stream()).thenReturn(Stream.of(existingVacature)); + + vacatureService.checkAndSendNewVacatures(); + + verify(vacatureRepository, never()).persist(any(Vacature.class)); + // Omdat het nooit wordt aangeroepen, kunnen we hier wel any() en anyString() gebruiken + verify(emailService, never()).stuurVacatureEmail(anyString(), any()); + + verify(eventService).logInfo("VacatureService", "checkAndSendNewVacatures", "Geen nieuwe vacatures gevonden."); + } + + @Test + @SuppressWarnings("unchecked") + void checkAndSendNewVacatures_HandlesIOException() throws IOException { + Vacature vacature = new Vacature(); + vacature.setUrl("url1"); + + when(scraperService.scrapeVacatures(anyString())).thenReturn(List.of(vacature)); + + IOException exception = new IOException("Scrape failed"); + doThrow(exception).when(scraperService).getVacatureDetails(any(Vacature.class)); + + PanacheQuery query = mock(PanacheQuery.class); + when(vacatureRepository.findAll()).thenReturn(query); + when(query.stream()).thenReturn(Stream.empty()); + + vacatureService.checkAndSendNewVacatures(); + + // Pass the actual exception object directly + verify(eventService, times(2)).logError("VacatureService", "checkAndSendNewVacatures", "checkAndSendNewVacatures failed", exception); + } + + @Test + void getAllVacatures() { + List vacatures = List.of(new Vacature()); + when(vacatureRepository.listAll()).thenReturn(vacatures); + + List result = vacatureService.getAllVacatures(); + + assertEquals(1, result.size()); + verify(eventService).logInfo("VacatureService", "getAllVacatures", "fetching all vacatures"); + } + + @Test + void cleanVacatures() { + Vacature expired = new Vacature(); + expired.setTitel("Oude Vacature"); + expired.setClosingDate(LocalDate.now().minusDays(1)); + VacatureDetail detail = mock(VacatureDetail.class); + expired.setDetail(detail); + + Vacature valid = new Vacature(); + valid.setClosingDate(LocalDate.now().plusDays(1)); + + when(vacatureRepository.listAll()).thenReturn(List.of(expired, valid)); + + vacatureService.cleanVacatures(); + + verify(vacatureDetailRepository).delete(detail); + verify(vacatureRepository).delete(expired); + verify(vacatureRepository, never()).delete(valid); + + verify(eventService).logSucces("VacatureService", "cleanVacatures", "Cleaning vacatures done"); + } + + @Test + @SuppressWarnings("unchecked") + void dagelijksControleerEnVerstuur() { + PanacheQuery query = mock(PanacheQuery.class); + when(vacatureRepository.findAll()).thenReturn(query); + when(query.stream()).thenReturn(Stream.empty()); + + vacatureService.dagelijksControleerEnVerstuur(); + + verify(eventService).logInfo("VacatureService", "checkAndSendNewVacatures", "Checking for new vacatures"); + } +} \ No newline at end of file diff --git a/src/test/java/nl/veenm/jobfindr/util/EventServiceTest.java b/src/test/java/nl/veenm/jobfindr/util/EventServiceTest.java new file mode 100644 index 0000000..9e33aec --- /dev/null +++ b/src/test/java/nl/veenm/jobfindr/util/EventServiceTest.java @@ -0,0 +1,80 @@ +package nl.veenm.jobfindr.util; + +import nl.veenm.jobfindr.domain.Event; +import nl.veenm.jobfindr.repository.EventRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +class EventServiceTest { + + @Mock + EventRepository eventRepository; + + @InjectMocks + EventService eventService; + + @Captor + ArgumentCaptor eventCaptor; + + @Test + void testLogInfo_SavesInfoEvent() { + eventService.logInfo("MyClass", "myMethod", "Dit is een info bericht"); + + verify(eventRepository).persist(eventCaptor.capture()); + Event capturedEvent = eventCaptor.getValue(); + + assertNotNull(capturedEvent.getTimestamp()); + assertEquals("MyClass", capturedEvent.getClassName()); + assertEquals("myMethod", capturedEvent.getMethodName()); + assertEquals("Dit is een info bericht", capturedEvent.getMessage()); + assertEquals("INFO", capturedEvent.getLevel()); + } + + @Test + void testLogSucces_SavesSuccessEvent() { + eventService.logSucces("MyClass", "myMethod", "Dit is gelukt"); + + verify(eventRepository).persist(eventCaptor.capture()); + Event capturedEvent = eventCaptor.getValue(); + + assertNotNull(capturedEvent.getTimestamp()); + assertEquals("MyClass", capturedEvent.getClassName()); + assertEquals("myMethod", capturedEvent.getMethodName()); + assertEquals("Dit is gelukt", capturedEvent.getMessage()); + assertEquals("SUCCESS", capturedEvent.getLevel()); + } + + @Test + void testLogError_SavesErrorEventWithExceptionMessage() { + Exception dummyException = new RuntimeException("Database connectie verbroken"); + + eventService.logError("MyClass", "myMethod", "Er ging iets mis", dummyException); + + verify(eventRepository).persist(eventCaptor.capture()); + Event capturedEvent = eventCaptor.getValue(); + + assertNotNull(capturedEvent.getTimestamp()); + assertEquals("MyClass", capturedEvent.getClassName()); + assertEquals("myMethod", capturedEvent.getMethodName()); + assertEquals("Er ging iets mis", capturedEvent.getMessage()); + assertEquals("ERROR", capturedEvent.getLevel()); + assertEquals("Database connectie verbroken", capturedEvent.getError()); + } + + @Test + void testCleanEvents_CallsDeleteAll() { + eventService.cleanEvents(); + + verify(eventRepository).deleteAll(); + } +} \ No newline at end of file