[Rt-commit] r5423 - in Test-Chimps: . trunk trunk/bin trunk/examples trunk/lib/Test/Smoke/Report

zev at bestpractical.com zev at bestpractical.com
Fri Jun 23 17:32:35 EDT 2006


Author: zev
Date: Fri Jun 23 17:32:32 2006
New Revision: 5423

Added:
   Test-Chimps/trunk/examples/
   Test-Chimps/trunk/examples/list.tmpl
Modified:
   Test-Chimps/   (props changed)
   Test-Chimps/trunk/Makefile.PL
   Test-Chimps/trunk/bin/receive_report.pl
   Test-Chimps/trunk/lib/Test/Smoke/Report.pm
   Test-Chimps/trunk/lib/Test/Smoke/Report/Client.pm
   Test-Chimps/trunk/lib/Test/Smoke/Report/Server.pm

Log:
 r4187 at galvatron (orig r4):  zev | 2006-06-20 17:58:25 -0400
  r4127 at galvatron:  zev | 2006-06-18 22:17:12 -0400
  listing works
 


Modified: Test-Chimps/trunk/Makefile.PL
==============================================================================
--- Test-Chimps/trunk/Makefile.PL	(original)
+++ Test-Chimps/trunk/Makefile.PL	Fri Jun 23 17:32:32 2006
@@ -6,7 +6,7 @@
 
 # Specific dependencies
 requires('Algorithm::TokenBucket');
-requires('HTML::Template');
+requires('HTML::Mason');
 requires('LWP::UserAgent');
 requires('Module::CoreList');
 requires('Params::Validate');

Modified: Test-Chimps/trunk/bin/receive_report.pl
==============================================================================
--- Test-Chimps/trunk/bin/receive_report.pl	(original)
+++ Test-Chimps/trunk/bin/receive_report.pl	Fri Jun 23 17:32:32 2006
@@ -4,6 +4,50 @@
 
 use Test::Smoke::Report::Server;
 
-my $server = Test::Smoke::Report::Server->new(base_dir => '/var/www/bps-smokes');
+my $server = Test::Smoke::Report::Server->new(base_dir => '/var/www/bps-smokes',
+                                              validate_extra =>
+                                                   { base_dir =>
+       { type => SCALAR,
+         optional => 0 },
+       bucket_file =>
+       { type => SCALAR,
+         default => 'bucket.dat',
+         optional => 1 },
+       burst_rate =>
+       { type => SCALAR,
+         optional => 1,
+         default => 5,
+         callbacks =>
+         { "greater than or equal to 0" =>
+           sub { $_[0] >= 0 }} },
+       max_rate =>
+       { type => SCALAR,
+         default => (1 / 30),
+         optional => 1,
+         callbacks =>
+         {"greater than or equal to 0" =>
+          sub { $_[0] >= 0 }} },
+       max_size =>
+       { type => SCALAR,
+         default => 2**20 * 3.0,
+         optional => 1,
+         callbacks =>
+         { "greater than or equal to 0" =>
+           sub { $_[0] >= 0 }} },
+       max_smokes_same_category =>
+       { type => SCALAR,
+         default => 5,
+         optional => 1,
+         callbacks =>
+         { "greater than or equal to 0" =>
+           sub { $_[0] >= 0 }} },
+       report_dir =>
+       { type => SCALAR,
+         default => 'reports',
+         optional => 1 },
+       validate_extra =>
+       { type => HASHREF,
+         optional => 1 }});
+
 
 $server->handle_request;

Added: Test-Chimps/trunk/examples/list.tmpl
==============================================================================
--- (empty file)
+++ Test-Chimps/trunk/examples/list.tmpl	Fri Jun 23 17:32:32 2006
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+  <title>Smoke Reports</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+  <style type="text/css">
+    body {
+      background-color: white;
+      margin:           0;
+
+      font-family: sans-serif;
+      line-height: 1.3em;
+      font-size:   95%;
+    }
+
+    h1, h2 {
+      background-color: #313052;
+      color:            white;
+      padding:          10px;
+    }
+
+    th       { text-align: left; }
+    .category       { padding-top:  30px; border-bottom: 2px solid #313052; }
+    .subcategory    { padding-top:  10px; border-bottom: 1px solid #313052; }
+    .report_summary { padding-left: 40px; }
+    .report_details { padding-left: 80px; padding-bottom: 10px; }
+
+    p, dl, pre, table { margin:      15px; }
+    dt    { font-weight: bold; }
+    dd+dt { margin-top:  1em;  }
+    .leftsep  { padding-left: 10px;  }
+    .num      { text-align:   right; }
+
+    .details  { display: none; }
+    .expander { color: blue; cursor: pointer; }  /* hack? */
+
+    .tests_ok       { color: #050; }
+    .tests_failed   { color: #500; }
+    .tests_todo     { color: #030; }
+    .tests_skipped  { color: #555; }
+    .tests_unexpect { color: #550; }
+  </style>
+
+  <script type="text/javascript">//<![CDATA[[
+    function toggle_visibility (id) {
+      var elem     = document.getElementById("details_"  + id),
+          expander = document.getElementById("expander_" + id);
+      if(elem.className == "details") {
+	elem.className = "";  /* hack? */
+	expander.innerHTML = "&laquo;";
+      } else {
+	elem.className = "details";
+	expander.innerHTML = "&raquo;";
+      }
+    }
+  //]]></script>
+</head>
+
+<body>
+  <h1>Smoke Reports</h1>
+
+  <p>
+    Note that old smoke reports may be automatically deleted, so you may not want
+    to link directly to a smoke.
+  </p>
+
+  <p>
+    Timezone is UTC
+  </p>
+ 
+  <table>
+% foreach my $category (keys %categories) {
+      <tr><th colspan="11" class="category"><% $category %></th></tr>
+% foreach my $subcategory (keys %{$categories{$category}}) {
+        <tr><th colspan="11" class="subcategory"><% $subcategory %></th></tr>
+% foreach my $report (@{$categories{$category}->{$subcategory}}) {
+% my $id = 5;
+% my $data = $report->extra_data;
+% my $model = Test::TAP::Model::Visual->new_with_struct($report->model_structure);
+          <tr>
+            <td class="report_summary"><% $data->{project} %></td>
+            <td>
+              r<% $data->{revision} %>
+            </td>
+            <td class="leftsep"><% $data->{timestamp} %></td>
+            <td class="leftsep num"><% $data->{duration} %></td>
+            <td class="leftsep num"><% $model->total_ratio %>>&nbsp;%&nbsp;ok</td>
+	    <td class="leftsep num tests_total"><span title="<% $model->total_seen %> total"><% $model->total_seen %></span>:</td>
+	    <td class="num tests_ok"><span title="<% $model->total_ok %> ok"><% $model->total_ok %></span>,</td>
+	    <td class="num tests_failed"><span title="<% $model->total_failed %> failed"><% $model->total_failed %></span>,</td>
+	    <td class="num tests_todo"><span title="<% $model->total_todo %> todo"><% $model->total_todo %></span>,</td>
+	    <td class="num tests_skipped"><span title="<% $model->total_skipped %> skipped"><% $model->total_skipped %></span>,</td>
+	    <td class="num tests_unexpect"><span title="<% $model->total_unexpectedly_succeeded %> unexpectedly succeeded"><% $model->total_unexpectedly_succeeded %></span></td>
+	    <td><span title="Details" class="expander" onclick="toggle_visibility('<% $id %>')" id="expander_<% $id %>">&raquo;</span></td>
+	    <td><a style="text-decoration: none" href="<tmpl_var name=link>" title="Full smoke report">&raquo;</a></td>
+          </tr>
+          <tr class="details" id="details_<% $id %>">
+            <td colspan="11" class="report_details">
+                <span class="tests_total"><% $model->total_seen %> test cases</span>:<br />
+		<span class="tests_ok"><% $model->total_ok %> ok</span>,
+		<span class="tests_failed"><% $model->total_failed %> failed</span>,
+		<span class="tests_todo"><% $model->total_todo %> todo</span>,<br />
+                <span class="tests_skipped"><% $model->total_skipped %> skipped</span> and
+		<span class="tests_unexpect"><% $model->total_unexpectedly_succeeded %> unexpectedly succeeded</span>
+              <br />
+              <a href="<tmpl_var name=link>" title="Full smoke report">View full smoke report</a>
+            </td>
+          </tr>
+% }
+% }
+% }
+  </table>
+</body>
+</html>
+
+<%args>
+ at reports
+</%args>
+
+<%init>
+my %categories;
+foreach my $report (@reports) {
+  my $data = $report->extra_data;
+  $categories{$data->{category}}->{$data->{subcategory}} = $report;
+}
+</%init>

Modified: Test-Chimps/trunk/lib/Test/Smoke/Report.pm
==============================================================================
--- Test-Chimps/trunk/lib/Test/Smoke/Report.pm	(original)
+++ Test-Chimps/trunk/lib/Test/Smoke/Report.pm	Fri Jun 23 17:32:32 2006
@@ -4,8 +4,9 @@
 use strict;
 
 use Carp;
-use Params::Validate;
+use Params::Validate qw/:all/;
 use Test::TAP::HTMLMatrix;
+use YAML::Syck;
 
 =head1 NAME
 
@@ -40,13 +41,26 @@
 
 =head2 new ARGS
 
-Creates a new Report.  ARGS is a hash whose valid keys are C<model>
-and C<report_text>.  C<model> is mandatory and must be an instance
-of C<Test::Tap::Model>.  C<report_text> is an optional free-form
-report.  If not supplied, it is filled in using
-C<Test::TAP::HTMLMatrix>.  Note that if you are using this class in
-conjunction with C<Test::Smoke::Report::Server>, C<report_text>
-should probably be HTML.
+Creates a new Report.  ARGS is a hash whose valid keys are:
+
+=over 4
+
+=item * model
+Mandatory and must be an instance of C<Test::Tap::Model>.
+
+=item * report_text
+
+A free-form report.  If not supplied, it is filled in using
+C<Test::TAP::HTMLMatrix>, and C<extra_data> will be passed as the
+C<extra> argument to its constructor.  Note that if you are using
+this class in conjunction with C<Test::Smoke::Report::Server>,
+C<report_text> should probably be HTML.
+
+=item * extra_data
+
+Extra data to be transmitted with the report.  
+
+=back
 
 =cut
 
@@ -59,10 +73,16 @@
 
 sub _init {
   my $self = shift;
-  validate(@_,
-           { model =>
-             { isa => 'Test::TAP::Model'},
-             report_text => 0 });
+  validate_with(params => \@_,
+                spec =>
+                { model =>
+                  {
+                   isa => 'Test::TAP::Model'},
+                  report_text => 0,
+                  extra_data =>
+                  { optional => 1,
+                    type => HASHREF } },
+                called => 'The Test::Smoke::Report constructor');
 
   my %args = @_;
 
@@ -70,7 +90,15 @@
   if (defined $args{report_text}) {
     $self->{report_text} = $args{report_text};
   } else {
-    my $v = Test::TAP::HTMLMatrix->new($args{model});
+    my $v;
+    if (defined $args{extra_data}) {
+      $v = Test::TAP::HTMLMatrix->new($args{model},
+                                         Dump($args{extra}));
+      $self->{extra_data} = $args{extra_data};
+    } else {
+      $v = Test::TAP::HTMLMatrix->new($args{model});
+      $self->{extra_data} = '';
+    }      
     $self->{report_text} = $v->detail_html;
   }
 }
@@ -97,6 +125,17 @@
   return $self->{report_text};
 }
 
+=head2 extra_data
+
+Accessor for any extra data passed in.
+
+=cut
+
+sub extra_data {
+  my $self = shift;
+  return $self->{extra_data};
+}
+
 =head1 AUTHOR
 
 Zev Benjamin, C<< <zev at cpan.org> >>

Modified: Test-Chimps/trunk/lib/Test/Smoke/Report/Client.pm
==============================================================================
--- Test-Chimps/trunk/lib/Test/Smoke/Report/Client.pm	(original)
+++ Test-Chimps/trunk/lib/Test/Smoke/Report/Client.pm	Fri Jun 23 17:32:32 2006
@@ -84,11 +84,13 @@
 
 sub _init {
   my $self = shift;
-  validate(@_,
-           { reports =>
-            { type => ARRAYREF },
-             server => 1,
-             compress => 0});
+  validate_with(params => \@_,
+                spec => 
+                { reports =>
+                  { type => ARRAYREF },
+                  server => 1,
+                  compress => 0},
+                called => 'The Test::Smoke::Report::Client constructor');
   
   my %args = @_;
   $self->{reports} = $args{reports};

Modified: Test-Chimps/trunk/lib/Test/Smoke/Report/Server.pm
==============================================================================
--- Test-Chimps/trunk/lib/Test/Smoke/Report/Server.pm	(original)
+++ Test-Chimps/trunk/lib/Test/Smoke/Report/Server.pm	Fri Jun 23 17:32:32 2006
@@ -9,11 +9,12 @@
 use Digest::MD5 qw<md5_hex>;
 use File::Spec;
 use Fcntl       qw<:DEFAULT :flock>;
-use HTML::Template;
+use HTML::Mason;
 use Params::Validate qw<:all>;
 use Storable    qw<store_fd fd_retrieve freeze>;
 use Time::Piece;
 use Time::Seconds;
+use YAML::Syck;
 
 use constant PROTO_VERSION => 0.1;
 
@@ -62,6 +63,11 @@
 Burst upload rate allowed (see L<Algorithm::Bucket>).  Defaults to
 5.
 
+=item * list_template
+
+Template filename under base_dir/template_dir to use for listing
+smoke reports.  Defaults to 'list.tmpl'.
+
 =item * max_rate
 
 Maximum upload rate allowed (see L<Algorithm::Bucket>).  Defaults
@@ -72,15 +78,26 @@
 Maximum size of HTTP POST that will be accepted.  Defaults to 3
 MiB.
 
-=item * max_smokes_same_category
+=item * max_smokes_per_subcategory
 
 Maximum number of smokes allowed per category.  Defaults to 5.
 
 =item * report_dir
 
-Directory under basedir where smoke reports will be stored.
+Directory under base_dir where smoke reports will be stored.
 Defaults to 'reports'.
 
+=item * template_dir
+
+Directory under base_dir where html templates will be stored.
+Defaults to 'templates'.
+
+=item * validate_extra
+
+A hash reference in the form accepted by Params::Validate.  If
+supplied, this will be used to validate the extra data submitted to
+the server.
+
 =back
 
 =cut
@@ -88,7 +105,8 @@
 {
   no strict 'refs';
   our @fields = qw/base_dir bucket_file max_rate max_size
-                   max_smokes_same_category report_dir/;
+                   max_smokes_per_subcategory report_dir
+                   template_dir list_template validate_extra/;
 
   foreach my $field (@fields) {
     *{$field} =
@@ -108,46 +126,64 @@
 
 sub _init {
   my $self = shift;
-  my %args = validate(@_,
-                      { base_dir =>
-                        { type => SCALAR,
-                          optional => 0 },
-                        bucket_file =>
-                        { type => SCALAR,
-                          default => 'bucket.dat',
-                          optional => 1 },
-                        burst_rate =>
-                        { type => SCALAR,
-                          optional => 1,
-                          default => 5,
-                          callbacks =>
-                          { "greater than or equal to 0" =>
-                            sub { $_[0] >= 0 }} },
-                        max_rate =>
-                        { type => SCALAR,
-                          default => (1 / 30),
-                          optional => 1,
-                          callbacks =>
-                          {"greater than or equal to 0" =>
-                           sub { $_[0] >= 0 }} },
-                        max_size =>
-                        { type => SCALAR,
-                          default => 2**20 * 3.0,
-                          optional => 1,
-                          callbacks =>
-                          { "greater than or equal to 0" =>
-                            sub { $_[0] >= 0 }} },
-                        max_smokes_same_category =>
-                        { type => SCALAR,
-                          default => 5,
-                          optional => 1,
-                          callbacks =>
-                          { "greater than or equal to 0" =>
-                            sub { $_[0] >= 0 }} },
-                        report_dir =>
-                        { type => SCALAR,
-                          default => 'reports',
-                          optional => 1 } });
+  my %args = validate_with
+    (params => \@_,
+     called => 'The Test::Smoke::Report::Server constructor',
+     spec => 
+     { base_dir =>
+       { type => SCALAR,
+         optional => 0 },
+       bucket_file =>
+       { type => SCALAR,
+         default => 'bucket.dat',
+         optional => 1 },
+       burst_rate =>
+       { type => SCALAR,
+         optional => 1,
+         default => 5,
+         callbacks =>
+         { "greater than or equal to 0" =>
+           sub { $_[0] >= 0 }} },
+       list_template =>
+       { type => SCALAR,
+         optional => 1,
+         default => 'list.tmpl' },
+       max_rate =>
+       { type => SCALAR,
+         default => (1 / 30),
+         optional => 1,
+         callbacks =>
+         {"greater than or equal to 0" =>
+          sub { $_[0] >= 0 }} },
+       max_size =>
+       { type => SCALAR,
+         default => 2**20 * 3.0,
+         optional => 1,
+         callbacks =>
+         { "greater than or equal to 0" =>
+           sub { $_[0] >= 0 }} },
+       max_smokes_per_subcategory =>
+       { type => SCALAR,
+         default => 5,
+         optional => 1,
+         callbacks =>
+         { "greater than or equal to 0" =>
+           sub { $_[0] >= 0 }} },
+       pre_add_hook =>
+       { type => CODEREF,
+         optional => 1 },
+       report_dir =>
+       { type => SCALAR,
+         default => 'reports',
+         optional => 1 },
+       template_dir =>
+       { type => SCALAR,
+         default => 'templates',
+         optional => 1 },
+       validate_extra =>
+       { type => HASHREF,
+         optional => 1 }
+     });
   
   foreach my $key (%args) {
     $self->{$key} = $args{$key};
@@ -168,7 +204,7 @@
   if ($cgi->param("upload")) {
     $self->_process_upload($cgi);
   } else {
-    $self->_process_listing();
+    $self->_process_listing($cgi);
   }
 }
 
@@ -178,7 +214,8 @@
 
   print $cgi->header("text/plain");
   $self->_limit_rate($cgi);
-  $self->_validate_params($cgi);
+  $self->_validate_params($cgi);  
+  $self->_validate_extra($cgi);
   $self->_add_report($cgi);
   $self->_clean_old_reports($cgi);
 
@@ -236,6 +273,28 @@
 #  uncompress_smoke();
 }
 
+sub _validate_extra {
+  my $self = shift;
+  my $cgi = shift;
+  
+  my @reports = map { Load($_) } $cgi->param("reports");
+  
+  if (defined $self->{validate_extra}) {
+    foreach my $report (@reports) {
+      eval {
+        validate(@{$report->{extra_data}}, $self->{validate_extra});
+      };
+      if ($@) {
+        # XXX: doesn't dump subroutines because we're using YAML::Syck
+        print "This server accepts extra parameters.  It's validation ",
+          "string looks like this:\n", Dump($self->{validate_extra});
+        exit;
+      }
+
+    }
+  }
+}
+
 sub _add_report {
   my $self = shift;
   my $cgi = shift;
@@ -265,6 +324,24 @@
   # XXX: stub
 }
 
+sub _process_listing {
+  my $self = shift;
+  my $cgi = shift;
 
+  print $cgi->header("text/html");
 
+  my @reports = map { bless LoadFile($_), 'Test::Smoke::Report' }
+    glob File::Spec->catfile($self->{base_dir},
+                             $self->{report_dir},
+                             "*.yml");
+
+  my $interp = HTML::Mason::Interp->new(comp_root =>
+                                        File::Spec->catfile($self->{base_dir},
+                                                            $self->{template_dir}));
+  $interp->exec(File::Spec->catfile('/' . $self->{list_template}),
+                reports => \@reports);
+  
+}
+
+  
 1;


More information about the Rt-commit mailing list