From 42b3ef0238600478aa5299cc1e55413b5c68df76 Mon Sep 17 00:00:00 2001 From: Mario Vitale Date: Tue, 7 Nov 2023 10:45:43 +0100 Subject: [PATCH] CLD-5699 Preliminary fixes (#25040) * Rework some of PR24647 * Store MM_LICENSE to .env.server file * Remove legacy network setup * Fixes, generate docker-compose and env files in one place * Simplify templating mechanism for server.yml * Fix race condition for dashboard start * Fix websockets for local debugging * Fix: make webhook-interaction work again * Simplify and fix dashboard&cloud configuration, formatting fix --------- Co-authored-by: Mattermost Build --- e2e-tests/.ci/.e2erc | 48 ++- e2e-tests/.ci/.e2erc_setup | 22 - e2e-tests/.ci/.env.cypress | 1 - e2e-tests/.ci/.env.dashboard | 1 - e2e-tests/.ci/.env.server | 1 - e2e-tests/.ci/.env.server.cloud | 1 - e2e-tests/.ci/.gitignore | 8 +- e2e-tests/.ci/dashboard.override.yml | 6 +- e2e-tests/.ci/dashboard.start.sh | 9 +- e2e-tests/.ci/dashboard.stop.sh | 2 +- e2e-tests/.ci/docker-compose.cypress.yml | 61 --- e2e-tests/.ci/docker-compose.playwright.yml | 32 -- e2e-tests/.ci/docker_compose_generator.sh | 242 ----------- e2e-tests/.ci/server.cloud_customer_delete.sh | 25 -- ...ustomer_create.sh => server.cloud_init.sh} | 17 +- e2e-tests/.ci/server.cloud_teardown.sh | 24 ++ e2e-tests/.ci/server.generate.sh | 376 ++++++++++++++++++ e2e-tests/.ci/server.prepare.sh | 48 ++- e2e-tests/.ci/server.run_cypress.sh | 1 - e2e-tests/.ci/server.run_playwright.sh | 1 - e2e-tests/.ci/server.run_test.sh | 22 + e2e-tests/.ci/server.start.sh | 72 ---- e2e-tests/.ci/server.stop.sh | 1 - e2e-tests/.gitignore | 3 - e2e-tests/Makefile | 79 ++-- e2e-tests/README.md | 41 +- e2e-tests/cypress/package-lock.json | 1 + e2e-tests/cypress/package.json | 1 + 28 files changed, 540 insertions(+), 606 deletions(-) delete mode 100644 e2e-tests/.ci/.e2erc_setup delete mode 100644 e2e-tests/.ci/.env.cypress delete mode 100644 e2e-tests/.ci/.env.dashboard delete mode 100644 e2e-tests/.ci/.env.server delete mode 100644 e2e-tests/.ci/.env.server.cloud delete mode 100644 e2e-tests/.ci/docker-compose.cypress.yml delete mode 100644 e2e-tests/.ci/docker-compose.playwright.yml delete mode 100755 e2e-tests/.ci/docker_compose_generator.sh delete mode 100755 e2e-tests/.ci/server.cloud_customer_delete.sh rename e2e-tests/.ci/{server.cloud_customer_create.sh => server.cloud_init.sh} (65%) create mode 100755 e2e-tests/.ci/server.cloud_teardown.sh create mode 100755 e2e-tests/.ci/server.generate.sh create mode 100755 e2e-tests/.ci/server.run_test.sh diff --git a/e2e-tests/.ci/.e2erc b/e2e-tests/.ci/.e2erc index a6c8efe301..d72ff7d707 100644 --- a/e2e-tests/.ci/.e2erc +++ b/e2e-tests/.ci/.e2erc @@ -2,6 +2,9 @@ # Utility variables # NB: these assume you `source` them from the directory this file is in +# Set up base docker compose file and export +export MME2E_DC_SERVER="docker compose -p mmserver -f ./server.yml" +export MME2E_DC_DASHBOARD="docker compose -p mmdashboard -f ./dashboard/docker/docker-compose.yml -f ./dashboard.override.yml" export MME2E_UID=$(id -u) export MME2E_OSTYPE=$(docker version -f '{{ .Client.Os }}') export MME2E_ARCHTYPE=$(docker version -f '{{ .Client.Arch }}') @@ -10,8 +13,11 @@ export NODE_VERSION_REQUIRED=$(cat ../../.nvmrc) # Default values for optional variables export SERVER_IMAGE_DEFAULT="mattermostdevelopment/mm-ee-test:$(git rev-parse --short=7 HEAD)" export BROWSER_DEFAULT="chrome" +export SERVER_DEFAULT="self-hosted" +export TEST_DEFAULT="cypress" +export ENABLED_DOCKER_SERVICES_DEFAULT="postgres inbucket" +# OS specific defaults overrides case $MME2E_OSTYPE in - # OS specific defaults overrides darwin ) BROWSER_DEFAULT="electron" ;; * ) @@ -20,6 +26,9 @@ esac # Populate the optional variables that are used in the docker-compose file export SERVER_IMAGE=${SERVER_IMAGE:-$SERVER_IMAGE_DEFAULT} export BROWSER=${BROWSER:-$BROWSER_DEFAULT} +export SERVER=${SERVER:-$SERVER_DEFAULT} +export TEST=${TEST:-$TEST_DEFAULT} +export ENABLED_DOCKER_SERVICES=${ENABLED_DOCKER_SERVICES:-$ENABLED_DOCKER_SERVICES_DEFAULT} # Function definitions mme2e_log () { echo "[$(date +%Y-%m-%dT%H:%M:%S%Z)]" "$@"; } @@ -30,16 +39,16 @@ mme2e_get_current_shopt_arg () { case $(set -o | sed -n -E "s/^${SHOPT_ARG}[[:space:]]+(o..?)$/\1/p") in on) echo -n "-o ${SHOPT_ARG}";; off) echo -n "+o ${SHOPT_ARG}";; - *) exit 1;; + *) return 1;; esac } mme2e_load_env_file () { - # This loads the ./.env file. Variables are automatically exported - [ -f ./.env ] || return 0 + # This loads the ./env file. Variables are automatically exported + [ -f ./env ] || return 0 MME2E_PREVIOUS_ALLEXPORT=$(mme2e_get_current_shopt_arg allexport) set -o allexport - mme2e_log "Loading .env file" - . ./.env + mme2e_log "Loading env file" + . ./env # shellcheck disable=SC2086 set ${MME2E_PREVIOUS_ALLEXPORT} } @@ -65,14 +74,15 @@ mme2e_wait_command_success () { # shellcheck disable=SC2086 set ${MME2E_PREVIOUS_PIPEFAIL} if [ "$RETRIES_LEFT" = "0" ]; then - exit 1 + return 1 fi } mme2e_wait_service_healthy () { + DC_COMMAND="${DC_COMMAND:-$MME2E_DC_SERVER}" SERVICE_NAME=${1?} RETRIES_LEFT=${2:-1} RETRIES_INTERVAL=${3:-10} - mme2e_wait_command_success "${MME2E_DC_SERVER} ps ${SERVICE_NAME} | grep -q '\(healthy\)'" "Waiting for ${SERVICE_NAME} container to be healthy" "$RETRIES_LEFT" "$RETRIES_INTERVAL" + mme2e_wait_command_success "${DC_COMMAND} ps ${SERVICE_NAME} | grep -q '\(healthy\)'" "Waiting for ${SERVICE_NAME} container to be healthy" "$RETRIES_LEFT" "$RETRIES_INTERVAL" } mme2e_wait_image () { IMAGE_NAME=${1?} @@ -80,20 +90,16 @@ mme2e_wait_image () { RETRIES_INTERVAL=${3:-10} mme2e_wait_command_success "docker pull $IMAGE_NAME" "Waiting for docker image ${IMAGE_NAME} to be available" "$RETRIES_LEFT" "$RETRIES_INTERVAL" } -mme2e_legacy_setup () { - # These functions are needed until every pipeline depending on the `server/build/gitlab-dc.*.yml` files is adapted to not use external docker networking anymore - # After that is fixed, this function and the external network in the docker-compose files may be removed - export COMPOSE_PROJECT_NAME=mmserver_legacy - case $MME2E_OSTYPE in - windows ) - # https://learn.microsoft.com/en-us/virtualization/windowscontainers/container-networking/network-drivers-topologies - DOCKER_NETWORK_DRIVER="nat" ;; - * ) - DOCKER_NETWORK_DRIVER="bridge" ;; - esac - docker network inspect ${COMPOSE_PROJECT_NAME} >/dev/null 2>&1 || docker network create --driver=${DOCKER_NETWORK_DRIVER} ${COMPOSE_PROJECT_NAME} +mme2e_is_token_in_list() { + local TOKEN=$1 + local LIST=$2 + grep -qE "(^| )$TOKEN( |$)" <<<"$LIST" } +# Utility alias, for interactive shell usage. Can be reversed with 'unalias docker-compose' in your shell +# NB: this won't work in the script +alias docker-compose-mmserver='${MME2E_DC_SERVER}' +alias docker-compose-mmdashboard='${MME2E_DC_DASHBOARD}' + # Call prerequisite utility functions mme2e_load_env_file -mme2e_legacy_setup # Temporary diff --git a/e2e-tests/.ci/.e2erc_setup b/e2e-tests/.ci/.e2erc_setup deleted file mode 100644 index e032f570a7..0000000000 --- a/e2e-tests/.ci/.e2erc_setup +++ /dev/null @@ -1,22 +0,0 @@ -# shellcheck disable=SC2148 - -# Set up base docker compose file and export -DC_FILE="docker-compose.server.override.yml" -if [ ! -f docker-compose.server.override.yml ]; then - echo "No './.ci/docker-compose.server.override.yml' found. You may need to run 'make generate-docker-compose'" - exit 1 -fi - -if [ "$TEST" = "cypress" ]; then - MME2E_DC_SERVER="docker compose -p mmserver -f ./$DC_FILE -f ./docker-compose.cypress.yml" -elif [ "$TEST" = "playwright" ]; then - MME2E_DC_SERVER="docker compose -p mmserver -f ./$DC_FILE -f ./docker-compose.playwright.yml" -else - MME2E_DC_SERVER="docker compose -p mmserver -f ./$DC_FILE" -fi - -export MME2E_DC_SERVER=$MME2E_DC_SERVER -alias docker-compose-mmserver='${MME2E_DC_SERVER}' - -export MME2E_DC_DASHBOARD="docker compose -p mmdashboard -f ./dashboard/docker/docker-compose.yml -f ./dashboard.override.yml" -alias docker-compose-mmdashboard='${MME2E_DC_DASHBOARD}' diff --git a/e2e-tests/.ci/.env.cypress b/e2e-tests/.ci/.env.cypress deleted file mode 100644 index 64c0275276..0000000000 --- a/e2e-tests/.ci/.env.cypress +++ /dev/null @@ -1 +0,0 @@ -# NB: this file is just a placeholder required by docker-compose. It's supposed to be modified by the CI pipeline and should remain empty in git diff --git a/e2e-tests/.ci/.env.dashboard b/e2e-tests/.ci/.env.dashboard deleted file mode 100644 index 64c0275276..0000000000 --- a/e2e-tests/.ci/.env.dashboard +++ /dev/null @@ -1 +0,0 @@ -# NB: this file is just a placeholder required by docker-compose. It's supposed to be modified by the CI pipeline and should remain empty in git diff --git a/e2e-tests/.ci/.env.server b/e2e-tests/.ci/.env.server deleted file mode 100644 index 64c0275276..0000000000 --- a/e2e-tests/.ci/.env.server +++ /dev/null @@ -1 +0,0 @@ -# NB: this file is just a placeholder required by docker-compose. It's supposed to be modified by the CI pipeline and should remain empty in git diff --git a/e2e-tests/.ci/.env.server.cloud b/e2e-tests/.ci/.env.server.cloud deleted file mode 100644 index 64c0275276..0000000000 --- a/e2e-tests/.ci/.env.server.cloud +++ /dev/null @@ -1 +0,0 @@ -# NB: this file is just a placeholder required by docker-compose. It's supposed to be modified by the CI pipeline and should remain empty in git diff --git a/e2e-tests/.ci/.gitignore b/e2e-tests/.ci/.gitignore index 855154b663..1d9b62a8aa 100644 --- a/e2e-tests/.ci/.gitignore +++ b/e2e-tests/.ci/.gitignore @@ -1,6 +1,4 @@ dashboard -.env -!.env.cypress -!.env.server -!.env.server.cloud -!.env.dashboard +server.yml +env +.env.* diff --git a/e2e-tests/.ci/dashboard.override.yml b/e2e-tests/.ci/dashboard.override.yml index 6ebd3526fa..3f8471ccaa 100644 --- a/e2e-tests/.ci/dashboard.override.yml +++ b/e2e-tests/.ci/dashboard.override.yml @@ -13,10 +13,14 @@ services: JWT_EXPIRES_IN: 365d ALLOWED_USER: cypress-test ALLOWED_ROLE: integration + healthcheck: + test: ["CMD", "curl", "-s", "-o/dev/null", "127.0.0.1:4000"] + interval: 10s + timeout: 15s + retries: 12 volumes: - "../:/app" - "../../dashboard.entrypoint.sh:/usr/local/bin/dashboard.entrypoint.sh:ro" - - "../../.env.dashboard:/var/local/.env.dashboard:rw" working_dir: /app entrypoint: /usr/local/bin/dashboard.entrypoint.sh ports: diff --git a/e2e-tests/.ci/dashboard.start.sh b/e2e-tests/.ci/dashboard.start.sh index 7a2429973e..18b146d2ff 100755 --- a/e2e-tests/.ci/dashboard.start.sh +++ b/e2e-tests/.ci/dashboard.start.sh @@ -2,7 +2,6 @@ set -e -u -o pipefail cd "$(dirname "$0")" . .e2erc -. .e2erc_setup MME2E_DASHBOARD_REF_DEFAULT="origin/main" MME2E_DASHBOARD_REF=${MME2E_DASHBOARD_REF:-$MME2E_DASHBOARD_REF_DEFAULT} @@ -12,7 +11,6 @@ if [ ! -d dashboard ]; then git clone https://github.com/saturninoabril/automation-dashboard.git dashboard # Must reinitialize some variables that depend on the dashboard repo being checked out . .e2erc - . .e2erc_setup fi git -C dashboard fetch git -C dashboard checkout "$MME2E_DASHBOARD_REF" @@ -20,6 +18,11 @@ git -C dashboard checkout "$MME2E_DASHBOARD_REF" mme2e_log "Starting the dashboard" ${MME2E_DC_DASHBOARD} up -d db dashboard +if ! DC_COMMAND="${MME2E_DC_DASHBOARD}" mme2e_wait_service_healthy dashboard 60 10; then + mme2e_log "Dashboard container not healthy, retry attempts exhausted. Giving up." >&2 + exit 1 +fi + mme2e_log "Generating the dashboard's local URL" case $MME2E_OSTYPE in darwin) @@ -36,7 +39,7 @@ esac AUTOMATION_DASHBOARD_URL="http://${AUTOMATION_DASHBOARD_IP}:4000/api" mme2e_log "Generating a signed JWT token for accessing the dashboard" -${MME2E_DC_DASHBOARD} exec -T dashboard bash -c "rm -rf node_modules && npm install --cache /tmp/empty-cache" +# Not running 'npm install'. We assume it has been run by the dashboard container's entrypoint # shellcheck disable=SC2034 AUTOMATION_DASHBOARD_TOKEN=$(${MME2E_DC_DASHBOARD} exec -T dashboard node script/sign.js | awk '{ print $2; }') # The token secret is specified in the dashboard.override.yml file diff --git a/e2e-tests/.ci/dashboard.stop.sh b/e2e-tests/.ci/dashboard.stop.sh index 61bcbea0e6..9ec0235ffa 100755 --- a/e2e-tests/.ci/dashboard.stop.sh +++ b/e2e-tests/.ci/dashboard.stop.sh @@ -2,11 +2,11 @@ set -e -u -o pipefail cd "$(dirname "$0")" . .e2erc -. .e2erc_setup if [ -d dashboard ]; then mme2e_log "Stopping the dashboard containers" ${MME2E_DC_DASHBOARD} down else + # Base docker-compose file is found in the dashboard repo, we can't run docker commands without it mme2e_log "Not stopping the dashboard containers: dashboard repo not checked out locally, skipping" fi diff --git a/e2e-tests/.ci/docker-compose.cypress.yml b/e2e-tests/.ci/docker-compose.cypress.yml deleted file mode 100644 index 11cb4472b7..0000000000 --- a/e2e-tests/.ci/docker-compose.cypress.yml +++ /dev/null @@ -1,61 +0,0 @@ -# Image hashes in this file are for amd64 systems - -version: "2.4" -services: - cypress: - image: "cypress/browsers:node-18.16.1-chrome-114.0.5735.133-1-ff-114.0.2-edge-114.0.1823.51-1" - ### Temporarily disabling this image, until both the amd64 and arm64 version are mirrored - # image: "mattermostdevelopment/mirrored-cypress-browsers-public:node-18.16.1-chrome-114.0.5735.133-1-ff-114.0.2-edge-114.0.1823.51-1" - entrypoint: ["/bin/bash", "-c"] - command: ["until [ -f /var/run/mm_terminate ]; do sleep 5; done"] - env_file: - - "../../e2e-tests/.ci/.env.dashboard" - - "../../e2e-tests/.ci/.env.cypress" - environment: - REPO: "mattermost" - # Cypress configuration - HEADLESS: "true" - CYPRESS_baseUrl: "http://server:8065" - CYPRESS_dbConnection: "postgres://mmuser:mostest@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10" - CYPRESS_smtpUrl: "http://inbucket:9001" - CYPRESS_webhookBaseUrl: "http://webhook-interactions:3000" - CYPRESS_chromeWebSecurity: "false" - CYPRESS_firstTest: "true" - CYPRESS_resetBeforeTest: "true" - CYPRESS_allowedUntrustedInternalConnections: "localhost webhook-interactions" - TM4J_ENABLE: "false" - # disable shared memory X11 affecting Cypress v4 and Chrome - # https://github.com/cypress-io/cypress-docker-images/issues/270 - QT_X11_NO_MITSHM: "1" - _X11_NO_MITSHM: "1" - _MITSHM: "0" - # avoid too many progress messages - # https://github.com/cypress-io/cypress/issues/1243 - CI: "1" - # Ensure we're independent from the global node environment - PATH: /cypress/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - ulimits: - nofile: - soft: 8096 - hard: 1048576 - working_dir: /cypress - volumes: - - "../../e2e-tests/cypress/:/cypress" - - webhook-interactions: - image: mattermostdevelopment/mirrored-node:${NODE_VERSION_REQUIRED} - command: sh -c "npm install --legacy-peer-deps && exec node webhook_serve.js" - environment: - NODE_PATH: /usr/local/lib/node_modules/ - healthcheck: - test: ["CMD", "curl", "-s", "-o/dev/null", "127.0.0.1:3000"] - interval: 10s - timeout: 15s - retries: 12 - working_dir: /cypress - volumes: - - "../../e2e-tests/cypress/:/cypress:ro" - networks: - default: - aliases: - - webhook-interactions diff --git a/e2e-tests/.ci/docker-compose.playwright.yml b/e2e-tests/.ci/docker-compose.playwright.yml deleted file mode 100644 index 78001da5f1..0000000000 --- a/e2e-tests/.ci/docker-compose.playwright.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Image hashes in this file are for amd64 systems - -version: "2.4" -services: - playwright: - image: mcr.microsoft.com/playwright:v1.38.1-jammy - entrypoint: ["/bin/bash", "-c"] - command: ["until [ -f /var/run/mm_terminate ]; do sleep 5; done"] - env_file: - - "./.env.playwright" - environment: - CI: "true" - NODE_OPTIONS: --no-experimental-fetch - PW_BASE_URL: http://server:8065 - PW_ADMIN_USERNAME: sysadmin - PW_ADMIN_PASSWORD: Sys@dmin-sample1 - PW_ADMIN_EMAIL: sysadmin@sample.mattermost.com - PW_ENSURE_PLUGINS_INSTALLED: "" - PW_HA_CLUSTER_ENABLED: "false" - PW_RESET_BEFORE_TEST: "false" - PW_HEADLESS: "true" - PW_SLOWMO: 0 - PW_WORKERS: 2 - PW_SNAPSHOT_ENABLE: "false" - PW_PERCY_ENABLE: "false" - ulimits: - nofile: - soft: 8096 - hard: 1048576 - working_dir: /mattermost - volumes: - - "../../:/mattermost" diff --git a/e2e-tests/.ci/docker_compose_generator.sh b/e2e-tests/.ci/docker_compose_generator.sh deleted file mode 100755 index 865a2bb15c..0000000000 --- a/e2e-tests/.ci/docker_compose_generator.sh +++ /dev/null @@ -1,242 +0,0 @@ -#!/bin/bash -# SC2034: appears unused. -# https://www.shellcheck.net/wiki/SC2034 -# shellcheck disable=SC2034 -# Note: Variables are dynamically used depending on usage input (ENABLED_DOCKER_SERVICES) - -set -e -u -o pipefail -cd "$(dirname "$0")" -. .e2erc - -# File to be used for overriding docker compose -CONFIG_FILE="docker-compose.server.override.yml" - -# Check if ENABLED_DOCKER_SERVICES is set or not -if [ -n "${ENABLED_DOCKER_SERVICES-}" ] && [ -n "$ENABLED_DOCKER_SERVICES" ]; then - mme2e_log "ENABLED_DOCKER_SERVICES: $ENABLED_DOCKER_SERVICES" -else - # If not set, then remove the override file if it exists and exit - mme2e_log "ENABLED_DOCKER_SERVICES is empty or unset." - if [ -f $CONFIG_FILE ]; then - rm -f $CONFIG_FILE - mme2e_log "$CONFIG_FILE removed." - else - mme2e_log "No override to docker compose." - fi - exit 0 -fi - -# Define list of valid services -validServices=("postgres:5432" "minio:9000" "inbucket:9001" "openldap:389" "elasticsearch:9200" "keycloak:8080") - -# Read the enabled docker services and split them into an array -enabled_docker_services="$ENABLED_DOCKER_SERVICES" -read -ra docker_services <<<"$enabled_docker_services" - -# Initialize variables for required services -postgres_found=false -inbucket_found=false - -# Get service and post of valid services -services=() -for service in "${docker_services[@]}"; do - port="" - for svcPort in "${validServices[@]}"; do - svc=${svcPort%%:*} - if [ "$service" == "$svc" ]; then - port=${svcPort#*:} - - # Find the required services - if [ "$service" == "$svc" ]; then - if [ "$service" == "postgres" ]; then - postgres_found=true - elif [ "$service" == "inbucket" ]; then - inbucket_found=true - fi - fi - break - fi - done - - if [ -z "$port" ]; then - mme2e_log "Unknown service $svc" - exit 1 - fi - - services+=("$service:$port") -done - -# Check if the required services such as postgres and inbucket are found -# Do not continue if any of the required services are not found. -if [ "$postgres_found" != true ] || [ "$inbucket_found" != true ]; then - mme2e_log "When overriding docker compose via ENABLED_DOCKER_SERVICES, postgres and inbucket are both required." - exit 1 -fi - -# Define each service values -postgres=' - postgres: - image: mattermostdevelopment/mirrored-postgres:12 - restart: always - environment: - POSTGRES_USER: mmuser - POSTGRES_PASSWORD: mostest - POSTGRES_DB: mattermost_test - command: postgres -c "config_file=/etc/postgresql/postgresql.conf" - volumes: - - ../../server/build/docker/postgres.conf:/etc/postgresql/postgresql.conf - healthcheck: - test: ["CMD", "pg_isready", "-h", "localhost"] - interval: 10s - timeout: 15s - retries: 12 - networks: - default: - aliases: - - postgres' - -inbucket=' - inbucket: - restart: "no" - container_name: mattermost-inbucket - ports: - - "9001:9001" - - "10025:10025" - - "10110:10110" - extends: - file: ../../server/build/gitlab-dc.common.yml - service: inbucket' - -minio=' - minio: - restart: "no" - container_name: mattermost-minio - ports: - - "9000:9000" - extends: - file: ../../server/build/gitlab-dc.common.yml - service: minio' - -openldap=' - openldap: - restart: "no" - container_name: mattermost-openldap - ports: - - "389:389" - - "636:636" - extends: - file: ../../server/build/gitlab-dc.common.yml - service: openldap' - -elasticsearch=' - elasticsearch: - restart: "no" - container_name: mattermost-elasticsearch - ports: - - "9200:9200" - - "9300:9300" - extends: - file: ../../server/build/gitlab-dc.common.yml - service: elasticsearch' - -elasticsearch_arm64=' - elasticsearch: - image: mattermostdevelopment/mattermost-elasticsearch:7.17.10 - platform: linux/arm64/v8 - restart: "no" - container_name: mattermost-elasticsearch - ports: - - "9200:9200" - - "9300:9300" - extends: - file: ../../server/build/gitlab-dc.common.yml - service: elasticsearch' - -keycloak=' - keycloak: - restart: "no" - container_name: mattermost-keycloak - ports: - - "8484:8080" - extends: - file: ../../server/build/gitlab-dc.common.yml - service: keycloak' - -# Function to get the service value based on the key -get_service_val_by_key() { - local key="$1" - - if [ "$MME2E_ARCHTYPE" = "arm64" ] && [ "$key" = "elasticsearch" ]; then - # Use arm64 version of elasticsearch - key="elasticsearch_arm64" - fi - - # Use variable indirection to retrieve the value - local service_val="${!key}" - - echo "$service_val" -} - -# Generate the docker compose override file -cat <"$CONFIG_FILE" -# Image hashes in this file are for amd64 systems -# NB: May include paths relative to the "server/build" directory, which contains the original compose file that this yaml is overriding - -version: "2.4" -services: - server: - image: \${SERVER_IMAGE} - restart: always - env_file: - - "./.env.server" - - "./.env.server.cloud" - environment: - MM_LICENSE: \${MM_LICENSE} - MM_SERVICESETTINGS_SITEURL: http://server:8065 - MM_SERVICESETTINGS_ENABLELOCALMODE: "true" - MM_PLUGINSETTINGS_ENABLED: "true" - MM_PLUGINSETTINGS_ENABLEUPLOADS: "true" - MM_PLUGINSETTINGS_AUTOMATICPREPACKAGEDPLUGINS: "true" - MM_TEAMSETTINGS_ENABLEOPENSERVER: "true" - MM_SQLSETTINGS_DATASOURCE: "postgres://mmuser:mostest@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10&binary_parameters=yes" - MM_SQLSETTINGS_DRIVERNAME: "postgres" - MM_EMAILSETTINGS_SMTPSERVER: "inbucket" - MM_CLUSTERSETTINGS_READONLYCONFIG: "false" - MM_SERVICESETTINGS_ENABLEONBOARDINGFLOW: "false" - MM_FEATUREFLAGS_ONBOARDINGTOURTIPS: "false" - MM_SERVICEENVIRONMENT: "test" - ports: - - "8065:8065" - depends_on: -$(for service in "${docker_services[@]}"; do - echo " $service:" - echo " condition: service_healthy" -done) -$(for service in "${docker_services[@]}"; do - service_val=$(get_service_val_by_key "$service") - - if [ -n "$service_val" ]; then - echo "$service_val" - fi -done) - - start_dependencies: - image: mattermost/mattermost-wait-for-dep:latest - depends_on: -$(for service in "${docker_services[@]}"; do - echo " - $service" -done) - command: $( - IFS=' ' - echo "${services[*]}" -) - networks: - default: - -networks: - default: - name: \${COMPOSE_PROJECT_NAME} - external: true -EOL - -mme2e_log "Configuration generated in $CONFIG_FILE" diff --git a/e2e-tests/.ci/server.cloud_customer_delete.sh b/e2e-tests/.ci/server.cloud_customer_delete.sh deleted file mode 100755 index 540eddbccf..0000000000 --- a/e2e-tests/.ci/server.cloud_customer_delete.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -e -u -o pipefail -cd "$(dirname "$0")" -. .e2erc - -if [ "$SERVER" != "cloud" ]; then - mme2e_log "Not applicable to SERVER='$SERVER'. For cloud only." - exit 0 -fi - -mme2e_log "Loading .env.server.cloud" -. .env.server.cloud - -# Check if CWS_URL is set or not -if [ -n "${CWS_URL-}" ] && [ -n "$CWS_URL" ]; then - mme2e_log "CWS_URL is set." -else - mme2e_log "Environment variable CWS_URL is empty or unset. It must be set to delete test cloud customer." - exit 1 -fi - -mme2e_log "Deleting customer $MM_CUSTOMER_ID." -curl -X DELETE "${CWS_URL}/api/v1/internal/tests/customers/$MM_CUSTOMER_ID/payment-customer" - -mme2e_log "Test cloud customer deleted, MM_CUSTOMER_ID: $MM_CUSTOMER_ID." diff --git a/e2e-tests/.ci/server.cloud_customer_create.sh b/e2e-tests/.ci/server.cloud_init.sh similarity index 65% rename from e2e-tests/.ci/server.cloud_customer_create.sh rename to e2e-tests/.ci/server.cloud_init.sh index aeb69564ad..23d797fe5f 100755 --- a/e2e-tests/.ci/server.cloud_customer_create.sh +++ b/e2e-tests/.ci/server.cloud_init.sh @@ -4,17 +4,16 @@ cd "$(dirname "$0")" . .e2erc if [ "$SERVER" != "cloud" ]; then - mme2e_log "Not applicable to SERVER='$SERVER'. For cloud only." + mme2e_log "Skipping cloud instance initialization: operation supported only for cloud server, but running with SERVER='$SERVER'" exit 0 fi -# Check if CWS_URL is set or not -if [ -n "${CWS_URL-}" ] && [ -n "$CWS_URL" ]; then - mme2e_log "CWS_URL is set." -else - mme2e_log "Environment variable CWS_URL is empty or unset. It must be set to create test cloud customer." - exit 1 -fi +mme2e_log "Initializing cloud tests" + +# Assert that required variables are set +MME2E_ENVCHECK_MSG="variable required for initializing cloud tests, but is empty or unset." +: "${CWS_URL:?$MME2E_ENVCHECK_MSG}" +: "${MM_LICENSE:?$MME2E_ENVCHECK_MSG}" response=$(curl -X POST "${CWS_URL}/api/v1/internal/tests/create-customer?sku=cloud-enterprise&is_paid=true") MM_CUSTOMER_ID=$(echo "$response" | jq -r .customer_id) @@ -27,7 +26,7 @@ export MM_CLOUD_INSTALLATION_ID=$MM_CLOUD_INSTALLATION_ID export MM_CLOUDSETTINGS_CWSURL=$CWS_URL export MM_CLOUDSETTINGS_CWSAPIURL=$CWS_URL -mme2e_generate_envfile_from_var_names >.env.server.cloud <.env.cloud < appears unused. +# https://www.shellcheck.net/wiki/SC2034 +# shellcheck disable=SC2034 +# Note: Variables are dynamically used depending on usage input (ENABLED_DOCKER_SERVICES) + +set -e -u -o pipefail +cd "$(dirname "$0")" +. .e2erc + +enable_docker_service() { + local SERVICE_TO_ENABLE="$1" + if ! mme2e_is_token_in_list "$SERVICE_TO_ENABLE" "$ENABLED_DOCKER_SERVICES"; then + ENABLED_DOCKER_SERVICES="$ENABLED_DOCKER_SERVICES $SERVICE_TO_ENABLE" + fi +} + +assert_docker_services_validity() { + local SERVICES_TO_CHECK="$*" + local SERVICES_VALID="postgres minio inbucket openldap elasticsearch keycloak cypress webhook-interactions playwright" + local SERVICES_REQUIRED="postgres inbucket" + for SERVICE_NAME in $SERVICES_TO_CHECK; do + if ! mme2e_is_token_in_list "$SERVICE_NAME" "$SERVICES_VALID"; then + mme2e_log "Error, requested invalid service: $SERVICE_NAME" >&2 + mme2e_log "Valid services are: $SERVICES_VALID" >&2 + mme2e_log "Aborting" >&2 + exit 1 + fi + SERVICES_REQUIRED="${SERVICES_REQUIRED/$SERVICE_NAME/}" + done + if [ -n "${SERVICES_REQUIRED/ /}" ]; then + mme2e_log "Missing required services: $SERVICES_REQUIRED" >&2 + mme2e_log "Aborting" >&2 + exit 2 + fi +} + +generate_docker_compose_file() { + # Generating the server docker-compose file + local DC_FILE="server.yml" + mme2e_log "Generating docker-compose file in: $DC_FILE" + + # Generate the docker compose override file + cat <"$DC_FILE" +# Image hashes in this file are for amd64 systems +# NB: May include paths relative to the "server/build" directory, which contains the original compose file that this yaml is overriding + +version: "2.4" +services: + server: + image: \${SERVER_IMAGE} + restart: always + env_file: + - "./.env.server" + environment: + MM_SERVICESETTINGS_ALLOWCORSFROM: "*" + MM_SERVICESETTINGS_ENABLELOCALMODE: "true" + MM_PLUGINSETTINGS_ENABLED: "true" + MM_PLUGINSETTINGS_ENABLEUPLOADS: "true" + MM_PLUGINSETTINGS_AUTOMATICPREPACKAGEDPLUGINS: "true" + MM_TEAMSETTINGS_ENABLEOPENSERVER: "true" + MM_SQLSETTINGS_DATASOURCE: "postgres://mmuser:mostest@localhost:5432/mattermost_test?sslmode=disable&connect_timeout=10&binary_parameters=yes" + MM_SQLSETTINGS_DRIVERNAME: "postgres" + MM_EMAILSETTINGS_SMTPSERVER: "inbucket" + MM_CLUSTERSETTINGS_READONLYCONFIG: "false" + MM_SERVICESETTINGS_ENABLEONBOARDINGFLOW: "false" + MM_FEATUREFLAGS_ONBOARDINGTOURTIPS: "false" + MM_SERVICEENVIRONMENT: "test" + network_mode: host + depends_on: +$(for service in $ENABLED_DOCKER_SERVICES; do + # The server container will start only if all other dependent services are healthy + # Skip creating the dependency for containers that don't need a healthcheck + if grep -qE "^(cypress|webhook-interactions|playwright)" <<<"$service"; then + continue + fi + echo " $service:" + echo " condition: service_healthy" + done) + +$(if mme2e_is_token_in_list "postgres" "$ENABLED_DOCKER_SERVICES"; then + echo ' + postgres: + image: mattermostdevelopment/mirrored-postgres:12 + restart: always + environment: + POSTGRES_USER: mmuser + POSTGRES_PASSWORD: mostest + POSTGRES_DB: mattermost_test + command: postgres -c "config_file=/etc/postgresql/postgresql.conf" + volumes: + - ../../server/build/docker/postgres.conf:/etc/postgresql/postgresql.conf + network_mode: host + healthcheck: + test: ["CMD", "pg_isready", "-h", "localhost"] + interval: 10s + timeout: 15s + retries: 12' + fi) + +$(if mme2e_is_token_in_list "inbucket" "$ENABLED_DOCKER_SERVICES"; then + echo ' + inbucket: + restart: "no" + network_mode: host + extends: + file: ../../server/build/gitlab-dc.common.yml + service: inbucket' + fi) + +$(if mme2e_is_token_in_list "minio" "$ENABLED_DOCKER_SERVICES"; then + echo ' + minio: + restart: "no" + network_mode: host + extends: + file: ../../server/build/gitlab-dc.common.yml + service: minio' + fi) + +$(if mme2e_is_token_in_list "openldap" "$ENABLED_DOCKER_SERVICES"; then + echo ' + openldap: + restart: "no" + network_mode: host + extends: + file: ../../server/build/gitlab-dc.common.yml + service: openldap' + fi) + +$(if mme2e_is_token_in_list "elasticsearch" "$ENABLED_DOCKER_SERVICES"; then + if [ "$MME2E_ARCHTYPE" = "arm64" ]; then + echo ' + elasticsearch: + image: mattermostdevelopment/mattermost-elasticsearch:7.17.10 + platform: linux/arm64/v8 + restart: "no" + network_mode: host + extends: + file: ../../server/build/gitlab-dc.common.yml + service: elasticsearch' + else + echo ' + elasticsearch: + restart: "no" + network_mode: host + extends: + file: ../../server/build/gitlab-dc.common.yml + service: elasticsearch' + fi + fi) + +$(if mme2e_is_token_in_list "keycloak" "$ENABLED_DOCKER_SERVICES"; then + echo ' + keycloak: + restart: "no" + network_mode: host + extends: + file: ../../server/build/gitlab-dc.common.yml + service: keycloak' + fi) + +$(if mme2e_is_token_in_list "cypress" "$ENABLED_DOCKER_SERVICES"; then + echo ' + cypress: + image: "cypress/browsers:node-18.16.1-chrome-114.0.5735.133-1-ff-114.0.2-edge-114.0.1823.51-1" + ### Temporarily disabling this image, until both the amd64 and arm64 version are mirrored + # image: "mattermostdevelopment/mirrored-cypress-browsers-public:node-18.16.1-chrome-114.0.5735.133-1-ff-114.0.2-edge-114.0.1823.51-1" + entrypoint: ["/bin/bash", "-c"] + command: ["until [ -f /var/run/mm_terminate ]; do sleep 5; done"] + env_file: + - "../../e2e-tests/.ci/.env.cypress" + environment: + REPO: "mattermost" + # Cypress configuration + HEADLESS: "true" + CYPRESS_baseUrl: "http://localhost:8065" + CYPRESS_dbConnection: "postgres://mmuser:mostest@localhost:5432/mattermost_test?sslmode=disable&connect_timeout=10" + CYPRESS_smtpUrl: "http://localhost:9001" + CYPRESS_webhookBaseUrl: "http://localhost:3000" + CYPRESS_chromeWebSecurity: "false" + CYPRESS_firstTest: "true" + CYPRESS_resetBeforeTest: "true" + CYPRESS_allowedUntrustedInternalConnections: "localhost webhook-interactions" + TM4J_ENABLE: "false" + # disable shared memory X11 affecting Cypress v4 and Chrome + # https://github.com/cypress-io/cypress-docker-images/issues/270 + QT_X11_NO_MITSHM: "1" + _X11_NO_MITSHM: "1" + _MITSHM: "0" + # avoid too many progress messages + # https://github.com/cypress-io/cypress/issues/1243 + CI: "1" + # Ensure we are independent from the global node environment + PATH: /cypress/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + ulimits: + nofile: + soft: 8096 + hard: 1048576 + working_dir: /cypress + network_mode: host + volumes: + - "../../e2e-tests/cypress/:/cypress"' + fi) + +$(if mme2e_is_token_in_list "webhook-interactions" "$ENABLED_DOCKER_SERVICES"; then + # shellcheck disable=SC2016 + echo ' + webhook-interactions: + image: mattermostdevelopment/mirrored-node:${NODE_VERSION_REQUIRED} + command: sh -c "npm install --global --legacy-peer-deps && exec node webhook_serve.js" + healthcheck: + test: ["CMD", "curl", "-s", "-o/dev/null", "127.0.0.1:3000"] + interval: 10s + timeout: 15s + retries: 12 + working_dir: /cypress + network_mode: host + restart: on-failure + volumes: + - "../../e2e-tests/cypress/:/cypress:ro"' + fi) + +$(if mme2e_is_token_in_list "playwright" "$ENABLED_DOCKER_SERVICES"; then + echo ' + playwright: + image: mcr.microsoft.com/playwright:v1.38.1-jammy + entrypoint: ["/bin/bash", "-c"] + command: ["until [ -f /var/run/mm_terminate ]; do sleep 5; done"] + env_file: + - "./.env.playwright" + environment: + CI: "true" + NODE_OPTIONS: --no-experimental-fetch + PW_BASE_URL: http://localhost:8065 + PW_ADMIN_USERNAME: sysadmin + PW_ADMIN_PASSWORD: Sys@dmin-sample1 + PW_ADMIN_EMAIL: sysadmin@sample.mattermost.com + PW_ENSURE_PLUGINS_INSTALLED: "" + PW_HA_CLUSTER_ENABLED: "false" + PW_RESET_BEFORE_TEST: "false" + PW_HEADLESS: "true" + PW_SLOWMO: 0 + PW_WORKERS: 2 + PW_SNAPSHOT_ENABLE: "false" + PW_PERCY_ENABLE: "false" + ulimits: + nofile: + soft: 8096 + hard: 1048576 + working_dir: /mattermost + network_mode: host + volumes: + - "../../:/mattermost"' + fi) +EOL + + mme2e_log "docker-compose file generated." +} + +generate_env_files() { + # Generate .env.server + mme2e_log "Generating .env.server" + mme2e_generate_envfile_from_var_names >.env.server <<-EOF + MM_LICENSE + EOF + + # Setting SERVER-specific variables + case "$SERVER" in + cloud) + echo "MM_NOTIFY_ADMIN_COOL_OFF_DAYS=0.00000001" >>.env.server + echo 'MM_FEATUREFLAGS_ANNUALSUBSCRIPTION="true"' >>.env.server + # Load .env.cloud into .env.server + # We assume the file exist at this point. The actual check for that should be done before calling this function + cat >>.env.server <.env.cloud + ;; + esac + + # Setting MM_ENV-injected variables + # shellcheck disable=SC2086 + envarr=$(echo ${MM_ENV:-} | tr "," "\n") + for env in $envarr; do + echo "$env" >>.env.server + done + + # Generating TEST-specific env files + BRANCH_DEFAULT=$(git branch --show-current) + BUILD_ID_DEFAULT=$(date +%s) + export BRANCH=${BRANCH:-$BRANCH_DEFAULT} + export BUILD_ID=${BUILD_ID:-$BUILD_ID_DEFAULT} + export CI_BASE_URL="${CI_BASE_URL:-localhost}" + case "$TEST" in + cypress) + mme2e_log "Cypress: Generating .env.cypress" + mme2e_generate_envfile_from_var_names >.env.cypress <<-EOF + BRANCH + BUILD_ID + CI_BASE_URL + BROWSER + AUTOMATION_DASHBOARD_URL + AUTOMATION_DASHBOARD_TOKEN + EOF + # Adding service-specific cypress variables + for SERVICE in $ENABLED_DOCKER_SERVICES; do + case $SERVICE in + openldap) + echo "CYPRESS_ldapServer=localhost" >>.env.cypress + echo "CYPRESS_runLDAPSync=true" >>.env.cypress + ;; + minio) + echo "CYPRESS_minioS3Endpoint=localhost:9000" >>.env.cypress + ;; + keycloak) + echo "CYPRESS_keycloakBaseUrl=http://localhost:8484" >>.env.cypress + ;; + elasticsearch) + echo "CYPRESS_elasticsearchConnectionURL=http://localhost:9200" >>.env.cypress + ;; + esac + done + # Adding SERVER-specific cypress variables + case "$SERVER" in + cloud) + echo "CYPRESS_serverEdition=Cloud" >>.env.cypress + ;; + *) + echo "CYPRESS_serverEdition=E20" >>.env.cypress + ;; + esac + # If the dashboard is running, load .env.dashboard into .env.cypress + if DC_COMMAND="$MME2E_DC_DASHBOARD" mme2e_wait_service_healthy dashboard 1; then + mme2e_log "Detected a running automation dashboard: loading its access variables into the Cypress container" + cat >>.env.cypress <.env.dashboard + fi + ;; + playwright) + mme2e_log "Playwright: Generating .env.playwright" + mme2e_generate_envfile_from_var_names >.env.playwright <<-EOF + BRANCH + BUILD_ID + EOF + ;; + none) + mme2e_log "Requested TEST=$TEST. Skipping generation of test-specific env files." + ;; + esac +} + +# Perform SERVER-specific checks/customizations +case "$SERVER" in +cloud) + if ! [ -f .env.cloud ]; then + mme2e_log "Error: when using SERVER=$SERVER, the .env.cloud file is expected to exist, before generating the docker-compose file. Aborting." >&2 + exit 1 + fi + ;; +esac + +# Perform TEST-specific checks/customizations +case $TEST in +cypress) + enable_docker_service cypress + enable_docker_service webhook-interactions + ;; +playwright) + enable_docker_service playwright + ;; +esac + +mme2e_log "Generating docker-compose file using the following parameters..." +mme2e_log "TEST: ${TEST}" +mme2e_log "SERVER: ${SERVER}" +mme2e_log "ENABLED_DOCKER_SERVICES: ${ENABLED_DOCKER_SERVICES}" +assert_docker_services_validity "$ENABLED_DOCKER_SERVICES" +generate_docker_compose_file +generate_env_files diff --git a/e2e-tests/.ci/server.prepare.sh b/e2e-tests/.ci/server.prepare.sh index 03e9459adf..c984c46c27 100755 --- a/e2e-tests/.ci/server.prepare.sh +++ b/e2e-tests/.ci/server.prepare.sh @@ -2,33 +2,31 @@ set -e -u -o pipefail cd "$(dirname "$0")" . .e2erc -. .e2erc_setup -if [ "$TEST" != "cypress" ]; then - mme2e_log "Not applicable to TEST='$TEST'. For cypress only." - exit 0 +if [ "$TEST" = "cypress" ]; then + mme2e_log "Prepare Cypress: install dependencies" + ${MME2E_DC_SERVER} exec -T -u 0 -- cypress bash -c "id $MME2E_UID || useradd -u $MME2E_UID -m nodeci" # Works around the node image's assumption that the app files are owned by user 1000 + ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress npm i + ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress cypress install + mme2e_log "Prepare Cypress: populating fixtures" + ${MME2E_DC_SERVER} exec -T -- server curl -L --silent https://github.com/mattermost/mattermost-plugin-gitlab/releases/download/v1.3.0/com.github.manland.mattermost-plugin-gitlab-1.3.0.tar.gz | ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/com.github.manland.mattermost-plugin-gitlab-1.3.0.tar.gz >/dev/null + ${MME2E_DC_SERVER} exec -T -- server curl -L --silent https://github.com/mattermost/mattermost-plugin-demo/releases/download/v0.9.0/com.mattermost.demo-plugin-0.9.0.tar.gz | ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/com.mattermost.demo-plugin-0.9.0.tar.gz >/dev/null + ${MME2E_DC_SERVER} exec -T -- server curl -L --silent https://github.com/mattermost/mattermost-plugin-demo/releases/download/v0.8.0/com.mattermost.demo-plugin-0.8.0.tar.gz | ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/com.mattermost.demo-plugin-0.8.0.tar.gz >/dev/null + ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/keycloak.crt >/dev/null <../../server/build/docker/keycloak/keycloak.crt fi -# Install cypress dependencies -mme2e_log "Prepare Cypress: install dependencies" -${MME2E_DC_SERVER} exec -T -u 0 -- cypress bash -c "id $MME2E_UID || useradd -u $MME2E_UID -m nodeci" # Works around the node image's assumption that the app files are owned by user 1000 -${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress npm i -${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress cypress install - -# Populate cypress fixtures -mme2e_log "Prepare Cypress: populating fixtures" -${MME2E_DC_SERVER} exec -T -- server curl -L --silent https://github.com/mattermost/mattermost-plugin-gitlab/releases/download/v1.3.0/com.github.manland.mattermost-plugin-gitlab-1.3.0.tar.gz | ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/com.github.manland.mattermost-plugin-gitlab-1.3.0.tar.gz >/dev/null -${MME2E_DC_SERVER} exec -T -- server curl -L --silent https://github.com/mattermost/mattermost-plugin-demo/releases/download/v0.9.0/com.mattermost.demo-plugin-0.9.0.tar.gz | ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/com.mattermost.demo-plugin-0.9.0.tar.gz >/dev/null -${MME2E_DC_SERVER} exec -T -- server curl -L --silent https://github.com/mattermost/mattermost-plugin-demo/releases/download/v0.8.0/com.mattermost.demo-plugin-0.8.0.tar.gz | ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/com.mattermost.demo-plugin-0.8.0.tar.gz >/dev/null -${MME2E_DC_SERVER} exec -T -- server curl -L --silent https://github.com/mattermost/mattermost-plugin-demo/releases/download/v0.8.0/com.mattermost.demo-plugin-0.8.0.tar.gz | ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/com.mattermost.demo-plugin-0.8.0.tar.gz >/dev/null -${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- cypress tee tests/fixtures/keycloak.crt >/dev/null <../../server/build/docker/keycloak/keycloak.crt - -if [[ $ENABLED_DOCKER_SERVICES == *"openldap"* ]]; then - ${MME2E_DC_SERVER} exec -T -- openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest' <../../server/tests/test-data.ldif -fi - -if [[ $ENABLED_DOCKER_SERVICES == *"minio"* ]]; then - ${MME2E_DC_SERVER} exec -T -- minio sh -c 'mkdir -p /data/mattermost-test' -fi +# Run service-specific initialization steps +for SERVICE in $ENABLED_DOCKER_SERVICES; do + case "$SERVICE" in + openldap) + mme2e_log "Configuring the $SERVICE container" + ${MME2E_DC_SERVER} exec -T -- openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest' <../../server/tests/test-data.ldif + ;; + minio) + mme2e_log "Configuring the $SERVICE container" + ${MME2E_DC_SERVER} exec -T -- minio sh -c 'mkdir -p /data/mattermost-test' + ;; + esac +done mme2e_log "Mattermost is running and ready for E2E testing" diff --git a/e2e-tests/.ci/server.run_cypress.sh b/e2e-tests/.ci/server.run_cypress.sh index 3c5914dd85..115f2d6a24 100755 --- a/e2e-tests/.ci/server.run_cypress.sh +++ b/e2e-tests/.ci/server.run_cypress.sh @@ -2,7 +2,6 @@ set -e -u -o pipefail cd "$(dirname "$0")" . .e2erc -. .e2erc_setup # Set required variables TEST_FILTER_DEFAULT='--stage=@prod --group=@smoke' diff --git a/e2e-tests/.ci/server.run_playwright.sh b/e2e-tests/.ci/server.run_playwright.sh index a183b1b095..ef2406a461 100755 --- a/e2e-tests/.ci/server.run_playwright.sh +++ b/e2e-tests/.ci/server.run_playwright.sh @@ -2,7 +2,6 @@ set -e -u -o pipefail cd "$(dirname "$0")" . .e2erc -. .e2erc_setup # Initialize Playwright report directory mme2e_log "Prepare Playwright: clean and initialize report and logs directory" diff --git a/e2e-tests/.ci/server.run_test.sh b/e2e-tests/.ci/server.run_test.sh new file mode 100755 index 0000000000..a47c919aa3 --- /dev/null +++ b/e2e-tests/.ci/server.run_test.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e -u -o pipefail +cd "$(dirname "$0")" +. .e2erc + +case $TEST in +cypress) + ./server.run_cypress.sh + ;; +playwright) + ./server.run_playwright.sh + ;; +none) + mme2e_log "Running with TEST=$TEST. No tests to run." + exit 0 + ;; +*) + mme2e_log "Error, unsupported value for TEST: $TEST" >&2 + mme2e_log "Aborting" >&2 + exit 1 + ;; +esac diff --git a/e2e-tests/.ci/server.start.sh b/e2e-tests/.ci/server.start.sh index 57619d56d3..e1ab708935 100755 --- a/e2e-tests/.ci/server.start.sh +++ b/e2e-tests/.ci/server.start.sh @@ -2,89 +2,17 @@ set -e -u -o pipefail cd "$(dirname "$0")" . .e2erc -. .e2erc_setup - -if [ "$TEST" != "cypress" ] && [ "$TEST" != "playwright" ] && [ "$TEST" != "server" ]; then - mme2e_log "Invalid TEST='$TEST', expected: 'cypress', 'playwright' or 'server'" - exit 1 -fi BRANCH_DEFAULT=$(git branch --show-current) export BRANCH=${BRANCH:-$BRANCH_DEFAULT} BUILD_ID_DEFAULT=$(date +%s) export BUILD_ID=${BUILD_ID:-$BUILD_ID_DEFAULT} export CI_BASE_URL="${CI_BASE_URL:-localhost}" -export SITE_URL="${SITE_URL:-http://server:8065}" # Cleanup old containers, if any mme2e_log "Stopping leftover E2E containers, if any are running" ${MME2E_DC_SERVER} down -v --remove-orphans -# Generate .env.server -mme2e_log "Generating .env.server" -if [ "$SERVER" = "cloud" ]; then - export "MM_NOTIFY_ADMIN_COOL_OFF_DAYS=0.00000001" - export 'MM_FEATUREFLAGS_ANNUALSUBSCRIPTION="true"' -fi -mme2e_generate_envfile_from_var_names >.env.server <>.env.server -done - -if [ "$TEST" = "cypress" ]; then - # Generate .env.cypress - mme2e_log "Cypress: Generating .env.cypress" - mme2e_generate_envfile_from_var_names >.env.cypress <>.env.cypress - echo "CYPRESS_runLDAPSync=true" >>.env.cypress - fi - - if [[ $ENABLED_DOCKER_SERVICES == *"minio"* ]]; then - echo "CYPRESS_minioS3Endpoint=minio:9000" >>.env.cypress - fi - - if [[ $ENABLED_DOCKER_SERVICES == *"keycloak"* ]]; then - echo "CYPRESS_keycloakBaseUrl=http://keycloak:8484" >>.env.cypress - fi - - if [[ $ENABLED_DOCKER_SERVICES == *"elasticsearch"* ]]; then - echo "CYPRESS_elasticsearchConnectionURL=http://elasticsearch:9200" >>.env.cypress - fi - - if [ "$SERVER" = "cloud" ]; then - echo "CYPRESS_serverEdition=Cloud" >>.env.cypress - else - echo "CYPRESS_serverEdition=E20" >>.env.cypress - fi -elif [ "$TEST" = "playwright" ]; then - # Generate .env.playwright - mme2e_log "Playwright: Generating .env.playwright" - mme2e_generate_envfile_from_var_names >.env.playwright </dev/null 2>&1 && echo yes) - -# Install with https://webinstall.dev/shfmt/ -HAVE_SHFMT ?= $(shell command -v shfmt >/dev/null 2>&1 && echo yes) - -prettier: - # formats yaml files +.PHONY: fmt-node fmt-shell fmt +requirecmd-%: + @which "$(*)" >/dev/null || { echo "Error, missing required CLI tool: $(*). Aborting." >&2; exit 1; } +fmt-node: requirecmd-npx + # Formats yaml files npx prettier ./.ci "!./.ci/dashboard" --write --cache -fmt-ci: prettier -ifeq ($(HAVE_SHFMT),yes) - shfmt -w -s -i 2 ./.ci/*.sh -endif -ifeq ($(HAVE_SHELLCHECK),yes) - shellcheck ./.ci/*.sh ./.ci/.e2erc* -endif +fmt-shell: requirecmd-shfmt requirecmd-shellcheck + shfmt -w -s -i 2 ./.ci/*.sh # Install with https://webinstall.dev/shellcheck/ + shellcheck ./.ci/*.sh ./.ci/.e2erc* # Install with https://webinstall.dev/shfmt/ +fmt: fmt-node fmt-shell diff --git a/e2e-tests/README.md b/e2e-tests/README.md index 58405c3e15..c1db06e87f 100644 --- a/e2e-tests/README.md +++ b/e2e-tests/README.md @@ -16,42 +16,35 @@ Instructions, tl;dr: create a local branch with your E2E test changes, then open Instructions, detailed: 1. (optional, undefined variables are set to sane defaults) Create the `.ci/env` file, and populate it with the variables you need out of the following list: - * The following variables will be passed over to the server container: `MM_LICENSE` (no enterprise features will be available if this is unset), and the exploded `MM_ENV` (a comma-separated list of env var specifications) - * `TEST` either `cypress` (default) or `playwright`. - * `SERVER` either `self-hosted` (default) or `cloud`. - * The `ENABLED_DOCKER_SERVICES` is by default set to `postgres` and `inbucket` for smoke tests purpose, and for lightweight and faster start up time. Depending on the test requirement being worked on, you may want to override as needed, as such: - * Cypress full tests require full services with `postgres`, `inbucket`, `minio`, `openldap`, `elasticsearch` and `keycloak`. - * Cypress smoke tests require `postgres` and `inbucket` only. - * Playwright full tests require `postgres` and `inbucket` only. - * The following variables will be passed over to the cypress container: `BRANCH`, `BUILD_ID`, `CI_BASE_URL`, `BROWSER`, `AUTOMATION_DASHBOARD_URL` and `AUTOMATION_DASHBOARD_TOKEN` + * `SERVER`: either `self-hosted` (default) or `cloud`. + * `CWS_URL` (mandatory when `SERVER=cloud`, only used in such caase): when spinning up a cloud-like test server that communicates with a test instance of customer web server. + * `TEST`: either `cypress` (default), `playwright`, or `none` (to avoid creating the cypress/playwright sidecar containers, e.g. if you only want to launch a server instance) + * `ENABLED_DOCKER_SERVICES`: a space-separated list of services to start alongside the server. Default to `postgres inbucket`, for smoke tests purposes and for lightweight and faster start up time. Depending on the test requirement being worked on, you may want to override as needed, as such: + - Cypress full tests require all services to be running: `postgres inbucket minio openldap elasticsearch keycloak`. + - Cypress smoke tests require only the following: `postgres inbucket`. + - Playwright full tests require only the folliwing: `postgres inbucket`. + * The following variables, which will be passed over to the server container: `MM_LICENSE` (no enterprise features will be available if this is unset; required when `SERVER=cloud`), and the exploded `MM_ENV` (a comma-separated list of env var specifications) + * The following variables, which will be passed over to the cypress container: `BRANCH`, `BUILD_ID`, `CI_BASE_URL`, `BROWSER`, `AUTOMATION_DASHBOARD_URL` and `AUTOMATION_DASHBOARD_TOKEN` * The `SERVER_IMAGE` variable can also be set, if you want to select a custom mattermost-server image. If not specified, the value of the `SERVER_IMAGE_DEFAULT` variable defined in file `.ci/.e2erc` is used. * The `TEST_FILTER` variable can also be set, to customize which tests you want cypress to run. If not specified, only the smoke tests will run. Please check the `e2e-tests/cypress/run_tests.js` file for details about its format. - * Set `CWS_URL` when spinning up a cloud-like test server that communicates with a test instance of customer web server. 2. (optional) `make start-dashboard`: start the automation-dashboard in the background * This also sets the `AUTOMATION_DASHBOARD_URL` and `AUTOMATION_DASHBOARD_TOKEN` variables for the cypress container * Note that if you run the dashboard locally, but also specify other `AUTOMATION_DASHBOARD_*` variables in your `.ci/env` file, the latter variables will take precedence. * The dashboard is used for orchestrating specs with parallel test run and is typically used in CI. * Only Cypress is currently using the dashboard; Playwright is not. -3. Run the following commands to run with cypress: - * `TEST=cypress make`: start and prepare the server, then run the cypress tests against self-hosted test server. - * `TEST=cypress SERVER=cloud make`: create test customer for cloud, start and prepare the server, run the cypress tests against cloud-like test server, then delete the test customer. When anticipating a licensed test server, make sure the loaded license via `MM_LICENSE` is for cloud. - * When anticipating a licensed test server, make sure the loaded license via `MM_LICENSE` does match either for self-hosted or cloud. - * `CWS_URL` is required to be set for cloud test. - * You can track the progress of the run in the `http://localhost:4000/cycles` dashboard, if you launched it locally. -4. Run the following commands to run with playwright: - * `TEST=playwright make`: start and prepare the server, then run the playwright tests against self-hosted test server. - * `TEST=playwright SERVER=cloud `: generate test customer for cloud, start and prepare the server, run the playwright tests against cloud-like test server, then delete the initially generated test customer. - * When anticipating a licensed test server, make sure the loaded license via `MM_LICENSE` does match either for self-hosted or cloud. - * `CWS_URL` is required to be set for cloud test. -5. `TEST=server make`: starts local server. -6. `make stop`: tears down the server (and the dashboard, if running), then cleans up the env placeholder files. +3. `make`: start and prepare the server, then run the Cypress smoke tests + * You can track the progress of the run in the `http://localhost:4000/cycles` dashboard, if you launched it locally + * When running with `SERVER=cloud`, this will automatically create a cloud customer against the specified `CWS_URL` service, and delete that user after the run is complete. + * If you want to run the Playwright tests instead of the Cypress ones, you can run `TEST=playwright make` + * If you just want to run a local server instance, without any further testing, you can run `TEST=none make` +4. `make stop`: tears down the server (and the dashboard, if running) + * `make clean` will also remove any generated environment or docker-compose files, in addition to stopping the containers. Notes: - Setting a variable in `.ci/env` is functionally equivalent to exporting variables in your current shell's environment, before invoking the makefile. - The `.ci/.env.*` files are auto generated by the pipeline scripts, and aren't meant to be modified manually. The only file you should edit to control the containers' environment is `.ci/env`, as specified in the instructions above. -- Aside from some exceptions (e.g. `TEST_FILTER`), most of the variables in `.ci/env` must be set before the `make start-server` command is run. Modifying that file afterwards has no effect, because the containers' env files are generated in that step. +- Aside from some exceptions (e.g. `TEST_FILTER`), most of the variables in `.ci/env` must be set before the `make generate-server` command is run. Modifying that file afterwards has no effect, because the containers' env files are generated in that step. - If you restart the dashboard at any point, you must also restart the server containers, so that it picks up the new IP of the dashboard from the newly generated `.env.dashboard` file -- If you started the dashboard locally in the past, but want to point to another dashboard later, you can run `make clean-env-placeholders` to remove references to the local dashboard (you'll likely need to restart the server) - If new variables need to be passed to any of the containers: * If their value is fixed (e.g. a static server configuration), these may be simply added to the `docker_compose_generator.sh` file, to the appropriate container. * If you need to introduce variables that you want to control from `.ci/env`: you need to update the scripts under the `.ci/` dir, and configure them to write the new variables' values over to the appropriate `.env.*` file. In particular, avoid defining variables that depend on other variables within the docker-compose override files: this is to ensure uniformity in their availability, and simplifies the question of what container has access to which variable considerably. diff --git a/e2e-tests/cypress/package-lock.json b/e2e-tests/cypress/package-lock.json index ab15642afd..9d84617ce9 100644 --- a/e2e-tests/cypress/package-lock.json +++ b/e2e-tests/cypress/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "name": "cypress", "devDependencies": { "@babel/eslint-parser": "7.22.15", "@babel/eslint-plugin": "7.22.10", diff --git a/e2e-tests/cypress/package.json b/e2e-tests/cypress/package.json index bc832c21ae..5e77da8dc9 100644 --- a/e2e-tests/cypress/package.json +++ b/e2e-tests/cypress/package.json @@ -1,4 +1,5 @@ { + "name": "cypress", "devDependencies": { "@babel/eslint-parser": "7.22.15", "@babel/eslint-plugin": "7.22.10",