rrrspec-web 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +5 -0
  4. data/Guardfile +4 -0
  5. data/Rakefile +2 -0
  6. data/app/css/application.sass +124 -0
  7. data/app/css/vendor/bootstrap-theme.css +384 -0
  8. data/app/css/vendor/bootstrap-theme.min.css +1 -0
  9. data/app/css/vendor/bootstrap.css +6805 -0
  10. data/app/css/vendor/bootstrap.min.css +9 -0
  11. data/app/js/index.coffee +51 -0
  12. data/app/js/models.coffee +177 -0
  13. data/app/js/tasksets.coffee +305 -0
  14. data/app/js/vendor/backbone-min.js +2 -0
  15. data/app/js/vendor/backbone-min.map +1 -0
  16. data/app/js/vendor/backbone.js +1581 -0
  17. data/app/js/vendor/bootstrap.js +1999 -0
  18. data/app/js/vendor/bootstrap.min.js +6 -0
  19. data/app/js/vendor/jquery-1.10.2.js +9789 -0
  20. data/app/js/vendor/jquery-1.10.2.min.js +6 -0
  21. data/app/js/vendor/jquery-1.10.2.min.map +1 -0
  22. data/app/js/vendor/moment.min.js +6 -0
  23. data/app/js/vendor/mustache.js +551 -0
  24. data/app/js/vendor/underscore-min.js +6 -0
  25. data/app/js/vendor/underscore-min.map +1 -0
  26. data/app/js/vendor/underscore.js +1276 -0
  27. data/compass.config +2 -0
  28. data/lib/rrrspec/web.rb +22 -0
  29. data/lib/rrrspec/web/api.rb +55 -0
  30. data/lib/rrrspec/web/app.rb +48 -0
  31. data/lib/rrrspec/web/configuration.rb +12 -0
  32. data/lib/rrrspec/web/persistent_models.rb +16 -0
  33. data/lib/rrrspec/web/version.rb +5 -0
  34. data/rrrspec-web.gemspec +47 -0
  35. data/spec/rrrspec/web/api_spec.rb +118 -0
  36. data/spec/spec_helper.rb +77 -0
  37. data/tasks/assets.rake +6 -0
  38. data/views/index.haml +46 -0
  39. data/views/taskset.haml +161 -0
  40. data/views/user.haml +33 -0
  41. metadata +379 -0
@@ -0,0 +1,2 @@
1
+ project_path = File.dirname(__FILE__)
2
+ sass_dir = File.join(project_path, 'views')
@@ -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,12 @@
1
+ module RRRSpec
2
+ module Web
3
+ class WebConfiguration < RRRSpec::Configuration
4
+ attr_accessor :persistence_db
5
+
6
+ def initialize
7
+ super()
8
+ @type = :web
9
+ end
10
+ end
11
+ end
12
+ 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
@@ -0,0 +1,5 @@
1
+ module RRRSpec
2
+ module Web
3
+ VERSION = "0.2.0"
4
+ end
5
+ end
@@ -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
@@ -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
@@ -0,0 +1,6 @@
1
+ APP_FILE = File.expand_path('../../lib/rrrspec/web/app.rb', __FILE__)
2
+ APP_CLASS = 'RRRSpec::Web::App'
3
+ require 'sinatra/assetpack/rake'
4
+
5
+ desc 'Build assets'
6
+ task 'assets:precompile' => 'assetpack:build'
@@ -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: "#"} &larr; Newer
23
+ %li.next
24
+ %a{href: "#"}Older &rarr;
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: "#"} &larr; Newer
34
+ %li.next
35
+ %a{href: "#"}Older &rarr;
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}}