diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..f53f32e7a --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,217 @@ +name: CI + +on: + push: + workflow_dispatch: + +jobs: + build: + name: Build App + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Cache Gradle packages + uses: actions/cache@v3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: ${{ runner.os }}-gradle + + - name: Build with Gradle + run: | + chmod +x gradlew + ./gradlew build + ls -lah $GITHUB_WORKSPACE/build/libs/ + + - name: Archive artifact java app + if: success() + uses: actions/upload-artifact@v3 + with: + name: java-app + path: build/libs/testing-web-0.0.1-SNAPSHOT.jar + + sonarcloud: + name: Analyze SonarCloud + runs-on: ubuntu-latest + needs: build + if: success() + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Cache SonarCloud packages + uses: actions/cache@v3 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Analyze SonarCloud + run: | + chmod +x gradlew + ./gradlew jacocoTestReport sonar -Dsonar.login=${{ secrets.TOKEN_SONARCLOUD }} --info --stacktrace + + deploy: + name: Deployment Docker and Cloud Run + runs-on: ubuntu-latest + needs: sonarcloud + if: success() + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Docker login + uses: docker/login-action@v2.2.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Download artifact java app + uses: actions/download-artifact@v3 + with: + name: java-app + path: . + + - name: Docker build + run: | + chmod 755 testing-web-0.0.1-SNAPSHOT.jar + ls -lah + docker build --tag lobozoldick/microservicio-java:latest . + docker images + + - name: Docker push + run: | + docker push lobozoldick/microservicio-java + + - name: Google Auth + id: auth + uses: google-github-actions/auth@v2 + with: + credentials_json: '${{ secrets.GCP_CREDENTIALS }}' + + - name: Deploy to Cloud Run + id: deploy + uses: google-github-actions/deploy-cloudrun@v2 + with: + service: microservicio-java + region: us-central1 + source: ./ + + - name: Save token and url to file + run: | + echo ${{ steps.deploy.outputs.url }} > url_cloud.txt + gcloud auth print-identity-token > gcp_token.txt + + - name: Archive artifact url + if: success() + uses: actions/upload-artifact@v3 + with: + name: url-cloud + path: url_cloud.txt + if-no-files-found: error + + - name: Archive artifact token + if: success() + uses: actions/upload-artifact@v3 + with: + name: gcp-token + path: gcp_token.txt + if-no-files-found: error + + postman: + name: Execute Postman + runs-on: ubuntu-latest + needs: deploy + if: success() + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Download artifact url + uses: actions/download-artifact@v3 + with: + name: url-cloud + path: . + + - name: Download artifact token + uses: actions/download-artifact@v3 + with: + name: gcp-token + path: . + + - name: Download Node.js And Newman + run: | + sudo apt-get install -y nodejs + npm install -g newman + npm install -g newman-reporter-htmlextra + + - name: Run Postman tests + run: | + export GCP_TOKEN=$(cat gcp_token.txt) + export URL=$(cat url_cloud.txt) + newman run Postman/scripts/pruebas_Aceptacion.postman_collection.json --env-var GCP_TOKEN=$GCP_TOKEN --env-var URL=$URL -r cli,htmlextra --reporter-htmlextra-export resultadoPostman.html + + - name: Archive result HTML Postman + if: success() + uses: actions/upload-artifact@v3 + with: + name: resultado-postman-html + path: resultadoPostman.html + if-no-files-found: error + + jmeter: + name: Execute Jmeter + runs-on: ubuntu-latest + needs: deploy + if: success() + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Download Apache JMeter + run: | + curl -LJO https://downloads.apache.org/jmeter/binaries/apache-jmeter-5.6.2.tgz + tar -xvzf apache-jmeter-5.6.2.tgz + ls -lash + + - name: Download artifact url + uses: actions/download-artifact@v3 + with: + name: url-cloud + path: apache-jmeter-5.6.2/ + + - name: Download artifact token + uses: actions/download-artifact@v3 + with: + name: gcp-token + path: apache-jmeter-5.6.2/ + + - name: Run JMeter tests + if: success() + run: | + ls -lah + cd apache-jmeter-5.6.2 + ls -lah + chmod 755 bin/jmeter.sh + mkdir reportHtml + ./bin/jmeter.sh -n -t $GITHUB_WORKSPACE/Jmeter/scripts/LoadTest.jmx -e -o ./reportHtml -l testresult.jtl + + - name: Archive artifact jmeter-html-reports + if: success() + uses: actions/upload-artifact@v3 + with: + name: jmeter-html-reports + path: apache-jmeter-5.6.2/reportHtml + if-no-files-found: error + + + + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..01fcad4e4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM openjdk:11-jre + +EXPOSE 8080 + +ADD testing-web-0.0.1-SNAPSHOT.jar /app/testing-web-0.0.1-SNAPSHOT.jar + +WORKDIR /app + +CMD java -jar testing-web-0.0.1-SNAPSHOT.jar diff --git a/Jmeter/scripts/LoadTest.jmx b/Jmeter/scripts/LoadTest.jmx new file mode 100644 index 000000000..afafd6d1b --- /dev/null +++ b/Jmeter/scripts/LoadTest.jmx @@ -0,0 +1,175 @@ + + + + + false + false + false + + + + + + + continue + + 1 + false + + 1 + 1 + false + false + + + true + + + + + + Authorization + Bearer ${__FileToString(./gcp_token.txt,,TOKEN)} + + + + + + false + + + + false + = + true + + + + ${HOST} + ${PROTOCOLO} + / + GET + true + false + true + false + false + false + false + 6 + false + 0 + + + + beanshell + + + true + ${__FileToString(./url_cloud.txt,,URL)}; + +String[] datosURL = vars.get("URL").replaceAll("\n", "").split("://"); + +log.info("PROTOCOLO Variable: " + datosURL[0]); +log.info("HOST Variable: " + datosURL[1]); + +vars.put("PROTOCOLO", datosURL[0]); +vars.put("HOST", datosURL[1]); + +log.info("PROTOCOLO Variable: " + vars.get("PROTOCOLO")); +log.info("HOST Variable: " + vars.get("HOST")); + + +; +//log.info("BEARER_TOKEN Variable: " + vars.get("TOKEN")); + +//String token = vars.get("TOKEN").replaceAll("\n", ""); + +//vars.put("BEARER_TOKEN", "Bearer " + token); +//log.info("BEARER_TOKEN Variable: " + vars.get("BEARER_TOKEN")); + + + + + Lab Final DevOps-Fundamentos-v6 + + + Assertion.response_data + false + 8 + + + + + false + + + + ${HOST} + ${PROTOCOLO} + /greeting + GET + true + false + true + false + false + false + false + 6 + false + 0 + + + + + Lab Final DevOps-Fundamentos-v6 Greeting + + + Assertion.response_data + false + 8 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + + diff --git a/Postman/scripts/pruebas_Aceptacion.postman_collection.json b/Postman/scripts/pruebas_Aceptacion.postman_collection.json new file mode 100644 index 000000000..e6d474ddf --- /dev/null +++ b/Postman/scripts/pruebas_Aceptacion.postman_collection.json @@ -0,0 +1,103 @@ +{ + "info": { + "_postman_id": "6b85cbae-208e-4cd5-b20c-6cff0dcf7709", + "name": "Pruebas de Aceptación", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "4933448" + }, + "item": [ + { + "name": "homeServices", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Prueba de contenido del Body\", function () {", + " pm.response.to.have.body(\"Lab Final DevOps-Fundamentos-v6\");", + "});", + "", + "pm.test(\"Response time is less than 500ms\", function () {", + " pm.expect(pm.response.responseTime).to.be.below(500);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{GCP_TOKEN}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}", + "host": [ + "{{URL}}" + ] + } + }, + "response": [] + }, + { + "name": "greetingServices", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Prueba de contenido del Body\", function () {", + " pm.response.to.have.body(\"Lab Final DevOps-Fundamentos-v6 Greeting\");", + "});", + "", + "pm.test(\"Response time is less than 500ms\", function () {", + " pm.expect(pm.response.responseTime).to.be.below(500);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{GCP_TOKEN}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/greeting", + "host": [ + "{{URL}}" + ], + "path": [ + "greeting" + ] + } + }, + "response": [] + } + ] +} diff --git a/bash/scripts/consultingLocalhost.sh b/bash/scripts/consultingLocalhost.sh new file mode 100644 index 000000000..6f0f6911f --- /dev/null +++ b/bash/scripts/consultingLocalhost.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Puerto al que se realizará la solicitud +PORT=8080 +# Número máximo de intentos +MAX_RETRIES=12 +# Tiempo de espera entre intentos (en segundos) +WAIT_TIME=5 + +# Función para realizar una solicitud HTTP +function make_request() { + curl -I http://localhost:$PORT/ +} + +# Esperar hasta que la aplicación esté lista +for ((i=1; i<=$MAX_RETRIES; i++)); do + if make_request; then + echo "La aplicación está lista." + exit 0 + fi + echo "Intento $i: La aplicación no está lista, esperando $WAIT_TIME segundos..." + sleep $WAIT_TIME +done + +echo "Número máximo de intentos alcanzado. La aplicación no se inició correctamente." +exit 1 diff --git a/bash/scripts/wait_application.sh b/bash/scripts/wait_application.sh new file mode 100644 index 000000000..32c26aa78 --- /dev/null +++ b/bash/scripts/wait_application.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Script para esperar hasta que la aplicación esté lista + +# Ruta al archivo JAR de la aplicación +JAR_FILE="testing-web-0.0.1-SNAPSHOT.jar" +# Puerto al que se realizará la solicitud +PORT=8080 +# Número máximo de intentos +MAX_RETRIES=12 +# Tiempo de espera entre intentos (en segundos) +WAIT_TIME=5 + +# Función para realizar una solicitud HTTP +function make_request() { + curl -I http://localhost:$PORT/ +} + +# Iniciar la aplicación en segundo plano +chmod +x $JAR_FILE +java -jar $JAR_FILE > /dev/null 2>&1 & + +# Esperar hasta que la aplicación esté lista +for ((i=1; i<=$MAX_RETRIES; i++)); do + if make_request; then + echo "La aplicación está lista." + exit 0 + fi + echo "Intento $i: La aplicación no está lista, esperando $WAIT_TIME segundos..." + sleep $WAIT_TIME +done + +echo "Número máximo de intentos alcanzado. La aplicación no se inició correctamente." +exit 1 diff --git a/build.gradle b/build.gradle index ee2bd23f9..92457fc3e 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,8 @@ plugins { id 'org.springframework.boot' version '2.6.3' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' + id "jacoco" + id 'org.sonarqube' version '4.2.1.3168' } group = 'com.example' @@ -17,6 +19,30 @@ dependencies { testImplementation('org.springframework.boot:spring-boot-starter-test') } +sonar { + properties { + property 'sonar.projectKey', 'lobozoldick_microservicio-java' + property 'sonar.organization', 'lobozoldick' + property 'sonar.host.url', 'https://sonarcloud.io/' + property 'sonar.projectName', 'microservicio-java' + property 'sonar.java.coveragePlugin', 'jacoco' + } +} + +jacoco { + toolVersion = "0.8.9" +} + +jacocoTestReport { + dependsOn test + reports { + xml.enabled true + } +} + test { + jacoco { + enabled = true + } useJUnitPlatform() } diff --git a/deployment.yml b/deployment.yml new file mode 100644 index 000000000..8e0b71de4 --- /dev/null +++ b/deployment.yml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: microservicio-java-deployment + labels: + app: microservicio-java +spec: + replicas: 1 + selector: + matchLabels: + app: microservicio-java + template: + metadata: + labels: + app: microservicio-java + spec: + containers: + - name: microservicio-java + image: lobozoldick/microservicio-java:latest + ports: + - containerPort: 8080 diff --git a/src/main/java/com/example/testingweb/GreetingService.java b/src/main/java/com/example/testingweb/GreetingService.java index 6661c82bc..b4b1f28bf 100644 --- a/src/main/java/com/example/testingweb/GreetingService.java +++ b/src/main/java/com/example/testingweb/GreetingService.java @@ -5,6 +5,6 @@ @Service public class GreetingService { public String greet() { - return "Hello, World"; + return "Lab Final DevOps-Fundamentos-v6 Greeting"; } } diff --git a/src/main/java/com/example/testingweb/HomeController.java b/src/main/java/com/example/testingweb/HomeController.java index 6472ecdf7..1a8392aab 100644 --- a/src/main/java/com/example/testingweb/HomeController.java +++ b/src/main/java/com/example/testingweb/HomeController.java @@ -9,7 +9,7 @@ public class HomeController { @RequestMapping("/") public @ResponseBody String greeting() { - return "Hello, World"; + return "Lab Final DevOps-Fundamentos-v6"; } } diff --git a/src/test/java/com/example/testingweb/HttpRequestTest.java b/src/test/java/com/example/testingweb/HttpRequestTest.java index 79e679e60..c6c17d6f4 100644 --- a/src/test/java/com/example/testingweb/HttpRequestTest.java +++ b/src/test/java/com/example/testingweb/HttpRequestTest.java @@ -22,6 +22,6 @@ public class HttpRequestTest { @Test public void greetingShouldReturnDefaultMessage() throws Exception { assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/", - String.class)).contains("Hello, World"); + String.class)).contains("Lab Final DevOps-Fundamentos-v6"); } } diff --git a/src/test/java/com/example/testingweb/SmokeTest.java b/src/test/java/com/example/testingweb/SmokeTest.java index 5b69622bb..46616323c 100644 --- a/src/test/java/com/example/testingweb/SmokeTest.java +++ b/src/test/java/com/example/testingweb/SmokeTest.java @@ -17,4 +17,19 @@ public class SmokeTest { public void contextLoads() throws Exception { assertThat(controller).isNotNull(); } + + @Test + public void contextLoads1() throws Exception { + assertThat(controller).isNotNull(); + } + + @Test + public void contextLoads2() throws Exception { + assertThat(controller).isNotNull(); + } + + @Test + public void contextLoads3() throws Exception { + assertThat(controller).isNotNull(); + } } diff --git a/src/test/java/com/example/testingweb/TestingWebApplicationTest.java b/src/test/java/com/example/testingweb/TestingWebApplicationTest.java index 135f48986..21162ea72 100644 --- a/src/test/java/com/example/testingweb/TestingWebApplicationTest.java +++ b/src/test/java/com/example/testingweb/TestingWebApplicationTest.java @@ -23,6 +23,6 @@ public class TestingWebApplicationTest { @Test public void shouldReturnDefaultMessage() throws Exception { this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, World"))); + .andExpect(content().string(containsString("Lab Final DevOps-Fundamentos-v6"))); } } diff --git a/src/test/java/com/example/testingweb/WebLayerTest.java b/src/test/java/com/example/testingweb/WebLayerTest.java index a0e87a8db..283ad5d00 100644 --- a/src/test/java/com/example/testingweb/WebLayerTest.java +++ b/src/test/java/com/example/testingweb/WebLayerTest.java @@ -22,7 +22,7 @@ public class WebLayerTest { @Test public void shouldReturnDefaultMessage() throws Exception { this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, World"))); + .andExpect(content().string(containsString("Lab Final DevOps-Fundamentos-v6"))); } } //end::test[] diff --git a/src/test/java/com/example/testingweb/WebMockTest.java b/src/test/java/com/example/testingweb/WebMockTest.java index 245b6cccb..5fdaf0a3a 100644 --- a/src/test/java/com/example/testingweb/WebMockTest.java +++ b/src/test/java/com/example/testingweb/WebMockTest.java @@ -25,8 +25,8 @@ public class WebMockTest { @Test public void greetingShouldReturnMessageFromService() throws Exception { - when(service.greet()).thenReturn("Hello, Mock"); + when(service.greet()).thenReturn("Lab Final DevOps-Fundamentos-v6 Greeting"); this.mockMvc.perform(get("/greeting")).andDo(print()).andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, Mock"))); + .andExpect(content().string(containsString("Lab Final DevOps-Fundamentos-v6 Greeting"))); } }