From 6bcbc21dac99675778bee19694746997ea43205a Mon Sep 17 00:00:00 2001 From: Lucian Behind The Scenes Date: Sun, 9 Aug 2026 13:29:27 +0300 Subject: [PATCH 1/3] docs: remove deployerphp.com references and document docs site usage The deployerphp.com domain is being retired. Point readers at the docs folder and the loadinglucian/deployerphp.com repo for a local docs site. --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d51c972..4b40f74 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- + DeployerPHP Logo

@@ -10,10 +10,6 @@ License

-

- https://deployerphp.com -

- # Meet DeployerPHP This is DeployerPHP, a complete set of CLI tools for provisioning, installing, and deploying servers and sites using PHP. It serves as an open-source alternative to services such as Ploi, RunCloud or Laravel Forge. @@ -28,6 +24,7 @@ Here it is in action: - [Crash Course](#crash-course) +- [Documentation](#documentation) - [Benefits](#benefits) - [Unlimited Servers & Sites](#unlimited-servers--sites) - [No Vendor Lock-In](#no-vendor-lock-in) @@ -84,6 +81,14 @@ deployer site:deploy deployer site:https ``` + + +## Documentation + +The full documentation lives in the [docs](/docs) folder of this repository. + +To browse it as a beautiful documentation website, clone the [deployerphp.com](https://github.com/loadinglucian/deployerphp.com) repository and run it locally — it renders the documentation from this package. See its README for setup instructions. + ## Benefits From a3c2d86d7b71a74d8b860ff312c6879e98d460d6 Mon Sep 17 00:00:00 2001 From: Lucian Behind The Scenes Date: Sun, 9 Aug 2026 13:29:27 +0300 Subject: [PATCH 2/3] test: comment out cloud provider bats tests The AWS, DigitalOcean, and Cloudflare test accounts and domains have been spun down; these tests cannot run without live credentials. --- tests/bats/cloud-aws.bats | 1811 +++++++++++++++++++------------------ tests/bats/cloud-do.bats | 1683 +++++++++++++++++----------------- 2 files changed, 1752 insertions(+), 1742 deletions(-) diff --git a/tests/bats/cloud-aws.bats b/tests/bats/cloud-aws.bats index 0d8fcdb..5fa7aac 100644 --- a/tests/bats/cloud-aws.bats +++ b/tests/bats/cloud-aws.bats @@ -1,906 +1,911 @@ #!/usr/bin/env bats -# AWS Integration Tests -# Tests: AWS key/provision/DNS + site lifecycle commands +# NOTE: These tests are disabled because the cloud provider accounts +# (AWS, DigitalOcean, Cloudflare) and test domains they depend on have +# been spun down. Uncomment the lines below to re-enable them once +# active credentials are available again. # -# Prerequisites: -# - AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION in environment -# - Valid AWS credentials with EC2 permissions -# - SSH private key at ~/.ssh/id_ed25519 - -load 'lib/helpers' -load 'lib/cloud-helpers' - -# ---- -# Setup/Teardown -# ---- - -setup_file() { - require_aws_credentials - require_cf_credentials - require_aws_dns_prefix_config - require_cf_dns_prefix_config - cloud_note "Run suffix: ${BATS_RUN_SUFFIX}" - aws_cleanup_all - cf_cleanup_all -} - -teardown_file() { - if ! aws_credentials_available; then - return 0 - fi - aws_cleanup_all - cf_cleanup_all - rm -f "$TEST_INVENTORY" -} - -setup() { - cloud_check_failed - require_aws_credentials -} - -teardown() { - cloud_mark_failed -} - -# ---- -# aws:key:add -# ---- - -@test "aws:key:add uploads public key to AWS" { - run_deployer aws:key:add \ - --name="$AWS_TEST_KEY_NAME" \ - --public-key-path="$CLOUD_TEST_KEY_PATH" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Key pair imported successfully" - assert_output_contains "Name: $AWS_TEST_KEY_NAME" - assert_command_replay "aws:key:add" -} - -# ---- -# aws:key:list -# ---- - -@test "aws:key:list shows uploaded key" { - run_deployer aws:key:list - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "$AWS_TEST_KEY_NAME" - assert_command_replay "aws:key:list" -} - -# ---- -# aws:key:delete -# ---- - -@test "aws:key:delete removes key from AWS" { - run_deployer aws:key:delete \ - --key="$AWS_TEST_KEY_NAME" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Key pair deleted successfully" - assert_command_replay "aws:key:delete" -} - -@test "aws:key:list confirms key deleted" { - run_deployer aws:key:list - - debug_output - - [ "$status" -eq 0 ] - assert_output_not_contains "$AWS_TEST_KEY_NAME" -} - -# ---- -# aws:provision -# ---- - -@test "aws:provision creates EC2 instance and adds to inventory" { - require_aws_provision_config - - # Cleanup any leftover test server - aws_cleanup_test_server - - run_deployer aws:provision \ - --name="$AWS_TEST_SERVER_NAME" \ - --instance-type="$AWS_TEST_INSTANCE_TYPE" \ - --image="$AWS_TEST_IMAGE" \ - --key-pair="$AWS_TEST_KEY_PAIR" \ - --private-key-path="$AWS_TEST_PRIVATE_KEY_PATH" \ - --vpc="$AWS_TEST_VPC" \ - --subnet="$AWS_TEST_SUBNET" \ - --disk-size="$AWS_TEST_DISK_SIZE" \ - --no-monitoring - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Instance provisioned" - assert_output_contains "Instance is running" - assert_output_contains "Elastic IP allocated" - assert_output_contains "Server added to inventory" - assert_command_replay "aws:provision" - - # Tag contract for janitor discovery - aws_assert_instance_tag_contract "$AWS_TEST_SERVER_NAME" - aws_assert_eip_tag_contract "$AWS_TEST_SERVER_NAME" - aws_assert_root_volume_tag_contract "$AWS_TEST_SERVER_NAME" -} - -@test "server:install configures AWS provisioned server" { - require_aws_provision_config - - local primary_php_version secondary_php_version installed_php_versions - primary_php_version="$CLOUD_TEST_PHP_PRIMARY_VERSION" - secondary_php_version="$CLOUD_TEST_PHP_SECONDARY_VERSION" - - # Full install takes time - use longer timeout - run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ - --server="$AWS_TEST_SERVER_NAME" \ - --generate-deploy-key \ - --timezone="UTC" \ - --php-version="$primary_php_version" \ - --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Server installation completed" - assert_output_contains "public key" - assert_command_replay "server:install" - - # Install secondary PHP-FPM version on the same server (keep primary as default) - run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ - --server="$AWS_TEST_SERVER_NAME" \ - --generate-deploy-key \ - --timezone="UTC" \ - --php-version="$secondary_php_version" \ - --no-php-default \ - --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Server installation completed" - assert_command_replay "server:install" - - installed_php_versions="$(get_installed_php_fpm_versions_for_server "$AWS_TEST_SERVER_NAME")" - printf '%s\n' "$installed_php_versions" | grep -qx "$primary_php_version" - printf '%s\n' "$installed_php_versions" | grep -qx "$secondary_php_version" -} - -# ---- -# site:create -# ---- - -@test "site:create creates site ${AWS_TEST_SITE_DOMAIN} on AWS provisioned server" { - require_aws_provision_config - - # Cleanup any leftover test site - cleanup_test_site "$AWS_TEST_SITE_DOMAIN" - - run_deployer site:create \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --server="$AWS_TEST_SERVER_NAME" \ - --php-version="$CLOUD_TEST_PHP_PRIMARY_VERSION" \ - --web-root="/" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "site:create" -} - -@test "site:create creates secondary site ${AWS_TEST_SITE_DOMAIN_SECONDARY} on AWS provisioned server" { - require_aws_provision_config - - # Cleanup any leftover secondary test site - cleanup_test_site "$AWS_TEST_SITE_DOMAIN_SECONDARY" - - run_deployer site:create \ - --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ - --server="$AWS_TEST_SERVER_NAME" \ - --php-version="$CLOUD_TEST_PHP_SECONDARY_VERSION" \ - --web-root="/" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "site:create" -} - -# ---- -# aws:dns:set -# ---- - -@test "aws:dns:set creates prefixed A record for ${AWS_TEST_DNS_ROOT_FQDN}" { - require_aws_provision_config - - # Get server IP from inventory - local server_ip - server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer aws:dns:set \ - --zone="$AWS_TEST_HOSTED_ZONE" \ - --type="A" \ - --name="$AWS_TEST_DNS_ROOT" \ - --value="$server_ip" \ - --ttl="60" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record upserted successfully" - assert_command_replay "aws:dns:set" -} - -@test "aws:dns:set creates secondary prefixed A record for ${AWS_TEST_DNS_ROOT_SECONDARY_FQDN}" { - require_aws_provision_config - - local server_ip - server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer aws:dns:set \ - --zone="$AWS_TEST_HOSTED_ZONE" \ - --type="A" \ - --name="$AWS_TEST_DNS_ROOT_SECONDARY" \ - --value="$server_ip" \ - --ttl="60" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record upserted successfully" - assert_command_replay "aws:dns:set" -} - -@test "aws:dns:list shows ${AWS_TEST_DNS_ROOT_FQDN} and ${AWS_TEST_DNS_ROOT_SECONDARY_FQDN}" { - require_aws_provision_config - - run_deployer aws:dns:list \ - --zone="$AWS_TEST_HOSTED_ZONE" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "$AWS_TEST_HOSTED_ZONE" - assert_output_contains "$AWS_TEST_DNS_ROOT_FQDN" - assert_output_contains "$AWS_TEST_DNS_ROOT_SECONDARY_FQDN" - assert_command_replay "aws:dns:list" -} - -# ---- -# cf:dns:set -# ---- - -@test "cf:dns:set creates prefixed A record for ${CF_TEST_DNS_ROOT_FQDN} (non-proxied)" { - require_aws_provision_config - - # Get server IP from inventory - local server_ip - server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer cf:dns:set \ - --zone="$CF_TEST_DOMAIN" \ - --type="A" \ - --name="$CF_TEST_DNS_ROOT" \ - --value="$server_ip" \ - --ttl="60" \ - --no-proxied - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record" - assert_output_contains "successfully" - assert_command_replay "cf:dns:set" -} - -@test "cf:dns:list shows ${CF_TEST_DNS_ROOT_FQDN}" { - require_aws_provision_config - - run_deployer cf:dns:list \ - --zone="$CF_TEST_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "$CF_TEST_DOMAIN" - assert_command_replay "cf:dns:list" -} - -# ---- -# site:dns:check -# ---- - -@test "site:dns:check resolves DNS for ${AWS_TEST_SITE_DOMAIN}" { - require_aws_provision_config - - local server_ip - server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer site:dns:check \ - --domain="$AWS_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "Check DNS" - assert_output_contains "Domain: $AWS_TEST_SITE_DOMAIN" - assert_output_contains "A:" - assert_output_contains "AAAA:" - assert_output_contains "$server_ip" - assert_command_replay "site:dns:check" -} - -@test "site:dns:check resolves DNS for ${AWS_TEST_SITE_DOMAIN_SECONDARY}" { - require_aws_provision_config - - local server_ip - server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer site:dns:check \ - --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "Check DNS" - assert_output_contains "Domain: $AWS_TEST_SITE_DOMAIN_SECONDARY" - assert_output_contains "A:" - assert_output_contains "AAAA:" - assert_output_contains "$server_ip" - assert_command_replay "site:dns:check" -} - -# ---- -# site:shared:push -# ---- - -@test "site:shared:push uploads .env to AWS site" { - require_aws_provision_config - - run_deployer site:shared:push \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ - --remote=".env" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Shared file uploaded" - assert_command_replay "site:shared:push" -} - -@test "site:shared:push uploads .env to AWS secondary site" { - require_aws_provision_config - - run_deployer site:shared:push \ - --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ - --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ - --remote=".env" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Shared file uploaded" - assert_command_replay "site:shared:push" -} - -# ---- -# site:shared:list -# ---- - -@test "site:shared:list shows uploaded shared files for AWS site" { - require_aws_provision_config - - run_deployer site:shared:list \ - --domain="$AWS_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains ".env" - assert_command_replay "site:shared:list" -} - -# ---- -# site:shared:pull -# ---- - -@test "site:shared:pull downloads .env from AWS site" { - require_aws_provision_config - - local pulled_env="${BATS_TEST_TMPDIR}/aws-shared.env" - - run_deployer site:shared:pull \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --remote=".env" \ - --local="$pulled_env" \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Shared file downloaded" - assert_command_replay "site:shared:pull" - [[ -f "$pulled_env" ]] - - run grep -q "APP_MESSAGE=$CLOUD_TEST_APP_MESSAGE" "$pulled_env" - [ "$status" -eq 0 ] -} - -# ---- -# site:deploy -# ---- - -@test "site:deploy deploys application to AWS site" { - require_aws_provision_config - - # Deploy takes time - use longer timeout - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --repo="$CLOUD_TEST_DEPLOY_REPO" \ - --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Deployment completed" - assert_command_replay "site:deploy" -} - -@test "site:deploy deploys application to AWS secondary site" { - require_aws_provision_config - - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ - --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ - --repo="$CLOUD_TEST_DEPLOY_REPO" \ - --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Deployment completed" - assert_command_replay "site:deploy" -} - -# ---- -# cron/supervisor -# ---- - -@test "cron:create adds hello.sh cron for AWS site" { - require_aws_provision_config - - run_deployer cron:create \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ - --schedule="* * * * *" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "cron:create" -} - -@test "cron:sync applies hello.sh cron to AWS server" { - require_aws_provision_config - - run_deployer cron:sync \ - --domain="$AWS_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "synced to server" - assert_command_replay "cron:sync" -} - -@test "cron:sync writes AWS crontab entry and log file for hello.sh" { - require_aws_provision_config - - run_deployer server:run \ - --server="$AWS_TEST_SERVER_NAME" \ - --command="sudo -n crontab -l -u deployer | grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" - - run_deployer server:run \ - --server="$AWS_TEST_SERVER_NAME" \ - --command="test -f /var/log/cron/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT.log && echo cron-log-found" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "cron-log-found" -} - -@test "supervisor:create adds hello.sh program for AWS site" { - require_aws_provision_config - - run_deployer supervisor:create \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ - --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ - --no-autostart \ - --no-autorestart \ - --stopwaitsecs="10" \ - --numprocs="1" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "supervisor:create" -} - -@test "supervisor:sync applies hello.sh program to AWS server" { - require_aws_provision_config - - run_deployer supervisor:sync \ - --domain="$AWS_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "synced to server" - assert_command_replay "supervisor:sync" -} - -@test "supervisor:sync writes AWS supervisor config for hello.sh" { - require_aws_provision_config - - run_deployer server:run \ - --server="$AWS_TEST_SERVER_NAME" \ - --command="test -f /etc/supervisor/conf.d/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT' /etc/supervisor/conf.d/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && echo supervisor-config-found" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "supervisor-config-found" -} - -@test "supervisor lifecycle commands restart/stop/start work on AWS server" { - require_aws_provision_config - - run_deployer supervisor:restart \ - --server="$AWS_TEST_SERVER_NAME" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:restart" - - run_deployer supervisor:stop \ - --server="$AWS_TEST_SERVER_NAME" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:stop" - - run_deployer supervisor:start \ - --server="$AWS_TEST_SERVER_NAME" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:start" -} - -@test "cron:delete removes hello.sh cron for AWS site" { - require_aws_provision_config - - run_deployer cron:delete \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "cron:delete" -} - -@test "cron:sync removes hello.sh crontab entry from AWS server" { - require_aws_provision_config - - run_deployer cron:sync \ - --domain="$AWS_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "cron:sync" - - run_deployer server:run \ - --server="$AWS_TEST_SERVER_NAME" \ - --command="if sudo -n crontab -l -u deployer 2>/dev/null | grep -Fq 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'; then echo cron-entry-present; exit 1; else echo cron-entry-absent; fi" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "cron-entry-absent" -} - -@test "supervisor:delete removes hello.sh program for AWS site" { - require_aws_provision_config - - run_deployer supervisor:delete \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "supervisor:delete" -} - -@test "supervisor:sync removes hello.sh supervisor config from AWS server" { - require_aws_provision_config - - run_deployer supervisor:sync \ - --domain="$AWS_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:sync" - - run_deployer server:run \ - --server="$AWS_TEST_SERVER_NAME" \ - --command="if test -f /etc/supervisor/conf.d/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf; then echo supervisor-config-present; exit 1; else echo supervisor-config-absent; fi" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "supervisor-config-absent" -} - -# ---- -# site:https -# ---- - -@test "site:https enables HTTPS for ${AWS_TEST_SITE_DOMAIN}" { - require_aws_provision_config - - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ - --domain="$AWS_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "HTTPS enabled successfully" - assert_command_replay "site:https" -} - -@test "site:https enables HTTPS for ${AWS_TEST_SITE_DOMAIN_SECONDARY}" { - require_aws_provision_config - - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ - --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "HTTPS enabled successfully" - assert_command_replay "site:https" -} - -# ---- -# HTTP Verification -# ---- - -@test "deployed AWS site responds to HTTP requests after HTTPS setup" { - require_aws_provision_config - - # Verify app response after HTTPS setup. - wait_for_http "$AWS_TEST_SITE_DOMAIN" "$CLOUD_TEST_APP_MESSAGE" 30 -} - -@test "deployed AWS secondary site responds to HTTP requests after HTTPS setup" { - require_aws_provision_config - - wait_for_http "$AWS_TEST_SITE_DOMAIN_SECONDARY" "$CLOUD_TEST_APP_MESSAGE" 30 -} - -# ---- -# site:rollback -# ---- - -@test "site:rollback shows forward-only deployment guidance" { - require_aws_provision_config - - run_deployer site:rollback - - debug_output - - [ "$status" -eq 0 ] - assert_info_output - assert_output_contains "Forward-only deployments" - assert_bullet_output -} - -# ---- -# site:delete -# ---- - -@test "site:delete removes ${AWS_TEST_SITE_DOMAIN_SECONDARY} from server and inventory" { - require_aws_provision_config - - run_deployer site:delete \ - --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "site:delete" -} - -@test "site:delete removes ${AWS_TEST_SITE_DOMAIN} from server and inventory" { - require_aws_provision_config - - run_deployer site:delete \ - --domain="$AWS_TEST_SITE_DOMAIN" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "site:delete" -} - -# ---- -# cf:dns:delete -# ---- - -@test "cf:dns:delete removes prefixed A record ${CF_TEST_DNS_ROOT_FQDN}" { - require_aws_provision_config - - run_deployer cf:dns:delete \ - --zone="$CF_TEST_DOMAIN" \ - --type="A" \ - --name="$CF_TEST_DNS_ROOT" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record deleted successfully" - assert_command_replay "cf:dns:delete" -} - -# ---- -# aws:dns:delete -# ---- - -@test "aws:dns:delete removes prefixed A record ${AWS_TEST_DNS_ROOT_SECONDARY_FQDN}" { - require_aws_provision_config - - run_deployer aws:dns:delete \ - --zone="$AWS_TEST_HOSTED_ZONE" \ - --type="A" \ - --name="$AWS_TEST_DNS_ROOT_SECONDARY" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record deleted successfully" - assert_command_replay "aws:dns:delete" -} - -@test "aws:dns:delete removes prefixed A record ${AWS_TEST_DNS_ROOT_FQDN}" { - require_aws_provision_config - - run_deployer aws:dns:delete \ - --zone="$AWS_TEST_HOSTED_ZONE" \ - --type="A" \ - --name="$AWS_TEST_DNS_ROOT" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record deleted successfully" - assert_command_replay "aws:dns:delete" -} - -# ---- -# Cleanup -# ---- - -@test "server:delete removes AWS instance and cleans up resources" { - require_aws_provision_config - - run_deployer server:delete \ - --server="$AWS_TEST_SERVER_NAME" \ - --force \ - --yes \ - --destroy-cloud - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Instance terminated" - assert_output_contains "Elastic IP released" - assert_output_contains "removed from inventory" - assert_command_replay "server:delete" - aws_assert_no_bats_volumes "$BATS_RUN_SUFFIX" -} +# # AWS Integration Tests +# # Tests: AWS key/provision/DNS + site lifecycle commands +# # +# # Prerequisites: +# # - AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION in environment +# # - Valid AWS credentials with EC2 permissions +# # - SSH private key at ~/.ssh/id_ed25519 +# +# load 'lib/helpers' +# load 'lib/cloud-helpers' +# +# # ---- +# # Setup/Teardown +# # ---- +# +# setup_file() { +# require_aws_credentials +# require_cf_credentials +# require_aws_dns_prefix_config +# require_cf_dns_prefix_config +# cloud_note "Run suffix: ${BATS_RUN_SUFFIX}" +# aws_cleanup_all +# cf_cleanup_all +# } +# +# teardown_file() { +# if ! aws_credentials_available; then +# return 0 +# fi +# aws_cleanup_all +# cf_cleanup_all +# rm -f "$TEST_INVENTORY" +# } +# +# setup() { +# cloud_check_failed +# require_aws_credentials +# } +# +# teardown() { +# cloud_mark_failed +# } +# +# # ---- +# # aws:key:add +# # ---- +# +# @test "aws:key:add uploads public key to AWS" { +# run_deployer aws:key:add \ +# --name="$AWS_TEST_KEY_NAME" \ +# --public-key-path="$CLOUD_TEST_KEY_PATH" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Key pair imported successfully" +# assert_output_contains "Name: $AWS_TEST_KEY_NAME" +# assert_command_replay "aws:key:add" +# } +# +# # ---- +# # aws:key:list +# # ---- +# +# @test "aws:key:list shows uploaded key" { +# run_deployer aws:key:list +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "$AWS_TEST_KEY_NAME" +# assert_command_replay "aws:key:list" +# } +# +# # ---- +# # aws:key:delete +# # ---- +# +# @test "aws:key:delete removes key from AWS" { +# run_deployer aws:key:delete \ +# --key="$AWS_TEST_KEY_NAME" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Key pair deleted successfully" +# assert_command_replay "aws:key:delete" +# } +# +# @test "aws:key:list confirms key deleted" { +# run_deployer aws:key:list +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_not_contains "$AWS_TEST_KEY_NAME" +# } +# +# # ---- +# # aws:provision +# # ---- +# +# @test "aws:provision creates EC2 instance and adds to inventory" { +# require_aws_provision_config +# +# # Cleanup any leftover test server +# aws_cleanup_test_server +# +# run_deployer aws:provision \ +# --name="$AWS_TEST_SERVER_NAME" \ +# --instance-type="$AWS_TEST_INSTANCE_TYPE" \ +# --image="$AWS_TEST_IMAGE" \ +# --key-pair="$AWS_TEST_KEY_PAIR" \ +# --private-key-path="$AWS_TEST_PRIVATE_KEY_PATH" \ +# --vpc="$AWS_TEST_VPC" \ +# --subnet="$AWS_TEST_SUBNET" \ +# --disk-size="$AWS_TEST_DISK_SIZE" \ +# --no-monitoring +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Instance provisioned" +# assert_output_contains "Instance is running" +# assert_output_contains "Elastic IP allocated" +# assert_output_contains "Server added to inventory" +# assert_command_replay "aws:provision" +# +# # Tag contract for janitor discovery +# aws_assert_instance_tag_contract "$AWS_TEST_SERVER_NAME" +# aws_assert_eip_tag_contract "$AWS_TEST_SERVER_NAME" +# aws_assert_root_volume_tag_contract "$AWS_TEST_SERVER_NAME" +# } +# +# @test "server:install configures AWS provisioned server" { +# require_aws_provision_config +# +# local primary_php_version secondary_php_version installed_php_versions +# primary_php_version="$CLOUD_TEST_PHP_PRIMARY_VERSION" +# secondary_php_version="$CLOUD_TEST_PHP_SECONDARY_VERSION" +# +# # Full install takes time - use longer timeout +# run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --generate-deploy-key \ +# --timezone="UTC" \ +# --php-version="$primary_php_version" \ +# --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Server installation completed" +# assert_output_contains "public key" +# assert_command_replay "server:install" +# +# # Install secondary PHP-FPM version on the same server (keep primary as default) +# run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --generate-deploy-key \ +# --timezone="UTC" \ +# --php-version="$secondary_php_version" \ +# --no-php-default \ +# --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Server installation completed" +# assert_command_replay "server:install" +# +# installed_php_versions="$(get_installed_php_fpm_versions_for_server "$AWS_TEST_SERVER_NAME")" +# printf '%s\n' "$installed_php_versions" | grep -qx "$primary_php_version" +# printf '%s\n' "$installed_php_versions" | grep -qx "$secondary_php_version" +# } +# +# # ---- +# # site:create +# # ---- +# +# @test "site:create creates site ${AWS_TEST_SITE_DOMAIN} on AWS provisioned server" { +# require_aws_provision_config +# +# # Cleanup any leftover test site +# cleanup_test_site "$AWS_TEST_SITE_DOMAIN" +# +# run_deployer site:create \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --php-version="$CLOUD_TEST_PHP_PRIMARY_VERSION" \ +# --web-root="/" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "site:create" +# } +# +# @test "site:create creates secondary site ${AWS_TEST_SITE_DOMAIN_SECONDARY} on AWS provisioned server" { +# require_aws_provision_config +# +# # Cleanup any leftover secondary test site +# cleanup_test_site "$AWS_TEST_SITE_DOMAIN_SECONDARY" +# +# run_deployer site:create \ +# --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --php-version="$CLOUD_TEST_PHP_SECONDARY_VERSION" \ +# --web-root="/" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "site:create" +# } +# +# # ---- +# # aws:dns:set +# # ---- +# +# @test "aws:dns:set creates prefixed A record for ${AWS_TEST_DNS_ROOT_FQDN}" { +# require_aws_provision_config +# +# # Get server IP from inventory +# local server_ip +# server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer aws:dns:set \ +# --zone="$AWS_TEST_HOSTED_ZONE" \ +# --type="A" \ +# --name="$AWS_TEST_DNS_ROOT" \ +# --value="$server_ip" \ +# --ttl="60" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record upserted successfully" +# assert_command_replay "aws:dns:set" +# } +# +# @test "aws:dns:set creates secondary prefixed A record for ${AWS_TEST_DNS_ROOT_SECONDARY_FQDN}" { +# require_aws_provision_config +# +# local server_ip +# server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer aws:dns:set \ +# --zone="$AWS_TEST_HOSTED_ZONE" \ +# --type="A" \ +# --name="$AWS_TEST_DNS_ROOT_SECONDARY" \ +# --value="$server_ip" \ +# --ttl="60" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record upserted successfully" +# assert_command_replay "aws:dns:set" +# } +# +# @test "aws:dns:list shows ${AWS_TEST_DNS_ROOT_FQDN} and ${AWS_TEST_DNS_ROOT_SECONDARY_FQDN}" { +# require_aws_provision_config +# +# run_deployer aws:dns:list \ +# --zone="$AWS_TEST_HOSTED_ZONE" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "$AWS_TEST_HOSTED_ZONE" +# assert_output_contains "$AWS_TEST_DNS_ROOT_FQDN" +# assert_output_contains "$AWS_TEST_DNS_ROOT_SECONDARY_FQDN" +# assert_command_replay "aws:dns:list" +# } +# +# # ---- +# # cf:dns:set +# # ---- +# +# @test "cf:dns:set creates prefixed A record for ${CF_TEST_DNS_ROOT_FQDN} (non-proxied)" { +# require_aws_provision_config +# +# # Get server IP from inventory +# local server_ip +# server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer cf:dns:set \ +# --zone="$CF_TEST_DOMAIN" \ +# --type="A" \ +# --name="$CF_TEST_DNS_ROOT" \ +# --value="$server_ip" \ +# --ttl="60" \ +# --no-proxied +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record" +# assert_output_contains "successfully" +# assert_command_replay "cf:dns:set" +# } +# +# @test "cf:dns:list shows ${CF_TEST_DNS_ROOT_FQDN}" { +# require_aws_provision_config +# +# run_deployer cf:dns:list \ +# --zone="$CF_TEST_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "$CF_TEST_DOMAIN" +# assert_command_replay "cf:dns:list" +# } +# +# # ---- +# # site:dns:check +# # ---- +# +# @test "site:dns:check resolves DNS for ${AWS_TEST_SITE_DOMAIN}" { +# require_aws_provision_config +# +# local server_ip +# server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer site:dns:check \ +# --domain="$AWS_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "Check DNS" +# assert_output_contains "Domain: $AWS_TEST_SITE_DOMAIN" +# assert_output_contains "A:" +# assert_output_contains "AAAA:" +# assert_output_contains "$server_ip" +# assert_command_replay "site:dns:check" +# } +# +# @test "site:dns:check resolves DNS for ${AWS_TEST_SITE_DOMAIN_SECONDARY}" { +# require_aws_provision_config +# +# local server_ip +# server_ip=$(get_server_ip "$AWS_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer site:dns:check \ +# --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "Check DNS" +# assert_output_contains "Domain: $AWS_TEST_SITE_DOMAIN_SECONDARY" +# assert_output_contains "A:" +# assert_output_contains "AAAA:" +# assert_output_contains "$server_ip" +# assert_command_replay "site:dns:check" +# } +# +# # ---- +# # site:shared:push +# # ---- +# +# @test "site:shared:push uploads .env to AWS site" { +# require_aws_provision_config +# +# run_deployer site:shared:push \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ +# --remote=".env" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Shared file uploaded" +# assert_command_replay "site:shared:push" +# } +# +# @test "site:shared:push uploads .env to AWS secondary site" { +# require_aws_provision_config +# +# run_deployer site:shared:push \ +# --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ +# --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ +# --remote=".env" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Shared file uploaded" +# assert_command_replay "site:shared:push" +# } +# +# # ---- +# # site:shared:list +# # ---- +# +# @test "site:shared:list shows uploaded shared files for AWS site" { +# require_aws_provision_config +# +# run_deployer site:shared:list \ +# --domain="$AWS_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains ".env" +# assert_command_replay "site:shared:list" +# } +# +# # ---- +# # site:shared:pull +# # ---- +# +# @test "site:shared:pull downloads .env from AWS site" { +# require_aws_provision_config +# +# local pulled_env="${BATS_TEST_TMPDIR}/aws-shared.env" +# +# run_deployer site:shared:pull \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --remote=".env" \ +# --local="$pulled_env" \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Shared file downloaded" +# assert_command_replay "site:shared:pull" +# [[ -f "$pulled_env" ]] +# +# run grep -q "APP_MESSAGE=$CLOUD_TEST_APP_MESSAGE" "$pulled_env" +# [ "$status" -eq 0 ] +# } +# +# # ---- +# # site:deploy +# # ---- +# +# @test "site:deploy deploys application to AWS site" { +# require_aws_provision_config +# +# # Deploy takes time - use longer timeout +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --repo="$CLOUD_TEST_DEPLOY_REPO" \ +# --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Deployment completed" +# assert_command_replay "site:deploy" +# } +# +# @test "site:deploy deploys application to AWS secondary site" { +# require_aws_provision_config +# +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ +# --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ +# --repo="$CLOUD_TEST_DEPLOY_REPO" \ +# --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Deployment completed" +# assert_command_replay "site:deploy" +# } +# +# # ---- +# # cron/supervisor +# # ---- +# +# @test "cron:create adds hello.sh cron for AWS site" { +# require_aws_provision_config +# +# run_deployer cron:create \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ +# --schedule="* * * * *" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "cron:create" +# } +# +# @test "cron:sync applies hello.sh cron to AWS server" { +# require_aws_provision_config +# +# run_deployer cron:sync \ +# --domain="$AWS_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "synced to server" +# assert_command_replay "cron:sync" +# } +# +# @test "cron:sync writes AWS crontab entry and log file for hello.sh" { +# require_aws_provision_config +# +# run_deployer server:run \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --command="sudo -n crontab -l -u deployer | grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" +# +# run_deployer server:run \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --command="test -f /var/log/cron/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT.log && echo cron-log-found" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "cron-log-found" +# } +# +# @test "supervisor:create adds hello.sh program for AWS site" { +# require_aws_provision_config +# +# run_deployer supervisor:create \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ +# --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ +# --no-autostart \ +# --no-autorestart \ +# --stopwaitsecs="10" \ +# --numprocs="1" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "supervisor:create" +# } +# +# @test "supervisor:sync applies hello.sh program to AWS server" { +# require_aws_provision_config +# +# run_deployer supervisor:sync \ +# --domain="$AWS_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "synced to server" +# assert_command_replay "supervisor:sync" +# } +# +# @test "supervisor:sync writes AWS supervisor config for hello.sh" { +# require_aws_provision_config +# +# run_deployer server:run \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --command="test -f /etc/supervisor/conf.d/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT' /etc/supervisor/conf.d/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && echo supervisor-config-found" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "supervisor-config-found" +# } +# +# @test "supervisor lifecycle commands restart/stop/start work on AWS server" { +# require_aws_provision_config +# +# run_deployer supervisor:restart \ +# --server="$AWS_TEST_SERVER_NAME" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:restart" +# +# run_deployer supervisor:stop \ +# --server="$AWS_TEST_SERVER_NAME" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:stop" +# +# run_deployer supervisor:start \ +# --server="$AWS_TEST_SERVER_NAME" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:start" +# } +# +# @test "cron:delete removes hello.sh cron for AWS site" { +# require_aws_provision_config +# +# run_deployer cron:delete \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "cron:delete" +# } +# +# @test "cron:sync removes hello.sh crontab entry from AWS server" { +# require_aws_provision_config +# +# run_deployer cron:sync \ +# --domain="$AWS_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "cron:sync" +# +# run_deployer server:run \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --command="if sudo -n crontab -l -u deployer 2>/dev/null | grep -Fq 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'; then echo cron-entry-present; exit 1; else echo cron-entry-absent; fi" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "cron-entry-absent" +# } +# +# @test "supervisor:delete removes hello.sh program for AWS site" { +# require_aws_provision_config +# +# run_deployer supervisor:delete \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "supervisor:delete" +# } +# +# @test "supervisor:sync removes hello.sh supervisor config from AWS server" { +# require_aws_provision_config +# +# run_deployer supervisor:sync \ +# --domain="$AWS_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:sync" +# +# run_deployer server:run \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --command="if test -f /etc/supervisor/conf.d/$AWS_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf; then echo supervisor-config-present; exit 1; else echo supervisor-config-absent; fi" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "supervisor-config-absent" +# } +# +# # ---- +# # site:https +# # ---- +# +# @test "site:https enables HTTPS for ${AWS_TEST_SITE_DOMAIN}" { +# require_aws_provision_config +# +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ +# --domain="$AWS_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "HTTPS enabled successfully" +# assert_command_replay "site:https" +# } +# +# @test "site:https enables HTTPS for ${AWS_TEST_SITE_DOMAIN_SECONDARY}" { +# require_aws_provision_config +# +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ +# --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "HTTPS enabled successfully" +# assert_command_replay "site:https" +# } +# +# # ---- +# # HTTP Verification +# # ---- +# +# @test "deployed AWS site responds to HTTP requests after HTTPS setup" { +# require_aws_provision_config +# +# # Verify app response after HTTPS setup. +# wait_for_http "$AWS_TEST_SITE_DOMAIN" "$CLOUD_TEST_APP_MESSAGE" 30 +# } +# +# @test "deployed AWS secondary site responds to HTTP requests after HTTPS setup" { +# require_aws_provision_config +# +# wait_for_http "$AWS_TEST_SITE_DOMAIN_SECONDARY" "$CLOUD_TEST_APP_MESSAGE" 30 +# } +# +# # ---- +# # site:rollback +# # ---- +# +# @test "site:rollback shows forward-only deployment guidance" { +# require_aws_provision_config +# +# run_deployer site:rollback +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_info_output +# assert_output_contains "Forward-only deployments" +# assert_bullet_output +# } +# +# # ---- +# # site:delete +# # ---- +# +# @test "site:delete removes ${AWS_TEST_SITE_DOMAIN_SECONDARY} from server and inventory" { +# require_aws_provision_config +# +# run_deployer site:delete \ +# --domain="$AWS_TEST_SITE_DOMAIN_SECONDARY" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "site:delete" +# } +# +# @test "site:delete removes ${AWS_TEST_SITE_DOMAIN} from server and inventory" { +# require_aws_provision_config +# +# run_deployer site:delete \ +# --domain="$AWS_TEST_SITE_DOMAIN" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "site:delete" +# } +# +# # ---- +# # cf:dns:delete +# # ---- +# +# @test "cf:dns:delete removes prefixed A record ${CF_TEST_DNS_ROOT_FQDN}" { +# require_aws_provision_config +# +# run_deployer cf:dns:delete \ +# --zone="$CF_TEST_DOMAIN" \ +# --type="A" \ +# --name="$CF_TEST_DNS_ROOT" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record deleted successfully" +# assert_command_replay "cf:dns:delete" +# } +# +# # ---- +# # aws:dns:delete +# # ---- +# +# @test "aws:dns:delete removes prefixed A record ${AWS_TEST_DNS_ROOT_SECONDARY_FQDN}" { +# require_aws_provision_config +# +# run_deployer aws:dns:delete \ +# --zone="$AWS_TEST_HOSTED_ZONE" \ +# --type="A" \ +# --name="$AWS_TEST_DNS_ROOT_SECONDARY" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record deleted successfully" +# assert_command_replay "aws:dns:delete" +# } +# +# @test "aws:dns:delete removes prefixed A record ${AWS_TEST_DNS_ROOT_FQDN}" { +# require_aws_provision_config +# +# run_deployer aws:dns:delete \ +# --zone="$AWS_TEST_HOSTED_ZONE" \ +# --type="A" \ +# --name="$AWS_TEST_DNS_ROOT" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record deleted successfully" +# assert_command_replay "aws:dns:delete" +# } +# +# # ---- +# # Cleanup +# # ---- +# +# @test "server:delete removes AWS instance and cleans up resources" { +# require_aws_provision_config +# +# run_deployer server:delete \ +# --server="$AWS_TEST_SERVER_NAME" \ +# --force \ +# --yes \ +# --destroy-cloud +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Instance terminated" +# assert_output_contains "Elastic IP released" +# assert_output_contains "removed from inventory" +# assert_command_replay "server:delete" +# aws_assert_no_bats_volumes "$BATS_RUN_SUFFIX" +# } diff --git a/tests/bats/cloud-do.bats b/tests/bats/cloud-do.bats index 1e566cf..9746c63 100644 --- a/tests/bats/cloud-do.bats +++ b/tests/bats/cloud-do.bats @@ -1,842 +1,847 @@ #!/usr/bin/env bats -# DigitalOcean Integration Tests -# Tests: DigitalOcean key/provision/DNS + site lifecycle commands +# NOTE: These tests are disabled because the cloud provider accounts +# (AWS, DigitalOcean, Cloudflare) and test domains they depend on have +# been spun down. Uncomment the lines below to re-enable them once +# active credentials are available again. # -# Prerequisites: -# - DIGITALOCEAN_API_TOKEN or DO_API_TOKEN in environment -# - Valid DigitalOcean API token with droplet permissions -# - SSH private key at ~/.ssh/id_ed25519 - -load 'lib/helpers' -load 'lib/cloud-helpers' - -# ---- -# Setup/Teardown -# ---- - -setup_file() { - require_do_credentials - require_do_dns_prefix_config - cloud_note "Run suffix: ${BATS_RUN_SUFFIX}" - do_cleanup_all -} - -teardown_file() { - if ! do_credentials_available; then - return 0 - fi - do_cleanup_all - rm -f "$TEST_INVENTORY" -} - -setup() { - cloud_check_failed - require_do_credentials -} - -teardown() { - cloud_mark_failed -} - -# ---- -# do:key:add -# ---- - -@test "do:key:add uploads public key to DigitalOcean" { - run_deployer do:key:add \ - --name="$DO_TEST_KEY_NAME" \ - --public-key-path="$CLOUD_TEST_KEY_PATH" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Public SSH key uploaded successfully" - assert_output_contains "ID:" - assert_command_replay "do:key:add" -} - -# ---- -# do:key:list -# ---- - -@test "do:key:list shows uploaded key" { - run_deployer do:key:list - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "$DO_TEST_KEY_NAME" - assert_command_replay "do:key:list" -} - -# ---- -# do:key:delete -# ---- - -@test "do:key:delete removes key from DigitalOcean" { - # Find key ID by name (safe: only deletes key we created) - local key_id - key_id=$(do_find_key_id_by_name "$DO_TEST_KEY_NAME") - - # Safety: only proceed if we found a key with our test name - [[ -n "$key_id" ]] || skip "Test key not found" - - run_deployer do:key:delete \ - --key="$key_id" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Public SSH key deleted successfully" - assert_command_replay "do:key:delete" -} - -@test "do:key:list confirms key deleted" { - run_deployer do:key:list - - debug_output - - [ "$status" -eq 0 ] - assert_output_not_contains "$DO_TEST_KEY_NAME" -} - -# ---- -# do:provision -# ---- - -@test "do:provision creates droplet and adds to inventory" { - require_do_provision_config - - # Cleanup any leftover test server - do_cleanup_test_server - - run_deployer do:provision \ - --name="$DO_TEST_SERVER_NAME" \ - --region="$DO_TEST_REGION" \ - --size="$DO_TEST_SIZE" \ - --image="$DO_TEST_IMAGE" \ - --ssh-key-id="$DO_TEST_SSH_KEY_ID" \ - --private-key-path="$DO_TEST_PRIVATE_KEY_PATH" \ - --no-backups \ - --monitoring \ - --ipv6 \ - --vpc-uuid="$DO_TEST_VPC_UUID" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Droplet provisioned" - assert_output_contains "Droplet is active" - assert_output_contains "Server added to inventory" - assert_command_replay "do:provision" - - # Tag contract for janitor discovery - do_assert_droplet_tag_contract "$DO_TEST_SERVER_NAME" -} - -@test "server:install configures DigitalOcean provisioned server" { - require_do_provision_config - - local primary_php_version secondary_php_version installed_php_versions - primary_php_version="$CLOUD_TEST_PHP_PRIMARY_VERSION" - secondary_php_version="$CLOUD_TEST_PHP_SECONDARY_VERSION" - - # Full install takes time - use longer timeout - run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ - --server="$DO_TEST_SERVER_NAME" \ - --generate-deploy-key \ - --timezone="UTC" \ - --php-version="$primary_php_version" \ - --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Server installation completed" - assert_output_contains "public key" - assert_command_replay "server:install" - - # Install secondary PHP-FPM version on the same server (keep primary as default) - run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ - --server="$DO_TEST_SERVER_NAME" \ - --generate-deploy-key \ - --timezone="UTC" \ - --php-version="$secondary_php_version" \ - --no-php-default \ - --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Server installation completed" - assert_command_replay "server:install" - - installed_php_versions="$(get_installed_php_fpm_versions_for_server "$DO_TEST_SERVER_NAME")" - printf '%s\n' "$installed_php_versions" | grep -qx "$primary_php_version" - printf '%s\n' "$installed_php_versions" | grep -qx "$secondary_php_version" -} - -# ---- -# site:create -# ---- - -@test "site:create creates site ${DO_TEST_SITE_DOMAIN} on DigitalOcean provisioned server" { - require_do_provision_config - - # Cleanup any leftover test site - cleanup_test_site "$DO_TEST_SITE_DOMAIN" - - run_deployer site:create \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --server="$DO_TEST_SERVER_NAME" \ - --php-version="$CLOUD_TEST_PHP_PRIMARY_VERSION" \ - --web-root="/" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "site:create" -} - -@test "site:create creates secondary site ${DO_TEST_SITE_DOMAIN_SECONDARY} on DigitalOcean provisioned server" { - require_do_provision_config - - # Cleanup any leftover secondary test site - cleanup_test_site "$DO_TEST_SITE_DOMAIN_SECONDARY" - - run_deployer site:create \ - --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ - --server="$DO_TEST_SERVER_NAME" \ - --php-version="$CLOUD_TEST_PHP_SECONDARY_VERSION" \ - --web-root="/" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "site:create" -} - -# ---- -# do:dns:set -# ---- - -@test "do:dns:set creates prefixed A record for ${DO_TEST_DNS_ROOT_FQDN}" { - require_do_provision_config - - # Get server IP from inventory - local server_ip - server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer do:dns:set \ - --zone="$DO_TEST_DOMAIN" \ - --type="A" \ - --name="$DO_TEST_DNS_ROOT" \ - --value="$server_ip" \ - --ttl="60" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record" - assert_output_contains "successfully" - assert_command_replay "do:dns:set" -} - -@test "do:dns:set creates secondary prefixed A record for ${DO_TEST_DNS_ROOT_SECONDARY_FQDN}" { - require_do_provision_config - - local server_ip - server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer do:dns:set \ - --zone="$DO_TEST_DOMAIN" \ - --type="A" \ - --name="$DO_TEST_DNS_ROOT_SECONDARY" \ - --value="$server_ip" \ - --ttl="60" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record" - assert_output_contains "successfully" - assert_command_replay "do:dns:set" -} - -@test "do:dns:list shows ${DO_TEST_DNS_ROOT_FQDN} and ${DO_TEST_DNS_ROOT_SECONDARY_FQDN}" { - require_do_provision_config - - run_deployer do:dns:list \ - --zone="$DO_TEST_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "$DO_TEST_DOMAIN" - assert_output_contains "$DO_TEST_DNS_ROOT" - assert_output_contains "$DO_TEST_DNS_ROOT_SECONDARY" - assert_command_replay "do:dns:list" -} - -# ---- -# site:dns:check -# ---- - -@test "site:dns:check resolves DNS for ${DO_TEST_SITE_DOMAIN}" { - require_do_provision_config - - local server_ip - server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer site:dns:check \ - --domain="$DO_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "Check DNS" - assert_output_contains "Domain: $DO_TEST_SITE_DOMAIN" - assert_output_contains "A:" - assert_output_contains "AAAA:" - assert_output_contains "$server_ip" - assert_command_replay "site:dns:check" -} - -@test "site:dns:check resolves DNS for ${DO_TEST_SITE_DOMAIN_SECONDARY}" { - require_do_provision_config - - local server_ip - server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") - - [[ -n "$server_ip" ]] || skip "Could not determine server IP" - - run_deployer site:dns:check \ - --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "Check DNS" - assert_output_contains "Domain: $DO_TEST_SITE_DOMAIN_SECONDARY" - assert_output_contains "A:" - assert_output_contains "AAAA:" - assert_output_contains "$server_ip" - assert_command_replay "site:dns:check" -} - -# ---- -# site:shared:push -# ---- - -@test "site:shared:push uploads .env to DigitalOcean site" { - require_do_provision_config - - run_deployer site:shared:push \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ - --remote=".env" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Shared file uploaded" - assert_command_replay "site:shared:push" -} - -@test "site:shared:push uploads .env to DigitalOcean secondary site" { - require_do_provision_config - - run_deployer site:shared:push \ - --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ - --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ - --remote=".env" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Shared file uploaded" - assert_command_replay "site:shared:push" -} - -# ---- -# site:shared:list -# ---- - -@test "site:shared:list shows uploaded shared files for DigitalOcean site" { - require_do_provision_config - - run_deployer site:shared:list \ - --domain="$DO_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains ".env" - assert_command_replay "site:shared:list" -} - -# ---- -# site:shared:pull -# ---- - -@test "site:shared:pull downloads .env from DigitalOcean site" { - require_do_provision_config - - local pulled_env="${BATS_TEST_TMPDIR}/do-shared.env" - - run_deployer site:shared:pull \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --remote=".env" \ - --local="$pulled_env" \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Shared file downloaded" - assert_command_replay "site:shared:pull" - [[ -f "$pulled_env" ]] - - run grep -q "APP_MESSAGE=$CLOUD_TEST_APP_MESSAGE" "$pulled_env" - [ "$status" -eq 0 ] -} - -# ---- -# site:deploy -# ---- - -@test "site:deploy deploys application to DigitalOcean site" { - require_do_provision_config - - # Deploy takes time - use longer timeout - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --repo="$CLOUD_TEST_DEPLOY_REPO" \ - --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Deployment completed" - assert_command_replay "site:deploy" -} - -@test "site:deploy deploys application to DigitalOcean secondary site" { - require_do_provision_config - - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ - --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ - --repo="$CLOUD_TEST_DEPLOY_REPO" \ - --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Deployment completed" - assert_command_replay "site:deploy" -} - -# ---- -# cron/supervisor -# ---- - -@test "cron:create adds hello.sh cron for DigitalOcean site" { - require_do_provision_config - - run_deployer cron:create \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ - --schedule="* * * * *" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "cron:create" -} - -@test "cron:sync applies hello.sh cron to DigitalOcean server" { - require_do_provision_config - - run_deployer cron:sync \ - --domain="$DO_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "synced to server" - assert_command_replay "cron:sync" -} - -@test "cron:sync writes DigitalOcean crontab entry and log file for hello.sh" { - require_do_provision_config - - run_deployer server:run \ - --server="$DO_TEST_SERVER_NAME" \ - --command="sudo -n crontab -l -u deployer | grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" - - run_deployer server:run \ - --server="$DO_TEST_SERVER_NAME" \ - --command="test -f /var/log/cron/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT.log && echo cron-log-found" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "cron-log-found" -} - -@test "supervisor:create adds hello.sh program for DigitalOcean site" { - require_do_provision_config - - run_deployer supervisor:create \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ - --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ - --no-autostart \ - --no-autorestart \ - --stopwaitsecs="10" \ - --numprocs="1" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "added to inventory" - assert_command_replay "supervisor:create" -} - -@test "supervisor:sync applies hello.sh program to DigitalOcean server" { - require_do_provision_config - - run_deployer supervisor:sync \ - --domain="$DO_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "synced to server" - assert_command_replay "supervisor:sync" -} - -@test "supervisor:sync writes DigitalOcean supervisor config for hello.sh" { - require_do_provision_config - - run_deployer server:run \ - --server="$DO_TEST_SERVER_NAME" \ - --command="test -f /etc/supervisor/conf.d/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT' /etc/supervisor/conf.d/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && echo supervisor-config-found" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "supervisor-config-found" -} - -@test "supervisor lifecycle commands restart/stop/start work on DigitalOcean server" { - require_do_provision_config - - run_deployer supervisor:restart \ - --server="$DO_TEST_SERVER_NAME" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:restart" - - run_deployer supervisor:stop \ - --server="$DO_TEST_SERVER_NAME" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:stop" - - run_deployer supervisor:start \ - --server="$DO_TEST_SERVER_NAME" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:start" -} - -@test "cron:delete removes hello.sh cron for DigitalOcean site" { - require_do_provision_config - - run_deployer cron:delete \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "cron:delete" -} - -@test "cron:sync removes hello.sh crontab entry from DigitalOcean server" { - require_do_provision_config - - run_deployer cron:sync \ - --domain="$DO_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "cron:sync" - - run_deployer server:run \ - --server="$DO_TEST_SERVER_NAME" \ - --command="if sudo -n crontab -l -u deployer 2>/dev/null | grep -Fq 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'; then echo cron-entry-present; exit 1; else echo cron-entry-absent; fi" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "cron-entry-absent" -} - -@test "supervisor:delete removes hello.sh program for DigitalOcean site" { - require_do_provision_config - - run_deployer supervisor:delete \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "supervisor:delete" -} - -@test "supervisor:sync removes hello.sh supervisor config from DigitalOcean server" { - require_do_provision_config - - run_deployer supervisor:sync \ - --domain="$DO_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_command_replay "supervisor:sync" - - run_deployer server:run \ - --server="$DO_TEST_SERVER_NAME" \ - --command="if test -f /etc/supervisor/conf.d/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf; then echo supervisor-config-present; exit 1; else echo supervisor-config-absent; fi" - - debug_output - - [ "$status" -eq 0 ] - assert_output_contains "supervisor-config-absent" -} - -# ---- -# site:https -# ---- - -@test "site:https enables HTTPS for ${DO_TEST_SITE_DOMAIN}" { - require_do_provision_config - - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ - --domain="$DO_TEST_SITE_DOMAIN" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "HTTPS enabled successfully" - assert_command_replay "site:https" -} - -@test "site:https enables HTTPS for ${DO_TEST_SITE_DOMAIN_SECONDARY}" { - require_do_provision_config - - run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ - --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "HTTPS enabled successfully" - assert_command_replay "site:https" -} - -# ---- -# HTTP Verification -# ---- - -@test "deployed DigitalOcean site responds to HTTP requests after HTTPS setup" { - require_do_provision_config - - # Verify app response after HTTPS setup. - wait_for_http "$DO_TEST_SITE_DOMAIN" "$CLOUD_TEST_APP_MESSAGE" 30 -} - -@test "deployed DigitalOcean secondary site responds to HTTP requests after HTTPS setup" { - require_do_provision_config - - wait_for_http "$DO_TEST_SITE_DOMAIN_SECONDARY" "$CLOUD_TEST_APP_MESSAGE" 30 -} - -# ---- -# site:rollback -# ---- - -@test "site:rollback shows forward-only deployment guidance" { - require_do_provision_config - - run_deployer site:rollback - - debug_output - - [ "$status" -eq 0 ] - assert_info_output - assert_output_contains "Forward-only deployments" - assert_bullet_output -} - -# ---- -# site:delete -# ---- - -@test "site:delete removes ${DO_TEST_SITE_DOMAIN_SECONDARY} from server and inventory" { - require_do_provision_config - - run_deployer site:delete \ - --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "site:delete" -} - -@test "site:delete removes ${DO_TEST_SITE_DOMAIN} from server and inventory" { - require_do_provision_config - - run_deployer site:delete \ - --domain="$DO_TEST_SITE_DOMAIN" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "removed from inventory" - assert_command_replay "site:delete" -} - -# ---- -# do:dns:delete -# ---- - -@test "do:dns:delete removes prefixed A record ${DO_TEST_DNS_ROOT_SECONDARY_FQDN}" { - require_do_provision_config - - run_deployer do:dns:delete \ - --zone="$DO_TEST_DOMAIN" \ - --type="A" \ - --name="$DO_TEST_DNS_ROOT_SECONDARY" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record deleted successfully" - assert_command_replay "do:dns:delete" -} - -@test "do:dns:delete removes prefixed A record ${DO_TEST_DNS_ROOT_FQDN}" { - require_do_provision_config - - run_deployer do:dns:delete \ - --zone="$DO_TEST_DOMAIN" \ - --type="A" \ - --name="$DO_TEST_DNS_ROOT" \ - --force \ - --yes - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "DNS record deleted successfully" - assert_command_replay "do:dns:delete" -} - -# ---- -# Cleanup -# ---- - -@test "server:delete removes DigitalOcean droplet" { - require_do_provision_config - - run_deployer server:delete \ - --server="$DO_TEST_SERVER_NAME" \ - --force \ - --yes \ - --destroy-cloud - - debug_output - - [ "$status" -eq 0 ] - assert_success_output - assert_output_contains "Droplet destroyed" - assert_output_contains "removed from inventory" - assert_command_replay "server:delete" -} +# # DigitalOcean Integration Tests +# # Tests: DigitalOcean key/provision/DNS + site lifecycle commands +# # +# # Prerequisites: +# # - DIGITALOCEAN_API_TOKEN or DO_API_TOKEN in environment +# # - Valid DigitalOcean API token with droplet permissions +# # - SSH private key at ~/.ssh/id_ed25519 +# +# load 'lib/helpers' +# load 'lib/cloud-helpers' +# +# # ---- +# # Setup/Teardown +# # ---- +# +# setup_file() { +# require_do_credentials +# require_do_dns_prefix_config +# cloud_note "Run suffix: ${BATS_RUN_SUFFIX}" +# do_cleanup_all +# } +# +# teardown_file() { +# if ! do_credentials_available; then +# return 0 +# fi +# do_cleanup_all +# rm -f "$TEST_INVENTORY" +# } +# +# setup() { +# cloud_check_failed +# require_do_credentials +# } +# +# teardown() { +# cloud_mark_failed +# } +# +# # ---- +# # do:key:add +# # ---- +# +# @test "do:key:add uploads public key to DigitalOcean" { +# run_deployer do:key:add \ +# --name="$DO_TEST_KEY_NAME" \ +# --public-key-path="$CLOUD_TEST_KEY_PATH" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Public SSH key uploaded successfully" +# assert_output_contains "ID:" +# assert_command_replay "do:key:add" +# } +# +# # ---- +# # do:key:list +# # ---- +# +# @test "do:key:list shows uploaded key" { +# run_deployer do:key:list +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "$DO_TEST_KEY_NAME" +# assert_command_replay "do:key:list" +# } +# +# # ---- +# # do:key:delete +# # ---- +# +# @test "do:key:delete removes key from DigitalOcean" { +# # Find key ID by name (safe: only deletes key we created) +# local key_id +# key_id=$(do_find_key_id_by_name "$DO_TEST_KEY_NAME") +# +# # Safety: only proceed if we found a key with our test name +# [[ -n "$key_id" ]] || skip "Test key not found" +# +# run_deployer do:key:delete \ +# --key="$key_id" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Public SSH key deleted successfully" +# assert_command_replay "do:key:delete" +# } +# +# @test "do:key:list confirms key deleted" { +# run_deployer do:key:list +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_not_contains "$DO_TEST_KEY_NAME" +# } +# +# # ---- +# # do:provision +# # ---- +# +# @test "do:provision creates droplet and adds to inventory" { +# require_do_provision_config +# +# # Cleanup any leftover test server +# do_cleanup_test_server +# +# run_deployer do:provision \ +# --name="$DO_TEST_SERVER_NAME" \ +# --region="$DO_TEST_REGION" \ +# --size="$DO_TEST_SIZE" \ +# --image="$DO_TEST_IMAGE" \ +# --ssh-key-id="$DO_TEST_SSH_KEY_ID" \ +# --private-key-path="$DO_TEST_PRIVATE_KEY_PATH" \ +# --no-backups \ +# --monitoring \ +# --ipv6 \ +# --vpc-uuid="$DO_TEST_VPC_UUID" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Droplet provisioned" +# assert_output_contains "Droplet is active" +# assert_output_contains "Server added to inventory" +# assert_command_replay "do:provision" +# +# # Tag contract for janitor discovery +# do_assert_droplet_tag_contract "$DO_TEST_SERVER_NAME" +# } +# +# @test "server:install configures DigitalOcean provisioned server" { +# require_do_provision_config +# +# local primary_php_version secondary_php_version installed_php_versions +# primary_php_version="$CLOUD_TEST_PHP_PRIMARY_VERSION" +# secondary_php_version="$CLOUD_TEST_PHP_SECONDARY_VERSION" +# +# # Full install takes time - use longer timeout +# run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ +# --server="$DO_TEST_SERVER_NAME" \ +# --generate-deploy-key \ +# --timezone="UTC" \ +# --php-version="$primary_php_version" \ +# --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Server installation completed" +# assert_output_contains "public key" +# assert_command_replay "server:install" +# +# # Install secondary PHP-FPM version on the same server (keep primary as default) +# run timeout 600 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi server:install \ +# --server="$DO_TEST_SERVER_NAME" \ +# --generate-deploy-key \ +# --timezone="UTC" \ +# --php-version="$secondary_php_version" \ +# --no-php-default \ +# --php-extensions="$CLOUD_TEST_PHP_EXTENSIONS" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Server installation completed" +# assert_command_replay "server:install" +# +# installed_php_versions="$(get_installed_php_fpm_versions_for_server "$DO_TEST_SERVER_NAME")" +# printf '%s\n' "$installed_php_versions" | grep -qx "$primary_php_version" +# printf '%s\n' "$installed_php_versions" | grep -qx "$secondary_php_version" +# } +# +# # ---- +# # site:create +# # ---- +# +# @test "site:create creates site ${DO_TEST_SITE_DOMAIN} on DigitalOcean provisioned server" { +# require_do_provision_config +# +# # Cleanup any leftover test site +# cleanup_test_site "$DO_TEST_SITE_DOMAIN" +# +# run_deployer site:create \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --server="$DO_TEST_SERVER_NAME" \ +# --php-version="$CLOUD_TEST_PHP_PRIMARY_VERSION" \ +# --web-root="/" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "site:create" +# } +# +# @test "site:create creates secondary site ${DO_TEST_SITE_DOMAIN_SECONDARY} on DigitalOcean provisioned server" { +# require_do_provision_config +# +# # Cleanup any leftover secondary test site +# cleanup_test_site "$DO_TEST_SITE_DOMAIN_SECONDARY" +# +# run_deployer site:create \ +# --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ +# --server="$DO_TEST_SERVER_NAME" \ +# --php-version="$CLOUD_TEST_PHP_SECONDARY_VERSION" \ +# --web-root="/" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "site:create" +# } +# +# # ---- +# # do:dns:set +# # ---- +# +# @test "do:dns:set creates prefixed A record for ${DO_TEST_DNS_ROOT_FQDN}" { +# require_do_provision_config +# +# # Get server IP from inventory +# local server_ip +# server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer do:dns:set \ +# --zone="$DO_TEST_DOMAIN" \ +# --type="A" \ +# --name="$DO_TEST_DNS_ROOT" \ +# --value="$server_ip" \ +# --ttl="60" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record" +# assert_output_contains "successfully" +# assert_command_replay "do:dns:set" +# } +# +# @test "do:dns:set creates secondary prefixed A record for ${DO_TEST_DNS_ROOT_SECONDARY_FQDN}" { +# require_do_provision_config +# +# local server_ip +# server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer do:dns:set \ +# --zone="$DO_TEST_DOMAIN" \ +# --type="A" \ +# --name="$DO_TEST_DNS_ROOT_SECONDARY" \ +# --value="$server_ip" \ +# --ttl="60" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record" +# assert_output_contains "successfully" +# assert_command_replay "do:dns:set" +# } +# +# @test "do:dns:list shows ${DO_TEST_DNS_ROOT_FQDN} and ${DO_TEST_DNS_ROOT_SECONDARY_FQDN}" { +# require_do_provision_config +# +# run_deployer do:dns:list \ +# --zone="$DO_TEST_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "$DO_TEST_DOMAIN" +# assert_output_contains "$DO_TEST_DNS_ROOT" +# assert_output_contains "$DO_TEST_DNS_ROOT_SECONDARY" +# assert_command_replay "do:dns:list" +# } +# +# # ---- +# # site:dns:check +# # ---- +# +# @test "site:dns:check resolves DNS for ${DO_TEST_SITE_DOMAIN}" { +# require_do_provision_config +# +# local server_ip +# server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer site:dns:check \ +# --domain="$DO_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "Check DNS" +# assert_output_contains "Domain: $DO_TEST_SITE_DOMAIN" +# assert_output_contains "A:" +# assert_output_contains "AAAA:" +# assert_output_contains "$server_ip" +# assert_command_replay "site:dns:check" +# } +# +# @test "site:dns:check resolves DNS for ${DO_TEST_SITE_DOMAIN_SECONDARY}" { +# require_do_provision_config +# +# local server_ip +# server_ip=$(get_server_ip "$DO_TEST_SERVER_NAME") +# +# [[ -n "$server_ip" ]] || skip "Could not determine server IP" +# +# run_deployer site:dns:check \ +# --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "Check DNS" +# assert_output_contains "Domain: $DO_TEST_SITE_DOMAIN_SECONDARY" +# assert_output_contains "A:" +# assert_output_contains "AAAA:" +# assert_output_contains "$server_ip" +# assert_command_replay "site:dns:check" +# } +# +# # ---- +# # site:shared:push +# # ---- +# +# @test "site:shared:push uploads .env to DigitalOcean site" { +# require_do_provision_config +# +# run_deployer site:shared:push \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ +# --remote=".env" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Shared file uploaded" +# assert_command_replay "site:shared:push" +# } +# +# @test "site:shared:push uploads .env to DigitalOcean secondary site" { +# require_do_provision_config +# +# run_deployer site:shared:push \ +# --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ +# --local="${BATS_TEST_ROOT}/fixtures/env/deploy-me.env" \ +# --remote=".env" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Shared file uploaded" +# assert_command_replay "site:shared:push" +# } +# +# # ---- +# # site:shared:list +# # ---- +# +# @test "site:shared:list shows uploaded shared files for DigitalOcean site" { +# require_do_provision_config +# +# run_deployer site:shared:list \ +# --domain="$DO_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains ".env" +# assert_command_replay "site:shared:list" +# } +# +# # ---- +# # site:shared:pull +# # ---- +# +# @test "site:shared:pull downloads .env from DigitalOcean site" { +# require_do_provision_config +# +# local pulled_env="${BATS_TEST_TMPDIR}/do-shared.env" +# +# run_deployer site:shared:pull \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --remote=".env" \ +# --local="$pulled_env" \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Shared file downloaded" +# assert_command_replay "site:shared:pull" +# [[ -f "$pulled_env" ]] +# +# run grep -q "APP_MESSAGE=$CLOUD_TEST_APP_MESSAGE" "$pulled_env" +# [ "$status" -eq 0 ] +# } +# +# # ---- +# # site:deploy +# # ---- +# +# @test "site:deploy deploys application to DigitalOcean site" { +# require_do_provision_config +# +# # Deploy takes time - use longer timeout +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --repo="$CLOUD_TEST_DEPLOY_REPO" \ +# --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Deployment completed" +# assert_command_replay "site:deploy" +# } +# +# @test "site:deploy deploys application to DigitalOcean secondary site" { +# require_do_provision_config +# +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:deploy \ +# --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ +# --repo="$CLOUD_TEST_DEPLOY_REPO" \ +# --branch="$CLOUD_TEST_DEPLOY_BRANCH" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Deployment completed" +# assert_command_replay "site:deploy" +# } +# +# # ---- +# # cron/supervisor +# # ---- +# +# @test "cron:create adds hello.sh cron for DigitalOcean site" { +# require_do_provision_config +# +# run_deployer cron:create \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ +# --schedule="* * * * *" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "cron:create" +# } +# +# @test "cron:sync applies hello.sh cron to DigitalOcean server" { +# require_do_provision_config +# +# run_deployer cron:sync \ +# --domain="$DO_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "synced to server" +# assert_command_replay "cron:sync" +# } +# +# @test "cron:sync writes DigitalOcean crontab entry and log file for hello.sh" { +# require_do_provision_config +# +# run_deployer server:run \ +# --server="$DO_TEST_SERVER_NAME" \ +# --command="sudo -n crontab -l -u deployer | grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" +# +# run_deployer server:run \ +# --server="$DO_TEST_SERVER_NAME" \ +# --command="test -f /var/log/cron/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT.log && echo cron-log-found" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "cron-log-found" +# } +# +# @test "supervisor:create adds hello.sh program for DigitalOcean site" { +# require_do_provision_config +# +# run_deployer supervisor:create \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ +# --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ +# --no-autostart \ +# --no-autorestart \ +# --stopwaitsecs="10" \ +# --numprocs="1" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "added to inventory" +# assert_command_replay "supervisor:create" +# } +# +# @test "supervisor:sync applies hello.sh program to DigitalOcean server" { +# require_do_provision_config +# +# run_deployer supervisor:sync \ +# --domain="$DO_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "synced to server" +# assert_command_replay "supervisor:sync" +# } +# +# @test "supervisor:sync writes DigitalOcean supervisor config for hello.sh" { +# require_do_provision_config +# +# run_deployer server:run \ +# --server="$DO_TEST_SERVER_NAME" \ +# --command="test -f /etc/supervisor/conf.d/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && grep -F 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT' /etc/supervisor/conf.d/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf && echo supervisor-config-found" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "supervisor-config-found" +# } +# +# @test "supervisor lifecycle commands restart/stop/start work on DigitalOcean server" { +# require_do_provision_config +# +# run_deployer supervisor:restart \ +# --server="$DO_TEST_SERVER_NAME" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:restart" +# +# run_deployer supervisor:stop \ +# --server="$DO_TEST_SERVER_NAME" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:stop" +# +# run_deployer supervisor:start \ +# --server="$DO_TEST_SERVER_NAME" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:start" +# } +# +# @test "cron:delete removes hello.sh cron for DigitalOcean site" { +# require_do_provision_config +# +# run_deployer cron:delete \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --script="$CLOUD_TEST_CRON_SUPERVISOR_SCRIPT" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "cron:delete" +# } +# +# @test "cron:sync removes hello.sh crontab entry from DigitalOcean server" { +# require_do_provision_config +# +# run_deployer cron:sync \ +# --domain="$DO_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "cron:sync" +# +# run_deployer server:run \ +# --server="$DO_TEST_SERVER_NAME" \ +# --command="if sudo -n crontab -l -u deployer 2>/dev/null | grep -Fq 'runner.sh $CLOUD_TEST_CRON_SUPERVISOR_SCRIPT'; then echo cron-entry-present; exit 1; else echo cron-entry-absent; fi" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "cron-entry-absent" +# } +# +# @test "supervisor:delete removes hello.sh program for DigitalOcean site" { +# require_do_provision_config +# +# run_deployer supervisor:delete \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --program="$CLOUD_TEST_SUPERVISOR_PROGRAM" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "supervisor:delete" +# } +# +# @test "supervisor:sync removes hello.sh supervisor config from DigitalOcean server" { +# require_do_provision_config +# +# run_deployer supervisor:sync \ +# --domain="$DO_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_command_replay "supervisor:sync" +# +# run_deployer server:run \ +# --server="$DO_TEST_SERVER_NAME" \ +# --command="if test -f /etc/supervisor/conf.d/$DO_TEST_SITE_DOMAIN-$CLOUD_TEST_SUPERVISOR_PROGRAM.conf; then echo supervisor-config-present; exit 1; else echo supervisor-config-absent; fi" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_output_contains "supervisor-config-absent" +# } +# +# # ---- +# # site:https +# # ---- +# +# @test "site:https enables HTTPS for ${DO_TEST_SITE_DOMAIN}" { +# require_do_provision_config +# +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ +# --domain="$DO_TEST_SITE_DOMAIN" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "HTTPS enabled successfully" +# assert_command_replay "site:https" +# } +# +# @test "site:https enables HTTPS for ${DO_TEST_SITE_DOMAIN_SECONDARY}" { +# require_do_provision_config +# +# run timeout 300 "$DEPLOYER_BIN" --inventory="$TEST_INVENTORY" --no-ansi site:https \ +# --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "HTTPS enabled successfully" +# assert_command_replay "site:https" +# } +# +# # ---- +# # HTTP Verification +# # ---- +# +# @test "deployed DigitalOcean site responds to HTTP requests after HTTPS setup" { +# require_do_provision_config +# +# # Verify app response after HTTPS setup. +# wait_for_http "$DO_TEST_SITE_DOMAIN" "$CLOUD_TEST_APP_MESSAGE" 30 +# } +# +# @test "deployed DigitalOcean secondary site responds to HTTP requests after HTTPS setup" { +# require_do_provision_config +# +# wait_for_http "$DO_TEST_SITE_DOMAIN_SECONDARY" "$CLOUD_TEST_APP_MESSAGE" 30 +# } +# +# # ---- +# # site:rollback +# # ---- +# +# @test "site:rollback shows forward-only deployment guidance" { +# require_do_provision_config +# +# run_deployer site:rollback +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_info_output +# assert_output_contains "Forward-only deployments" +# assert_bullet_output +# } +# +# # ---- +# # site:delete +# # ---- +# +# @test "site:delete removes ${DO_TEST_SITE_DOMAIN_SECONDARY} from server and inventory" { +# require_do_provision_config +# +# run_deployer site:delete \ +# --domain="$DO_TEST_SITE_DOMAIN_SECONDARY" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "site:delete" +# } +# +# @test "site:delete removes ${DO_TEST_SITE_DOMAIN} from server and inventory" { +# require_do_provision_config +# +# run_deployer site:delete \ +# --domain="$DO_TEST_SITE_DOMAIN" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "removed from inventory" +# assert_command_replay "site:delete" +# } +# +# # ---- +# # do:dns:delete +# # ---- +# +# @test "do:dns:delete removes prefixed A record ${DO_TEST_DNS_ROOT_SECONDARY_FQDN}" { +# require_do_provision_config +# +# run_deployer do:dns:delete \ +# --zone="$DO_TEST_DOMAIN" \ +# --type="A" \ +# --name="$DO_TEST_DNS_ROOT_SECONDARY" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record deleted successfully" +# assert_command_replay "do:dns:delete" +# } +# +# @test "do:dns:delete removes prefixed A record ${DO_TEST_DNS_ROOT_FQDN}" { +# require_do_provision_config +# +# run_deployer do:dns:delete \ +# --zone="$DO_TEST_DOMAIN" \ +# --type="A" \ +# --name="$DO_TEST_DNS_ROOT" \ +# --force \ +# --yes +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "DNS record deleted successfully" +# assert_command_replay "do:dns:delete" +# } +# +# # ---- +# # Cleanup +# # ---- +# +# @test "server:delete removes DigitalOcean droplet" { +# require_do_provision_config +# +# run_deployer server:delete \ +# --server="$DO_TEST_SERVER_NAME" \ +# --force \ +# --yes \ +# --destroy-cloud +# +# debug_output +# +# [ "$status" -eq 0 ] +# assert_success_output +# assert_output_contains "Droplet destroyed" +# assert_output_contains "removed from inventory" +# assert_command_replay "server:delete" +# } From d93cf02082273e5fff5c2057114b148379e82cfa Mon Sep 17 00:00:00 2001 From: Lucian Behind The Scenes Date: Sun, 9 Aug 2026 13:29:27 +0300 Subject: [PATCH 3/3] ci: disable cloud test jobs and janitor sweeps Removes the hourly janitor schedule and comments out the cloud-tests and janitor jobs that depend on retired cloud provider accounts. --- .github/workflows/ci.yml | 443 ++++++++++++++++++++------------------- 1 file changed, 226 insertions(+), 217 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e9eb4c..f88fd67 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,8 +24,11 @@ on: branches: - main paths: *ci_paths - schedule: - - cron: "0 * * * *" + # NOTE: The hourly janitor-sweep schedule is disabled because the cloud + # provider accounts it swept (AWS, DigitalOcean, Cloudflare) have been + # spun down. Restore it together with the cloud jobs below if needed. + # schedule: + # - cron: "0 * * * *" jobs: trust-context: @@ -251,218 +254,224 @@ jobs: BATS_DISTRO: ubuntu24 run: ./bats.sh ci vm ubuntu24 - cloud-tests-do: - name: cloud-tests (do) - needs: [trust-context, vm-tests-ubuntu24] - if: ${{ needs.trust-context.outputs.run_secret_jobs == 'true' && needs.vm-tests-ubuntu24.result == 'success' }} - runs-on: ubuntu-24.04 - timeout-minutes: 12 - concurrency: - group: bats-cloud-do-${{ needs.trust-context.outputs.checkout_ref }} - cancel-in-progress: true - - env: - CI: "true" - BATS_RUN_SUFFIX: ${{ github.run_id }} - - steps: - - name: Checkout repository - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - ref: ${{ needs.trust-context.outputs.checkout_ref }} - - - name: Setup PHP and Composer - uses: ./.github/actions/setup-php-composer - - - name: Install BATS and dependencies - run: | - sudo apt-get update - sudo apt-get install -y bats jq curl - aws --version - - - name: Setup environment file - run: | - cat <<'EOF' > .env - ${{ secrets.DOTENV_FILE }} - EOF - - - name: Setup SSH key for cloud provisioning - run: | - mkdir -p ~/.ssh tests/bats/fixtures/keys - echo "${{ secrets.SSH_PRIVATE_KEY_B64 }}" | base64 -d > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub - cp ~/.ssh/id_ed25519.pub tests/bats/fixtures/keys/id_test.pub - - - name: Run DO tests - run: | - set -a - # shellcheck disable=SC1091 - source .env - set +a - ./bats.sh ci cloud do - - - name: Cleanup cloud resources (backstop) - if: always() - run: | - set -a - # shellcheck disable=SC1091 - source .env - set +a - tests/bats/lib/cloud-janitor.sh \ - --mode=targeted \ - --suffix="${BATS_RUN_SUFFIX}" \ - --providers="do" - - cloud-tests-aws: - name: cloud-tests (aws) - needs: [trust-context, vm-tests-ubuntu24] - if: ${{ needs.trust-context.outputs.run_secret_jobs == 'true' && needs.vm-tests-ubuntu24.result == 'success' }} - runs-on: ubuntu-24.04 - timeout-minutes: 12 - concurrency: - group: bats-cloud-aws-${{ needs.trust-context.outputs.checkout_ref }} - cancel-in-progress: true - - env: - CI: "true" - BATS_RUN_SUFFIX: ${{ github.run_id }} - - steps: - - name: Checkout repository - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - ref: ${{ needs.trust-context.outputs.checkout_ref }} - - - name: Setup PHP and Composer - uses: ./.github/actions/setup-php-composer - - - name: Install BATS and dependencies - run: | - sudo apt-get update - sudo apt-get install -y bats jq curl - aws --version - - - name: Setup environment file - run: | - cat <<'EOF' > .env - ${{ secrets.DOTENV_FILE }} - EOF - - - name: Setup SSH key for cloud provisioning - run: | - mkdir -p ~/.ssh tests/bats/fixtures/keys - echo "${{ secrets.SSH_PRIVATE_KEY_B64 }}" | base64 -d > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub - cp ~/.ssh/id_ed25519.pub tests/bats/fixtures/keys/id_test.pub - - - name: Run AWS tests - run: | - set -a - # shellcheck disable=SC1091 - source .env - set +a - ./bats.sh ci cloud aws - - - name: Cleanup cloud resources (backstop) - if: always() - run: | - set -a - # shellcheck disable=SC1091 - source .env - set +a - tests/bats/lib/cloud-janitor.sh \ - --mode=targeted \ - --suffix="${BATS_RUN_SUFFIX}" \ - --providers="aws" - - janitor-targeted: - name: janitor-targeted - needs: [trust-context, cloud-tests-do, cloud-tests-aws] - if: >- - ${{ - always() && - needs.trust-context.outputs.run_secret_jobs == 'true' && - (needs['cloud-tests-do'].result != 'skipped' || needs['cloud-tests-aws'].result != 'skipped') - }} - runs-on: ubuntu-24.04 - timeout-minutes: 12 - concurrency: - group: bats-cloud-janitor-targeted-${{ github.run_id }} - cancel-in-progress: false - - env: - GITHUB_TOKEN: ${{ github.token }} - - steps: - - name: Checkout repository - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - - name: Setup PHP and Composer - uses: ./.github/actions/setup-php-composer - - - name: Install janitor dependencies - run: | - sudo apt-get update - sudo apt-get install -y jq curl - aws --version - - - name: Setup environment file - run: | - cat <<'ENVEOF' > .env - ${{ secrets.DOTENV_FILE }} - ENVEOF - - - name: Janitor cleanup after cloud jobs - run: | - set -a - # shellcheck disable=SC1091 - source .env - set +a - tests/bats/lib/cloud-janitor.sh \ - --mode=targeted \ - --suffix="${{ github.run_id }}" \ - --providers="aws,do,cf" - - janitor-sweep: - needs: trust-context - if: ${{ needs.trust-context.outputs.run_sweep == 'true' }} - runs-on: ubuntu-24.04 - timeout-minutes: 12 - concurrency: - group: bats-cloud-janitor - cancel-in-progress: false - - env: - GITHUB_TOKEN: ${{ github.token }} - - steps: - - name: Checkout repository - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - - name: Setup PHP and Composer - uses: ./.github/actions/setup-php-composer - - - name: Install janitor dependencies - run: | - sudo apt-get update - sudo apt-get install -y jq curl - aws --version - - - name: Setup environment file - run: | - cat <<'ENVEOF' > .env - ${{ secrets.DOTENV_FILE }} - ENVEOF - - - name: Janitor scheduled sweep - run: | - set -a - # shellcheck disable=SC1091 - source .env - set +a - tests/bats/lib/cloud-janitor.sh \ - --mode=sweep \ - --providers="aws,do,cf" \ - --min-age-minutes=30 + # ---- + # NOTE: The jobs below are disabled because the cloud provider accounts + # (AWS, DigitalOcean, Cloudflare) and test domains they depend on have + # been spun down. Uncomment them (and the schedule trigger above) to + # re-enable once active credentials are available again. + # ---- + # cloud-tests-do: + # name: cloud-tests (do) + # needs: [trust-context, vm-tests-ubuntu24] + # if: ${{ needs.trust-context.outputs.run_secret_jobs == 'true' && needs.vm-tests-ubuntu24.result == 'success' }} + # runs-on: ubuntu-24.04 + # timeout-minutes: 12 + # concurrency: + # group: bats-cloud-do-${{ needs.trust-context.outputs.checkout_ref }} + # cancel-in-progress: true + + # env: + # CI: "true" + # BATS_RUN_SUFFIX: ${{ github.run_id }} + + # steps: + # - name: Checkout repository + # uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + # with: + # ref: ${{ needs.trust-context.outputs.checkout_ref }} + + # - name: Setup PHP and Composer + # uses: ./.github/actions/setup-php-composer + + # - name: Install BATS and dependencies + # run: | + # sudo apt-get update + # sudo apt-get install -y bats jq curl + # aws --version + + # - name: Setup environment file + # run: | + # cat <<'EOF' > .env + # ${{ secrets.DOTENV_FILE }} + # EOF + + # - name: Setup SSH key for cloud provisioning + # run: | + # mkdir -p ~/.ssh tests/bats/fixtures/keys + # echo "${{ secrets.SSH_PRIVATE_KEY_B64 }}" | base64 -d > ~/.ssh/id_ed25519 + # chmod 600 ~/.ssh/id_ed25519 + # ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub + # cp ~/.ssh/id_ed25519.pub tests/bats/fixtures/keys/id_test.pub + + # - name: Run DO tests + # run: | + # set -a + # # shellcheck disable=SC1091 + # source .env + # set +a + # ./bats.sh ci cloud do + + # - name: Cleanup cloud resources (backstop) + # if: always() + # run: | + # set -a + # # shellcheck disable=SC1091 + # source .env + # set +a + # tests/bats/lib/cloud-janitor.sh \ + # --mode=targeted \ + # --suffix="${BATS_RUN_SUFFIX}" \ + # --providers="do" + + # cloud-tests-aws: + # name: cloud-tests (aws) + # needs: [trust-context, vm-tests-ubuntu24] + # if: ${{ needs.trust-context.outputs.run_secret_jobs == 'true' && needs.vm-tests-ubuntu24.result == 'success' }} + # runs-on: ubuntu-24.04 + # timeout-minutes: 12 + # concurrency: + # group: bats-cloud-aws-${{ needs.trust-context.outputs.checkout_ref }} + # cancel-in-progress: true + + # env: + # CI: "true" + # BATS_RUN_SUFFIX: ${{ github.run_id }} + + # steps: + # - name: Checkout repository + # uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + # with: + # ref: ${{ needs.trust-context.outputs.checkout_ref }} + + # - name: Setup PHP and Composer + # uses: ./.github/actions/setup-php-composer + + # - name: Install BATS and dependencies + # run: | + # sudo apt-get update + # sudo apt-get install -y bats jq curl + # aws --version + + # - name: Setup environment file + # run: | + # cat <<'EOF' > .env + # ${{ secrets.DOTENV_FILE }} + # EOF + + # - name: Setup SSH key for cloud provisioning + # run: | + # mkdir -p ~/.ssh tests/bats/fixtures/keys + # echo "${{ secrets.SSH_PRIVATE_KEY_B64 }}" | base64 -d > ~/.ssh/id_ed25519 + # chmod 600 ~/.ssh/id_ed25519 + # ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub + # cp ~/.ssh/id_ed25519.pub tests/bats/fixtures/keys/id_test.pub + + # - name: Run AWS tests + # run: | + # set -a + # # shellcheck disable=SC1091 + # source .env + # set +a + # ./bats.sh ci cloud aws + + # - name: Cleanup cloud resources (backstop) + # if: always() + # run: | + # set -a + # # shellcheck disable=SC1091 + # source .env + # set +a + # tests/bats/lib/cloud-janitor.sh \ + # --mode=targeted \ + # --suffix="${BATS_RUN_SUFFIX}" \ + # --providers="aws" + + # janitor-targeted: + # name: janitor-targeted + # needs: [trust-context, cloud-tests-do, cloud-tests-aws] + # if: >- + # ${{ + # always() && + # needs.trust-context.outputs.run_secret_jobs == 'true' && + # (needs['cloud-tests-do'].result != 'skipped' || needs['cloud-tests-aws'].result != 'skipped') + # }} + # runs-on: ubuntu-24.04 + # timeout-minutes: 12 + # concurrency: + # group: bats-cloud-janitor-targeted-${{ github.run_id }} + # cancel-in-progress: false + + # env: + # GITHUB_TOKEN: ${{ github.token }} + + # steps: + # - name: Checkout repository + # uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + # - name: Setup PHP and Composer + # uses: ./.github/actions/setup-php-composer + + # - name: Install janitor dependencies + # run: | + # sudo apt-get update + # sudo apt-get install -y jq curl + # aws --version + + # - name: Setup environment file + # run: | + # cat <<'ENVEOF' > .env + # ${{ secrets.DOTENV_FILE }} + # ENVEOF + + # - name: Janitor cleanup after cloud jobs + # run: | + # set -a + # # shellcheck disable=SC1091 + # source .env + # set +a + # tests/bats/lib/cloud-janitor.sh \ + # --mode=targeted \ + # --suffix="${{ github.run_id }}" \ + # --providers="aws,do,cf" + + # janitor-sweep: + # needs: trust-context + # if: ${{ needs.trust-context.outputs.run_sweep == 'true' }} + # runs-on: ubuntu-24.04 + # timeout-minutes: 12 + # concurrency: + # group: bats-cloud-janitor + # cancel-in-progress: false + + # env: + # GITHUB_TOKEN: ${{ github.token }} + + # steps: + # - name: Checkout repository + # uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + # - name: Setup PHP and Composer + # uses: ./.github/actions/setup-php-composer + + # - name: Install janitor dependencies + # run: | + # sudo apt-get update + # sudo apt-get install -y jq curl + # aws --version + + # - name: Setup environment file + # run: | + # cat <<'ENVEOF' > .env + # ${{ secrets.DOTENV_FILE }} + # ENVEOF + + # - name: Janitor scheduled sweep + # run: | + # set -a + # # shellcheck disable=SC1091 + # source .env + # set +a + # tests/bats/lib/cloud-janitor.sh \ + # --mode=sweep \ + # --providers="aws,do,cf" \ + # --min-age-minutes=30