rbsim 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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