baleen 0.0.2 → 0.0.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc7921b0867d0a73836d50b562b35e7cf9692d7f
4
- data.tar.gz: 43d2f2f70271efdd4407247e55e0341ffeb689ae
3
+ metadata.gz: abadaf7bacf699bd38b6bc8825b8decd083de9f5
4
+ data.tar.gz: 8bc97b2c0b3806f1288f736dcc7141fd6a7ce7e1
5
5
  SHA512:
6
- metadata.gz: 2c9f0dab84c29a08f66fe481fa110c26ec6a8bf06b20826077c29cc2333696d7693209ea569d0a587a899144fa5bcefb42be29b4ff2824d4b06be2e68e6d8b78
7
- data.tar.gz: 8ec1a88eac0e64c7402f9a2414c88bb9352a08fda0e68b8fdd3c0d90064e311a331c573f1bdfe4e3550d849f133fc5fe46a80949709e718e20c811e337b7c67a
6
+ metadata.gz: ae47b1bff4d6b98b5cfd3def67984d7aac351b680a807b195c24d1135be62b7e1e60551b90a2b9ab6a593c3a1b87615b4a60b4781880ac9d42eacdd106079f75
7
+ data.tar.gz: 3ead613980c270d3095ba89647391d7a9af188d2edaaebead15ed9c8de08d70f8fe238f41cddb8a662ae68a23ad8aa7e157b9606fdff1334af47ad6c974c2913
data/Gemfile CHANGED
@@ -3,4 +3,5 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in baleen.gemspec
4
4
  gemspec
5
5
 
6
- gem 'docker-client', path: File.expand_path("/Users/kimh/git/docker-ruby", __FILE__)
6
+ #gem 'docker-client', path: File.expand_path("/Users/kimh/git/docker-ruby", __FILE__)
7
+ #gem 'baleen', path: File.expand_path("/Users/kimh/git/baleen", __FILE__)
data/README.md CHANGED
@@ -1,24 +1,64 @@
1
1
  # Baleen
2
+ Baleen is a test runner powered by Docker and Celluloid::IO.
3
+ Baleen allows you to run ruby standard tests such as Cucumber or Rspec in totally isolated environment and parallel.
2
4
 
3
- TODO: Write a gem description
5
+ By using Baleen, you can run feature or spec in a dedicated linux container, so test will not affect the state of other tests.
6
+ Also, Baleen will speed up your tests since multiple containers run their tests in parallel.
7
+
8
+ ## Requirement
9
+ Linux machine with Docker installed
4
10
 
5
11
  ## Installation
6
12
 
7
- Add this line to your application's Gemfile:
13
+ TODO
8
14
 
9
- gem 'baleen'
15
+ ## Usage
10
16
 
11
- And then execute:
12
17
 
13
- $ bundle
18
+ Baleen is server-client model. You need to run baleen-server which talks Docker API to Docker and you can use baleen-client to put your request to the server like below.
14
19
 
15
- Or install it yourself as:
20
+ $ bundle exec baleen cucumber --image kimh/baleen-poc --files features/ --work_dir /git/baleen/poc --before_command "source /etc/profile"
21
+ [Summary]
22
+ Result: Pass
23
+ Time: 0min 38sec
24
+ 12 containers
16
25
 
17
- $ gem install baleen
26
+ [Details]
27
+ Id: 5a836a088480f557bf79a00b0c6e34b36e8432f53ee8b5231b8983d902ae21d9
28
+ status code: 0
29
+ feature file: features/io_bound.feature
30
+ logs:
31
+ ------------------------------------
32
+ Rack::File headers parameter replaces cache_control after Rack 1.5.
33
+ Using the default profile...
34
+ Feature: Benchmark IO intensive feature
35
+
36
+ Scenario: Benchmark for IO bound operation # features/io_bound.feature:2
37
+ Then io intensive operation # features/step_definitions/fake_test_steps.rb:20
38
+
39
+ 1 scenario (1 passed)
40
+ 1 step (1 passed)
41
+ 0m1.556s
42
+
43
+ Id: 1e25993136553319379a07efd61fbc2b86094151fa25df4da0fc613f8c4fe87c
44
+ status code: 0
45
+ feature file: features/io_bound.feature
46
+ logs:
47
+ ------------------------------------
48
+ Rack::File headers parameter replaces cache_control after Rack 1.5.
49
+ Using the default profile...
50
+ Feature: Benchmark IO intensive feature
51
+
52
+ Scenario: Benchmark for IO bound operation # features/io_bound.feature:2
53
+ Then io intensive operation # features/step_definitions/fake_test_steps.rb:20
54
+
55
+ 1 scenario (1 passed)
56
+ 1 step (1 passed)
57
+ 0m1.518s
58
+
59
+ ....snip.....
18
60
 
19
- ## Usage
20
61
 
21
- TODO: Write usage instructions here
22
62
 
23
63
  ## Contributing
24
64
 
@@ -27,3 +67,4 @@ TODO: Write usage instructions here
27
67
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
68
  4. Push to the branch (`git push origin my-new-feature`)
29
69
  5. Create new Pull Request
70
+
data/baleen.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Kim, Hirokuni"]
10
10
  spec.email = ["kimh@kvh.co.jp"]
11
11
  spec.description = %q{Ballen allows you to run standard ruby tests in parallel and isolated environment}
12
- spec.summary = %q{Parallel and container-based test runner powered by Docker}
12
+ spec.summary = %q{Container-based parallel test runner powered by Docker}
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
15
 
data/bin/baleen CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "thor"
4
+ require "baleen"
4
5
 
5
6
  class BaleenCommand < Thor
6
7
 
@@ -9,8 +10,19 @@ class BaleenCommand < Thor
9
10
  option :work_dir, :default => "./"
10
11
  option :files, :default => "features"
11
12
  option :before_command, :default => nil
13
+ option :host, :default => "127.0.0.1"
14
+ option :port, :default => "5533"
12
15
  def cucumber
13
- puts options[:image]
16
+ client = Baleen::Client.new(options[:host], options[:port])
17
+ request = Baleen::Message::Request::Cucumber.new(
18
+ image: options[:image],
19
+ work_dir: options[:work_dir],
20
+ files: options[:files],
21
+ before_command: options[:before_command],
22
+ )
23
+
24
+ job = Baleen::Job.new(client, request)
25
+ job.start
14
26
  end
15
27
  end
16
28
 
data/bin/baleen-server ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "thor"
4
+ require "baleen"
5
+
6
+ def pid
7
+ ### Use this when implement restart command
8
+ #pid = `ps ax | grep -E "baleen-server start|restart" | grep -v grep | awk '{print $1}'`
9
+ pid = `ps ax | grep -E "baleen-server start|restart" | grep -v grep | awk '{print $1}'`
10
+ pid.split("\n")
11
+ end
12
+
13
+ def running?
14
+ pid.size >= 1
15
+ end
16
+
17
+ class BaleenServerCli < Thor
18
+
19
+ desc "start", "Start Baleen server"
20
+ option :docker_host, :default => "127.0.0.1"
21
+ option :docker_port, :default => 4243
22
+ option :port, :default => 5533
23
+ option :debug, :type => :boolean
24
+ def start
25
+ if pid.size > 1
26
+ warning "baleen-server is already running"
27
+ warning "Exiting..."
28
+ exit
29
+ end
30
+
31
+ docker_host = options[:docker_host]
32
+ docker_port = options[:docker_port]
33
+ port = options[:port]
34
+ debug = options[:debug]
35
+
36
+ info "Starting baleen-server..."
37
+ info " Listening on: #{port}"
38
+ info " Docker API: http://#{docker_host}:#{docker_port}"
39
+
40
+ Process.daemon(true, debug)
41
+ Baleen::Server.new(docker_host: docker_host, docker_port: docker_port, port: port)
42
+
43
+ # Prevent main thread from exiting for Celluloid actors to continue running
44
+ # See https://github.com/celluloid/celluloid/wiki/Frequently-Asked-Questions
45
+ sleep
46
+ end
47
+
48
+ desc "stop", "Stop Baleen server"
49
+ def stop
50
+ if running?
51
+ notice "Stopping Baleen server..."
52
+ `kill -9 #{pid.first}`
53
+ else
54
+ notice "baleen-server is not running"
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ BaleenServerCli.start
data/lib/baleen.rb CHANGED
@@ -1,5 +1,14 @@
1
1
  require "baleen/version"
2
2
 
3
+ require 'baleen/client'
4
+ require 'baleen/message/message'
5
+ require 'baleen/task'
6
+ require 'baleen/job'
7
+
8
+ require 'baleen/server'
9
+ require 'baleen/container'
10
+ require 'baleen/runner'
11
+
3
12
  module Baleen
4
13
  # Your code goes here...
5
14
  end
data/lib/baleen/client.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'celluloid/io'
2
2
  require 'celluloid/autostart'
3
+ require 'baleen/utils/colored_puts'
3
4
 
4
5
  module Baleen
5
6
  class Client
@@ -8,16 +9,18 @@ module Baleen
8
9
 
9
10
  def initialize(host, port=12345)
10
11
  @socket = TCPSocket.open(host, port)
11
- @result = "running"
12
- async.response
13
12
  end
14
13
 
15
14
  def request(request)
16
15
  @socket.puts(request.to_json)
17
16
  end
18
17
 
19
- def response
20
- loop { break if handle_response(@socket.gets) }
18
+ def wait_response
19
+ loop {
20
+ if response = handle_response(@socket.gets)
21
+ return response
22
+ end
23
+ }
21
24
  end
22
25
 
23
26
  def close
@@ -32,13 +35,7 @@ module Baleen
32
35
  raise RuntimeError, 'Connection closed by server'
33
36
  end
34
37
 
35
- info "Got response"
36
- @result = Baleen::Message::Decoder.new(response).decode
37
- true
38
- end
39
-
40
- def result
41
- @result
38
+ Baleen::Message::Decoder.new(response).decode
42
39
  end
43
40
 
44
41
  end
@@ -0,0 +1,5 @@
1
+ module Baleen
2
+ module Error
3
+ class StartContainerFail < StandardError; end
4
+ end
5
+ end
data/lib/baleen/job.rb CHANGED
@@ -1,17 +1,28 @@
1
+ require 'baleen/result_display'
2
+
1
3
  module Baleen
2
4
  class Job
3
5
 
4
6
  def initialize(client, msg)
5
7
  @client = client
6
8
  @msg = msg
9
+ @response = nil
7
10
  end
8
11
 
9
12
  def start
13
+ start_time = Time.now
10
14
  @client.request(@msg.params)
15
+ @response = @client.wait_response
16
+ end_time = Time.now
17
+ show_results(start_time, end_time)
11
18
  end
12
19
 
13
- def result
14
- @client.result
20
+ private
21
+
22
+ def show_results(s_time, e_time)
23
+ display = ResultDisplay.new(@response, start_time: s_time, end_time: e_time)
24
+ display.summary
25
+ display.detail
15
26
  end
16
27
 
17
28
  end
@@ -3,7 +3,17 @@ require "json"
3
3
  module Baleen
4
4
  module Message
5
5
 
6
+ def symbolize_keys(hash)
7
+ hash.inject({}){|new_hash, key_value|
8
+ key, value = key_value
9
+ value = symbolize_keys(value) if value.is_a?(Hash)
10
+ new_hash[key.to_sym] = value
11
+ new_hash
12
+ }
13
+ end
14
+
6
15
  class Decoder
16
+ include Baleen::Message
7
17
 
8
18
  def initialize(json_string)
9
19
  @params = JSON.parse(json_string)
@@ -13,27 +23,24 @@ module Baleen
13
23
  klass = @params.delete "klass"
14
24
  Object.const_get(klass).new(symbolize_keys(@params))
15
25
  end
16
-
17
- private
18
-
19
- def symbolize_keys(hash)
20
- hash.inject({}){|new_hash, key_value|
21
- key, value = key_value
22
- value = symbolize_keys(value) if value.is_a?(Hash)
23
- new_hash[key.to_sym] = value
24
- new_hash
25
- }
26
- end
27
26
  end
28
27
 
29
28
  class Base
30
- attr_accessor :json_msg
31
29
 
32
30
  def initialize
33
31
  @params = {}
34
32
  @params[:klass] = self.class.to_s
35
33
  end
36
34
 
35
+ def method_missing(name, *args)
36
+ Base.class_eval{
37
+ define_method "#{name}" do
38
+ @params[name.to_sym]
39
+ end
40
+ }
41
+ send(name)
42
+ end
43
+
37
44
  def params
38
45
  @params
39
46
  end
@@ -0,0 +1,2 @@
1
+ require "baleen/message/request"
2
+ require "baleen/message/response"
@@ -1,4 +1,5 @@
1
1
  require "json"
2
+ require "baleen/message/base"
2
3
 
3
4
  module Baleen
4
5
  module Message
@@ -13,7 +14,7 @@ module Baleen
13
14
  end
14
15
 
15
16
  class Cucumber < Base
16
- def initialize(image: "kimh/baleen-poc", work_dir: "./", files: "./features", shell: "/bin/bash", opt: "-c", exe: "bundle exec cucumber", before_command: nil, command: nil)
17
+ def initialize(image: nil, work_dir: "./", files: "features", shell: "/bin/bash", opt: "-c", exe: "bundle exec cucumber", before_command: nil, command: nil)
17
18
  super()
18
19
  @params[:image] = image
19
20
  @params[:shell] = shell
@@ -1,27 +1,32 @@
1
+ require 'json'
2
+
1
3
  module Baleen
2
4
  module Message
3
5
  module Response
4
6
 
5
- class JobComplete < Base
7
+ class RunnerFinish < Base
8
+
6
9
  def initialize(opt = {})
7
10
  super()
8
11
  @params[:status_code] = opt[:status_code]
9
12
  @params[:log ] = opt[:log]
10
- @params[:container_id ] = opt[:log]
13
+ @params[:container_id ] = opt[:container_id]
14
+ @params[:file] = opt[:file]
11
15
  end
12
-
13
- def status_code; @params[:status_code] end
14
- def log; @params[:log] end
15
- def container_id; @params[:container_id] end
16
16
  end
17
17
 
18
- class RunnerFinish < Base
18
+ class JobComplete < Base
19
+ include Baleen::Message
20
+
19
21
  def initialize(opt = {})
20
22
  super()
21
- @params[:status] = opt[:status]
23
+ @params[:status] = opt[:status]
24
+ @params[:results] = opt[:results]
22
25
  end
23
26
 
24
- def status; @params[:status] end
27
+ def result
28
+ JSON.parse(@params[:results]).map {|r| symbolize_keys(r) }
29
+ end
25
30
  end
26
31
 
27
32
  end
@@ -0,0 +1,47 @@
1
+ require "colorize"
2
+
3
+ module Baleen
4
+ class ResultDisplay
5
+ def initialize(result, start_time: nil, end_time: nil)
6
+ @result = result.result
7
+ @start_time = start_time
8
+ @end_time = end_time
9
+ end
10
+
11
+ def summary
12
+ tests_result = pass_all? ? "Pass".green : "Fail".red
13
+ time = run_time
14
+
15
+ puts ""
16
+ notice "[Summary]"
17
+ puts "Result: ".yellow + tests_result
18
+ puts "Time: ".yellow + time.green
19
+ puts ""
20
+ end
21
+
22
+ def detail
23
+ notice "[Details]"
24
+ @result.each do |r|
25
+ puts "Id: ".yellow + "#{r[:container_id]}".green
26
+ puts "status code: ".yellow + "#{r[:status_code]}".green
27
+ puts "feature file: ".yellow + "#{r[:file]}".green
28
+ puts "logs:".yellow
29
+ puts "------------------------------------".yellow
30
+ puts "#{r[:log]}".green
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def pass_all?
37
+ @result.all? {|r| r[:status_code] == 0}
38
+ end
39
+
40
+ def run_time
41
+ diff = @end_time - @start_time
42
+ min = (diff / 60).floor
43
+ sec = min != 0 ? (diff - (min * 60)).floor : diff.floor
44
+ "#{min}min #{sec}sec"
45
+ end
46
+ end
47
+ end
data/lib/baleen/runner.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "baleen/error"
2
+
1
3
  module Baleen
2
4
 
3
5
  class DockerParam
@@ -49,6 +51,7 @@ module Baleen
49
51
  @containers = containers
50
52
  @socket = socket
51
53
  @queue = []
54
+ @results = []
52
55
  @params = DockerParam.new(msg.params)
53
56
  end
54
57
 
@@ -59,9 +62,9 @@ module Baleen
59
62
  runner.async.run
60
63
  end
61
64
  loop {break if monitor_runners}
65
+ @results += @queue.map {|runner| runner.status.params}
62
66
  end
63
-
64
- msg = Message::Response::RunnerFinish.new(status: "done")
67
+ msg = Message::Response::JobComplete.new(status: "done", results: @results.to_json)
65
68
  @socket.puts(msg.to_json)
66
69
  end
67
70
 
@@ -100,18 +103,30 @@ module Baleen
100
103
 
101
104
  def run
102
105
  start_runner do |result|
103
- @status = Message::Response::JobComplete.new(
106
+ @status = Message::Response::RunnerFinish.new(
104
107
  status_code: result.status_code,
105
108
  container_id: result.container_id,
106
- log: result.log
109
+ log: result.log,
110
+ file: @params.files,
107
111
  )
108
112
  end
109
113
  sleep 0.1 # Stop a moment until RunnerManager checks the status
110
114
  end
111
115
 
112
116
  def start_runner
113
- @docker_client.create_container(@params)
114
- @docker_client.start_container
117
+ max_retry = 3; count = 0
118
+
119
+ begin
120
+ @docker_client.create_container(@params)
121
+ @docker_client.start_container
122
+ rescue Docker::Error::ContainerNotFound => e
123
+ count += 1
124
+ if count > max_retry
125
+ raise Baleen::Error::StartContainerFail
126
+ else
127
+ retry
128
+ end
129
+ end
115
130
  yield( @docker_client.result )
116
131
  end
117
132
 
data/lib/baleen/server.rb CHANGED
@@ -13,11 +13,11 @@ module Baleen
13
13
 
14
14
  attr_accessor :containers
15
15
 
16
- def initialize(host, port: 4243)
17
- @base_url = "http://#{host}:#{port}"
16
+ def initialize(docker_host: "127.0.0.1", docker_port: 4243, port: 5533)
17
+ @base_url = "http://#{docker_host}:#{docker_port}"
18
18
  @docker = Docker::API.new(base_url: @base_url)
19
19
  @containers = @docker.containers
20
- @server = TCPServer.new("127.0.0.1", 12345)
20
+ @server = TCPServer.new("0.0.0.0", port)
21
21
  async.run
22
22
  end
23
23
 
@@ -7,11 +7,11 @@ module Kernel
7
7
  puts msg.green
8
8
  end
9
9
 
10
- def warn(msg)
10
+ def notice(msg)
11
11
  puts msg.yellow
12
12
  end
13
13
 
14
- def error(msg)
14
+ def warning(msg)
15
15
  puts msg.red
16
16
  end
17
17
  end
@@ -1,3 +1,3 @@
1
1
  module Baleen
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -6,7 +6,7 @@ CiApp::Application.configure do
6
6
  # since you don't have to restart the web server when you make code changes.
7
7
  config.cache_classes = false
8
8
 
9
- # Log error messages when you accidentally call methods on nil.
9
+ # Log error message when you accidentally call methods on nil.
10
10
  config.whiny_nils = true
11
11
 
12
12
  # Show full error reports and disable caching
@@ -11,7 +11,7 @@ CiApp::Application.configure do
11
11
  config.serve_static_assets = true
12
12
  config.static_cache_control = "public, max-age=3600"
13
13
 
14
- # Log error messages when you accidentally call methods on nil
14
+ # Log error message when you accidentally call methods on nil
15
15
  config.whiny_nils = true
16
16
 
17
17
  # Show full error reports and disable caching
@@ -2,11 +2,11 @@ Feature: t1
2
2
  Scenario: Benchmark for IO bound operation
3
3
  Then io intensive operation
4
4
 
5
- Scenario: Benchmark for CPU bound operation
6
- Then cpu intensive operation
5
+ #Scenario: Benchmark for CPU bound operation
6
+ # Then cpu intensive operation
7
7
 
8
- Scenario: Benchmark for IO bound operation
9
- Then io intensive operation
8
+ #Scenario: Benchmark for IO bound operation
9
+ # Then io intensive operation
10
10
 
11
- Scenario: Benchmark for CPU bound operation
12
- Then cpu intensive operation
11
+ #Scenario: Benchmark for CPU bound operation
12
+ # Then cpu intensive operation
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: baleen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kim, Hirokuni
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-09 00:00:00.000000000 Z
11
+ date: 2013-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -142,6 +142,7 @@ email:
142
142
  - kimh@kvh.co.jp
143
143
  executables:
144
144
  - baleen
145
+ - baleen-server
145
146
  extensions: []
146
147
  extra_rdoc_files: []
147
148
  files:
@@ -152,13 +153,17 @@ files:
152
153
  - Rakefile
153
154
  - baleen.gemspec
154
155
  - bin/baleen
156
+ - bin/baleen-server
155
157
  - lib/baleen.rb
156
158
  - lib/baleen/client.rb
157
159
  - lib/baleen/container.rb
160
+ - lib/baleen/error.rb
158
161
  - lib/baleen/job.rb
159
- - lib/baleen/messages/messages.rb
160
- - lib/baleen/messages/request.rb
161
- - lib/baleen/messages/response.rb
162
+ - lib/baleen/message/base.rb
163
+ - lib/baleen/message/message.rb
164
+ - lib/baleen/message/request.rb
165
+ - lib/baleen/message/response.rb
166
+ - lib/baleen/result_display.rb
162
167
  - lib/baleen/runner.rb
163
168
  - lib/baleen/server.rb
164
169
  - lib/baleen/task.rb
@@ -258,5 +263,5 @@ rubyforge_project:
258
263
  rubygems_version: 2.0.3
259
264
  signing_key:
260
265
  specification_version: 4
261
- summary: Parallel and container-based test runner powered by Docker
266
+ summary: Container-based parallel test runner powered by Docker
262
267
  test_files: []