From 170f936fe8c263b6d50e0f83ab0815204960e574 Mon Sep 17 00:00:00 2001 From: Manager Bot Date: Thu, 24 Nov 2022 07:00:30 +0000 Subject: [PATCH] Initial testing environment. --- Web/lib/MJB/Web.pm | 5 +- Web/lib/MJB/Web/Test.pm | 52 +++++++ Web/lib/Test/Mojo/MJB.pm | 145 ++++++++++++++++++ Web/t/01_endpoints/01_auth/01_register_open.t | 38 +++++ 4 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 Web/lib/MJB/Web/Test.pm create mode 100644 Web/lib/Test/Mojo/MJB.pm create mode 100644 Web/t/01_endpoints/01_auth/01_register_open.t diff --git a/Web/lib/MJB/Web.pm b/Web/lib/MJB/Web.pm index 88c5d85..1e1924f 100644 --- a/Web/lib/MJB/Web.pm +++ b/Web/lib/MJB/Web.pm @@ -32,8 +32,11 @@ sub startup ($self) { # Load the MJB::Web::Plugin::Jekyll plugin for $c->jekyll $self->plugin('Jekyll'); + # Create $self->db as an MJB::DB connection. $self->helper( db => sub { - return state $db = MJB::DB->connect($config->{database}->{mjb}); + return state $db = exists $ENV{MJB_TESTMODE} && $ENV{MJB_TESTMODE} == 1 + ? MJB::DB->connect( $ENV{MJB_DSN}, '', '' ) + : MJB::DB->connect($self->config->{database}->{mjb}); }); $self->helper( sync_blog => sub ( $c, $blog ) { diff --git a/Web/lib/MJB/Web/Test.pm b/Web/lib/MJB/Web/Test.pm new file mode 100644 index 0000000..1260bcd --- /dev/null +++ b/Web/lib/MJB/Web/Test.pm @@ -0,0 +1,52 @@ +package MJB::Web::Test; +use Import::Into; +use Test::More; +use Test::Deep; +use Test::Mojo::MJB; +use Test::Postgresql58; + +push our @ISA, qw( Exporter ); +push our @EXPORT, qw( $run_code ); + +sub import { + shift->export_to_level(1); + my $target = caller; + + Mojo::Base ->import::into($target, '-strict', '-signatures' ); + warnings ->import::into($target); + strict ->import::into($target); + Test::More ->import::into($target); + Test::Deep ->import::into($target); + Test::Mojo::MJB->import::into($target); +} + +our $pgsql = Test::Postgresql58->new() + or BAILOUT( "PSQL Error: " . $Test::Postgresql58::errstr ); + +load_psql_file("../DB/etc/schema.sql"); + +$ENV{MJB_TESTMODE} = 1; +$ENV{MJB_DSN} = $pgsql->dsn; + +sub load_psql_file { + my ( $file ) = @_; + + open my $lf, "<", $file + or die "Failed to open $file for reading: $!"; + my $content; + while ( defined( my $line = <$lf> ) ) { + next unless $line !~ /^\s*--/; + $content .= $line; + } + close $lf; + + my $dbh = DBI->connect( $pgsql->dsn ); + for my $command ( split( /;/, $content ) ) { + next if $command =~ /^\s*$/; + $dbh->do( $command ) + or BAIL_OUT( "PSQL Error($file): $command: " . $dbh->errstr); + } + undef $dbh; +} + +1; diff --git a/Web/lib/Test/Mojo/MJB.pm b/Web/lib/Test/Mojo/MJB.pm new file mode 100644 index 0000000..ac02a56 --- /dev/null +++ b/Web/lib/Test/Mojo/MJB.pm @@ -0,0 +1,145 @@ +package Test::Mojo::MJB; +# This package subclasses Test::Mojo and sets up some +# functionality. +# +# _stash_ +# The $t object will now have a stash method that returns +# the stash. +# +# _code_block_ +# The $t object will now have a code_block method that +# accepts a code block, runs it, and returns $t. +# +# This combination of stash and code_block enable a +# pattern like the following: +# +# $t->post_ok( '/login', { user => $user, pass => $pass}) +# ->code_block( sub { +# my $t = shift; +# is($t->stash->{person}->user, $user, "User saved in stash."); +# })->status_is( 200 ); +# +# _dump_stash_ +# The $t object now has a dump_stash method that prints the +# stash to STDERR. By default this will supress mojo-specific +# stash elements, pass a true value to dump the full stash. +# +# $t->get_ok('/') +# ->dump_stash(1) +# ->status_is(200); +# +use warnings; +use strict; +use parent 'Test::Mojo'; +use Data::Dumper; +use Test::Deep; +use Test::More; + +sub new { + my $class = shift; + my $self = $class->SUPER::new(@_); + + $self->app->hook( after_dispatch => sub { + my ( $c ) = @_; + $self->stash( $c->stash ); + }); + + return $self; +} + +sub stash { + my $self = shift; + $self->{stash} = shift if @_; + return $self->{stash}; +} + +sub code_block { + my ( $t, $code ) = @_; + + $code->($t); + + return $t; +} + +sub dump_stash { + my ( $t, $show_all ) = @_; + + if ( $show_all ) { + warn Dumper $t->stash; + return $t; + } + + my $ds; + + foreach my $key ( keys %{$t->stash}) { + next if $key eq 'controller'; + next if $key eq 'action'; + next if $key eq 'cb'; + next if $key eq 'template'; + next if $key eq 'person'; + next if $key =~ m|^mojo\.|; + + $ds->{$key} = $t->stash->{$key}; + } + + warn Dumper $ds; + + return $t; +} + +sub stash_has { + my ( $t, $expect, $desc ) = @_; + + cmp_deeply( $t->stash, superhashof($expect), $desc); + + return $t; +} + +sub create_user { + my ( $t, $settings ) = @_; + + my $user = join( '', map({ ('a'..'z','A'..'Z')[int rand 52] } ( 0 .. 8)) ); + $t->post_ok( '/register/open', form => { + username => $user, + email => "$user\@blogdb.com", + password => $user, + confirm => $user, + }) + ->get_ok( '/') + ->code_block( sub { + is(shift->stash->{person}->username, $user, "Created test user $user"); + }) + ->code_block( sub { + # Now we're just gonna add whatever settings from $settings. + my $t = shift; + foreach my $key ( keys %{$settings || {}}) { + $t->stash->{person}->setting( $key, $settings->{$key}); + } + }); + + return $t; +} + +sub create_tag { + my ( $t, $tag, $is_adult ) = @_; + + $t->post_ok( '/tags/suggest', form => { + tag => $tag, + ($is_adult ? ( is_adult => 1 ) : ( ) ), + }); + + return $t; +} + +# Storage stack for a run, convenience for stashing stuff. +sub _ss { + my ( $t, $data_stack ) = @_; + $t->{data_stack} = $data_stack; + return $t; +} + +sub _sg { + return shift->{data_stack}; +} + +1; diff --git a/Web/t/01_endpoints/01_auth/01_register_open.t b/Web/t/01_endpoints/01_auth/01_register_open.t new file mode 100644 index 0000000..052e644 --- /dev/null +++ b/Web/t/01_endpoints/01_auth/01_register_open.t @@ -0,0 +1,38 @@ +#!/usr/bin/env perl +use MJB::Web::Test; + +my $t = Test::Mojo::MJB->new('MJB::Web'); + +# Make sure that this registration method is enabled. +$t->app->config->{register}{enable_open} = 1; + +# Try creating an account with an error, ensure we get the error. +$t->post_ok( '/register/open', form => { + name => 'fred', + email => 'fred@blog.com', + password => 'SuperSecure', + password_confirm => 'SuperFail', + })->status_is( 302 + )->code_block( sub { + is( shift->stash->{errors}->[0], 'Password and confirm password must match', 'Expected error thrown' ); + })->code_block( sub { + is( shift->app->db->resultset('Person')->search( { name => 'fred'})->count, 0, 'No user created.'); + }); + +## Try creating a valid account, ensure it exists in the DB. +$t->post_ok( '/register/open', form => { + name => 'fred', + email => 'fred@blog.com', + password => 'SuperSecure', + password_confirm => 'SuperSecure', + })->status_is( 302 + )->code_block( sub { + is( scalar(@{shift->stash->{errors}}), 0, 'No errors' ); + })->code_block( sub { + is( shift->app->db->resultset('Person')->search( { name => 'fred'})->count, 1, 'User created.'); + })->get_ok( '/' + )->code_block( sub { + is(shift->stash->{person}->name, 'fred', 'Got the fred after login...'); + }); + +done_testing();