diff --git a/docs/assets/img/github-action-dark.avif b/docs/assets/img/github-action-dark.avif new file mode 100644 index 000000000..f81dbb845 Binary files /dev/null and b/docs/assets/img/github-action-dark.avif differ diff --git a/docs/assets/img/github-action-dark.webp b/docs/assets/img/github-action-dark.webp new file mode 100644 index 000000000..773d3b3a1 Binary files /dev/null and b/docs/assets/img/github-action-dark.webp differ diff --git a/docs/assets/img/github-action-light.avif b/docs/assets/img/github-action-light.avif new file mode 100644 index 000000000..b28ca7d59 Binary files /dev/null and b/docs/assets/img/github-action-light.avif differ diff --git a/docs/assets/img/github-action-light.webp b/docs/assets/img/github-action-light.webp new file mode 100644 index 000000000..001139a8f Binary files /dev/null and b/docs/assets/img/github-action-light.webp differ diff --git a/docs/assets/img/github-new-repository-dark.avif b/docs/assets/img/github-new-repository-dark.avif new file mode 100644 index 000000000..58a2b8dbc Binary files /dev/null and b/docs/assets/img/github-new-repository-dark.avif differ diff --git a/docs/assets/img/github-new-repository-dark.webp b/docs/assets/img/github-new-repository-dark.webp new file mode 100644 index 000000000..77bddecbf Binary files /dev/null and b/docs/assets/img/github-new-repository-dark.webp differ diff --git a/docs/assets/img/github-new-repository-light.avif b/docs/assets/img/github-new-repository-light.avif new file mode 100644 index 000000000..0549d0487 Binary files /dev/null and b/docs/assets/img/github-new-repository-light.avif differ diff --git a/docs/assets/img/github-new-repository-light.webp b/docs/assets/img/github-new-repository-light.webp new file mode 100644 index 000000000..7bf41a57e Binary files /dev/null and b/docs/assets/img/github-new-repository-light.webp differ diff --git a/docs/assets/img/gitlab-new-repository-dark.avif b/docs/assets/img/gitlab-new-repository-dark.avif new file mode 100644 index 000000000..b800526c4 Binary files /dev/null and b/docs/assets/img/gitlab-new-repository-dark.avif differ diff --git a/docs/assets/img/gitlab-new-repository-dark.png b/docs/assets/img/gitlab-new-repository-dark.png new file mode 100644 index 000000000..b6bc843f0 Binary files /dev/null and b/docs/assets/img/gitlab-new-repository-dark.png differ diff --git a/docs/assets/img/gitlab-new-repository-dark.webp b/docs/assets/img/gitlab-new-repository-dark.webp new file mode 100644 index 000000000..97f744e56 Binary files /dev/null and b/docs/assets/img/gitlab-new-repository-dark.webp differ diff --git a/docs/assets/img/gitlab-new-repository-light.avif b/docs/assets/img/gitlab-new-repository-light.avif new file mode 100644 index 000000000..973f4c5e8 Binary files /dev/null and b/docs/assets/img/gitlab-new-repository-light.avif differ diff --git a/docs/assets/img/gitlab-new-repository-light.png b/docs/assets/img/gitlab-new-repository-light.png new file mode 100644 index 000000000..f9883e02b Binary files /dev/null and b/docs/assets/img/gitlab-new-repository-light.png differ diff --git a/docs/assets/img/gitlab-new-repository-light.webp b/docs/assets/img/gitlab-new-repository-light.webp new file mode 100644 index 000000000..7bc9c31d4 Binary files /dev/null and b/docs/assets/img/gitlab-new-repository-light.webp differ diff --git a/docs/assets/img/gitlab-pipeline-dark.avif b/docs/assets/img/gitlab-pipeline-dark.avif new file mode 100644 index 000000000..173da843e Binary files /dev/null and b/docs/assets/img/gitlab-pipeline-dark.avif differ diff --git a/docs/assets/img/gitlab-pipeline-dark.png b/docs/assets/img/gitlab-pipeline-dark.png new file mode 100644 index 000000000..bcabbdb0c Binary files /dev/null and b/docs/assets/img/gitlab-pipeline-dark.png differ diff --git a/docs/assets/img/gitlab-pipeline-dark.webp b/docs/assets/img/gitlab-pipeline-dark.webp new file mode 100644 index 000000000..da9fefb3b Binary files /dev/null and b/docs/assets/img/gitlab-pipeline-dark.webp differ diff --git a/docs/assets/img/gitlab-pipeline-light.avif b/docs/assets/img/gitlab-pipeline-light.avif new file mode 100644 index 000000000..414f894a9 Binary files /dev/null and b/docs/assets/img/gitlab-pipeline-light.avif differ diff --git a/docs/assets/img/gitlab-pipeline-light.png b/docs/assets/img/gitlab-pipeline-light.png new file mode 100644 index 000000000..651246040 Binary files /dev/null and b/docs/assets/img/gitlab-pipeline-light.png differ diff --git a/docs/assets/img/gitlab-pipeline-light.webp b/docs/assets/img/gitlab-pipeline-light.webp new file mode 100644 index 000000000..519e8b6ab Binary files /dev/null and b/docs/assets/img/gitlab-pipeline-light.webp differ diff --git a/docs/tutorial/ci-cd-integration.md b/docs/tutorial/ci-cd-integration.md index 6bd692d21..4261a9117 100644 --- a/docs/tutorial/ci-cd-integration.md +++ b/docs/tutorial/ci-cd-integration.md @@ -1,9 +1,8 @@ # CI/CD Integration -Up until now, we have run our test files locally. Now, we want to integrate -them in a CI/CD pipeline (like [GitHub Actions] or [GitLab CI/CD pipelines]). As -Hurl is very fast, we're going to run our tests on each commit of our project, -drastically improving the project quality. +Up until now, we have run our test files locally. Now, we want to integrate them in a CI/CD pipeline +(like [GitHub Actions] or [GitLab CI/CD pipelines]). As Hurl is very fast, we're going to run our tests on each commit +of our project, drastically improving the project quality. A typical web project pipeline is: @@ -11,23 +10,74 @@ A typical web project pipeline is: - publish the application image to a Docker registry, - pull the application image and run integration tests. -In this workflow, we're testing the same image that will be used and deployed in -production. +In this workflow, we're testing the same image that will be used and deployed in production. > For the tutorial, we are skipping build and publication phases and > only run integration tests on a prebuilt Docker image. To check a complete > project with build, Docker upload/publish and integration tests, go to -In a first step, we're going to write a bash script that will pull our Docker -image, launch it and run Hurl tests against it. Once we have checked that this -script runs locally, we'll see how to run it automatically in a CI/CD pipeline. +In a first step, we're going to write a shell script that will pull our Docker image, launch it and run Hurl tests +against it. Once we have checked that this script runs locally, we'll see how to run it automatically in a CI/CD +pipeline. + + +## Templating Tests + +Before writing our test script, we're going to template our Hurl files so we can run them more easily in various +configuration. One way to do this is to use [variables]. We've already seen variables when [chaining requests], +we're going to see how we can use them to inject data. + +In the file `basic.hurl`, we first test the home page: + +```hurl +# Checking our home page: +GET http://localhost:3000 + +# ... +``` + +We've hardcoded our server's URL but what if we need to run the same test on another URL (against production +URL with HTTPS for example)? We can use a variable like this: + +```hurl +# Checking our home page: +GET {{host}} + +# ... +``` + +And run our file with [`--variable`] option: + +```shell +$ hurl --variable host=http://localhost:3000 --test basic.hurl +``` + +This way, our host is not hardcoded any more and we can run our tests in various configurations. + +1. Replace `http://localhost:3000` by `{{host}}` in `basic.hurl`, `login.hurl` and `signup.hurl` and test that everything is ok + +```shell +$ hurl --variable host=http://localhost:3000 --test *.hurl +Running Hurl tests +integration/basic.hurl: Running [1/2] +integration/basic.hurl: Success (4 request(s) in 18 ms) +integration/login.hurl: Running [2/2] +integration/login.hurl: Success (6 request(s) in 18 ms) +-------------------------------------------------------------------------------- +Executed files: 2 +Succeeded files: 2 (100.0%) +Failed files: 0 (0.0%) +Duration: 48 ms +``` + +Now, we're ready to write our integration script. ## Integration Script 1. First, create a directory name `movies-project`, add [`integration/basic.hurl`] and [`integration/create-quiz.hurl`] from the previous tutorial to the directory. -
$ mkdir movies-project
+
$ mkdir movies-project
 $ cd movies-project
 $ mkdir integration
 $ vi integration/basic.hurl
@@ -36,15 +86,19 @@ $ vi integration/basic.hurl
 
 $ vi integration/login.hurl
 
-# Import login.hurl here!
+# Import login.hurl here! + +$ vi integration/signup.hurl + +# Import signup.hurl here!
Next, we are going to write the first version of our integration script that will -just pull the Quiz image and run it: +just pull the Quiz image and run it. This script will our server URl as argument 2. Create a script named `bin/integration.sh` with the following content: ```bash -#!/bin/bash +#!/bin/sh set -eu echo "Starting container" @@ -55,7 +109,7 @@ docker run --name movies --rm --detach --publish 3000:3000 ghcr.io/jcamiel/hurl- ```shell $ chmod u+x bin/integration.sh -$ bin/integration.sh +$ bin/integration.sh http://localhost:3000 Starting container 5d311561828d6078e84eb4b8b87dfd5d67bde6d9614ad83860b60cf310438d2a ``` @@ -70,9 +124,8 @@ $ docker stop movies movies ``` -Now, we have a basic script that starts our container. Before adding our -integration tests, we need to ensure that our application server is ready: the -container has started, but the application server can take a few seconds to be +Now, we have a basic script that starts our container. Before adding our integration tests, we need to ensure that our +application server is ready: the container has started, but the application server can take a few seconds to be really ready to accept incoming HTTP requests. To do so, we can test our health API. With a function `wait_for_url`, @@ -82,12 +135,12 @@ until the check succeeds with [`--retry`] Hurl option. Once the test has succeed 5. Modify `bin/integration.sh` to wait for the application to be ready: ```bash -#!/bin/bash +#!/bin/sh set -eu wait_for_url () { echo "Testing $1..." - echo -e "GET $1\nHTTP 200" | hurl --retry "$2" > /dev/null; + printf 'GET %s\nHTTP 200' "$1" | hurl --retry "$2" > /dev/null; return 0 } @@ -95,21 +148,20 @@ echo "Starting container" docker run --name movies --rm --detach --publish 3000:3000 ghcr.io/jcamiel/hurl-express-tutorial:latest echo "Waiting server to be ready" -wait_for_url 'http://localhost:3000' 60 +wait_for_url "$1" 60 echo "Stopping container" docker stop movies ``` -We have now the simplest integration test script: it pulls our Docker image, then starts -the container and waits for a `200 OK` response. +We have now the simplest integration test script: it pulls our Docker image, then starts the container and waits for a `200 OK` response. Next, we're going to add our Hurl tests to the script. 6. Modify `bin/integration.sh` to add integration tests: ```bash -#!/bin/bash +#!/bin/sh set -eu # ... @@ -121,7 +173,7 @@ echo "Waiting server to be ready" # ... echo "Running Hurl tests" -hurl --test integration/*.hurl +hurl --variable host="$1" --test integration/*.hurl echo "Stopping container" # ... @@ -130,7 +182,7 @@ echo "Stopping container" 7. Run [`bin/integration.sh`] to check that our application passes all tests: ```shell -$ bin/integration.sh +$ bin/integration.sh http://localhost:3000 Starting container 48cf21d193a01651fc42b80648abdb51dc626f31c3f9c8917aea899c68eb4a12 Waiting server to be ready @@ -160,8 +212,18 @@ to create a [GitHub Action]. You can also see how to integrate your tests in [Gi 1. Create a new empty repository in GitHub, named `movies-project`:
- Create new GitHub repository - Create new GitHub repository + + + + + Create new GitHub repository + + + + + + Create new GitHub repository +
@@ -178,7 +240,7 @@ $ git commit -m "Add integration tests." create mode 100755 bin/integration.sh ... $ git remote add origin https://github.com/jcamiel/movies-project.git -$ git push -u origin main +$ git push --set-upstream origin main Enumerating objects: 7, done. Counting objects: 100% (7/7), done. ... @@ -187,7 +249,7 @@ Counting objects: 100% (7/7), done. Next, we are going to add a GitHub Action to our repo. The purpose of this action will be to launch our integration script on each commit. -3. Create a file in `.github/workflows/ci.yml`: +3. Create a file in `.github/workflows/ci.yml`: ```yaml name: CI @@ -211,7 +273,7 @@ jobs: run: | curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb sudo dpkg -i hurl_4.0.0_amd64.deb - bin/integration.sh + bin/integration.sh http://localhost:3000 ``` 4. Commit and push the new action: @@ -231,13 +293,113 @@ Counting objects: 100% (6/6), done. Finally, you can check on GitHub that our action is running:
- GitHub Action - GitHub Action + + + + + GitHub Action + + + + + + GitHub Action +
## Running Tests with GitLab CI/CD -If you use [GitLab CI/CD], you can check [this detailed tutorial] on how to continuously run your Hurl test suite. +1. Create a new empty repository in GitLab, named `movies-project`: + +
+ + + + + Create new GitLab repository + + + + + + Create new GitLab repository + +
+ +2. On your computer, create a git repo in `movies-project` directory and + commit the projects files: + +```shell +$ git init +Initialized empty Git repository in /Users/jc/Documents/Dev/movies-project/.git/ +$ git add . +$ git commit -m "Add integration tests." +[master (root-commit) ea3e5cd] Add integration tests. + 3 files changed, 146 insertions(+) + create mode 100755 bin/integration.sh +... +$ git remote add origin git@gitlab.com:jcamiel/movies-project.git +$ git push --set-upstream origin main +Enumerating objects: 7, done. +Counting objects: 100% (7/7), done. +... +``` + +Next, we are going to add a GitLab CI/CD pipeline. The purpose of this pipeline will be to launch our integration +script on each commit. We'll base our image on a Docker based image, with a [Docker-In-Docker service]. + +3. Create a file `.gitlab-ci.yml`: + +```yaml +image: docker:24 + +build: + stage: build + services: + - docker:24-dind + before_script: + # Add Hurl on Alpine (testing channel) + - apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing hurl + script: + - bin/integration.sh http://docker:3000 +``` + +> Because of Docker-In-Docker, our server is accessible with the `docker` hostname (and not `localhost`). As we have +> made our script configurable, we can just pass the hostname and don't modify our integration script + + +4. Commit and push the new action: + +```shell +$ git add .gitlab-ci.yml +$ git commit -m "Add GitLab CI/CD pipeline." +[main 11c4e7e] Add GitLab CI/CD pipeline. + 1 file changed, 13 insertions(+) + create mode 100644 .gitlab-ci.yml +$ git push +Enumerating objects: 6, done. +Counting objects: 100% (6/6), done. +... +``` + +Finally, you can check on GitLab that our pipeline is running: + +
+ + + + + GitHub Action + + + + + + GitHub Action + +
+ +For a more complete [GitLab CI/CD] example, you can check [this detailed tutorial] on how to continuously run your Hurl test suite. ## Tests Report @@ -259,3 +421,7 @@ Now, we can add more Hurl tests and start developing new features with confidenc [GitLab CI/CD]: https://about.gitlab.com/why-gitlab/ [this detailed tutorial]: https://about.gitlab.com/blog/2022/12/14/how-to-continously-test-web-apps-apis-with-hurl-and-gitlab-ci-cd/ [`--retry`]: /docs/manual.md#retry +[variables]: /docs/templates.md#variables +[chaining requests]: /docs/tutorial/chaining-requests.md +[Docker-In-Docker service]: https://docs.gitlab.com/ee/ci/docker/ +[`--variable`]: /docs/manual.md#variable