rbsim 0.0.3

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.hgignore +6 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +12 -0
  5. data/Gemfile.lock +66 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +960 -0
  8. data/TODO +28 -0
  9. data/basic_sim.rb +62 -0
  10. data/fast-tcpn.rb +3 -0
  11. data/lib/rbsim.rb +14 -0
  12. data/lib/rbsim/dsl.rb +30 -0
  13. data/lib/rbsim/dsl/infrastructure.rb +48 -0
  14. data/lib/rbsim/dsl/mapping.rb +32 -0
  15. data/lib/rbsim/dsl/process.rb +129 -0
  16. data/lib/rbsim/dsl/program.rb +10 -0
  17. data/lib/rbsim/experiment.rb +110 -0
  18. data/lib/rbsim/hlmodel.rb +25 -0
  19. data/lib/rbsim/hlmodel/infrastructure.rb +116 -0
  20. data/lib/rbsim/hlmodel/mapping.rb +5 -0
  21. data/lib/rbsim/hlmodel/process.rb +152 -0
  22. data/lib/rbsim/numeric_units.rb +107 -0
  23. data/lib/rbsim/simulator.rb +184 -0
  24. data/lib/rbsim/statistics.rb +77 -0
  25. data/lib/rbsim/tokens.rb +146 -0
  26. data/lib/rbsim/version.rb +3 -0
  27. data/new_process.rb +49 -0
  28. data/rbsim.gemspec +42 -0
  29. data/show_readme.rb +15 -0
  30. data/sim.rb +142 -0
  31. data/sim_bamboo.rb +251 -0
  32. data/sim_process.rb +83 -0
  33. data/sim_process_dsl.rb +58 -0
  34. data/spec/dsl/infrastructure_nets_spec.rb +39 -0
  35. data/spec/dsl/infrastructure_nodes_spec.rb +72 -0
  36. data/spec/dsl/infrastructure_routes_spec.rb +44 -0
  37. data/spec/dsl/mapping_spec.rb +70 -0
  38. data/spec/dsl/process_spec.rb +56 -0
  39. data/spec/dsl/program_spec.rb +36 -0
  40. data/spec/dsl_and_hlmodel/new_process_spec.rb +235 -0
  41. data/spec/hlmodel/net_spec.rb +112 -0
  42. data/spec/hlmodel/process_spec.rb +242 -0
  43. data/spec/hlmodel/route_spec.rb +47 -0
  44. data/spec/hlmodel/routes_spec.rb +44 -0
  45. data/spec/integration/basic_simulation_spec.rb +104 -0
  46. data/spec/integration/net_spec.rb +44 -0
  47. data/spec/integration/process_spec.rb +117 -0
  48. data/spec/integration/rbsim_spec.rb +40 -0
  49. data/spec/simulator/logger_spec.rb +35 -0
  50. data/spec/simulator/stats_spec.rb +93 -0
  51. data/spec/spec_helper.rb +26 -0
  52. data/spec/statistics_spec.rb +300 -0
  53. data/spec/tcpn/add_route_spec.rb +55 -0
  54. data/spec/tcpn/cpu_spec.rb +53 -0
  55. data/spec/tcpn/map_data_spec.rb +37 -0
  56. data/spec/tcpn/network_spec.rb +163 -0
  57. data/spec/tcpn/register_event_spec.rb +48 -0
  58. data/spec/tcpn/route_to_self_spec.rb +53 -0
  59. data/spec/tcpn/stats_spec.rb +77 -0
  60. data/spec/tokens/data_queue_obsolete.rb +121 -0
  61. data/spec/tokens/data_queue_spec.rb +111 -0
  62. data/spec/units_spec.rb +48 -0
  63. data/tcpn/model.rb +6 -0
  64. data/tcpn/model/add_route.rb +78 -0
  65. data/tcpn/model/application.rb +250 -0
  66. data/tcpn/model/cpu.rb +75 -0
  67. data/tcpn/model/map_data.rb +42 -0
  68. data/tcpn/model/network.rb +108 -0
  69. data/tcpn/model/register_event.rb +89 -0
  70. data/tcpn/model/stats.rb +46 -0
  71. metadata +221 -0
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Application process activity" do
4
+
5
+ module ProcessActivitySpec
6
+ class CPU
7
+ attr_accessor :node, :performance
8
+ def initialize(node, performance)
9
+ @node, @performance = node, performance
10
+ end
11
+ end
12
+
13
+ class CPUToken < CPU
14
+ #include TCPN::TokenMethods
15
+ end
16
+
17
+ end
18
+
19
+ let :hlmodel do
20
+ RBSim.dsl do
21
+ new_process :worker do
22
+ on_event :data do |volume|
23
+ delay_for 100
24
+ cpu do |c|
25
+ 12/c.performance
26
+ end
27
+ new_process :child do
28
+ delay_for 500
29
+ cpu do |c|
30
+ 450/c.performance
31
+ end
32
+ send_data to: :worker, size: 1024, type: :hi, content: 'hello!'
33
+ end
34
+ end
35
+ delay_for 100
36
+ cpu do |cpu|
37
+ 100/cpu.performance
38
+ end
39
+ register_event :data, delay: 200, args: 1000
40
+ log "a log message here"
41
+ end
42
+ end
43
+ end
44
+
45
+ let(:process_token) { hlmodel.processes[:worker] }
46
+ let(:data_queue) { RBSim::Tokens::DataQueueToken.new(process_token.name) }
47
+
48
+ # FIXME: marking for TCPN should be set by DSL!
49
+ let :tcpn do
50
+ process_token.node = :node01
51
+ cpu_token = ProcessActivitySpec::CPUToken.new(:node01, 10)
52
+ mapping_token = { ts: 0, val: { process_token.name => process_token.node } }
53
+
54
+
55
+ tcpn = FastTCPN.read 'tcpn/model/application.rb'
56
+
57
+ tcpn.add_marking_for 'CPU', cpu_token
58
+ tcpn.add_marking_for 'process', process_token
59
+ tcpn.add_marking_for 'mapping', mapping_token
60
+ tcpn.add_marking_for 'data to receive', data_queue
61
+ tcpn
62
+ end
63
+
64
+ it "produces correct transition firing sequence and final TCPN marking" do
65
+ transitions = []
66
+ tcpn.cb_for :transition, :after do |t, e|
67
+ transitions << e.transition
68
+ end
69
+
70
+ tcpn.sim
71
+
72
+ expect(transitions).to eq ["event::delay_for",
73
+ "event::cpu",
74
+ "event::cpu_finished",
75
+ "event::register_event",
76
+ "event::log",
77
+ "event::enqueue_event",
78
+ "event::serve_user",
79
+ "event::delay_for",
80
+ "event::cpu",
81
+ "event::cpu_finished",
82
+ "event::new_process",
83
+ "event::delay_for",
84
+ "event::cpu",
85
+ "event::cpu_finished",
86
+ "event::send_data"
87
+ ]
88
+ # mapping token should be updated after new
89
+ # process is created
90
+ mapping = tcpn.marking_for('mapping').first[:val]
91
+ expect(mapping[:child]).to eq(:node01)
92
+
93
+ # do we have data to send token in proper place?
94
+ data = tcpn.marking_for('data to send').first[:val]
95
+ expect(data.dst).to eq(:worker)
96
+ end
97
+
98
+ it "receives data" do
99
+ data = RBSim::Tokens::DataToken.new(867545, :node01, :process01, to: :child, size: 1234)
100
+ data.fragments = 1
101
+ data_queue.put data
102
+ received_data = false
103
+ transitions = []
104
+ tcpn.cb_for :transition, :before do |t, e|
105
+ transitions << e.transition
106
+ if e.transition == 'event::serve_user' && e.binding['process'].value.has_event?(:data_received)
107
+ received_data = true
108
+ end
109
+ end
110
+
111
+ tcpn.sim
112
+
113
+ expect(transitions).to include("event::data_received")
114
+ expect(received_data).to be true
115
+ end
116
+
117
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ require 'tempfile'
4
+
5
+ describe RBSim do
6
+
7
+ describe "#model" do
8
+ it "passes its params to the loaded model" do
9
+ o = Object.new
10
+ expect(o).to receive(:to_s)
11
+ m = RBSim.model name: :apache, run: true do |params|
12
+ o.to_s
13
+ expect(params[:name]).to eq :apache
14
+ expect(params[:run]).to be true
15
+ end
16
+ m.hlmodel
17
+ end
18
+ end
19
+
20
+ describe "#read" do
21
+ it "reads model from file" do
22
+ file = Tempfile.new "rbsim_model_test"
23
+ file.write "program :prg do;end"
24
+ file.close
25
+ m = RBSim.read file.path
26
+ file.unlink
27
+ expect(m.hlmodel.programs).to have_key :prg
28
+ end
29
+
30
+ it "passes params to the model from file as 'params' variable" do
31
+ file = Tempfile.new "rbsim_model_test"
32
+ file.write "program params[:name] do;end"
33
+ file.close
34
+ m = RBSim.read file.path, name: :prg
35
+ file.unlink
36
+ expect(m.hlmodel.programs).to have_key :prg
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe RBSim::Simulator do
4
+ describe "#logger" do
5
+ let :model do
6
+ RBSim.model do
7
+ new_process :worker do
8
+ log "start"
9
+ delay_for 20.seconds
10
+ log "stop"
11
+ end
12
+
13
+ node :n1 do
14
+ cpu 100.miliseconds
15
+ end
16
+
17
+ put :worker, on: :n1
18
+
19
+ end
20
+ end
21
+
22
+ it "logs to default logger" do
23
+ expect { model.run }.to output("0.000: start\n20.000: stop\n").to_stdout
24
+ end
25
+
26
+ it "logs to custom logger" do
27
+ logs = []
28
+ model.logger do |clock, message|
29
+ logs << { time: clock, message: message }
30
+ end
31
+ model.run
32
+ expect(logs).to eq [ {time: 0, message: "start" }, {time: 20.seconds, message: "stop"} ]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe RBSim::Simulator do
4
+ describe "statistics" do
5
+ let :model do
6
+ RBSim.model do
7
+ new_process :worker do
8
+ stats_start tag: :work, group_name: 'worker'
9
+ delay_for 200
10
+ stats_stop tag: :work, group_name: 'worker'
11
+ delay_for 100
12
+ stats tag: :wait, group_name: 'worker'
13
+ delay_for 100
14
+ stats tag: :wait, group_name: 'worker'
15
+ stats_save 31415, tag: :queue_length, group_name: 'worker'
16
+ end
17
+
18
+ node :n1 do
19
+ cpu 100
20
+ end
21
+
22
+ put :worker, on: :n1
23
+
24
+ end
25
+ end
26
+
27
+ it "registers events in Statistisc" do
28
+ expect_any_instance_of(RBSim::Statistics).to receive(:event).with(:start, {tag: :work, group_name: 'worker'}, 0).once
29
+ expect_any_instance_of(RBSim::Statistics).to receive(:event).with(:stop, {tag: :work, group_name: 'worker'}, 200)
30
+ expect_any_instance_of(RBSim::Statistics).to receive(:event).with(:stats, {tag: :wait, group_name: 'worker'}, 300)
31
+ expect_any_instance_of(RBSim::Statistics).to receive(:event).with(:stats, {tag: :wait, group_name: 'worker'}, 400)
32
+ expect_any_instance_of(RBSim::Statistics).to receive(:event).with(:save, {value: 31415, tags: { tag: :queue_length, group_name: 'worker'} }, 400)
33
+ model.run
34
+ end
35
+
36
+ describe "net dropping packages" do
37
+ let :model do
38
+ RBSim.model do
39
+ new_process :sender do
40
+ 10.times { send_data to: :receiver, size: 10, content: "Test message" }
41
+ end
42
+
43
+ new_process :receiver do
44
+ end
45
+
46
+ node :sender do
47
+ cpu 1
48
+ end
49
+
50
+ node :receiver do
51
+ cpu 1
52
+ end
53
+
54
+ net :net01, bw: 1024, drop: drop
55
+
56
+ put :sender, on: :sender
57
+ put :receiver, on: :receiver
58
+ route from: :sender, to: :receiver, via: [ :net01 ], toway: true
59
+ end
60
+ end
61
+
62
+ describe "when dropping" do
63
+ let(:drop) { 1 }
64
+
65
+ it "counts dropped" do
66
+
67
+ allow(RBSim::Statistics).to receive(:dropped_stats)
68
+ allow_any_instance_of(RBSim::Statistics).to receive(:event) do |*a|
69
+ if a[1..-2] == [:stats, {net: :net01, event: 'NET DROP'}]
70
+ RBSim::Statistics.dropped_stats
71
+ end
72
+ end
73
+ expect(RBSim::Statistics).to receive(:dropped_stats).exactly(10 * model.data_fragmentation).times
74
+ model.run
75
+ end
76
+ end
77
+
78
+ describe "when not dropping" do
79
+ let(:drop) { 1 }
80
+
81
+ it "counts dropped" do
82
+ expect_any_instance_of(RBSim::Statistics).not_to receive(:event).with(:stats,
83
+ {tag: :net01,
84
+ group_name: 'NET DROP'})
85
+ model.run
86
+ end
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
@@ -0,0 +1,26 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ end
5
+
6
+ require 'rbsim'
7
+ require 'rspec/its'
8
+
9
+
10
+ # This file was generated by the `rspec --init` command. Conventionally, all
11
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
12
+ # Require this file using `require "spec_helper"` to ensure that it is only
13
+ # loaded once.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+ RSpec.configure do |config|
17
+ #config.treat_symbols_as_metadata_keys_with_true_values = true
18
+ config.run_all_when_everything_filtered = true
19
+ config.filter_run :focus
20
+
21
+ # Run specs in random order to surface order dependencies. If you find an
22
+ # order dependency and want to debug it, you can fix the order by providing
23
+ # the seed, which is printed after each run.
24
+ # --seed 1234
25
+ config.order = 'random'
26
+ end
@@ -0,0 +1,300 @@
1
+ require 'spec_helper'
2
+
3
+ describe RBSim::Statistics do
4
+
5
+ describe "with hash based tags" do
6
+ describe "event counters" do
7
+ let :stats do
8
+ stats = RBSim::Statistics.new
9
+ stats.event :stats, { score: :hit, target: 'small' }, 100
10
+ stats.event :stats, { score: :hit, target: 'big' }, 300
11
+ stats.event :stats, { score: :miss, target: 'small' }, 500
12
+ stats.event :stats, { score: :hit, target: 'small' }, 500
13
+ stats.event :stats, { score: :miss, target: 'small' }, 500
14
+ stats.event :stats, { score: :hit, target: 'big' }, 900
15
+ stats.event :stats, { score: :hit3, target: 'big' }, 900
16
+ stats.event :stats, { score: :hit, target: 'big', value: 23 }, 900
17
+ stats.event :stats, { score: :hit, target: 'big', value: 230 }, 900
18
+ stats.event :stats, { score: :hit5, target: 'huge' }, 950
19
+ stats.clock = 1000
20
+ stats
21
+ end
22
+ subject { stats }
23
+
24
+ it "returns all counters" do
25
+ counters = subject.counters.to_h
26
+ expected_counters = {
27
+ { score: :hit, target: 'small' } => [ 100, 500 ],
28
+ { score: :hit, target: 'big' } => [ 300, 900 ],
29
+ { score: :hit, target: 'big', value: 23 } => [ 900 ],
30
+ { score: :hit, target: 'big', value: 230 } => [ 900 ],
31
+ { score: :miss, target: 'small' } => [ 500, 500 ],
32
+ { score: :hit3, target: 'big' } => [ 900 ],
33
+ { score: :hit5, target: 'huge' } => [ 950 ],
34
+ }
35
+ expect(counters).to eq expected_counters
36
+ end
37
+
38
+ it "filters counters by single tag" do
39
+ counters = subject.counters(score: :hit).to_h
40
+ expected_counters = {
41
+ { score: :hit, target: 'small' } => [ 100, 500 ],
42
+ { score: :hit, target: 'big' } => [ 300, 900 ],
43
+ { score: :hit, target: 'big', value: 23 } => [ 900 ],
44
+ { score: :hit, target: 'big', value: 230 } => [ 900 ],
45
+ }
46
+ expect(counters).to eq expected_counters
47
+ end
48
+
49
+ it "filters counters by two tags" do
50
+ counters = subject.counters(score: :hit, target: 'big').to_h
51
+ expected_counters = {
52
+ { score: :hit, target: 'big' } => [ 300, 900 ],
53
+ { score: :hit, target: 'big', value: 23 } => [ 900 ],
54
+ { score: :hit, target: 'big', value: 230 } => [ 900 ],
55
+ }
56
+ expect(counters).to eq expected_counters
57
+ end
58
+
59
+ it "filters counters by rare tag" do
60
+ counters = subject.counters(value: 23).to_h
61
+ expected_counters = {
62
+ { score: :hit, target: 'big', value: 23 } => [ 900 ],
63
+ }
64
+ expect(counters).to eq expected_counters
65
+ end
66
+
67
+ it "filters counters by regexp" do
68
+ counters = subject.counters(score: /hit.?/).to_h
69
+ expected_counters = {
70
+ { score: :hit, target: 'small' } => [ 100, 500 ],
71
+ { score: :hit, target: 'big' } => [ 300, 900 ],
72
+ { score: :hit, target: 'big', value: 23 } => [ 900 ],
73
+ { score: :hit, target: 'big', value: 230 } => [ 900 ],
74
+ { score: :hit3, target: 'big' } => [ 900 ],
75
+ { score: :hit5, target: 'huge' } => [ 950 ],
76
+ }
77
+ expect(counters).to eq expected_counters
78
+ end
79
+
80
+ it "filters counters by any regexp matching any value if key exists" do
81
+ counters = subject.counters(value: /.*/).to_h
82
+ expected_counters = {
83
+ { score: :hit, target: 'big', value: 23 } => [ 900 ],
84
+ { score: :hit, target: 'big', value: 230 } => [ 900 ],
85
+ }
86
+ expect(counters).to eq expected_counters
87
+ end
88
+
89
+ end
90
+
91
+ describe "correctly computes event duration" do
92
+ context "for correct data" do
93
+ let :stats do
94
+ stats = RBSim::Statistics.new
95
+ stats.event :start, { tag: :working, name: 'apache' }, 100
96
+ stats.event :start, { tag: :working, name: 'nginx' }, 100
97
+
98
+ stats.event :start, { tag: :request, name: 'apache' }, 200
99
+ stats.event :stop, { tag: :request, name: 'apache' }, 300
100
+ stats.event :start, { tag: :request, name: 'nginx' }, 350
101
+ stats.event :start, { tag: :request, name: 'apache' }, 350
102
+ stats.event :stop, { tag: :request, name: 'nginx' }, 400
103
+ stats.event :stop, { tag: :request, name: 'apache' }, 420
104
+ stats.event :start, { tag: :compute, name: 'apache', mod: :php }, 500
105
+ stats.event :stop, { tag: :compute, name: 'apache', mod: :php }, 600
106
+
107
+ stats.event :stop, { tag: :working, name: 'nginx' }, 850
108
+ stats.event :stop, { tag: :working, name: 'apache' }, 900
109
+ stats.clock = 1000
110
+
111
+ stats
112
+ end
113
+
114
+ subject { stats }
115
+
116
+ it "returns all durations" do
117
+ durations = subject.durations.to_a
118
+ expected_durations = [
119
+ [ { tag: :working, name: 'apache' }, 100, 900 ],
120
+ [ { tag: :working, name: 'nginx' }, 100, 850 ],
121
+ [ { tag: :request, name: 'apache' }, 200, 300 ],
122
+ [ { tag: :request, name: 'apache' }, 350, 420 ],
123
+ [ { tag: :compute, name: 'apache', mod: :php }, 500, 600 ],
124
+ [ { tag: :request, name: 'nginx' }, 350, 400 ],
125
+ ]
126
+ expect(durations).to match_array expected_durations
127
+ end
128
+
129
+ it "filters durations by single tag" do
130
+ durations = subject.durations(tag: :working).to_a
131
+ expected_durations = [
132
+ [ { tag: :working, name: 'apache' }, 100, 900 ],
133
+ [ { tag: :working, name: 'nginx' }, 100, 850 ],
134
+ ]
135
+ expect(durations).to match_array expected_durations
136
+ end
137
+
138
+ it "filters durations by two tags" do
139
+ durations = subject.durations(tag: :request, name: 'apache').to_a
140
+ expected_durations = [
141
+ [ { tag: :request, name: 'apache' }, 200, 300 ],
142
+ [ { tag: :request, name: 'apache' }, 350, 420 ],
143
+ ]
144
+ expect(durations).to match_array expected_durations
145
+ end
146
+
147
+ it "filters durations by rare tag" do
148
+ durations = subject.durations(tag: :compute).to_a
149
+ expected_durations = [
150
+ [ { tag: :compute, name: 'apache', mod: :php }, 500, 600 ],
151
+ ]
152
+ expect(durations).to match_array expected_durations
153
+ end
154
+
155
+ it "filters durations by regexp" do
156
+ durations = subject.durations(tag: /r/).to_a
157
+ expected_durations = [
158
+ [ { tag: :working, name: 'apache' }, 100, 900 ],
159
+ [ { tag: :working, name: 'nginx' }, 100, 850 ],
160
+ [ { tag: :request, name: 'apache' }, 200, 300 ],
161
+ [ { tag: :request, name: 'apache' }, 350, 420 ],
162
+ [ { tag: :request, name: 'nginx' }, 350, 400 ],
163
+ ]
164
+ expect(durations).to match_array expected_durations
165
+ end
166
+
167
+ it "filters durations by any regexp matching any value if key exists" do
168
+ durations = subject.durations(mod: /.*/).to_a
169
+ expected_durations = [
170
+ [ { tag: :compute, name: 'apache', mod: :php }, 500, 600 ],
171
+ ]
172
+ expect(durations).to match_array expected_durations
173
+ end
174
+
175
+ end
176
+ context "for incorrect data" do
177
+ let :stats do
178
+ stats = RBSim::Statistics.new
179
+ stats.event :start, { tag: :request, name: 'apache' }, 200
180
+ stats.event :start, { tag: :request, name: 'apache' }, 300
181
+ stats.event :start, { tag: :request, name: 'apache' }, 400
182
+ stats.event :stop, { tag: :request, name: 'apache' }, 450
183
+ stats.event :stop, { tag: :request, name: 'apache' }, 550
184
+ stats.event :stop, { tag: :request, name: 'apache' }, 650
185
+
186
+ stats.clock = 1000
187
+
188
+ stats
189
+ end
190
+
191
+ subject { stats }
192
+
193
+ it "correctly yields first start with first stop and so on" do
194
+ durations = subject.durations.to_a
195
+ expected_durations = [
196
+ [ { tag: :request, name: 'apache' }, 200, 450 ],
197
+ [ { tag: :request, name: 'apache' }, 300, 550 ],
198
+ [ { tag: :request, name: 'apache' }, 400, 650 ],
199
+ ]
200
+ expect(durations).to match_array expected_durations
201
+ end
202
+ end
203
+ end
204
+
205
+ describe "saves reported values" do
206
+ let :stats do
207
+ stats = RBSim::Statistics.new
208
+
209
+ stats.event :save, { value: 1024, tags: { tag: :queue_length, name: 'apache' } }, 100
210
+ stats.event :save, { value: 1524, tags: { tag: :queue_length, name: 'apache' } }, 100
211
+ stats.event :save, { value: 1024, tags: { tag: :queue_length, name: 'nginx' } }, 100
212
+ stats.event :save, { value: 2048, tags: { tag: :queue_length, name: 'apache' } }, 200
213
+ stats.event :save, { value: 2048, tags: { tag: :queue_length, name: 'apache', mod: :php } }, 200
214
+ stats.event :save, { value: 2048, tags: { tag: :queue_length, name: 'nginx' } }, 200
215
+ stats.event :save, { value: 2048, tags: { tag: :queue_length, name: 'nginx', mod: :php } }, 300
216
+ stats.event :save, { value: 20, tags: { tag: :wait_time, name: 'nginx' } }, 350
217
+ stats.event :save, { value: 512, tags: { tag: :queue_length, name: 'apache' } }, 400
218
+ stats.event :save, { value: 30, tags: { tag: :wait_time, name: 'nginx' } }, 400
219
+
220
+ stats.clock = 1000
221
+
222
+ stats
223
+ end
224
+
225
+ subject { stats }
226
+
227
+ it "returns all values" do
228
+ values = subject.values.to_a
229
+ expected_values = [
230
+ [ { tag: :queue_length, name: 'apache' }, 100, [ 1024, 1524 ] ],
231
+ [ { tag: :queue_length, name: 'nginx' }, 100, [ 1024 ] ],
232
+ [ { tag: :queue_length, name: 'apache' }, 200, [ 2048 ] ],
233
+ [ { tag: :queue_length, name: 'apache', mod: :php }, 200, [ 2048 ] ],
234
+ [ { tag: :queue_length, name: 'nginx' }, 200, [ 2048 ] ],
235
+ [ { tag: :queue_length, name: 'nginx', mod: :php }, 300, [ 2048 ] ],
236
+ [ { tag: :wait_time, name: 'nginx' }, 350, [ 20 ] ],
237
+ [ { tag: :queue_length, name: 'apache' }, 400, [ 512 ] ],
238
+ [ { tag: :wait_time, name: 'nginx' }, 400, [ 30 ] ],
239
+ ]
240
+ expect(values).to match_array expected_values
241
+ end
242
+
243
+ it "filters values by single tag" do
244
+ values = subject.values(tag: :queue_length).to_a
245
+ expected_values = [
246
+ [ { tag: :queue_length, name: 'apache' }, 100, [ 1024, 1524 ] ],
247
+ [ { tag: :queue_length, name: 'nginx' }, 100, [ 1024 ] ],
248
+ [ { tag: :queue_length, name: 'apache' }, 200, [ 2048 ] ],
249
+ [ { tag: :queue_length, name: 'apache', mod: :php }, 200, [ 2048 ] ],
250
+ [ { tag: :queue_length, name: 'nginx' }, 200, [ 2048 ] ],
251
+ [ { tag: :queue_length, name: 'nginx', mod: :php }, 300, [ 2048 ] ],
252
+ [ { tag: :queue_length, name: 'apache' }, 400, [ 512 ] ],
253
+ ]
254
+ expect(values).to match_array expected_values
255
+ end
256
+
257
+ it "filters values by two tags" do
258
+ values = subject.values(tag: :queue_length, name: 'apache').to_a
259
+ expected_values = [
260
+ [ { tag: :queue_length, name: 'apache' }, 100, [ 1024, 1524 ] ],
261
+ [ { tag: :queue_length, name: 'apache' }, 200, [ 2048 ] ],
262
+ [ { tag: :queue_length, name: 'apache', mod: :php }, 200, [ 2048 ] ],
263
+ [ { tag: :queue_length, name: 'apache' }, 400, [ 512 ] ],
264
+ ]
265
+ expect(values).to match_array expected_values
266
+ end
267
+
268
+ it "filters values by rare tag" do
269
+ values = subject.values(mod: :php).to_a
270
+ expected_values = [
271
+ [ { tag: :queue_length, name: 'apache', mod: :php }, 200, [ 2048 ] ],
272
+ [ { tag: :queue_length, name: 'nginx', mod: :php }, 300, [ 2048 ] ],
273
+ ]
274
+ expect(values).to match_array expected_values
275
+ end
276
+
277
+ it "filters values by regexp" do
278
+ values = subject.values(name: /^a.*/).to_a
279
+ expected_values = [
280
+ [ { tag: :queue_length, name: 'apache' }, 100, [ 1024, 1524 ] ],
281
+ [ { tag: :queue_length, name: 'apache' }, 200, [ 2048 ] ],
282
+ [ { tag: :queue_length, name: 'apache', mod: :php }, 200, [ 2048 ] ],
283
+ [ { tag: :queue_length, name: 'apache' }, 400, [ 512 ] ],
284
+ ]
285
+ expect(values).to match_array expected_values
286
+ end
287
+
288
+ it "filters values by any regexp matching any value if key exists" do
289
+ values = subject.values(mod: /.*/).to_a
290
+ expected_values = [
291
+ [ { tag: :queue_length, name: 'apache', mod: :php }, 200, [ 2048 ] ],
292
+ [ { tag: :queue_length, name: 'nginx', mod: :php }, 300, [ 2048 ] ],
293
+ ]
294
+ expect(values).to match_array expected_values
295
+ end
296
+
297
+ end
298
+ end
299
+
300
+ end