sisfc 0.0.1
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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +55 -0
- data/Rakefile +9 -0
- data/bin/sisfc +32 -0
- data/examples/generator.R +45 -0
- data/examples/simulator.conf +70 -0
- data/examples/vm_allocation.conf +8 -0
- data/lib/sisfc/configuration.rb +60 -0
- data/lib/sisfc/data_center.rb +59 -0
- data/lib/sisfc/evaluation.rb +36 -0
- data/lib/sisfc/event.rb +36 -0
- data/lib/sisfc/generator.rb +80 -0
- data/lib/sisfc/request.rb +122 -0
- data/lib/sisfc/service_type.rb +16 -0
- data/lib/sisfc/simulation.rb +205 -0
- data/lib/sisfc/sorted_array.rb +57 -0
- data/lib/sisfc/statistics.rb +29 -0
- data/lib/sisfc/support/dsl_helper.rb +18 -0
- data/lib/sisfc/version.rb +3 -0
- data/lib/sisfc/vm.rb +86 -0
- data/lib/sisfc.rb +4 -0
- data/sisfc.gemspec +27 -0
- data/test/sisfc/configuration_test.rb +94 -0
- data/test/sisfc/generator_test.rb +63 -0
- data/test/sisfc/reference_configuration.rb +178 -0
- data/test/sisfc/request_test.rb +13 -0
- data/test/test_helper.rb +4 -0
- metadata +148 -0
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'sisfc/data_center'
|
2
|
+
require 'sisfc/event'
|
3
|
+
require 'sisfc/generator'
|
4
|
+
require 'sisfc/sorted_array'
|
5
|
+
require 'sisfc/statistics'
|
6
|
+
require 'sisfc/vm'
|
7
|
+
|
8
|
+
|
9
|
+
module SISFC
|
10
|
+
class Simulation
|
11
|
+
|
12
|
+
attr_reader :start_time
|
13
|
+
|
14
|
+
|
15
|
+
def initialize(opts = {})
|
16
|
+
@configuration = opts[:configuration]
|
17
|
+
@evaluator = opts[:evaluator]
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def new_event(type, data, time, destination)
|
22
|
+
e = Event.new(type, data, time, destination)
|
23
|
+
@event_queue << e
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def now
|
28
|
+
@current_time
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def evaluate_allocation(vm_allocation)
|
33
|
+
# setup simulation start and current time
|
34
|
+
@current_time = @start_time = @configuration.start_time
|
35
|
+
|
36
|
+
# create data centers
|
37
|
+
data_centers = @configuration.data_centers.map {|k,v| DataCenter.new(k,v) }
|
38
|
+
|
39
|
+
# initialize statistics
|
40
|
+
stats = Statistics.new
|
41
|
+
dc_stats = data_centers.map {|k,v| Statistics.new }
|
42
|
+
|
43
|
+
# create VMs
|
44
|
+
@vms = []
|
45
|
+
vmid = 0
|
46
|
+
vm_allocation.each do |opts|
|
47
|
+
# setup service_time_distribution
|
48
|
+
opts[:service_time_distribution] = @configuration.service_component_types[opts[:component_type]][:service_time_distribution]
|
49
|
+
|
50
|
+
# allocate the VMs
|
51
|
+
opts[:vm_num].times do
|
52
|
+
# create VM ...
|
53
|
+
vm = VM.new(vmid, opts) # vm = VM.new(vmid, opts.except(:vm_num))
|
54
|
+
# ... add it to the vm list ...
|
55
|
+
@vms << vm
|
56
|
+
# ... and register it in the corresponding data center
|
57
|
+
data_centers[opts[:dc_id]-1].add_vm(vm, opts[:component_type])
|
58
|
+
# update vm id
|
59
|
+
vmid += 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# create event queue
|
64
|
+
@event_queue = SortedArray.new
|
65
|
+
|
66
|
+
# puts "========== Simulation Start =========="
|
67
|
+
|
68
|
+
# generate first request
|
69
|
+
rg = RequestGenerator.new(@configuration.request_generation)
|
70
|
+
new_req = rg.generate
|
71
|
+
new_event(Event::ET_REQUEST_ARRIVAL, new_req, new_req.arrival_time, nil)
|
72
|
+
|
73
|
+
# schedule end of simulation
|
74
|
+
unless @configuration.end_time.nil?
|
75
|
+
# puts "Simulation ends at: #{@configuration.end_time}"
|
76
|
+
new_event(Event::ET_END_OF_SIMULATION, nil, @configuration.end_time, nil)
|
77
|
+
end
|
78
|
+
|
79
|
+
# calculate warmup threshold
|
80
|
+
warmup_threshold = @configuration.start_time + @configuration.warmup_duration.to_i
|
81
|
+
|
82
|
+
requests_being_worked_on = 0
|
83
|
+
events = 0
|
84
|
+
|
85
|
+
# launch simulation
|
86
|
+
until @event_queue.empty?
|
87
|
+
e = @event_queue.shift
|
88
|
+
|
89
|
+
events += 1
|
90
|
+
# sanity check on simulation time flow
|
91
|
+
if @current_time > e.time
|
92
|
+
raise "Error: simulation time inconsistency for event #{events} " +
|
93
|
+
"e.type=#{e.type} @current_time=#{@current_time}, e.time=#{e.time}"
|
94
|
+
end
|
95
|
+
|
96
|
+
@current_time = e.time
|
97
|
+
|
98
|
+
case e.type
|
99
|
+
when Event::ET_REQUEST_ARRIVAL
|
100
|
+
# get request
|
101
|
+
req = e.data
|
102
|
+
|
103
|
+
# find data center
|
104
|
+
data_center = data_centers[req.data_center_id-1]
|
105
|
+
|
106
|
+
# find next component name
|
107
|
+
workflow = @configuration.workflow_types[req.workflow_type_id]
|
108
|
+
next_component_name = workflow[:component_sequence][req.next_step][:name]
|
109
|
+
|
110
|
+
# get random vm providing next service component type
|
111
|
+
vm = data_center.get_random_vm(next_component_name)
|
112
|
+
|
113
|
+
# forward request to the vm
|
114
|
+
vm.new_request(self, req, e.time)
|
115
|
+
|
116
|
+
# update stats
|
117
|
+
if req.arrival_time > warmup_threshold
|
118
|
+
# increase the number of requests being worked on
|
119
|
+
requests_being_worked_on += 1
|
120
|
+
end
|
121
|
+
|
122
|
+
# generate next request
|
123
|
+
new_req = rg.generate
|
124
|
+
new_event(Event::ET_REQUEST_ARRIVAL, new_req, new_req.arrival_time, nil)
|
125
|
+
|
126
|
+
|
127
|
+
# Leave these events for when we add VM migration support
|
128
|
+
# when Event::ET_VM_SUSPEND
|
129
|
+
# when Event::ET_VM_RESUME
|
130
|
+
|
131
|
+
|
132
|
+
when Event::ET_WORKFLOW_STEP_COMPLETED
|
133
|
+
# retrieve request and vm
|
134
|
+
req = e.data
|
135
|
+
vm = e.destination
|
136
|
+
|
137
|
+
# tell the old vm that it can start processing another request
|
138
|
+
vm.request_finished(self, e.time)
|
139
|
+
|
140
|
+
# find data center and workflow
|
141
|
+
data_center = data_centers[req.data_center_id-1]
|
142
|
+
workflow = @configuration.workflow_types[req.workflow_type_id]
|
143
|
+
|
144
|
+
# check if there are other steps left to complete the workflow
|
145
|
+
if req.next_step < workflow[:component_sequence].size
|
146
|
+
# find next component name
|
147
|
+
next_component_name = workflow[:component_sequence][req.next_step][:name]
|
148
|
+
|
149
|
+
# get random vm providing next service component type
|
150
|
+
new_vm = data_center.get_random_vm(next_component_name)
|
151
|
+
|
152
|
+
# forward request to the new vm
|
153
|
+
new_vm.new_request(self, req, e.time)
|
154
|
+
else # workflow is finished
|
155
|
+
# schedule request closure
|
156
|
+
new_event(Event::ET_REQUEST_CLOSURE, req, e.time + req.communication_latency, nil)
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
when Event::ET_REQUEST_CLOSURE
|
161
|
+
# retrieve request and vm
|
162
|
+
req = e.data
|
163
|
+
|
164
|
+
# request is closed
|
165
|
+
req.finished_processing(e.time)
|
166
|
+
|
167
|
+
# update stats
|
168
|
+
if req.arrival_time > warmup_threshold
|
169
|
+
# decrease the number of requests being worked on
|
170
|
+
requests_being_worked_on -= 1
|
171
|
+
|
172
|
+
# collect request statistics
|
173
|
+
stats.record_request(req)
|
174
|
+
dc_stats[req.data_center_id - 1].record_request(req)
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
when Event::ET_END_OF_SIMULATION
|
179
|
+
# puts "#{e.time}: end simulation"
|
180
|
+
break
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# puts "========== Simulation Finished =========="
|
186
|
+
|
187
|
+
# calculate kpis (for the moment, we only have mttr)
|
188
|
+
kpis = { :mttr => stats.mean,
|
189
|
+
:served_requests => stats.n,
|
190
|
+
:queued_requests => requests_being_worked_on }
|
191
|
+
dc_kpis = dc_stats.map do |s|
|
192
|
+
{ :mttr => s.mean,
|
193
|
+
:served_requests => s.n, }
|
194
|
+
end
|
195
|
+
fitness = @evaluator.evaluate_business_impact(kpis, dc_kpis, vm_allocation)
|
196
|
+
puts "====== Evaluating new allocation ======\n" +
|
197
|
+
vm_allocation.map{|x| x.except(:service_time_distribution) }.inspect + "\n" +
|
198
|
+
"kpis #{kpis.to_s}\n" +
|
199
|
+
"dc_kpis: #{dc_kpis.to_s}\n" +
|
200
|
+
"=======================================\n"
|
201
|
+
fitness
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module SISFC
|
2
|
+
# the SortedArray class was taken from the ruby cookbook
|
3
|
+
class SortedArray < Array
|
4
|
+
def initialize(*args, &sort_by)
|
5
|
+
@sort_by = sort_by || Proc.new { |x,y| x <=> y }
|
6
|
+
super(*args)
|
7
|
+
sort! &sort_by
|
8
|
+
end
|
9
|
+
|
10
|
+
def insert(i, v)
|
11
|
+
if size == 0 or v < self[0]
|
12
|
+
super(0, v)
|
13
|
+
elsif v > self[-1]
|
14
|
+
super(-1, v)
|
15
|
+
else
|
16
|
+
left = 0
|
17
|
+
right = size - 1
|
18
|
+
middle = (left + right)/2
|
19
|
+
while left < right
|
20
|
+
if v >= self[middle]
|
21
|
+
left = middle + 1
|
22
|
+
else
|
23
|
+
right = middle
|
24
|
+
end
|
25
|
+
middle = (left + right)/2
|
26
|
+
end
|
27
|
+
super(middle, v)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def <<(el)
|
32
|
+
insert(0, el)
|
33
|
+
end
|
34
|
+
|
35
|
+
alias push <<
|
36
|
+
alias unshift <<
|
37
|
+
|
38
|
+
# some methods, like collect!, can modify the items in an array,
|
39
|
+
# taking them out of sort order. we need to redefine those
|
40
|
+
# methods.
|
41
|
+
# we can't use define_method to define these methods because in
|
42
|
+
# Ruby 1.8 you can't use define_method to create a method that
|
43
|
+
# takes a block argument.
|
44
|
+
[ "collect!", "flatten!", "[]=" ].each do |method_name|
|
45
|
+
class_eval %{
|
46
|
+
def #{method_name}(*args)
|
47
|
+
super
|
48
|
+
sort! &@sort_by
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def reverse!
|
54
|
+
# do nothing: reversing the array would disorder it.
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'sisfc/request'
|
2
|
+
|
3
|
+
module SISFC
|
4
|
+
class Statistics
|
5
|
+
attr_reader :mean, :n
|
6
|
+
|
7
|
+
# see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
|
8
|
+
def initialize
|
9
|
+
@n = 0 # number of requests
|
10
|
+
@mean = 0.0
|
11
|
+
@m_2 = 0.0
|
12
|
+
end
|
13
|
+
|
14
|
+
def record_request(req)
|
15
|
+
# get new sample
|
16
|
+
x = req.ttr
|
17
|
+
|
18
|
+
# update counters
|
19
|
+
@n += 1
|
20
|
+
delta = x - @mean
|
21
|
+
@mean += delta / @n
|
22
|
+
@m_2 += delta * (x - @mean)
|
23
|
+
end
|
24
|
+
|
25
|
+
def variance
|
26
|
+
@m_2 / (@n - 1)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# taken from Jim Freeze's excellent article "Creating DSLs with Ruby"
|
2
|
+
# http://www.artima.com/rubycs/articles/ruby_as_dsl.html
|
3
|
+
|
4
|
+
class Module
|
5
|
+
def dsl_accessor(*symbols)
|
6
|
+
symbols.each { |sym|
|
7
|
+
class_eval %{
|
8
|
+
def #{sym}(*val)
|
9
|
+
if val.empty?
|
10
|
+
@#{sym}
|
11
|
+
else
|
12
|
+
@#{sym} = val.size == 1 ? val[0] : val
|
13
|
+
end
|
14
|
+
end
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
data/lib/sisfc/vm.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'sisfc/event'
|
2
|
+
require 'erv'
|
3
|
+
|
4
|
+
|
5
|
+
module SISFC
|
6
|
+
|
7
|
+
class VM
|
8
|
+
|
9
|
+
# setup readable/accessible attributes
|
10
|
+
ATTRIBUTES = [ :vmid, :dc_id, :size ]
|
11
|
+
|
12
|
+
attr_reader *ATTRIBUTES
|
13
|
+
|
14
|
+
def initialize(vmid, opts)
|
15
|
+
# make sure all the required opts were provided
|
16
|
+
[ :dc_id, :vm_size, :service_time_distribution ].each do |k|
|
17
|
+
raise ArgumentError, "opts[:#{k}] missing" unless opts.has_key? k
|
18
|
+
end
|
19
|
+
|
20
|
+
@vmid = vmid
|
21
|
+
@dcid = opts[:dc_id]
|
22
|
+
@size = opts[:vm_size]
|
23
|
+
@service_times_rv = ERV::RandomVariable.new(opts[:service_time_distribution][@size])
|
24
|
+
|
25
|
+
# initialize request queue and related tracking information
|
26
|
+
@busy = false
|
27
|
+
@request_queue = []
|
28
|
+
|
29
|
+
# @request_queue_info = []
|
30
|
+
# @request_currently_servicing = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def new_request(sim, r, time)
|
34
|
+
# put the (request, service time, arrival time) tuple at the end of the queue
|
35
|
+
@request_queue << [ r, @service_times_rv.next, time ]
|
36
|
+
|
37
|
+
# update queue size tracking information
|
38
|
+
# @request_queue_info << { :size => @request_queue.size, :time => time }
|
39
|
+
|
40
|
+
unless @busy
|
41
|
+
# try to allocate operator
|
42
|
+
try_servicing_new_request(sim, time)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def request_finished(sim, time)
|
47
|
+
@busy = false
|
48
|
+
try_servicing_new_request(sim, time)
|
49
|
+
end
|
50
|
+
|
51
|
+
# def suspend(time)
|
52
|
+
# raise "VM is already suspended!" if @suspended
|
53
|
+
# @request_currently_servicing.finishing_time =
|
54
|
+
# @request_currently_servicing.status = Request::STATE_WORKING
|
55
|
+
# end
|
56
|
+
|
57
|
+
# def resume(time)
|
58
|
+
# raise "VM is already working!" unless @suspended
|
59
|
+
# end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def try_servicing_new_request(sim, time)
|
64
|
+
raise "Busy VM (vmid: #{@vmid})!" if @busy
|
65
|
+
|
66
|
+
unless @request_queue.empty?
|
67
|
+
# pick request and metadata from the incoming request queue
|
68
|
+
req, service_time, arrival_time = @request_queue.shift
|
69
|
+
|
70
|
+
# update the request's queuing information
|
71
|
+
req.queuing_completed(arrival_time, time - arrival_time)
|
72
|
+
|
73
|
+
# the VM is busy now
|
74
|
+
@busy = true
|
75
|
+
|
76
|
+
# update the request's working information
|
77
|
+
req.step_completed(time, time + service_time)
|
78
|
+
|
79
|
+
# schedule completion of workflow step
|
80
|
+
sim.new_event(Event::ET_WORKFLOW_STEP_COMPLETED, req, time + service_time, self)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/lib/sisfc.rb
ADDED
data/sisfc.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sisfc/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'sisfc'
|
8
|
+
spec.version = SISFC::VERSION
|
9
|
+
spec.authors = ['Mauro Tortonesi']
|
10
|
+
spec.email = ['mauro.tortonesi@unife.it']
|
11
|
+
spec.description = %q{Simulator for IT Services in Federated Clouds}
|
12
|
+
spec.summary = %q{A simulator for business-driven IT management research capable of evaluating IT service component placement in federated Cloud environments}
|
13
|
+
spec.homepage = 'https://github.com/mtortonesi/sisfc'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/).reject{|x| x == '.gitignore' }
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'activesupport', '~> 4.0.0'
|
22
|
+
spec.add_dependency 'awesome_print', '~> 1.2.0'
|
23
|
+
spec.add_dependency 'erv', '~> 0.0.2'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.5.3'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.1.1'
|
27
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'sisfc/reference_configuration'
|
4
|
+
|
5
|
+
|
6
|
+
describe SISFC::Configuration do
|
7
|
+
|
8
|
+
describe 'simulation-related parameters' do
|
9
|
+
|
10
|
+
it 'should correctly load simulation start' do
|
11
|
+
with_reference_config do |conf|
|
12
|
+
conf.start_time.must_equal START_TIME
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should correctly load simulation duration' do
|
17
|
+
with_reference_config do |conf|
|
18
|
+
conf.duration.must_equal DURATION
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should correctly load simulation end time' do
|
23
|
+
with_reference_config do |conf|
|
24
|
+
conf.end_time.must_equal START_TIME + DURATION
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should correctly load warmup phase duration' do
|
29
|
+
with_reference_config do |conf|
|
30
|
+
conf.warmup_duration.must_equal WARMUP_DURATION
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
describe 'service_component_types' do
|
38
|
+
|
39
|
+
it 'should have 3 items' do
|
40
|
+
with_reference_config do |conf|
|
41
|
+
conf.service_component_types.size.must_equal 3
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should define a Web Server' do
|
46
|
+
with_reference_config do |conf|
|
47
|
+
conf.service_component_types.keys.must_include('Web Server')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should define an App Server' do
|
52
|
+
with_reference_config do |conf|
|
53
|
+
conf.service_component_types.keys.must_include('App Server')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should define a Financial Transaction Server' do
|
58
|
+
with_reference_config do |conf|
|
59
|
+
conf.service_component_types.keys.must_include('Financial Transaction Server')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'the Web Server' do
|
64
|
+
it 'should work on medium or large VMs' do
|
65
|
+
with_reference_config do |conf|
|
66
|
+
item_conf = conf.service_component_types['Web Server']
|
67
|
+
item_conf[:allowed_vm_types].must_include(:medium)
|
68
|
+
item_conf[:allowed_vm_types].must_include(:large)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'the App Server' do
|
74
|
+
it 'should work on large and huge VMs' do
|
75
|
+
with_reference_config do |conf|
|
76
|
+
item_conf = conf.service_component_types['App Server']
|
77
|
+
item_conf[:allowed_vm_types].must_include(:large)
|
78
|
+
item_conf[:allowed_vm_types].must_include(:huge)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
describe 'data_centers' do
|
87
|
+
it 'should have 5 items' do
|
88
|
+
with_reference_config do |conf|
|
89
|
+
conf.data_centers.size.must_equal 5
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'sisfc/generator'
|
5
|
+
|
6
|
+
|
7
|
+
describe SISFC::RequestGenerator do
|
8
|
+
|
9
|
+
GENERATION_TIMES = [ Time.now, Time.now + 1.second, Time.now + 2.seconds ].map(&:to_f)
|
10
|
+
DATA_CENTER_IDS = (1..GENERATION_TIMES.size).to_a
|
11
|
+
ARRIVAL_TIMES = GENERATION_TIMES.map {|x| x + 1.0 }
|
12
|
+
WORKFLOW_IDS = GENERATION_TIMES.map { rand(10) }
|
13
|
+
REQUEST_GENERATION_DATA=<<-END
|
14
|
+
Generation Time,Data Center ID,Arrival Time,Workflow ID
|
15
|
+
#{GENERATION_TIMES[0]},#{DATA_CENTER_IDS[0]},#{ARRIVAL_TIMES[0]},#{WORKFLOW_IDS[0]}
|
16
|
+
#{GENERATION_TIMES[1]},#{DATA_CENTER_IDS[1]},#{ARRIVAL_TIMES[1]},#{WORKFLOW_IDS[1]}
|
17
|
+
#{GENERATION_TIMES[2]},#{DATA_CENTER_IDS[2]},#{ARRIVAL_TIMES[2]},#{WORKFLOW_IDS[2]}
|
18
|
+
END
|
19
|
+
|
20
|
+
it 'should read from CSV file' do
|
21
|
+
begin
|
22
|
+
# create temporary file with request generation information
|
23
|
+
tf = Tempfile.new('generator_test')
|
24
|
+
tf.write(REQUEST_GENERATION_DATA)
|
25
|
+
tf.close
|
26
|
+
|
27
|
+
with_reference_config(request_generation: { filename: tf.path }) do |conf|
|
28
|
+
rg = SISFC::RequestGenerator.new(conf.request_generation)
|
29
|
+
r = rg.generate
|
30
|
+
r.rid.must_equal 1
|
31
|
+
r.generation_time.must_equal GENERATION_TIMES[0]
|
32
|
+
r.data_center_id.must_equal DATA_CENTER_IDS[0]
|
33
|
+
r.arrival_time.must_equal ARRIVAL_TIMES[0]
|
34
|
+
end
|
35
|
+
|
36
|
+
ensure
|
37
|
+
# delete temporary file
|
38
|
+
tf.delete
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should read from command' do
|
43
|
+
begin
|
44
|
+
# create temporary file with request generation information
|
45
|
+
tf = Tempfile.new('generator_test')
|
46
|
+
tf.write(REQUEST_GENERATION_DATA)
|
47
|
+
tf.close
|
48
|
+
|
49
|
+
with_reference_config(request_generation: { command: "cat #{tf.path}" }) do |conf|
|
50
|
+
rg = SISFC::RequestGenerator.new(conf.request_generation)
|
51
|
+
r = rg.generate
|
52
|
+
r.rid.must_equal 1
|
53
|
+
r.generation_time.must_equal GENERATION_TIMES[0]
|
54
|
+
r.data_center_id.must_equal DATA_CENTER_IDS[0]
|
55
|
+
r.arrival_time.must_equal ARRIVAL_TIMES[0]
|
56
|
+
end
|
57
|
+
ensure
|
58
|
+
# delete temporary file
|
59
|
+
tf.delete
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|