lab_bench 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -1,7 +1,12 @@
1
1
  source "http://rubygems.org"
2
+
2
3
  # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
4
+ gem 'haml', '~> 2.2.0'
5
+ gem 'sinatra', '~> 1.1.0'
6
+ gem 'eventmachine', '~> 0.12.10'
7
+ gem 'em-websocket', '~> 0.2.0'
8
+ gem 'thin', '~> 1.2.0'
9
+ gem 'yajl-ruby', '~> 0.7.8'
5
10
 
6
11
  # Add dependencies to develop your gem here.
7
12
  # Include everything needed to run rake, tests, features, etc.
@@ -10,4 +15,5 @@ group :development do
10
15
  gem "bundler", "~> 1.0.0"
11
16
  gem "jeweler", "~> 1.5.1"
12
17
  gem "rcov", ">= 0"
18
+ gem 'hpricot'
13
19
  end
data/Gemfile.lock CHANGED
@@ -1,20 +1,45 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ addressable (2.2.2)
5
+ daemons (1.1.0)
6
+ em-websocket (0.2.0)
7
+ addressable (>= 2.1.1)
8
+ eventmachine (>= 0.12.9)
9
+ eventmachine (0.12.10)
4
10
  git (1.2.5)
11
+ haml (2.2.24)
12
+ hpricot (0.8.3)
5
13
  jeweler (1.5.1)
6
14
  bundler (~> 1.0.0)
7
15
  git (>= 1.2.5)
8
16
  rake
17
+ rack (1.2.1)
9
18
  rake (0.8.7)
10
19
  rcov (0.9.9)
11
20
  shoulda (2.11.3)
21
+ sinatra (1.1.0)
22
+ rack (~> 1.1)
23
+ tilt (~> 1.1)
24
+ thin (1.2.7)
25
+ daemons (>= 1.0.9)
26
+ eventmachine (>= 0.12.6)
27
+ rack (>= 1.0.0)
28
+ tilt (1.1)
29
+ yajl-ruby (0.7.8)
12
30
 
13
31
  PLATFORMS
14
32
  ruby
15
33
 
16
34
  DEPENDENCIES
17
35
  bundler (~> 1.0.0)
36
+ em-websocket (~> 0.2.0)
37
+ eventmachine (~> 0.12.10)
38
+ haml (~> 2.2.0)
39
+ hpricot
18
40
  jeweler (~> 1.5.1)
19
41
  rcov
20
42
  shoulda
43
+ sinatra (~> 1.1.0)
44
+ thin (~> 1.2.0)
45
+ yajl-ruby (~> 0.7.8)
data/README.rdoc CHANGED
@@ -2,8 +2,28 @@
2
2
 
3
3
  A browser-based runner for ruby Test::Unit tests.
4
4
 
5
+ == Usage
6
+
7
+ Install the gem:
8
+
9
+ <tt>gem install lab_bench</tt>
10
+
11
+ If you're using Rails 2.x, add this to config/environment.rb:
12
+
13
+ <tt>config.gem 'lab_bench'</tt>
14
+
15
+ Start the server in a new console / screen:
16
+
17
+ <tt>lab_bench_server</tt>
18
+
19
+ Send your browser to http://localhost:9020/ then run your tests like this:
20
+
21
+ <tt>rake test TESTOPTS="--runner=lab_bench"</tt>
22
+
5
23
  == TODO
6
24
 
25
+ * Buffer test events in server and replay to new browser clients so they can start "hot"
26
+ * Browser should show whether it is connected to the server and reconnect if it dies
7
27
  * Show me test failures as they happen
8
28
  * Give me more context on the test suite (names of files being run, command line, project directory, etc)
9
29
  * Allow me to rerun a suite
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
data/assets/css/app.css CHANGED
@@ -1,9 +1,35 @@
1
+ appstatus {
2
+ display: block;
3
+ height: 5%;
4
+ position: fixed;
5
+ top: 0;
6
+ left: 0;
7
+ right: 0;
8
+ padding: 2px;
9
+ padding-left: 30px;
10
+ background-image: url(/images/disconnect.png);
11
+ background-repeat: no-repeat;
12
+ background-position: 6px 13px;
13
+ background-color: #222;
14
+ color: white;
15
+ font-size: 1.6em;
16
+ line-height: 1.6em;
17
+ }
18
+
19
+ appstatus.backfilling {
20
+ background-image: url(/images/spinner.gif);
21
+ }
22
+
23
+ appstatus.realtime {
24
+ background-image: url(/images/connect.png);
25
+ }
26
+
1
27
  testruns {
2
28
  display: block;
3
29
  overflow-y: scroll;
4
- height: 65%;
30
+ height: 60%;
5
31
  position: fixed;
6
- top: 0;
32
+ top: 6%;
7
33
  left: 0;
8
34
  right: 0;
9
35
  }
Binary file
Binary file
data/assets/js/app.js CHANGED
@@ -31,58 +31,64 @@ head.ready(function(){
31
31
  socket.onmessage = function(jsonMessage) {
32
32
  if (jsonMessage && jsonMessage.data) {
33
33
  var message = $.parseJSON(jsonMessage.data);
34
+
35
+ if (_.isEqual(message, ['backfilling'])) {
36
+ $('appstatus').attr('class', 'backfilling');
37
+ } else if (_.isEqual(message,['realtime'])) {
38
+ $('appstatus').attr('class', 'realtime');
39
+ } else {
40
+ // append message to event log
41
+ message.timestamp = new Date(message.milliseconds).toLocaleTimeString();
42
+ var template = templates[message.event];
43
+ $('eventlog')
44
+ .append(Mustache.to_html(template, message))
45
+ .scrollTop($('eventlog').attr('scrollHeight') - $('eventlog').height());
34
46
 
35
- // append message to event log
36
- message.timestamp = new Date(message.milliseconds).toLocaleTimeString();
37
- var template = templates[message.event];
38
- $('eventlog')
39
- .append(Mustache.to_html(template, message))
40
- .scrollTop($('eventlog').attr('scrollHeight') - $('eventlog').height());
41
-
42
- // find or create the corresponding suite
43
- var guid = message.guid;
44
- if ($('#' + guid).length == 0) {
45
- $('testruns').prepend('<testrun id=' + guid + '>');
46
- }
47
+ // find or create the corresponding suite
48
+ var guid = message.guid;
49
+ if ($('#' + guid).length == 0) {
50
+ $('testruns').prepend('<testrun id=' + guid + '>');
51
+ }
47
52
 
48
- // update its data based on the event
49
- var testrun = $('#' + guid);
50
- var testrunData = testrun.data();
51
- if (message.event === "Test::Unit::UI::TestRunnerMediator::STARTED") {
52
- testrunData.guid = guid;
53
- testrunData.timestamp = new Date(message.milliseconds).toLocaleTimeString();
54
- testrunData.status = 'Initializing';
55
- testrunData.testCount = 0;
56
- testrunData.failedCount = 0;
57
- } else if (message.event === "Test::Unit::TestCase::STARTED") {
58
- testrunData.status = 'Running';
59
- testrunData.currentTest = message.args;
60
- testrunData.running = true;
61
- } else if (message.event === "FAULT") {
62
- testrunData.failedCount += 1;
63
- } else if (message.event === "Test::Unit::TestCase::FINISHED") {
64
- testrunData.running = false;
65
- testrunData.testCount += 1;
66
- } else if (message.event === "Test::Unit::UI::TestRunnerMediator::FINISHED") {
67
- if (testrunData.failedCount == 0) {
68
- testrunData.status = 'Success';
69
- } else {
70
- testrunData.status = 'Failed';
53
+ // update its data based on the event
54
+ var testrun = $('#' + guid);
55
+ var testrunData = testrun.data();
56
+ if (message.event === "Test::Unit::UI::TestRunnerMediator::STARTED") {
57
+ testrunData.guid = guid;
58
+ testrunData.timestamp = new Date(message.milliseconds).toLocaleTimeString();
59
+ testrunData.status = 'Initializing';
60
+ testrunData.testCount = 0;
61
+ testrunData.failedCount = 0;
62
+ } else if (message.event === "Test::Unit::TestCase::STARTED") {
63
+ testrunData.status = 'Running';
64
+ testrunData.currentTest = message.args;
65
+ testrunData.running = true;
66
+ } else if (message.event === "FAULT") {
67
+ testrunData.failedCount += 1;
68
+ } else if (message.event === "Test::Unit::TestCase::FINISHED") {
69
+ testrunData.running = false;
70
+ testrunData.testCount += 1;
71
+ } else if (message.event === "Test::Unit::UI::TestRunnerMediator::FINISHED") {
72
+ if (testrunData.failedCount == 0) {
73
+ testrunData.status = 'Success';
74
+ } else {
75
+ testrunData.status = 'Failed';
76
+ }
71
77
  }
72
- }
73
78
 
74
- // rerender the suite based on the updated data
75
- testrun.html(Mustache.to_html("\
76
- <testrunsummary class='{{status}}'> \
77
- <started>Test Run Started {{timestamp}} - {{status}}</started> \
78
- {{#running}} \
79
- <currenttest>Current Test: {{currentTest}}</currenttest> \
80
- {{/running}} \
81
- <statistics> \
82
- <testcount>{{testCount}} total test(s)</testcount> \
83
- <failedcount>{{failedCount}} failure(s)</failedcount> \
84
- </statistics> \
85
- </testrunsummary>", testrunData));
79
+ // rerender the suite based on the updated data
80
+ testrun.html(Mustache.to_html("\
81
+ <testrunsummary class='{{status}}'> \
82
+ <started>Test Run Started {{timestamp}} - {{status}}</started> \
83
+ {{#running}} \
84
+ <currenttest>Current Test: {{currentTest}}</currenttest> \
85
+ {{/running}} \
86
+ <statistics> \
87
+ <testcount>{{testCount}} total test(s)</testcount> \
88
+ <failedcount>{{failedCount}} failure(s)</failedcount> \
89
+ </statistics> \
90
+ </testrunsummary>", testrunData));
91
+ }
86
92
  }
87
93
  };
88
94
  });
@@ -0,0 +1,25 @@
1
+ // Underscore.js 1.1.3
2
+ // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
3
+ // Underscore is freely distributable under the MIT license.
4
+ // Portions of Underscore are inspired or borrowed from Prototype,
5
+ // Oliver Steele's Functional, and John Resig's Micro-Templating.
6
+ // For all details and documentation:
7
+ // http://documentcloud.github.com/underscore
8
+ (function(){var p=this,C=p._,m={},j=Array.prototype,n=Object.prototype,i=j.slice,D=j.unshift,E=n.toString,q=n.hasOwnProperty,s=j.forEach,t=j.map,u=j.reduce,v=j.reduceRight,w=j.filter,x=j.every,y=j.some,o=j.indexOf,z=j.lastIndexOf;n=Array.isArray;var F=Object.keys,c=function(a){return new l(a)};if(typeof module!=="undefined"&&module.exports){module.exports=c;c._=c}else p._=c;c.VERSION="1.1.3";var k=c.each=c.forEach=function(a,b,d){if(s&&a.forEach===s)a.forEach(b,d);else if(c.isNumber(a.length))for(var e=
9
+ 0,f=a.length;e<f;e++){if(b.call(d,a[e],e,a)===m)break}else for(e in a)if(q.call(a,e))if(b.call(d,a[e],e,a)===m)break};c.map=function(a,b,d){if(t&&a.map===t)return a.map(b,d);var e=[];k(a,function(f,g,h){e[e.length]=b.call(d,f,g,h)});return e};c.reduce=c.foldl=c.inject=function(a,b,d,e){var f=d!==void 0;if(u&&a.reduce===u){if(e)b=c.bind(b,e);return f?a.reduce(b,d):a.reduce(b)}k(a,function(g,h,G){d=!f&&h===0?g:b.call(e,d,g,h,G)});return d};c.reduceRight=c.foldr=function(a,b,d,e){if(v&&a.reduceRight===
10
+ v){if(e)b=c.bind(b,e);return d!==void 0?a.reduceRight(b,d):a.reduceRight(b)}a=(c.isArray(a)?a.slice():c.toArray(a)).reverse();return c.reduce(a,b,d,e)};c.find=c.detect=function(a,b,d){var e;A(a,function(f,g,h){if(b.call(d,f,g,h)){e=f;return true}});return e};c.filter=c.select=function(a,b,d){if(w&&a.filter===w)return a.filter(b,d);var e=[];k(a,function(f,g,h){if(b.call(d,f,g,h))e[e.length]=f});return e};c.reject=function(a,b,d){var e=[];k(a,function(f,g,h){b.call(d,f,g,h)||(e[e.length]=f)});return e};
11
+ c.every=c.all=function(a,b,d){b=b||c.identity;if(x&&a.every===x)return a.every(b,d);var e=true;k(a,function(f,g,h){if(!(e=e&&b.call(d,f,g,h)))return m});return e};var A=c.some=c.any=function(a,b,d){b=b||c.identity;if(y&&a.some===y)return a.some(b,d);var e=false;k(a,function(f,g,h){if(e=b.call(d,f,g,h))return m});return e};c.include=c.contains=function(a,b){if(o&&a.indexOf===o)return a.indexOf(b)!=-1;var d=false;A(a,function(e){if(d=e===b)return true});return d};c.invoke=function(a,b){var d=i.call(arguments,
12
+ 2);return c.map(a,function(e){return(b?e[b]:e).apply(e,d)})};c.pluck=function(a,b){return c.map(a,function(d){return d[b]})};c.max=function(a,b,d){if(!b&&c.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};k(a,function(f,g,h){g=b?b.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};k(a,function(f,g,h){g=b?b.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});
13
+ return e.value};c.sortBy=function(a,b,d){return c.pluck(c.map(a,function(e,f,g){return{value:e,criteria:b.call(d,e,f,g)}}).sort(function(e,f){var g=e.criteria,h=f.criteria;return g<h?-1:g>h?1:0}),"value")};c.sortedIndex=function(a,b,d){d=d||c.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(b)?e=g+1:f=g}return e};c.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(c.isArray(a))return a;if(c.isArguments(a))return i.call(a);return c.values(a)};c.size=function(a){return c.toArray(a).length};
14
+ c.first=c.head=function(a,b,d){return b&&!d?i.call(a,0,b):a[0]};c.rest=c.tail=function(a,b,d){return i.call(a,c.isUndefined(b)||d?1:b)};c.last=function(a){return a[a.length-1]};c.compact=function(a){return c.filter(a,function(b){return!!b})};c.flatten=function(a){return c.reduce(a,function(b,d){if(c.isArray(d))return b.concat(c.flatten(d));b[b.length]=d;return b},[])};c.without=function(a){var b=i.call(arguments,1);return c.filter(a,function(d){return!c.include(b,d)})};c.uniq=c.unique=function(a,
15
+ b){return c.reduce(a,function(d,e,f){if(0==f||(b===true?c.last(d)!=e:!c.include(d,e)))d[d.length]=e;return d},[])};c.intersect=function(a){var b=i.call(arguments,1);return c.filter(c.uniq(a),function(d){return c.every(b,function(e){return c.indexOf(e,d)>=0})})};c.zip=function(){for(var a=i.call(arguments),b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e<b;e++)d[e]=c.pluck(a,""+e);return d};c.indexOf=function(a,b){if(o&&a.indexOf===o)return a.indexOf(b);for(var d=0,e=a.length;d<e;d++)if(a[d]===b)return d;
16
+ return-1};c.lastIndexOf=function(a,b){if(z&&a.lastIndexOf===z)return a.lastIndexOf(b);for(var d=a.length;d--;)if(a[d]===b)return d;return-1};c.range=function(a,b,d){var e=i.call(arguments),f=e.length<=1;a=f?0:e[0];b=f?e[0]:e[1];d=e[2]||1;e=Math.max(Math.ceil((b-a)/d),0);f=0;for(var g=Array(e);f<e;){g[f++]=a;a+=d}return g};c.bind=function(a,b){var d=i.call(arguments,2);return function(){return a.apply(b||{},d.concat(i.call(arguments)))}};c.bindAll=function(a){var b=i.call(arguments,1);if(b.length==
17
+ 0)b=c.functions(a);k(b,function(d){a[d]=c.bind(a[d],a)});return a};c.memoize=function(a,b){var d={};b=b||c.identity;return function(){var e=b.apply(this,arguments);return e in d?d[e]:d[e]=a.apply(this,arguments)}};c.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};c.defer=function(a){return c.delay.apply(c,[a,1].concat(i.call(arguments,1)))};var B=function(a,b,d){var e;return function(){var f=this,g=arguments,h=function(){e=null;a.apply(f,g)};d&&
18
+ clearTimeout(e);if(d||!e)e=setTimeout(h,b)}};c.throttle=function(a,b){return B(a,b,false)};c.debounce=function(a,b){return B(a,b,true)};c.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments));return b.apply(b,d)}};c.compose=function(){var a=i.call(arguments);return function(){for(var b=i.call(arguments),d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=F||function(a){if(c.isArray(a))return c.range(0,a.length);var b=[],d;for(d in a)if(q.call(a,d))b[b.length]=d;return b};
19
+ c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){k(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a,b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a.isEqual)return a.isEqual(b);
20
+ if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false;d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length===
21
+ 0;for(var b in a)if(q.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=n||function(a){return!!(a&&a.concat&&a.unshift&&!a.callee)};c.isArguments=function(a){return!!(a&&a.callee)};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};c.isNaN=function(a){return E.call(a)==="[object Number]"&&isNaN(a)};
22
+ c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};c.isNull=function(a){return a===null};c.isUndefined=function(a){return a===void 0};c.noConflict=function(){p._=C;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};c.mixin=function(a){k(c.functions(a),function(b){H(b,c[b]=a[b])})};var I=
23
+ 0;c.uniqueId=function(a){var b=I++;return a?a+b:b};c.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,
24
+ "\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var r=function(a,b){return b?c(a).chain():a},H=function(a,b){l.prototype[a]=function(){var d=i.call(arguments);D.call(d,this._wrapped);return r(b.apply(c,d),this._chain)}};c.mixin(c);k(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=j[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments);
25
+ return r(this._wrapped,this._chain)}});k(["concat","join","slice"],function(a){var b=j[a];l.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})();
@@ -0,0 +1,16 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title
5
+ LabBench Test Status
6
+ %link{ :href => css('app'), :rel => "stylesheet" }
7
+ %script{ :src => js('head.min') }
8
+ %body
9
+ %appstatus LabBench
10
+ %testruns
11
+ %eventlog
12
+ %script{ :type => "text/javascript" }
13
+ head.js("http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js");
14
+ head.js("#{js('mustache')}");
15
+ head.js("#{js('underscore-min')}");
16
+ head.js("#{js('app')}");
data/bin/lab_bench_server CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'rubygems'
4
4
  require 'lab_bench'
5
5
 
6
+ require 'haml'
6
7
  require 'eventmachine'
7
8
  require 'em-websocket'
8
9
  require 'sinatra/base'
@@ -10,22 +11,36 @@ require 'thin'
10
11
  require 'yajl'
11
12
 
12
13
  SOCKETS = []
14
+ MESSAGES = [] # TODO this is unbounded
13
15
 
14
16
  class LabBenchServer < Sinatra::Base
15
17
  set :public, LabBench::ASSETS
18
+ set :views, File.join(LabBench::ASSETS, 'views')
19
+
20
+ helpers do
21
+ def css(css)
22
+ "/css/#{css}.css?" + File.mtime(File.join(LabBench::ASSETS, "css", "#{css}.css")).to_i.to_s
23
+ end
24
+
25
+ def js(js)
26
+ "/js/#{js}.js?" + File.mtime(File.join(LabBench::ASSETS, "js", "#{js}.js")).to_i.to_s
27
+ end
28
+ end
16
29
 
17
30
  get '/' do
18
- redirect '/index.html'
31
+ haml :index
19
32
  end
20
33
 
21
- # lets the babyship ensure that we're up and running
34
+ # lets the TestRunner ensure that we're up and running
22
35
  get '/ping' do
23
36
  'Pong!'
24
37
  end
25
38
 
26
- # give the babyship a chance to post events, that we just rebroadcast
39
+ # give the TestRunner a chance to post events, which we cache and rebrooadcase
27
40
  post '/test_event' do
28
41
  message = Yajl::Encoder.encode(params.merge(:milliseconds => (Time.now.to_f * 1000).to_i))
42
+ MESSAGES << message
43
+
29
44
  SOCKETS.each { |s| s.send message }
30
45
 
31
46
  # should vend back a UID for this test run or something
@@ -38,6 +53,13 @@ EventMachine.run do
38
53
  # HACK - websockets and HTTP on different (adjacent) ports
39
54
  EventMachine::WebSocket.start(:host => '0.0.0.0', :port => 9021) do |ws|
40
55
  ws.onopen do
56
+ # backfill old messages to the client
57
+ # TODO is this blocking? I would guess no...
58
+ ws.send Yajl::Encoder.encode(['backfilling'])
59
+ MESSAGES.each { |message| ws.send(message) }
60
+
61
+ # put the client in the list of real-time recipients
62
+ ws.send Yajl::Encoder.encode(['realtime'])
41
63
  SOCKETS << ws
42
64
  end
43
65
 
@@ -45,7 +67,7 @@ EventMachine.run do
45
67
  SOCKETS.delete(ws)
46
68
  end
47
69
 
48
- ws.onerror { |e| puts "Error: #{e.message}" }
70
+ ws.onerror { |e| puts "Error: #{e.message}" }
49
71
  end
50
72
 
51
73
  LabBenchServer.run!(:host => '0.0.0.0', :port => 9020)
data/lab_bench.gemspec ADDED
@@ -0,0 +1,114 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{lab_bench}
8
+ s.version = "0.2.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Bradley Buda"]
12
+ s.date = %q{2010-12-03}
13
+ s.default_executable = %q{lab_bench_server}
14
+ s.description = %q{Like autotest, but in your browser. Currently unsuitable for use by anyone.}
15
+ s.email = %q{bradleybuda@gmail.com}
16
+ s.executables = ["lab_bench_server"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".rvmrc",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE.txt",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "assets/css/app.css",
31
+ "assets/images/connect.png",
32
+ "assets/images/disconnect.png",
33
+ "assets/images/spinner.gif",
34
+ "assets/js/app.js",
35
+ "assets/js/head.min.js",
36
+ "assets/js/mustache.js",
37
+ "assets/js/underscore-min.js",
38
+ "assets/views/index.haml",
39
+ "bin/lab_bench_server",
40
+ "lab_bench.gemspec",
41
+ "lib/lab_bench.rb",
42
+ "lib/lab_bench/test_runner.rb",
43
+ "test/helper.rb",
44
+ "test/test_lab_bench.rb"
45
+ ]
46
+ s.homepage = %q{http://github.com/bradleybuda/lab_bench}
47
+ s.licenses = ["MIT"]
48
+ s.require_paths = ["lib"]
49
+ s.rubygems_version = %q{1.3.7}
50
+ s.summary = %q{A browser-based runner for Test::Unit}
51
+ s.test_files = [
52
+ "test/helper.rb",
53
+ "test/test_lab_bench.rb"
54
+ ]
55
+
56
+ if s.respond_to? :specification_version then
57
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
58
+ s.specification_version = 3
59
+
60
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
61
+ s.add_runtime_dependency(%q<haml>, ["~> 2.2.0"])
62
+ s.add_runtime_dependency(%q<sinatra>, ["~> 1.1.0"])
63
+ s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.10"])
64
+ s.add_runtime_dependency(%q<em-websocket>, ["~> 0.2.0"])
65
+ s.add_runtime_dependency(%q<thin>, ["~> 1.2.0"])
66
+ s.add_runtime_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
67
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
68
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
70
+ s.add_development_dependency(%q<rcov>, [">= 0"])
71
+ s.add_development_dependency(%q<hpricot>, [">= 0"])
72
+ s.add_runtime_dependency(%q<sinatra>, ["~> 1.1.0"])
73
+ s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.10"])
74
+ s.add_runtime_dependency(%q<em-websocket>, ["~> 0.2.0"])
75
+ s.add_runtime_dependency(%q<thin>, ["~> 1.2.0"])
76
+ s.add_runtime_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
77
+ else
78
+ s.add_dependency(%q<haml>, ["~> 2.2.0"])
79
+ s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
80
+ s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
81
+ s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
82
+ s.add_dependency(%q<thin>, ["~> 1.2.0"])
83
+ s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
84
+ s.add_dependency(%q<shoulda>, [">= 0"])
85
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
86
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
87
+ s.add_dependency(%q<rcov>, [">= 0"])
88
+ s.add_dependency(%q<hpricot>, [">= 0"])
89
+ s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
90
+ s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
91
+ s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
92
+ s.add_dependency(%q<thin>, ["~> 1.2.0"])
93
+ s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
94
+ end
95
+ else
96
+ s.add_dependency(%q<haml>, ["~> 2.2.0"])
97
+ s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
98
+ s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
99
+ s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
100
+ s.add_dependency(%q<thin>, ["~> 1.2.0"])
101
+ s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
102
+ s.add_dependency(%q<shoulda>, [">= 0"])
103
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
104
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
105
+ s.add_dependency(%q<rcov>, [">= 0"])
106
+ s.add_dependency(%q<hpricot>, [">= 0"])
107
+ s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
108
+ s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
109
+ s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
110
+ s.add_dependency(%q<thin>, ["~> 1.2.0"])
111
+ s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
112
+ end
113
+ end
114
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lab_bench
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 0
10
- version: 0.2.0
9
+ - 1
10
+ version: 0.2.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Bradley Buda
@@ -18,11 +18,107 @@ cert_chain: []
18
18
  date: 2010-12-03 00:00:00 -08:00
19
19
  default_executable: lab_bench_server
20
20
  dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ type: :runtime
24
+ name: haml
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 7
31
+ segments:
32
+ - 2
33
+ - 2
34
+ - 0
35
+ version: 2.2.0
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
39
+ type: :runtime
40
+ name: sinatra
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 19
47
+ segments:
48
+ - 1
49
+ - 1
50
+ - 0
51
+ version: 1.1.0
52
+ requirement: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ prerelease: false
55
+ type: :runtime
56
+ name: eventmachine
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ hash: 59
63
+ segments:
64
+ - 0
65
+ - 12
66
+ - 10
67
+ version: 0.12.10
68
+ requirement: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ prerelease: false
71
+ type: :runtime
72
+ name: em-websocket
73
+ version_requirements: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ hash: 23
79
+ segments:
80
+ - 0
81
+ - 2
82
+ - 0
83
+ version: 0.2.0
84
+ requirement: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ prerelease: false
87
+ type: :runtime
88
+ name: thin
89
+ version_requirements: &id005 !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ hash: 31
95
+ segments:
96
+ - 1
97
+ - 2
98
+ - 0
99
+ version: 1.2.0
100
+ requirement: *id005
101
+ - !ruby/object:Gem::Dependency
102
+ prerelease: false
103
+ type: :runtime
104
+ name: yajl-ruby
105
+ version_requirements: &id006 !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ hash: 19
111
+ segments:
112
+ - 0
113
+ - 7
114
+ - 8
115
+ version: 0.7.8
116
+ requirement: *id006
21
117
  - !ruby/object:Gem::Dependency
22
118
  prerelease: false
23
119
  type: :development
24
120
  name: shoulda
25
- version_requirements: &id001 !ruby/object:Gem::Requirement
121
+ version_requirements: &id007 !ruby/object:Gem::Requirement
26
122
  none: false
27
123
  requirements:
28
124
  - - ">="
@@ -31,12 +127,12 @@ dependencies:
31
127
  segments:
32
128
  - 0
33
129
  version: "0"
34
- requirement: *id001
130
+ requirement: *id007
35
131
  - !ruby/object:Gem::Dependency
36
132
  prerelease: false
37
133
  type: :development
38
134
  name: bundler
39
- version_requirements: &id002 !ruby/object:Gem::Requirement
135
+ version_requirements: &id008 !ruby/object:Gem::Requirement
40
136
  none: false
41
137
  requirements:
42
138
  - - ~>
@@ -47,12 +143,12 @@ dependencies:
47
143
  - 0
48
144
  - 0
49
145
  version: 1.0.0
50
- requirement: *id002
146
+ requirement: *id008
51
147
  - !ruby/object:Gem::Dependency
52
148
  prerelease: false
53
149
  type: :development
54
150
  name: jeweler
55
- version_requirements: &id003 !ruby/object:Gem::Requirement
151
+ version_requirements: &id009 !ruby/object:Gem::Requirement
56
152
  none: false
57
153
  requirements:
58
154
  - - ~>
@@ -63,12 +159,12 @@ dependencies:
63
159
  - 5
64
160
  - 1
65
161
  version: 1.5.1
66
- requirement: *id003
162
+ requirement: *id009
67
163
  - !ruby/object:Gem::Dependency
68
164
  prerelease: false
69
165
  type: :development
70
166
  name: rcov
71
- version_requirements: &id004 !ruby/object:Gem::Requirement
167
+ version_requirements: &id010 !ruby/object:Gem::Requirement
72
168
  none: false
73
169
  requirements:
74
170
  - - ">="
@@ -77,12 +173,26 @@ dependencies:
77
173
  segments:
78
174
  - 0
79
175
  version: "0"
80
- requirement: *id004
176
+ requirement: *id010
177
+ - !ruby/object:Gem::Dependency
178
+ prerelease: false
179
+ type: :development
180
+ name: hpricot
181
+ version_requirements: &id011 !ruby/object:Gem::Requirement
182
+ none: false
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ hash: 3
187
+ segments:
188
+ - 0
189
+ version: "0"
190
+ requirement: *id011
81
191
  - !ruby/object:Gem::Dependency
82
192
  prerelease: false
83
193
  type: :runtime
84
194
  name: sinatra
85
- version_requirements: &id005 !ruby/object:Gem::Requirement
195
+ version_requirements: &id012 !ruby/object:Gem::Requirement
86
196
  none: false
87
197
  requirements:
88
198
  - - ~>
@@ -93,12 +203,12 @@ dependencies:
93
203
  - 1
94
204
  - 0
95
205
  version: 1.1.0
96
- requirement: *id005
206
+ requirement: *id012
97
207
  - !ruby/object:Gem::Dependency
98
208
  prerelease: false
99
209
  type: :runtime
100
210
  name: eventmachine
101
- version_requirements: &id006 !ruby/object:Gem::Requirement
211
+ version_requirements: &id013 !ruby/object:Gem::Requirement
102
212
  none: false
103
213
  requirements:
104
214
  - - ~>
@@ -109,12 +219,12 @@ dependencies:
109
219
  - 12
110
220
  - 10
111
221
  version: 0.12.10
112
- requirement: *id006
222
+ requirement: *id013
113
223
  - !ruby/object:Gem::Dependency
114
224
  prerelease: false
115
225
  type: :runtime
116
226
  name: em-websocket
117
- version_requirements: &id007 !ruby/object:Gem::Requirement
227
+ version_requirements: &id014 !ruby/object:Gem::Requirement
118
228
  none: false
119
229
  requirements:
120
230
  - - ~>
@@ -125,12 +235,12 @@ dependencies:
125
235
  - 2
126
236
  - 0
127
237
  version: 0.2.0
128
- requirement: *id007
238
+ requirement: *id014
129
239
  - !ruby/object:Gem::Dependency
130
240
  prerelease: false
131
241
  type: :runtime
132
242
  name: thin
133
- version_requirements: &id008 !ruby/object:Gem::Requirement
243
+ version_requirements: &id015 !ruby/object:Gem::Requirement
134
244
  none: false
135
245
  requirements:
136
246
  - - ~>
@@ -141,12 +251,12 @@ dependencies:
141
251
  - 2
142
252
  - 0
143
253
  version: 1.2.0
144
- requirement: *id008
254
+ requirement: *id015
145
255
  - !ruby/object:Gem::Dependency
146
256
  prerelease: false
147
257
  type: :runtime
148
258
  name: yajl-ruby
149
- version_requirements: &id009 !ruby/object:Gem::Requirement
259
+ version_requirements: &id016 !ruby/object:Gem::Requirement
150
260
  none: false
151
261
  requirements:
152
262
  - - ~>
@@ -157,7 +267,7 @@ dependencies:
157
267
  - 7
158
268
  - 8
159
269
  version: 0.7.8
160
- requirement: *id009
270
+ requirement: *id016
161
271
  description: Like autotest, but in your browser. Currently unsuitable for use by anyone.
162
272
  email: bradleybuda@gmail.com
163
273
  executables:
@@ -177,12 +287,16 @@ files:
177
287
  - Rakefile
178
288
  - VERSION
179
289
  - assets/css/app.css
290
+ - assets/images/connect.png
291
+ - assets/images/disconnect.png
180
292
  - assets/images/spinner.gif
181
- - assets/index.html
182
293
  - assets/js/app.js
183
294
  - assets/js/head.min.js
184
295
  - assets/js/mustache.js
296
+ - assets/js/underscore-min.js
297
+ - assets/views/index.haml
185
298
  - bin/lab_bench_server
299
+ - lab_bench.gemspec
186
300
  - lib/lab_bench.rb
187
301
  - lib/lab_bench/test_runner.rb
188
302
  - test/helper.rb
data/assets/index.html DELETED
@@ -1,18 +0,0 @@
1
- <!DOCTYPE HTML>
2
- <html>
3
- <head>
4
- <title>LabBench Test Status</title>
5
- <link rel="stylesheet" href="/css/app.css">
6
- <script src="/js/head.min.js"></script>
7
- </head>
8
- <body>
9
- <testruns></testruns>
10
- <eventlog></eventlog>
11
-
12
- <script type='text/javascript'>
13
- head.js("http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js");
14
- head.js("/js/mustache.js");
15
- head.js("/js/app.js");
16
- </script>
17
- </body>
18
- </html>