diff options
26 files changed, 738 insertions, 1 deletions
diff --git a/lib/MGA/Mirrors.pm b/lib/MGA/Mirrors.pm index 03de5c6..dce921a 100644 --- a/lib/MGA/Mirrors.pm +++ b/lib/MGA/Mirrors.pm @@ -16,6 +16,10 @@ use Catalyst qw/ -Debug ConfigLoader Static::Simple + Prototype + Session + Session::State::Cookie + Session::Store::FastMmap /; extends 'Catalyst'; @@ -36,6 +40,7 @@ __PACKAGE__->config( name => 'MGA::Mirrors', # Disable deprecated behavior needed by old applications disable_component_resolution_regex_fallback => 1, + default_view => 'TT', ); # Start the application diff --git a/lib/MGA/Mirrors/Controller/New.pm b/lib/MGA/Mirrors/Controller/New.pm new file mode 100644 index 0000000..fbb1fbe --- /dev/null +++ b/lib/MGA/Mirrors/Controller/New.pm @@ -0,0 +1,125 @@ +package MGA::Mirrors::Controller::New; +use Moose; +use namespace::autoclean; +use URI; + +BEGIN {extends 'Catalyst::Controller'; } + +=head1 NAME + +MGA::Mirrors::Controller::New - Catalyst Controller + +=head1 DESCRIPTION + +Catalyst Controller. + +=head1 METHODS + +=cut + + +=head2 index + +=cut + +sub index :Path :Args(0) { + my ( $self, $c ) = @_; + + if ($c->req->param('url')) { + my $uri = URI->new($c->req->param('url')); + $c->stash->{uri} = $uri; + + if (!($uri->can('host') && $uri->can('scheme'))) { + $c->stash->{subtemplate} = 'new/invalid_uri.tt'; + return; + } + + if (!$c->model('Mirrors')->get_protocol_info($uri->scheme)) { + $c->stash->{subtemplate} = 'new/unsupported_protocol.tt'; + return; + } + + my $urls = $c->model('Mirrors')->find_urls( + { protocol => $uri->scheme, + hostname => $uri->host, }); + if (@{$urls || []}) { + $c->stash->{exists_url} = $urls; + $c->stash->{subtemplate} = 'new/mirror_exists.tt'; + return; + } + + if (!$c->model('Mirrors')->mirror_validity($uri)) { + $c->stash->{subtemplate} = 'new/invalid_mirror.tt'; + return; + } + + if (my @overlap_hosts = $c->model('Mirrors')->find_host_ip_overlap($uri->host)) { + $c->stash->{overlap_hosts} = \@overlap_hosts; + $c->stash->{subtemplate} = 'new/overlap_hosts.tt'; + return; + } + + my @ips = $c->model('Mirrors')->host_ips($uri->host); + + $c->stash->{location} = $c->model('Mirrors')->locate_ips(@ips); + + my $mirror = $c->model('Mirrors')->find_mirrors( + { hostname => $uri->host, }); + if (@{ $mirror || []}) { + $c->stash->{mirror} = $mirror->[0]; + } elsif ($c->req->param('hostinfo')) { + foreach (qw(city country)) { + $c->session->{hostinfo}{$_} = $c->req->param($_); + } + } else { + $c->stash->{subtemplate} = 'new/host_information.tt'; + return; + } + + $c->session->{new_uri} = $uri; + $c->stash->{template} = 'new/confirm.tt'; + } +} + +sub confirm :Path :Args(1) { + my ( $self, $c ) = @_; + $c->stash->{current_view} = 'TTBlock'; + if ($c->session->{new_uri} && $c->req->param('confirm')) { + my $uri = URI->new($c->session->{new_uri}); + my $mirror = $c->model('Mirrors')->find_mirrors( + { hostname => $uri->host, }); + if (!@{$mirror || []}) { + if ($c->session->{hostinfo}) { + $c->model->add_or_update_host( + $uri->host, + city => $c->session->{hostinfo}{city}, + country => $c->session->{hostinfo}{country}, + ); + } else { + return; + } + } + if ($c->model('Mirrors')->add_or_update_url($uri)) { + $c->session->{hostinfo} = undef; + $c->session->{new_uri} = undef; + $c->stash->{template} = 'new/success.tt'; + $c->model('Mirrors')->db->commit; + return; + } + } +} + +=head1 AUTHOR + +Olivier Thauvin + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + +__PACKAGE__->meta->make_immutable; + +1; diff --git a/lib/MGA/Mirrors/Controller/Root.pm b/lib/MGA/Mirrors/Controller/Root.pm index 5decc3a..bbc4d4d 100644 --- a/lib/MGA/Mirrors/Controller/Root.pm +++ b/lib/MGA/Mirrors/Controller/Root.pm @@ -30,7 +30,7 @@ sub index :Path :Args(0) { my ( $self, $c ) = @_; # Hello World - $c->response->body( $c->welcome_message ); + #$c->response->body( $c->welcome_message ); } =head2 default diff --git a/lib/MGA/Mirrors/DB.pm b/lib/MGA/Mirrors/DB.pm new file mode 100644 index 0000000..78b6862 --- /dev/null +++ b/lib/MGA/Mirrors/DB.pm @@ -0,0 +1,364 @@ +package MGA::Mirrors::DB; + +# $Id$ + +use strict; +use warnings; +use Config::IniFiles; +use URI; +use DBI; +use File::Temp qw(tempfile); +use Net::DNS; + +sub configfile { '/etc/mga-mirror.ini' } + +sub new { + my ($class) = @_; + + my $conf = (-f './mga-mirror.ini') + ? Config::IniFiles->new(-file => './mga-mirror.ini') + : Config::IniFiles->new(-file => configfile()) + or return; + + my $db = DBI->connect( + 'dbi:Pg:' . $conf->val('db', 'pgconn', ''), + $conf->val('db', 'user') || undef, + $conf->val('db', 'password') || undef, + { + AutoCommit => 0, + PrintError => 1, + } + ) or return; + + bless { + db => $db, + conf => $conf, + }, $class; +} + +sub host_ips { + my ($self, $hostname) = @_; + + my $resolver = Net::DNS::Resolver->new; + my @addresses; + foreach my $type (qw'A AAAA') { + my $packet = $resolver->search($hostname, $type) or next; + foreach ($packet->answer) { + $_->type eq $type or next; + push(@addresses, $_->address); + } + } + @addresses; +} + +sub db { $_[0]->{db} } + +sub locate_ips { + my ($self, @ips) = @_; + + my $find = $self->db->prepare(q{ + select countries.* from geoip + join countries on geoip.code = countries.code + where ipmin <= $1 and ipmax >= $1 + }); + + foreach (@ips) { + $find->execute($_); + my $res = $find->fetchrow_hashref; + if ($res) { + $find->finish; + return $res; + } + } + + return; +} + +sub country_list { + my ($self) = @_; + my $list = $self->db->prepare(q{ + select * from countries order by name + }); + $list->execute; + return $list->fetchall_arrayref({}); +} + +sub mirror_validity { + my ($self, $uri) = @_; + my $listf = $self->db->prepare(q{ + select * from global_files + }); + $listf->execute; + while (my $res = $listf->fetchrow_hashref) { + my $furi = URI->new($uri . $res->{relpath}); + $self->_check_url($furi) or return; + } + + 1; +} + +sub check_distributions { + my ($self) = @_; + + my $uneeded_check = $self->db->prepare(q{ + select * from mirrors_distributions where + lastcheck > now() - '6 hours'::interval + }); + $uneeded_check->execute(); + my $uch = $uneeded_check->fetchall_hashref([ qw(urlskey distributionkey) ]); + + my $listd = $self->db->prepare(q{ + select * from urls, distributions + where urls.valid = true + }); + + my $addstatus = $self->db->prepare(q{ + insert into mirrors_distributions (urlskey, distributionkey, exists) + values (?,?,?) + }); + + my $updstatus = $self->db->prepare(q{ + update mirrors_distributions set lastcheck = now(), exists = ? + where urlskey = ? and distributionkey = ? + }); + + my %urls_status = (); + + my $updurl = $self->db->prepare(q{ + update urls set lastcheck = now(), valid = ? + where key = ? + }); + + $listd->execute(); + while (my $res = $listd->fetchrow_hashref) { + $uch->{$res->{key}}{$res->{dkey}} and next; + my $url = $self->fmt_url($res); + if (!exists($urls_status{$res->{key}})) { + my $ok = $self->mirror_validity($url); + $updurl->execute($ok ? 1 : 0, $res->{key}); + $urls_status{$res->{key}} = $ok; + } + $urls_status{$res->{key}} or next; + my $furi = URI->new(join('/', $url, $res->{relpath}, $res->{relfile})); + my $exists = $self->_check_url($furi); + if ($updstatus->execute($exists, $res->{key}, $res->{dkey}) == 0) { + $addstatus->execute($res->{key}, $res->{dkey}, $exists); + } + $self->db->commit; + } +} + +sub _check_url { + my ($self, $furi) = @_; + my ($fh, $filename) = tempfile(); + close($fh); + my $cmd = + $furi->scheme =~ /^http|ftp$/ ? "wget -nv -t 1 -T 4 -O $filename " . $furi->as_string : + $furi->scheme eq 'rsync' ? "rsync --timeout 4 -q " . $furi->as_string . " $filename" : ''; + my $ok = (system($cmd) == 0); + unlink($filename); + return $ok +} + +sub get_protocol_info { + my ($self, $protocol) = @_; + my $get = $self->db->prepare(q{ + select * from protocol where name = ? + }); + $get->execute($protocol); + my $res = $get->fetchrow_hashref; + $get->finish; + $res; +} + +sub find_mirrors { + my ($self, $filters, $key) = @_; + + my $query = q{ + select * from hosts + left join countries on countries.code = hosts.country + where hosts.hostname in (select hostname from urls %s) + %s + }; + + my (@mvals, @uvals); + my (@mw, @uw); + if (keys %{ $filters || {}}) { + foreach (keys %$filters) { + $filters->{$_} or next; + if (my $field = { + hostname => 'hosts.hostname', + country => 'countries.code', + continent => 'countries.contienent_code', + }->{$_}) { + push(@mw, sprintf('%s = ?', $field)); + push(@mvals, $filters->{$_}); + } + if (my $field = { + protocol => 'protocol', + }->{$_}) { + push(@uw, sprintf('%s = ?', $field)); + push(@uvals, $filters->{$_}); + } + } + } + my $list = $self->db->prepare(sprintf( + $query, + (@uw ? 'where ' . join(' and ', @uw) : ''), + (@mw ? 'and ' . join(' and ', @mw) : ''), + )); + $list->execute(@uvals, @mvals); + return $list->fetchall_arrayref({}); +} + +sub _find_urls { + my ($self, $filters, $key) = @_; + + my $query = q{ + select urls.* from urls join + hosts on hosts.hostname = urls.hostname + }; + my @vals; + if (keys %{ $filters || {} }) { + $query .= ' where '; + my @w; + foreach (keys %$filters) { + my $field = { + hostname => 'hosts.hostname', + protocol => 'urls.protocol', + }->{$_} or next; + + push(@w, sprintf('%s = ?', $field)); + push(@vals, $filters->{$_}); + } + $query .= join(' and ', @w); + } + my $list = $self->db->prepare($query); + $list->execute(@vals); + return $list->fetchall_arrayref({}); +} + +sub find_host_ip_overlap { + my ($self, $hostname) = @_; + + my @addresses = $self->host_ips($hostname); + + my $list = $self->db->prepare(q{ + select * from ips where ip = any(?) + and hostname != ? + }); + $list->execute(\@addresses, $hostname); + my $res = $list->fetchall_hashref('hostname'); + return keys %{ $res }; +} + +sub add_or_update_host { + my ($self, $hostname, %info) = @_; + + my (@fields, @vals); + while (my ($field, $val) = each(%info)) { + push(@fields, $field); + push(@vals, $val); + } + if (keys %info) { + my $upd = $self->db->prepare(sprintf(q{ + update hosts set %s where hostname = ? + }, join(', ', map { "$_ = ?" } @fields))); + if ($upd->execute(@vals, $hostname) == 0) { + my $add = $self->db->prepare(sprintf(q{ + insert into hosts (%s) values (%s) + }, join(', ', (@fields, 'hostname')), + join(',', ('?') x (scalar(@fields)+1)) + )); + $add->execute(@vals, $hostname) or do { + $self->db->rollback; + return; + }; + } + } + + $self->update_host_ips($hostname); + + 1; +} + +sub add_or_update_url { + my ($self, $uri) = @_; + if (!ref $uri) { + $uri = URI->new($uri); + } + + my $update = $self->db->prepare(q{ + update urls set path = ?, port = ? + where hostname = ? and protocol = ? + }); + + if ($update->execute( + $uri->path, $uri->port == $uri->default_port ? undef : $uri->port, + $uri->host, $uri->scheme + ) == 0) { + my $add = $self->db->prepare(q{ + insert into urls (path, port, hostname, protocol) + values (?,?,?,?) + }); + $add->execute($uri->path, $uri->port == $uri->default_port ? undef : $uri->port, + $uri->host, $uri->scheme) or do { + $self->db->rollback; + return; + } + } + + 1; +} + +sub update_host_ips { + my ($self, $hostname) = @_; + + my @addresses = $self->host_ips($hostname); + my $delete = $self->db->prepare( + q{delete from ips where hostname = ? + and ip != any(?) + } + ); + + $delete->execute($hostname, [ @addresses ]); + + my $getip = $self->db->prepare(q{ + select 1 from ips where hostname = ? and ip = ? + }); + my $addip = $self->db->prepare(q{ + insert into ips (hostname, ip) values (?,?) + }); + foreach (@addresses) { + if ($getip->execute($hostname, $_) == 0) { + $addip->execute($hostname, $_); + } + $getip->finish; + } + + 1; +} + +sub find_urls { + my ($self, $filters, $key) = @_; + return [ + map { $_->{url} = $self->fmt_url($_); $_ } + @{ $self->_find_urls($filters) || []}] +} + +sub fmt_url { + my ($self, $dburl) = @_; + + my $uri = URI->new( + sprintf('%s://%s%s', + $dburl->{protocol}, + $dburl->{hostname}, + $dburl->{path} || '/', + ) + ); + $uri->port($dburl->{port}); + + return $uri->as_string; +} + +1; diff --git a/lib/MGA/Mirrors/Model/Mirrors.pm b/lib/MGA/Mirrors/Model/Mirrors.pm new file mode 100644 index 0000000..c1e1852 --- /dev/null +++ b/lib/MGA/Mirrors/Model/Mirrors.pm @@ -0,0 +1,33 @@ +package MGA::Mirrors::Model::Mirrors; +use Moose; +use namespace::autoclean; + +extends 'MGA::Mirrors::DB', 'Catalyst::Model'; + +=head1 NAME + +MGA::Mirrors::Model::Mirrors - Catalyst Model + +=head1 DESCRIPTION + +Catalyst Model. + +=head1 AUTHOR + +Olivier Thauvin + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + +sub new { + my ($class) = @_; + return bless(MGA::Mirrors::DB->new(), $class); +} + +__PACKAGE__->meta->make_immutable(inline_constructor => 0); + +1; diff --git a/lib/MGA/Mirrors/View/TT.pm b/lib/MGA/Mirrors/View/TT.pm new file mode 100644 index 0000000..f5e2a50 --- /dev/null +++ b/lib/MGA/Mirrors/View/TT.pm @@ -0,0 +1,43 @@ +package MGA::Mirrors::View::TT; + +use strict; +use warnings; +use MGA::Mirrors; + +use base 'Catalyst::View::TT'; + +__PACKAGE__->config( + TEMPLATE_EXTENSION => '.tt', + render_die => 1, + INCLUDE_PATH => [ + MGA::Mirrors->path_to( 'root', 'html', 'includes' ), + MGA::Mirrors->path_to( 'root', 'html', 'pages' ), + ], + PRE_PROCESS => 'header.tt', + POST_PROCESS => 'footer.tt', +); + +=head1 NAME + +MGA::Mirrors::View::TT - TT View for MGA::Mirrors + +=head1 DESCRIPTION + +TT View for MGA::Mirrors. + +=head1 SEE ALSO + +L<MGA::Mirrors> + +=head1 AUTHOR + +Olivier Thauvin + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + +1; diff --git a/lib/MGA/Mirrors/View/TTBlock.pm b/lib/MGA/Mirrors/View/TTBlock.pm new file mode 100644 index 0000000..468a063 --- /dev/null +++ b/lib/MGA/Mirrors/View/TTBlock.pm @@ -0,0 +1,40 @@ +package MGA::Mirrors::View::TTBlock; + +use strict; +use warnings; +use MGA::Mirrors; + +use base 'Catalyst::View::TT'; + +__PACKAGE__->config( + TEMPLATE_EXTENSION => '.tt', + render_die => 1, + INCLUDE_PATH => [ + MGA::Mirrors->path_to( 'root', 'html', 'includes' ), + ], +); + +=head1 NAME + +MGA::Mirrors::View::TT - TT View for MGA::Mirrors + +=head1 DESCRIPTION + +TT View for MGA::Mirrors. + +=head1 SEE ALSO + +L<MGA::Mirrors> + +=head1 AUTHOR + +Olivier Thauvin + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + +1; diff --git a/root/html/includes/footer.tt b/root/html/includes/footer.tt new file mode 100644 index 0000000..2a1c949 --- /dev/null +++ b/root/html/includes/footer.tt @@ -0,0 +1,3 @@ +<!-- $Id$ --> +</body> +</html> diff --git a/root/html/includes/header.tt b/root/html/includes/header.tt new file mode 100644 index 0000000..5319e52 --- /dev/null +++ b/root/html/includes/header.tt @@ -0,0 +1,10 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<!-- $Id$ --> +<head> +<title></title> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +[% c.prototype.define_javascript_functions %] +</head> + +<body> diff --git a/root/html/includes/mirrorslist.tt b/root/html/includes/mirrorslist.tt new file mode 100644 index 0000000..fd855f5 --- /dev/null +++ b/root/html/includes/mirrorslist.tt @@ -0,0 +1,40 @@ +<form action="[% c.uri_for() %]"> +<select name="country"> +<option value="">--</option> +[% FOREACH country = c.model('Mirrors').country_list %] +<option value="[% country.code %]" [% "selected=select" IF country.code == c.req.param('country') %]>[% country.name | html %]</option> +[% END %] +</select> +<input type="submit"> +</form> + +[% db = c.model('Mirrors') %] +[% mirrorslist = db.find_mirrors({ + 'protocol' => c.req.param('protocol'), + 'country' => c.req.param('country'), +}) %] +[% FOREACH item = mirrorslist %] +[% IF loop.first %] +<table border=1> +<tr><th>Server name</th><th>Location</th><th>Urls</th><tr> +[% END %] +<tr> +[% urls = db.find_urls({ "hostname" => item.hostname }) %] +<td> +[% item.hostname | html %] +</td> +<td> +[% IF item.name %] +[% item.continent | html %], [% item.name | html %] +[% END %] +</td> +<td> +[% FOREACH u = urls %] +<a href="[% u.url %]">[% u.protocol %]</a> +[% END %] +</td> +</tr> +[% IF loop.last %] +</table> +[% END %] +[% END %] diff --git a/root/html/includes/new/checkurl.tt b/root/html/includes/new/checkurl.tt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/root/html/includes/new/checkurl.tt @@ -0,0 +1 @@ + diff --git a/root/html/includes/new/confirm.tt b/root/html/includes/new/confirm.tt new file mode 100644 index 0000000..b3eb3f3 --- /dev/null +++ b/root/html/includes/new/confirm.tt @@ -0,0 +1,6 @@ +<div id="foo"> +[% c.prototype.form_remote_tag({ url => c.uri_for('confirm'), update => 'foo' } ) %] +<input type="hidden" name="confirm" value="1"> +<input type="submit"> +</form> +</div> diff --git a/root/html/includes/new/host_information.tt b/root/html/includes/new/host_information.tt new file mode 100644 index 0000000..78c04c2 --- /dev/null +++ b/root/html/includes/new/host_information.tt @@ -0,0 +1,19 @@ +Enter Info for [% uri.host %] + +<form action="[% c.uri_for() %]" method="POST"> +<input type="hidden" name="url" value="[% uri | html %]"> +<input type="hidden" name="hostinfo" value="1"> + +[% location.name %] / [% location.continent %]<br> + +Country: +<select name="country"> +<option value="">--</option> +[% FOREACH country = c.model('Mirrors').country_list %] +<option value="[% country.code %]" [% "selected=select" IF country.code == location.code %]>[% country.name | html %]</option> +[% END %] +</select> + +City: <input type="text" name="city"> +<input type="submit"> +</form> diff --git a/root/html/includes/new/invalid_mirror.tt b/root/html/includes/new/invalid_mirror.tt new file mode 100644 index 0000000..f22d0f3 --- /dev/null +++ b/root/html/includes/new/invalid_mirror.tt @@ -0,0 +1 @@ +This url seems to not contain a valid mirror. diff --git a/root/html/includes/new/invalid_uri.tt b/root/html/includes/new/invalid_uri.tt new file mode 100644 index 0000000..87ced3c --- /dev/null +++ b/root/html/includes/new/invalid_uri.tt @@ -0,0 +1 @@ +[% uri %] is not a valid url. diff --git a/root/html/includes/new/mirror_exists.tt b/root/html/includes/new/mirror_exists.tt new file mode 100644 index 0000000..f891993 --- /dev/null +++ b/root/html/includes/new/mirror_exists.tt @@ -0,0 +1 @@ +<p>The url [% uri | html %] has same server and same protocol than [% exists_url.0.url %].</p> diff --git a/root/html/includes/new/overlap_hosts.tt b/root/html/includes/new/overlap_hosts.tt new file mode 100644 index 0000000..3d60603 --- /dev/null +++ b/root/html/includes/new/overlap_hosts.tt @@ -0,0 +1 @@ +This server seems to be the same than [% overlap_hosts.join(', ') | html %]. diff --git a/root/html/includes/new/success.tt b/root/html/includes/new/success.tt new file mode 100644 index 0000000..56d757d --- /dev/null +++ b/root/html/includes/new/success.tt @@ -0,0 +1,3 @@ +Host added + +[% INCLUDE 'new/url_form.tt' %] diff --git a/root/html/includes/new/unsupported_protocol.tt b/root/html/includes/new/unsupported_protocol.tt new file mode 100644 index 0000000..7552c82 --- /dev/null +++ b/root/html/includes/new/unsupported_protocol.tt @@ -0,0 +1 @@ +Unsuported protocol diff --git a/root/html/includes/new/url_form.tt b/root/html/includes/new/url_form.tt new file mode 100644 index 0000000..f8840b9 --- /dev/null +++ b/root/html/includes/new/url_form.tt @@ -0,0 +1,5 @@ +<form action="[% c.uri_for() %]" method="POST"> +Enter the url to the top level mirror tree:<br> +<input type="text" name="url" size=40 value="[% c.req.param('url') | html %]"> +<input type=submit> +</form> diff --git a/root/html/pages/index.tt b/root/html/pages/index.tt new file mode 100644 index 0000000..f1f0251 --- /dev/null +++ b/root/html/pages/index.tt @@ -0,0 +1,6 @@ +<!-- $Id$ --> +<p>Mageia mirrors database</p> + +<p>Mirror not found ? <a href="[% c.uri_for('/new') %]">register it</a></p> + +[% INCLUDE 'mirrorslist.tt' %] diff --git a/root/html/pages/new/index.tt b/root/html/pages/new/index.tt new file mode 100644 index 0000000..0ef4cfd --- /dev/null +++ b/root/html/pages/new/index.tt @@ -0,0 +1,5 @@ +[% INCLUDE 'new/url_form.tt' %] + +[% IF subtemplate %] +[% INCLUDE $subtemplate %] +[% END %] diff --git a/root/static/style.css b/root/static/style.css new file mode 100644 index 0000000..cfa1da3 --- /dev/null +++ b/root/static/style.css @@ -0,0 +1 @@ +// $Id$ diff --git a/t/controller_New.t b/t/controller_New.t new file mode 100644 index 0000000..64ecee3 --- /dev/null +++ b/t/controller_New.t @@ -0,0 +1,9 @@ +use strict; +use warnings; +use Test::More; + +BEGIN { use_ok 'Catalyst::Test', 'MGA::Mirrors' } +BEGIN { use_ok 'MGA::Mirrors::Controller::New' } + +ok( request('/new')->is_success, 'Request should succeed' ); +done_testing(); diff --git a/t/model_Mirrors.t b/t/model_Mirrors.t new file mode 100644 index 0000000..e09d845 --- /dev/null +++ b/t/model_Mirrors.t @@ -0,0 +1,7 @@ +use strict; +use warnings; +use Test::More; + +BEGIN { use_ok 'MGA::Mirrors::Model::Mirrors' } + +done_testing(); diff --git a/t/view_TT.t b/t/view_TT.t new file mode 100644 index 0000000..34c2283 --- /dev/null +++ b/t/view_TT.t @@ -0,0 +1,7 @@ +use strict; +use warnings; +use Test::More; + +BEGIN { use_ok 'MGA::Mirrors::View::TT' } + +done_testing(); |