rrrspec-web 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/Guardfile +4 -0
- data/Rakefile +2 -0
- data/app/css/application.sass +124 -0
- data/app/css/vendor/bootstrap-theme.css +384 -0
- data/app/css/vendor/bootstrap-theme.min.css +1 -0
- data/app/css/vendor/bootstrap.css +6805 -0
- data/app/css/vendor/bootstrap.min.css +9 -0
- data/app/js/index.coffee +51 -0
- data/app/js/models.coffee +177 -0
- data/app/js/tasksets.coffee +305 -0
- data/app/js/vendor/backbone-min.js +2 -0
- data/app/js/vendor/backbone-min.map +1 -0
- data/app/js/vendor/backbone.js +1581 -0
- data/app/js/vendor/bootstrap.js +1999 -0
- data/app/js/vendor/bootstrap.min.js +6 -0
- data/app/js/vendor/jquery-1.10.2.js +9789 -0
- data/app/js/vendor/jquery-1.10.2.min.js +6 -0
- data/app/js/vendor/jquery-1.10.2.min.map +1 -0
- data/app/js/vendor/moment.min.js +6 -0
- data/app/js/vendor/mustache.js +551 -0
- data/app/js/vendor/underscore-min.js +6 -0
- data/app/js/vendor/underscore-min.map +1 -0
- data/app/js/vendor/underscore.js +1276 -0
- data/compass.config +2 -0
- data/lib/rrrspec/web.rb +22 -0
- data/lib/rrrspec/web/api.rb +55 -0
- data/lib/rrrspec/web/app.rb +48 -0
- data/lib/rrrspec/web/configuration.rb +12 -0
- data/lib/rrrspec/web/persistent_models.rb +16 -0
- data/lib/rrrspec/web/version.rb +5 -0
- data/rrrspec-web.gemspec +47 -0
- data/spec/rrrspec/web/api_spec.rb +118 -0
- data/spec/spec_helper.rb +77 -0
- data/tasks/assets.rake +6 -0
- data/views/index.haml +46 -0
- data/views/taskset.haml +161 -0
- data/views/user.haml +33 -0
- metadata +379 -0
data/compass.config
ADDED
data/lib/rrrspec/web.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'kaminari/grape'
|
3
|
+
|
4
|
+
require 'rrrspec'
|
5
|
+
require 'rrrspec/server'
|
6
|
+
require 'rrrspec/web/persistent_models'
|
7
|
+
require 'rrrspec/web/api'
|
8
|
+
require 'rrrspec/web/app'
|
9
|
+
require 'rrrspec/web/configuration'
|
10
|
+
|
11
|
+
RRRSpec.configuration = RRRSpec::Web::WebConfiguration.new
|
12
|
+
|
13
|
+
module RRRSpec
|
14
|
+
module Web
|
15
|
+
def self.setup
|
16
|
+
ActiveRecord::Base.establish_connection(
|
17
|
+
**RRRSpec.configuration.persistence_db
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'grape'
|
2
|
+
require 'api-pagination'
|
3
|
+
|
4
|
+
module RRRSpec
|
5
|
+
module Web
|
6
|
+
class API < Grape::API
|
7
|
+
version 'v1', using: :path
|
8
|
+
format :json
|
9
|
+
|
10
|
+
resource :tasksets do
|
11
|
+
desc "Return active tasksets"
|
12
|
+
get :actives do
|
13
|
+
ActiveTaskset.list
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Return recently finished tasksets"
|
17
|
+
get :recents do
|
18
|
+
paginate(RRRSpec::Server::Persistence::Taskset.recent).map(&:as_json_with_no_relation)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Return tasksets that contains failure_exit slave"
|
22
|
+
get :failure_slaves do
|
23
|
+
paginate(RRRSpec::Server::Persistence::Taskset.has_failed_slaves.recent).map(&:as_json_with_no_relation)
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Return a taskset."
|
27
|
+
params { requires :key, type: String, desc: "Taskset key." }
|
28
|
+
route_param :key do
|
29
|
+
get do
|
30
|
+
p_obj = RRRSpec::Server::Persistence::Taskset.where(key: params[:key]).full.first
|
31
|
+
if p_obj
|
32
|
+
p_obj.as_full_json.update('is_full' => true)
|
33
|
+
else
|
34
|
+
error!('Not Found', 404)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
namespace :batch do
|
41
|
+
resource :tasks do
|
42
|
+
desc "Return all tasks in the taskset"
|
43
|
+
params { requires :key, type: String, desc: "Taskset key." }
|
44
|
+
route_param :key do
|
45
|
+
get do
|
46
|
+
r_taskset = Taskset.new(params[:key])
|
47
|
+
error!('Not Found', 404) unless r_taskset.exist?
|
48
|
+
r_taskset.tasks.map(&:to_h)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/assetpack'
|
3
|
+
require 'haml'
|
4
|
+
require 'sass'
|
5
|
+
require 'coffee-script'
|
6
|
+
|
7
|
+
module RRRSpec
|
8
|
+
module Web
|
9
|
+
class App < Sinatra::Base
|
10
|
+
configure do
|
11
|
+
set :root, File.expand_path(File.join(__FILE__, '..', '..', '..', '..'))
|
12
|
+
set :haml, :format => :html5
|
13
|
+
end
|
14
|
+
|
15
|
+
register Sinatra::AssetPack
|
16
|
+
|
17
|
+
assets do
|
18
|
+
JSLIBS = [
|
19
|
+
'/js/vendor/jquery-1.10.2.min.js',
|
20
|
+
'/js/vendor/underscore-min.js',
|
21
|
+
'/js/vendor/backbone-min.js',
|
22
|
+
'/js/vendor/mustache.js',
|
23
|
+
'/js/vendor/bootstrap.min.js',
|
24
|
+
'/js/vendor/moment.min.js',
|
25
|
+
'/js/models.js',
|
26
|
+
]
|
27
|
+
|
28
|
+
CSSLIBS = [
|
29
|
+
'/css/vendor/bootstrap.min.css',
|
30
|
+
'/css/vendor/bootstrap-theme.min.css',
|
31
|
+
]
|
32
|
+
|
33
|
+
js :tasksets, JSLIBS + ["/js/tasksets.js"]
|
34
|
+
js :index, JSLIBS + ["/js/index.js"]
|
35
|
+
css :application, CSSLIBS + ["/css/application.css"]
|
36
|
+
|
37
|
+
js_compression :jsmin
|
38
|
+
css_compression :simple
|
39
|
+
|
40
|
+
prebuild true
|
41
|
+
cache_dynamic_assets true
|
42
|
+
end
|
43
|
+
|
44
|
+
get('/') { haml :index }
|
45
|
+
get('/tasksets/*') { haml :taskset }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Extensions to RRRSpec::Server::Persistence
|
2
|
+
|
3
|
+
module RRRSpec
|
4
|
+
module Server
|
5
|
+
module Persistence
|
6
|
+
class Taskset
|
7
|
+
scope :recent, order('finished_at DESC')
|
8
|
+
scope :has_failed_slaves, includes(:slaves).where(slaves: {status: 'failure_exit'})
|
9
|
+
|
10
|
+
def as_json_with_no_relation
|
11
|
+
as_json(except: :id)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/rrrspec-web.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rrrspec/web/version'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "rrrspec-web"
|
9
|
+
spec.version = RRRSpec::Web::VERSION
|
10
|
+
spec.authors = ["Masaya Suzuki"]
|
11
|
+
spec.email = ["draftcode@gmail.com"]
|
12
|
+
spec.description = "Execute RSpec in a distributed manner"
|
13
|
+
spec.summary = "Execute RSpec in a distributed manner"
|
14
|
+
spec.homepage = ""
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
gemspec_dir = File.expand_path('..', __FILE__)
|
18
|
+
spec.files = `git ls-files`.split($/).
|
19
|
+
map { |f| File.absolute_path(f) }.
|
20
|
+
select { |f| f.start_with?(gemspec_dir) }.
|
21
|
+
map { |f| Pathname(f).relative_path_from(Pathname(gemspec_dir)).to_s }
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.4"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
|
+
spec.add_development_dependency "rack-test"
|
30
|
+
spec.add_development_dependency "database_cleaner", "~> 1.2.0"
|
31
|
+
spec.add_development_dependency "sqlite3"
|
32
|
+
spec.add_development_dependency "mysql2"
|
33
|
+
spec.add_development_dependency "guard-livereload"
|
34
|
+
spec.add_development_dependency "rack-livereload"
|
35
|
+
spec.add_dependency "activerecord", "~> 3.0"
|
36
|
+
spec.add_dependency "activesupport"
|
37
|
+
spec.add_dependency "api-pagination"
|
38
|
+
spec.add_dependency "coffee-script", "~> 2.2.0"
|
39
|
+
spec.add_dependency "grape"
|
40
|
+
spec.add_dependency "haml", "~> 4.0.3"
|
41
|
+
spec.add_dependency "kaminari", "~> 0.15.0"
|
42
|
+
spec.add_dependency "rrrspec-client"
|
43
|
+
spec.add_dependency "rrrspec-server"
|
44
|
+
spec.add_dependency "sass"
|
45
|
+
spec.add_dependency "sinatra", "~> 1.4.3"
|
46
|
+
spec.add_dependency "sinatra-assetpack"
|
47
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RRRSpec
|
4
|
+
describe Web::API do
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
def app
|
8
|
+
Web::API
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
RRRSpec.configuration = Configuration.new
|
13
|
+
RRRSpec.configuration.redis = @redis
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:taskset) do
|
17
|
+
Taskset.create(
|
18
|
+
'testuser', 'echo 1', 'echo 2', 'default', 'default', 3, 3, 5, 5
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:task) do
|
23
|
+
Task.create(taskset, 10, 'spec/test_spec.rb')
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:worker) do
|
27
|
+
Worker.create('default')
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:worker_log) do
|
31
|
+
WorkerLog.create(worker, taskset)
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:slave) do
|
35
|
+
Slave.create
|
36
|
+
end
|
37
|
+
|
38
|
+
before do
|
39
|
+
worker # Create worker
|
40
|
+
taskset.add_task(task)
|
41
|
+
taskset.enqueue_task(task)
|
42
|
+
ActiveTaskset.add(taskset)
|
43
|
+
worker_log # Create worker_log
|
44
|
+
worker_log.set_rsync_finished_time
|
45
|
+
worker_log.append_log('worker_log log body')
|
46
|
+
worker_log.set_setup_finished_time
|
47
|
+
slave # Create slave
|
48
|
+
taskset.add_slave(slave)
|
49
|
+
slave.append_log('slave log body')
|
50
|
+
trial = Trial.create(task, slave)
|
51
|
+
trial.start
|
52
|
+
trial.finish('pending', 'stdout body', 'stderr body', 10, 2, 0)
|
53
|
+
task.update_status('pending')
|
54
|
+
taskset.incr_succeeded_count
|
55
|
+
taskset.finish_task(task)
|
56
|
+
taskset.update_status('succeeded')
|
57
|
+
taskset.set_finished_time
|
58
|
+
ActiveTaskset.remove(taskset)
|
59
|
+
slave.update_status('normal_exit')
|
60
|
+
worker_log.set_finished_time
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "GET /v1/tasksets/actives" do
|
64
|
+
before { ActiveTaskset.add(taskset) }
|
65
|
+
|
66
|
+
it 'returns the active tasksets' do
|
67
|
+
get "/v1/tasksets/actives"
|
68
|
+
expect(last_response.status).to eq(200)
|
69
|
+
expect(JSON.parse(last_response.body)).to eq(JSON.parse(ActiveTaskset.list.to_json))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "GET /v1/tasksets/recents" do
|
74
|
+
context 'there are 11 tasksets' do
|
75
|
+
before do
|
76
|
+
11.times { Server::Persistence::Taskset.create() }
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'returns the recent 10 tasksets' do
|
80
|
+
get "/v1/tasksets/recents"
|
81
|
+
expect(last_response.status).to eq(200)
|
82
|
+
expect(JSON.parse(last_response.body).size).to eq(10)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "GET /v1/tasksets/:key" do
|
88
|
+
context 'with the taskset persisted' do
|
89
|
+
before do
|
90
|
+
Server::Persister.persist(taskset)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns the taskset' do
|
94
|
+
get "/v1/tasksets/#{taskset.key}"
|
95
|
+
expect(last_response.status).to eq(200)
|
96
|
+
expect(JSON.parse(last_response.body)).to eq(
|
97
|
+
JSON.parse(JSON.generate(Server::Persistence::Taskset.first.as_full_json)).update("is_full" => true)
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'with the taskset not persisted' do
|
103
|
+
it 'returns 404' do
|
104
|
+
get "/v1/tasksets/#{taskset.key}"
|
105
|
+
expect(last_response.status).to eq(404)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "GET /v1/batch/tasks/:key" do
|
111
|
+
it 'returns all tasks in the taskset' do
|
112
|
+
get "/v1/batch/tasks/#{taskset.key}"
|
113
|
+
expect(last_response.status).to eq(200)
|
114
|
+
expect(JSON.parse(last_response.body)).to eq([JSON.parse(task.to_json)])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
require 'rrrspec/web'
|
8
|
+
require 'rack/test'
|
9
|
+
require 'database_cleaner'
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
config.run_all_when_everything_filtered = true
|
14
|
+
config.filter_run :focus
|
15
|
+
|
16
|
+
# Run specs in random order to surface order dependencies. If you find an
|
17
|
+
# order dependency and want to debug it, you can fix the order by providing
|
18
|
+
# the seed, which is printed after each run.
|
19
|
+
# --seed 1234
|
20
|
+
config.order = 'random'
|
21
|
+
|
22
|
+
pid = nil
|
23
|
+
config.before(:suite) do
|
24
|
+
pid = Kernel.spawn("redis-server --port 9999 --save ''",
|
25
|
+
in: '/dev/null', out: '/dev/null', err: '/dev/null')
|
26
|
+
redis = Redis.new(port: 9999)
|
27
|
+
retry_count = 1
|
28
|
+
loop do
|
29
|
+
begin
|
30
|
+
redis.client.connect
|
31
|
+
break
|
32
|
+
rescue Redis::CannotConnectError
|
33
|
+
if retry_count < 10
|
34
|
+
retry_count += 1
|
35
|
+
sleep 0.01
|
36
|
+
retry
|
37
|
+
end
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
config.before(:each) do
|
44
|
+
@redis = Redis.new(port: 9999)
|
45
|
+
@redis.flushall
|
46
|
+
|
47
|
+
RRRSpec.configuration = nil
|
48
|
+
RRRSpec.flushredis
|
49
|
+
RRRSpec.hostname = 'testhostname'
|
50
|
+
end
|
51
|
+
|
52
|
+
config.after(:suite) do
|
53
|
+
Process.kill('KILL', pid) if pid
|
54
|
+
end
|
55
|
+
|
56
|
+
def key(*args)
|
57
|
+
args.join(':')
|
58
|
+
end
|
59
|
+
|
60
|
+
config.before(:suite) do
|
61
|
+
ActiveRecord::Base.establish_connection(
|
62
|
+
adapter: "sqlite3", database: ":memory:"
|
63
|
+
)
|
64
|
+
ActiveRecord::Migration.verbose = false
|
65
|
+
ActiveRecord::Migrator.up "#{Gem::Specification.find_by_name('rrrspec-server').gem_dir}/db/migrate"
|
66
|
+
DatabaseCleaner.strategy = :transaction
|
67
|
+
DatabaseCleaner.clean_with(:truncation)
|
68
|
+
end
|
69
|
+
|
70
|
+
config.before(:each) do
|
71
|
+
DatabaseCleaner.start
|
72
|
+
end
|
73
|
+
|
74
|
+
config.after(:each) do
|
75
|
+
DatabaseCleaner.clean
|
76
|
+
end
|
77
|
+
end
|
data/tasks/assets.rake
ADDED
data/views/index.haml
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%meta{charset: 'utf-8', 'http-equiv' => 'Content-Type', content: 'text/html'}
|
5
|
+
%title RRRSpec
|
6
|
+
!= css :application
|
7
|
+
!= js :index
|
8
|
+
%body
|
9
|
+
.index.container
|
10
|
+
.panel.panel-default.active-tasksets
|
11
|
+
.panel-heading
|
12
|
+
.panel-title Active Tasksets
|
13
|
+
%ul.list-group.tasksets
|
14
|
+
|
15
|
+
.index.container
|
16
|
+
.panel.panel-default.recent-tasksets
|
17
|
+
.panel-heading
|
18
|
+
.panel-title Recent Tasksets
|
19
|
+
%ul.list-group.tasksets
|
20
|
+
%ul.pager
|
21
|
+
%li.previous
|
22
|
+
%a{href: "#"} ← Newer
|
23
|
+
%li.next
|
24
|
+
%a{href: "#"}Older →
|
25
|
+
|
26
|
+
.index.container
|
27
|
+
.panel.panel-default.slave-failed-tasksets
|
28
|
+
.panel-heading
|
29
|
+
.panel-title Slave Failed Tasksets
|
30
|
+
%ul.list-group.tasksets
|
31
|
+
%ul.pager
|
32
|
+
%li.previous
|
33
|
+
%a{href: "#"} ← Newer
|
34
|
+
%li.next
|
35
|
+
%a{href: "#"}Older →
|
36
|
+
|
37
|
+
%script#taskset-template{type: 'text/template'}
|
38
|
+
%ul
|
39
|
+
%li.taskset-status
|
40
|
+
{{status}}
|
41
|
+
%li
|
42
|
+
%a{href: "/tasksets/{{key}}"} {{key}}
|
43
|
+
%li.pull-right
|
44
|
+
{{#created_at}}{{created_at}} ({{created_at_humanized}}){{/created_at}}
|
45
|
+
%li.username.pull-right
|
46
|
+
{{rsync_name}}
|