Skip to content

Commit

Permalink
Merge branch 'e2e-tests' into 'master'
Browse files Browse the repository at this point in the history
Add e2e Playwright tests to gitlab CI

See merge request kchat/webapp!783
  • Loading branch information
antonbuks committed Jul 3, 2024
2 parents d383427 + a8337a0 commit 5ab5853
Show file tree
Hide file tree
Showing 94 changed files with 10,191 additions and 4,926 deletions.
499 changes: 335 additions & 164 deletions .gitlab-ci.yml

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions .gitlab/e2e_report_notify.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
require 'net/http'
require 'uri'
require 'json'

CI_ACCESS_TOKEN = ENV['GITLAB_API_TOKEN']
CI_API_BASE = ENV['CI_API_V4_URL']
CI_MERGE_REQUEST_IID = ENV['CI_MERGE_REQUEST_IID']
CI_PAGES_PREFIX = ENV['PAGES_PREFIX']
CI_PAGES_URL = ENV['CI_PAGES_URL']
CI_PROJECT_ID = ENV['CI_PROJECT_ID']
GUILD_WEBHOOK_URL = ENV['GUILD_WEBHOOK_URL']

# Function to send a message to kChat
def send_to_kchat(msg)
uri = URI(GUILD_WEBHOOK_URL)
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')

message = <<-MESSAGE
#{msg}
MESSAGE
req.body = { text: message }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end

unless res.is_a?(Net::HTTPSuccess)
raise "HTTP Request to kChat failed: #{res.body}"
end
end

# Assert if an e2e report note has already been sent by the dev-bot
def has_e2e_report_note()
uri = URI("#{CI_API_BASE}/projects/#{CI_PROJECT_ID}/merge_requests/#{CI_MERGE_REQUEST_IID}/notes?per_page=1000")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')

request = Net::HTTP::Get.new(uri.request_uri, 'PRIVATE-TOKEN' => CI_ACCESS_TOKEN)
response = http.request(request)

unless response.is_a?(Net::HTTPSuccess)
raise "Failed to get notes from Merge Request IID #{merge_request_iid}: #{response.body}"
end

# Parse the notes
notes = JSON.parse(response.body)

# Find the note with the staging URL posted by dev_bot
report_note = notes.find do |note|
note['author']['username'] == 'dev_bot' && note['body'].include?("E2E report is now available at")
end

# Cast to boolean
return report_note ? true : false
end

# Notify about the new available pages url
def create_e2e_report_note(message)
uri = URI.parse("#{CI_API_BASE}/projects/#{CI_PROJECT_ID}/merge_requests/#{CI_MERGE_REQUEST_IID}/notes")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')

request = Net::HTTP::Post.new(uri.path, { 'PRIVATE-TOKEN' => CI_ACCESS_TOKEN })
request.set_form_data({ 'body' => message })

response = http.request(request)

unless response.is_a?(Net::HTTPSuccess)
raise "Failed to create note for Merge Request IID #{CI_MERGE_REQUEST_IID}: #{response.body}"
end
end

# Main execution flow
if !has_e2e_report_note()
message = "E2E report is now available at #{CI_PAGES_URL}/#{CI_PAGES_PREFIX}"
create_e2e_report_note(message)
send_to_kchat(message)
end
41 changes: 41 additions & 0 deletions .gitlab/get_staging_baseurl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'net/http'
require 'uri'
require 'json'

CI_API_BASE = ENV['CI_API_V4_URL']
CI_PROJECT_ID = ENV['CI_PROJECT_ID']
CI_ACCESS_TOKEN = ENV['GITLAB_API_TOKEN']
CI_MERGE_REQUEST_IID = ENV['CI_MERGE_REQUEST_IID']

# Function to parse the staging URL from the comments
def get_staging_url()
uri = URI("#{CI_API_BASE}/projects/#{CI_PROJECT_ID}/merge_requests/#{CI_MERGE_REQUEST_IID}/notes?per_page=1000")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')

request = Net::HTTP::Get.new(uri.request_uri, 'PRIVATE-TOKEN' => CI_ACCESS_TOKEN)
response = http.request(request)

unless response.is_a?(Net::HTTPSuccess)
raise "Failed to get notes from Merge Request IID #{CI_MERGE_REQUEST_IID}: #{response.body}"
end

# Parse the notes
notes = JSON.parse(response.body)

# Find the note with the staging URL posted by dev_bot
staging_note = notes.find do |note|
note['author']['username'] == 'dev_bot' && note['body'].include?("Staging is now available at")
end

# Extract the URL if the note is found, or return 'none'
if staging_note
match = staging_note['body'].match(/Staging is now available at (\S+)/)
match[1] if match
else
'none'
end
end

# Main execution flow
puts get_staging_url()
893 changes: 0 additions & 893 deletions .yarn/releases/yarn-4.0.1.cjs

This file was deleted.

894 changes: 894 additions & 0 deletions .yarn/releases/yarn-4.2.2.cjs

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
cacheFolder: .yarn/cache

compressionLevel: mixed

enableGlobalCache: false

nodeLinker: node-modules

npmScopes:
Expand All @@ -8,4 +12,4 @@ npmScopes:
npmAuthToken: "${NPM_TOKEN}"
npmRegistryServer: "https://npm.pkg.github.com"

yarnPath: .yarn/releases/yarn-4.0.1.cjs
yarnPath: .yarn/releases/yarn-4.2.2.cjs
78 changes: 42 additions & 36 deletions e2e-tests/.ci/.e2erc
Original file line number Diff line number Diff line change
@@ -1,37 +1,5 @@
# shellcheck disable=SC2148,SC2155

# 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 }}')
export NODE_VERSION_REQUIRED=$(cat ../../.nvmrc)

# Default values for optional variables
export SERVER_IMAGE_DEFAULT="mattermostdevelopment/mattermost-enterprise-edition:$(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"
export TEST_FILTER_DEFAULT='--stage=@prod --group=@smoke'
# OS specific defaults overrides
case $MME2E_OSTYPE in
darwin )
BROWSER_DEFAULT="electron" ;;
* )
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}
export TEST_FILTER=${TEST_FILTER:-$TEST_FILTER_DEFAULT}

# Function definitions
mme2e_log () { echo "[$(date +%Y-%m-%dT%H:%M:%S%Z)]" "$@"; }
mme2e_get_current_shopt_arg () {
Expand Down Expand Up @@ -98,10 +66,48 @@ mme2e_is_token_in_list() {
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
# Call prerequisite utility functions
mme2e_load_env_file

# 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 }}')
export NODE_VERSION_REQUIRED=$(cat ../../.nvmrc)

# Utility alias, for interactive shell usage. Can be reversed with 'unalias docker-compose-mmserver' in your shell
# NB: this only works in interactive shells
alias docker-compose-mmserver='${MME2E_DC_SERVER}'
alias docker-compose-mmdashboard='${MME2E_DC_DASHBOARD}'

# Call prerequisite utility functions
mme2e_load_env_file
# Default values for optional variables
export SERVER_IMAGE_DEFAULT="mattermostdevelopment/mattermost-enterprise-edition:$(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"
export TEST_FILTER_DEFAULT='--stage=@prod --group=@smoke'
export BRANCH_DEFAULT=$(git branch --show-current || echo -n "unknown")
export BUILD_ID_DEFAULT=$(date +%s)
# OS specific defaults overrides
case $MME2E_OSTYPE in
darwin )
BROWSER_DEFAULT="electron" ;;
* )
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}
export TEST_FILTER=${TEST_FILTER:-$TEST_FILTER_DEFAULT}
export BRANCH_UNSANITIZED=${BRANCH:-$BRANCH_DEFAULT}
export BRANCH=${BRANCH_UNSANITIZED::50} # The automation dashboard only accepts branch names up to 50 characters
export BUILD_ID_UNSANITIZED=${BUILD_ID:-$BUILD_ID_DEFAULT}
export BUILD_ID=${BUILD_ID_UNSANITIZED::64} # The automation dashboard only accepts build IDs up to 64 characters
6 changes: 6 additions & 0 deletions e2e-tests/.ci/dashboard.generate_test_cycle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ fi
set -a
. .env.cypress

if [ -z "${AUTOMATION_DASHBOARD_URL:-}" ]; then
mme2e_log "AUTOMATION_DASHBOARD_URL is unset. Skipping test cycle generation."
exit 0
fi

mme2e_log "Generating the test cycle on the Automation Dashboard"
cd ../cypress
npm i
# shellcheck disable=SC2086
exec node --trace-warnings generate_test_cycle.js $TEST_FILTER
2 changes: 1 addition & 1 deletion e2e-tests/.ci/dashboard.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: "3.1"

services:
dashboard:
image: mattermostdevelopment/mirrored-node:18.17
image: node:18.17
environment:
PG_URI: postgres://mmuser:mostest@db:5432/automation_dashboard_db
JWT_SECRET: s8gGBA3ujKRohSw1L8HLOY7Jjnu2ZYv8 # Generated with e.g. `dd if=/dev/urandom count=24 bs=1 2>/dev/null | base64 -w0`
Expand Down
65 changes: 65 additions & 0 deletions e2e-tests/.ci/report.publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/bash
# SC2034: <variable> appears unused.
# https://www.shellcheck.net/wiki/SC2034
# shellcheck disable=SC2034

set -e -u -o pipefail
cd "$(dirname "$0")"
. .e2erc

# Default required variables, assert that they are set, and document optional variables
: ${FULL_REPORT:=false} # Valid values: true, false
: ${TYPE:=NONE} # Valid values: PR, RELEASE, MASTER, MASTER_UNSTABLE, CLOUD, CLOUD_UNSTABLE, NONE (which is the same as omitting it)
: ${WEBHOOK_URL:-} # Optional. Mattermost webhook to post the report back to
: ${RELEASE_DATE:-} # Optional. If set, its value will be included in the report as the release date of the tested artifact

# Env vars used during the test. Their values will be included in the report
: ${BRANCH:?}
: ${BUILD_ID:?}
: ${MM_ENV:-}

# Populate intermediate variables
export BUILD_TAG="${SERVER_IMAGE##*/}"
export MM_DOCKER_IMAGE="${BUILD_TAG%%:*}" # NB: the 'mattermostdevelopment/' prefix is assumed
export MM_DOCKER_TAG="${BUILD_TAG##*:}"
export SERVER_TYPE="${SERVER}"
# NB: assume that BRANCH follows the convention 'server-pr-${PR_NUMBER}'. If multiple PRs match, the last one is used to generate the link
# Only needed if TYPE=PR
export PULL_REQUEST="https://github.com/mattermost/mattermost/pull/${BRANCH##*-}"

if [ -n "${TM4J_API_KEY:-}" ]; then
export TM4J_ENABLE=true
export JIRA_PROJECT_KEY=MM
export TM4J_ENVIRONMENT_NAME="${TEST}/${BROWSER}/${SERVER}"
case "${SERVER}" in
cloud)
export TM4J_FOLDER_ID="2014474" ;;
*)
export TM4J_FOLDER_ID="2014475" ;;
esac
: ${TEST_CYCLE_LINK_PREFIX:?}
: ${TM4J_CYCLE_KEY:-}
: ${TM4J_CYCLE_NAME:-}
mme2e_log "TMJ4 integration enabled."
fi

if [ -n "${DIAGNOSTIC_WEBHOOK_URL:-}" ]; then
: ${DIAGNOSTIC_USER_ID:?}
: ${DIAGNOSTIC_TEAM_ID:?}
mme2e_log "Diagnostic report upload enabled."
fi

if [ -n "${AWS_S3_BUCKET:-}" ]; then
: ${AWS_ACCESS_KEY_ID:?}
: ${AWS_SECRET_ACCESS_KEY:?}
mme2e_log "S3 report upload enabled."
fi

cd ../cypress/
if [ ! -d "results/" ]; then
mme2e_log "Error: 'results/' directory does not exist. Aborting report generation." >&2
exit 1
fi

npm i
node save_report.js
Loading

0 comments on commit 5ab5853

Please sign in to comment.