daf 0.3.0
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/.gitignore +34 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +71 -0
- data/LICENSE.txt +21 -0
- data/README.md +37 -0
- data/Rakefile +23 -0
- data/bin/dad +5 -0
- data/daf.gemspec +35 -0
- data/examples/config/SendEmail.yaml +16 -0
- data/lib/daf.rb +50 -0
- data/lib/daf/action.rb +25 -0
- data/lib/daf/actions/email_action.rb +34 -0
- data/lib/daf/actions/pushbullet_action.rb +26 -0
- data/lib/daf/actions/shell_action.rb +21 -0
- data/lib/daf/actions/sms_action.rb +25 -0
- data/lib/daf/command.rb +55 -0
- data/lib/daf/configurable.rb +145 -0
- data/lib/daf/datasources/yaml_data_source.rb +53 -0
- data/lib/daf/monitor.rb +27 -0
- data/lib/daf/monitors/file_update_monitor.rb +46 -0
- data/lib/daf/version.rb +4 -0
- data/spec/action_spec.rb +38 -0
- data/spec/command_spec.rb +78 -0
- data/spec/configurable_spec.rb +62 -0
- data/spec/daf_spec.rb +93 -0
- data/spec/email_action_spec.rb +61 -0
- data/spec/file_update_monitor_spec.rb +85 -0
- data/spec/monitor_spec.rb +41 -0
- data/spec/shell_action_spec.rb +55 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/yaml_data_source_spec.rb +117 -0
- metadata +188 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DAF::Configurable do
|
4
|
+
# Test class to verify Configurable functionality
|
5
|
+
class MockClass
|
6
|
+
include DAF::Configurable
|
7
|
+
|
8
|
+
attr_option :test, String, :required
|
9
|
+
attr_option :test2, Integer, :optional do |val|
|
10
|
+
val > 2
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_output :test_out, String
|
14
|
+
attr_output :test2_out, Integer
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
@under_test = MockClass.new
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has required option' do
|
22
|
+
expect { MockClass.required_options }.to_not raise_error
|
23
|
+
expect(MockClass.required_options).not_to be_empty
|
24
|
+
expect(MockClass.required_options.length).to eq(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'has options' do
|
28
|
+
expect { MockClass.options }.to_not raise_error
|
29
|
+
expect(MockClass.options).not_to be_empty
|
30
|
+
expect(MockClass.options.length).to eq(2)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'has outputs' do
|
34
|
+
expect { MockClass.outputs }.to_not raise_error
|
35
|
+
expect(MockClass.outputs).not_to be_empty
|
36
|
+
expect(MockClass.outputs.length).to eq(2)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'has readable outputs' do
|
40
|
+
expect { @under_test.test2_out }.to_not raise_error
|
41
|
+
expect { @under_test.test_out }.to_not raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'exposes required type for inputs' do
|
45
|
+
expect(@under_test.test.type).to eq(String)
|
46
|
+
expect(@under_test.test2.type).to eq(Integer)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'has writable inputs' do
|
50
|
+
@under_test.test.value = 'Test'
|
51
|
+
@under_test.test2.value = 40
|
52
|
+
expect(@under_test.test.value).to eq('Test')
|
53
|
+
expect(@under_test.test2.value).to eq(40)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'validates inputs' do
|
57
|
+
@under_test.test.value = 40
|
58
|
+
@under_test.test2.value = 'bad value'
|
59
|
+
expect(@under_test.test.valid?).to eq(false)
|
60
|
+
expect(@under_test.test.valid?).to eq(false)
|
61
|
+
end
|
62
|
+
end
|
data/spec/daf_spec.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include DAF
|
3
|
+
|
4
|
+
describe 'DAF' do
|
5
|
+
context 'when start_dad is called' do
|
6
|
+
let!(:data_source) do
|
7
|
+
dup = class_double('DAF::YAMLDataSource').as_stubbed_const
|
8
|
+
allow(dup).to receive(:new)
|
9
|
+
dup
|
10
|
+
end
|
11
|
+
|
12
|
+
let!(:command) do
|
13
|
+
dup = class_double('DAF::Command').as_stubbed_const
|
14
|
+
allow(dup).to receive(:new).and_return('com')
|
15
|
+
dup
|
16
|
+
end
|
17
|
+
|
18
|
+
let!(:dir) do
|
19
|
+
dup = class_double('Dir').as_stubbed_const(
|
20
|
+
transfer_nested_constants: true)
|
21
|
+
allow(dup).to receive(:[]).and_return(%w(test1 test2))
|
22
|
+
dup
|
23
|
+
end
|
24
|
+
|
25
|
+
let!(:dad) do
|
26
|
+
dup = class_double('DAF::DynamicActionDaemon').as_stubbed_const
|
27
|
+
allow(dup).to receive(:new).and_return(idad)
|
28
|
+
dup
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:idad) do
|
32
|
+
dup = double('DAF::DynamicActionDaemon')
|
33
|
+
allow(dup).to receive(:start)
|
34
|
+
dup
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should print usage if argument is not directory' do
|
38
|
+
expect(self).to receive(:print_usage)
|
39
|
+
ARGV[0] = '/dev/null'
|
40
|
+
start_dad
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should get list of files using Dir' do
|
44
|
+
expect(dir).to receive(:[]).with('//*.yaml')
|
45
|
+
ARGV[0] = '/'
|
46
|
+
start_dad
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should generate a list of commands from each file' do
|
50
|
+
expect(command).to receive(:new).twice
|
51
|
+
expect(data_source).to receive(:new).with('test1')
|
52
|
+
expect(data_source).to receive(:new).with('test2')
|
53
|
+
ARGV[0] = '/'
|
54
|
+
start_dad
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should create a new daemon with commands' do
|
58
|
+
expect(dad).to receive(:new).with(%w(com com))
|
59
|
+
ARGV[0] = '/'
|
60
|
+
start_dad
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should start the daemon' do
|
64
|
+
expect(idad).to receive(:start)
|
65
|
+
ARGV[0] = '/'
|
66
|
+
start_dad
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when usage information is printed' do
|
71
|
+
it 'should write to stdout' do
|
72
|
+
expect($stdout).to receive(:write).at_least(1).times
|
73
|
+
print_usage
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'DAF::DynamicActionDaemon' do
|
79
|
+
context 'when started' do
|
80
|
+
it 'should execute each command' do
|
81
|
+
command1 = double('DAF::Command')
|
82
|
+
command2 = double('DAF::Command')
|
83
|
+
expect(command1).to receive(:execute)
|
84
|
+
expect(command2).to receive(:execute)
|
85
|
+
dad = DynamicActionDaemon.new([command1, command2])
|
86
|
+
thread = Thread.new do
|
87
|
+
dad.start
|
88
|
+
end
|
89
|
+
sleep(1)
|
90
|
+
thread.kill
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DAF::EmailAction do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@server = 'mail.example.com'
|
7
|
+
@options = { 'from' => 'test@example.com',
|
8
|
+
'to' => 'test_to@example.com',
|
9
|
+
'subject' => 'Test Subject',
|
10
|
+
'body' => 'Test Body',
|
11
|
+
'server' => @server }
|
12
|
+
@action = DAF::EmailAction.new
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'has five required options' do
|
16
|
+
expect { @action.class.required_options }.not_to raise_error
|
17
|
+
expect(@action.class.required_options.length).to eq(5)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'has six options' do
|
21
|
+
expect { @action.class.options }.not_to raise_error
|
22
|
+
expect(@action.class.options.length).to eq(6)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has a port option of type Integer' do
|
26
|
+
expect(@action.class.options['port']).to eq(Integer)
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when activate is called' do
|
30
|
+
before(:each) do
|
31
|
+
@smtp_obj = double(Net::SMTP.new('mail.example.com'))
|
32
|
+
@smtp = class_double('Net::SMTP')
|
33
|
+
.as_stubbed_const(transfer_nested_constants: true)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sends with the server and port passed in' do
|
37
|
+
@options['port'] = 333
|
38
|
+
expect(@smtp).to receive(:start).with(@server, 333)
|
39
|
+
@action.activate(@options)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should use a default port if none is specified' do
|
43
|
+
expect(@smtp).to receive(:start).with(@server, 25)
|
44
|
+
@action.activate(@options)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should send a message' do
|
48
|
+
target_message = <<END
|
49
|
+
From: test@example.com
|
50
|
+
To: test_to@example.com
|
51
|
+
Subject: Test Subject
|
52
|
+
|
53
|
+
Test Body
|
54
|
+
END
|
55
|
+
allow(@smtp).to receive(:start).and_yield(@smtp_obj)
|
56
|
+
expect(@smtp_obj).to receive(:send_message).with(
|
57
|
+
target_message, 'test@example.com', 'test_to@example.com')
|
58
|
+
@action.activate(@options)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'DAF::FileUpdateMonitor' do
|
4
|
+
context 'when new monitor is created' do
|
5
|
+
it 'should validate that the path exists' do
|
6
|
+
options = { 'frequency' => 2, 'path' => '/tmp/fake' }
|
7
|
+
expect { FileUpdateMonitor.new(options) }.to raise_error
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should validate that the frequency is > 1' do
|
11
|
+
options = { 'frequency' => 0, 'path' => '/' }
|
12
|
+
expect { FileUpdateMonitor.new(options) }.to raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should have a required option named path' do
|
16
|
+
expect(FileUpdateMonitor.required_options).to include('path')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should have a required option named frequency' do
|
20
|
+
expect(FileUpdateMonitor.required_options).to include('frequency')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when block_until_triggered is called' do
|
25
|
+
let(:monitor) do
|
26
|
+
options = { 'frequency' => 2, 'path' => '/' }
|
27
|
+
FileUpdateMonitor.new(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
let!(:file) do
|
31
|
+
dup = class_double('File').as_stubbed_const(
|
32
|
+
transfer_nested_constants: true)
|
33
|
+
@time = 0
|
34
|
+
allow(dup).to receive(:mtime) do
|
35
|
+
@time += 1
|
36
|
+
end
|
37
|
+
allow(dup).to receive(:exist?).and_return(true)
|
38
|
+
allow(dup).to receive(:open).and_return(ifile)
|
39
|
+
dup
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:ifile) do
|
43
|
+
dup = double('File')
|
44
|
+
allow(dup).to receive(:read).and_return('contents')
|
45
|
+
allow(dup).to receive(:close)
|
46
|
+
dup
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should sleep the set frequency' do
|
50
|
+
expect(monitor).to receive(:sleep).with(2)
|
51
|
+
monitor.block_until_triggered
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should record current time' do
|
55
|
+
expect(file).to receive(:mtime).twice
|
56
|
+
monitor.block_until_triggered
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should skip loop unless file modify time changes' do
|
60
|
+
expect(monitor).to receive(:sleep).with(2).exactly(3).times
|
61
|
+
@mtime = 0
|
62
|
+
allow(file).to receive(:mtime) do
|
63
|
+
@mtime += 1
|
64
|
+
if @mtime < 4
|
65
|
+
0
|
66
|
+
else
|
67
|
+
1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
monitor.block_until_triggered
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when file is modified' do
|
74
|
+
it 'should record the time as output' do
|
75
|
+
monitor.block_until_triggered
|
76
|
+
expect(monitor.time).to eq(2)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should record the contents of the file as output' do
|
80
|
+
monitor.block_until_triggered
|
81
|
+
expect(monitor.contents).to eq('contents')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Test monitor to verify functionality
|
4
|
+
class TestMonitor < DAF::Monitor
|
5
|
+
attr_option :option, String
|
6
|
+
attr_reader :output
|
7
|
+
def block_until_triggered
|
8
|
+
@output = 123
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe DAF::Monitor do
|
13
|
+
let(:test_monitor) { TestMonitor.new('option' => 'test') }
|
14
|
+
|
15
|
+
it 'should be configurable' do
|
16
|
+
mixed_in = DAF::Monitor.ancestors.select { |o| o.class == Module }
|
17
|
+
expect(mixed_in).to include(DAF::Configurable)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should have an on_trigger method' do
|
21
|
+
expect(test_monitor).to respond_to(:on_trigger)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should require a block to execute' do
|
25
|
+
expect { test_monitor.on_trigger }.to raise_error(LocalJumpError)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should call block_until_triggered' do
|
29
|
+
test_monitor.on_trigger {}
|
30
|
+
expect(test_monitor.output).to eq(123)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should yield to a given block when triggered' do
|
34
|
+
expect { |b| test_monitor.on_trigger(&b) }
|
35
|
+
.to yield_with_no_args
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should set option values' do
|
39
|
+
expect(test_monitor.option.value).to eq('test')
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DAF::ShellAction do
|
4
|
+
before(:each) do
|
5
|
+
@options = { 'path' => '/bin/ls' }
|
6
|
+
@action = DAF::ShellAction.new
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'options' do
|
10
|
+
it 'has a required path option of type String' do
|
11
|
+
expect { @action.class.required_options }.not_to raise_error
|
12
|
+
expect(@action.class.required_options.length).to eq(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'validates the path is executable and exists' do
|
16
|
+
@action.path.value = '/bin/ls'
|
17
|
+
expect(@action.path.valid?).to eq(true)
|
18
|
+
@action.path.value = '/tmp/nonsense'
|
19
|
+
expect(@action.path.valid?).to eq(false)
|
20
|
+
@action.path.value = '/tmp/test1'
|
21
|
+
expect(@action.path.valid?).to eq(false)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'has an optional arguments option of type String' do
|
25
|
+
expect { @action.class.options }.not_to raise_error
|
26
|
+
expect(@action.class.options.length).to eq(2)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'has an output results of type String' do
|
31
|
+
expect { @action.class.outputs }.not_to raise_error
|
32
|
+
expect(@action.class.outputs.length).to eq(1)
|
33
|
+
expect(@action.class.outputs['results']).to eq(String)
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when activate is called' do
|
37
|
+
it 'executes a shell script' do
|
38
|
+
expect(@action).to receive(:`).with('/bin/ls')
|
39
|
+
@action.activate(@options)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns the result of shell script' do
|
43
|
+
allow(@action).to receive(:`).and_return('result!')
|
44
|
+
@action.activate(@options)
|
45
|
+
expect(@action.results).to eq('result!')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'passes arguments to the shell script' do
|
49
|
+
expect(@action).to receive(:`).with('/bin/ls test')
|
50
|
+
@options['arguments'] = 'test'
|
51
|
+
@action.activate(@options)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start do
|
3
|
+
add_filter '/spec/'
|
4
|
+
add_group 'Actions', 'lib/daf/actions/'
|
5
|
+
add_group 'Monitors', 'lib/daf/monitors/'
|
6
|
+
add_group 'Data Sources', 'lib/daf/datasources/'
|
7
|
+
minimum_coverage 95
|
8
|
+
refuse_coverage_drop
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'daf'
|
12
|
+
require 'daf/command'
|
13
|
+
require 'daf/configurable'
|
14
|
+
require 'daf/monitor'
|
15
|
+
require 'daf/action'
|
16
|
+
require 'daf/monitors/file_update_monitor'
|
17
|
+
require 'daf/actions/email_action'
|
18
|
+
require 'daf/actions/shell_action'
|
19
|
+
require 'daf/datasources/yaml_data_source'
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestMonitor < DAF::Monitor
|
4
|
+
end
|
5
|
+
|
6
|
+
class TestAction < DAF::Action
|
7
|
+
end
|
8
|
+
|
9
|
+
describe DAF::YAMLDataSource do
|
10
|
+
let!(:yaml) do
|
11
|
+
yaml = class_double('YAML').as_stubbed_const(
|
12
|
+
transfer_nested_constants: true)
|
13
|
+
allow(yaml).to receive(:load_file).and_return(
|
14
|
+
'Monitor' => { 'Options' => {}, 'Type' => 'TestMonitor' },
|
15
|
+
'Action' => { 'Options' => {
|
16
|
+
'test' => '{{test}}',
|
17
|
+
'test2' => 'thing: {{test2}}'
|
18
|
+
}, 'Type' => 'TestAction' })
|
19
|
+
yaml
|
20
|
+
end
|
21
|
+
let(:data_source) { DAF::YAMLDataSource.new('/tmp/test') }
|
22
|
+
|
23
|
+
context 'properties' do
|
24
|
+
it 'responds to #monitor' do
|
25
|
+
expect(data_source).to respond_to(:monitor)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'responds to #action' do
|
29
|
+
expect(data_source).to respond_to(:action)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when new is called' do
|
34
|
+
it 'should load the file at the given path' do
|
35
|
+
expect(yaml).to receive(:load_file).with('/tmp/2')
|
36
|
+
DAF::YAMLDataSource.new('/tmp/2')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should initialize monitor class specified' do
|
40
|
+
expect(data_source.monitor.class).to eq(TestMonitor)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should initialize action class specified' do
|
44
|
+
expect(data_source.action.class).to eq(TestAction)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should throw an exception if class does not exist' do
|
48
|
+
allow(yaml).to receive(:load_file).and_return(
|
49
|
+
'Monitor' => { 'Options' => [], 'Type' => 'BadTestMonitor' },
|
50
|
+
'Action' => { 'Options' => [], 'Type' => 'BadTestAction' })
|
51
|
+
expect { DAF::YAMLDataSource.new('/tmp/new') }.to raise_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when asked for action_options' do
|
56
|
+
let(:itest_action) do
|
57
|
+
double('TestAction')
|
58
|
+
end
|
59
|
+
let!(:test_action) do
|
60
|
+
dup = class_double('TestAction').as_stubbed_const
|
61
|
+
allow(dup).to receive(:new).and_return(itest_action)
|
62
|
+
dup
|
63
|
+
end
|
64
|
+
let(:itest_monitor) do
|
65
|
+
double('TestMonitor')
|
66
|
+
end
|
67
|
+
let!(:test_monitor) do
|
68
|
+
dup = class_double('TestMonitor').as_stubbed_const
|
69
|
+
allow(dup).to receive(:new).and_return(itest_monitor)
|
70
|
+
dup
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should return raw options if no outputs defined' do
|
74
|
+
allow(test_monitor).to receive(:outputs).and_return({})
|
75
|
+
expect(data_source.action_options).to have_key('test')
|
76
|
+
expect(data_source.action_options['test']).to eq('{{test}}')
|
77
|
+
expect(data_source.action_options).to have_key('test2')
|
78
|
+
expect(data_source.action_options['test2']).to eq('thing: {{test2}}')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should return raw options if no outputs match outputs' do
|
82
|
+
allow(test_monitor).to receive(:outputs).and_return(
|
83
|
+
'another_test' => String
|
84
|
+
)
|
85
|
+
allow(itest_monitor).to receive(:another_test).and_return('test_output')
|
86
|
+
expect(data_source.action_options).to have_key('test')
|
87
|
+
expect(data_source.action_options['test']).to eq('{{test}}')
|
88
|
+
expect(data_source.action_options).to have_key('test2')
|
89
|
+
expect(data_source.action_options['test2']).to eq('thing: {{test2}}')
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should substitute outputs into options' do
|
93
|
+
allow(test_monitor).to receive(:outputs).and_return(
|
94
|
+
'test' => String
|
95
|
+
)
|
96
|
+
allow(itest_monitor).to receive(:test).and_return('test output')
|
97
|
+
expect(data_source.action_options).to have_key('test')
|
98
|
+
expect(data_source.action_options['test']).to eq('test output')
|
99
|
+
expect(data_source.action_options).to have_key('test2')
|
100
|
+
expect(data_source.action_options['test2']).to eq('thing: {{test2}}')
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should substitute multiple outputs into multiple inputs' do
|
104
|
+
allow(test_monitor).to receive(:outputs).and_return(
|
105
|
+
'test' => String,
|
106
|
+
'test2' => String
|
107
|
+
)
|
108
|
+
allow(itest_monitor).to receive(:test).and_return('test output')
|
109
|
+
allow(itest_monitor).to receive(:test2).and_return('aout')
|
110
|
+
expect(data_source.action_options).to have_key('test')
|
111
|
+
expect(data_source.action_options['test']).to eq('test output')
|
112
|
+
expect(data_source.action_options).to have_key('test2')
|
113
|
+
expect(data_source.action_options['test2']).to eq('thing: aout')
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|