drone 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.
@@ -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
+