Browse files

first commit

  • Loading branch information...
0 parents commit f3b3ae2296990d0c0e90f75f1c89255ad5456548 @jugyo committed Jan 6, 2010
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 jugyo
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 README.markdown
@@ -0,0 +1,18 @@
+Tester
+======
+
+Continuation testing tool.
+
+Usage
+------
+
+
+
+Installation
+------
+
+
+
+== Copyright
+
+Copyright (c) 2010 jugyo. See LICENSE for details.
55 Rakefile
@@ -0,0 +1,55 @@
+require 'rubygems'
+require 'rake'
+
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |gem|
+ gem.name = "tester"
+ gem.summary = %Q{Continuation testing tool.}
+ gem.description = %Q{Continuation testing tool for project that use git.}
+ gem.email = "jugyo.org@gmail.com"
+ gem.homepage = "http://github.com/jugyo/tester"
+ gem.authors = ["jugyo"]
+ gem.add_development_dependency "shoulda", ">= 0"
+ gem.add_development_dependency "rr", ">= 0"
+ gem.add_dependency 'kvs'
+ gem.add_dependency 'sinatra'
+ gem.add_dependency 'choice'
+ end
+rescue LoadError
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
+end
+
+require 'rake/testtask'
+Rake::TestTask.new(:test) do |test|
+ test.libs << 'lib' << 'test'
+ test.pattern = 'test/**/test_*.rb'
+ test.verbose = true
+end
+
+begin
+ require 'rcov/rcovtask'
+ Rcov::RcovTask.new do |test|
+ test.libs << 'test'
+ test.pattern = 'test/**/test_*.rb'
+ test.verbose = true
+ end
+rescue LoadError
+ task :rcov do
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
+ end
+end
+
+task :test => :check_dependencies
+
+task :default => :test
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "tester #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
1 VERSION
@@ -0,0 +1 @@
+0.1.0
86 bin/tester
@@ -0,0 +1,86 @@
+#!/usr/bin/env ruby
+
+$:.unshift(File.dirname(__FILE__) + "/../lib")
+
+require 'rubygems'
+require 'tester'
+require 'choice'
+
+Choice.options do
+ banner "Usage: #{File.basename(__FILE__)} [-hpv] path_to_git_repo"
+ header ''
+ header 'Server options:'
+
+ option :host do
+ d = "0.0.0.0"
+ short '-h'
+ long '--host=HOST'
+ desc "The hostname or ip of the host to bind to (default #{d})"
+ default d
+ end
+
+ option :port do
+ d = 4567
+ short '-p'
+ long '--port=PORT'
+ desc "The port to listen on (default #{d})"
+ cast Integer
+ default d
+ end
+
+ option :branch do
+ d = 'master'
+ short '-b'
+ long '--branch=BRANCH'
+ desc "The branch to test (default #{d})"
+ default d
+ end
+
+ option :command do
+ d = 'rake'
+ short '-c'
+ long '--command=COMMAND'
+ desc "The test command (default #{d})"
+ default d
+ end
+
+ option :interval do
+ d = 60
+ short '-i'
+ long '--interval=INTERVAL'
+ desc "The interval to check update (default #{d})"
+ cast Integer
+ default d
+ end
+
+ separator ''
+ separator 'Common options: '
+
+ option :help do
+ long '--help'
+ desc 'Show this message'
+ end
+
+ option :version do
+ short '-v'
+ long '--version'
+ desc 'Show version'
+ action do
+ puts "#{File.basename(__FILE__)} v#{CIJoe::Version}"
+ exit
+ end
+ end
+end
+
+options = Choice.choices
+
+Tester::Runner.start(
+ :branch => options[:branch],
+ :test_command => options[:command],
+ :interval => options[:interval]
+)
+
+Tester::Server.run!(
+ :host => options[:host],
+ :port => options[:port]
+)
16 lib/tester.rb
@@ -0,0 +1,16 @@
+unless File.exists?('.git')
+ puts 'not git dir'
+ exit!
+end
+
+require 'kvs'
+require 'singleton'
+require 'sinatra'
+
+work_dir = '.tester'
+Dir.mkdir(work_dir) unless File.exists?(work_dir)
+KVS.dir = work_dir
+
+Dir[File.join(File.dirname(__FILE__), 'tester', '*.rb')].each do |filename|
+ require filename
+end
26 lib/tester/checker.rb
@@ -0,0 +1,26 @@
+module Tester
+ class Checker
+ attr_reader :branch
+ attr_accessor :last_hash
+
+ def initialize(branch)
+ @branch = branch
+ end
+
+ def if_updated(&block)
+ hash = head
+ if KVS['HEAD'] != hash
+ block.call(hash)
+ KVS['HEAD'] = self.last_hash = hash
+ end
+ end
+
+ def update
+ `git fetch origin && git reset --hard origin/#{branch}`
+ end
+
+ def head
+ `git rev-parse origin/#{branch}`.chomp
+ end
+ end
+end
18 lib/tester/log.rb
@@ -0,0 +1,18 @@
+module Tester
+ module Log
+ class << self
+ def []=(hash, result)
+ KVS['logs'] = logs << hash
+ KVS[hash] = result
+ end
+
+ def [](hash)
+ KVS[hash]
+ end
+
+ def logs
+ KVS['logs'] || []
+ end
+ end
+ end
+end
54 lib/tester/runner.rb
@@ -0,0 +1,54 @@
+module Tester
+ class Runner
+ def self.start(options)
+ self.new(options).start
+ end
+
+ attr_reader :config, :checker
+ attr_accessor :testing, :started
+
+ def initialize(options)
+ @config = (KVS['config'] || {}).merge(options)
+ @checker = Checker.new(@config[:branch])
+ end
+
+ def start
+ return if started
+ Thread.start do
+ loop do
+ begin
+ test_if_updated
+ rescue Exception => e
+ puts "#{e.message}\n #{e.backtrace.join("\n ")}"
+ ensure
+ sleep config[:interval]
+ end
+ end
+ end
+ self.started = true
+ end
+
+ def test_if_updated
+ checker.if_updated do |hash|
+ begin
+ self.testing = true
+ test(hash)
+ ensure
+ self.testing = false
+ end
+ end
+ end
+
+ def test(hash)
+ process = TestProcess.new(config[:test_command])
+ process.start
+ puts "#{hash} => #{process.status}"
+ puts process.output
+ Log[hash] = process.to_hash.merge(
+ :hash => hash,
+ :created_at => Time.now,
+ :branch => config[:branch]
+ )
+ end
+ end
+end
25 lib/tester/server.rb
@@ -0,0 +1,25 @@
+module Tester
+ class Server < Sinatra::Base
+ dir = File.dirname(File.expand_path(__FILE__))
+
+ set :views, "#{dir}/views"
+ set :public, "#{dir}/public"
+ set :static, true
+ set :lock, true
+
+ get '/' do
+ @logs = Log.logs.map {|key| Log[key]}
+ haml :index
+ end
+
+ get '/css' do
+ sass :styles
+ end
+
+ get '/logs/:hash' do
+ @hash = params[:hash]
+ @log = Log[@hash]
+ haml :show
+ end
+ end
+end
22 lib/tester/test_process.rb
@@ -0,0 +1,22 @@
+module Tester
+ class TestProcess < Struct.new(:status, :pid)
+ attr_reader :command, :status, :pid, :output
+
+ def initialize(command)
+ @command = command
+ end
+
+ def start
+ IO.popen("#{command} 2>&1") do |io|
+ @pid = pid
+ @output = io.read
+ end
+ @status = $?.exitstatus.to_i
+ rescue Exception => e
+ end
+
+ def to_hash
+ {:status => status, :output => output}
+ end
+ end
+end
12 lib/tester/views/index.haml
@@ -0,0 +1,12 @@
+%table
+ - @logs.each do |log|
+ %tr
+ %td
+ %a{:href => "/logs/#{log[:hash]}"}= log[:hash]
+ %td
+ -if log[:status] == 0
+ .success Success!
+ - else
+ .failure Failure!
+ %td
+ = log[:created_at]
16 lib/tester/views/layout.haml
@@ -0,0 +1,16 @@
+%html
+ %head
+ %meta{:"http-equiv"=>"Content-Type", :content=>"text/html;charset=UTF-8"}
+ %title Tester
+ %link{:rel=>'stylesheet', :type=>'text/css', :href=>'/css', :media=>'screen,tv,projection'}
+ %body
+ #wrap
+ #header
+ %h1
+ %a{:href => '/'} Tester
+
+ #content
+ = yield
+
+ #footer
+ %a{:href => 'http://github.com/jugyo/tester'} Tester
12 lib/tester/views/show.haml
@@ -0,0 +1,12 @@
+%a{:href => '/'} « logs
+
+%h2= @hash
+
+-if @log[:status] == 0
+ %h3.success Success!
+- else
+ %h3.failure Failure!
+
+= @log[:created_at]
+
+%pre= @log[:output]
35 lib/tester/views/styles.css
@@ -0,0 +1,35 @@
+body {
+ font-family: Verdana, Helvetica;
+ font-size: 13.0px;
+ margin: 0;
+ padding: 0;
+ background: url(/background.png);
+ background-repeat: no-repeat;
+ background-position: top right;
+ color: gray; }
+
+pre {
+ color: white;
+ background-color: black;
+ border: solid 1px gray;
+ overflow: auto; }
+
+td {
+ padding: 4px;
+ border-right: solid 1px silver;
+ border-bottom: dashed 1px silver; }
+
+#wrap {
+ margin: 20px; }
+
+
+#footer {
+ text-align: right; }
+
+.success {
+ font-weight: bold;
+ color: green; }
+
+.failure {
+ font-weight: bold;
+ color: red; }
35 lib/tester/views/styles.sass
@@ -0,0 +1,35 @@
+body
+ font-family: Verdana, Helvetica
+ font-size: 13.0px
+ margin: 0
+ padding: 0
+ background: url(/background.png)
+ background-repeat: no-repeat
+ background-position: top right
+ color: gray
+
+pre
+ color: white
+ background-color: black
+ border: solid 1px gray
+ overflow: auto
+
+td
+ padding: 4px
+ border-bottom: dashed 1px silver
+
+#wrap
+ margin: 20px
+
+#header
+
+#footer
+ text-align: right
+
+.success
+ font-weight: bold
+ color: green
+
+.failure
+ font-weight: bold
+ color: red
12 test/helper.rb
@@ -0,0 +1,12 @@
+require 'rubygems'
+require 'test/unit'
+require 'shoulda'
+require 'rr'
+
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require 'tester'
+
+class Test::Unit::TestCase
+ include RR::Adapters::TestUnit
+end
7 test/test_tester.rb
@@ -0,0 +1,7 @@
+require 'helper'
+require 'tmpdir'
+
+class TestTester < Test::Unit::TestCase
+ should 'test' do
+ end
+end
3 test/tester.ru
@@ -0,0 +1,3 @@
+$:.unshift(File.dirname(__FILE__) + "/../lib")
+require 'tester'
+run Tester::Server
27 test/tester/test_checker.rb
@@ -0,0 +1,27 @@
+require 'helper'
+require 'fakefs'
+
+class TestChecker < Test::Unit::TestCase
+ context 'main' do
+ setup do
+ KVS.dir = 'foo'
+ KVS['HEAD'] = ''
+ @checker = Tester::Checker.new('master')
+ stub(@checker).update
+ end
+
+ should 'check updated' do
+ stub(@checker).head { 'foo' }
+ block = lambda {}
+ mock(block).call('foo')
+ # NOTE: rr が思ったような動作をしてくれないのでこんな書き方になってます...
+ @checker.if_updated do |hash|
+ block.call(hash)
+ end
+ mock(block).call('foo').times(0)
+ @checker.if_updated do |hash|
+ block.call(hash)
+ end
+ end
+ end
+end
19 test/tester/test_log.rb
@@ -0,0 +1,19 @@
+require 'helper'
+require 'fakefs'
+
+class TestLog < Test::Unit::TestCase
+ context 'main' do
+ setup do
+ KVS.dir = 'foo'
+ end
+
+ should 'save log' do
+ Tester::Log['test1'] = {:foo => :bar}
+ assert_equal(['test1'], Tester::Log.logs)
+ assert_equal({:foo => :bar}, Tester::Log['test1'])
+ Tester::Log['test2'] = {:FOO => :BAR}
+ assert_equal(['test1', 'test2'], Tester::Log.logs)
+ assert_equal({:FOO => :BAR}, Tester::Log['test2'])
+ end
+ end
+end
28 test/tester/test_runner.rb
@@ -0,0 +1,28 @@
+require 'helper'
+
+class TestRunner < Test::Unit::TestCase
+ context 'main' do
+ setup do
+ @runner = Tester::Runner.new({:branch => 'foo', :test_command => 'bar', :interval => 10})
+ end
+
+ should 'Runner.new' do
+ assert_equal(@runner.config[:branch], @runner.checker.branch)
+ end
+
+ should 'test if updated' do
+ test_process_stub = Object.new
+ mock(test_process_stub).start
+ stub(test_process_stub).to_hash { {:foo => :bar} }
+ stub(test_process_stub).status { 0 }
+ stub(test_process_stub).output { 'output' }
+ mock(Tester::TestProcess).new(@runner.config[:test_command]) { test_process_stub }
+ mock(Tester::Log).[]=.with_any_args
+ stub(Time).now { 'now' }
+
+ $stdout = StringIO.new
+ @runner.test('XXXX')
+ $stdout = STDOUT
+ end
+ end
+end
24 test/tester/test_test_process.rb
@@ -0,0 +1,24 @@
+require 'helper'
+require 'tmpdir'
+
+class TestTestProcess < Test::Unit::TestCase
+ context 'main' do
+ setup do
+ @test = Tester::TestProcess.new('foo')
+ end
+
+ should 'pass the test' do
+ stub(@test).command {'ls'}
+ @test.start
+ assert_equal(0, @test.status)
+ assert_equal(`ls 2>&1`, @test.output)
+ end
+
+ should 'not pass the test' do
+ stub(@test).command {'ls foo'}
+ @test.start
+ assert_not_equal(0, @test.status)
+ assert_equal(`ls foo 2>&1`, @test.output)
+ end
+ end
+end

0 comments on commit f3b3ae2

Please sign in to comment.