drone 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,138 @@
1
+ require File.expand_path('../../common', __FILE__)
2
+
3
+ require 'drone/utils/ewma'
4
+
5
+ describe 'EWMA' do
6
+
7
+ describe 'A 1min EWMA with a value of 3' do
8
+ before do
9
+ @ewma = EWMA.one_minute_ewma
10
+ @ewma.update(3)
11
+ @ewma.tick()
12
+ end
13
+
14
+
15
+ def mark_minutes(minutes)
16
+ 1.upto( (minutes*60.0) / 5 ) do
17
+ @ewma.tick()
18
+ end
19
+ end
20
+
21
+ should "have a rate of 0.6 events/sec after the first tick" do
22
+ @ewma.rate.should.be.close(0.6, 0.000001)
23
+ end
24
+
25
+ {
26
+ 1 => 0.22072766,
27
+ 2 => 0.08120117,
28
+ 3 => 0.02987224,
29
+ 4 => 0.01098938,
30
+ 5 => 0.00404277,
31
+ 6 => 0.00148725,
32
+ 7 => 0.00054713,
33
+ 8 => 0.00020128,
34
+ 9 => 0.00007405,
35
+ 10 => 0.00002724,
36
+ 11 => 0.00001002,
37
+ 12 => 0.00000369,
38
+ 13 => 0.00000136,
39
+ 14 => 0.00000050,
40
+ 15 => 0.00000018
41
+
42
+ }.each do |minutes, expected|
43
+ should "have a rate of #{expected} events/sec after #{minutes} minute(s)" do
44
+ mark_minutes(minutes)
45
+ @ewma.rate.should.be.close(expected, 0.00000001)
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+
52
+
53
+ describe 'A 5min EWMA with a value of 3' do
54
+ before do
55
+ @ewma = EWMA.five_minutes_ewma
56
+ @ewma.update(3)
57
+ @ewma.tick()
58
+ end
59
+
60
+ should "have a rate of 0.6 events/sec after the first tick" do
61
+ @ewma.rate.should.be.close(0.6, 0.000001)
62
+ end
63
+
64
+ def mark_minutes(minutes)
65
+ 1.upto( (minutes*60.0) / 5 ) do
66
+ @ewma.tick()
67
+ end
68
+ end
69
+
70
+ {
71
+ 1 => 0.49123845,
72
+ 2 => 0.40219203,
73
+ 3 => 0.32928698,
74
+ 4 => 0.26959738,
75
+ 5 => 0.22072766,
76
+ 6 => 0.18071653,
77
+ 7 => 0.14795818,
78
+ 8 => 0.12113791,
79
+ 9 => 0.09917933,
80
+ 10 => 0.08120117,
81
+ 11 => 0.06648190,
82
+ 12 => 0.05443077,
83
+ 13 => 0.04456415,
84
+ 14 => 0.03648604,
85
+ 15 => 0.02987224
86
+ }.each do |minutes, expected|
87
+ should "have a rate of #{expected} events/sec after #{minutes} minute(s)" do
88
+ mark_minutes(minutes)
89
+ @ewma.rate.should.be.close(expected, 0.00000001)
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+
96
+ describe 'A 15min EWMA with a value of 3' do
97
+ before do
98
+ @ewma = EWMA.fifteen_minutes_ewma
99
+ @ewma.update(3)
100
+ @ewma.tick()
101
+ end
102
+
103
+ should "have a rate of 0.6 events/sec after the first tick" do
104
+ @ewma.rate.should.be.close(0.6, 0.000001)
105
+ end
106
+
107
+ def mark_minutes(minutes)
108
+ 1.upto( (minutes*60.0) / 5 ) do
109
+ @ewma.tick()
110
+ end
111
+ end
112
+
113
+ {
114
+ 1 => 0.56130419,
115
+ 2 => 0.52510399,
116
+ 3 => 0.49123845,
117
+ 4 => 0.45955700,
118
+ 5 => 0.42991879,
119
+ 6 => 0.40219203,
120
+ 7 => 0.37625345,
121
+ 8 => 0.35198773,
122
+ 9 => 0.32928698,
123
+ 10 => 0.30805027,
124
+ 11 => 0.28818318,
125
+ 12 => 0.26959738,
126
+ 13 => 0.25221023,
127
+ 14 => 0.23594443,
128
+ 15 => 0.22072766
129
+ }.each do |minutes, expected|
130
+ should "have a rate of #{expected} events/sec after #{minutes} minute(s)" do
131
+ mark_minutes(minutes)
132
+ @ewma.rate.should.be.close(expected, 0.00000001)
133
+ end
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1,83 @@
1
+ require File.expand_path('../../common', __FILE__)
2
+
3
+ require 'drone/utils/exponentially_decaying_sample'
4
+
5
+ describe 'Exponentially Decaying Sample' do
6
+ describe "A sample of 100 out of 1000 elements" do
7
+ before do
8
+ @population = (0...100)
9
+ @sample = ExponentiallyDecayingSample.new(1000, 0.99)
10
+ @population.step(1){|n| @sample.update(n) }
11
+ end
12
+
13
+
14
+ should "have 100 elements" do
15
+ @sample.size.should == 100
16
+ @sample.values.size.should == 100
17
+ end
18
+
19
+ should "only have elements from the population" do
20
+ arr = @sample.values - @population.to_a
21
+ arr.should == []
22
+ end
23
+
24
+ end
25
+
26
+
27
+ describe "A sample of 100 out of 10 elements" do
28
+ before do
29
+ @population = (0...10)
30
+ @sample = ExponentiallyDecayingSample.new(100, 0.99)
31
+ @population.step(1){|n| @sample.update(n) }
32
+ end
33
+
34
+ should "have 10 elements" do
35
+ @sample.size.should == 10
36
+ @sample.values.size.should == 10
37
+ end
38
+
39
+ should "only have elements from the population" do
40
+ arr = @sample.values - @population.to_a
41
+ arr.should == []
42
+ end
43
+
44
+ end
45
+
46
+
47
+ describe "A heavily-biased sample of 100 out of 1000 elements" do
48
+ before do
49
+ @population = (0...100)
50
+ @sample = ExponentiallyDecayingSample.new(1000, 0.99)
51
+ @population.step(1){|n| @sample.update(n) }
52
+ end
53
+
54
+ should "have 100 elements" do
55
+ @sample.size.should == 100
56
+ @sample.values.size.should == 100
57
+ end
58
+
59
+ should "only have elements from the population" do
60
+ arr = @sample.values - @population.to_a
61
+ arr.should == []
62
+ end
63
+
64
+ should "rescale after 1 hour" do
65
+ @sample.expects(:rescale)
66
+
67
+ Delorean.time_travel_to("2 hours from now") do
68
+ @sample.update(1)
69
+ end
70
+
71
+ @sample.size.should == 101
72
+ @sample.values.size.should == 101
73
+ end
74
+
75
+ it 'can rescale' do
76
+ @sample.rescale(Time.now)
77
+ @sample.values.should.not == []
78
+ # TODO: add a real test here, for now it only tests
79
+ # that the code actually runs
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,87 @@
1
+ require File.expand_path('../../common', __FILE__)
2
+
3
+ require 'drone/metrics/histogram'
4
+
5
+ include Drone
6
+
7
+ describe 'Histogram' do
8
+ describe "A histogram with zero recorded valeus" do
9
+ before do
10
+ @histogram = Histogram.new(UniformSample.new(100))
11
+ end
12
+
13
+ should "have a count of 0" do
14
+ @histogram.count.should == 0
15
+ end
16
+
17
+ should "have a max of 0" do
18
+ @histogram.max.should == 0
19
+ end
20
+
21
+ should "have a min of 0" do
22
+ @histogram.min.should == 0
23
+ end
24
+
25
+ should "have a mean of 0" do
26
+ @histogram.mean.should == 0.0
27
+ end
28
+
29
+ should "have a standard deviation of 0" do
30
+ @histogram.stdDev.should == 0
31
+ end
32
+
33
+ should "calculate percentiles" do
34
+ percentiles = @histogram.percentiles(0.5, 0.75, 0.99)
35
+
36
+ percentiles[0].should.be.close?(0, 0.01)
37
+ percentiles[1].should.be.close?(0, 0.01)
38
+ percentiles[2].should.be.close?(0, 0.01)
39
+ end
40
+
41
+ should "have no values" do
42
+ @histogram.values.should == []
43
+ end
44
+ end
45
+
46
+
47
+ describe "A histogram of the numbers 1 through 10000" do
48
+ before do
49
+ @histogram = Histogram.new( UniformSample.new(100000) )
50
+ (1..10000).each{|n| @histogram.update(n) }
51
+ end
52
+
53
+ should "have a count of 10000" do
54
+ @histogram.count.should == 10000
55
+ end
56
+
57
+ should "have a max value of 10000" do
58
+ @histogram.max.should == 10000
59
+ end
60
+
61
+ should "have a min value of 1" do
62
+ @histogram.min.should == 1
63
+ end
64
+
65
+ should "have a mean value of 5000.5" do
66
+ @histogram.mean.should.be.close?(5000.5, 0.01)
67
+ end
68
+
69
+ should "have a standard deviation of X" do
70
+ @histogram.stdDev.should.be.close?(2886.89, 0.1)
71
+ end
72
+
73
+ should "calculate percentiles" do
74
+ percentiles = @histogram.percentiles(0.5, 0.75, 0.99)
75
+
76
+ percentiles[0].should.be.close?(5000.5, 0.01)
77
+ percentiles[1].should.be.close?(7500.75, 0.01)
78
+ percentiles[2].should.be.close?(9900.99, 0.01)
79
+ end
80
+
81
+ should "have 10000 values" do
82
+ @histogram.values.should == (1..10000).to_a
83
+ # histogram.values.toList must beEqualTo((1 to 10000).toList)
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,129 @@
1
+ require File.expand_path('../../common', __FILE__)
2
+
3
+ require 'drone'
4
+ require 'drone/monitoring'
5
+
6
+ EM.describe 'Monitoring' do
7
+ describe 'rate monitor' do
8
+ before do
9
+
10
+ Drone::init_drone()
11
+
12
+ @klass = Class.new() do
13
+ include Drone::Monitoring
14
+
15
+ monitor_rate("users/no_args")
16
+ def a_method_without_args; 42; end
17
+
18
+ monitor_rate("users/with_args")
19
+ def method_with_args(a, b); a + b; end
20
+
21
+ monitor_rate("users/with_block")
22
+ def method_with_block(&block); block.call; end
23
+
24
+ end
25
+ @obj = @klass.new
26
+
27
+ end
28
+
29
+ should 'reuse same meter for every instances of this class' do
30
+ meter = Drone::find_metric("users/no_args")
31
+ meter.count.should == 0
32
+
33
+ obj1 = @klass.new
34
+ obj2 = @klass.new
35
+
36
+ obj1.a_method_without_args()
37
+ meter.count.should == 1
38
+
39
+ obj2.a_method_without_args()
40
+ meter.count.should == 2
41
+
42
+ done
43
+ end
44
+
45
+ should 'increment counter on call' do
46
+ Drone::Metrics::Meter.any_instance.expects(:mark)
47
+
48
+ ret = @obj.a_method_without_args()
49
+ ret.should == 42
50
+ done
51
+ end
52
+
53
+ should 'be transparent for method with arguments' do
54
+ Drone::Metrics::Meter.any_instance.expects(:mark)
55
+
56
+ ret = @obj.method_with_args(4, 5)
57
+ ret.should == 9
58
+ done
59
+ end
60
+
61
+ should 'be transparent for method with block argument' do
62
+ Drone::Metrics::Meter.any_instance.expects(:mark)
63
+
64
+ ret = @obj.method_with_block(){ 32 }
65
+ ret.should == 32
66
+ done
67
+ end
68
+
69
+ end
70
+
71
+
72
+ describe 'timing monitor' do
73
+ before do
74
+
75
+ Drone::init_drone()
76
+
77
+ klass = Class.new() do
78
+ include Drone::Monitoring
79
+
80
+ monitor_time("users/no_args")
81
+ def a_method_without_args; 42; end
82
+
83
+ monitor_time("users/with_args")
84
+ def method_with_args(a, b); a + b; end
85
+
86
+ monitor_time("users/with_block")
87
+ def method_with_block(&block); block.call; end
88
+
89
+ end
90
+ @obj = klass.new
91
+
92
+ end
93
+
94
+ should 'time call with no args' do
95
+ Drone::Metrics::Timer.any_instance.expects(:update).with{|delay|
96
+ delay.should.be.close?(0, 0.001)
97
+ true
98
+ }
99
+
100
+ ret = @obj.a_method_without_args()
101
+ ret.should == 42
102
+ done
103
+ end
104
+
105
+ should 'time call with args' do
106
+ Drone::Metrics::Timer.any_instance.expects(:update).with{|delay|
107
+ delay.should.be.close?(0, 0.001)
108
+ true
109
+ }
110
+
111
+ ret = @obj.method_with_args(2, 4)
112
+ ret.should == 6
113
+ done
114
+ end
115
+
116
+ should 'time call with a block' do
117
+ Drone::Metrics::Timer.any_instance.expects(:update).with{|delay|
118
+ delay.should.be.close?(0, 0.001)
119
+ true
120
+ }
121
+
122
+ ret = @obj.method_with_block(){ 42 }
123
+ ret.should == 42
124
+ done
125
+ end
126
+
127
+ end
128
+
129
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../../common', __FILE__)
2
+
3
+ require 'drone/utils/uniform_sample'
4
+
5
+ describe 'EWMA' do
6
+ describe "A sample of 100 out of 1000 elements" do
7
+ before do
8
+ @population = (0...1000)
9
+ @sample = UniformSample.new(100)
10
+ @population.step(1){|n| @sample.update(n) }
11
+ end
12
+
13
+ should "have 100 elements" do
14
+ @sample.size.should == 100
15
+ @sample.values.size.should == 100
16
+ end
17
+
18
+ should "only have elements from the population" do
19
+ arr = @sample.values - @population.to_a
20
+ arr.should == []
21
+ end
22
+ end
23
+
24
+ describe "A sample of 100 out of 10 elements" do
25
+ before do
26
+ @population = (0...10)
27
+ @sample = UniformSample.new(100)
28
+ @population.step(1){|n| @sample.update(n) }
29
+ end
30
+
31
+ should "have 10 elements" do
32
+ @sample.size.should == 10
33
+ @sample.values.size.should == 10
34
+ end
35
+
36
+ should "only have elements from the population" do
37
+ arr = @sample.values - @population.to_a
38
+ arr.should == []
39
+ end
40
+ end
41
+
42
+ end
43
+