[CI] Collect coverage from frontend during integration tests (#1472)
This change will allow us to collect frontend code coverage from our Selenium based integration tests. Given that the frontend is embedded into the Go binary and the integration tests run with a compiled binary in Docker this poses some issues with the instrumented code and the ability for it to run in this manner. To fix this we need to relax Authelia's CSP for the integration tests. This is achieved by setting the env variable `ENVIRONMENT` to `dev`.pull/1473/head
parent
ec0af02aa3
commit
6db5455762
|
@ -10,16 +10,11 @@ if [[ $BUILDKITE_PULL_REQUEST != "false" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! $BUILDKITE_BRANCH =~ ^(v.*) ]] && [[ $BUILDKITE_COMMAND_EXIT_STATUS == 0 ]]; then
|
if [[ ! $BUILDKITE_BRANCH =~ ^(v.*) ]] && [[ $BUILDKITE_COMMAND_EXIT_STATUS == 0 ]]; then
|
||||||
if [[ $BUILDKITE_LABEL == ":hammer_and_wrench: Unit Test" ]]; then
|
if [[ $BUILDKITE_LABEL == ":hammer_and_wrench: Unit Test" ]] || [[ $BUILDKITE_LABEL =~ ":selenium:" ]]; then
|
||||||
echo "--- :codecov: Upload coverage reports"
|
echo "--- :codecov: Upload coverage reports"
|
||||||
bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -f "coverage.txt" -F backend
|
bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -f "coverage.txt" -F backend
|
||||||
bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -F frontend
|
bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -F frontend
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $BUILDKITE_LABEL =~ ":selenium:" ]]; then
|
|
||||||
echo "--- :codecov: Upload coverage reports"
|
|
||||||
bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -f "coverage.txt" -F backend
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $BUILDKITE_LABEL =~ ":selenium:" ]] || [[ $BUILDKITE_LABEL =~ ":docker: Build Image" ]]; then
|
if [[ $BUILDKITE_LABEL =~ ":selenium:" ]] || [[ $BUILDKITE_LABEL =~ ":docker: Build Image" ]]; then
|
||||||
|
|
|
@ -7,7 +7,7 @@ WORKDIR /node/src/app
|
||||||
COPY web .
|
COPY web .
|
||||||
|
|
||||||
# Install the dependencies and build
|
# Install the dependencies and build
|
||||||
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn build
|
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn coverage
|
||||||
|
|
||||||
# =======================================
|
# =======================================
|
||||||
# ===== Build image for the backend =====
|
# ===== Build image for the backend =====
|
||||||
|
|
|
@ -138,6 +138,21 @@ func runSuiteSetupTeardown(command string, suite string) error {
|
||||||
|
|
||||||
s := suites.GlobalRegistry.Get(selectedSuite)
|
s := suites.GlobalRegistry.Get(selectedSuite)
|
||||||
|
|
||||||
|
if command == "teardown" {
|
||||||
|
if _, err := os.Stat("../../web/.nyc_output"); err == nil {
|
||||||
|
log.Infof("Generating frontend coverage reports for suite %s...", suite)
|
||||||
|
|
||||||
|
cmd := utils.Command("yarn", "report")
|
||||||
|
cmd.Dir = "web"
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd := utils.CommandWithStdout("go", "run", "cmd/authelia-suites/main.go", command, selectedSuite)
|
cmd := utils.CommandWithStdout("go", "run", "cmd/authelia-suites/main.go", command, selectedSuite)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
const dev = "dev"
|
|
@ -3,6 +3,7 @@ package server
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
@ -36,7 +37,12 @@ func ServeIndex(publicDir, base, rememberMe, resetPassword string) fasthttp.Requ
|
||||||
nonce := utils.RandomString(32, alphaNumericRunes)
|
nonce := utils.RandomString(32, alphaNumericRunes)
|
||||||
|
|
||||||
ctx.SetContentType("text/html; charset=utf-8")
|
ctx.SetContentType("text/html; charset=utf-8")
|
||||||
|
|
||||||
|
if os.Getenv("ENVIRONMENT") == dev {
|
||||||
|
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
|
||||||
|
} else {
|
||||||
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
|
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
|
||||||
|
}
|
||||||
|
|
||||||
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ Base, CSPNonce, RememberMe, ResetPassword string }{Base: base, CSPNonce: nonce, RememberMe: rememberMe, ResetPassword: resetPassword})
|
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ Base, CSPNonce, RememberMe, ResetPassword string }{Base: base, CSPNonce: nonce, RememberMe: rememberMe, ResetPassword: resetPassword})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -99,7 +99,7 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi
|
||||||
// Configure DUO api endpoint only if configuration exists.
|
// Configure DUO api endpoint only if configuration exists.
|
||||||
if configuration.DuoAPI != nil {
|
if configuration.DuoAPI != nil {
|
||||||
var duoAPI duo.API
|
var duoAPI duo.API
|
||||||
if os.Getenv("ENVIRONMENT") == "dev" {
|
if os.Getenv("ENVIRONMENT") == dev {
|
||||||
duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi(
|
duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi(
|
||||||
configuration.DuoAPI.IntegrationKey,
|
configuration.DuoAPI.IntegrationKey,
|
||||||
configuration.DuoAPI.SecretKey,
|
configuration.DuoAPI.SecretKey,
|
||||||
|
|
|
@ -24,6 +24,7 @@ authentication_backend:
|
||||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||||
group_name_attribute: cn
|
group_name_attribute: cn
|
||||||
mail_attribute: mail
|
mail_attribute: mail
|
||||||
|
display_name_attribute: displayName
|
||||||
user: cn=admin,dc=example,dc=com
|
user: cn=admin,dc=example,dc=com
|
||||||
password: password
|
password: password
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ authentication_backend:
|
||||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||||
group_name_attribute: cn
|
group_name_attribute: cn
|
||||||
mail_attribute: mail
|
mail_attribute: mail
|
||||||
|
display_name_attribute: displayName
|
||||||
user: cn=admin,dc=example,dc=com
|
user: cn=admin,dc=example,dc=com
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
|
|
|
@ -40,6 +40,8 @@ spec:
|
||||||
value: /app/secrets/session
|
value: /app/secrets/session
|
||||||
- name: AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE
|
- name: AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE
|
||||||
value: /app/secrets/sql_password
|
value: /app/secrets/sql_password
|
||||||
|
- name: ENVIRONMENT
|
||||||
|
value: dev
|
||||||
volumes:
|
volumes:
|
||||||
- name: config-volume
|
- name: config-volume
|
||||||
configMap:
|
configMap:
|
||||||
|
|
|
@ -2,12 +2,15 @@ package suites
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/tebeka/selenium"
|
"github.com/tebeka/selenium"
|
||||||
|
@ -82,8 +85,31 @@ func StartWebDriver() (*WebDriverSession, error) {
|
||||||
|
|
||||||
// Stop stop the selenium session.
|
// Stop stop the selenium session.
|
||||||
func (wds *WebDriverSession) Stop() error {
|
func (wds *WebDriverSession) Stop() error {
|
||||||
err := wds.WebDriver.Quit()
|
var coverage map[string]interface{}
|
||||||
|
|
||||||
|
coverageDir := "../../web/.nyc_output"
|
||||||
|
time := time.Now()
|
||||||
|
|
||||||
|
resp, err := wds.WebDriver.ExecuteScriptRaw("return JSON.stringify(window.__coverage__)", nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resp, &coverage)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
coverageData := fmt.Sprintf("%s", coverage["value"])
|
||||||
|
|
||||||
|
_ = os.MkdirAll(coverageDir, 0775)
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(fmt.Sprintf("%s/coverage-%d.json", coverageDir, time.Unix()), []byte(coverageData), 0664) //nolint:gosec
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = wds.WebDriver.Quit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
babel: {
|
||||||
|
plugins: [ "babel-plugin-istanbul" ]
|
||||||
|
}
|
||||||
|
};
|
|
@ -3,6 +3,7 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@craco/craco": "^5.8.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.15.1",
|
"@fortawesome/free-regular-svg-icons": "^5.15.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.1",
|
"@fortawesome/free-solid-svg-icons": "^5.15.1",
|
||||||
|
@ -40,9 +41,11 @@
|
||||||
"u2f-api": "^1.1.1"
|
"u2f-api": "^1.1.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "craco start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
|
"coverage": "craco build",
|
||||||
"test": "react-scripts test --coverage --no-cache",
|
"test": "react-scripts test --coverage --no-cache",
|
||||||
|
"report": "nyc report -r clover -r json -r lcov -r text",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
|
|
|
@ -1159,6 +1159,15 @@
|
||||||
exec-sh "^0.3.2"
|
exec-sh "^0.3.2"
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
|
|
||||||
|
"@craco/craco@^5.8.0":
|
||||||
|
version "5.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@craco/craco/-/craco-5.8.0.tgz#2a0f551290a5eab353b615de4d7093dd83785777"
|
||||||
|
integrity sha512-4rhusETLD7rJ195GxOK9VmVdv/VD4jawFxc9hcQ9TrZ3/9ny+qwc0uW+08qu9GYwEF9Eb9meSeSvpWjaqdDr1Q==
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^7.0.0"
|
||||||
|
lodash "^4.17.15"
|
||||||
|
webpack-merge "^4.2.2"
|
||||||
|
|
||||||
"@csstools/convert-colors@^1.4.0":
|
"@csstools/convert-colors@^1.4.0":
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
|
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
|
||||||
|
@ -11979,6 +11988,13 @@ webpack-manifest-plugin@2.2.0:
|
||||||
object.entries "^1.1.0"
|
object.entries "^1.1.0"
|
||||||
tapable "^1.0.0"
|
tapable "^1.0.0"
|
||||||
|
|
||||||
|
webpack-merge@^4.2.2:
|
||||||
|
version "4.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d"
|
||||||
|
integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.17.15"
|
||||||
|
|
||||||
webpack-sources@^1.1.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
|
webpack-sources@^1.1.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
|
||||||
version "1.4.3"
|
version "1.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
||||||
|
|
Loading…
Reference in New Issue