bounscale 0.0.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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bounscale.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 DTS Corporation
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Bounscale
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'bounscale'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install bounscale
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bounscale.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bounscale/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "bounscale"
8
+ gem.version = Bounscale::VERSION
9
+ gem.authors = ["DTS Corporation"]
10
+ gem.email = ["info@bounscale.com"]
11
+ gem.description = %q{Rack agent of auto scaling for Heroku by Bounscale.}
12
+ gem.summary = %q{Rack agent for Bounscale}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'json'
21
+ gem.add_development_dependency "rspec"
22
+ end
@@ -0,0 +1,13 @@
1
+ module Bounscale
2
+ module Collector
3
+ class Base
4
+ def pre
5
+
6
+ end
7
+
8
+ def post
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,61 @@
1
+ class Bounscale::Collector::Busyness < Bounscale::Collector::Base
2
+ HISTORY_HOLDING_SEC = 10
3
+
4
+ class << self
5
+ def clear_history!
6
+ Thread.current[:bounscale_busyness_history] = []
7
+ end
8
+ end
9
+
10
+ def pre
11
+ @pre_time = Time.now
12
+ end
13
+
14
+ def post
15
+ @post_time = Time.now
16
+ history << [@pre_time, @post_time]
17
+ fix_history
18
+ end
19
+
20
+ def name
21
+ "busyness"
22
+ end
23
+
24
+ def value
25
+ #2つ以上のアクセスがないと測定不能なので0を返す
26
+ return 0 if history.length < 2
27
+
28
+ #積算値 / 全体の秒数 がビジー率(%なので100をかける)
29
+ (estimate_sec / whole_sec) * 100
30
+ end
31
+
32
+ private
33
+ def history
34
+ Thread.current[:bounscale_busyness_history] ||= []
35
+ Thread.current[:bounscale_busyness_history]
36
+ end
37
+
38
+ def fix_history
39
+ history.delete_if do |h|
40
+ (@post_time.to_f - h[1].to_f) > HISTORY_HOLDING_SEC
41
+ end
42
+ end
43
+
44
+ def whole_sec
45
+ #履歴の最初から最後までの秒数を算出
46
+ oldest_pre = history[0][0].to_f
47
+ newest_post = history[-1][1].to_f
48
+ whole_sec = newest_post - oldest_pre
49
+ end
50
+
51
+ def estimate_sec
52
+ #各履歴の所要時間の積算値を算出
53
+ result = 0.0
54
+ history.each do |h|
55
+ pre_time = h[0].to_f
56
+ post_time = h[1].to_f
57
+ result += (post_time - pre_time)
58
+ end
59
+ result
60
+ end
61
+ end
@@ -0,0 +1,21 @@
1
+ class Bounscale::Collector::Cpu < Bounscale::Collector::Base
2
+ def pre
3
+ @pre_user_time = Process.times.utime
4
+ @pre_system_time = Process.times.stime
5
+ end
6
+
7
+ def post
8
+ @post_user_time = Process.times.utime
9
+ @post_system_time = Process.times.stime
10
+ @elapsed_user_time = @post_user_time - @pre_user_time
11
+ @elapsed_system_time = @post_system_time - @pre_system_time
12
+ end
13
+
14
+ def name
15
+ "cpu"
16
+ end
17
+
18
+ def value
19
+ (@elapsed_user_time + @elapsed_system_time) * 1000
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ class Bounscale::Collector::Memory < Bounscale::Collector::Base
2
+ def pre
3
+ end
4
+
5
+ def post
6
+ process = $$
7
+ @post_memory = ps_value(process).split("\n")[1].to_f / 1024.0 rescue 0
8
+ end
9
+
10
+ def name
11
+ "memory"
12
+ end
13
+
14
+ def value
15
+ @post_memory
16
+ end
17
+
18
+ def ps_value(process)
19
+ `ps -o rsz #{process}`
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ class Bounscale::Collector::Throughput < Bounscale::Collector::Busyness
2
+ def pre
3
+ end
4
+
5
+ def post
6
+ end
7
+
8
+ def name
9
+ "throughput"
10
+ end
11
+
12
+ def value
13
+ #2つ以上のアクセスがないと測定不能なので0を返す
14
+ return 0 if history.length < 2
15
+
16
+ #リクエスト数 / 全体の時間 がスループット(分あたり換算なので60をかける)
17
+ (history.length.to_f / whole_sec) * 60
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ require "bounscale/collector/base"
2
+
3
+ module Bounscale
4
+ class Middleware
5
+ COLLECTOR_CLASSES = [
6
+ Bounscale::Collector::Cpu,
7
+ Bounscale::Collector::Memory,
8
+ Bounscale::Collector::Busyness,
9
+ Bounscale::Collector::Throughput
10
+ ]
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ collector_instances = COLLECTOR_CLASSES.map do |klass|
17
+ collector = klass.new
18
+ collector.pre
19
+ collector
20
+ end
21
+
22
+ app_response = @app.call(env)
23
+
24
+ collector_instances.each do |collector|
25
+ collector.post
26
+ end
27
+
28
+ Bounscale::Writer::HerokuWriter.new.write(collector_instances)
29
+ return app_response
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module Bounscale
2
+ class Railtie < ::Rails::Railtie
3
+ initializer "bounscale.add_middleware" do |app|
4
+ app.middleware.use Bounscale::Middleware
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Bounscale
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'json'
2
+
3
+ module Bounscale
4
+ module Writer
5
+ class Base
6
+ FORMAT_VERSION = 0
7
+ BOUNSCALE_OPEN_UUID = "b74e646e-7e55-448f-814d-e36eedc44ea9"
8
+ BOUNSCALE_CLOSE_UUID = "4a061908-db52-4224-ad4b-9850a47c7edf"
9
+
10
+ class << self
11
+ def strip_uuid(str)
12
+ str.gsub(BOUNSCALE_OPEN_UUID, "").gsub(BOUNSCALE_CLOSE_UUID, "")
13
+ end
14
+ end
15
+
16
+ def write(collector_instances)
17
+ result = {:format_ver => FORMAT_VERSION, :datetime => Time.now.to_s, :data => []}
18
+ result[:framework_ver] = defined?(Rails) ? "Rails " + Rails::VERSION::STRING : "Not Support"
19
+ collector_instances.each do |collector|
20
+ result[:data] << {:name => collector.name, :value => collector.value}
21
+ end
22
+ str = "#{BOUNSCALE_OPEN_UUID}#{result.to_json}#{BOUNSCALE_CLOSE_UUID}"
23
+ self.output(str)
24
+ str
25
+ end
26
+
27
+ def output(str)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ class Bounscale::Writer::HerokuWriter < Bounscale::Writer::Base
2
+ def output(str)
3
+ puts str
4
+ end
5
+ end
data/lib/bounscale.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "rubygems"
2
+
3
+ require "bounscale/version"
4
+
5
+ require "bounscale/collector/base"
6
+ require "bounscale/collector/cpu"
7
+ require "bounscale/collector/memory"
8
+ require "bounscale/collector/busyness"
9
+ require "bounscale/collector/throughput"
10
+
11
+ require "bounscale/writer/base"
12
+ require "bounscale/writer/heroku_writer"
13
+
14
+ require "bounscale/middlerware"
15
+ require "bounscale/railtie" if defined?(Rails::Railtie)
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ビジー率を取得できていることを確認する" do
4
+ before do
5
+ Bounscale::Collector::Busyness.clear_history!
6
+ end
7
+
8
+ it "collection名がbusynessであること" do
9
+ busy = Bounscale::Collector::Busyness.new
10
+ busy.name.should == "busyness"
11
+ end
12
+
13
+ it "ビジー率は%であること" do
14
+ base_time = Time.parse("2013/1/1 00:00:00")
15
+ busy = Bounscale::Collector::Busyness.new
16
+ Thread.current[:bounscale_busyness_history] = [
17
+ [base_time, base_time + 3],
18
+ [base_time + 8, base_time + 9]
19
+ ]
20
+ #%なので100をかける
21
+ busy.value.should == (4.0/9.0) * 100
22
+ end
23
+
24
+ it "2つ以上の履歴がない場合は0を返す事" do
25
+ base_time = Time.parse("2013/1/1 00:00:00")
26
+ busy = Bounscale::Collector::Busyness.new
27
+
28
+ Thread.current[:bounscale_busyness_history] = []
29
+ busy.value.should == 0
30
+
31
+ Thread.current[:bounscale_busyness_history] = [
32
+ [base_time, base_time + 3]
33
+ ]
34
+ busy.value.should == 0
35
+
36
+ Thread.current[:bounscale_busyness_history] = [
37
+ [base_time, base_time + 3],
38
+ [base_time + 8, base_time + 9]
39
+ ]
40
+ busy.value.should_not == 0
41
+
42
+ end
43
+
44
+ it "ビジー率が取得できることを確認(モック)" do
45
+ #1秒→(2秒)→3秒→(4秒)→5秒の場合
46
+ fake_now = Time.parse("2013/1/1 00:00:00")
47
+
48
+ busy = Bounscale::Collector::Busyness.new
49
+ #[]サンプルが1つもないと0を返す
50
+ busy.value.should == 0
51
+
52
+ Time.stub!(:now).and_return(fake_now)
53
+ busy.pre
54
+ Time.stub!(:now).and_return(fake_now + 1)
55
+ busy.post
56
+
57
+ #[1]サンプルが一つしかないと0を返す
58
+ busy.value.should == 0
59
+
60
+ busy = Bounscale::Collector::Busyness.new
61
+ Time.stub!(:now).and_return(fake_now + 1 + 2)
62
+ busy.pre
63
+ Time.stub!(:now).and_return(fake_now + 1 + 2 + 3)
64
+ busy.post
65
+
66
+ #[1, (2), 3]なので4/6がビジー率
67
+ busy.value.should == (4.0 / 6.0) * 100
68
+
69
+ busy = Bounscale::Collector::Busyness.new
70
+ Time.stub!(:now).and_return(fake_now + 1 + 2 + 3 + 4)
71
+ busy.pre
72
+ Time.stub!(:now).and_return(fake_now + 1 + 2 + 3 + 4 + 5)
73
+ busy.post
74
+
75
+ #[1, (2), 3, (4), 5]だが、処理終端が10秒前以前は消えるので
76
+ #[3, (4), 5]で、8/12がビジー率
77
+ busy.value.should == (8.0 / 12.0) * 100
78
+ end
79
+
80
+ it "ビジー率がモックなしで大体取得できることを確認" do
81
+ busy = nil
82
+ 10.times do
83
+ busy = Bounscale::Collector::Busyness.new
84
+ busy.name.should eq "busyness"
85
+ busy.pre
86
+ sleep(0.01)
87
+ busy.post
88
+ sleep(0.04)
89
+ end
90
+ busy.value.should > 20
91
+ busy.value.should < 40
92
+ end
93
+
94
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Collectorの枠組みを確認する" do
4
+ it "枠組みとなるメソッドを実行できること" do
5
+ base = Bounscale::Collector::Base.new
6
+ base.pre.should == nil
7
+ base.post.should == nil
8
+ end
9
+ end
data/spec/cpu_spec.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe "CPU時間を取得できていることを確認する" do
4
+ it "CPU時間が取得できることを確認" do
5
+ cpu = Bounscale::Collector::Cpu.new
6
+ cpu.name.should eq "cpu"
7
+ cpu.pre
8
+ 1000000.times{}
9
+ cpu.post
10
+ cpu.value.should > 0
11
+ end
12
+
13
+ it "collector名がcpuであること" do
14
+ cpu = Bounscale::Collector::Cpu.new
15
+ cpu.name.should == "cpu"
16
+ end
17
+
18
+ it "user/system timeを足したCPU時間がミリ秒で返却されること" do
19
+ cpu = Bounscale::Collector::Cpu.new
20
+
21
+ times = double(:utime => 0.001, :stime => 0.002)
22
+ Process.stub!(:times).and_return(times)
23
+
24
+ cpu.pre
25
+
26
+ times = double(:utime => 0.005, :stime => 0.008)
27
+ Process.stub!(:times).and_return(times)
28
+
29
+ cpu.post
30
+ cpu.value.should == 10
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe "文字列化が正常にできることの確認" do
4
+ before :each do
5
+ fake_now = Time.parse("2013/01/01 00:00:00")
6
+ Time.stub!(:now).and_return(fake_now)
7
+ end
8
+
9
+ it "データが標準出力に書き込まれていること" do
10
+ collectors = [
11
+ double(:name => "collector1", :value => 10),
12
+ double(:name => "collector2", :value => 20)
13
+ ]
14
+
15
+ str = capture(:stdout) {
16
+ writer = Bounscale::Writer::HerokuWriter.new
17
+ str = writer.write(collectors)
18
+ }
19
+
20
+ str.include?("b74e646e-7e55-448f-814d-e36eedc44ea9").should be_true
21
+ str.include?("\"datetime\":\"Tue Jan 01 00:00:00 +0000 2013\"").should be_true
22
+ str.include?("\"framework_ver\":\"Not Support\"").should be_true
23
+ str.include?("\"data\":[{\"value\":10,\"name\":\"collector1\"},{\"value\":20,\"name\":\"collector2\"}]").should be_true
24
+ str.include?("\"format_ver\":0").should be_true
25
+ str.include?("4a061908-db52-4224-ad4b-9850a47c7edf").should be_true
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe "メモリ使用量を取得できていることを確認する" do
4
+ it "collector名がmemoryであること" do
5
+ mem = Bounscale::Collector::Memory.new
6
+ mem.name.should == "memory"
7
+ end
8
+
9
+ it "メモリ使用量が取得できること(モック)" do
10
+ dummy_ps = " RSZ\n2036 \n780"
11
+ mem = Bounscale::Collector::Memory.new
12
+ mem.stub!(:ps_value).and_return(dummy_ps)
13
+ mem.pre
14
+ mem.post
15
+ mem.value.should == 2036.to_f / 1024
16
+ end
17
+
18
+ it "メモリ使用量が正常に取得できない場合0が返ること" do
19
+ mem = Bounscale::Collector::Memory.new
20
+ mem.should_receive(:ps_value) do
21
+ raise
22
+ end
23
+ mem.pre
24
+ mem.post
25
+ mem.value.should == 0
26
+ end
27
+
28
+ it "モックなしでメモリ使用量が大体取得できることを確認" do
29
+ mem = Bounscale::Collector::Memory.new
30
+ mem.name.should eq "memory"
31
+ mem.pre
32
+ mem.post
33
+ mem.value.should > 0
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ class Bounscale::MockApp
4
+ attr_accessor :called
5
+
6
+ def initialize
7
+ self.called = false
8
+ end
9
+
10
+ def call(env)
11
+ self.called = true
12
+ end
13
+ end
14
+
15
+ describe "情報を収集し、書きこめていることを確認する" do
16
+ before do
17
+ Bounscale::Collector::Busyness.clear_history!
18
+ end
19
+
20
+ it "情報を収集できていること" do
21
+ $stdout = StringIO.new
22
+
23
+ mock_app = Bounscale::MockApp.new
24
+ middleware = Bounscale::Middleware.new(mock_app)
25
+ result = middleware.call(ENV)
26
+
27
+ out = $stdout.string
28
+ $stdout = STDOUT
29
+
30
+ out = Bounscale::Writer::Base.strip_uuid(out)
31
+ result_json = JSON.parse(out)
32
+ result_json["format_ver"].should eq 0
33
+ result_json["data"][0]["name"].should eq "cpu"
34
+ result_json["data"][0]["value"].should eq 0
35
+ result_json["data"][1]["name"].should eq "memory"
36
+ result_json["data"][1]["value"].should > 0
37
+ result_json["data"][2]["name"].should eq "busyness"
38
+ result_json["data"][2]["value"].should eq 0
39
+ result_json["data"][3]["name"].should eq "throughput"
40
+ result_json["data"][3]["value"].should eq 0
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'lib/bounscale'
4
+
5
+ require 'time'
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_framework = :rspec
9
+ end
10
+
11
+ def capture(stream)
12
+ begin
13
+ stream = stream.to_s
14
+ eval "$#{stream} = StringIO.new"
15
+ yield
16
+ result = eval("$#{stream}").string
17
+ ensure
18
+ eval "$#{stream} = #{stream.upcase}"
19
+ end
20
+ result
21
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe "スループットを取得できていることを確認する" do
4
+ before :each do
5
+ Bounscale::Collector::Busyness.clear_history!
6
+ end
7
+
8
+ it "collector名がthroughputであること" do
9
+ th = Bounscale::Collector::Throughput.new
10
+ th.name.should == "throughput"
11
+ end
12
+
13
+ it "Busynessで収集された履歴を用いてリクエスト数/全体の時間の分辺りの値で算出すること" do
14
+ base_time = Time.parse("2013/1/1 00:00:00")
15
+ throughput = Bounscale::Collector::Throughput.new
16
+ Thread.current[:bounscale_busyness_history] = [
17
+ [base_time, base_time + 3],
18
+ [base_time + 8, base_time + 9]
19
+ ]
20
+
21
+ #2リクエストが9秒の間にきている負荷の分辺りの負荷がスループット
22
+ throughput.value.should == ((2 / 9.0) * 60.0)
23
+ end
24
+
25
+ it "履歴が2つ以下の場合スループットは0を返す事" do
26
+ base_time = Time.parse("2013/1/1 00:00:00")
27
+ throughput = Bounscale::Collector::Throughput.new
28
+ Thread.current[:bounscale_busyness_history] = []
29
+ throughput.value.should == 0
30
+
31
+ Thread.current[:bounscale_busyness_history] = [
32
+ [base_time, base_time + 3]
33
+ ]
34
+ throughput.value.should == 0
35
+
36
+ Thread.current[:bounscale_busyness_history] = [
37
+ [base_time, base_time + 3],
38
+ [base_time + 8, base_time + 9]
39
+ ]
40
+ throughput.value.should_not == 0
41
+ end
42
+
43
+ it "スループットが取得できる事を確認(モック)" do
44
+ #1秒→(2秒)→3秒→(4秒)→5秒の場合
45
+ fake_now = Time.parse("2013/1/1 00:00:00")
46
+
47
+ busy = Bounscale::Collector::Busyness.new
48
+ th = Bounscale::Collector::Throughput.new
49
+
50
+ Time.stub!(:now).and_return(fake_now)
51
+ busy.pre
52
+ th.pre
53
+ Time.stub!(:now).and_return(fake_now + 1)
54
+ busy.post
55
+ th.post
56
+
57
+ #[1]サンプルが一つしかないと0を返す
58
+ th.value.should == 0
59
+
60
+ busy = Bounscale::Collector::Busyness.new
61
+ th = Bounscale::Collector::Throughput.new
62
+
63
+ Time.stub!(:now).and_return(fake_now + 1 + 2)
64
+ busy.pre
65
+ th.pre
66
+ Time.stub!(:now).and_return(fake_now + 1 + 2 + 3)
67
+ busy.post
68
+ th.post
69
+
70
+ #[1, (2), 3]なので2/6がスループット
71
+ th.value.should == (2 / 6.0) * 60
72
+
73
+ busy = Bounscale::Collector::Busyness.new
74
+ th = Bounscale::Collector::Throughput.new
75
+ Time.stub!(:now).and_return(fake_now + 1 + 2 + 3 + 4)
76
+ busy.pre
77
+ th.pre
78
+ Time.stub!(:now).and_return(fake_now + 1 + 2 + 3 + 4 + 5)
79
+ busy.post
80
+ th.post
81
+
82
+ #[1, (2), 3, (4), 5]だが、処理終端が10秒前以前は消えるので
83
+ #[3, (4), 5]で、3/12がスループット
84
+ th.value.should == (2 / 12.0) * 60
85
+ end
86
+
87
+ it "スループットがモックなしで代替の値で取得できることを確認" do
88
+ throughput = nil
89
+ 10.times do
90
+ busyness = Bounscale::Collector::Busyness.new
91
+ throughput = Bounscale::Collector::Throughput.new
92
+ throughput.name.should eq "throughput"
93
+ busyness.pre
94
+ busyness.post
95
+ sleep(0.1)
96
+ end
97
+ throughput.value.should > 500
98
+ throughput.value.should < 700
99
+ end
100
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe "文字列化が正常にできることの確認" do
4
+ before :each do
5
+ fake_now = Time.parse("2013/01/01 00:00:00")
6
+ Time.stub!(:now).and_return(fake_now)
7
+ end
8
+
9
+ it "ひきわたされたcollectorの情報が全て書き込み文字列に含まれていること" do
10
+ collectors = [
11
+ double(:name => "collector1", :value => 10),
12
+ double(:name => "collector2", :value => 20)
13
+ ]
14
+ writer = Bounscale::Writer::Base.new
15
+ str = writer.write(collectors)
16
+
17
+ str.include?("b74e646e-7e55-448f-814d-e36eedc44ea9").should be_true
18
+ str.include?("\"datetime\":\"Tue Jan 01 00:00:00 +0000 2013\"").should be_true
19
+ str.include?("\"framework_ver\":\"Not Support\"").should be_true
20
+ str.include?("\"data\":[{\"value\":10,\"name\":\"collector1\"},{\"value\":20,\"name\":\"collector2\"}]").should be_true
21
+ str.include?("\"format_ver\":0").should be_true
22
+ str.include?("4a061908-db52-4224-ad4b-9850a47c7edf").should be_true
23
+ end
24
+
25
+ it "フレームワークバージョンが書きこまれていること" do
26
+ class Rails
27
+ class VERSION
28
+ STRING = "9.9.9"
29
+ end
30
+ end
31
+
32
+ writer = Bounscale::Writer::Base.new
33
+ str = writer.write([])
34
+ str.include?("\"framework_ver\":\"Not Support\"").should be_false
35
+ str.include?("\"framework_ver\":\"Rails 9.9.9\"").should be_true
36
+ end
37
+
38
+ it "想定しないフレームワークではフレームワークバージョンが書きこまれないこと" do
39
+ Object.class_eval do
40
+ remove_const :Rails
41
+ end
42
+
43
+ writer = Bounscale::Writer::Base.new
44
+ str = writer.write([])
45
+
46
+ str.include?("\"framework_ver\":\"Not Support\"").should be_true
47
+ end
48
+
49
+ it "フォーマットバージョンが書きこまれていること" do
50
+ writer = Bounscale::Writer::Base.new
51
+ str = writer.write([])
52
+
53
+ str.include?("\"format_ver\":0").should be_true
54
+ end
55
+
56
+ it "識別用UUIDに囲まれた領域をくくりだせること" do
57
+ before_str = "b74e646e-7e55-448f-814d-e36eedc44ea9DUMMYSTRING4a061908-db52-4224-ad4b-9850a47c7edf"
58
+ after_str = Bounscale::Writer::Base.strip_uuid(before_str)
59
+ after_str.should == "DUMMYSTRING"
60
+ end
61
+
62
+ it "取得したデータがJSON形式でパースできること" do
63
+ writer = Bounscale::Writer::HerokuWriter.new
64
+ str = writer.write([])
65
+ str = Bounscale::Writer::Base.strip_uuid(str)
66
+ result = JSON.parse(str)
67
+ result["format_ver"].should eq 0
68
+ (Time.now.to_i - Time.parse(result["datetime"]).to_i).should < 10
69
+ end
70
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bounscale
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - DTS Corporation
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-06-21 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id002
48
+ description: Rack agent of auto scaling for Heroku by Bounscale.
49
+ email:
50
+ - info@bounscale.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gitignore
59
+ - Gemfile
60
+ - LICENSE.txt
61
+ - README.md
62
+ - Rakefile
63
+ - bounscale.gemspec
64
+ - lib/bounscale.rb
65
+ - lib/bounscale/collector/base.rb
66
+ - lib/bounscale/collector/busyness.rb
67
+ - lib/bounscale/collector/cpu.rb
68
+ - lib/bounscale/collector/memory.rb
69
+ - lib/bounscale/collector/throughput.rb
70
+ - lib/bounscale/middlerware.rb
71
+ - lib/bounscale/railtie.rb
72
+ - lib/bounscale/version.rb
73
+ - lib/bounscale/writer/base.rb
74
+ - lib/bounscale/writer/heroku_writer.rb
75
+ - spec/busyness_spec.rb
76
+ - spec/collector_base_spec.rb
77
+ - spec/cpu_spec.rb
78
+ - spec/heroku_writer_spec.rb
79
+ - spec/memory_spec.rb
80
+ - spec/middleware_spec.rb
81
+ - spec/spec_helper.rb
82
+ - spec/throughput_spec.rb
83
+ - spec/writer_base_spec.rb
84
+ homepage: ""
85
+ licenses: []
86
+
87
+ post_install_message:
88
+ rdoc_options: []
89
+
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ requirements: []
111
+
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.25
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: Rack agent for Bounscale
117
+ test_files:
118
+ - spec/busyness_spec.rb
119
+ - spec/collector_base_spec.rb
120
+ - spec/cpu_spec.rb
121
+ - spec/heroku_writer_spec.rb
122
+ - spec/memory_spec.rb
123
+ - spec/middleware_spec.rb
124
+ - spec/spec_helper.rb
125
+ - spec/throughput_spec.rb
126
+ - spec/writer_base_spec.rb