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