fast-tcpn 0.0.5

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 (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