active_metric 2.5.2

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.
Files changed (45) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +5 -0
  3. data/Rakefile +37 -0
  4. data/lib/active_metric.rb +38 -0
  5. data/lib/active_metric/axis.rb +11 -0
  6. data/lib/active_metric/behavior/calculates_derivative.rb +18 -0
  7. data/lib/active_metric/behavior/graph_calculation.rb +78 -0
  8. data/lib/active_metric/calculators/reservoir.rb +81 -0
  9. data/lib/active_metric/calculators/standard_deviator.rb +39 -0
  10. data/lib/active_metric/config/initializers/inflections.rb +4 -0
  11. data/lib/active_metric/graph_view_model.rb +60 -0
  12. data/lib/active_metric/measurement.rb +13 -0
  13. data/lib/active_metric/point_series_data.rb +17 -0
  14. data/lib/active_metric/report.rb +57 -0
  15. data/lib/active_metric/report_view_model.rb +106 -0
  16. data/lib/active_metric/sample.rb +148 -0
  17. data/lib/active_metric/series_data.rb +26 -0
  18. data/lib/active_metric/stat.rb +72 -0
  19. data/lib/active_metric/stat_definition.rb +20 -0
  20. data/lib/active_metric/statistics/defaults.rb +157 -0
  21. data/lib/active_metric/statistics/standard_deviation.rb +43 -0
  22. data/lib/active_metric/subject.rb +117 -0
  23. data/lib/active_metric/version.rb +3 -0
  24. data/test/active_metric_test.rb +30 -0
  25. data/test/axis_test.rb +22 -0
  26. data/test/behavior_tests/calculates_derivative_test.rb +35 -0
  27. data/test/behavior_tests/graph_calculation_test.rb +68 -0
  28. data/test/config/mongoid.yml +13 -0
  29. data/test/dummy/db/test.sqlite3 +0 -0
  30. data/test/dummy/log/test.log +18597 -0
  31. data/test/graph_view_model_test.rb +92 -0
  32. data/test/integration_test.rb +149 -0
  33. data/test/measurement_test.rb +45 -0
  34. data/test/mongoid_test.rb +24 -0
  35. data/test/point_series_data_test.rb +27 -0
  36. data/test/report_test.rb +73 -0
  37. data/test/report_view_model_test.rb +94 -0
  38. data/test/reservoir_test.rb +67 -0
  39. data/test/sample_test.rb +142 -0
  40. data/test/series_data_test.rb +20 -0
  41. data/test/standard_deviator_test.rb +45 -0
  42. data/test/stat_test.rb +222 -0
  43. data/test/subject_test.rb +22 -0
  44. data/test/test_helper.rb +76 -0
  45. metadata +123 -0
@@ -0,0 +1,92 @@
1
+ require_relative "test_helper"
2
+
3
+ module ActiveMetric
4
+ class GraphViewModelTest < ActiveSupport::TestCase
5
+
6
+ EULERS_DAY= MONGO_MAX_LIMIT = (1 << 31) - 1
7
+
8
+ test "can retrieve series by label" do
9
+ gvm = GraphViewModel.create
10
+ gvm.series_data << generate_series_data(5, "first")
11
+ gvm.series_data << generate_series_data(5, "second")
12
+
13
+ series = gvm.series_for("second")
14
+
15
+ assert_equal "second", series.label
16
+
17
+ end
18
+
19
+ test "size returns 0 if no series_data" do
20
+ gvm = GraphViewModel.create
21
+ assert_equal 0, gvm.size
22
+ end
23
+
24
+ test "can create from definitions" do
25
+ axises_defintions = [{index: 1, label: "second"},
26
+ {index: 0, label: "first"},
27
+ {index: 0, label: "actually first"}]
28
+ options = {name: "test graph"}
29
+
30
+ stat_definitions = []
31
+ stat_definitions << stat_definition(true)
32
+ stat_definitions << stat_definition(true)
33
+ stat_definitions << stat_definition(false)
34
+
35
+ gvm = GraphViewModel.create_from_meta_data(axises_defintions, stat_definitions, options)
36
+
37
+ assert_equal 2, gvm.y_axises.size
38
+
39
+ index_zero_axises = gvm.y_axises.select{|axis| axis.index == 0}
40
+
41
+ assert_equal 1, index_zero_axises.size
42
+ assert_equal 0, index_zero_axises.first.index
43
+ assert_equal "actually first", index_zero_axises.first.label
44
+
45
+ assert_equal 2, gvm.series_data.size
46
+ end
47
+
48
+ test "can read y_axises sorted by index" do
49
+ axises_defintions = [{index: 1, label: "second"},
50
+ {index: 0, label: "first"},
51
+ {index: 0, label: "actually first"}]
52
+
53
+ gvm = GraphViewModel.create_from_meta_data(axises_defintions, [], {})
54
+
55
+ axises = gvm.ordered_y_axises
56
+
57
+ assert_equal 2, axises.size
58
+
59
+ assert_equal 0, axises.first.index
60
+ assert_equal "actually first", axises.first.label
61
+
62
+ assert_equal 1, axises.second.index
63
+ assert_equal "second", axises.second.label
64
+ end
65
+
66
+
67
+ test "can retrieve partial array" do
68
+ subject = Subject.create
69
+ graph_view_model = subject.graph_view_model
70
+ graph_view_model.series_data << generate_series_data(4)
71
+ graph_view_model.series_data << generate_series_data(4,"label 2")
72
+
73
+ partial_graph = subject.graph_view_model_starting_at(2)
74
+
75
+ assert_equal [[2,2],[3,3]], partial_graph.series_data.first.data
76
+ assert_equal [[2,2],[3,3]], partial_graph.series_data.second.data
77
+
78
+ end
79
+
80
+ def generate_series_data(x_count, label = "label")
81
+ data = []
82
+ x_count.times {|x| data << [x,x]}
83
+ PointSeriesData.new(data: data, label: label)
84
+ end
85
+
86
+ def stat_definition(graphable)
87
+ axis = graphable ? 0 : -1
88
+ StatDefinition.new(:name_of_stat,Min,"min_name_of_stat",{axis: axis})
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,149 @@
1
+ require_relative 'test_helper'
2
+
3
+ module ActiveMetric
4
+
5
+ class IntegrationTest < ActiveSupport::TestCase
6
+
7
+ test "can calculate correct eightieth percentile for subject" do
8
+ report = Report.create
9
+ subject = TestSubject.create :report => report
10
+ subject2 = TestSubject.create :report => report
11
+ 10.times do |value|
12
+ subject.calculate TestMeasurement.new(:value => 100 - value, :timestamp => value)
13
+ end
14
+ 10.times do |value|
15
+ subject2.calculate TestMeasurement.new(:value => 200 - value, :timestamp => value)
16
+ end
17
+ subject2.complete
18
+ subject.complete
19
+ assert_equal 99, subject.summary.eightieth_value.value
20
+ assert_equal 199, subject2.summary.eightieth_value.value
21
+ end
22
+
23
+ test "can calculate correct ninety eighth percentile for subject" do
24
+ report = Report.create
25
+ subject = TestSubject.create :report => report
26
+ subject2 = TestSubject.create :report => report
27
+ 5.times do |value|
28
+ subject.calculate TestMeasurement.new(:value => 100 - value, :timestamp => value)
29
+ end
30
+ 5.times do |value|
31
+ subject.calculate TestMeasurement.new(:value => 150 - value, :timestamp => value)
32
+ end
33
+ 10.times do |value|
34
+ subject2.calculate TestMeasurement.new(:value => 200 - value, :timestamp => value)
35
+ end
36
+ subject2.complete
37
+ subject.complete
38
+ assert_equal 150, subject.summary.ninety_eighth_value.value
39
+ assert_equal 200, subject2.summary.ninety_eighth_value.value
40
+ end
41
+
42
+ test "can calculate correct percentiles with multiple subjects" do
43
+ report = Report.create
44
+ subject = TestSubject.create :report => report
45
+ subject2 = TestSubject.create :report => report
46
+ 5.times do |value|
47
+ subject.calculate TestMeasurement.new(:value => 100 - value, :timestamp => value)
48
+ end
49
+ 5.times do |value|
50
+ subject.calculate TestMeasurement.new(:value => 150 - value, :timestamp => value)
51
+ end
52
+ 10.times do |value|
53
+ subject2.calculate TestMeasurement.new(:value => 155 - value, :timestamp => value)
54
+ end
55
+ subject2.complete
56
+ subject.complete
57
+
58
+ assert_equal 149, subject.summary.eightieth_value.value
59
+ assert_equal 150, subject.summary.ninety_eighth_value.value
60
+
61
+ assert_equal 154, subject2.summary.eightieth_value.value
62
+ assert_equal 155, subject2.summary.ninety_eighth_value.value
63
+ end
64
+
65
+ test "can calculate standard deviations" do
66
+ report = Report.create
67
+ subject = TestSubject.create :report => report
68
+ 10.times do |value|
69
+ subject.calculate TestMeasurement.new(:value => 100 - value, :timestamp => value)
70
+ end
71
+
72
+ subject.complete
73
+ assert_close_to 2.87, subject.summary.standard_deviation_value.value
74
+ end
75
+
76
+ test "summary should update when samples changes" do
77
+ report = Report.create
78
+ subject = TestSubject.create :report => report
79
+ 6.times do |value|
80
+ subject.calculate TestMeasurement.new(:value => value, :timestamp => value)
81
+ end
82
+
83
+ assert_equal 4.0, subject.summary.eightieth_value.value
84
+
85
+ subject.calculate TestMeasurement.new(:value => 6, :timestamp => 6)
86
+
87
+ assert_equal 4.0, subject.summary.eightieth_value.value
88
+ end
89
+
90
+ test "subjects should delegate to summaries" do
91
+ report = Report.create
92
+ subject = TestSubject.create :report => report
93
+ 6.times do |value|
94
+ subject.calculate TestMeasurement.new(:value => value, :timestamp => value)
95
+ end
96
+
97
+ assert_equal 4.0, subject.eightieth_value
98
+ assert_equal 4.0, subject.eightieth_value
99
+ end
100
+
101
+ test "subjects should delegate to document before summaries" do
102
+ report = Report.create
103
+ subject = TestSubject.create :report => report, :test_field => "subject name"
104
+ 6.times do |value|
105
+ subject.calculate TestMeasurement.new(:value => value, :timestamp => value)
106
+ end
107
+ assert_equal "subject name", subject.test_field
108
+ assert_equal 4.0, subject.eightieth_value
109
+ end
110
+
111
+ test "subjects should be able to delegate to non stat properties on summary" do
112
+ report = Report.create
113
+ subject = TestSubject.create :report => report
114
+ 6.times do |value|
115
+ subject.calculate TestMeasurement.new(:value => value, :timestamp => value)
116
+ end
117
+ assert_equal 5, subject.duration_in_seconds
118
+ assert_equal 5, subject.duration_in_seconds
119
+ end
120
+
121
+ test "no measurements or interval samples should be in the database" do
122
+ report = Report.create
123
+ subject = TestSubject.create :report => report
124
+ subject2 = TestSubject.create :report => report
125
+ 11.times do |value|
126
+ subject.calculate TestMeasurement.new(:value => 100 - value, :timestamp => value)
127
+ end
128
+ 10.times do |value|
129
+ subject2.calculate TestMeasurement.new(:value => 200 - value, :timestamp => value)
130
+ end
131
+ subject2.complete
132
+ subject.complete
133
+ assert_equal 90, subject.min_value
134
+ assert_equal 191, subject2.min_value
135
+
136
+ assert_equal 0, ActiveMetric::Measurement.count
137
+ assert_equal 0, ActiveMetric::Sample.where(:interval.ne => nil).count
138
+ assert_equal 2, ActiveMetric::Sample.where(:interval => nil).count
139
+ end
140
+
141
+ private
142
+
143
+ def assert_within_threshold(threshold, actual, estimated)
144
+ range_val = actual * threshold
145
+ range = ((actual - range_val)..(actual + range_val))
146
+ assert_within_range range, estimated
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'test_helper'
2
+
3
+ module ActiveMetric
4
+
5
+ class MeasurementTest < ActiveSupport::TestCase
6
+
7
+ setup do
8
+ @measurement = TestMeasurement.new
9
+ end
10
+
11
+ test 'can create measurement' do
12
+ assert @measurement
13
+ end
14
+
15
+ test 'is a mongoid document' do
16
+ assert @measurement.kind_of? Mongoid::Document
17
+ end
18
+
19
+ test 'time returns datetime in seconds for timestamp' do
20
+ @measurement.timestamp = 1318338826385
21
+ assert_equal Time.at(1318338826), @measurement.time
22
+ end
23
+
24
+ test "converts appropriate fields to integer" do
25
+ assert_saves_as_integer @measurement, :timestamp
26
+ end
27
+
28
+ test "measurements default timestamp to now" do
29
+ assert @measurement.timestamp
30
+ sleep(1)
31
+ measurement2 = TestMeasurement.new
32
+ assert measurement2.timestamp
33
+
34
+ assert_not_equal @measurement.timestamp, measurement2.timestamp
35
+ end
36
+
37
+ private
38
+
39
+ def assert_saves_as_integer(measurement, field)
40
+ measurement.send("#{field}=","12345")
41
+ measurement.save!
42
+ assert_equal 12345, measurement.send(field)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'test_helper'
2
+
3
+ class MongoidTest < ActiveSupport::TestCase
4
+
5
+
6
+ test "inherited documents from class dot new dont get a type" do
7
+ class TopLevel
8
+ include Mongoid::Document
9
+ end
10
+
11
+ class SecondLevel < TopLevel
12
+ end
13
+
14
+ second_level = SecondLevel.create
15
+ assert_equal "MongoidTest::SecondLevel", second_level._type
16
+
17
+ klass = Class.new(TopLevel)
18
+ MongoidTest.const_set(:NewKlass, klass)
19
+
20
+ new_object = NewKlass.create
21
+ assert_equal "MongoidTest::NewKlass", new_object._type
22
+ #assert_equal nil, new_object._type, "Mongoid correctly sets _type on Anonymous Classes now. Go remove the hack in stat: create_custom_stat WRT _type "
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ require_relative "test_helper"
2
+
3
+ module ActiveMetric
4
+ class PointSeriesDataTest < ActiveSupport::TestCase
5
+
6
+ test "can push and pop atomically" do
7
+ gvm = GraphViewModel.create
8
+ psd = PointSeriesData.new(data: [[1,1],[2,2]])
9
+ gvm.series_data << psd
10
+
11
+ psd.pop_data
12
+
13
+ assert_equal [[1,1]], psd.data
14
+
15
+ psd.push_data([3,3])
16
+
17
+ assert_equal [[1,1],[3,3]], psd.data
18
+ end
19
+
20
+ test "can calculate size of data" do
21
+ psd = PointSeriesData.new(data: [[1,1],[2,2]])
22
+
23
+ assert_equal 2, psd.size
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,73 @@
1
+ require_relative 'test_helper'
2
+
3
+ module ActiveMetric
4
+
5
+ class ReportTest < ActiveSupport::TestCase
6
+
7
+
8
+ test "method missing for subjects" do
9
+ report = Report.create
10
+ subjects = 2.times.map {TestSubject.create :report => report}
11
+ assert_equal subjects, report.test_subjects
12
+ end
13
+
14
+ test "responds properly to method missing if not a subject name" do
15
+ report = Report.create
16
+ assert_raises NoMethodError do
17
+ report.bad_method
18
+ end
19
+ end
20
+
21
+ test "can still use dynamic fields with overwritten method missing" do
22
+ report = Report.create :some_random_field => "value"
23
+ assert_equal "value", report.some_random_field
24
+ end
25
+
26
+ test "can still access dynamic fields with subjects in name" do
27
+ report = Report.create :some_subjects => "value"
28
+ assert_equal "value", report.some_subjects
29
+ end
30
+
31
+ test "can delete a report" do
32
+ report = Report.create
33
+ report.subjects.create
34
+
35
+ report.delete
36
+
37
+ assert_equal 0, ActiveMetric::Report.count
38
+ assert_equal 0, ActiveMetric::Subject.count
39
+ assert_equal 0, ActiveMetric::Sample.count
40
+ assert_equal 0, ActiveMetric::GraphViewModel.count
41
+
42
+ end
43
+
44
+ test "can set display name" do
45
+ class TestReport < Report
46
+
47
+ def set_display_name
48
+ "Overriden Display Name"
49
+ end
50
+ end
51
+
52
+ report = TestReport.create
53
+
54
+ assert_equal "Overriden Display Name", report.display_name
55
+ end
56
+
57
+ test "can set display name through attribute" do
58
+ class TestReport < Report
59
+
60
+ def set_display_name
61
+ "TestReport Display Name"
62
+ end
63
+ end
64
+
65
+ report = TestReport.create display_name: "Overriden Display Name"
66
+
67
+ assert_equal "Overriden Display Name", report.display_name
68
+ end
69
+
70
+
71
+
72
+ end
73
+ end
@@ -0,0 +1,94 @@
1
+ require_relative "test_helper"
2
+
3
+ module ActiveMetric
4
+ class ReportViewModelTest < ActiveSupport::TestCase
5
+
6
+ class TestReportViewModel < ActiveMetric::ReportViewModel
7
+
8
+ table :table1 do
9
+ column "header 1", :field1
10
+ column "header 2", :field2, :precision => 2
11
+ column "header 3", :field3, :format => :duration_with_format
12
+ end
13
+
14
+ table :table2 do
15
+ column "header 1", :field1
16
+ column "header 2", :field2
17
+ end
18
+
19
+ end
20
+
21
+ test "can instantiate a view model" do
22
+ rvm = TestReportViewModel.new
23
+ rvm.add_table :table1, subjects
24
+ table = rvm.tables.first
25
+
26
+ expected_headers = ["header 1", "header 2", "header 3"]
27
+ assert_equal expected_headers, table.headers
28
+
29
+ expected_cells = ["name",2.8345, 3]
30
+ expected_cell_options = [{},{:precision =>2},{:format => :duration_with_format}]
31
+ table.rows.each do |row|
32
+ assert_equal expected_cells, row.cells.map(&:value)
33
+ assert_equal expected_cell_options, row.cells.map(&:format_options)
34
+ assert row.has_series
35
+ end
36
+ end
37
+
38
+ test "cannot add a table that does not exist" do
39
+ rvm = TestReportViewModel.new
40
+ assert_raise ReportViewModel::TableDoesNotExist do
41
+ rvm.add_table :bad_table, subjects
42
+ end
43
+ end
44
+
45
+ test "can have multiple tables" do
46
+ rvm = TestReportViewModel.new
47
+ rvm.add_table :table1, subjects
48
+ rvm.add_table :table2, subjects
49
+ rvm.add_table :table1, subjects
50
+
51
+ table1_headers = ["header 1", "header 2", "header 3"]
52
+ table2_headers = ["header 1", "header 2"]
53
+
54
+ assert_equal table1_headers, rvm.tables[0].headers
55
+ assert_equal table2_headers, rvm.tables[1].headers
56
+ assert_equal table1_headers, rvm.tables[2].headers
57
+
58
+ table1_data = ["name",2.8345, 3]
59
+ table2_data = ["name",2.8345]
60
+ table3_data = ["name",2.8345, 3]
61
+
62
+ assert_table_data table1_data, rvm.tables[0]
63
+ assert_table_data table2_data, rvm.tables[1]
64
+ assert_table_data table3_data, rvm.tables[2]
65
+ end
66
+
67
+
68
+ def assert_table_data(data, table)
69
+ table.rows.each do |row|
70
+ assert_equal data, row.cells.map(&:value)
71
+ assert_equal "1", row.row_id
72
+ end
73
+ end
74
+
75
+ def subjects
76
+ subject = create_row_data(field1: "name",
77
+ field2: 2.8345,
78
+ field3: 3)
79
+
80
+ subject.stubs(:to_param).returns("1")
81
+ subject.stubs(:has_graph_data).returns(true)
82
+ [subject]
83
+ end
84
+
85
+ def create_row_data(values)
86
+ row_data = mock
87
+ values.each do |key,value|
88
+ row_data.stubs(key).returns(value)
89
+ end
90
+ row_data
91
+ end
92
+
93
+ end
94
+ end