From 272b66574a52195419e9bc8a663e809cc5a26cb7 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Mon, 20 May 2024 19:53:41 +0100 Subject: [PATCH 1/7] :white_check_mark: Add bats tests --- tests/test_expand_pg_ldap_sync.bats | 180 ++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 tests/test_expand_pg_ldap_sync.bats diff --git a/tests/test_expand_pg_ldap_sync.bats b/tests/test_expand_pg_ldap_sync.bats new file mode 100644 index 0000000..2921150 --- /dev/null +++ b/tests/test_expand_pg_ldap_sync.bats @@ -0,0 +1,180 @@ +# bats file_tags=ruby:expand_pg_ldap_sync + +setup() { + touch test_output.yaml + # get the containing directory of this file using $BATS_TEST_FILENAME + # instead of ${BASH_SOURCE[0]} or $0, as those will point to the bats + # executable's location or the preprocessed file respectively + TEST_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")" >/dev/null 2>&1 && pwd)" +} + + +check_success() { + if (( status )); then + echo $output + return 1 + fi +} + +check_failure() { + if (( ! status )); then + echo $output + return 1 + fi +} + +test_expansion() { + rm test_output.yaml + ${TEST_DIR}/../scripts/expand_pg_ldap_sync.rb > test_output.yaml + grep "$1" test_output.yaml && return + echo "Failed to find '$1' in expanded output" + cat test_output.yaml + return 1 +} + +@test "Test setting LDAP_BIND_DN" { + export LDAP_BIND_DN="CN=user,DC=example,DC=com" + run test_expansion 'username: "CN=user,DC=example,DC=com"' + export -n LDAP_BIND_DN + check_success +} + +@test "Test setting LDAP_BIND_PASSWORD only" { + export LDAP_BIND_PASSWORD="!a#b$c" + run test_expansion 'password: "!a#b$c"' + export -n LDAP_BIND_PASSWORD + check_failure +} + +@test "Test setting LDAP_BIND_PASSWORD with LDAP_BIND_DN" { + export LDAP_BIND_DN="CN=user,DC=example,DC=com" + export LDAP_BIND_PASSWORD="!a#b%c" + run test_expansion 'password: "!a#b%c"' + export -n LDAP_BIND_DN LDAP_BIND_PASSWORD + check_success +} + +@test "Test setting LDAP_GROUP_BASE_DN" { + export LDAP_GROUP_BASE_DN="OU=groups,DC=example,DC=com" + run test_expansion 'base: "OU=groups,DC=example,DC=com"' + export -n LDAP_GROUP_BASE_DN + check_success +} + +@test "Test setting LDAP_GROUP_FILTER" { + export LDAP_GROUP_FILTER="(objectClass=posixGroup)" + run test_expansion 'filter: "(objectClass=posixGroup)"' + export -n LDAP_GROUP_FILTER + check_success +} + +@test "Test setting LDAP_GROUP_NAME_ATTR" { + export LDAP_GROUP_NAME_ATTR="samAccountName" + run test_expansion 'name_attribute: "samAccountName"' + export -n LDAP_GROUP_NAME_ATTR + check_success +} + +@test "Test default LDAP_GROUP_NAME_ATTR" { + export -n LDAP_GROUP_NAME_ATTR + run test_expansion 'name_attribute: "cn"' + check_success +} + +@test "Test setting LDAP_HOST" { + export LDAP_HOST="ldap.example.com" + run test_expansion 'host: "ldap.example.com"' + export -n LDAP_HOST + check_success +} + +@test "Test setting LDAP_PORT" { + export LDAP_PORT="1234" + run test_expansion 'port: "1234"' + export -n LDAP_PORT + check_success +} + +@test "Test default LDAP_PORT" { + export -n LDAP_PORT + run test_expansion 'port: "389"' + check_success +} + +@test "Test setting LDAP_USER_BASE_DN" { + export LDAP_USER_BASE_DN="OU=users,DC=example,DC=com" + run test_expansion 'base: "OU=users,DC=example,DC=com"' + export -n LDAP_USER_BASE_DN + check_success +} + +@test "Test setting LDAP_USER_FILTER" { + export LDAP_USER_FILTER="(objectClass=posixAccount)" + run test_expansion 'filter: "(objectClass=posixAccount)"' + export -n LDAP_USER_FILTER + check_success +} + +@test "Test setting LDAP_USER_NAME_ATTR" { + export LDAP_USER_NAME_ATTR="samAccountName" + run test_expansion 'name_attribute: "samAccountName"' + export -n LDAP_USER_NAME_ATTR + check_success +} + +@test "Test default LDAP_USER_NAME_ATTR" { + export -n LDAP_USER_NAME_ATTR + run test_expansion 'name_attribute: "userPrincipalName"' + check_success +} + +@test "Test setting POSTGRESQL_DB_NAME" { + export POSTGRESQL_DB_NAME="db-names" + run test_expansion 'dbname: "db-names"' + export -n POSTGRESQL_DB_NAME + check_success +} + +@test "Test default POSTGRESQL_DB_NAME" { + export -n POSTGRESQL_DB_NAME + run test_expansion 'dbname: "guacamole"' + check_success +} + +@test "Test setting POSTGRESQL_HOST" { + export POSTGRESQL_HOST="postgresql.example.com" + run test_expansion 'host: "postgresql.example.com"' + export -n POSTGRESQL_HOST + check_success +} + +@test "Test setting POSTGRESQL_PASSWORD" { + export POSTGRESQL_PASSWORD="!a#b%c" + run test_expansion 'password: "!a#b%c"' + export -n POSTGRESQL_PASSWORD + check_success +} + +@test "Test setting POSTGRESQL_PORT" { + export POSTGRESQL_PORT="1234" + run test_expansion 'port: "1234"' + export -n POSTGRESQL_PORT + check_success +} + +@test "Test default POSTGRESQL_PORT" { + export -n POSTGRESQL_PORT + run test_expansion 'port: "5432"' + check_success +} + +@test "Test setting POSTGRESQL_USERNAME" { + export POSTGRESQL_USERNAME="psqladmin" + run test_expansion 'user: "psqladmin"' + export -n POSTGRESQL_USERNAME + check_success +} + +teardown() { + rm test_output.yaml +} \ No newline at end of file From 8a54af99aefb8d15b4c2b0290779ee1d9c28abd1 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Mon, 20 May 2024 19:55:44 +0100 Subject: [PATCH 2/7] :construction_worker: Add bats tests --- .github/workflows/test_code.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/test_code.yaml diff --git a/.github/workflows/test_code.yaml b/.github/workflows/test_code.yaml new file mode 100644 index 0000000..7749c0a --- /dev/null +++ b/.github/workflows/test_code.yaml @@ -0,0 +1,25 @@ +--- +name: Test code + +# Run workflow on PRs and pushes to matching branches +on: # yamllint disable-line rule:truthy + push: + branches: [main] + pull_request: + +jobs: + test_bash: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install bats + run: sudo apt-get update && sudo apt-get install bats + - name: Install ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.4 + - name: Install ruby dependencies + run: gem install mustache + - name: Run tests + run: bats tests From 395c16c7b04167f37eeeb27ebf27683dc48fc7b5 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 11:29:49 +0100 Subject: [PATCH 3/7] :sparkles: Added utility functions in a common file --- tests/common.bash | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/common.bash diff --git a/tests/common.bash b/tests/common.bash new file mode 100644 index 0000000..834c5e2 --- /dev/null +++ b/tests/common.bash @@ -0,0 +1,48 @@ +#! /usr/bin/env bats + +common_setup() { + # Use $BATS_TEST_FILENAME to get the containing directory of this file + # instead of ${BASH_SOURCE[0]}, which points to the bats executable, or + # $0, which points to the preprocessed file. + + # shellcheck disable=SC2034 + TEST_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")" >/dev/null 2>&1 && pwd)" +} + +assert_output() { + # This is a light version of the function with the same name in `bats-assert` + is_mode_partial=0 + while (($# > 0)); do + case "$1" in + -p | --partial) + is_mode_partial=1 + shift + ;; + --) + shift + break + ;; + *) break ;; + esac + done + + expected=$1 + if ((is_mode_partial)); then + # shellcheck disable=SC2154 + if [[ $output != *"$expected"* ]]; then + echo "-- output does not contain substring --" + echo "substring $expected" + echo "output $output" + echo "--" + return 1 + fi + else + if [[ $output != *"$expected"* ]]; then + echo "-- output differs --" + echo "expected $expected" + echo "actual $output" + echo "--" + return 1 + fi + fi +} From 7a6a2c5afb947ac231e7bfd594c711b17419a90a Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 11:30:10 +0100 Subject: [PATCH 4/7] :recycle: Updated expand_pg_ldap_sync tests to use assert_output --- tests/test_expand_pg_ldap_sync.bats | 126 +++++++++++----------------- 1 file changed, 51 insertions(+), 75 deletions(-) diff --git a/tests/test_expand_pg_ldap_sync.bats b/tests/test_expand_pg_ldap_sync.bats index 2921150..efb8d43 100644 --- a/tests/test_expand_pg_ldap_sync.bats +++ b/tests/test_expand_pg_ldap_sync.bats @@ -1,180 +1,156 @@ +#! /usr/bin/env bats # bats file_tags=ruby:expand_pg_ldap_sync setup() { - touch test_output.yaml - # get the containing directory of this file using $BATS_TEST_FILENAME - # instead of ${BASH_SOURCE[0]} or $0, as those will point to the bats - # executable's location or the preprocessed file respectively - TEST_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")" >/dev/null 2>&1 && pwd)" + load 'common' + common_setup } - -check_success() { - if (( status )); then - echo $output - return 1 - fi -} - -check_failure() { - if (( ! status )); then - echo $output - return 1 - fi -} - -test_expansion() { - rm test_output.yaml - ${TEST_DIR}/../scripts/expand_pg_ldap_sync.rb > test_output.yaml - grep "$1" test_output.yaml && return - echo "Failed to find '$1' in expanded output" - cat test_output.yaml - return 1 +query_pg_ldap_sync() { + query_string="$1" + ${TEST_DIR}/../scripts/expand_pg_ldap_sync.rb | yq eval "$query_string" } @test "Test setting LDAP_BIND_DN" { export LDAP_BIND_DN="CN=user,DC=example,DC=com" - run test_expansion 'username: "CN=user,DC=example,DC=com"' + run query_pg_ldap_sync ".ldap_connection.auth.username" export -n LDAP_BIND_DN - check_success + assert_output "CN=user,DC=example,DC=com" } @test "Test setting LDAP_BIND_PASSWORD only" { - export LDAP_BIND_PASSWORD="!a#b$c" - run test_expansion 'password: "!a#b$c"' + export LDAP_BIND_PASSWORD="!a#b%c" + run query_pg_ldap_sync ".ldap_connection.auth.password" export -n LDAP_BIND_PASSWORD - check_failure + assert_output null } @test "Test setting LDAP_BIND_PASSWORD with LDAP_BIND_DN" { export LDAP_BIND_DN="CN=user,DC=example,DC=com" export LDAP_BIND_PASSWORD="!a#b%c" - run test_expansion 'password: "!a#b%c"' + run query_pg_ldap_sync ".ldap_connection.auth.password" export -n LDAP_BIND_DN LDAP_BIND_PASSWORD - check_success + assert_output "!a#b%c" } @test "Test setting LDAP_GROUP_BASE_DN" { export LDAP_GROUP_BASE_DN="OU=groups,DC=example,DC=com" - run test_expansion 'base: "OU=groups,DC=example,DC=com"' + run query_pg_ldap_sync ".ldap_groups.base" export -n LDAP_GROUP_BASE_DN - check_success + assert_output "OU=groups,DC=example,DC=com" } @test "Test setting LDAP_GROUP_FILTER" { export LDAP_GROUP_FILTER="(objectClass=posixGroup)" - run test_expansion 'filter: "(objectClass=posixGroup)"' + run query_pg_ldap_sync ".ldap_groups.filter" export -n LDAP_GROUP_FILTER - check_success + assert_output "(objectClass=posixGroup)" } @test "Test setting LDAP_GROUP_NAME_ATTR" { export LDAP_GROUP_NAME_ATTR="samAccountName" - run test_expansion 'name_attribute: "samAccountName"' + run query_pg_ldap_sync ".ldap_groups.name_attribute" export -n LDAP_GROUP_NAME_ATTR - check_success + assert_output "samAccountName" } @test "Test default LDAP_GROUP_NAME_ATTR" { export -n LDAP_GROUP_NAME_ATTR - run test_expansion 'name_attribute: "cn"' - check_success + run query_pg_ldap_sync ".ldap_groups.name_attribute" + assert_output "cn" } @test "Test setting LDAP_HOST" { export LDAP_HOST="ldap.example.com" - run test_expansion 'host: "ldap.example.com"' + run query_pg_ldap_sync ".ldap_connection.host" export -n LDAP_HOST - check_success + assert_output "ldap.example.com" } @test "Test setting LDAP_PORT" { export LDAP_PORT="1234" - run test_expansion 'port: "1234"' + run query_pg_ldap_sync ".ldap_connection.port" export -n LDAP_PORT - check_success + assert_output "1234" } @test "Test default LDAP_PORT" { export -n LDAP_PORT - run test_expansion 'port: "389"' - check_success + run query_pg_ldap_sync ".ldap_connection.port" + assert_output "389" } @test "Test setting LDAP_USER_BASE_DN" { export LDAP_USER_BASE_DN="OU=users,DC=example,DC=com" - run test_expansion 'base: "OU=users,DC=example,DC=com"' + run query_pg_ldap_sync ".ldap_users.base" export -n LDAP_USER_BASE_DN - check_success + assert_output "OU=users,DC=example,DC=com" } @test "Test setting LDAP_USER_FILTER" { export LDAP_USER_FILTER="(objectClass=posixAccount)" - run test_expansion 'filter: "(objectClass=posixAccount)"' + run query_pg_ldap_sync ".ldap_users.filter" export -n LDAP_USER_FILTER - check_success + assert_output "(objectClass=posixAccount)" } @test "Test setting LDAP_USER_NAME_ATTR" { export LDAP_USER_NAME_ATTR="samAccountName" - run test_expansion 'name_attribute: "samAccountName"' + run query_pg_ldap_sync ".ldap_users.name_attribute" export -n LDAP_USER_NAME_ATTR - check_success + assert_output "samAccountName" } @test "Test default LDAP_USER_NAME_ATTR" { export -n LDAP_USER_NAME_ATTR - run test_expansion 'name_attribute: "userPrincipalName"' - check_success + run query_pg_ldap_sync ".ldap_users.name_attribute" + assert_output "userPrincipalName" } @test "Test setting POSTGRESQL_DB_NAME" { - export POSTGRESQL_DB_NAME="db-names" - run test_expansion 'dbname: "db-names"' + export POSTGRESQL_DB_NAME="custom-db-name" + run query_pg_ldap_sync ".pg_connection.dbname" export -n POSTGRESQL_DB_NAME - check_success + assert_output "custom-db-name" } @test "Test default POSTGRESQL_DB_NAME" { export -n POSTGRESQL_DB_NAME - run test_expansion 'dbname: "guacamole"' - check_success + run query_pg_ldap_sync ".pg_connection.dbname" + export -n POSTGRESQL_DB_NAME + assert_output "guacamole" } @test "Test setting POSTGRESQL_HOST" { export POSTGRESQL_HOST="postgresql.example.com" - run test_expansion 'host: "postgresql.example.com"' + run query_pg_ldap_sync ".pg_connection.host" export -n POSTGRESQL_HOST - check_success + assert_output "postgresql.example.com" } @test "Test setting POSTGRESQL_PASSWORD" { export POSTGRESQL_PASSWORD="!a#b%c" - run test_expansion 'password: "!a#b%c"' + run query_pg_ldap_sync ".pg_connection.password" export -n POSTGRESQL_PASSWORD - check_success + assert_output "!a#b%c" } @test "Test setting POSTGRESQL_PORT" { export POSTGRESQL_PORT="1234" - run test_expansion 'port: "1234"' + run query_pg_ldap_sync ".pg_connection.port" export -n POSTGRESQL_PORT - check_success + assert_output "1234" } @test "Test default POSTGRESQL_PORT" { export -n POSTGRESQL_PORT - run test_expansion 'port: "5432"' - check_success + run query_pg_ldap_sync ".pg_connection.port" + assert_output "5432" } @test "Test setting POSTGRESQL_USERNAME" { export POSTGRESQL_USERNAME="psqladmin" - run test_expansion 'user: "psqladmin"' + run query_pg_ldap_sync ".pg_connection.user" export -n POSTGRESQL_USERNAME - check_success + assert_output "psqladmin" } - -teardown() { - rm test_output.yaml -} \ No newline at end of file From 9d94255f49c6489f05a069cdb503dbf3153f4739 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 11:30:25 +0100 Subject: [PATCH 5/7] :sparkles: Added tests for expand_psql --- tests/test_expand_psql.bats | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/test_expand_psql.bats diff --git a/tests/test_expand_psql.bats b/tests/test_expand_psql.bats new file mode 100644 index 0000000..0b1649a --- /dev/null +++ b/tests/test_expand_psql.bats @@ -0,0 +1,46 @@ +#! /usr/bin/env bats +# bats file_tags=ruby:expand_psql + +setup() { + load 'common' + common_setup +} + +expand_psql() { + ${TEST_DIR}/../scripts/expand_psql.rb +} + +@test "Test setting POSTGRESQL_PASSWORD" { + export POSTGRESQL_PASSWORD="!a#b%c" + run expand_psql + export -n POSTGRESQL_PASSWORD + assert_output --partial "PGPASSWORD='!a#b%c'" +} + +@test "Test setting POSTGRESQL_HOST" { + export POSTGRESQL_HOST="postgresql.example.com" + run expand_psql + export -n POSTGRESQL_HOST + assert_output --partial "-h 'postgresql.example.com'" +} + +@test "Test setting POSTGRESQL_PORT" { + export POSTGRESQL_PORT="1234" + run expand_psql + export -n POSTGRESQL_PORT + assert_output --partial "-p '1234'" +} + +@test "Test setting POSTGRESQL_DB_NAME" { + export POSTGRESQL_DB_NAME="custom-db-name" + run expand_psql + export -n POSTGRESQL_DB_NAME + assert_output --partial "-d 'custom-db-name'" +} + +@test "Test setting POSTGRESQL_USERNAME" { + export POSTGRESQL_USERNAME="postgresqladmin" + run expand_psql + export -n POSTGRESQL_USERNAME + assert_output --partial "-U 'postgresqladmin'" +} From c4ca9e1e523f3665474711f5fba3edf258827e0f Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 11:30:46 +0100 Subject: [PATCH 6/7] :memo: Added instructions for running tests --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 79ea828..079312c 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,16 @@ Synchronise a Guacamole PostgreSQL database with an LDAP server, such as Microso - POSTGRESQL_PORT: PostgreSQL server port (default: '5432') - POSTGRESQL_USERNAME: Username of PostgreSQL user - REPEAT_INTERVAL: How often (in seconds) to wait before attempting to synchronise again (default: '300') + +## Tests + +To run the tests you will need to install + +- `bats-core` +- `yq` + +The tests can be run with: + +```console +$ bats tests +``` From 26fe396ea6b833fccf5085e8e985cac16453353e Mon Sep 17 00:00:00 2001 From: James Robinson Date: Tue, 21 May 2024 11:32:33 +0100 Subject: [PATCH 7/7] :sparkles: Added yq installation to GitHub Actions workflow --- .github/workflows/test_code.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test_code.yaml b/.github/workflows/test_code.yaml index 7749c0a..541c3a1 100644 --- a/.github/workflows/test_code.yaml +++ b/.github/workflows/test_code.yaml @@ -21,5 +21,10 @@ jobs: ruby-version: 3.4 - name: Install ruby dependencies run: gem install mustache + - name: Install yq + run: | + VERSION=v4.44.1 + BINARY=yq_linux_amd64 + wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -O - | tar xz && sudo mv ${BINARY} /usr/bin/yq - name: Run tests run: bats tests