├── .gitignore ├── LICENSE ├── README.md ├── calculator-microservices ├── .gitignore ├── adder │ ├── .dockerignore │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── docker │ │ │ ├── Dockerfile.jvm │ │ │ └── Dockerfile.native │ │ ├── java │ │ │ └── com │ │ │ │ └── redhat │ │ │ │ └── training │ │ │ │ ├── AdderResource.java │ │ │ │ └── service │ │ │ │ ├── AdderService.java │ │ │ │ └── SolverService.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── resources │ │ │ │ └── index.html │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── redhat │ │ └── training │ │ └── AdderResourceTest.java ├── create-projects.sh ├── multiplier │ ├── .dockerignore │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── docker │ │ │ ├── Dockerfile.jvm │ │ │ └── Dockerfile.native │ │ ├── java │ │ │ └── com │ │ │ │ └── redhat │ │ │ │ └── training │ │ │ │ ├── MultiplierResource.java │ │ │ │ └── service │ │ │ │ ├── MultiplierService.java │ │ │ │ └── SolverService.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── resources │ │ │ │ └── index.html │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── redhat │ │ └── training │ │ └── MultiplierResourceTest.java ├── solver │ ├── .dockerignore │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── docker │ │ │ ├── Dockerfile.jvm │ │ │ └── Dockerfile.native │ │ ├── java │ │ │ └── com │ │ │ │ └── redhat │ │ │ │ └── training │ │ │ │ ├── SolverResource.java │ │ │ │ └── service │ │ │ │ ├── AdderService.java │ │ │ │ ├── MultiplierService.java │ │ │ │ └── SolverService.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── resources │ │ │ │ └── index.html │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── redhat │ │ └── training │ │ └── SolverResourceTest.java ├── start-dependant.sh └── start-locally.sh ├── calculator-monolith ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── kubefiles │ ├── application-template.yml │ └── security-scan-template.yml ├── mvnw ├── mvnw.cmd ├── pom.xml ├── scripts │ ├── build-and-push-image.sh │ ├── check-job-state.sh │ ├── include-container-extensions.sh │ └── redeploy.sh └── src │ ├── main │ └── java │ │ └── com │ │ └── redhat │ │ └── training │ │ ├── SolverResource.java │ │ ├── operation │ │ ├── Add.java │ │ ├── Identity.java │ │ ├── Operation.java │ │ └── Substract.java │ │ └── service │ │ └── SolverService.java │ └── test │ └── java │ └── com │ └── redhat │ └── training │ ├── SolverIT.java │ ├── SolverTest.java │ └── operation │ ├── AddTest.java │ └── SubstractTest.java ├── exchange-cli ├── .eslintrc.json ├── .gitignore ├── functional.spec.ts ├── jest-functional.config.js ├── jest.config.js ├── package-lock.json ├── package.json ├── src │ ├── convert.test.ts │ ├── convert.ts │ └── index.ts └── tsconfig.json ├── greeting-cd-pipeline ├── Dockerfile ├── Jenkinsfile ├── greet.js ├── server.js └── test.js ├── greeting-console ├── .dockerignore ├── .eslintrc ├── .gitignore ├── Dockerfile ├── Jenkinsfile ├── README.md ├── build.yml ├── greet.js ├── index.js ├── package-lock.json ├── package.json └── test │ └── greet.test.js ├── greeting-devsecops ├── Dockerfile ├── Jenkinsfile ├── greet.js ├── server.js └── test.js ├── greeting-service ├── .dockerignore ├── .eslintrc.json ├── .gitignore ├── Dockerfile ├── Jenkinsfile ├── README.md ├── greet.js ├── package-lock.json ├── package.json ├── server.js └── test │ └── greet.test.js ├── hello └── helloworld.py ├── home-automation-service ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── kubefiles │ └── application-template.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── docker │ │ ├── Dockerfile.fast-jar │ │ ├── Dockerfile.jvm │ │ └── Dockerfile.native │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── training │ │ │ └── home │ │ │ └── automation │ │ │ ├── .gitkeep │ │ │ ├── HomeAutomation.java │ │ │ ├── HomeResource.java │ │ │ ├── RoomConditions.java │ │ │ ├── lights │ │ │ ├── ConsoleLightSystem.java │ │ │ └── LightSystem.java │ │ │ └── rules │ │ │ ├── DaylightRule.java │ │ │ ├── InMemoryRulesRepository.java │ │ │ ├── PresenceRule.java │ │ │ ├── Rule.java │ │ │ └── RulesRepository.java │ └── resources │ │ ├── META-INF │ │ └── resources │ │ │ └── index.html │ │ └── application.properties │ └── test │ └── java │ └── com │ └── redhat │ └── training │ └── home │ └── automation │ ├── .gitkeep │ ├── HomeAutomationTest.java │ └── PresenceRuleTest.java ├── home-automation ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── docker │ │ ├── Dockerfile.fast-jar │ │ ├── Dockerfile.jvm │ │ └── Dockerfile.native │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── training │ │ │ └── home │ │ │ └── automation │ │ │ └── .gitkeep │ └── resources │ │ ├── META-INF │ │ └── resources │ │ │ └── index.html │ │ └── application.properties │ └── test │ └── java │ └── com │ └── redhat │ └── training │ └── home │ └── automation │ └── .gitkeep ├── jenkins-agents └── jenkins-agent-template.yml ├── school-library ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── docker │ │ ├── Dockerfile.fast-jar │ │ ├── Dockerfile.jvm │ │ └── Dockerfile.native │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── training │ │ │ ├── BookStats.java │ │ │ ├── Library.java │ │ │ ├── SchoolLibraryApp.java │ │ │ ├── books │ │ │ ├── Book.java │ │ │ └── BookNotAvailableException.java │ │ │ └── inventory │ │ │ ├── InMemoryInventory.java │ │ │ └── Inventory.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── redhat │ └── training │ ├── BookStatsTest.java │ ├── LibraryTest.java │ └── LibraryWithMockedInventoryTest.java ├── scoreboard ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── README.md ├── cypress.json ├── cypress │ ├── fixtures │ │ └── example.json │ ├── integration │ │ └── scoreboard.spec.ts │ ├── plugins │ │ └── index.js │ ├── support │ │ ├── commands.js │ │ └── index.js │ └── tsconfig.json ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── screenshot.png ├── src │ ├── App.test.tsx │ ├── App.tsx │ ├── Player.ts │ ├── ScoreDisplay.test.tsx │ ├── ScoreDisplay.tsx │ ├── __mocks__ │ │ └── ScoreDisplay.tsx │ ├── index.css │ ├── index.tsx │ ├── react-app-env.d.ts │ ├── serviceWorker.ts │ └── setupTests.ts └── tsconfig.json ├── shipping-calculator ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── docker │ │ ├── Dockerfile.fast-jar │ │ ├── Dockerfile.jvm │ │ └── Dockerfile.native │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── shipping │ │ │ └── .gitkeep │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── redhat │ └── shipping │ └── ShippingCalculatorTest.java ├── shopping-cart-v2 ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── .s2i │ └── environment ├── README.md ├── kubefiles │ └── application-template.yml ├── mvnw ├── mvnw.cmd ├── pom.xml ├── scripts │ ├── build-and-push-image.sh │ ├── deploy-image.sh │ ├── include-container-extensions.sh │ ├── redeploy.sh │ └── tag-exists-in-quay.sh └── src │ ├── main │ ├── docker │ │ ├── Dockerfile.fast-jar │ │ ├── Dockerfile.jvm │ │ └── Dockerfile.native │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── shopping │ │ │ ├── ShoppingCartResource.java │ │ │ ├── cart │ │ │ ├── AddToCartCommand.java │ │ │ ├── CartItem.java │ │ │ ├── CartService.java │ │ │ ├── CartView.java │ │ │ └── ProductNotInCartException.java │ │ │ └── catalog │ │ │ ├── Catalog.java │ │ │ ├── CatalogService.java │ │ │ ├── CatalogStorage.java │ │ │ ├── Product.java │ │ │ ├── ProductNotFoundInCatalogException.java │ │ │ └── persistence │ │ │ └── InMemoryCatalogStorage.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── redhat │ └── shopping │ ├── integration │ ├── blackbox │ │ ├── .gitkeep │ │ └── ShoppingCartTest.java │ └── whitebox │ │ ├── .gitkeep │ │ └── ShoppingCartTest.java │ └── unit │ ├── ProductMother.java │ ├── cart │ └── CartServiceTest.java │ └── catalog │ └── CatalogServiceTest.java ├── shopping-cart ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── docker │ │ ├── Dockerfile.fast-jar │ │ ├── Dockerfile.jvm │ │ └── Dockerfile.native │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── shopping │ │ │ ├── ShoppingCartResource.java │ │ │ ├── cart │ │ │ ├── AddToCartCommand.java │ │ │ ├── CartItem.java │ │ │ ├── CartService.java │ │ │ ├── CartView.java │ │ │ └── ProductNotInCartException.java │ │ │ └── catalog │ │ │ ├── Catalog.java │ │ │ ├── CatalogService.java │ │ │ ├── Product.java │ │ │ └── ProductNotFoundInCatalogException.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── redhat │ └── shopping │ └── integration │ ├── blackbox │ └── .gitkeep │ └── whitebox │ └── .gitkeep ├── simple-calculator ├── .dockerignore ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── kubefiles │ └── email-service.yaml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── docker │ │ ├── Dockerfile.fast-jar │ │ ├── Dockerfile.jvm │ │ └── Dockerfile.native │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── simple │ │ │ └── calculator │ │ │ ├── AdvancedCalculator.java │ │ │ └── BasicCalculator.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── redhat │ └── simple │ └── calculator │ ├── .gitkeep │ ├── AdvancedCalculatorTest.java │ └── BasicCalculatorTest.java ├── simple-webapp ├── backend │ ├── greet.js │ ├── server.js │ ├── test.js │ └── test_api.sh └── frontend │ ├── greet.js │ ├── index.html │ ├── main.js │ └── test.js ├── story-count ├── frankenstein.txt └── test-wc.sh └── tools ├── check.py ├── email-service.yml └── prometheus-template.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio Code 2 | .vscode 3 | 4 | # OSX 5 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DO400 Application Repository 2 | 3 | This repository contains applications used in the Red Hat training DO400 - 4 | Red Hat DevOps Pipelines and Processes: CI/CD with Jenkins, Git, and Test Driven Development (TDD). 5 | 6 | ## Issues 7 | 8 | Should you find any issues with the course applications, or have any general 9 | questions, file a new [issue](https://github.com/RedHatTraining/DO400-apps/issues/new). 10 | -------------------------------------------------------------------------------- /calculator-microservices/.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | .project 3 | -------------------------------------------------------------------------------- /calculator-microservices/adder/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* -------------------------------------------------------------------------------- /calculator-microservices/adder/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | 19 | # OSX 20 | .DS_Store 21 | 22 | # Vim 23 | *.swp 24 | *.swo 25 | 26 | # patch 27 | *.orig 28 | *.rej 29 | 30 | # Maven 31 | target/ 32 | pom.xml.tag 33 | pom.xml.releaseBackup 34 | pom.xml.versionsBackup 35 | release.properties -------------------------------------------------------------------------------- /calculator-microservices/adder/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/calculator-microservices/adder/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /calculator-microservices/adder/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /calculator-microservices/adder/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the docker image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/quarkus-adder-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/quarkus-adder-jvm 15 | # 16 | ### 17 | FROM fabric8/java-alpine-openjdk8-jre 18 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 19 | ENV AB_ENABLED=jmx_exporter 20 | COPY target/lib/* /deployments/lib/ 21 | COPY target/*-runner.jar /deployments/app.jar 22 | ENTRYPOINT [ "/deployments/run-java.sh" ] -------------------------------------------------------------------------------- /calculator-microservices/adder/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the docker image run: 5 | # 6 | # mvn package -Pnative -Dnative-image.docker-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/quarkus-adder . 11 | #8080 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/quarkus-adder 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal 18 | ENV JAEGER_SERVICE_NAME=adder\ 19 | JAEGER_ENDPOINT=http://jaeger-collector.istio-system.svc:14268/api/traces\ 20 | JAEGER_PROPAGATION=b3\ 21 | JAEGER_SAMPLER_TYPE=const\ 22 | JAEGER_SAMPLER_PARAM=1 23 | WORKDIR /work/ 24 | COPY target/*-runner /work/application 25 | RUN chmod 775 /work 26 | EXPOSE 8080 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] -------------------------------------------------------------------------------- /calculator-microservices/adder/src/main/java/com/redhat/training/AdderResource.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import org.eclipse.microprofile.rest.client.inject.RestClient; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.inject.Inject; 8 | import javax.ws.rs.*; 9 | import javax.ws.rs.core.MediaType; 10 | import javax.ws.rs.core.Response; 11 | 12 | import com.redhat.training.service.AdderService; 13 | import com.redhat.training.service.SolverService; 14 | 15 | @Path("/adder") 16 | public class AdderResource implements AdderService { 17 | 18 | final Logger log = LoggerFactory.getLogger(AdderResource.class); 19 | 20 | @Inject 21 | @RestClient 22 | SolverService solverService; 23 | 24 | @GET 25 | @Path("/{lhs}/{rhs}") 26 | @Produces(MediaType.TEXT_PLAIN) 27 | public Float add(@PathParam("lhs") String lhs, @PathParam("rhs") String rhs) { 28 | log.info("Adding {} to {}" ,lhs, rhs); 29 | return solverService.solve(lhs)+solverService.solve(rhs); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /calculator-microservices/adder/src/main/java/com/redhat/training/service/AdderService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.PathParam; 6 | import javax.ws.rs.Produces; 7 | import javax.ws.rs.core.MediaType; 8 | 9 | @Path("/adder") 10 | public interface AdderService { 11 | 12 | @GET 13 | @Path("/{lhs}/{rhs}") 14 | @Produces(MediaType.TEXT_PLAIN) 15 | Float add(@PathParam("lhs") String lhs, @PathParam("rhs") String rhs); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /calculator-microservices/adder/src/main/java/com/redhat/training/service/SolverService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import javax.ws.rs.GET; 5 | import javax.ws.rs.Path; 6 | import javax.ws.rs.PathParam; 7 | import javax.ws.rs.Produces; 8 | import javax.ws.rs.core.MediaType; 9 | 10 | import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; 11 | 12 | @Path("/solver") 13 | @ApplicationScoped 14 | @RegisterRestClient 15 | public interface SolverService { 16 | @GET 17 | @Path("{equation}") 18 | @Produces(MediaType.TEXT_PLAIN) 19 | Float solve(@PathParam("equation") String equation); 20 | } 21 | -------------------------------------------------------------------------------- /calculator-microservices/adder/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | quarkus.application.name=adder 2 | %dev.quarkus.http.port=8081 3 | 4 | com.redhat.training.service.SolverService/mp-rest/url=http://solver:8080 5 | com.redhat.training.service.AdderService/mp-rest/url=http://adder:8080 6 | com.redhat.training.service.MultiplierService/mp-rest/url=http://multiplier:8080 7 | %dev.com.redhat.training.service.SolverService/mp-rest/url=http://localhost:8080 8 | %dev.com.redhat.training.service.AdderService/mp-rest/url=http://localhost:8081 9 | %dev.com.redhat.training.service.MultiplierService/mp-rest/url=http://localhost:8082 10 | 11 | -------------------------------------------------------------------------------- /calculator-microservices/adder/src/test/java/com/redhat/training/AdderResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import com.redhat.training.service.SolverService; 4 | 5 | import org.eclipse.microprofile.rest.client.inject.RestClient; 6 | 7 | import io.quarkus.test.common.http.TestHTTPEndpoint; 8 | import io.quarkus.test.junit.QuarkusTest; 9 | import io.quarkus.test.junit.mockito.InjectMock; 10 | 11 | @QuarkusTest 12 | @TestHTTPEndpoint(AdderResource.class) 13 | public class AdderResourceTest { 14 | 15 | @InjectMock 16 | @RestClient 17 | SolverService solverService; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /calculator-microservices/create-projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ~/DO378/labs/apps-connect 4 | 5 | echo "Creating the 'adder' project " 6 | mvn io.quarkus:quarkus-maven-plugin:1.3.4.Final-redhat-00004:create \ 7 | -DprojectGroupId=com.redhat.training \ 8 | -DprojectArtifactId=adder \ 9 | -DplatformGroupId=com.redhat.quarkus \ 10 | -DplatformVersion=1.3.4.Final-redhat-00004 \ 11 | -DclassName="com.redhat.training.AdderResource" \ 12 | -Dpath="/adder" \ 13 | -Dextensions="rest-client" 14 | 15 | echo "Removing the test folder for the 'adder' project" 16 | rm -rf ./adder/src/test 17 | 18 | echo "Creating the 'multiplier' project " 19 | mvn io.quarkus:quarkus-maven-plugin:1.3.4.Final-redhat-00004:create \ 20 | -DprojectGroupId=com.redhat.training \ 21 | -DprojectArtifactId=multiplier \ 22 | -DplatformGroupId=com.redhat.quarkus \ 23 | -DplatformVersion=1.3.4.Final-redhat-00004 \ 24 | -DclassName="com.redhat.training.MultiplierResource" \ 25 | -Dpath="/multiplier" \ 26 | -Dextensions="rest-client" 27 | 28 | echo "Removing the test folder for the 'multiplier' project" 29 | rm -rf ./multiplier/src/test 30 | 31 | echo "All done." 32 | -------------------------------------------------------------------------------- /calculator-microservices/multiplier/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* -------------------------------------------------------------------------------- /calculator-microservices/multiplier/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | 19 | # OSX 20 | .DS_Store 21 | 22 | # Vim 23 | *.swp 24 | *.swo 25 | 26 | # patch 27 | *.orig 28 | *.rej 29 | 30 | # Maven 31 | target/ 32 | pom.xml.tag 33 | pom.xml.releaseBackup 34 | pom.xml.versionsBackup 35 | release.properties -------------------------------------------------------------------------------- /calculator-microservices/multiplier/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/calculator-microservices/multiplier/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /calculator-microservices/multiplier/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /calculator-microservices/multiplier/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the docker image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/quarkus-multiplier-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/quarkus-multiplier-jvm 15 | # 16 | ### 17 | FROM fabric8/java-alpine-openjdk8-jre 18 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 19 | ENV AB_ENABLED=jmx_exporter 20 | COPY target/lib/* /deployments/lib/ 21 | COPY target/*-runner.jar /deployments/app.jar 22 | ENTRYPOINT [ "/deployments/run-java.sh" ] -------------------------------------------------------------------------------- /calculator-microservices/multiplier/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the docker image run: 5 | # 6 | # mvn package -Pnative -Dnative-image.docker-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/quarkus-multiplier . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/quarkus-multiplier 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal 18 | ENV JAEGER_SERVICE_NAME=multiplier\ 19 | JAEGER_ENDPOINT=http://jaeger-collector.istio-system.svc:14268/api/traces\ 20 | JAEGER_PROPAGATION=b3\ 21 | JAEGER_SAMPLER_TYPE=const\ 22 | JAEGER_SAMPLER_PARAM=1 23 | WORKDIR /work/ 24 | COPY target/*-runner /work/application 25 | RUN chmod 775 /work 26 | EXPOSE 8080 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] -------------------------------------------------------------------------------- /calculator-microservices/multiplier/src/main/java/com/redhat/training/MultiplierResource.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import javax.inject.Inject; 4 | import javax.ws.rs.GET; 5 | import javax.ws.rs.Path; 6 | import javax.ws.rs.PathParam; 7 | import javax.ws.rs.Produces; 8 | import javax.ws.rs.core.MediaType; 9 | 10 | import com.redhat.training.service.MultiplierService; 11 | import com.redhat.training.service.SolverService; 12 | 13 | import org.eclipse.microprofile.rest.client.inject.RestClient; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | public class MultiplierResource implements MultiplierService { 18 | final Logger log = LoggerFactory.getLogger(MultiplierResource.class); 19 | 20 | SolverService solverService; 21 | 22 | @Inject 23 | public MultiplierResource( @RestClient SolverService solverService ) { 24 | this.solverService = solverService; 25 | } 26 | 27 | 28 | @GET 29 | @Path("/{lhs}/{rhs}") 30 | @Produces(MediaType.TEXT_PLAIN) 31 | public Float multiply(@PathParam("lhs") String lhs, @PathParam("rhs") String rhs) { 32 | log.info("Multiplying {} to {}" ,lhs, rhs); 33 | return solverService.solve(lhs)*solverService.solve(rhs); 34 | } 35 | } -------------------------------------------------------------------------------- /calculator-microservices/multiplier/src/main/java/com/redhat/training/service/MultiplierService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.PathParam; 6 | import javax.ws.rs.Produces; 7 | import javax.ws.rs.core.MediaType; 8 | 9 | @Path("/multiplier") 10 | public interface MultiplierService { 11 | 12 | @GET 13 | @Path("/{lhs}/{rhs}") 14 | @Produces(MediaType.TEXT_PLAIN) 15 | Float multiply(@PathParam("lhs") String lhs, @PathParam("rhs") String rhs); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /calculator-microservices/multiplier/src/main/java/com/redhat/training/service/SolverService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import javax.ws.rs.GET; 5 | import javax.ws.rs.Path; 6 | import javax.ws.rs.PathParam; 7 | import javax.ws.rs.Produces; 8 | import javax.ws.rs.core.MediaType; 9 | 10 | import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; 11 | 12 | @Path("/solver") 13 | @ApplicationScoped 14 | @RegisterRestClient 15 | public interface SolverService { 16 | @GET 17 | @Path("{equation}") 18 | @Produces(MediaType.TEXT_PLAIN) 19 | Float solve(@PathParam("equation") String equation); 20 | } 21 | -------------------------------------------------------------------------------- /calculator-microservices/multiplier/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | quarkus.application.name=multiplier 2 | %dev.quarkus.http.port=8082 3 | 4 | com.redhat.training.service.SolverService/mp-rest/url=http://solver:8080 5 | com.redhat.training.service.AdderService/mp-rest/url=http://adder:8080 6 | com.redhat.training.service.MultiplierService/mp-rest/url=http://multiplier:8080 7 | %dev.com.redhat.training.service.SolverService/mp-rest/url=http://localhost:8080 8 | %dev.com.redhat.training.service.AdderService/mp-rest/url=http://localhost:8081 9 | %dev.com.redhat.training.service.MultiplierService/mp-rest/url=http://localhost:8082 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /calculator-microservices/multiplier/src/test/java/com/redhat/training/MultiplierResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import static org.mockito.Mockito.mock; 4 | 5 | import com.redhat.training.service.SolverService; 6 | 7 | import org.junit.jupiter.api.BeforeEach; 8 | 9 | public class MultiplierResourceTest { 10 | 11 | SolverService solverService; 12 | MultiplierResource multiplierResource; 13 | 14 | @BeforeEach 15 | public void setup() { 16 | solverService = mock(SolverService.class); 17 | multiplierResource = new MultiplierResource(solverService); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /calculator-microservices/solver/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* -------------------------------------------------------------------------------- /calculator-microservices/solver/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | 19 | # OSX 20 | .DS_Store 21 | 22 | # Vim 23 | *.swp 24 | *.swo 25 | 26 | # patch 27 | *.orig 28 | *.rej 29 | 30 | # Maven 31 | target/ 32 | pom.xml.tag 33 | pom.xml.releaseBackup 34 | pom.xml.versionsBackup 35 | release.properties -------------------------------------------------------------------------------- /calculator-microservices/solver/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/calculator-microservices/solver/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /calculator-microservices/solver/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /calculator-microservices/solver/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the docker image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/quarkus-solver-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/quarkus-solver-jvm 15 | # 16 | ### 17 | FROM fabric8/java-alpine-openjdk8-jre 18 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 19 | ENV AB_ENABLED=jmx_exporter 20 | COPY target/lib/* /deployments/lib/ 21 | COPY target/*-runner.jar /deployments/app.jar 22 | ENTRYPOINT [ "/deployments/run-java.sh" ] -------------------------------------------------------------------------------- /calculator-microservices/solver/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the docker image run: 5 | # 6 | # mvn package -Pnative -Dnative-image.docker-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/quarkus-solver . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/quarkus-solver 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal 18 | WORKDIR /work/ 19 | ENV JAEGER_SERVICE_NAME=solver\ 20 | JAEGER_ENDPOINT=http://jaeger-collector.istio-system.svc:14268/api/traces\ 21 | JAEGER_PROPAGATION=b3\ 22 | JAEGER_SAMPLER_TYPE=const\ 23 | JAEGER_SAMPLER_PARAM=1 24 | COPY target/*-runner /work/application 25 | RUN chmod 775 /work 26 | EXPOSE 8080 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] -------------------------------------------------------------------------------- /calculator-microservices/solver/src/main/java/com/redhat/training/SolverResource.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import org.eclipse.microprofile.rest.client.inject.RestClient; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.inject.Inject; 8 | import javax.ws.rs.*; 9 | import javax.ws.rs.core.MediaType; 10 | import javax.ws.rs.core.Response; 11 | 12 | import com.redhat.training.service.AdderService; 13 | import com.redhat.training.service.MultiplierService; 14 | import com.redhat.training.service.SolverService; 15 | 16 | import java.util.regex.Matcher; 17 | import java.util.regex.Pattern; 18 | 19 | public class SolverResource implements SolverService { 20 | final Logger log = LoggerFactory.getLogger(SolverResource.class); 21 | 22 | @Inject 23 | @RestClient 24 | AdderService adderService; 25 | 26 | @Inject 27 | @RestClient 28 | MultiplierService multiplierService; 29 | 30 | static final Pattern multiplyPattern = Pattern.compile("(.+)\\*(.+)"); 31 | static final Pattern addPattern = Pattern.compile("(.+)\\+(.+)"); 32 | 33 | @Override 34 | @GET 35 | @Path("{equation}") 36 | @Produces(MediaType.TEXT_PLAIN) 37 | public Float solve(@PathParam("equation") String equation) { 38 | log.info("Solving '{}'", equation); 39 | try { 40 | return Float.valueOf(equation); 41 | } catch (NumberFormatException e) { 42 | Matcher addMatcher = addPattern.matcher(equation); 43 | if (addMatcher.matches()) { 44 | return adderService.add(addMatcher.group(1), addMatcher.group(2)); 45 | } 46 | Matcher multiplyMatcher = multiplyPattern.matcher(equation); 47 | if (multiplyMatcher.matches()) { 48 | return multiplierService.multiply(multiplyMatcher.group(1), multiplyMatcher.group(2)); 49 | } else { 50 | throw new WebApplicationException( 51 | Response.status(Response.Status.BAD_REQUEST).entity("Unable to parse: " + equation).build()); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /calculator-microservices/solver/src/main/java/com/redhat/training/service/AdderService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; 4 | 5 | import javax.ws.rs.GET; 6 | import javax.ws.rs.Path; 7 | import javax.ws.rs.PathParam; 8 | import javax.ws.rs.Produces; 9 | import javax.ws.rs.core.MediaType; 10 | 11 | @Path("/adder") 12 | @RegisterRestClient 13 | public interface AdderService { 14 | 15 | @GET 16 | @Path("/{lhs}/{rhs}") 17 | @Produces(MediaType.TEXT_PLAIN) 18 | Float add(@PathParam("lhs") String lhs, @PathParam("rhs") String rhs); 19 | } 20 | -------------------------------------------------------------------------------- /calculator-microservices/solver/src/main/java/com/redhat/training/service/MultiplierService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; 4 | 5 | import javax.ws.rs.GET; 6 | import javax.ws.rs.Path; 7 | import javax.ws.rs.PathParam; 8 | import javax.ws.rs.Produces; 9 | import javax.ws.rs.core.MediaType; 10 | 11 | @Path("/multiplier") 12 | @RegisterRestClient 13 | public interface MultiplierService { 14 | 15 | @GET 16 | @Path("/{lhs}/{rhs}") 17 | @Produces(MediaType.TEXT_PLAIN) 18 | Float multiply(@PathParam("lhs") String lhs, @PathParam("rhs") String rhs); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /calculator-microservices/solver/src/main/java/com/redhat/training/service/SolverService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.PathParam; 6 | import javax.ws.rs.Produces; 7 | import javax.ws.rs.core.MediaType; 8 | 9 | import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; 10 | 11 | @Path("/solver") 12 | @RegisterRestClient 13 | public interface SolverService { 14 | @GET 15 | @Path("{equation}") 16 | @Produces(MediaType.TEXT_PLAIN) 17 | Float solve(@PathParam("equation") String equation); 18 | } 19 | -------------------------------------------------------------------------------- /calculator-microservices/solver/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | quarkus.application.name=solver 2 | quarkus.http.test-port=8080 3 | com.redhat.training.service.AdderService/mp-rest/url=http://adder:8080 4 | com.redhat.training.service.MultiplierService/mp-rest/url=http://multiplier:8080 5 | %dev.com.redhat.training.service.AdderService/mp-rest/url=http://localhost:8081 6 | %dev.com.redhat.training.service.MultiplierService/mp-rest/url=http://localhost:8082 7 | %test.com.redhat.training.service.AdderService/mp-rest/url=http://localhost:8081 8 | %test.com.redhat.training.service.MultiplierService/mp-rest/url=http://localhost:8082 9 | -------------------------------------------------------------------------------- /calculator-microservices/solver/src/test/java/com/redhat/training/SolverResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import io.quarkus.test.common.http.TestHTTPEndpoint; 4 | import io.quarkus.test.junit.QuarkusTest; 5 | 6 | @QuarkusTest 7 | @TestHTTPEndpoint(SolverResource.class) 8 | public class SolverResourceTest { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /calculator-microservices/start-dependant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Starting the 'adder' project " 4 | cd adder 5 | ./mvnw quarkus:dev & 6 | ADDER_PID=$! 7 | sleep 5 8 | cd .. 9 | 10 | echo "Starting the 'multiplier' project " 11 | cd multiplier 12 | ./mvnw quarkus:dev & 13 | MULTIPLIER_PID=$! 14 | sleep 5 15 | cd .. 16 | 17 | echo 18 | read -p "Press enter to Terminate" 19 | echo 20 | kill $ADDER_PID $MULTIPLIER_PID 21 | sleep 2 22 | echo "All services terminated" 23 | echo 24 | -------------------------------------------------------------------------------- /calculator-microservices/start-locally.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Starting the 'solver' project " 4 | cd solver 5 | mvn quarkus:dev & 6 | SOLVER_PID=$! 7 | sleep 5 8 | cd .. 9 | 10 | echo "Starting the 'adder' project " 11 | cd adder 12 | mvn quarkus:dev & 13 | ADDER_PID=$! 14 | sleep 5 15 | cd .. 16 | 17 | echo "Starting the 'multiplier' project " 18 | cd multiplier 19 | mvn quarkus:dev & 20 | MULTIPLIER_PID=$! 21 | sleep 5 22 | cd .. 23 | 24 | echo 25 | read -p "Press enter to Terminate" 26 | echo 27 | kill $SOLVER_PID $ADDER_PID $MULTIPLIER_PID 28 | sleep 2 29 | echo "All services terminated" 30 | echo 31 | -------------------------------------------------------------------------------- /calculator-monolith/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* -------------------------------------------------------------------------------- /calculator-monolith/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | 19 | # OSX 20 | .DS_Store 21 | 22 | # Vim 23 | *.swp 24 | *.swo 25 | 26 | # patch 27 | *.orig 28 | *.rej 29 | 30 | # Maven 31 | target/ 32 | pom.xml.tag 33 | pom.xml.releaseBackup 34 | pom.xml.versionsBackup 35 | release.properties -------------------------------------------------------------------------------- /calculator-monolith/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/calculator-monolith/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /calculator-monolith/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /calculator-monolith/kubefiles/application-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: calculator-template 5 | annotations: 6 | description: "Quarkus Calculator" 7 | objects: 8 | - kind: Deployment 9 | apiVersion: apps/v1 10 | metadata: 11 | name: calculator 12 | spec: 13 | selector: 14 | matchLabels: 15 | app: calculator 16 | replicas: 1 17 | template: 18 | metadata: 19 | labels: 20 | app: calculator 21 | spec: 22 | containers: 23 | - name: calculator 24 | image: quay.io/${QUAY_USER_OR_GROUP}/${QUAY_REPOSITORY}:${APP_IMAGE_TAG} 25 | imagePullPolicy: Always 26 | ports: 27 | - containerPort: 8080 28 | - kind: Service 29 | apiVersion: v1 30 | metadata: 31 | labels: 32 | app: calculator 33 | name: calculator 34 | spec: 35 | ports: 36 | - port: 8080 37 | protocol: TCP 38 | targetPort: 8080 39 | selector: 40 | app: calculator 41 | - kind: Route 42 | apiVersion: route.openshift.io/v1 43 | metadata: 44 | name: calculator 45 | labels: 46 | app: calculator 47 | spec: 48 | to: 49 | kind: Service 50 | name: calculator 51 | port: 52 | targetPort: 8080 53 | 54 | parameters: 55 | - name: QUAY_USER_OR_GROUP 56 | description: "Quay User/Group" 57 | required: true 58 | - name: QUAY_REPOSITORY 59 | description: "Image repository" 60 | required: true 61 | - name: APP_IMAGE_TAG 62 | description: "Image Tag" 63 | required: false 64 | value: "latest" 65 | -------------------------------------------------------------------------------- /calculator-monolith/kubefiles/security-scan-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: calculator-security-scan-template 5 | annotations: 6 | description: "Calculator - Security Scan Template" 7 | objects: 8 | - kind: Job 9 | apiVersion: batch/v1 10 | metadata: 11 | name: ${APP_NAME}-trivy 12 | spec: 13 | backoffLimit: 0 14 | template: 15 | metadata: 16 | name: ${APP_NAME}-trivy 17 | spec: 18 | containers: 19 | - name: ${APP_NAME}-trivy 20 | image: quay.io/${QUAY_USER}/${QUAY_REPOSITORY} 21 | env: 22 | command: [ "/bin/sh" ] 23 | args: 24 | - -c 25 | - >- 26 | cd /tmp && 27 | curl -sL https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_RELEASE}/trivy_${TRIVY_RELEASE}_Linux-64bit.tar.gz -o - | tar -zxf - && 28 | { ./trivy fs --cache-dir /tmp/.cache --severity HIGH,CRITICAL --no-progress --ignore-unfixed / | grep ${CVE_CODE} ; 29 | ./trivy fs --cache-dir /tmp/.cache --severity HIGH,CRITICAL --no-progress --ignore-unfixed / | grep ${CVE_CODE} | wc -l | xargs -I % sh -c 'test % -eq 0' ; } 30 | restartPolicy: Never 31 | 32 | parameters: 33 | - name: QUAY_USER 34 | description: "Quay User" 35 | required: true 36 | - name: QUAY_REPOSITORY 37 | description: "Quay Repository" 38 | required: true 39 | - name: APP_NAME 40 | description: "Application Name" 41 | required: true 42 | - name: TRIVY_RELEASE 43 | description: "Trivy Release Version" 44 | required: false 45 | value: "0.14.0" 46 | - name: CVE_CODE 47 | description: "CVE Code" 48 | required: false 49 | value: "CVE-2021-23840" 50 | -------------------------------------------------------------------------------- /calculator-monolith/scripts/build-and-push-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts u:p:b:r: flag 4 | do 5 | case "${flag}" in 6 | u) quay_user=${OPTARG};; 7 | p) quay_password=${OPTARG};; 8 | b) build_number=${OPTARG};; 9 | r) quay_repo=${OPTARG};; 10 | esac 11 | done 12 | 13 | ./mvnw package -DskipTests \ 14 | -Dquarkus.jib.base-jvm-image=quay.io/redhattraining/do400-java-alpine-openjdk11-jre:latest \ 15 | -Dquarkus.container-image.build=true \ 16 | -Dquarkus.container-image.registry=quay.io \ 17 | -Dquarkus.container-image.group="${quay_user}" \ 18 | -Dquarkus.container-image.name="${quay_repo}" \ 19 | -Dquarkus.container-image.username="${quay_user}" \ 20 | -Dquarkus.container-image.password="${quay_password}" \ 21 | -Dquarkus.container-image.tag="1.0.0-${build_number}" \ 22 | -Dquarkus.container-image.additional-tags="latest" \ 23 | -Dquarkus.container-image.push=true 24 | -------------------------------------------------------------------------------- /calculator-monolith/scripts/check-job-state.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | oc wait --for=condition=ContainersReady \ 4 | --timeout=60s pod --selector job-name=${1} -n ${2} 5 | 6 | oc logs --pod-running-timeout=120s -f "jobs/${1}" -n "${2}" && \ 7 | podState=$(oc get pods --selector=job-name="${1}" -n "${2}" \ 8 | --output=jsonpath='{.items[0].status.containerStatuses[0].state.terminated.exitCode}') 9 | 10 | if [ "${podState}" -eq 0 ] 11 | then 12 | exit 0 13 | fi 14 | 15 | exit 1 16 | -------------------------------------------------------------------------------- /calculator-monolith/scripts/include-container-extensions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./mvnw quarkus:add-extension \ 3 | -Dextensions="kubernetes,container-image-jib" 4 | -------------------------------------------------------------------------------- /calculator-monolith/scripts/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts d:n: flag 4 | do 5 | case "${flag}" in 6 | d) deployment_name=${OPTARG};; 7 | n) namespace=${OPTARG};; 8 | esac 9 | done 10 | 11 | oc patch "deployment/${deployment_name}" \ 12 | -n "${namespace}" \ 13 | -p "{\"spec\": {\"template\": {\"metadata\": { \"labels\": { \"redeploy\": \"$(date +%s)\" }}}}}" 14 | -------------------------------------------------------------------------------- /calculator-monolith/src/main/java/com/redhat/training/SolverResource.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import java.util.List; 4 | 5 | import javax.annotation.PostConstruct; 6 | import javax.inject.Inject; 7 | import javax.ws.rs.PathParam; 8 | import javax.ws.rs.WebApplicationException; 9 | import javax.ws.rs.core.Response; 10 | 11 | import com.redhat.training.operation.Add; 12 | import com.redhat.training.operation.Identity; 13 | import com.redhat.training.operation.Operation; 14 | import com.redhat.training.operation.Substract; 15 | import com.redhat.training.service.SolverService; 16 | 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | public final class SolverResource implements SolverService { 21 | private static final Logger LOG = LoggerFactory.getLogger(SolverResource.class); 22 | 23 | @Inject 24 | Add add; 25 | 26 | @Inject 27 | Substract substract; 28 | 29 | @Inject 30 | Identity identity; 31 | 32 | private List operations; 33 | 34 | @PostConstruct 35 | public void buildOperationList() { 36 | operations = List.of(substract, add, identity); 37 | } 38 | 39 | @Override 40 | public Float solve(@PathParam("equation") final String equation) { 41 | LOG.info("Solving '{}'", equation); 42 | for (Operation operation : operations) { 43 | Float result = operation.apply(equation); 44 | if (result != null) { 45 | LOG.info("Solved '{} = {}'", equation, result); 46 | return result; 47 | } 48 | } 49 | 50 | throw new WebApplicationException( 51 | Response.status(Response.Status.BAD_REQUEST).entity("Unable to parse: " + equation).build()); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /calculator-monolith/src/main/java/com/redhat/training/operation/Add.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.operation; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.function.BinaryOperator; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | import javax.enterprise.context.ApplicationScoped; 11 | import javax.inject.Inject; 12 | 13 | import com.redhat.training.service.SolverService; 14 | 15 | @ApplicationScoped 16 | public final class Add implements Operation { 17 | private static final String REGEX = "(.+)\\+(.+)"; 18 | private static final BinaryOperator OPERATOR = (lhs, rhs) -> lhs + rhs; 19 | 20 | public Add() { 21 | super(); 22 | } 23 | 24 | @Override 25 | public Float apply(final String equation) { 26 | return solveGroups(equation).stream().reduce(OPERATOR).orElse(null); 27 | } 28 | 29 | private List solveGroups(final String equation) { 30 | Matcher matcher = Pattern.compile(REGEX).matcher(equation); 31 | if (matcher.matches()) { 32 | List result = new ArrayList<>(matcher.groupCount()); 33 | for (int groupNum = 1; groupNum <= matcher.groupCount(); groupNum++) { 34 | result.add(solve(matcher.group(groupNum))); 35 | } 36 | return result; 37 | } else { 38 | return Collections.emptyList(); 39 | } 40 | } 41 | 42 | @Inject 43 | SolverService solverService; 44 | 45 | private Float solve(final String equation) { 46 | return solverService.solve(equation); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /calculator-monolith/src/main/java/com/redhat/training/operation/Identity.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.operation; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | @ApplicationScoped 6 | public final class Identity implements Operation { 7 | 8 | public Identity() { 9 | super(); 10 | } 11 | 12 | @Override 13 | public Float apply(final String equation) { 14 | try { 15 | return Float.valueOf(equation); 16 | } catch (final NumberFormatException e) { 17 | return null; 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /calculator-monolith/src/main/java/com/redhat/training/operation/Operation.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.operation; 2 | 3 | public interface Operation { 4 | Float apply(String equation); 5 | } 6 | -------------------------------------------------------------------------------- /calculator-monolith/src/main/java/com/redhat/training/operation/Substract.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.operation; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.function.BinaryOperator; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | import javax.enterprise.context.ApplicationScoped; 11 | import javax.inject.Inject; 12 | 13 | import com.redhat.training.service.SolverService; 14 | @ApplicationScoped 15 | public final class Substract implements Operation { 16 | 17 | private static final String REGEX = "(.+)\\-(.+)"; 18 | private static final BinaryOperator OPERATOR = (lhs, rhs) -> lhs - rhs; 19 | 20 | public Substract() { 21 | super(); 22 | } 23 | 24 | @Override 25 | public Float apply(final String equation) { 26 | return solveGroups(equation).stream().reduce(OPERATOR).orElse(null); 27 | } 28 | 29 | private List solveGroups(final String equation) { 30 | Matcher matcher = Pattern.compile(REGEX).matcher(equation); 31 | if (matcher.matches()) { 32 | List result = new ArrayList<>(matcher.groupCount()); 33 | for (int groupNum = 1; groupNum <= matcher.groupCount(); groupNum++) { 34 | result.add(solve(matcher.group(groupNum))); 35 | } 36 | return result; 37 | } else { 38 | return Collections.emptyList(); 39 | } 40 | } 41 | 42 | @Inject 43 | SolverService solverService; 44 | 45 | private Float solve(final String equation) { 46 | return solverService.solve(equation); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /calculator-monolith/src/main/java/com/redhat/training/service/SolverService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.service; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.PathParam; 6 | import javax.ws.rs.Produces; 7 | import javax.ws.rs.core.MediaType; 8 | 9 | @Path("/solver") 10 | public interface SolverService { 11 | @GET 12 | @Path("{equation}") 13 | @Produces(MediaType.TEXT_PLAIN) 14 | Float solve(@PathParam("equation") String equation); 15 | } 16 | -------------------------------------------------------------------------------- /calculator-monolith/src/test/java/com/redhat/training/SolverIT.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import static io.restassured.RestAssured.given; 4 | import static org.hamcrest.CoreMatchers.is; 5 | 6 | import com.redhat.training.service.SolverService; 7 | 8 | import org.junit.jupiter.api.Tag; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import io.quarkus.test.common.http.TestHTTPEndpoint; 12 | import io.quarkus.test.junit.QuarkusTest; 13 | 14 | @QuarkusTest 15 | @TestHTTPEndpoint(SolverService.class) 16 | @Tag("integration") 17 | public class SolverIT { 18 | 19 | private static void expectEquationSolution(final String equation, final String body) { 20 | given().when().get(equation).then().statusCode(200).body(is(body)); 21 | } 22 | 23 | @Test 24 | public void solve_number() { 25 | expectEquationSolution("4", "4.0"); 26 | } 27 | 28 | @Test 29 | public void solve_add() { 30 | expectEquationSolution("4+2","6.0"); 31 | } 32 | 33 | @Test 34 | public void solve_substract() { 35 | expectEquationSolution("4-2","2.0"); 36 | } 37 | 38 | @Test 39 | public void solve_composed() { 40 | expectEquationSolution("4+2-1","5.0"); 41 | } 42 | 43 | @Test 44 | public void solve_error() { 45 | given().when().get("error").then().statusCode(400); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /calculator-monolith/src/test/java/com/redhat/training/SolverTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertThrows; 5 | 6 | import javax.inject.Inject; 7 | import javax.ws.rs.WebApplicationException; 8 | 9 | import com.redhat.training.service.SolverService; 10 | 11 | import org.junit.jupiter.api.Tag; 12 | import org.junit.jupiter.api.Test; 13 | 14 | import io.quarkus.test.junit.QuarkusTest; 15 | 16 | @QuarkusTest 17 | @Tag("unit") 18 | public class SolverTest { 19 | @Inject 20 | SolverService solverService; 21 | 22 | @Test 23 | public void solve_number() { 24 | assertEquals(solverService.solve("5"), 5); 25 | } 26 | 27 | @Test 28 | public void solve_add() { 29 | assertEquals(solverService.solve("5+3"), 8); 30 | } 31 | 32 | @Test 33 | public void solve_substract() { 34 | assertEquals(solverService.solve("5-3"), 2); 35 | } 36 | 37 | @Test 38 | public void solve_composition() { 39 | assertEquals(solverService.solve("20+5+3+2"), 30); 40 | } 41 | 42 | @Test 43 | public void solve_addition_overprioritize_substraction() { 44 | assertEquals(solverService.solve("20-5+3+2"), 10); 45 | } 46 | 47 | @Test 48 | public void solve_error() { 49 | assertThrows(WebApplicationException.class, () -> solverService.solve("5+")); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /calculator-monolith/src/test/java/com/redhat/training/operation/AddTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.operation; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNull; 5 | 6 | import javax.inject.Inject; 7 | 8 | import org.junit.jupiter.api.Tag; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import io.quarkus.test.junit.QuarkusTest; 12 | 13 | @QuarkusTest 14 | @Tag("unit") 15 | public class AddTest { 16 | 17 | @Inject 18 | Add add; 19 | 20 | @Test 21 | public void simple_addition() { 22 | assertEquals(add.apply("4+5"),9); 23 | } 24 | 25 | @Test 26 | public void unparseable_operation() { 27 | assertNull(add.apply("4*5")); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /calculator-monolith/src/test/java/com/redhat/training/operation/SubstractTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.operation; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNull; 5 | 6 | import javax.inject.Inject; 7 | 8 | import org.junit.jupiter.api.Tag; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import io.quarkus.test.junit.QuarkusTest; 12 | 13 | @QuarkusTest 14 | @Tag("unit") 15 | public class SubstractTest { 16 | 17 | @Inject 18 | Substract substract; 19 | 20 | @Test 21 | public void simple_substraction() { 22 | assertEquals(substract.apply("5-4"),1); 23 | } 24 | 25 | @Test 26 | public void unparseable_operation() { 27 | assertNull(substract.apply("4+5")); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /exchange-cli/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es2020": true, 4 | "node": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended" 9 | ], 10 | "parser": "@typescript-eslint/parser", 11 | "parserOptions": { 12 | "ecmaVersion": 11, 13 | "sourceType": "module" 14 | }, 15 | "plugins": [ 16 | "@typescript-eslint" 17 | ], 18 | "rules": { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /exchange-cli/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /exchange-cli/functional.spec.ts: -------------------------------------------------------------------------------- 1 | import { exec } from "child_process"; 2 | 3 | const cmd = "node dist/index.js"; 4 | // const cmd = "exchange"; 5 | 6 | describe("functional tests", () => { 7 | describe("miscellaneous flags", () => { 8 | it("should print help", async () => { 9 | // GIVEN the command is available on PATH 10 | 11 | // WHEN the command is run with the help flag 12 | const res = await runCommand(`${cmd} --help`); 13 | 14 | // THEN the CLI should print help info 15 | expect(res.stdout).toContain("Convert from one currency to another"); 16 | }); 17 | 18 | it("should check for missing flags", async () => { 19 | // GIVEN the command is available on PATH 20 | 21 | // WHEN the command is run with no arguments 22 | try { 23 | await runCommand(cmd); 24 | fail(); 25 | } catch (e) { 26 | expect(e).toContain("Missing required flags"); 27 | } 28 | 29 | // THEN the CLI should print missing args 30 | }); 31 | }); 32 | 33 | describe("conversions", () => { 34 | it('should do a simple "conversion"', async () => { 35 | // GIVEN the command is available on PATH 36 | 37 | // WHEN the command is run with `exchange -i usd -o usd 3.5` 38 | const res = await runCommand(`${cmd} -i usd -o usd 3.5`); 39 | 40 | // THEN the CLI should convert from USD to USD 41 | expect(res.stdout).toMatch("3.5 USD -> 3.5 USD"); 42 | }); 43 | 44 | it("should convert different currencies", async () => { 45 | // GIVEN the command is available on PATH 46 | 47 | // WHEN the command is run with `exchange -i usd -o jpy 3.5` 48 | const res = await runCommand(`${cmd} -i usd -o jpy 3.5`); 49 | 50 | // THEN the CLI should convert between two different currencies 51 | expect(res.stdout).toMatch("3.5 USD -> 364.6 JPY"); 52 | }); 53 | }); 54 | 55 | async function runCommand( 56 | cmd: string 57 | ): Promise<{ stdout: string; stderr: string }> { 58 | return new Promise((resolve, reject) => { 59 | exec(cmd, (err, stdout, stderr) => { 60 | if (err) { 61 | reject(stderr); 62 | } else { 63 | resolve({ stdout, stderr }); 64 | } 65 | }); 66 | }); 67 | } 68 | }); 69 | -------------------------------------------------------------------------------- /exchange-cli/jest-functional.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node", 4 | testMatch: ["**/*.spec.*"], 5 | }; 6 | -------------------------------------------------------------------------------- /exchange-cli/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node", 4 | testMatch: ["**/*.test.*"], 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /exchange-cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exchange-cli", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "scripts": { 7 | "start": "tsc-watch", 8 | "build": "tsc", 9 | "postinstall": "npm run build", 10 | "test": "npm run test:unit && npm run test:functional", 11 | "test:unit": "jest", 12 | "test:functional": "jest -c jest-functional.config.js" 13 | }, 14 | "bin": { 15 | "exchange": "./dist/index.js" 16 | }, 17 | "dependencies": { 18 | "meow": "^8.0.0", 19 | "ts-node": "^9.1.0", 20 | "typescript": "^4.1.2" 21 | }, 22 | "devDependencies": { 23 | "@types/lowdb": "^1.0.9", 24 | "@types/node": "^14.14.10", 25 | "@typescript-eslint/eslint-plugin": "^4.9.0", 26 | "@typescript-eslint/parser": "^4.9.0", 27 | "eslint": "^7.15.0", 28 | "jest": "^26.6.3", 29 | "ts-jest": "^26.4.4", 30 | "tsc-watch": "^4.2.9" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /exchange-cli/src/convert.test.ts: -------------------------------------------------------------------------------- 1 | import { convert } from "./convert"; 2 | 3 | describe("convert", () => { 4 | it("should convert USD to USD", () => { 5 | const result = convert("usd", "usd", 3.5); 6 | expect(result).toBe(3.5); 7 | }); 8 | 9 | it("should convert from USD", () => { 10 | const result = convert("usd", "gbp", 3.5); 11 | expect(result).toBe(2.6); 12 | }); 13 | 14 | it("should convert to USD", () => { 15 | const result = convert("gbp", "usd", 2.6); 16 | expect(result).toBe(3.49); 17 | }); 18 | 19 | it("should convert between non-USD", () => { 20 | const result = convert("gbp", "eur", 2.6); 21 | expect(result).toBe(2.88); 22 | }); 23 | 24 | it("should convert GBP to GBP", () => { 25 | const result = convert("gbp", "gbp", 3.5); 26 | expect(result).toBe(3.5); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /exchange-cli/src/convert.ts: -------------------------------------------------------------------------------- 1 | export const currencyRates = { 2 | usd: 1, 3 | eur: 0.824, 4 | gbp: 0.744, 5 | inr: 73.798, 6 | aud: 1.345, 7 | cad: 1.278, 8 | jpy: 104.171, 9 | }; 10 | 11 | export function convert( 12 | inCurrency: string, 13 | outCurrency: string, 14 | amount: number 15 | ): number { 16 | const conversionRate = 17 | (1 / currencyRates[inCurrency]) * currencyRates[outCurrency]; 18 | const convertedAmount = amount * conversionRate; 19 | return Math.round(convertedAmount * 100) / 100; 20 | } 21 | -------------------------------------------------------------------------------- /exchange-cli/src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as meow from "meow"; 3 | import { convert } from "./convert"; 4 | 5 | const usageText = ` 6 | Convert from one currency to another. Note that the rates are fixed values and therefore inaccurate. 7 | 8 | Usage 9 | $ exchange -i -o 10 | 11 | Options 12 | --input, -i Input currency 13 | --output, -o Output currency 14 | 15 | Available Currencies 16 | 17 | USD, EUR, GBP, INR, AUD, CAD, JPY 18 | 19 | Examples 20 | $ exchange -i usd -o gbp 4.30 21 | `; 22 | 23 | const cliOptions: meow.Options = { 24 | autoHelp: true, 25 | autoVersion: true, 26 | inferType: true, 27 | flags: { 28 | input: { 29 | type: "string", 30 | alias: "i", 31 | isRequired: true, 32 | }, 33 | output: { 34 | type: "string", 35 | alias: "o", 36 | isRequired: true, 37 | }, 38 | }, 39 | }; 40 | 41 | const cli = meow(usageText, cliOptions); 42 | 43 | const inCurr: string = (cli.flags.input + "").toLowerCase(); 44 | const outCurr: string = (cli.flags.output + "").toLowerCase(); 45 | const amount: number = parseFloat(cli.input[0]); 46 | const converted = convert(inCurr, outCurr, amount); 47 | 48 | console.log( 49 | `${amount} ${inCurr.toUpperCase()} -> ${converted} ${outCurr.toUpperCase()}` 50 | ); 51 | -------------------------------------------------------------------------------- /exchange-cli/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2017", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "noImplicitAny": false, 8 | "removeComments": true 9 | }, 10 | "include": ["src/**/*.ts"], 11 | "exclude": ["node_modules", "src/**/*.test.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /greeting-cd-pipeline/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi8/nodejs-12 2 | 3 | # Copy app 4 | COPY . . 5 | 6 | EXPOSE 3000 7 | ENTRYPOINT [ "node", "server" ] 8 | -------------------------------------------------------------------------------- /greeting-cd-pipeline/Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { label 'nodejs' } 3 | 4 | // Set your OCP project 5 | environment { APP_NAMESPACE = '...' } 6 | 7 | stages{ 8 | 9 | stage('Test'){ 10 | steps { 11 | sh "node test.js" 12 | } 13 | } 14 | 15 | // Add more stages here 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /greeting-cd-pipeline/greet.js: -------------------------------------------------------------------------------- 1 | module.exports = function greet(name) { 2 | return `Hello ${name || "student"}`; 3 | } 4 | -------------------------------------------------------------------------------- /greeting-cd-pipeline/server.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const url = require("url"); 3 | const greet = require("./greet"); 4 | 5 | const server = http.createServer((req, res) => { 6 | const { name } = url.parse(req.url, true).query; 7 | res.statusCode = 200; 8 | res.setHeader("Content-Type", "text/plain"); 9 | res.setHeader("Access-Control-Allow-Origin", "*"); 10 | res.end(greet(name)); 11 | }); 12 | 13 | const port = 3000; 14 | server.listen(port, () => { 15 | console.log(`Server listening on ${port}`); 16 | }); 17 | -------------------------------------------------------------------------------- /greeting-cd-pipeline/test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert").strict; 2 | const greet = require("./greet"); 3 | 4 | assert.strictEqual(greet(), "Hello student"); 5 | assert.strictEqual(greet("Guy"), "Hello Guy"); 6 | -------------------------------------------------------------------------------- /greeting-console/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | .eslintrc.json 4 | node_modules/ 5 | test/ 6 | *.md 7 | -------------------------------------------------------------------------------- /greeting-console/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "globals": { 8 | "describe": false, 9 | "it": false 10 | }, 11 | "extends": "eslint:recommended", 12 | "parserOptions": { 13 | "ecmaVersion": 12 14 | }, 15 | "rules": { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /greeting-console/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /greeting-console/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi8/nodejs-12 2 | 3 | # Install dependencies 4 | COPY package.json package-lock.json /app/ 5 | WORKDIR /app 6 | RUN npm ci --production 7 | 8 | # Copy app 9 | COPY . /app 10 | 11 | ENTRYPOINT [ "node", "index" ] 12 | -------------------------------------------------------------------------------- /greeting-console/Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline{ 2 | agent{ 3 | label "nodejs" 4 | } 5 | stages{ 6 | stage("Install dependencies"){ 7 | steps{ 8 | sh "npm ci" 9 | } 10 | } 11 | 12 | stage("Check Style"){ 13 | steps{ 14 | sh "npm run lint" 15 | } 16 | } 17 | 18 | stage("Test"){ 19 | steps{ 20 | sh "npm test" 21 | } 22 | } 23 | 24 | // Add the Release stage here 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /greeting-console/README.md: -------------------------------------------------------------------------------- 1 | # Greeting console app 2 | 3 | Sample console application for DO400 course. 4 | 5 | Usage: 6 | 7 | > node index.js *NAME* 8 | -------------------------------------------------------------------------------- /greeting-console/build.yml: -------------------------------------------------------------------------------- 1 | kind: BuildConfig 2 | apiVersion: build.openshift.io/v1 3 | metadata: 4 | name: greeting-console 5 | spec: 6 | nodeSelector: {} 7 | strategy: 8 | type: Docker 9 | source: 10 | type: Git 11 | git: 12 | uri: 'https://github.com/YOUR_GITHUB_USER/do400-greeting-console' 13 | ref: main 14 | output: 15 | to: 16 | kind: DockerImage 17 | name: quay.io/YOUR_QUAY_USER/greeting-console 18 | pushSecret: 19 | name: quay-credentials 20 | -------------------------------------------------------------------------------- /greeting-console/greet.js: -------------------------------------------------------------------------------- 1 | module.exports = function greet(name) { 2 | return `Hello ${name}!`; 3 | } 4 | -------------------------------------------------------------------------------- /greeting-console/index.js: -------------------------------------------------------------------------------- 1 | const greet = require("./greet"); 2 | 3 | if (process.argv.length < 3) { 4 | console.error("Please specify the name paremeter"); 5 | process.exit(1); 6 | } 7 | 8 | const name = process.argv[2]; 9 | console.log(greet(name)); 10 | -------------------------------------------------------------------------------- /greeting-console/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "greetings-console", 3 | "version": "0.0.1", 4 | "description": "Sample app for DO400", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "test": "mocha test" 9 | }, 10 | "license": "ISC", 11 | "devDependencies": { 12 | "eslint": "^7.13.0", 13 | "mocha": "^8.2.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /greeting-console/test/greet.test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const greet = require("../greet"); 3 | 4 | 5 | describe("greet", () =>{ 6 | 7 | it("greets in english", () => { 8 | assert.strictEqual("Hello Guy!", greet("Guy")); 9 | }); 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /greeting-devsecops/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi8/nodejs-12 2 | 3 | # Copy app 4 | COPY . . 5 | 6 | EXPOSE 3000 7 | ENTRYPOINT [ "node", "server" ] 8 | -------------------------------------------------------------------------------- /greeting-devsecops/Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { label 'nodejs' } 3 | 4 | // Set your OCP project 5 | environment { APP_NAMESPACE = '...' } 6 | 7 | stages{ 8 | 9 | stage('Test'){ 10 | steps { 11 | sh "node test.js" 12 | } 13 | } 14 | 15 | // Add more stages here 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /greeting-devsecops/greet.js: -------------------------------------------------------------------------------- 1 | module.exports = function greet(name) { 2 | return `Hello ${name || "student"}`; 3 | } 4 | -------------------------------------------------------------------------------- /greeting-devsecops/server.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const url = require("url"); 3 | const greet = require("./greet"); 4 | 5 | const server = http.createServer((req, res) => { 6 | const { name } = url.parse(req.url, true).query; 7 | res.statusCode = 200; 8 | res.setHeader("Content-Type", "text/plain"); 9 | res.setHeader("Access-Control-Allow-Origin", "*"); 10 | res.end(greet(name)); 11 | }); 12 | 13 | const port = 3000; 14 | server.listen(port, () => { 15 | console.log(`Server listening on ${port}`); 16 | }); 17 | -------------------------------------------------------------------------------- /greeting-devsecops/test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert").strict; 2 | const greet = require("./greet"); 3 | 4 | assert.strictEqual(greet(), "Hello student"); 5 | assert.strictEqual(greet("Guy"), "Hello Guy"); 6 | -------------------------------------------------------------------------------- /greeting-service/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | .eslintrc.json 4 | node_modules/ 5 | test/ 6 | *.md 7 | -------------------------------------------------------------------------------- /greeting-service/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "globals": { 8 | "describe": false, 9 | "it": false 10 | }, 11 | "extends": "eslint:recommended", 12 | "parserOptions": { 13 | "ecmaVersion": 12 14 | }, 15 | "rules": { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /greeting-service/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /greeting-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi8/nodejs-12 2 | 3 | # Install dependencies 4 | COPY package.json package-lock.json /app/ 5 | WORKDIR /app 6 | RUN npm ci --production 7 | 8 | # Copy app 9 | COPY . /app 10 | 11 | EXPOSE 3000 12 | ENTRYPOINT [ "npm", "start" ] 13 | -------------------------------------------------------------------------------- /greeting-service/Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline{ 2 | agent{ 3 | label "nodejs" 4 | } 5 | stages{ 6 | stage("Install dependencies"){ 7 | steps{ 8 | sh "npm ci" 9 | } 10 | } 11 | 12 | stage("Check Style"){ 13 | steps{ 14 | sh "npm run lint" 15 | } 16 | } 17 | 18 | stage("Test"){ 19 | steps{ 20 | sh "npm test" 21 | } 22 | } 23 | 24 | // Add the "Deploy" stage here 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /greeting-service/README.md: -------------------------------------------------------------------------------- 1 | # Greeting console app 2 | 3 | Sample greeting service for DO400 course. 4 | 5 | Run server: 6 | 7 | ```sh 8 | $ npm start 9 | ``` 10 | -------------------------------------------------------------------------------- /greeting-service/greet.js: -------------------------------------------------------------------------------- 1 | module.exports = function greet(name) { 2 | return `Hello ${name || "guest"}!`; 3 | } 4 | -------------------------------------------------------------------------------- /greeting-service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "greeting-service", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "greet.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "lint": "eslint .", 9 | "test": "mocha test" 10 | }, 11 | "license": "ISC", 12 | "devDependencies": { 13 | "eslint": "^7.13.0", 14 | "mocha": "^8.2.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /greeting-service/server.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const url = require("url"); 3 | const greet = require("./greet"); 4 | 5 | const server = http.createServer((req, res) => { 6 | const { name } = url.parse(req.url, true).query; 7 | res.statusCode = 200; 8 | res.setHeader("Content-Type", "text/plain"); 9 | res.setHeader("Access-Control-Allow-Origin", "*"); 10 | res.end(greet(name)); 11 | }); 12 | 13 | const port = 3000; 14 | server.listen(port, () => { 15 | console.log(`Server listening on ${port}`); 16 | }); 17 | -------------------------------------------------------------------------------- /greeting-service/test/greet.test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const greet = require("../greet"); 3 | 4 | 5 | describe("greet", () =>{ 6 | 7 | it("greets in italian", () => { 8 | assert.strictEqual("Ciao Guy!", greet("Guy")); 9 | }); 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /hello/helloworld.py: -------------------------------------------------------------------------------- 1 | print("Hello world!") 2 | -------------------------------------------------------------------------------- /home-automation-service/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* 6 | -------------------------------------------------------------------------------- /home-automation-service/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | .factorypath 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Vim 24 | *.swp 25 | *.swo 26 | 27 | # patch 28 | *.orig 29 | *.rej 30 | 31 | # Maven 32 | target/ 33 | pom.xml.tag 34 | pom.xml.releaseBackup 35 | pom.xml.versionsBackup 36 | release.properties 37 | -------------------------------------------------------------------------------- /home-automation-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/home-automation-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /home-automation-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /home-automation-service/README.md: -------------------------------------------------------------------------------- 1 | # Home Automation App 2 | 3 | Use this skeleton to build a home automation app using TDD in the DO400 course. 4 | 5 | This project uses Quarkus, the Supersonic Subatomic Java Framework. 6 | 7 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . 8 | 9 | ## Running the application in dev mode 10 | 11 | You can run your application in dev mode that enables live coding using: 12 | ``` 13 | ./mvnw quarkus:dev 14 | ``` 15 | ## Running tests 16 | 17 | You can run your tests using: 18 | ```shell script 19 | ./mvnw test 20 | ``` 21 | -------------------------------------------------------------------------------- /home-automation-service/kubefiles/application-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: home-automation-template 5 | annotations: 6 | description: "Home Automation Application Template" 7 | objects: 8 | - kind: Deployment 9 | apiVersion: apps/v1 10 | metadata: 11 | name: home-automation 12 | spec: 13 | selector: 14 | matchLabels: 15 | app: home-automation 16 | replicas: 1 17 | template: 18 | metadata: 19 | labels: 20 | app: home-automation 21 | spec: 22 | containers: 23 | - name: home-automation 24 | image: quay.io/${QUAY_USER_OR_GROUP}/${APP_IMAGE_NAME}:${APP_IMAGE_TAG} 25 | imagePullPolicy: Always 26 | ports: 27 | - containerPort: 8080 28 | strategy: 29 | type: RollingUpdate 30 | - kind: Service 31 | apiVersion: v1 32 | metadata: 33 | labels: 34 | app: home-automation 35 | name: home-automation 36 | spec: 37 | ports: 38 | - port: 8080 39 | protocol: TCP 40 | targetPort: 8080 41 | selector: 42 | app: home-automation 43 | - kind: Route 44 | apiVersion: route.openshift.io/v1 45 | metadata: 46 | name: home-automation 47 | labels: 48 | app: home-automation 49 | spec: 50 | to: 51 | kind: Service 52 | name: home-automation 53 | port: 54 | targetPort: 8080 55 | 56 | parameters: 57 | - name: QUAY_USER_OR_GROUP 58 | description: "Quay User/Group" 59 | required: true 60 | - name: APP_IMAGE_NAME 61 | description: "Image Name" 62 | required: false 63 | value: "home-automation" 64 | - name: APP_IMAGE_TAG 65 | description: "Image Tag" 66 | required: false 67 | value: "latest" 68 | -------------------------------------------------------------------------------- /home-automation-service/src/main/docker/Dockerfile.fast-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/home-automation-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/home-automation-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/home-automation-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | # We make four distinct layers so if there are application changes the library layers can be re-used 49 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 50 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 51 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 52 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 53 | 54 | EXPOSE 8080 55 | USER 1001 56 | 57 | ENTRYPOINT [ "/deployments/run-java.sh" ] 58 | -------------------------------------------------------------------------------- /home-automation-service/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/home-automation-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/home-automation-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/home-automation-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /home-automation-service/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/home-automation . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/home-automation 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/home-automation-service/src/main/java/com/redhat/training/home/automation/.gitkeep -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/HomeAutomation.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | import com.redhat.training.home.automation.lights.LightSystem; 6 | import com.redhat.training.home.automation.rules.Rule; 7 | import com.redhat.training.home.automation.rules.RulesRepository; 8 | 9 | @ApplicationScoped 10 | class HomeAutomation { 11 | private LightSystem lightSystem; 12 | private RulesRepository rulesRepository; 13 | 14 | public HomeAutomation(LightSystem lightSystem, RulesRepository rulesRepository) { 15 | this.lightSystem = lightSystem; 16 | this.rulesRepository = rulesRepository; 17 | } 18 | 19 | public void processConditions(RoomConditions conditions) { 20 | Iterable rules = rulesRepository.getAll(); 21 | 22 | for (Rule rule : rules) { 23 | if (!rule.meets(conditions)) { 24 | lightSystem.switchOff(); 25 | return; 26 | } 27 | } 28 | 29 | lightSystem.switchOn(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/HomeResource.java: -------------------------------------------------------------------------------- 1 | 2 | package com.redhat.training.home.automation; 3 | 4 | import javax.inject.Inject; 5 | import javax.ws.rs.GET; 6 | import javax.ws.rs.Path; 7 | import javax.ws.rs.core.Response; 8 | 9 | import com.redhat.training.home.automation.lights.ConsoleLightSystem; 10 | 11 | import org.jboss.resteasy.annotations.jaxrs.PathParam; 12 | 13 | @Path( "/home" ) 14 | public class HomeResource { 15 | 16 | @Inject 17 | HomeAutomation home; 18 | 19 | @Inject 20 | ConsoleLightSystem light; 21 | 22 | @GET 23 | @Path("/process/daylight/{daylight}") 24 | public Response setConditions(@PathParam float daylight) { 25 | RoomConditions conditions = new RoomConditions(daylight, true); 26 | 27 | home.processConditions(conditions); 28 | 29 | return Response.accepted("Room conditions processed").build(); 30 | } 31 | 32 | @GET 33 | @Path("/lights") 34 | public Response getLights(@PathParam float daylight) { 35 | String message = light.isOn() ? "Lights are on" : "Lights are off"; 36 | 37 | return Response.accepted(message).build(); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/RoomConditions.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation; 2 | 3 | public class RoomConditions { 4 | public double daylightFactor; 5 | public boolean presenceDetected; 6 | 7 | RoomConditions(double daylightFactor, boolean presenceDetected) { 8 | this.daylightFactor = daylightFactor; 9 | this.presenceDetected = presenceDetected; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/lights/ConsoleLightSystem.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation.lights; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | 5 | @ApplicationScoped 6 | public class ConsoleLightSystem implements LightSystem { 7 | private boolean on = false; 8 | 9 | public void switchOn() { 10 | System.out.println("Lights ON!"); 11 | on = true; 12 | } 13 | 14 | public void switchOff() { 15 | System.out.println("Lights OFF!"); 16 | on = false; 17 | } 18 | 19 | public boolean isOn() { 20 | return on; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/lights/LightSystem.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation.lights; 2 | 3 | public interface LightSystem { 4 | void switchOff(); 5 | 6 | void switchOn(); 7 | 8 | boolean isOn(); 9 | } 10 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/rules/DaylightRule.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation.rules; 2 | 3 | import com.redhat.training.home.automation.RoomConditions; 4 | 5 | public class DaylightRule extends Rule { 6 | @Override 7 | public boolean meets(RoomConditions conditions) { 8 | return conditions.daylightFactor < 0.2; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/rules/InMemoryRulesRepository.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation.rules; 2 | 3 | import java.util.Arrays; 4 | 5 | import javax.enterprise.context.ApplicationScoped; 6 | 7 | @ApplicationScoped 8 | public class InMemoryRulesRepository implements RulesRepository { 9 | @Override 10 | public Iterable getAll() { 11 | return Arrays.asList(new DaylightRule(), new PresenceRule()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/rules/PresenceRule.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation.rules; 2 | 3 | import com.redhat.training.home.automation.RoomConditions; 4 | 5 | public class PresenceRule extends Rule { 6 | 7 | @Override 8 | public boolean meets(RoomConditions conditions) { 9 | return conditions.presenceDetected; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/rules/Rule.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation.rules; 2 | 3 | import com.redhat.training.home.automation.RoomConditions; 4 | 5 | public abstract class Rule { 6 | public abstract boolean meets(RoomConditions conditions); 7 | } 8 | -------------------------------------------------------------------------------- /home-automation-service/src/main/java/com/redhat/training/home/automation/rules/RulesRepository.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation.rules; 2 | 3 | public interface RulesRepository { 4 | Iterable getAll(); 5 | } 6 | -------------------------------------------------------------------------------- /home-automation-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | quarkus.http.test-port=8081 2 | -------------------------------------------------------------------------------- /home-automation-service/src/test/java/com/redhat/training/home/automation/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/home-automation-service/src/test/java/com/redhat/training/home/automation/.gitkeep -------------------------------------------------------------------------------- /home-automation-service/src/test/java/com/redhat/training/home/automation/HomeAutomationTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import static org.junit.jupiter.api.Assertions.assertFalse; 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import com.redhat.training.home.automation.lights.LightSystem; 8 | import com.redhat.training.home.automation.lights.ConsoleLightSystem; 9 | import com.redhat.training.home.automation.rules.InMemoryRulesRepository; 10 | import com.redhat.training.home.automation.rules.RulesRepository; 11 | 12 | public class HomeAutomationTest { 13 | LightSystem light; 14 | HomeAutomation home; 15 | RulesRepository rulesRepository; 16 | 17 | @BeforeEach 18 | public void setUp() { 19 | light = new ConsoleLightSystem(); 20 | rulesRepository = new InMemoryRulesRepository(); 21 | home = new HomeAutomation(light, rulesRepository); 22 | } 23 | 24 | @Test 25 | public void switchOffLightsUnderEnoughDaylight() { 26 | home.processConditions(new RoomConditions(0.20, true)); 27 | 28 | assertFalse(light.isOn()); 29 | } 30 | 31 | @Test 32 | public void switchOnLightsUnderLowDaylight() { 33 | home.processConditions(new RoomConditions(0.19, true)); 34 | 35 | assertTrue(light.isOn()); 36 | } 37 | 38 | @Test 39 | public void transitionToLightsOnUnderEnoughDaylight() { 40 | light.switchOn(); 41 | 42 | home.processConditions(new RoomConditions(0.30, true)); 43 | 44 | assertFalse(light.isOn()); 45 | } 46 | 47 | @Test 48 | public void switchOffLightsAtNightIfNoPresenceDetected() { 49 | home.processConditions(new RoomConditions(0.1, false)); 50 | 51 | assertFalse(light.isOn()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /home-automation-service/src/test/java/com/redhat/training/home/automation/PresenceRuleTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.home.automation; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | import com.redhat.training.home.automation.rules.PresenceRule; 7 | 8 | public class PresenceRuleTest { 9 | @Test 10 | public void isMetWhenPresenceDetected() { 11 | PresenceRule rule = new PresenceRule(); 12 | 13 | RoomConditions conditions = new RoomConditions(0, true); 14 | 15 | assertTrue(rule.meets(conditions)); 16 | } 17 | 18 | @Test 19 | public void isNotMetWhenPresenceNotDetected() { 20 | PresenceRule rule = new PresenceRule(); 21 | 22 | RoomConditions conditions = new RoomConditions(0, false); 23 | 24 | assertFalse(rule.meets(conditions)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /home-automation/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* 6 | -------------------------------------------------------------------------------- /home-automation/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | .factorypath 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Vim 24 | *.swp 25 | *.swo 26 | 27 | # patch 28 | *.orig 29 | *.rej 30 | 31 | # Maven 32 | target/ 33 | pom.xml.tag 34 | pom.xml.releaseBackup 35 | pom.xml.versionsBackup 36 | release.properties 37 | -------------------------------------------------------------------------------- /home-automation/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/home-automation/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /home-automation/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /home-automation/README.md: -------------------------------------------------------------------------------- 1 | # Home Automation App 2 | 3 | Use this skeleton to build a home automation app using TDD in the DO400 course. 4 | 5 | This project uses Quarkus, the Supersonic Subatomic Java Framework. 6 | 7 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . 8 | 9 | ## Running the application in dev mode 10 | 11 | You can run your application in dev mode that enables live coding using: 12 | ``` 13 | ./mvnw quarkus:dev 14 | ``` 15 | ## Running tests 16 | 17 | You can run your tests using: 18 | ```shell script 19 | ./mvnw test 20 | ``` 21 | -------------------------------------------------------------------------------- /home-automation/src/main/docker/Dockerfile.fast-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/home-automation-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/home-automation-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/home-automation-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | # We make four distinct layers so if there are application changes the library layers can be re-used 49 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 50 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 51 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 52 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 53 | 54 | EXPOSE 8080 55 | USER 1001 56 | 57 | ENTRYPOINT [ "/deployments/run-java.sh" ] 58 | -------------------------------------------------------------------------------- /home-automation/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/home-automation-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/home-automation-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/home-automation-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /home-automation/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/home-automation . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/home-automation 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /home-automation/src/main/java/com/redhat/training/home/automation/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/home-automation/src/main/java/com/redhat/training/home/automation/.gitkeep -------------------------------------------------------------------------------- /home-automation/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuration file 2 | # key = value 3 | -------------------------------------------------------------------------------- /home-automation/src/test/java/com/redhat/training/home/automation/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/home-automation/src/test/java/com/redhat/training/home/automation/.gitkeep -------------------------------------------------------------------------------- /jenkins-agents/jenkins-agent-template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: template.openshift.io/v1 3 | kind: Template 4 | metadata: 5 | name: "${NAME}" 6 | annotations: 7 | openshift.io/display-name: Generic Build Pod 8 | description: "${NAME} build pod template pre-configured to use a jenkins slave in the 9 | same project/namespace" 10 | objects: 11 | - apiVersion: image.openshift.io/v1 12 | kind: ImageStream 13 | metadata: 14 | labels: 15 | build: "${NAME}" 16 | role: jenkins-slave 17 | name: "${NAME}" 18 | - apiVersion: build.openshift.io/v1 19 | kind: BuildConfig 20 | metadata: 21 | labels: 22 | build: "${NAME}" 23 | type: image 24 | name: "${NAME}" 25 | spec: 26 | nodeSelector: 27 | output: 28 | to: 29 | kind: ImageStreamTag 30 | name: "${NAME}:${SLAVE_IMAGE_TAG}" 31 | postCommit: {} 32 | resources: {} 33 | runPolicy: Serial 34 | source: 35 | contextDir: "${SOURCE_CONTEXT_DIR}" 36 | git: 37 | ref: "${SOURCE_REPOSITORY_REF}" 38 | uri: "${SOURCE_REPOSITORY_URL}" 39 | type: Git 40 | strategy: 41 | dockerStrategy: 42 | dockerfilePath: "${DOCKERFILE_PATH}" 43 | type: Docker 44 | triggers: 45 | - type: ConfigChange 46 | - type: ImageChange 47 | parameters: 48 | - name: NAME 49 | displayName: Name 50 | description: The name assigned to all objects and the resulting imagestream. 51 | required: true 52 | - name: SOURCE_REPOSITORY_URL 53 | displayName: Git Repository URL 54 | description: The URL of the repository with your application source code. 55 | value: https://github.com/RedHatTraining/DO400-apps 56 | - name: SOURCE_REPOSITORY_REF 57 | displayName: Git Reference 58 | description: Set this to a branch name, tag or other ref of your repository if you 59 | are not using the default (master) branch. 60 | value: master 61 | - name: SOURCE_CONTEXT_DIR 62 | displayName: Git Context Directory 63 | description: Set this to the directory where the build information is (e.g. Dockerfile) 64 | if not using the default 65 | - name: SLAVE_IMAGE_TAG 66 | displayName: Image tag for Jenkins slave. 67 | description: This is the image tag used for the Jenkins slave. 68 | value: latest 69 | - name: DOCKERFILE_PATH 70 | displayName: Path to Dockerfile 71 | description: Path for alternate Dockerfile to use for build 72 | value: Dockerfile 73 | labels: 74 | template: build-pod-template 75 | -------------------------------------------------------------------------------- /school-library/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* 6 | -------------------------------------------------------------------------------- /school-library/.gitignore: -------------------------------------------------------------------------------- 1 | #Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | release.properties 7 | 8 | # Eclipse 9 | .project 10 | .classpath 11 | .settings/ 12 | bin/ 13 | 14 | # IntelliJ 15 | .idea 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # NetBeans 21 | nb-configuration.xml 22 | 23 | # Visual Studio Code 24 | .vscode 25 | .factorypath 26 | 27 | # OSX 28 | .DS_Store 29 | 30 | # Vim 31 | *.swp 32 | *.swo 33 | 34 | # patch 35 | *.orig 36 | *.rej 37 | 38 | -------------------------------------------------------------------------------- /school-library/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/school-library/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /school-library/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /school-library/README.md: -------------------------------------------------------------------------------- 1 | # School Library example app 2 | 3 | Quarkus example application for the DO400 course. 4 | 5 | This project uses Quarkus, the Supersonic Subatomic Java Framework. 6 | 7 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . 8 | 9 | ## Running the application in dev mode 10 | 11 | You can run your application in dev mode that enables live coding using: 12 | ```shell script 13 | ./mvnw compile quarkus:dev 14 | ``` 15 | 16 | ## Running tests 17 | 18 | You can run your tests using: 19 | ```shell script 20 | ./mvnw test 21 | ``` 22 | 23 | ## Packaging and running the application 24 | 25 | The application can be packaged using: 26 | ```shell script 27 | ./mvnw package 28 | ``` 29 | It produces the `code-with-quarkus-1.0.0-SNAPSHOT-runner.jar` file in the `/target` directory. 30 | Be aware that it?s not an _?ber-jar_ as the dependencies are copied into the `target/lib` directory. 31 | If you want to build an _?ber-jar_, just add the `--uber-jar` option to the command line: 32 | ```shell script 33 | ./mvnw package -PuberJar 34 | ``` 35 | 36 | The application is now runnable using `java -jar target/code-with-quarkus-1.0.0-SNAPSHOT-runner.jar`. 37 | 38 | ## Creating a native executable 39 | 40 | You can create a native executable using: 41 | ```shell script 42 | ./mvnw package -Pnative 43 | ``` 44 | 45 | Or, if you don't have GraalVM installed, you can run the native executable build in a container using: 46 | ```shell script 47 | ./mvnw package -Pnative -Dquarkus.native.container-build=true 48 | ``` 49 | 50 | You can then execute your native executable with: `./target/code-with-quarkus-1.0.0-SNAPSHOT-runner` 51 | 52 | If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html. 53 | 54 | # Command Mode 55 | 56 | Guide: https://quarkus.io/guides/command-mode-reference 57 | -------------------------------------------------------------------------------- /school-library/src/main/docker/Dockerfile.fast-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/code-with-quarkus-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/code-with-quarkus-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | # We make four distinct layers so if there are application changes the library layers can be re-used 49 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 50 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 51 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 52 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 53 | 54 | EXPOSE 8080 55 | USER 1001 56 | 57 | ENTRYPOINT [ "/deployments/run-java.sh" ] 58 | -------------------------------------------------------------------------------- /school-library/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/code-with-quarkus-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/code-with-quarkus-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] -------------------------------------------------------------------------------- /school-library/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/code-with-quarkus . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] -------------------------------------------------------------------------------- /school-library/src/main/java/com/redhat/training/BookStats.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import com.redhat.training.books.Book; 4 | 5 | public class BookStats { 6 | 7 | public static int countWords(Book book) { 8 | if (book.text.isEmpty()) { 9 | return 0; 10 | } 11 | 12 | return book.text.split("\\s+").length; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /school-library/src/main/java/com/redhat/training/Library.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | 6 | import javax.enterprise.context.ApplicationScoped; 7 | 8 | import com.redhat.training.books.Book; 9 | import com.redhat.training.books.BookNotAvailableException; 10 | import com.redhat.training.inventory.Inventory; 11 | 12 | 13 | @ApplicationScoped 14 | public class Library { 15 | 16 | private final Inventory inventory; 17 | private final LoanRegistry loans = new LoanRegistry(); 18 | 19 | public Library(Inventory inventory) { 20 | this.inventory = inventory; 21 | } 22 | 23 | public Book checkOut(String studentId, String isbn) throws BookNotAvailableException { 24 | if (!inventory.isBookAvailable(isbn)) { 25 | throw new BookNotAvailableException(isbn); 26 | } 27 | 28 | Book book = inventory.withdraw(isbn); 29 | loans.markAsBorrowed(studentId, book); 30 | 31 | return book; 32 | } 33 | 34 | public double getAvailablityRate() { 35 | return 1 - ((double) loans.count() / inventory.count()); 36 | } 37 | } 38 | 39 | class LoanRegistry { 40 | 41 | private final HashMap> loans = new HashMap<>(); 42 | 43 | public void markAsBorrowed(String studentId, Book book) { 44 | if (!loans.containsKey(studentId)) { 45 | loans.put(studentId, new ArrayList()); 46 | } 47 | loans.get(studentId).add(book); 48 | } 49 | 50 | public int count() { 51 | int count = 0; 52 | for (ArrayList studentLoans: loans.values()) { 53 | count += studentLoans.size(); 54 | } 55 | return count; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /school-library/src/main/java/com/redhat/training/SchoolLibraryApp.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import javax.inject.Inject; 5 | 6 | import com.redhat.training.books.Book; 7 | import com.redhat.training.inventory.Inventory; 8 | 9 | import io.quarkus.runtime.QuarkusApplication; 10 | import io.quarkus.runtime.annotations.QuarkusMain; 11 | 12 | 13 | @QuarkusMain 14 | @ApplicationScoped 15 | public class SchoolLibraryApp implements QuarkusApplication { 16 | 17 | @Inject 18 | Library library; 19 | 20 | @Inject 21 | Inventory inventory; 22 | 23 | @Override 24 | public int run(String... args) throws Exception { 25 | inventory.add(new Book("book1")); 26 | inventory.add(new Book("book1")); 27 | inventory.add(new Book("book1")); 28 | 29 | library.checkOut("student1" , "book1"); 30 | System.out.println(library.getAvailablityRate() * 100 + "% of the library books are available"); 31 | 32 | return 0; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /school-library/src/main/java/com/redhat/training/books/Book.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.books; 2 | 3 | public class Book { 4 | 5 | public String isbn; 6 | public String text; 7 | 8 | public Book(String isbn) { 9 | this.isbn = isbn; 10 | text = ""; 11 | } 12 | 13 | public Book(String isbn, String text) { 14 | this.isbn = isbn; 15 | this.text = text; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /school-library/src/main/java/com/redhat/training/books/BookNotAvailableException.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.books; 2 | 3 | public class BookNotAvailableException extends Exception { 4 | 5 | private static final long serialVersionUID = -5692072907291015767L; 6 | 7 | public BookNotAvailableException(String isbn) { 8 | super(String.format("Book %s is not available", isbn)); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /school-library/src/main/java/com/redhat/training/inventory/InMemoryInventory.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.inventory; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | 6 | import javax.enterprise.context.ApplicationScoped; 7 | 8 | import com.redhat.training.books.Book; 9 | 10 | 11 | @ApplicationScoped 12 | public class InMemoryInventory implements Inventory { 13 | 14 | int totalCopies = 0; 15 | HashMap> books = new HashMap<>(); 16 | 17 | @Override 18 | public void add(Book book) { 19 | if (!books.containsKey(book.isbn)) { 20 | books.put(book.isbn, new ArrayList()); 21 | } 22 | books.get(book.isbn).add(book); 23 | totalCopies++; 24 | } 25 | 26 | @Override 27 | public Book withdraw(String bookId) { 28 | return books.get(bookId).remove(0); 29 | } 30 | 31 | @Override 32 | public boolean isBookAvailable(String isbn) { 33 | if (books.containsKey(isbn)) { 34 | return books.get(isbn).size() > 0; 35 | } 36 | 37 | return false; 38 | } 39 | 40 | @Override 41 | public int count() { 42 | return totalCopies; 43 | } 44 | 45 | public Integer countCopies(String isbn) { 46 | return books.get(isbn).size(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /school-library/src/main/java/com/redhat/training/inventory/Inventory.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training.inventory; 2 | 3 | import com.redhat.training.books.Book; 4 | 5 | public interface Inventory { 6 | public void add(Book book); 7 | 8 | public int count(); 9 | 10 | public boolean isBookAvailable(String isbn); 11 | 12 | public Book withdraw(String isbn); 13 | } 14 | -------------------------------------------------------------------------------- /school-library/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/school-library/src/main/resources/application.properties -------------------------------------------------------------------------------- /school-library/src/test/java/com/redhat/training/BookStatsTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import com.redhat.training.books.Book; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | public class BookStatsTest { 10 | 11 | @Test 12 | public void countingWordsOfEmptyBookReturnsZero() { 13 | // Given 14 | Book book = new Book("someISBN"); 15 | 16 | // When 17 | double wordCount = BookStats.countWords(book); 18 | 19 | // Then 20 | assertEquals(0, wordCount); 21 | } 22 | 23 | @Test 24 | public void countingWordsReturnsNumberOfWordsInBook() { 25 | assertEquals(0, 1); // Replace this line with the actual test code... 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /school-library/src/test/java/com/redhat/training/LibraryTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.assertThrows; 8 | import static org.junit.jupiter.api.Assertions.assertTrue; 9 | 10 | import com.redhat.training.books.Book; 11 | import com.redhat.training.books.BookNotAvailableException; 12 | import com.redhat.training.inventory.InMemoryInventory; 13 | 14 | 15 | public class LibraryTest { 16 | 17 | InMemoryInventory inventory; 18 | Library library; 19 | 20 | @BeforeEach 21 | public void setUp() { 22 | inventory = new InMemoryInventory(); 23 | library = new Library(inventory); 24 | } 25 | 26 | // Add tests here... 27 | } 28 | -------------------------------------------------------------------------------- /school-library/src/test/java/com/redhat/training/LibraryWithMockedInventoryTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.training; 2 | 3 | import static org.mockito.Mockito.verify; 4 | import static org.mockito.Mockito.when; 5 | import static org.mockito.Mockito.mock; 6 | import static org.mockito.Mockito.times; 7 | 8 | import com.redhat.training.books.BookNotAvailableException; 9 | import com.redhat.training.inventory.Inventory; 10 | 11 | import org.junit.jupiter.api.BeforeEach; 12 | import org.junit.jupiter.api.Test; 13 | 14 | 15 | public class LibraryWithMockedInventoryTest { 16 | 17 | Inventory inventory; 18 | Library library; 19 | 20 | @BeforeEach 21 | public void setUp() { 22 | inventory = mock(Inventory.class); 23 | library = new Library(inventory); 24 | } 25 | 26 | // Add tests here... 27 | } 28 | -------------------------------------------------------------------------------- /scoreboard/.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | tab_width = 4 3 | indent_size = 4 4 | insert_final_newline = true 5 | -------------------------------------------------------------------------------- /scoreboard/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true, 5 | "es6": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:react/recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "prettier/@typescript-eslint", 12 | "plugin:prettier/recommended" 13 | ], 14 | "globals": { 15 | "Atomics": "readonly", 16 | "SharedArrayBuffer": "readonly", 17 | "process": "readonly" 18 | }, 19 | "parser": "@typescript-eslint/parser", 20 | "parserOptions": { 21 | "ecmaFeatures": { 22 | "jsx": true 23 | }, 24 | "ecmaVersion": 2018, 25 | "sourceType": "module" 26 | }, 27 | "plugins": ["react", "@typescript-eslint"], 28 | "rules": { 29 | "max-len": ["error", 120], 30 | "indent": ["error", 4], 31 | "linebreak-style": ["error", "unix"], 32 | // Prettier determines quotes that are easiest to read 33 | "quotes": ["off", "double"], 34 | "semi": ["error", "always"], 35 | "eol-last": ["error", "always"] 36 | }, 37 | "settings": { 38 | "react": { 39 | "version": "detect" 40 | } 41 | }, 42 | "overrides": [ 43 | { 44 | "files": ["*.ts", "*.tsx"], 45 | "rules": { 46 | "@typescript-eslint/no-unused-vars": [ 47 | 2, 48 | { 49 | "args": "none" 50 | } 51 | ] 52 | } 53 | }, 54 | { 55 | "files": ["server.js", "src/Config.js"], 56 | "env": { 57 | "node": true 58 | } 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /scoreboard/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | 23 | # cypress 24 | *.mp4 25 | -------------------------------------------------------------------------------- /scoreboard/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 4 4 | } 5 | -------------------------------------------------------------------------------- /scoreboard/README.md: -------------------------------------------------------------------------------- 1 | # Scoreboard 2 | 3 | A simple scoreboard app built using React. 4 | 5 | ![](screenshot.png) 6 | 7 | ## Pre-requisites 8 | 9 | To run the application, you will need: 10 | 11 | - Node.js version 12 or higher 12 | - NPM version 6 or higher 13 | 14 | Additionally, in order to run functional tests with Cypress, you will need either Chrome or Firefox installed. 15 | You may instead use Docker to run Cypress in "headless mode" (see below under `npm run cy:docker`). 16 | 17 | See more details about system requirements for Cypress here: 18 | [https://docs.cypress.io/guides/getting-started/installing-cypress.html#System-requirements](https://docs.cypress.io/guides/getting-started/installing-cypress.html#System-requirements) 19 | 20 | ## Installation 21 | 22 | Install all NPM dependencies by running: 23 | 24 | `npm install` 25 | 26 | Install NPM dependencies excluding develepment-only dependencies by running: 27 | 28 | `npm install --prod` 29 | 30 | ## Available Scripts 31 | 32 | In the project directory, you can run: 33 | 34 | ### `npm start` 35 | 36 | Runs the app in the development mode.
37 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 38 | 39 | The page will reload if you make edits.
40 | You will also see any lint errors in the console. 41 | 42 | ### `npm test` 43 | 44 | Launches the test runner in the interactive watch mode.
45 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 46 | 47 | ### `npm run build` 48 | 49 | Builds the app for production to the `build` folder.
50 | It correctly bundles React in production mode and optimizes the build for the best performance. 51 | 52 | The build is minified and the filenames include the hashes.
53 | Your app is ready to be deployed! 54 | 55 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 56 | 57 | ### `npm run format` 58 | 59 | Automatically formats all files using Prettier. 60 | Learn more about Prettier at [prettier.io](https://prettier.io) 61 | 62 | ### `npm run cy:open` 63 | 64 | Opens the Cypress GUI. 65 | This allows you to select which browser Cypress should use, as well as select test files to run. 66 | 67 | Requires Chrome or Firefox installation. 68 | The development server must also be running (see `npm start`). 69 | 70 | ### `npm run cy:run` 71 | 72 | Runs all Cypress tests in "headless mode" (doesn't open a browser window). 73 | 74 | Requires Chrome or Firefox installation. 75 | The development server must also be running (see `npm start`). 76 | 77 | ### `npm run cy:docker` 78 | 79 | Runs all Cypress tests in "headless mode" withing a container using Docker. 80 | 81 | Requires Docker installation. 82 | The development server must also be running (see `npm start`). 83 | 84 | ### `npm run cy:podman` 85 | 86 | Runs all Cypress tests in "headless mode" withing a container using podman. 87 | 88 | Requires podman installation. 89 | The development server must also be running (see `npm start`). 90 | -------------------------------------------------------------------------------- /scoreboard/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000" 3 | } 4 | -------------------------------------------------------------------------------- /scoreboard/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /scoreboard/cypress/integration/scoreboard.spec.ts: -------------------------------------------------------------------------------- 1 | beforeEach(() => { 2 | // GIVEN the user is on the app 3 | cy.visit("/"); 4 | }); 5 | 6 | describe("add player", () => { 7 | it("should add a player", () => { 8 | // AND the user has entered 'bobby' into the 'Player Name' field 9 | cy.get("form").find('[placeholder="Player Name"]').type("bobby"); 10 | 11 | // WHEN they submit the form 12 | cy.get("form").submit(); 13 | 14 | // THEN 'bobby' should be added to the players 15 | cy.get("#player-scores").should("contain", "bobby"); 16 | }); 17 | }); 18 | 19 | describe("update score", () => { 20 | beforeEach(() => { 21 | // AND the player 'tom' exists 22 | cy.get("form").find('[placeholder="Player Name"]').type("tom"); 23 | cy.get("form").submit(); 24 | }); 25 | 26 | it("should increase a player's score", () => { 27 | // AND tom has a score of 0 28 | cy.get("#player-scores").should("contain", "tom: 0"); 29 | 30 | // WHEN the user hits '+' next to 'tom' 31 | cy.get("#player-scores") 32 | .contains("tom") 33 | .siblings() 34 | .contains("+") 35 | .click(); 36 | 37 | // THEN 'tom's score should be 1 38 | cy.get("#player-scores").should("contain", "tom: 1"); 39 | }); 40 | 41 | it.skip("should decrease a player's score", () => { 42 | // AND tom has a score of 0 43 | cy.get("#player-scores").should("contain", "tom: 0"); 44 | 45 | // WHEN the user hits '-' next to 'tom' 46 | cy.get("#player-scores") 47 | .contains("tom") 48 | .siblings() 49 | .contains("-") 50 | .click(); 51 | 52 | // THEN 'tom's score should be -1 53 | cy.get("#player-scores").should("contain", "tom: 0"); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /scoreboard/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | module.exports = (on, config) => { 19 | // `on` is used to hook into various events Cypress emits 20 | // `config` is the resolved Cypress config 21 | } 22 | -------------------------------------------------------------------------------- /scoreboard/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /scoreboard/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /scoreboard/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es5", "dom"], 5 | "types": ["cypress"] 6 | }, 7 | "include": ["**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /scoreboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scoreboard", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^4.2.4", 7 | "@testing-library/react": "^9.3.2", 8 | "@testing-library/user-event": "^7.1.2", 9 | "@types/jest": "^24.0.0", 10 | "@types/node": "^12.0.0", 11 | "@types/react": "^16.9.0", 12 | "@types/react-dom": "^16.9.0", 13 | "react": "^16.14.0", 14 | "react-dom": "^16.14.0", 15 | "react-scripts": "^3.4.4", 16 | "typescript": "~3.7.2" 17 | }, 18 | "devDependencies": { 19 | "cross-env": "^7.0.2", 20 | "cypress": "^5.4.0" 21 | }, 22 | "scripts": { 23 | "start": "react-scripts start", 24 | "build": "react-scripts build", 25 | "format": "prettier --write .", 26 | "test": "react-scripts test", 27 | "test:coverage": "cross-env CI=true npm run test --ci --coverage --collectCoverageFrom='src'", 28 | "cy:open": "cross-env CYPRESS_CRASH_REPORTS=0 cypress open", 29 | "cy:run": "cross-env CYPRESS_CRASH_REPORTS=0 cypress run", 30 | "cy:docker": "docker run -it --rm -v $PWD:/e2e -w /e2e cypress/included:5.4.0 --config baseUrl=http://host.docker.internal:3000", 31 | "cy:podman": "podman run -it --rm -v $PWD:/e2e -w /e2e cypress/included:5.4.0 --config baseUrl=http://172.17.0.1:3000" 32 | }, 33 | "eslintConfig": { 34 | "extends": "react-app" 35 | }, 36 | "browserslist": { 37 | "production": [ 38 | ">0.2%", 39 | "not dead", 40 | "not op_mini all" 41 | ], 42 | "development": [ 43 | "last 1 chrome version", 44 | "last 1 firefox version", 45 | "last 1 safari version" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /scoreboard/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/scoreboard/public/favicon.ico -------------------------------------------------------------------------------- /scoreboard/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Scoreboard 28 | 29 | 30 | 31 |
32 | 42 | 43 | -------------------------------------------------------------------------------- /scoreboard/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/scoreboard/public/logo192.png -------------------------------------------------------------------------------- /scoreboard/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/scoreboard/public/logo512.png -------------------------------------------------------------------------------- /scoreboard/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /scoreboard/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /scoreboard/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/scoreboard/screenshot.png -------------------------------------------------------------------------------- /scoreboard/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import App from "./App"; 4 | 5 | jest.mock("./ScoreDisplay"); 6 | 7 | describe("App Component", () => { 8 | test("renders the app component", () => { 9 | const { getByText, getAllByText } = render(); 10 | expect(getByText(/Scoreboard/i)).toBeInTheDocument(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /scoreboard/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | 3 | import { Player } from "./Player"; 4 | import { ScoreDisplay } from "./ScoreDisplay"; 5 | 6 | function App() { 7 | const [playerName, setPlayerName] = useState(""); 8 | const [players, setPlayers] = useState([]); 9 | 10 | function updateScore(playerName: string, newScore: number) { 11 | const updatedPlayers = players.map((player) => { 12 | if (player.name === playerName) { 13 | return { ...player, score: newScore }; 14 | } else { 15 | return player; 16 | } 17 | }); 18 | setPlayers(updatedPlayers); 19 | } 20 | 21 | function newPlayerSubmit(e: React.FormEvent) { 22 | e.preventDefault(); 23 | setPlayers([...players, { name: playerName, score: 0 }]); 24 | } 25 | 26 | return ( 27 | <> 28 |

Scoreboard

29 | 30 |
31 | {players.map((player, index) => ( 32 | 38 | ))} 39 |
40 | 41 |
42 | 43 |
44 | setPlayerName(e.currentTarget.value)} 50 | /> 51 | 52 |
53 | 54 | ); 55 | } 56 | 57 | export default App; 58 | -------------------------------------------------------------------------------- /scoreboard/src/Player.ts: -------------------------------------------------------------------------------- 1 | export interface Player { 2 | name: string; 3 | score: number; 4 | } 5 | -------------------------------------------------------------------------------- /scoreboard/src/ScoreDisplay.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { fireEvent, render } from "@testing-library/react"; 3 | import { ScoreDisplay } from "./ScoreDisplay"; 4 | 5 | describe("ScoreDisplay Component", () => { 6 | test("renders a player's score", () => { 7 | const { getByText } = render( 8 | {}} />, 9 | ); 10 | expect(getByText(/foo: 3/i)).toBeInTheDocument(); 11 | }); 12 | 13 | test("calls update score on + and -", () => { 14 | const updateScoreMock = jest.fn(); 15 | const { getByText } = render( 16 | , 21 | ); 22 | fireEvent.click(getByText(/\+/)); 23 | fireEvent.click(getByText(/\-/)); 24 | expect(updateScoreMock).toBeCalledTimes(2); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /scoreboard/src/ScoreDisplay.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export function ScoreDisplay(props: { 4 | name: string; 5 | score: number; 6 | onUpdateScore: (name: string, score: number) => void; 7 | }) { 8 | const { name, score } = props; 9 | 10 | return ( 11 |
12 | 13 | {name}: {score} 14 | 15 | 22 | 29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /scoreboard/src/__mocks__/ScoreDisplay.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export function ScoreDisplay() { 4 | return mocked score display; 5 | } 6 | -------------------------------------------------------------------------------- /scoreboard/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", 3 | "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 4 | "Helvetica Neue", sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | width: 15em; 8 | } 9 | 10 | .score-display { 11 | height: 2em; 12 | } 13 | 14 | .score-display button { 15 | float: right; 16 | } 17 | -------------------------------------------------------------------------------- /scoreboard/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import * as serviceWorker from "./serviceWorker"; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById("root"), 12 | ); 13 | 14 | // If you want your app to work offline and load faster, you can change 15 | // unregister() to register() below. Note this comes with some pitfalls. 16 | // Learn more about service workers: https://bit.ly/CRA-PWA 17 | serviceWorker.unregister(); 18 | -------------------------------------------------------------------------------- /scoreboard/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /scoreboard/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import "@testing-library/jest-dom/extend-expect"; 6 | -------------------------------------------------------------------------------- /scoreboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "react" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /shipping-calculator/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* 6 | -------------------------------------------------------------------------------- /shipping-calculator/.gitignore: -------------------------------------------------------------------------------- 1 | #Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | release.properties 7 | # Eclipse 8 | .project 9 | .classpath 10 | .settings/ 11 | bin/ 12 | 13 | # IntelliJ 14 | .idea 15 | *.ipr 16 | *.iml 17 | *.iws 18 | 19 | # NetBeans 20 | nb-configuration.xml 21 | 22 | # Visual Studio Code 23 | .vscode 24 | .factorypath 25 | 26 | # OSX 27 | .DS_Store 28 | 29 | # Vim 30 | *.swp 31 | *.swo 32 | 33 | # patch 34 | *.orig 35 | *.rej 36 | 37 | -------------------------------------------------------------------------------- /shipping-calculator/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shipping-calculator/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /shipping-calculator/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /shipping-calculator/README.md: -------------------------------------------------------------------------------- 1 | # Shipping Calculator example app 2 | 3 | This project uses Quarkus, the Supersonic Subatomic Java Framework. 4 | 5 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . 6 | 7 | ## Running the application in dev mode 8 | 9 | You can run your application in dev mode that enables live coding using: 10 | ```shell script 11 | ./mvnw compile quarkus:dev 12 | ``` 13 | 14 | ## Packaging and running the application 15 | 16 | The application can be packaged using: 17 | ```shell script 18 | ./mvnw package 19 | ``` 20 | It produces the `shipping-calculator-1.0-SNAPSHOT-runner.jar` file in the `/target` directory. 21 | Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/lib` directory. 22 | If you want to build an _über-jar_, execute the following command: 23 | ```shell script 24 | ./mvnw package build -Dquarkus.package.type=uber-jar 25 | ``` 26 | 27 | The application is now runnable using `java -jar target/shipping-calculator-1.0-SNAPSHOT-runner.jar`. 28 | 29 | ## Creating a native executable 30 | 31 | You can create a native executable using: 32 | ```shell script 33 | ./mvnw package -Pnative 34 | ``` 35 | 36 | Or, if you don't have GraalVM installed, you can run the native executable build in a container using: 37 | ```shell script 38 | ./mvnw package -Pnative -Dquarkus.native.container-build=true 39 | ``` 40 | 41 | You can then execute your native executable with: `./target/shipping-calculator-1.0-SNAPSHOT-runner` 42 | 43 | If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html. 44 | 45 | # Command Mode 46 | 47 | Guide: https://quarkus.io/guides/command-mode-reference 48 | -------------------------------------------------------------------------------- /shipping-calculator/src/main/docker/Dockerfile.fast-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/shipping-calculator-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shipping-calculator-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/shipping-calculator-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | # We make four distinct layers so if there are application changes the library layers can be re-used 49 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 50 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 51 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 52 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 53 | 54 | EXPOSE 8080 55 | USER 1001 56 | 57 | ENTRYPOINT [ "/deployments/run-java.sh" ] 58 | -------------------------------------------------------------------------------- /shipping-calculator/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/shipping-calculator-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shipping-calculator-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/shipping-calculator-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /shipping-calculator/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/shipping-calculator . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shipping-calculator 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /shipping-calculator/src/main/java/com/redhat/shipping/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shipping-calculator/src/main/java/com/redhat/shipping/.gitkeep -------------------------------------------------------------------------------- /shipping-calculator/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shipping-calculator/src/main/resources/application.properties -------------------------------------------------------------------------------- /shipping-calculator/src/test/java/com/redhat/shipping/ShippingCalculatorTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shipping; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.*; 6 | 7 | public class ShippingCalculatorTest { 8 | 9 | // @todo: add tests 10 | } 11 | -------------------------------------------------------------------------------- /shopping-cart-v2/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* 6 | -------------------------------------------------------------------------------- /shopping-cart-v2/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | .factorypath 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Vim 24 | *.swp 25 | *.swo 26 | 27 | # patch 28 | *.orig 29 | *.rej 30 | 31 | # Maven 32 | target/ 33 | pom.xml.tag 34 | pom.xml.releaseBackup 35 | pom.xml.versionsBackup 36 | release.properties 37 | -------------------------------------------------------------------------------- /shopping-cart-v2/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shopping-cart-v2/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /shopping-cart-v2/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /shopping-cart-v2/.s2i/environment: -------------------------------------------------------------------------------- 1 | MAVEN_S2I_ARTIFACT_DIRS=target 2 | S2I_SOURCE_DEPLOYMENTS_FILTER=*-runner.jar lib 3 | JAVA_OPTIONS=-Dquarkus.http.host=0.0.0.0 4 | AB_JOLOKIA_OFF=true 5 | -------------------------------------------------------------------------------- /shopping-cart-v2/README.md: -------------------------------------------------------------------------------- 1 | # Shopping Cart example app with slow storage 2 | 3 | Quarkus example application for the DO400 course. 4 | 5 | This project uses Quarkus, the Supersonic Subatomic Java Framework. 6 | 7 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . 8 | 9 | ## Running the application in dev mode 10 | 11 | You can run your application in dev mode that enables live coding using: 12 | ``` 13 | ./mvnw quarkus:dev 14 | ``` 15 | 16 | ## Packaging and running the application 17 | 18 | The application can be packaged using `./mvnw package`. 19 | It produces the `shopping-cart-1.0-SNAPSHOT-runner.jar` file in the `/target` directory. 20 | Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/lib` directory. 21 | 22 | The application is now runnable using `java -jar target/shopping-cart-1.0-SNAPSHOT-runner.jar`. 23 | 24 | ## Creating a native executable 25 | 26 | You can create a native executable using: `./mvnw package -Pnative`. 27 | 28 | Or, if you don't have GraalVM installed, you can run the native executable build in a container using: `./mvnw package -Pnative -Dquarkus.native.container-build=true`. 29 | 30 | You can then execute your native executable with: `./target/shopping-cart-1.0-SNAPSHOT-runner` 31 | 32 | If you want to learn more about building native executables, please consult https://quarkus.io/guides/building-native-image. -------------------------------------------------------------------------------- /shopping-cart-v2/kubefiles/application-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Template 3 | metadata: 4 | name: shopping-cart-template 5 | annotations: 6 | description: "Shopping Cart Template" 7 | objects: 8 | - kind: Deployment 9 | apiVersion: apps/v1 10 | metadata: 11 | name: shopping-cart-v2 12 | spec: 13 | selector: 14 | matchLabels: 15 | app: shopping-cart-v2 16 | replicas: 1 17 | template: 18 | metadata: 19 | labels: 20 | app: shopping-cart-v2 21 | spec: 22 | containers: 23 | - name: shopping-cart-v2 24 | image: quay.io/${QUAY_USER_OR_GROUP}/do400-recover:${APP_IMAGE_TAG} 25 | imagePullPolicy: Always 26 | ports: 27 | - containerPort: 8080 28 | - kind: Service 29 | apiVersion: v1 30 | metadata: 31 | labels: 32 | app: shopping-cart-v2 33 | name: shopping-cart-v2 34 | spec: 35 | ports: 36 | - port: 8080 37 | protocol: TCP 38 | targetPort: 8080 39 | selector: 40 | app: shopping-cart-v2 41 | - kind: Route 42 | apiVersion: route.openshift.io/v1 43 | metadata: 44 | name: shopping-cart-v2 45 | labels: 46 | app: shopping-cart-v2 47 | spec: 48 | to: 49 | kind: Service 50 | name: shopping-cart-v2 51 | port: 52 | targetPort: 8080 53 | 54 | parameters: 55 | - name: QUAY_USER_OR_GROUP 56 | description: "Quay User/Group" 57 | required: true 58 | - name: APP_IMAGE_TAG 59 | description: "Image Tag" 60 | required: false 61 | value: "latest" 62 | -------------------------------------------------------------------------------- /shopping-cart-v2/scripts/build-and-push-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts u:p:b: flag 4 | do 5 | case "${flag}" in 6 | u) quay_user=${OPTARG};; 7 | p) quay_password=${OPTARG};; 8 | b) build_number=${OPTARG};; 9 | esac 10 | done 11 | 12 | ./mvnw -Drevision="${build_number}" package -DskipTests \ 13 | -Dquarkus.jib.base-jvm-image=quay.io/redhattraining/do400-java-alpine-openjdk11-jre:latest \ 14 | -Dquarkus.container-image.build=true \ 15 | -Dquarkus.container-image.registry=quay.io \ 16 | -Dquarkus.container-image.group="${quay_user}" \ 17 | -Dquarkus.container-image.name=do400-recover \ 18 | -Dquarkus.container-image.username="${quay_user}" \ 19 | -Dquarkus.container-image.password="${quay_password}" \ 20 | -Dquarkus.container-image.additional-tags="latest" \ 21 | -Dquarkus.container-image.push=true 22 | -------------------------------------------------------------------------------- /shopping-cart-v2/scripts/deploy-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts u:t:n: flag 4 | do 5 | case "${flag}" in 6 | u) quay_user=${OPTARG};; 7 | t) image_tag=${OPTARG};; 8 | n) app_namespace=${OPTARG};; 9 | esac 10 | done 11 | 12 | oc set image deployment/shopping-cart-v2 \ 13 | -n "${app_namespace}" \ 14 | "shopping-cart-v2=quay.io/${quay_user}/do400-recover:${image_tag}" 15 | -------------------------------------------------------------------------------- /shopping-cart-v2/scripts/include-container-extensions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./mvnw quarkus:add-extension \ 3 | -Dextensions="kubernetes,container-image-jib" 4 | -------------------------------------------------------------------------------- /shopping-cart-v2/scripts/redeploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | oc patch deployment/shopping-cart-v2 \ 4 | -n ${1} \ 5 | -p "{\"spec\": {\"template\": {\"metadata\": { \"labels\": { \"redeploy\": \"$(date +%s)\"}}}}}" 6 | -------------------------------------------------------------------------------- /shopping-cart-v2/scripts/tag-exists-in-quay.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function tag_exists() { 4 | curl -sfSL https://quay.io/v1/repositories/$1/tags/$2 &> /dev/null 5 | } 6 | 7 | echo "Checking the existence of the tag $2 in the repository $1" 8 | 9 | if tag_exists ${1} ${2}; then 10 | echo "Tag exists" 11 | exit 0 12 | fi 13 | 14 | echo "Tag not found!" 15 | exit 1 16 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/docker/Dockerfile.fast-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/shopping-cart-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shopping-cart-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/shopping-cart-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | # We make four distinct layers so if there are application changes the library layers can be re-used 49 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 50 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 51 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 52 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 53 | 54 | EXPOSE 8080 55 | USER 1001 56 | 57 | ENTRYPOINT [ "/deployments/run-java.sh" ] 58 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/shopping-cart-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shopping-cart-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/shopping-cart-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/shopping-cart . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shopping-cart 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/cart/AddToCartCommand.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | public class AddToCartCommand { 4 | 5 | public int id; 6 | public int quantity; 7 | 8 | public AddToCartCommand() { 9 | } 10 | 11 | public AddToCartCommand(int id, int quantity) { 12 | this.id = id; 13 | this.quantity = quantity; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/cart/CartItem.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | public class CartItem { 4 | 5 | private final int id; 6 | private final int price; 7 | private int quantity = 0; 8 | 9 | public CartItem(int id, int price) { 10 | this.id = id; 11 | this.price = price; 12 | } 13 | 14 | public void increaseQuantityBy(int increment) { 15 | this.quantity += increment; 16 | } 17 | 18 | public int getId() { 19 | return this.id; 20 | } 21 | 22 | public int getPrice() { 23 | return this.price; 24 | } 25 | 26 | public int getQuantity() { 27 | return this.quantity; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/cart/CartService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | import com.redhat.shopping.catalog.Catalog; 4 | import com.redhat.shopping.catalog.Product; 5 | import com.redhat.shopping.catalog.ProductNotFoundInCatalogException; 6 | 7 | import javax.enterprise.context.ApplicationScoped; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | @ApplicationScoped 12 | public class CartService { 13 | 14 | private final Map products = new HashMap<>(); 15 | private int totalItems = 0; 16 | 17 | private final Catalog catalog; 18 | 19 | public CartService(Catalog catalog) { 20 | this.catalog = catalog; 21 | } 22 | 23 | private void recalculate() { 24 | this.totalItems = 0; 25 | 26 | this.products.forEach((id, cartItem) -> { 27 | this.totalItems += cartItem.getQuantity(); 28 | }); 29 | } 30 | 31 | public void addProduct(int productId, int quantity) throws ProductNotFoundInCatalogException { 32 | Product product = this.catalog.ofId(productId); 33 | 34 | if (!this.products.containsKey(productId)) { 35 | this.products.put(product.id(), new CartItem(product.id(), product.price())); 36 | } 37 | 38 | this.products.get(product.id()).increaseQuantityBy(quantity); 39 | 40 | this.recalculate(); 41 | } 42 | 43 | public void clear() { 44 | this.products.clear(); 45 | this.recalculate(); 46 | } 47 | 48 | public CartView cartContent() { 49 | return new CartView(this.products.values(), this.totalItems()); 50 | } 51 | 52 | public void removeProduct(int productId) throws ProductNotFoundInCatalogException, ProductNotInCartException { 53 | Product product = this.catalog.ofId(productId); 54 | 55 | if (!this.products.containsKey(product.id())) { 56 | throw ProductNotInCartException.ofId(product.id()); 57 | } 58 | 59 | this.products.remove(product.id()); 60 | 61 | this.recalculate(); 62 | } 63 | 64 | public int totalItems() { 65 | return this.totalItems; 66 | } 67 | 68 | public int totalProducts() { 69 | return this.products.size(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/cart/CartView.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | 6 | public class CartView { 7 | 8 | public ArrayList products; 9 | public int totalItems; 10 | 11 | public CartView() { 12 | } 13 | 14 | public CartView(Collection products, int totalItems) { 15 | this.products = new ArrayList<>(products); 16 | this.totalItems = totalItems; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/cart/ProductNotInCartException.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | public class ProductNotInCartException extends Exception { 4 | 5 | public ProductNotInCartException(String errorMessage) { 6 | super(errorMessage); 7 | } 8 | 9 | public static ProductNotInCartException ofId(int id) { 10 | return new ProductNotInCartException(String.format("Product with ID: %d not found in cart", id)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/catalog/Catalog.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | import java.util.Collection; 4 | 5 | public interface Catalog { 6 | Collection getAll(); 7 | 8 | Product ofId(int id) throws ProductNotFoundInCatalogException; 9 | } 10 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/catalog/CatalogService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import java.util.Collection; 5 | 6 | @ApplicationScoped 7 | public class CatalogService implements Catalog { 8 | 9 | private final CatalogStorage storage; 10 | 11 | public CatalogService(CatalogStorage storage) { 12 | this.storage = storage; 13 | } 14 | 15 | @Override 16 | public Collection getAll() { 17 | return this.storage.getAll(); 18 | } 19 | 20 | public Product ofId(int id) throws ProductNotFoundInCatalogException { 21 | if (!this.storage.containsKey(id)) { 22 | throw ProductNotFoundInCatalogException.ofId(id); 23 | } 24 | 25 | return this.storage.get(id); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/catalog/CatalogStorage.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | import java.util.Collection; 4 | 5 | public interface CatalogStorage { 6 | boolean containsKey(int id); 7 | Product get(int id); 8 | Collection getAll(); 9 | } 10 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/catalog/Product.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | public class Product { 4 | 5 | private final int id; 6 | private final int price; 7 | 8 | public Product(int id, int price) { 9 | this.id = id; 10 | this.price = price; 11 | } 12 | 13 | public int id() { 14 | return this.id; 15 | } 16 | 17 | public int price() { 18 | return this.price; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/catalog/ProductNotFoundInCatalogException.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | public class ProductNotFoundInCatalogException extends Exception { 4 | 5 | public ProductNotFoundInCatalogException(String errorMessage) { 6 | super(errorMessage); 7 | } 8 | 9 | public static ProductNotFoundInCatalogException ofId(int id) { 10 | return new ProductNotFoundInCatalogException(String.format("Unable to find product with ID: %d", id)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/java/com/redhat/shopping/catalog/persistence/InMemoryCatalogStorage.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog.persistence; 2 | 3 | import com.redhat.shopping.catalog.CatalogStorage; 4 | import com.redhat.shopping.catalog.Product; 5 | 6 | import javax.enterprise.context.ApplicationScoped; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | @ApplicationScoped 13 | public class InMemoryCatalogStorage implements CatalogStorage { 14 | 15 | private final Map storage = new HashMap<>(); 16 | 17 | private void simulateSlowStorage() { 18 | try { 19 | Thread.sleep(4000); 20 | } catch (InterruptedException e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | 25 | /** 26 | * Initializes a list of 5 products with IDs from 1 to 5 and the price being the result of the ID * 100. 27 | * Simulates persistence with a known set of products. 28 | */ 29 | public InMemoryCatalogStorage() { 30 | for (int id = 1; id < 5; id++) { 31 | this.storage.put(id, new Product(id, id * 100)); 32 | } 33 | } 34 | 35 | public boolean containsKey(int id) { 36 | return storage.containsKey(id); 37 | } 38 | 39 | public Product get(int id) { 40 | this.simulateSlowStorage(); 41 | return storage.get(id); 42 | } 43 | 44 | public Collection getAll() { 45 | return new ArrayList<>(this.storage.values()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | quarkus.http.test-port=8084 2 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/test/java/com/redhat/shopping/integration/blackbox/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shopping-cart-v2/src/test/java/com/redhat/shopping/integration/blackbox/.gitkeep -------------------------------------------------------------------------------- /shopping-cart-v2/src/test/java/com/redhat/shopping/integration/whitebox/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shopping-cart-v2/src/test/java/com/redhat/shopping/integration/whitebox/.gitkeep -------------------------------------------------------------------------------- /shopping-cart-v2/src/test/java/com/redhat/shopping/integration/whitebox/ShoppingCartTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.integration.whitebox; 2 | 3 | import com.redhat.shopping.cart.CartService; 4 | import com.redhat.shopping.catalog.CatalogStorage; 5 | import com.redhat.shopping.catalog.Product; 6 | import com.redhat.shopping.catalog.ProductNotFoundInCatalogException; 7 | import com.redhat.shopping.catalog.persistence.InMemoryCatalogStorage; 8 | import io.quarkus.test.junit.QuarkusMock; 9 | import io.quarkus.test.junit.QuarkusTest; 10 | import org.junit.jupiter.api.BeforeAll; 11 | import org.junit.jupiter.api.BeforeEach; 12 | import org.junit.jupiter.api.Tag; 13 | import org.junit.jupiter.api.Test; 14 | import org.mockito.Mockito; 15 | 16 | import javax.inject.Inject; 17 | 18 | import static org.junit.jupiter.api.Assertions.assertEquals; 19 | import static org.junit.jupiter.api.Assertions.assertThrows; 20 | 21 | @QuarkusTest 22 | @Tag("integration") 23 | public class ShoppingCartTest { 24 | 25 | @Inject 26 | CartService cartService; 27 | 28 | @BeforeEach 29 | void clearCart() { 30 | this.cartService.clear(); 31 | } 32 | 33 | @Test 34 | void addingNonExistingProductInCatalogRaisesAnException() { 35 | assertThrows( 36 | ProductNotFoundInCatalogException.class, 37 | () -> this.cartService.addProduct(9999, 10) 38 | ); 39 | } 40 | 41 | @Test 42 | void addingNonExistingProductInCartTheTotalItemsMatchTheInitialQuantity() 43 | throws ProductNotFoundInCatalogException { 44 | 45 | // Adding a product to the cart 46 | this.cartService.addProduct(1, 10); 47 | 48 | // Assert: the total number of items in the cart is equal to the quantity we added 49 | assertEquals(10, this.cartService.totalItems()); 50 | } 51 | 52 | @Test 53 | void addingProductThatIsInTheCartTheTotalItemsMatchTheSumOfQuantities() 54 | throws ProductNotFoundInCatalogException { 55 | 56 | // Adding a product to the cart with a specified initial quantity 57 | this.cartService.addProduct(1, 10); 58 | 59 | // Adding again the same product to the cart with a specified quantity 60 | this.cartService.addProduct(1, 100); 61 | 62 | // Assert: the total number of items in the cart is the sum of the initial and the incremental quantities 63 | assertEquals(110, this.cartService.totalItems()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/test/java/com/redhat/shopping/unit/ProductMother.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.unit; 2 | 3 | import com.redhat.shopping.catalog.Product; 4 | 5 | public class ProductMother { 6 | 7 | public static Product any() { 8 | return new Product(1, 20); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /shopping-cart-v2/src/test/java/com/redhat/shopping/unit/catalog/CatalogServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.unit.catalog; 2 | 3 | import com.redhat.shopping.catalog.CatalogService; 4 | import com.redhat.shopping.catalog.CatalogStorage; 5 | import com.redhat.shopping.catalog.Product; 6 | import com.redhat.shopping.catalog.ProductNotFoundInCatalogException; 7 | import com.redhat.shopping.unit.ProductMother; 8 | import org.junit.jupiter.api.BeforeEach; 9 | import org.junit.jupiter.api.Tag; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import java.util.Collections; 13 | 14 | import static org.junit.jupiter.api.Assertions.*; 15 | import static org.mockito.Mockito.mock; 16 | import static org.mockito.Mockito.when; 17 | 18 | @Tag("unit") 19 | public class CatalogServiceTest { 20 | 21 | private CatalogStorage catalogStorageMock; 22 | private CatalogService catalogService; 23 | 24 | @BeforeEach 25 | public void setUp() { 26 | catalogStorageMock = mock(CatalogStorage.class); 27 | catalogService = new CatalogService(catalogStorageMock); 28 | } 29 | 30 | @Test 31 | public void givenNoItemsInCatalogThenGetAllReturnsEmptyCollection() { 32 | when(catalogStorageMock.getAll()).thenReturn(Collections.emptyList()); 33 | 34 | assertTrue(catalogService.getAll().isEmpty()); 35 | } 36 | 37 | @Test 38 | public void getAllReturnsCollectionWithProducts() { 39 | when(catalogStorageMock.getAll()).thenReturn(Collections.singletonList(ProductMother.any())); 40 | 41 | assertEquals(1, catalogService.getAll().size()); 42 | } 43 | 44 | @Test 45 | public void givenProductExistsThenOfIdReturnsProduct() throws Exception { 46 | Product product = ProductMother.any(); 47 | when(catalogStorageMock.containsKey(product.id())).thenReturn(true); 48 | when(catalogStorageMock.get(product.id())).thenReturn(product); 49 | 50 | assertEquals(product, catalogService.ofId(product.id())); 51 | } 52 | 53 | @Test 54 | public void givenProductDoesNotExistsWhenOfIdIsCalledThenProductNotFoundInCatalogExceptionIsThrown() throws Exception { 55 | Product product = ProductMother.any(); 56 | when(catalogStorageMock.containsKey(product.id())).thenReturn(false); 57 | 58 | assertThrows( 59 | ProductNotFoundInCatalogException.class, 60 | () -> catalogService.ofId(product.id()) 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /shopping-cart/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* 6 | -------------------------------------------------------------------------------- /shopping-cart/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | .factorypath 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Vim 24 | *.swp 25 | *.swo 26 | 27 | # patch 28 | *.orig 29 | *.rej 30 | 31 | # Maven 32 | target/ 33 | pom.xml.tag 34 | pom.xml.releaseBackup 35 | pom.xml.versionsBackup 36 | release.properties 37 | -------------------------------------------------------------------------------- /shopping-cart/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shopping-cart/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /shopping-cart/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /shopping-cart/README.md: -------------------------------------------------------------------------------- 1 | # Shopping Cart example app 2 | 3 | Quarkus example application for the DO400 course. 4 | 5 | This project uses Quarkus, the Supersonic Subatomic Java Framework. 6 | 7 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . 8 | 9 | ## Running the application in dev mode 10 | 11 | You can run your application in dev mode that enables live coding using: 12 | ``` 13 | ./mvnw quarkus:dev 14 | ``` 15 | 16 | ## Packaging and running the application 17 | 18 | The application can be packaged using `./mvnw package`. 19 | It produces the `shopping-cart-1.0-SNAPSHOT-runner.jar` file in the `/target` directory. 20 | Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/lib` directory. 21 | 22 | The application is now runnable using `java -jar target/shopping-cart-1.0-SNAPSHOT-runner.jar`. 23 | 24 | ## Creating a native executable 25 | 26 | You can create a native executable using: `./mvnw package -Pnative`. 27 | 28 | Or, if you don't have GraalVM installed, you can run the native executable build in a container using: `./mvnw package -Pnative -Dquarkus.native.container-build=true`. 29 | 30 | You can then execute your native executable with: `./target/shopping-cart-1.0-SNAPSHOT-runner` 31 | 32 | If you want to learn more about building native executables, please consult https://quarkus.io/guides/building-native-image. -------------------------------------------------------------------------------- /shopping-cart/src/main/docker/Dockerfile.fast-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/shopping-cart-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shopping-cart-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/shopping-cart-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | # We make four distinct layers so if there are application changes the library layers can be re-used 49 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 50 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 51 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 52 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 53 | 54 | EXPOSE 8080 55 | USER 1001 56 | 57 | ENTRYPOINT [ "/deployments/run-java.sh" ] 58 | -------------------------------------------------------------------------------- /shopping-cart/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/shopping-cart-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shopping-cart-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/shopping-cart-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /shopping-cart/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/shopping-cart . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/shopping-cart 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/cart/AddToCartCommand.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | public class AddToCartCommand { 4 | 5 | public int id; 6 | public int quantity; 7 | 8 | public AddToCartCommand() { 9 | } 10 | 11 | public AddToCartCommand(int id, int quantity) { 12 | this.id = id; 13 | this.quantity = quantity; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/cart/CartItem.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | public class CartItem { 4 | 5 | private final int id; 6 | private final int price; 7 | private int quantity = 0; 8 | 9 | public CartItem(int id, int price) { 10 | this.id = id; 11 | this.price = price; 12 | } 13 | 14 | public void increaseQuantityBy(int increment) { 15 | this.quantity += increment; 16 | } 17 | 18 | public int getId() { 19 | return this.id; 20 | } 21 | 22 | public int getPrice() { 23 | return this.price; 24 | } 25 | 26 | public int getQuantity() { 27 | return this.quantity; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/cart/CartService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | import com.redhat.shopping.catalog.Catalog; 4 | import com.redhat.shopping.catalog.Product; 5 | import com.redhat.shopping.catalog.ProductNotFoundInCatalogException; 6 | 7 | import javax.enterprise.context.ApplicationScoped; 8 | import javax.inject.Inject; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | @ApplicationScoped 13 | public class CartService { 14 | 15 | private final Map products = new HashMap<>(); 16 | private int totalItems = 0; 17 | 18 | @Inject 19 | Catalog catalog; 20 | 21 | private void recalculate() { 22 | this.totalItems = 0; 23 | 24 | this.products.forEach((id, cartItem) -> { 25 | this.totalItems += cartItem.getQuantity(); 26 | }); 27 | } 28 | 29 | public void addProduct(int productId, int quantity) throws ProductNotFoundInCatalogException { 30 | Product product = this.catalog.ofId(productId); 31 | 32 | if (!this.products.containsKey(productId)) { 33 | this.products.put(product.id(), new CartItem(product.id(), product.price())); 34 | } 35 | 36 | this.products.get(product.id()).increaseQuantityBy(quantity); 37 | 38 | this.recalculate(); 39 | } 40 | 41 | public void clear() { 42 | this.products.clear(); 43 | this.recalculate(); 44 | } 45 | 46 | public CartView cartContent() { 47 | return new CartView(this.products.values(), this.totalItems()); 48 | } 49 | 50 | public void removeProduct(int productId) throws ProductNotFoundInCatalogException, ProductNotInCartException { 51 | Product product = this.catalog.ofId(productId); 52 | 53 | if (!this.products.containsKey(product.id())) { 54 | throw ProductNotInCartException.ofId(product.id()); 55 | } 56 | 57 | this.products.remove(product.id()); 58 | 59 | this.recalculate(); 60 | } 61 | 62 | public int totalItems() { 63 | return this.totalItems; 64 | } 65 | 66 | public int totalProducts() { 67 | return this.products.size(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/cart/CartView.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | 6 | public class CartView { 7 | 8 | public ArrayList products; 9 | public int totalItems; 10 | 11 | public CartView() { 12 | } 13 | 14 | public CartView(Collection products, int totalItems) { 15 | this.products = new ArrayList<>(products); 16 | this.totalItems = totalItems; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/cart/ProductNotInCartException.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.cart; 2 | 3 | public class ProductNotInCartException extends Exception { 4 | 5 | public ProductNotInCartException(String errorMessage) { 6 | super(errorMessage); 7 | } 8 | 9 | public static ProductNotInCartException ofId(int id) { 10 | return new ProductNotInCartException(String.format("Product with ID: %d not found in cart", id)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/catalog/Catalog.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | public interface Catalog { 4 | 5 | public Product ofId(int id) throws ProductNotFoundInCatalogException; 6 | } 7 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/catalog/CatalogService.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | @ApplicationScoped 8 | public class CatalogService implements Catalog { 9 | 10 | private final Map storage = new HashMap<>(); 11 | 12 | /** 13 | * Initializes a list of 5 products with IDs from 1 to 5 and the price being the result of the ID * 100. 14 | * Simulates persistence with a known set of products. 15 | */ 16 | public CatalogService() { 17 | for (int id = 1; id < 5; id++) { 18 | this.storage.put(id, new Product(id, id * 100)); 19 | } 20 | } 21 | 22 | public Product ofId(int id) throws ProductNotFoundInCatalogException { 23 | if (!this.storage.containsKey(id)) { 24 | throw ProductNotFoundInCatalogException.ofId(id); 25 | } 26 | 27 | return this.storage.get(id); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/catalog/Product.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | public class Product { 4 | 5 | private final int id; 6 | private final int price; 7 | 8 | public Product(int id, int price) { 9 | this.id = id; 10 | this.price = price; 11 | } 12 | 13 | public int id() { 14 | return this.id; 15 | } 16 | 17 | public int price() { 18 | return this.price; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /shopping-cart/src/main/java/com/redhat/shopping/catalog/ProductNotFoundInCatalogException.java: -------------------------------------------------------------------------------- 1 | package com.redhat.shopping.catalog; 2 | 3 | public class ProductNotFoundInCatalogException extends Exception { 4 | 5 | public ProductNotFoundInCatalogException(String errorMessage) { 6 | super(errorMessage); 7 | } 8 | 9 | public static ProductNotFoundInCatalogException ofId(int id) { 10 | return new ProductNotFoundInCatalogException(String.format("Unable to find product with ID: %d", id)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /shopping-cart/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuration file 2 | # key = value 3 | -------------------------------------------------------------------------------- /shopping-cart/src/test/java/com/redhat/shopping/integration/blackbox/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shopping-cart/src/test/java/com/redhat/shopping/integration/blackbox/.gitkeep -------------------------------------------------------------------------------- /shopping-cart/src/test/java/com/redhat/shopping/integration/whitebox/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/shopping-cart/src/test/java/com/redhat/shopping/integration/whitebox/.gitkeep -------------------------------------------------------------------------------- /simple-calculator/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* 6 | -------------------------------------------------------------------------------- /simple-calculator/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | .factorypath 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Vim 24 | *.swp 25 | *.swo 26 | 27 | # patch 28 | *.orig 29 | *.rej 30 | 31 | # Maven 32 | target/ 33 | pom.xml.tag 34 | pom.xml.releaseBackup 35 | pom.xml.versionsBackup 36 | release.properties 37 | -------------------------------------------------------------------------------- /simple-calculator/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/simple-calculator/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /simple-calculator/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /simple-calculator/README.md: -------------------------------------------------------------------------------- 1 | # Simple Calculator 2 | 3 | This project uses Quarkus, the Supersonic Subatomic Java Framework. 4 | 5 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . 6 | 7 | ## Running the application in dev mode 8 | 9 | You can run your application in dev mode that enables live coding using: 10 | ``` 11 | ./mvnw quarkus:dev 12 | ``` 13 | 14 | ## Packaging and running the application 15 | 16 | The application can be packaged using `./mvnw package`. 17 | It produces the `simple-calculator-1.0-SNAPSHOT-runner.jar` file in the `/target` directory. 18 | Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/lib` directory. 19 | 20 | The application is now runnable using `java -jar target/simple-calculator-1.0-SNAPSHOT-runner.jar`. 21 | 22 | ## Creating a native executable 23 | 24 | You can create a native executable using: `./mvnw package -Pnative`. 25 | 26 | Or, if you don't have GraalVM installed, you can run the native executable build in a container using: `./mvnw package -Pnative -Dquarkus.native.container-build=true`. 27 | 28 | You can then execute your native executable with: `./target/simple-calculator-1.0-SNAPSHOT-runner` 29 | 30 | If you want to learn more about building native executables, please consult https://quarkus.io/guides/building-native-image. -------------------------------------------------------------------------------- /simple-calculator/kubefiles/email-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: email 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: email 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: email 14 | spec: 15 | containers: 16 | - name: email 17 | image: quay.io/redhattraining/maildev-mirror:latest 18 | imagePullPolicy: Always 19 | command: ["bin/maildev"] 20 | args: ["--web", "8080", "--smtp", "1025", "--verbose"] 21 | ports: 22 | - containerPort: 1025 23 | protocol: TCP 24 | - containerPort: 8080 25 | protocol: TCP 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | labels: 31 | app: email 32 | name: email 33 | spec: 34 | ports: 35 | - port: 8080 36 | name: web 37 | protocol: TCP 38 | targetPort: 8080 39 | - port: 25 40 | name: smtp 41 | protocol: TCP 42 | targetPort: 1025 43 | selector: 44 | app: email 45 | --- 46 | kind: Route 47 | apiVersion: route.openshift.io/v1 48 | metadata: 49 | name: email 50 | labels: 51 | app: email 52 | spec: 53 | to: 54 | kind: Service 55 | name: email 56 | port: 57 | targetPort: 8080 58 | -------------------------------------------------------------------------------- /simple-calculator/src/main/docker/Dockerfile.fast-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/simple-calculator-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/simple-calculator-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/simple-calculator-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | # We make four distinct layers so if there are application changes the library layers can be re-used 49 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 50 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 51 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 52 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 53 | 54 | EXPOSE 8080 55 | USER 1001 56 | 57 | ENTRYPOINT [ "/deployments/run-java.sh" ] 58 | -------------------------------------------------------------------------------- /simple-calculator/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/simple-calculator-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/simple-calculator-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/simple-calculator-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /simple-calculator/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/simple-calculator . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/simple-calculator 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /simple-calculator/src/main/java/com/redhat/simple/calculator/BasicCalculator.java: -------------------------------------------------------------------------------- 1 | package com.redhat.simple.calculator; 2 | 3 | import java.util.*; 4 | 5 | public class BasicCalculator { 6 | public int divide(int dividend, int divisor) { 7 | if (divisor == 0) 8 | return Integer.MAX_VALUE; 9 | else 10 | return dividend / divisor; 11 | } 12 | 13 | public int subs(int minuend, int subtrahend) { 14 | return minuend-subtrahend; 15 | } 16 | 17 | public int sum(int addendA, int addendB) { 18 | return addendA+addendB; 19 | } 20 | 21 | public int multiply(int multiplicand, int multiplier) { 22 | return multiplicand*multiplier; 23 | } 24 | 25 | public int Random() { 26 | Random r = new Random(); 27 | 28 | return r.nextInt(); 29 | } 30 | } -------------------------------------------------------------------------------- /simple-calculator/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuration file 2 | # key = value 3 | -------------------------------------------------------------------------------- /simple-calculator/src/test/java/com/redhat/simple/calculator/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatTraining/DO400-apps/cc78ffcccc68014a1c7d765e07d634fb462d392c/simple-calculator/src/test/java/com/redhat/simple/calculator/.gitkeep -------------------------------------------------------------------------------- /simple-calculator/src/test/java/com/redhat/simple/calculator/BasicCalculatorTest.java: -------------------------------------------------------------------------------- 1 | package com.redhat.simple.calculator; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | 8 | class BasicCalculatorTest { 9 | BasicCalculator calculator; 10 | 11 | @BeforeEach 12 | void setUp() { 13 | calculator = new BasicCalculator(); 14 | } 15 | 16 | @Test 17 | void testSumIntegers() { 18 | assertEquals(2, calculator.sum(1, 1)); 19 | } 20 | 21 | @Test 22 | void testSubstractIntegers() { 23 | assertEquals(5, calculator.subs(10, 5)); 24 | } 25 | 26 | @Test 27 | void testMultiplyIntegers() { 28 | assertEquals(25, calculator.multiply(5, 5)); 29 | } 30 | 31 | @Test 32 | void testDivideIntegers() { 33 | assertEquals(1, calculator.divide(4, 3)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /simple-webapp/backend/greet.js: -------------------------------------------------------------------------------- 1 | module.exports = function greet(name) { 2 | return `Hello ${name || "guest"}`; 3 | } 4 | -------------------------------------------------------------------------------- /simple-webapp/backend/server.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const url = require("url"); 3 | const greet = require("./greet"); 4 | 5 | const server = http.createServer((req, res) => { 6 | const { name } = url.parse(req.url, true).query; 7 | res.statusCode = 200; 8 | res.setHeader("Content-Type", "text/plain"); 9 | res.setHeader("Access-Control-Allow-Origin", "*"); 10 | res.end(greet(name)); 11 | }); 12 | 13 | const port = 3000; 14 | server.listen(port, () => { 15 | console.log(`Server listening on ${port}`); 16 | }); 17 | -------------------------------------------------------------------------------- /simple-webapp/backend/test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert").strict; 2 | const greet = require("./greet"); 3 | 4 | assert.strictEqual(greet(), "Hello guest"); 5 | assert.strictEqual(greet("Guy"), "Hello Guy"); 6 | -------------------------------------------------------------------------------- /simple-webapp/backend/test_api.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Always set the current working directory as the project's root 4 | PROJECT_ROOT=$(cd $(dirname $0)/.. && pwd) 5 | 6 | # HTTP method 7 | METHOD=$1 8 | 9 | # Run server 10 | node $PROJECT_ROOT/backend/server & 11 | PID=$! 12 | 13 | # Try to make a successful request 14 | for i in {1..3} 15 | do 16 | curl -Is -X $METHOD http://localhost:3000 | grep 200 17 | EXITCODE=$? 18 | 19 | if [ $EXITCODE -eq 0 ] 20 | then 21 | break 22 | fi 23 | 24 | sleep 1 25 | done 26 | 27 | # Stop server 28 | kill -15 $PID 29 | 30 | exit $EXITCODE 31 | -------------------------------------------------------------------------------- /simple-webapp/frontend/greet.js: -------------------------------------------------------------------------------- 1 | function greet(domInput, domElement) { 2 | const api = greet.api || getGreeting; 3 | return api(domInput.value).then(text => { 4 | domElement.innerHTML = text; 5 | }); 6 | } 7 | 8 | function getGreeting(name) { 9 | const url = "http://localhost:3000?name=" + name 10 | return fetch(url) 11 | .then(response => response.text()); 12 | } 13 | 14 | if (typeof module !== "undefined") { 15 | module.exports = greet; 16 | } 17 | -------------------------------------------------------------------------------- /simple-webapp/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /simple-webapp/frontend/main.js: -------------------------------------------------------------------------------- 1 | 2 | document.addEventListener("DOMContentLoaded", () => { 3 | const input = document.getElementById("username"); 4 | const greeting = document.getElementById("greeting"); 5 | input.addEventListener("keyup", () => greet(input, greeting)); 6 | }); 7 | -------------------------------------------------------------------------------- /simple-webapp/frontend/test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert").strict; 2 | const greet = require("./greet"); 3 | 4 | greet.api = async function apiMock(name) { 5 | return `Hello ${name}`; 6 | } 7 | 8 | const input = { value: "Pablo" } 9 | const h1 = { innerHTML: "" } 10 | 11 | greet(input, h1).then(() => { 12 | assert.strictEqual(h1.innerHTML, "Hello Pablo"); 13 | }); 14 | -------------------------------------------------------------------------------- /story-count/frankenstein.txt: -------------------------------------------------------------------------------- 1 | You will rejoice to hear that no disaster has accompanied the 2 | commencement of an enterprise which you have regarded with such evil 3 | forebodings. I arrived here yesterday, and my first task is to assure 4 | my dear sister of my welfare and increasing confidence in the success 5 | of my undertaking. 6 | 7 | I am already far north of London, and as I walk in the streets of 8 | Petersburgh, I feel a cold northern breeze play upon my cheeks, which 9 | braces my nerves and fills me with delight. Do you understand this 10 | feeling? This breeze, which has travelled from the regions towards 11 | which I am advancing, gives me a foretaste of those icy climes. 12 | Inspirited by this wind of promise, my daydreams become more fervent 13 | and vivid. I try in vain to be persuaded that the pole is the seat of 14 | frost and desolation; it ever presents itself to my imagination as the 15 | region of beauty and delight. There, Margaret, the sun is for ever 16 | visible, its broad disk just skirting the horizon and diffusing a 17 | perpetual splendour. There—for with your leave, my sister, I will put 18 | some trust in preceding navigators—there snow and frost are banished; 19 | and, sailing over a calm sea, we may be wafted to a land surpassing in 20 | wonders and in beauty every region hitherto discovered on the habitable 21 | globe. Its productions and features may be without example, as the 22 | phenomena of the heavenly bodies undoubtedly are in those undiscovered 23 | solitudes. What may not be expected in a country of eternal light? I 24 | may there discover the wondrous power which attracts the needle and may 25 | regulate a thousand celestial observations that require only this 26 | voyage to render their seeming eccentricities consistent for ever. I 27 | shall satiate my ardent curiosity with the sight of a part of the world 28 | never before visited, and may tread a land never before imprinted by 29 | the foot of man. These are my enticements, and they are sufficient to 30 | conquer all fear of danger or death and to induce me to commence this 31 | laborious voyage with the joy a child feels when he embarks in a little 32 | boat, with his holiday mates, on an expedition of discovery up his 33 | native river. But supposing all these conjectures to be false, you 34 | cannot contest the inestimable benefit which I shall confer on all 35 | mankind, to the last generation, by discovering a passage near the pole 36 | to those countries, to reach which at present so many months are 37 | requisite; or by ascertaining the secret of the magnet, which, if at 38 | all possible, can only be effected by an undertaking such as mine. 39 | -------------------------------------------------------------------------------- /story-count/test-wc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXPECTED=$2 3 | ACTUAL=$(wc -w $1 | xargs | cut -f1 -d' ') 4 | 5 | if [[ $EXPECTED == $ACTUAL ]] 6 | then 7 | echo "SUCCESS: correct word count" 8 | else 9 | echo "FAIL: got $ACTUAL but expected $EXPECTED" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /tools/check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import time 5 | import logging 6 | import urllib.request 7 | 8 | 9 | logging.basicConfig( 10 | format='%(asctime)s %(levelname)-8s %(message)s', 11 | level=logging.INFO, 12 | datefmt='%Y-%m-%d %H:%M:%S') 13 | 14 | 15 | def request(url): 16 | try: 17 | response = urllib.request.urlopen(url) 18 | logging.info(response.read().decode()) 19 | except urllib.error.HTTPError as error: 20 | logging.error(error) 21 | 22 | 23 | if len(sys.argv) < 2: 24 | print("Please specify URL") 25 | print(" EXAMPLE: check.py http://your/url") 26 | exit(1) 27 | 28 | 29 | URL = sys.argv[1] 30 | print("Checking {}\n".format(URL)) 31 | 32 | while True: 33 | request(URL) 34 | time.sleep(1) 35 | -------------------------------------------------------------------------------- /tools/email-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: email 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: email 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: email 14 | spec: 15 | containers: 16 | - name: email 17 | image: quay.io/redhattraining/maildev-mirror:latest 18 | imagePullPolicy: Always 19 | command: ["bin/maildev"] 20 | args: ["--web", "8080", "--smtp", "1025", "--verbose"] 21 | ports: 22 | - containerPort: 1025 23 | protocol: TCP 24 | - containerPort: 8080 25 | protocol: TCP 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | labels: 31 | app: email 32 | name: email 33 | spec: 34 | ports: 35 | - port: 8080 36 | name: web 37 | protocol: TCP 38 | targetPort: 8080 39 | - port: 25 40 | name: smtp 41 | protocol: TCP 42 | targetPort: 1025 43 | selector: 44 | app: email 45 | --- 46 | kind: Route 47 | apiVersion: route.openshift.io/v1 48 | metadata: 49 | name: email 50 | labels: 51 | app: email 52 | spec: 53 | to: 54 | kind: Service 55 | name: email 56 | port: 57 | targetPort: 8080 58 | 59 | --------------------------------------------------------------------------------