From 9cf6052a809ab0d00eb00275d8d58bdfa2cb1f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=80=D0=BA=D0=BE=20=D0=94=D0=BE=D1=98=D0=BA?= =?UTF-8?q?=D0=B8=D1=9B?= Date: Sat, 2 Nov 2024 01:27:28 +0100 Subject: [PATCH] Corrected junit tests; Updated pom dependencies to latest; Updated project version, readme and changed Dockerfile to use supervisord and java 22 --- Dockerfile | 33 ++--- README.md | 2 +- pom.xml | 22 +-- .../DeveloperImpl.java | 14 +- .../config/SwaggerConfig.java | 6 +- .../util/Utilities.java | 8 +- .../web/DevelopersPageController.java | 4 +- .../web/MainController.java | 4 +- src/main/resources/banner.txt | 4 +- .../test/BaseTaskTest.java | 8 +- .../test/Config/GlobalSetupExtension.java | 21 --- ...twareDevelopmentSimulationAppBaseTest.java | 12 +- .../test/DeveloperTest.java | 3 +- .../test/DevelopersPageControllerTest.java | 7 +- ...DevelopmentTeamCreationParametersTest.java | 2 +- .../test/MainControllerTests.java | 15 ++- .../SoftwareDevelopmentSimulationAppTest.java | 127 +++++++++++++----- ...areDevelopmentSimulationAppTestsSuite.java | 1 + .../test/SwaggerTest.java | 49 +++++++ supervisord.conf | 10 ++ 20 files changed, 228 insertions(+), 124 deletions(-) delete mode 100644 src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/GlobalSetupExtension.java create mode 100644 src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SwaggerTest.java create mode 100644 supervisord.conf diff --git a/Dockerfile b/Dockerfile index f7e14c2..1dc5533 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build the Spring Boot application -FROM amazoncorretto:21-alpine AS build +FROM amazoncorretto:22-alpine-jdk AS build # Install necessary build tools RUN apk add --no-cache maven @@ -15,34 +15,37 @@ COPY src /app/src/ RUN mvn clean package -DskipTests # Stage 2: Create an image with RabbitMQ and your Spring Boot application -FROM rabbitmq:3.13.7-management-alpine AS final +FROM rabbitmq:management-alpine AS final # Install necessary runtime packages -RUN apk add --no-cache openjdk21-jdk \ +RUN apk add --no-cache openjdk22-jdk supervisor \ && rabbitmq-plugins enable --offline rabbitmq_mqtt \ - && rabbitmq-plugins enable --offline rabbitmq_web_mqtt + && rabbitmq-plugins enable --offline rabbitmq_web_mqtt \ + && addgroup -S runtimeUsers \ + && adduser -S runtimeUser -G runtimeUsers # Copy the Spring Boot application from the build stage -COPY --from=build /app/target/softwaredevelopmentsimulation-1.3.0.jar /app/software-development-simulation.jar +COPY --from=build /app/target/softwaredevelopmentsimulation-1.4.0.jar /app/software-development-simulation.jar + +#Use nonroot user to run application +USER runtimeUser + +# Supervisor configuration +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf # Add a health check for RabbitMQ HEALTHCHECK --interval=10s --timeout=3s --retries=3 \ - CMD nc -z localhost 5672 || exit 1 + CMD ["sh", "-c", "nc -z localhost 5672 || exit 1"] # Expose ports for RabbitMQ and Spring Boot application EXPOSE 5672 15672 15675 21682 -# Start RabbitMQ and wait for it to be ready before starting the Spring Boot application -CMD sh -c "rabbitmq-server & \ - until nc -z localhost 5672; do \ - echo 'Waiting for RabbitMQ...'; \ - sleep 1; \ - done; \ - java -jar /app/software-development-simulation.jar" +# Use supervisord to start and manage RabbitMQ and the Java application +ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] LABEL maintainer="Marko Dojkic " \ - version="1.3.0" \ + version="1.4.0" \ description="Docker image for the Software Development Simulation Spring Boot application" \ org.opencontainers.image.source="https://github.com/MarkoDojkic/Software-Development-Simulation" \ org.opencontainers.image.documentation="https://github.com/MarkoDojkic/Software-Development-Simulation#readme" \ - org.opencontainers.image.licenses="MIT" \ No newline at end of file + org.opencontainers.image.licenses="MIT" diff --git a/README.md b/README.md index 221f0c7..7bf2c59 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The Software Development Simulation project is a web-based application designed ## Features -- **Spring Boot Application**: Built with Spring Boot 3.3.3. +- **Spring Boot Application**: Built with Spring Boot 3.3.5. - **Spring Integration**: Configured with multiple channels for task management. - **Swagger Documentation**: Integrated for API documentation and testing. - **SonarQube Integration**: Quality and security analysis with all issues resolved. diff --git a/pom.xml b/pom.xml index 29efeea..79dcdb3 100755 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dev.markodojkic softwaredevelopmentsimulation Software development simulator™ - 1.3.0 + 1.4.0 https://github.com/MarkoDojkic/Software-Development-Simulation @@ -37,10 +37,10 @@ UTF-8 - 3.3.2 - 6.3.2 + 3.3.5 + 6.3.5 1.49.2 - 5.11.0 + 5.11.3 ${project.version} @@ -138,7 +138,7 @@ com.google.guava guava - 33.3.0-jre + 33.3.1-jre compile @@ -183,13 +183,13 @@ org.junit.platform junit-platform-suite-api - 1.11.0 + 1.11.3 test org.mockito mockito-junit-jupiter - 5.13.0 + 5.14.2 test @@ -248,8 +248,8 @@ maven-compiler-plugin 3.13.0 - 21 - 21 + 22 + 22 @@ -279,10 +279,10 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.5.1 - ${argLine} + ${argLine} -Dspring.profiles.active=test -Xshare:off -XX:+EnableDynamicAgentLoading diff --git a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/DeveloperImpl.java b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/DeveloperImpl.java index fdc5543..521ee05 100644 --- a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/DeveloperImpl.java +++ b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/DeveloperImpl.java @@ -17,6 +17,8 @@ @MessageEndpoint public class DeveloperImpl { private static final Logger logger = Logger.getLogger(DeveloperImpl.class.getName()); + public static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active"; + public static final String TEST = "test"; @ServiceActivator(inputChannel = "trivialTechnicalTask.intermediate", outputChannel = "doneTechnicalTasks.output") public TechnicalTask trivialTaskHandler(TechnicalTask technicalTask) { @@ -29,7 +31,7 @@ public TechnicalTask trivialTaskHandler(TechnicalTask technicalTask) { * (6 - technicalTask.getPriority().getUrgency()) / 5.0 * 0.01 + 1500) - , TimeUnit.MILLISECONDS); + , System.getProperty(SPRING_PROFILES_ACTIVE, "").equals(TEST) ? TimeUnit.NANOSECONDS : TimeUnit.MILLISECONDS); logger.log(Level.INFO, () -> colorize(String.format("%n###Developer %s finished working on trivial technical task %s", technicalTask.getAssignee().getDisplayName(), technicalTask.getId()), Attribute.TEXT_COLOR(0), Attribute.BACK_COLOR(technicalTask.getPriority().getAnsiColorCode()))); return technicalTask; } @@ -45,7 +47,7 @@ public TechnicalTask normalTaskHandler(TechnicalTask technicalTask) { * (6 - technicalTask.getPriority().getUrgency()) / 5.0 * 0.02 + 1500) - , TimeUnit.MILLISECONDS); + , System.getProperty(SPRING_PROFILES_ACTIVE, "").equals(TEST) ? TimeUnit.NANOSECONDS : TimeUnit.MILLISECONDS); logger.log(Level.INFO, () -> colorize(String.format("%n###Developer %s finished working on normal technical task %s", technicalTask.getAssignee().getDisplayName(), technicalTask.getId()), Attribute.TEXT_COLOR(0), Attribute.BACK_COLOR(technicalTask.getPriority().getAnsiColorCode()))); return technicalTask; } @@ -61,7 +63,7 @@ public TechnicalTask minorTaskHandler(TechnicalTask technicalTask) { * (6 - technicalTask.getPriority().getUrgency()) / 5.0 * 0.03 + 1500) - , TimeUnit.MILLISECONDS); + , System.getProperty(SPRING_PROFILES_ACTIVE, "").equals(TEST) ? TimeUnit.NANOSECONDS : TimeUnit.MILLISECONDS); logger.log(Level.INFO, () -> colorize(String.format("%n###Developer %s finished working on minor technical task %s", technicalTask.getAssignee().getDisplayName(), technicalTask.getId()), Attribute.TEXT_COLOR(0), Attribute.BACK_COLOR(technicalTask.getPriority().getAnsiColorCode()))); return technicalTask; } @@ -77,7 +79,7 @@ public TechnicalTask majorTaskHandler(TechnicalTask technicalTask) { * (6 - technicalTask.getPriority().getUrgency()) / 5.0 * 0.04 + 1500) - , TimeUnit.MILLISECONDS); + , System.getProperty(SPRING_PROFILES_ACTIVE, "").equals(TEST) ? TimeUnit.NANOSECONDS : TimeUnit.MILLISECONDS); logger.log(Level.INFO, () -> colorize(String.format("%n###Developer %s finished working on major technical task %s", technicalTask.getAssignee().getDisplayName(), technicalTask.getId()), Attribute.TEXT_COLOR(0), Attribute.BACK_COLOR(technicalTask.getPriority().getAnsiColorCode()))); return technicalTask; } @@ -93,7 +95,7 @@ public TechnicalTask criticalTaskHandler(TechnicalTask technicalTask) { * (6 - technicalTask.getPriority().getUrgency()) / 5.0 * 0.05 + 1500) - , TimeUnit.MILLISECONDS); + , System.getProperty(SPRING_PROFILES_ACTIVE, "").equals(TEST) ? TimeUnit.NANOSECONDS : TimeUnit.MILLISECONDS); logger.log(Level.INFO, () -> colorize(String.format("%n###Developer %s finished working on critical technical task %s", technicalTask.getAssignee().getDisplayName(), technicalTask.getId()), Attribute.TEXT_COLOR(0), Attribute.BACK_COLOR(technicalTask.getPriority().getAnsiColorCode()))); return technicalTask; } @@ -109,7 +111,7 @@ public TechnicalTask blockerTaskHandler(TechnicalTask technicalTask) { * (6 - technicalTask.getPriority().getUrgency()) / 5.0 * 0.06 + 1500) - , TimeUnit.MILLISECONDS); + , System.getProperty(SPRING_PROFILES_ACTIVE, "").equals(TEST) ? TimeUnit.NANOSECONDS : TimeUnit.MILLISECONDS); logger.log(Level.INFO, () -> colorize(String.format("%n###Developer %s finished working on blocker technical task %s", technicalTask.getAssignee().getDisplayName(), technicalTask.getId()), Attribute.TEXT_COLOR(0), Attribute.BACK_COLOR(technicalTask.getPriority().getAnsiColorCode()))); return technicalTask; } diff --git a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/config/SwaggerConfig.java b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/config/SwaggerConfig.java index 12a4a7d..fd911f9 100644 --- a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/config/SwaggerConfig.java +++ b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/config/SwaggerConfig.java @@ -16,8 +16,10 @@ public OpenAPI customOpenAPI() { return new OpenAPI() .info(new Info().title("Software development simulator™ API") .description("This is the API documentation for the Software development simulator™ Developed by Ⓒ Marko Dojkić") - .version("v1.3.0") - .license(new License().name("Apache 2.0").url("https://springdoc.org"))) + .version("v1.4.0") + .license(new License() + .name("MIT License") + .url("https://github.com/MarkoDojkic/Software-Development-Simulation/blob/main/LICENSE"))) .externalDocs(new ExternalDocumentation() .description("GitHub Repository") .url("https://github.com/MarkoDojkic/Software-Development-Simulation")); diff --git a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/util/Utilities.java b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/util/Utilities.java index 4c43bf9..2730503 100644 --- a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/util/Utilities.java +++ b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/util/Utilities.java @@ -66,10 +66,10 @@ public class Utilities { static { boolean isTesting = System.getProperty("spring.profiles.active", "default").equals("test"); - Path base = isTesting ? Paths.get("src/test/resources", "dev.markodojkic.software_development_simulation.testing_data") : Paths.get(System.getProperty("user.home"), "dev.markodojkic", "software_development_simulation", "1.3.0"); + Path base = isTesting ? Paths.get("src/test/resources", "dev.markodojkic.software_development_simulation.testing_data") : Paths.get(System.getProperty("user.home"), "dev.markodojkic", "software_development_simulation", "1.4.0"); currentApplicationDataPath = base; - currentApplicationLogsPath = Paths.get(String.valueOf(base), "logs", isTesting ? "2012-12-12 00:00:00" : ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss"))); + currentApplicationLogsPath = Paths.get(String.valueOf(base), "logs", isTesting ? "2012-12-12 00-00-00" : ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss"))); if(isTesting){ try { @@ -116,7 +116,7 @@ public static void loadPredefinedTasks(List predefinedEpics){ public static void generateRandomEpics(boolean save, int epicCountDownLimit, int epicCountUpperLimit){ List epicList = new ArrayList<>(); AtomicReference jiraEpicCreatedOutput = new AtomicReference<>(Strings.EMPTY); - totalEpicsCount = (epicCountDownLimit == 0 && epicCountUpperLimit == 0) ? 0 : SECURE_RANDOM.nextInt(epicCountDownLimit,epicCountUpperLimit); + totalEpicsCount = epicCountDownLimit == epicCountUpperLimit ? epicCountDownLimit : SECURE_RANDOM.nextInt(epicCountUpperLimit - epicCountDownLimit + 1) + epicCountDownLimit; getAvailableDevelopmentTeamIds().addAll(IntStream.rangeClosed(0, getCurrentDevelopmentTeamsSetup().size() - 1).boxed().collect(Collectors.toCollection(ArrayList::new))); totalDevelopmentTeamsPresent = getCurrentDevelopmentTeamsSetup().size(); @@ -214,7 +214,7 @@ public static void addEpicForSaving(Epic epic) { public static void saveEpics(){ try { - String folderName = System.getProperty("spring.profiles.active", "default").equals("test") ? "2012-12-12 00:00:00" : ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss")); + String folderName = System.getProperty("spring.profiles.active", "default").equals("test") ? "2012-12-12 00-00-00" : ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss")); Path parentDirectory = Utilities.getCurrentApplicationDataPath().resolve(PREDEFINED_DATA); Files.createDirectories(parentDirectory.resolve(folderName)); diff --git a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/DevelopersPageController.java b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/DevelopersPageController.java index 933ab60..ce32791 100755 --- a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/DevelopersPageController.java +++ b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/DevelopersPageController.java @@ -46,7 +46,7 @@ public ModelAndView getDevelopersPage(){ }) @GetMapping(value = "/developers/edit") public ModelAndView getEditingDeveloperForm(@RequestParam("developmentTeamIndex") int developmentTeamIndex, @RequestParam("developerIndex") int developerIndex){ - ModelAndView editingDeveloperForm = new ModelAndView("/developers::editingDeveloperForm"); //Warning is false positive: View is thymeleaf fragment contained in developersPage.html file + ModelAndView editingDeveloperForm = new ModelAndView("/developersPage::editingDeveloperForm"); //Warning is false positive: View is thymeleaf fragment contained in developersPage.html file editingDeveloperForm.addObject("developmentTeams", getCurrentDevelopmentTeamsSetup()); editingDeveloperForm.addObject("developmentTeamIndex", developmentTeamIndex); @@ -101,7 +101,7 @@ public String modifyDeveloper(@ModelAttribute(name = "formEditDeveloperPlacehold @DeleteMapping(value = "/api/deleteDeveloper") public ModelAndView deleteDeveloper(@RequestParam("developmentTeamIndex") int developmentTeamIndex, @RequestParam("developerIndex") int developerIndex){ removeDeveloper(developmentTeamIndex, developerIndex); - return null; //This call is used in async matter so no redirection is needed + return null; //This call is used in async manner so no redirection is needed } private String getBackgroundColor(String text) { diff --git a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/MainController.java b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/MainController.java index 7590f9a..1635c7a 100644 --- a/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/MainController.java +++ b/src/main/java/dev/markodojkic/softwaredevelopmentsimulation/web/MainController.java @@ -92,7 +92,7 @@ public ResponseEntity getPredefinedDataFoldersList() { @PostMapping(value = "/api/saveSessionData") public ResponseEntity saveCurrentPredefinedData(@RequestBody String sessionDataJSON){ try { - String folderName = System.getProperty("spring.profiles.active", "default").equals("test") ? "2012-12-12 00:00:00" : ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss")); + String folderName = System.getProperty("spring.profiles.active", "default").equals("test") ? "2012-12-12 00-00-00" : ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss")); Path parentDirectory = getCurrentApplicationDataPath().resolve(PREDEFINED_DATA); Files.createDirectories(parentDirectory.resolve(folderName)); @@ -150,6 +150,6 @@ public ResponseEntity applicationFlowPredefined(@RequestBody String pred @PostMapping(value = "/api/applicationFlowRandomized") public ModelAndView applicationFlowRandomized(@RequestParam(name = "save", defaultValue = "false", required = false) boolean save, @RequestParam("min") int min, @RequestParam("max") int max){ generateRandomEpics(save, min, max); - return null; //This call is used in async matter so no redirection is needed + return null; //This call is used in async manner so no redirection is needed } } \ No newline at end of file diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt index 1d39718..3e9a332 100644 --- a/src/main/resources/banner.txt +++ b/src/main/resources/banner.txt @@ -15,6 +15,6 @@ \__ \ | | | | | | |_| | | (_| | || (_) | | |___/_|_| |_| |_|\__,_|_|\__,_|\__\___/|_| -Version: ${application.version} -Powered by Spring Boot ${spring-boot.version} +Application version: ${application.version} +Powered by Spring Boot (v${spring-version}) and Spring Integration (v${spring-integration-version}) Ⓒ Marko Dojkić 2024 \ No newline at end of file diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/BaseTaskTest.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/BaseTaskTest.java index 9a93c46..a8c25fa 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/BaseTaskTest.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/BaseTaskTest.java @@ -4,10 +4,8 @@ import dev.markodojkic.softwaredevelopmentsimulation.enums.DeveloperType; import dev.markodojkic.softwaredevelopmentsimulation.model.BaseTask; import dev.markodojkic.softwaredevelopmentsimulation.model.Developer; -import dev.markodojkic.softwaredevelopmentsimulation.test.Config.GlobalSetupExtension; +import dev.markodojkic.softwaredevelopmentsimulation.test.Config.SoftwareDevelopmentSimulationAppBaseTest; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.context.SpringBootTest; import java.time.ZonedDateTime; @@ -15,9 +13,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@SpringBootTest -@ExtendWith(GlobalSetupExtension.class) -class BaseTaskTest { +class BaseTaskTest extends SoftwareDevelopmentSimulationAppBaseTest { @Test void when_noArgsConstructorIsCalled_correctValuesAreSetAsDefault() { BaseTask task = new BaseTask(); diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/GlobalSetupExtension.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/GlobalSetupExtension.java deleted file mode 100644 index 5f20ba1..0000000 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/GlobalSetupExtension.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.markodojkic.softwaredevelopmentsimulation.test.Config; - -import dev.markodojkic.softwaredevelopmentsimulation.util.Utilities; -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.extension.AfterAllCallback; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.ExtensionContext; - -import static dev.markodojkic.softwaredevelopmentsimulation.util.DataProvider.setupDataProvider; - -public class GlobalSetupExtension implements BeforeAllCallback, AfterAllCallback { - @Override - public void beforeAll(ExtensionContext extensionContext) { - setupDataProvider(); - } - - @Override - public void afterAll(ExtensionContext context) throws Exception { - FileUtils.deleteDirectory(Utilities.getCurrentApplicationDataPath().toAbsolutePath().toFile()); - } -} \ No newline at end of file diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/SoftwareDevelopmentSimulationAppBaseTest.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/SoftwareDevelopmentSimulationAppBaseTest.java index 7c15b15..3b61bb5 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/SoftwareDevelopmentSimulationAppBaseTest.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/Config/SoftwareDevelopmentSimulationAppBaseTest.java @@ -16,11 +16,10 @@ import dev.markodojkic.softwaredevelopmentsimulation.web.MainController; import io.moquette.broker.Server; import io.moquette.broker.config.MemoryConfig; +import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -36,11 +35,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; @SpringBootTest -@AutoConfigureMockMvc // Enables MockMvc with full context -//@ComponentScan(basePackages = "dev.markodojkic.softwaredevelopmentsimulation") +@AutoConfigureMockMvc(addFilters = false) // Enables MockMvc with full context @ContextConfiguration(classes = { MiscellaneousConfig.class, TestConfig.class, SpringIntegrationMessageChannelsConfig.class, MQTTFlow.class, PrintoutFlow.class, FileHandlingFlow.class, PrinterTransformer.class, DeveloperImpl.class, ProjectManagerImpl.class, MainController.class, DevelopersPageController.class }) -@ExtendWith(MockitoExtension.class) -@ExtendWith(GlobalSetupExtension.class) +//@ExtendWith({MockitoExtension.class, GlobalSetupExtension.class}) public abstract class SoftwareDevelopmentSimulationAppBaseTest { private static Server mqttServer; @@ -66,8 +63,9 @@ public static void preSetup() throws Exception { } @AfterAll - public static void tearDown() { + public static void tearDown() throws IOException { mqttServer.stopServer(); + FileUtils.deleteDirectory(Utilities.getCurrentApplicationDataPath().toAbsolutePath().toFile()); } @BeforeEach diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DeveloperTest.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DeveloperTest.java index 9292864..08738a6 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DeveloperTest.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DeveloperTest.java @@ -12,6 +12,7 @@ class DeveloperTest extends SoftwareDevelopmentSimulationAppBaseTest { private Developer developer; @BeforeEach + @Override public void setup() { developer = new Developer(); } @@ -52,7 +53,7 @@ void testGetDisplayName() { @Test void testToString() { - Developer developer = new Developer("123", "Bob", "Smith", "9876543210987", "Test area", DeveloperType.INTERN_DEVELOPER, 1L, false); + developer = new Developer("123", "Bob", "Smith", "9876543210987", "Test area", DeveloperType.INTERN_DEVELOPER, 1L, false); String expectedString = "Developer(id=123, name=Bob, surname=Smith, yugoslavianUMCN=9876543210987, placeOfBirth=Test area, developerType=INTERN_DEVELOPER, experienceCoefficient=1)"; assertEquals(expectedString, developer.toString()); diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopersPageControllerTest.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopersPageControllerTest.java index 8768234..e75a123 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopersPageControllerTest.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopersPageControllerTest.java @@ -31,6 +31,7 @@ class DevelopersPageControllerTest extends SoftwareDevelopmentSimulationAppBaseT private DeveloperControllerAdvice developerControllerAdvice; @BeforeEach + @Override public void setup() { new MockUp() { @Mock @@ -67,8 +68,10 @@ void when_getRequestIsSentToDevelopersEditEndpoint_editingDeveloperFormViewIsRet .param("developmentTeamIndex", "0") .param("developerIndex", "0")) .andExpect(status().isOk()) - .andExpect(view().name("/developers::editingDeveloperForm")) + .andExpect(view().name("/developersPage::editingDeveloperForm")) .andExpect(model().attributeExists("developmentTeams")) + .andExpect(model().attributeExists("developerTypes")) + .andExpect(model().attributeExists("formEditDeveloperPlaceholder")) .andExpect(model().attribute("developmentTeamIndex", 0)) .andExpect(model().attribute("developerIndex", 0)); } @@ -140,7 +143,7 @@ void when_getRequestIsSentToDevelopersEndpoint_developersPageViewIsReturned() th void when_nullValuesAreProvidedForDeveloper_defaultDataIsPopulatedUsingAdvice() { // Section 1: whenYugoslavianUMCNIsEmpty_thenItIsGenerated Developer developer = new Developer(); // Assuming Developer is your model class - DeveloperControllerAdvice developerControllerAdvice = new DeveloperControllerAdvice(); // Your controller advice instance + developerControllerAdvice = new DeveloperControllerAdvice(); // Your controller advice instance // Act Developer updatedDeveloper = developerControllerAdvice.overrideDeveloperFields(developer); diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopmentTeamCreationParametersTest.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopmentTeamCreationParametersTest.java index 7ac3f31..ece7721 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopmentTeamCreationParametersTest.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/DevelopmentTeamCreationParametersTest.java @@ -11,8 +11,8 @@ class DevelopmentTeamCreationParametersTest extends SoftwareDevelopmentSimulatio private DevelopmentTeamCreationParameters params; @BeforeEach + @Override public void setup() { - // Initialize the DevelopmentTeamCreationParameters instance before each test params = new DevelopmentTeamCreationParameters(); } diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/MainControllerTests.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/MainControllerTests.java index cc98f82..f7b684e 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/MainControllerTests.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/MainControllerTests.java @@ -13,6 +13,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.OpenOption; @@ -31,7 +32,7 @@ void whenShowFileContentsMethodIsCalled_withNonExistingFilePath_FileNotFoundErro mockMvc.perform(MockMvcRequestBuilders.get("/api/logs") .param("filename", "nonExistentTestFile")) .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(content().string(String.format("Error occurred while trying to read file: %s/nonExistentTestFile.log", Utilities.getCurrentApplicationLogsPath().toAbsolutePath()))); + .andExpect(content().string(String.format("Error occurred while trying to read file: %s%snonExistentTestFile.log", Utilities.getCurrentApplicationLogsPath().toAbsolutePath(), File.separator))); } @Test @@ -58,7 +59,9 @@ void when_getPredefinedDataFoldersListEndpointIsCalled() throws Exception { @Test void when_getPredefinedDataFoldersListEndpointIsCalled_withNonExistingFilePath_PathNotFoundErrorIsThrown() throws Exception { - FileUtils.deleteDirectory(Utilities.getCurrentApplicationDataPath().toAbsolutePath().toFile()); + try { + FileUtils.deleteDirectory(Utilities.getCurrentApplicationDataPath().toAbsolutePath().toFile()); + } catch (IOException ignore) { /* Ignored exception */ } mockMvc.perform(MockMvcRequestBuilders.get("/api/getPredefinedDataFoldersList").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isInternalServerError()); } @@ -71,7 +74,7 @@ void when_saveSessionDataEndpointIsCalled_savePredefinedData() throws Exception .contentType(MediaType.TEXT_PLAIN) .content(sessionDataJSON)) .andExpect(status().is2xxSuccessful()) - .andExpect(content().string("Data successfully saved to folder '2012-12-12 00:00:00'")); + .andExpect(content().string("Data successfully saved to folder '2012-12-12 00-00-00'")); } @Test @@ -97,7 +100,7 @@ public static Path writeString(Path path, CharSequence csq, OpenOption... option @Test void when_loadSessionDataEndpointIsCalled_loadPredefinedData() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/api/loadSessionData") - .param("folder", "2012-12-12 00:00:00")) + .param("folder", "2012-12-12 00-00-00")) .andExpect(status().is2xxSuccessful()) .andExpect(content().string("{\"key\":\"value\"}")); } @@ -105,9 +108,9 @@ void when_loadSessionDataEndpointIsCalled_loadPredefinedData() throws Exception @Test void when_loadSessionDataEndpointIsCalled_loadPredefinedData_withNonExistingFilePath_fileNotFoundErrorIsThrown() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/api/loadSessionData") - .param("folder", "2012-12-12 06:06:06")) + .param("folder", "2012-12-12 06-06-06")) .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(content().string(String.format("Error occurred while trying to load predefined data: %s/developersData.json", Utilities.getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 06:06:06")))); + .andExpect(content().string(String.format("Error occurred while trying to load predefined data: %s%sdevelopersData.json", Utilities.getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 06-06-06"), File.separator))); } @Test diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTest.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTest.java index d7376c8..6aaa65e 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTest.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTest.java @@ -26,6 +26,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -66,7 +67,7 @@ class SoftwareDevelopmentSimulationAppTest extends SoftwareDevelopmentSimulation void whenSendInfoMessageViaGateway_InformationInputChannelReceiveMessageWithSentPayload() { assertNotNull(informationMQTTInput); - CountDownLatch interceptorLatch = new CountDownLatch(1); + CountDownLatch informationMQTTInputLatch = new CountDownLatch(1); List infoMessages = new ArrayList<>(); @@ -74,7 +75,7 @@ void whenSendInfoMessageViaGateway_InformationInputChannelReceiveMessageWithSent @Override public Message preSend(Message message, MessageChannel channel) { infoMessages.add(message.getPayload().toString()); - interceptorLatch.countDown(); + informationMQTTInputLatch.countDown(); return ExecutorChannelInterceptor.super.preSend(message, channel); } }); @@ -85,10 +86,10 @@ public Message preSend(Message message, MessageChannel channel) { // Wait for interceptors to process messages try { - assertTrue(interceptorLatch.await(10, TimeUnit.MILLISECONDS)); + informationMQTTInputLatch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw new RuntimeException("Interrupted while waiting for interceptors to complete", e); + fail("Interrupted while waiting for interceptors to complete", e); } assertEquals(1, infoMessages.size()); @@ -105,10 +106,12 @@ void when_generateRandomEpics_epicsAreCorrectlyCreated() throws Exception { String originalOsName = System.getProperty("os.name"); System.setProperty("os.name", "generic"); assertNotNull(epicMessageInput); + assertNotNull(doneEpicsOutput); - CountDownLatch interceptorLatch = new CountDownLatch(4); + CountDownLatch epicMessageInputLatch = new CountDownLatch(4); + CountDownLatch epicMessageDoneLatch = new CountDownLatch(4); int epicCountDownLimit = 4; - int epicCountUpperLimit = 5; + int epicCountUpperLimit = 4; List epics = new ArrayList<>(); @@ -116,21 +119,21 @@ void when_generateRandomEpics_epicsAreCorrectlyCreated() throws Exception { @Override public Message preSend(Message message, MessageChannel channel) { epics.add((Epic) message.getPayload()); - interceptorLatch.countDown(); + epicMessageInputLatch.countDown(); return ExecutorChannelInterceptor.super.preSend(message, channel); } }); - mockMvc.perform(post("/api/applicationFlowRandomized").param("save", "true").param("min", String.valueOf(epicCountDownLimit)).param("max", String.valueOf(epicCountUpperLimit))).andExpect(status().is2xxSuccessful()); + mockMvc.perform(post("/api/applicationFlowRandomized").param("save", "false").param("min", String.valueOf(epicCountDownLimit)).param("max", String.valueOf(epicCountUpperLimit))).andExpect(status().is2xxSuccessful()); try { - assertTrue(interceptorLatch.await(10, TimeUnit.MILLISECONDS)); + epicMessageInputLatch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Interrupted while waiting for interceptors to complete", e); } - assertTrue(epics.size() >= epicCountDownLimit && epics.size() < epicCountUpperLimit); + assertTrue(epics.size() >= epicCountDownLimit && epics.size() <= epicCountUpperLimit); for (Epic epic : epics) { List userStories = epic.getUserStories(); @@ -145,12 +148,64 @@ public Message preSend(Message message, MessageChannel channel) { ((PriorityChannel) epicMessageInput).removeInterceptor(0); - Uninterruptibles.sleepUninterruptibly(5, TimeUnit.SECONDS); + ((DirectChannel) doneEpicsOutput).addInterceptor(new ExecutorChannelInterceptor() { + @Override + public Message preSend(Message message, MessageChannel channel) { + epicMessageDoneLatch.countDown(); + return ExecutorChannelInterceptor.super.preSend(message, channel); + } + }); + + try { + epicMessageDoneLatch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted while waiting for interceptors to complete", e); + } + + ((DirectChannel) doneEpicsOutput).removeInterceptor(0); + + assertFalse(Files.readString(getCurrentApplicationLogsPath().resolve("informationChannel.log")).isEmpty()); + assertFalse(Files.readString(getCurrentApplicationLogsPath().resolve("jiraActivityStreamChannel.log")).isEmpty()); + + assertFalse(Files.exists(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00-00-00").resolve("sessionData.json"))); + assertFalse(Files.exists(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00-00-00").resolve("developersData.json"))); + + System.setProperty("os.name", originalOsName); + } + + @Test + void when_generateRandomEpicsWithSave_epicsAreCorrectlyCreatedAndSaved() throws Exception { + Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS); + String originalOsName = System.getProperty("os.name"); + System.setProperty("os.name", "generic"); + assertNotNull(doneEpicsOutput); + + CountDownLatch epicMessageDoneLatch = new CountDownLatch(1); + int epicCountDownLimit = 1; + int epicCountUpperLimit = 1; + + mockMvc.perform(post("/api/applicationFlowRandomized").param("save", "true").param("min", String.valueOf(epicCountDownLimit)).param("max", String.valueOf(epicCountUpperLimit))).andExpect(status().is2xxSuccessful()); + + ((DirectChannel) doneEpicsOutput).addInterceptor(new ExecutorChannelInterceptor() { + @Override + public Message preSend(Message message, MessageChannel channel) { + epicMessageDoneLatch.countDown(); + return ExecutorChannelInterceptor.super.preSend(message, channel); + } + }); + + try { + epicMessageDoneLatch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted while waiting for interceptors to complete", e); + } assertFalse(Files.readString(getCurrentApplicationLogsPath().resolve("informationChannel.log")).isEmpty()); assertFalse(Files.readString(getCurrentApplicationLogsPath().resolve("jiraActivityStreamChannel.log")).isEmpty()); - assertFalse(Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00:00:00").resolve("sessionData.json")).isEmpty()); - assertFalse(Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00:00:00").resolve("developersData.json")).isEmpty()); + assertFalse(Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00-00-00").resolve("sessionData.json")).isEmpty()); + assertFalse(Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00-00-00").resolve("developersData.json")).isEmpty()); System.setProperty("os.name", originalOsName); } @@ -163,23 +218,16 @@ void when_predefinedDataIsUsed_correctApplicationFlowIsExpected() { assertNotNull(doneSprintUserStoriesOutput); assertNotNull(doneTechnicalTasksOutput); - CountDownLatch epicsInputInterceptorLatch = new CountDownLatch(1); - List epicsInput = new ArrayList<>(); - CountDownLatch epicsDoneInterceptorLatch = new CountDownLatch(1); + List epicsInput = new ArrayList<>(); List epicsDone = new ArrayList<>(); - - CountDownLatch userStoriesDoneInterceptorLatch = new CountDownLatch(2); List userStoriesDone = new ArrayList<>(); - - CountDownLatch technicalTasksDoneInterceptorLatch = new CountDownLatch(3); List technicalTasksDone = new ArrayList<>(); ((PriorityChannel) epicMessageInput).addInterceptor(new ExecutorChannelInterceptor() { @Override public Message preSend(Message message, MessageChannel channel) { epicsInput.add((Epic) message.getPayload()); - epicsInputInterceptorLatch.countDown(); return ExecutorChannelInterceptor.super.preSend(message, channel); } }); @@ -197,7 +245,6 @@ public Message preSend(Message message, MessageChannel channel) { @Override public Message preSend(Message message, MessageChannel channel) { userStoriesDone.add((UserStory) message.getPayload()); - userStoriesDoneInterceptorLatch.countDown(); return ExecutorChannelInterceptor.super.preSend(message, channel); } }); @@ -206,7 +253,6 @@ public Message preSend(Message message, MessageChannel channel) { @Override public Message preSend(Message message, MessageChannel channel) { technicalTasksDone.add((TechnicalTask) message.getPayload()); - technicalTasksDoneInterceptorLatch.countDown(); return ExecutorChannelInterceptor.super.preSend(message, channel); } }); @@ -215,7 +261,12 @@ public Message preSend(Message message, MessageChannel channel) { mockMvc.perform(MockMvcRequestBuilders.post("/api/applicationFlowPredefined").content(Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("testSessionData.json")).toURI())))).andExpect(status().is2xxSuccessful()); - Uninterruptibles.sleepUninterruptibly(30, TimeUnit.SECONDS); //Time needed to complete application flow with test data + try { + epicsDoneInterceptorLatch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted while waiting for interceptors to complete", e); + } for (Epic epic : epicsInput) { List userStories = epic.getUserStories(); @@ -244,11 +295,10 @@ public Message preSend(Message message, MessageChannel channel) { .contentType(MediaType.APPLICATION_JSON) .content(Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("testSessionData.json")).toURI())))) .andExpect(status().is2xxSuccessful()) - .andExpect(MockMvcResultMatchers.content().string("Data successfully saved to folder '2012-12-12 00:00:00'")); - + .andExpect(MockMvcResultMatchers.content().string("Data successfully saved to folder '2012-12-12 00-00-00'")); - assertEquals(Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("testSessionData.json")).toURI())), Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00:00:00").resolve("sessionData.json"))); - assertEquals(Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("testDevelopersData.json")).toURI())), Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00:00:00").resolve("developersData.json"))); + assertEquals(Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("testSessionData.json")).toURI())), Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00-00-00").resolve("sessionData.json"))); + assertEquals(Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("testDevelopersData.json")).toURI())), Files.readString(getCurrentApplicationDataPath().resolve("predefinedData").resolve("2012-12-12 00-00-00").resolve("developersData.json"))); } catch (Exception e) { fail(e.getCause()); } @@ -269,7 +319,7 @@ void when_emptyRandomizedDataIsUsed_applicationFlowPassesWithoutError() throws E .andExpect(status().is3xxRedirection()) .andExpect(redirectedUrl("/developers")); - mockMvc.perform(post("/api/applicationFlowRandomized").param("save", "true").param("min", String.valueOf(0)).param("max", String.valueOf(0))).andExpect(status().is2xxSuccessful()); + mockMvc.perform(post("/api/applicationFlowRandomized").param("save", "false").param("min", String.valueOf(0)).param("max", String.valueOf(0))).andExpect(status().is2xxSuccessful()); } @Test @@ -300,12 +350,19 @@ void when_emptyOrPartialPredefinedDataIsUsed_applicationFlowPassesWithoutError() void when_errorTextIsPassedToErrorChannel_errorApplicationFlowIsTriggered() throws IOException { getIGateways().sendToError("Some error message"); - Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS); + Uninterruptibles.sleepUninterruptibly(15, TimeUnit.SECONDS); + + String expectedWindows = """ + [38;5;196m/*\t- !ERROR! - + !-- Some error message + \t - !ERROR! - */\u001B[0m%$ + """.trim(); + String expectedOther = """ + [38;5;196m/* - !ERROR! - +  !-- Some error message +  - !ERROR! - */%$ + """.trim(); - assertTrue(Files.readString(getCurrentApplicationLogsPath().resolve("errorChannel.log")).contains(""" - \u001B[38;5;196m/*\t- !ERROR! -\u001B[0m - \u001B[38;5;196m !-- Some error message\u001B[0m - \u001B[38;5;196m\t - !ERROR! - */\u001B[0m%$ - """)); + assertEquals(System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH).contains("windows") ? expectedWindows : expectedOther, Files.readString(getCurrentApplicationLogsPath().resolve("errorChannel.log")).trim()); } } \ No newline at end of file diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTestsSuite.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTestsSuite.java index da7fc15..cd2eb0f 100644 --- a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTestsSuite.java +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SoftwareDevelopmentSimulationAppTestsSuite.java @@ -5,6 +5,7 @@ @Suite @SelectClasses({ + SwaggerTest.class, BaseTaskTest.class, DataProviderTest.class, DeveloperTest.class, diff --git a/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SwaggerTest.java b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SwaggerTest.java new file mode 100644 index 0000000..8bc6db3 --- /dev/null +++ b/src/test/java/dev/markodojkic/softwaredevelopmentsimulation/test/SwaggerTest.java @@ -0,0 +1,49 @@ +package dev.markodojkic.softwaredevelopmentsimulation.test; + +import dev.markodojkic.softwaredevelopmentsimulation.config.SwaggerConfig; +import io.swagger.v3.oas.models.ExternalDocumentation; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.junit.jupiter.api.Test; +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest +@Import(SwaggerConfig.class) // Import the Swagger configuration +class SwaggerTest { + @Autowired + private OpenAPI openAPI; + + @Autowired + private GroupedOpenApi groupedOpenApi; + + @Test + void testCustomOpenAPIConfig() { + Info info = openAPI.getInfo(); + assertEquals("Software development simulator™ API", info.getTitle()); + assertEquals("This is the API documentation for the Software development simulator™ Developed by Ⓒ Marko Dojkić", info.getDescription()); + assertEquals("v1.4.0", info.getVersion()); + + License license = info.getLicense(); + assertEquals("MIT License", license.getName()); + assertEquals("https://github.com/MarkoDojkic/Software-Development-Simulation/blob/main/LICENSE", license.getUrl()); + + ExternalDocumentation externalDocs = openAPI.getExternalDocs(); + assertEquals("GitHub Repository", externalDocs.getDescription()); + assertEquals("https://github.com/MarkoDojkic/Software-Development-Simulation", externalDocs.getUrl()); + } + + @Test + void testApiGroupConfig() { + // Verify that the GroupedOpenApi is set up with the correct group name and paths + assertEquals("api", groupedOpenApi.getGroup()); + assertEquals(List.of("/api/**"), groupedOpenApi.getPathsToMatch()); + } +} \ No newline at end of file diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 0000000..50702c2 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,10 @@ +[supervisord] +nodaemon=true + +[program:rabbitmq] +command=rabbitmq-server +autorestart=true + +[program:app] +command=sh -c "until nc -z localhost 5672; do echo 'Waiting for RabbitMQ...'; sleep 1; done; java -jar /app/software-development-simulation.jar" +autorestart=true