fast-tcpn 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +40 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +453 -0
  8. data/fast-tcpn.gemspec +40 -0
  9. data/fast-tcpn.rb +192 -0
  10. data/lib/fast-tcpn.rb +25 -0
  11. data/lib/fast-tcpn/clone.rb +7 -0
  12. data/lib/fast-tcpn/clone/using_code_from_stack.rb +50 -0
  13. data/lib/fast-tcpn/clone/using_deep_clone.rb +10 -0
  14. data/lib/fast-tcpn/clone/using_deep_dive.rb +25 -0
  15. data/lib/fast-tcpn/clone/using_marshal.rb +8 -0
  16. data/lib/fast-tcpn/dsl.rb +177 -0
  17. data/lib/fast-tcpn/hash_marking.rb +220 -0
  18. data/lib/fast-tcpn/place.rb +70 -0
  19. data/lib/fast-tcpn/tcpn.rb +288 -0
  20. data/lib/fast-tcpn/timed_hash_marking.rb +87 -0
  21. data/lib/fast-tcpn/timed_place.rb +44 -0
  22. data/lib/fast-tcpn/timed_token.rb +27 -0
  23. data/lib/fast-tcpn/token.rb +30 -0
  24. data/lib/fast-tcpn/transition.rb +224 -0
  25. data/lib/fast-tcpn/version.rb +3 -0
  26. data/spec/callbacks_spec.rb +164 -0
  27. data/spec/dsl/page_spec.rb +195 -0
  28. data/spec/dsl/transition_spec.rb +41 -0
  29. data/spec/hash_marking_spec.rb +9 -0
  30. data/spec/place_spec.rb +10 -0
  31. data/spec/spec_helper.rb +101 -0
  32. data/spec/support/hash_marking_shared.rb +274 -0
  33. data/spec/support/place_shared.rb +66 -0
  34. data/spec/support/token_shared.rb +27 -0
  35. data/spec/support/uses_temp_files.rb +31 -0
  36. data/spec/tcpn_binding_spec.rb +54 -0
  37. data/spec/tcpn_sim_spec.rb +323 -0
  38. data/spec/tcpn_spec.rb +150 -0
  39. data/spec/timed_hash_marking_spec.rb +132 -0
  40. data/spec/timed_place_spec.rb +38 -0
  41. data/spec/timed_token_spec.rb +50 -0
  42. data/spec/token_spec.rb +13 -0
  43. data/spec/transition_spec.rb +236 -0
  44. metadata +156 -0
@@ -0,0 +1,66 @@
1
+ shared_examples "valid place" do
2
+
3
+ it "has name" do
4
+ p = place_class.new "process"
5
+ expect(p.name).to eq "process"
6
+ end
7
+
8
+ it "passes keys to marking constructor" do
9
+ expect(marking_class).to receive(:new).with(keys)
10
+ place_class.new "processes", keys
11
+ end
12
+
13
+ describe "when created" do
14
+ subject do
15
+ place_class.new "processes", keys
16
+ end
17
+ let(:token) { "for this example just anything" }
18
+ let(:new_keys) { { node: :node_name, priority: :pri } }
19
+
20
+ let :marking do
21
+ marking = double(marking_class)
22
+ mc = class_double(marking_class).as_stubbed_const(:transfer_nested_constants => true)
23
+ allow(mc).to receive(:new).and_return(marking)
24
+ marking
25
+ end
26
+
27
+ it "passes add to marking" do
28
+ expect(marking).to receive(:add).with(token)
29
+ subject.add token
30
+ end
31
+
32
+ it "passes delete to marking" do
33
+ expect(marking).to receive(:delete).with(token)
34
+ subject.delete token
35
+ end
36
+
37
+ it "passes add_keys to marking" do
38
+ expect(marking).to receive(:add_keys).with(new_keys)
39
+ subject.add_keys new_keys
40
+ end
41
+
42
+ it "passes keys to marking" do
43
+ expect(marking).to receive(:keys)
44
+ subject.keys
45
+ end
46
+
47
+ describe "net callback" do
48
+ let(:net) { double Object, call_callbacks: nil }
49
+ let :place do
50
+ place_class.new "process", {}, net
51
+ end
52
+
53
+ it "is called on :add" do
54
+ expect(net).to receive(:call_callbacks).with(:place, :add, anything())
55
+ place.add token
56
+ end
57
+
58
+ it "is called on :remove" do
59
+ expect(net).to receive(:call_callbacks).with(:place, :remove, anything())
60
+ allow(marking).to receive(:delete)
61
+ place.delete token
62
+ end
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,27 @@
1
+ shared_examples 'token' do
2
+
3
+ it "stores value" do
4
+ t = token_class.new "asd"
5
+ expect(t.value).to eq "asd"
6
+ end
7
+
8
+ describe "#==" do
9
+ it "is true for self" do
10
+ t = token_class.new "asd"
11
+ expect(t == t).to be true
12
+ end
13
+
14
+ it "is false for two different tokens, value does not matter" do
15
+ t1 = token_class.new "asd"
16
+ t2 = token_class.new "asd"
17
+ expect(t1 == t2).to be false
18
+ end
19
+
20
+ it "it true for clones" do
21
+ t1 = token_class.new "asd"
22
+ t2 = t1.clone
23
+ expect(t1 == t2).to be true
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,31 @@
1
+ # taken from here:
2
+ # http://gabebw.wordpress.com/2011/03/21/temp-files-in-rspec/
3
+ module UsesTempFiles
4
+ def self.included(example_group)
5
+ example_group.extend(self)
6
+ end
7
+
8
+ def in_directory_with_file(file)
9
+ before do
10
+ @pwd = Dir.pwd if @pwd.nil?
11
+ @tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
12
+ FileUtils.mkdir_p(@tmp_dir)
13
+ Dir.chdir(@tmp_dir)
14
+
15
+ FileUtils.mkdir_p(File.dirname(file))
16
+ FileUtils.touch(file)
17
+ end
18
+
19
+ define_method(:content_for_file) do |fname, content|
20
+ f = File.new(File.join(@tmp_dir, fname), 'a+')
21
+ f.write(content)
22
+ f.flush # VERY IMPORTANT
23
+ f.close
24
+ end
25
+
26
+ after do
27
+ Dir.chdir(@pwd)
28
+ FileUtils.rm_rf(@tmp_dir)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe FastTCPN::TCPNBinding do
4
+
5
+ let :marking_for do
6
+ process = FastTCPN::HashMarking.new
7
+ process.add "process1"
8
+ process.add "process2"
9
+
10
+ cpu = FastTCPN::HashMarking.new
11
+ cpu.add "cpu1"
12
+ cpu.add "cpu2"
13
+
14
+ { process: process, cpu: cpu }
15
+ end
16
+
17
+ let :selected_process do
18
+ marking_for[:process].each.first
19
+ end
20
+
21
+ let :selected_cpu do
22
+ marking_for[:cpu].each.first
23
+ end
24
+
25
+ let :mapping do
26
+ { process: selected_process, cpu: selected_cpu }
27
+ end
28
+
29
+ subject do
30
+ FastTCPN::TCPNBinding.new mapping, marking_for
31
+ end
32
+
33
+ describe "returns new copy of token for given place" do
34
+ it "returns selected process" do
35
+ expect(subject[:process]).to eq selected_process
36
+ end
37
+
38
+ it "returns selected cpu" do
39
+ expect(subject[:cpu]).to eq selected_cpu
40
+ end
41
+
42
+ end
43
+
44
+ context "for array of tokens for a place" do
45
+ let :selected_process do
46
+ [ marking_for[:process].to_a[0],
47
+ marking_for[:process].to_a[1] ]
48
+ end
49
+ it "returns array of new copies of tokens for this place" do
50
+ expect(subject[:process]).to eq selected_process
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,323 @@
1
+ require 'spec_helper'
2
+
3
+ describe FastTCPN::TCPN do
4
+ describe "#sim" do
5
+ AppProcess = Struct.new(:name)
6
+ CPU = Struct.new(:name, :process)
7
+
8
+ let(:net) do
9
+ n = FastTCPN::TCPN.new
10
+ n
11
+ end
12
+
13
+ let(:process_count) { 10 }
14
+ let(:cpu_count) { 10 }
15
+
16
+ shared_examples "correctly moves tokens" do
17
+
18
+ it "removes all tokens from process" do
19
+ expect(process.marking.size).to eq 0
20
+ end
21
+
22
+ it "returns all tokens back to cpu" do
23
+ expect(cpu.marking.size).to eq cpu_count * process_count
24
+ end
25
+
26
+ it "leaves no tokens in out" do
27
+ expect(out.marking.size).to eq 0
28
+ end
29
+
30
+ it "puts all tokens in finished" do
31
+ expect(finished.marking.size).to eq process_count
32
+ end
33
+ end
34
+
35
+ context "without time" do
36
+
37
+ let(:process) { net.place :process, name: :name }
38
+ let(:cpu) { net.place :cpu, name: :name, process: :process }
39
+ let(:out) { net.place :out }
40
+ let(:finished) { net.place :finished }
41
+
42
+
43
+ before do
44
+ t1 = net.transition :work
45
+ t1.sentry do |marking_for, clock, result|
46
+ marking_for[:process].each do |p|
47
+ marking_for[:cpu].each(:process, p.value.name) do |c|
48
+ result << { process: p, cpu: c }
49
+ end
50
+ end
51
+ end
52
+ t1.input process
53
+ t1.input cpu
54
+ t1.output out do |binding|
55
+ binding[:process].value.name + "_done"
56
+ end
57
+ t1.output cpu do |binding|
58
+ binding[:cpu]
59
+ end
60
+
61
+ t2 = net.transition :finish
62
+ t2.input out
63
+ t2.output finished do |binding|
64
+ binding[:out]
65
+ end
66
+
67
+ process_count.times do |p|
68
+ process.add AppProcess.new(p.to_s)
69
+ cpu_count.times.map { |c| cpu.add CPU.new("CPU#{c}_#{p}", p.to_s) }
70
+ end
71
+
72
+ net.sim
73
+
74
+ end
75
+
76
+ include_examples "correctly moves tokens"
77
+
78
+ end
79
+
80
+ context "with time" do
81
+
82
+ let(:process) { net.timed_place :process, name: :name }
83
+ let(:cpu) { net.timed_place :cpu, name: :name, process: :process }
84
+ let(:out) { net.timed_place :out }
85
+ let(:finished) { net.timed_place :finished }
86
+
87
+ before do
88
+ t1 = net.transition :work
89
+ t1.sentry do |marking_for, clock, result|
90
+ marking_for[:process].each do |p|
91
+ marking_for[:cpu].each(:process, p.value.name) do |c|
92
+ result << { process: p, cpu: c }
93
+ end
94
+ end
95
+ end
96
+ t1.input process
97
+ t1.input cpu
98
+ t1.output out do |binding, clock|
99
+ { val: binding[:process].value.name + "_done", ts: clock + 10 }
100
+ end
101
+ t1.output cpu do |binding, clock|
102
+ binding[:cpu].with_timestamp clock + 100
103
+ end
104
+
105
+ t2 = net.transition :finish
106
+ t2.input out
107
+ t2.output finished do |binding, clock|
108
+ binding[:out].with_timestamp clock + 100
109
+ end
110
+
111
+ process_count.times do |p|
112
+ process.add AppProcess.new(p.to_s)
113
+ cpu_count.times.map { |c| cpu.add CPU.new("CPU#{c}_#{p}", p.to_s) }
114
+ end
115
+
116
+ net.sim
117
+
118
+ end
119
+
120
+ include_examples "correctly moves tokens"
121
+
122
+ it "sets correct timestamps of used cpus" do
123
+ used_cpus = cpu.marking.select { |token| token.timestamp == 100 }.length
124
+ expect(used_cpus).to eq process_count
125
+ end
126
+
127
+ it "sets correct timestamps on processes" do
128
+ finished.marking.each do |token|
129
+ expect(token.timestamp).to eq 110
130
+ end
131
+ end
132
+
133
+ it "stops at correct time" do
134
+ expect(net.clock).to eq 110
135
+ end
136
+
137
+ end
138
+
139
+
140
+ describe "error handling" do
141
+ let(:process) { tcpn.timed_place :process, name: :name }
142
+ let(:cpu) { tcpn.timed_place :cpu, name: :name, process: :process }
143
+ let(:out) { tcpn.timed_place :out }
144
+
145
+ let(:tcpn) do
146
+ FastTCPN::TCPN.new
147
+ end
148
+
149
+ before do
150
+ t1 = tcpn.transition :work
151
+ t1.sentry &sentry
152
+ t1.input process
153
+ t1.input cpu
154
+ t1.output out, &out_output
155
+ t1.output cpu, &cpu_output
156
+
157
+ process.add AppProcess.new('process1')
158
+ cpu.add CPU.new("CPU1_process1", 'process1')
159
+ end
160
+
161
+ let(:sentry) do
162
+ proc do |marking_for, clock, result|
163
+ marking_for[:process].each do |p|
164
+ marking_for[:cpu].each(:process, p.value.name) do |c|
165
+ result << { process: p, cpu: c }
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ let(:out_output) do
172
+ proc do |binding, clock|
173
+ { val: binding[:process].value.name + "_done", ts: clock + 10 }
174
+ end
175
+ end
176
+
177
+ let(:cpu_output) do
178
+ proc do |binding, clock|
179
+ binding[:cpu].with_timestamp clock + 100
180
+ end
181
+ end
182
+
183
+ shared_examples 'error handler' do
184
+ it "raises TCPN::SimulationError" do
185
+ expect { tcpn.sim }.to raise_error FastTCPN::TCPN::SimulationError
186
+ end
187
+
188
+ context "when FastTCPN.debug is false" do
189
+ it "does not put FastTCPN files in backtrace" do
190
+ FastTCPN.debug = false
191
+ error_raised = false
192
+ begin
193
+ tcpn.sim
194
+ rescue FastTCPN::TCPN::SimulationError => e
195
+ error_raised = true
196
+ expect(e.backtrace.map { |b| b.sub /:.*$/,'' }.select{ |b| b =~ /\/lib\/fast-tcpn\// }).to be_empty
197
+ expect(e.backtrace).not_to be_empty
198
+ end
199
+ expect(error_raised).to be true
200
+ end
201
+ end
202
+
203
+ context "when FastTCPN.debug is true" do
204
+ it "puts FastTCPN files in backtrace" do
205
+ FastTCPN.debug = true
206
+ error_raised = false
207
+ begin
208
+ tcpn.sim
209
+ rescue FastTCPN::TCPN::SimulationError => e
210
+ error_raised = true
211
+ expect(e.backtrace.map { |b| b.sub /:.*$/,'' }.select{ |b| b =~ /\/lib\/fast-tcpn\// }).not_to be_empty
212
+ end
213
+ expect(error_raised).to be true
214
+ end
215
+ end
216
+ end
217
+
218
+ context "for invalid mapping from sentry" do
219
+ let(:sentry) do
220
+ proc do |marking_for, clock, result|
221
+ marking_for[:process].each do |p|
222
+ result << { process: p }
223
+ end
224
+ end
225
+ end
226
+
227
+ it_behaves_like 'error handler'
228
+ end
229
+
230
+ context "for NoMethodError inside simulator" do
231
+ let(:out_output) do
232
+ proc do |binding, clock|
233
+ { val: binding[:process].value.name.no_such_method_exists , ts: clock + 10 }
234
+ end
235
+ end
236
+
237
+ it_behaves_like 'error handler'
238
+ end
239
+
240
+ end
241
+ end
242
+
243
+ describe "#stop" do
244
+ AppProcess = Struct.new(:name)
245
+ CPU = Struct.new(:name, :process)
246
+
247
+ let(:net) do
248
+ n = FastTCPN::TCPN.new
249
+ n
250
+ end
251
+
252
+ let(:process_count) { 10 }
253
+ let(:cpu_count) { 10 }
254
+
255
+ let(:process) { net.place :process, name: :name }
256
+ let(:cpu) { net.place :cpu, name: :name, process: :process }
257
+ let(:out) { net.place :out }
258
+ let(:finished) { net.place :finished }
259
+
260
+
261
+ before do
262
+ t1 = net.transition :work
263
+ t1.sentry do |marking_for, clock, result|
264
+ marking_for[:process].each do |p|
265
+ marking_for[:cpu].each(:process, p.value.name) do |c|
266
+ result << { process: p, cpu: c }
267
+ end
268
+ end
269
+ end
270
+ t1.input process
271
+ t1.input cpu
272
+ t1.output out do |binding|
273
+ binding[:process].value.name + "_done"
274
+ end
275
+ t1.output cpu do |binding|
276
+ binding[:cpu]
277
+ end
278
+
279
+ t2 = net.transition :finish
280
+ t2.input out
281
+ t2.output finished do |binding|
282
+ binding[:out]
283
+ end
284
+
285
+ process_count.times do |p|
286
+ process.add AppProcess.new(p.to_s)
287
+ cpu_count.times.map { |c| cpu.add CPU.new("CPU#{c}_#{p}", p.to_s) }
288
+ end
289
+
290
+ end
291
+
292
+ it "stops running simulator" do
293
+ transitions = []
294
+ net.cb_for :transition, :after do |t, e|
295
+ transitions << e.transition
296
+ if transitions.size == 2
297
+ net.stop
298
+ end
299
+ end
300
+ net.sim
301
+ expect(transitions.size).to eq 2
302
+ end
303
+
304
+ describe "#stopped?" do
305
+ it "is true if simulation was stopped by #stop" do
306
+ transitions = []
307
+ net.cb_for :transition, :after do |t, e|
308
+ transitions << e.transition
309
+ if transitions.size == 2
310
+ net.stop
311
+ end
312
+ end
313
+ net.sim
314
+ expect(net.stopped?).to be true
315
+ end
316
+
317
+ it "is false if simulation finished without #stop" do
318
+ net.sim
319
+ expect(net.stopped?).to be false
320
+ end
321
+ end
322
+ end
323
+ end