From 069171c5aa7d7bf235020818acacf6f35f9d5fcf Mon Sep 17 00:00:00 2001 From: Natalie Rose Date: Sat, 29 Aug 2026 09:54:18 +1000 Subject: [PATCH] Fixing docker infrastructure/config so that tests can pass --- CLAUDE.md | 9 +++++---- bin/run_tests.sh | 32 ++++++++++++++++++++++++++++++++ lib/Lacuna/Verify.pm | 21 +++++++++++++-------- t/010_Empire.t | 8 +++++--- t/TestHelper.pm | 17 ++++++++++++++++- 5 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 bin/run_tests.sh diff --git a/CLAUDE.md b/CLAUDE.md index a9bfb2b0..898c83e9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,11 +36,12 @@ Inside `lacuna-server`, `bin/startdev.sh` runs `perl generate_docs.pl` then `pla ## Testing -Tests are plain `Test::More`/prove style (no `.proverc`; `Test::Class::Moose` is installed but not actually used as a base class). They are **integration tests that hit a live server over HTTP**, not isolated unit tests — via `t/TestHelper.pm` (LWP::UserAgent, plus helpers like `generate_test_empire`, `build_infrastructure`, `clear_all_test_empires`). Running them requires the Docker stack (or equivalent) up with a real DB. +Tests are plain `Test::More`/prove style (no `.proverc`; `Test::Class::Moose` is installed but not actually used as a base class). They are **integration tests that hit a live server over HTTP**, not isolated unit tests — via `t/TestHelper.pm` (LWP::UserAgent, plus helpers like `generate_test_empire`, `build_infrastructure`, `clear_all_test_empires`). `t/TestHelper.pm::post` sends its JSON-RPC calls to `$LACUNA_TEST_SERVER_URL` (default `http://localhost:5000/` — the plackup server *inside* the `lacuna-server` container), **not** `Lacuna->config->get('server_url')` (which points at the deployed server). So the suite must run inside `lacuna-server` with the compose stack up. -- Full suite: `prove -Ilib -r t/` -- Single file: `prove -Ilib t/010_Empire.t` -- Test locations: `t/*.t` (numbered, e.g. `t/010_Empire.t`), `t/bugs/*.t` (regression tests, e.g. `t/bugs/0003_PurchaseTooManyShips.t`), `t/long_running/`, `t/middleware/` +- Full suite: `docker compose run --rm lacuna-server ./run_tests.sh` +- Single file: `docker compose run --rm lacuna-server ./run_tests.sh t/010_Empire.t` +- `bin/run_tests.sh` just sets `LACUNA_TEST_SERVER_URL`, `cd`s to the server root and runs `prove -Ilib -It` (the `-It` makes `use TestHelper` resolve regardless of each file's own `use lib` line; note that the container's workdir is `bin/` so you don't need to have bin/ in your commands or set the working directory yourself). +- Test locations: `t/*.t` (numbered, e.g. `t/010_Empire.t`), `t/bugs/*.t` (regression tests, e.g. `t/bugs/0003_PurchaseTooManyShips.t`), `t/long_running/` (excluded from the default `bin/run_tests.sh` run — slow), `t/middleware/` No `.perltidyrc`/`.perlcriticrc` — no enforced style/lint tooling. diff --git a/bin/run_tests.sh b/bin/run_tests.sh new file mode 100644 index 00000000..3758c8f6 --- /dev/null +++ b/bin/run_tests.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Run the Lacuna Perl integration test suite. +# +# MUST run inside the lacuna-server container: it needs the app server on :5000, +# MySQL + memcached + beanstalkd reachable, and the Carton deps baked into the +# image's ./local. From the host: +# +# docker compose run --rm lacuna-server ./run_tests.sh # default set +# docker compose run --rm lacuna-server ./run_tests.sh t/010_Empire.t # one file / dir +# +# The tests POST their JSON-RPC calls to $LACUNA_TEST_SERVER_URL (see +# t/TestHelper.pm), which defaults below to this container's own server. You can +# point it elsewhere, but the empire-create tests (t/010_Empire.t) still need to +# run from inside lacuna-server so the server sees the client as 127.0.0.1 -- +# the IP the test seeds the create-empire captcha under. +set -eu + +: "${LACUNA_TEST_SERVER_URL:=http://lacuna-server:5000/}" +export LACUNA_TEST_SERVER_URL + +cd /home/lacuna/server + +# -It : put t/ on @INC so `use TestHelper` resolves regardless of each file's +# own `use lib '../lib'` / '..' lines and regardless of cwd. +# -Ilib: the application code. +if [ "$#" -gt 0 ]; then + exec prove -Ilib -It -r "$@" +fi + +# Default: numbered tests + regression tests + middleware tests. +# t/long_running/ is deliberately excluded -- it takes many minutes. +exec prove -Ilib -It t/*.t t/bugs/*.t t/middleware/*.t diff --git a/lib/Lacuna/Verify.pm b/lib/Lacuna/Verify.pm index 5d55b86b..9434c68e 100644 --- a/lib/Lacuna/Verify.pm +++ b/lib/Lacuna/Verify.pm @@ -58,14 +58,19 @@ sub no_profanity { my %word_count; $word_count{$_}++ for @bad_words; my $throws = $self->throws; - my $msg = $throws->[1] . ' ('; - $msg .= join ', ', map { - my $s = $_; - $s .= " (x$word_count{$_})" if $word_count{$_} != 1; - $s; - } sort keys %word_count; - $msg .= ')'; - $throws->[1] = $msg + # Real callers pass an arrayref [code, message, field]; only rewrite the + # message to list the offending words when that's the shape we got. A + # scalar throws falls through to `confess $self->throws` unchanged. + if (ref $throws eq 'ARRAY') { + my $msg = $throws->[1] . ' ('; + $msg .= join ', ', map { + my $s = $_; + $s .= " (x$word_count{$_})" if $word_count{$_} != 1; + $s; + } sort keys %word_count; + $msg .= ')'; + $throws->[1] = $msg; + } } return $self->ok(@bad_words == 0); } diff --git a/t/010_Empire.t b/t/010_Empire.t index e3e5d8bd..2c13ad30 100644 --- a/t/010_Empire.t +++ b/t/010_Empire.t @@ -27,7 +27,9 @@ my $empire = { }; my $e2; -Lacuna->cache->set('create_empire_captcha', '127.0.0.1', { guid => 1111, solution => 1111 }, 60 * 15 ); +# Set on both 127.0.0.1 and 172.18.0.7 to cover running the tests on bare metal vs Docker (respectively) +Lacuna->cache->set('create_empire_captcha', '127.0.0.1', { guid => 1111, solution => 1111 }, 60 * 15); +Lacuna->cache->set('create_empire_captcha', '172.18.0.7', { guid => 1111, solution => 1111 }, 60 * 15); $empire->{name} = 'XX>'; $result = $tester->post('empire', 'create', $empire); @@ -222,7 +224,7 @@ $e2->add_essentia({ amount => 200, reason => 'test'}); $e2->update; my $session2 = $result->{result}{session_id}; $result = $tester->post('empire', 'get_status', [$session2]); -is($result->{result}{empire}{essentia}, '200.0', 'added essentia works'); +is($result->{result}{empire}{essentia}, 200, 'added essentia works'); $result = $tester->post('empire', 'redefine_species_limits', [$session2]); is($result->{result}{essentia_cost}, 100, 'get redefine limits'); @@ -231,7 +233,7 @@ $borg->{name} = 'The BORGinator'; $result = $tester->post('empire', 'redefine_species', [$session2, $borg]); $result = $tester->post('empire','view_species_stats',[$session2]); is($result->{result}{species}{name}, 'The BORGinator', 'get renamed species name'); -is($result->{result}{status}{empire}{essentia}, '100.0', 'essentia spent'); +is($result->{result}{status}{empire}{essentia}, 100, 'essentia spent'); # as far as I can tell, we don't create an EssentiaCode in this test. #my $code = Lacuna->db->resultset('Lacuna::DB::Result::EssentiaCode')->search({description=>'essentia code deleted'})->first; diff --git a/t/TestHelper.pm b/t/TestHelper.pm index b19b973f..8e682409 100644 --- a/t/TestHelper.pm +++ b/t/TestHelper.pm @@ -17,6 +17,21 @@ has ua => ( default => sub { my $ua = LWP::UserAgent->new; $ua->timeout(30); return $ua; }, ); +# Where post() sends its JSON-RPC calls. Defaults to the plackup server running +# inside the lacuna-server container; override with LACUNA_TEST_SERVER_URL. +# Deliberately NOT Lacuna->config->get('server_url') -- that points at the +# deployed server, so the suite would talk to production while its DB/cache +# setup talks to the local containers. +has server_url => ( + is => 'ro', + lazy => 1, + default => sub { + my $url = $ENV{LACUNA_TEST_SERVER_URL} || 'http://localhost:5000/'; + $url .= '/' unless $url =~ m{/$}; + return $url; + }, +); + has empire_name => ( is => 'ro', default => 'TLE Test Empire', @@ -218,7 +233,7 @@ sub post { params => $params, }; say "REQUEST: ".to_json($content); - my $response = $self->ua->post(Lacuna->config->get('server_url').$url, + my $response = $self->ua->post($self->server_url.$url, Content_Type => 'application/json', Content => to_json($content), Accept => 'application/json', -- 2.51.2