mcollective-test 0.1.2
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.
- data/lib/mcollective/test.rb +9 -0
- data/lib/mcollective/test/application_test.rb +43 -0
- data/lib/mcollective/test/local_agent_test.rb +44 -0
- data/lib/mcollective/test/matchers.rb +10 -0
- data/lib/mcollective/test/matchers/application_description.rb +39 -0
- data/lib/mcollective/test/matchers/rpc_metadata.rb +40 -0
- data/lib/mcollective/test/matchers/rpc_result_items.rb +35 -0
- data/lib/mcollective/test/matchers/rpc_status.rb +45 -0
- data/lib/mcollective/test/remote_agent_test.rb +15 -0
- data/lib/mcollective/test/util.rb +109 -0
- metadata +71 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
autoload :Util, "mcollective/test/util"
|
|
4
|
+
autoload :Matchers, "mcollective/test/matchers"
|
|
5
|
+
autoload :LocalAgentTest, "mcollective/test/local_agent_test.rb"
|
|
6
|
+
autoload :RemoteAgentTest, "mcollective/test/remote_agent_test.rb"
|
|
7
|
+
autoload :ApplicationTest, "mcollective/test/application_test.rb"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
class ApplicationTest
|
|
4
|
+
attr_reader :config, :logger, :application, :plugin
|
|
5
|
+
|
|
6
|
+
include Test::Util
|
|
7
|
+
|
|
8
|
+
def initialize(application, options={})
|
|
9
|
+
config = options[:config] || {}
|
|
10
|
+
facts = options[:facts] || {"fact" => "value"}
|
|
11
|
+
|
|
12
|
+
ARGV.clear
|
|
13
|
+
|
|
14
|
+
@config = create_config_mock(config)
|
|
15
|
+
@application = application.to_s
|
|
16
|
+
@logger = create_logger_mock
|
|
17
|
+
@plugin = load_application(@application, options[:application_file])
|
|
18
|
+
|
|
19
|
+
@plugin.stubs(:printrpcstats)
|
|
20
|
+
@plugin.stubs(:puts)
|
|
21
|
+
@plugin.stubs(:printf)
|
|
22
|
+
|
|
23
|
+
make_create_client
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def make_create_client
|
|
27
|
+
@plugin.instance_eval "
|
|
28
|
+
def create_client(client)
|
|
29
|
+
mock_client = Mocha::Mock.new
|
|
30
|
+
mock_client.stubs(:progress=)
|
|
31
|
+
mock_client.stubs(:progress)
|
|
32
|
+
|
|
33
|
+
yield(mock_client) if block_given?
|
|
34
|
+
|
|
35
|
+
MCollective::Application::Facts.any_instance.expects(:rpcclient).with(client).returns(mock_client)
|
|
36
|
+
|
|
37
|
+
mock_client
|
|
38
|
+
end
|
|
39
|
+
"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
class LocalAgentTest
|
|
4
|
+
attr_reader :config, :logger, :agent, :connector, :plugin, :facts
|
|
5
|
+
|
|
6
|
+
include Test::Util
|
|
7
|
+
|
|
8
|
+
def initialize(agent, options={})
|
|
9
|
+
config = options[:config]
|
|
10
|
+
facts = options[:facts] || {"fact" => "value"}
|
|
11
|
+
|
|
12
|
+
@config = create_config_mock(config)
|
|
13
|
+
@agent = agent.to_s
|
|
14
|
+
@logger = create_logger_mock
|
|
15
|
+
@connector = create_connector_mock
|
|
16
|
+
@plugin = load_agent(agent, options[:agent_file])
|
|
17
|
+
|
|
18
|
+
create_facts_mock(facts)
|
|
19
|
+
|
|
20
|
+
make_call_helper
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Place the mocked connector into the plugin instance and
|
|
25
|
+
# create a call helper method that passes the connector in
|
|
26
|
+
# and call the action via handlemsg.
|
|
27
|
+
#
|
|
28
|
+
# This will let you test auditing etc
|
|
29
|
+
def make_call_helper
|
|
30
|
+
@plugin.instance_variable_set("@mocked_connector", @connector)
|
|
31
|
+
|
|
32
|
+
@plugin.instance_eval "
|
|
33
|
+
def call(action, args={})
|
|
34
|
+
request = {:action => action.to_s,
|
|
35
|
+
:agent => '#{@agent}',
|
|
36
|
+
:data => args}
|
|
37
|
+
|
|
38
|
+
handlemsg({:body => request}, @mocked_connector)
|
|
39
|
+
end
|
|
40
|
+
"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
module Matchers
|
|
4
|
+
require 'mcollective/test/matchers/rpc_result_items.rb'
|
|
5
|
+
require 'mcollective/test/matchers/rpc_metadata.rb'
|
|
6
|
+
require 'mcollective/test/matchers/rpc_status.rb'
|
|
7
|
+
require 'mcollective/test/matchers/application_description.rb'
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
module Matchers
|
|
4
|
+
def have_a_description(description=nil); ApplicationDescription.new(description); end
|
|
5
|
+
|
|
6
|
+
class ApplicationDescription
|
|
7
|
+
def initialize(match=nil)
|
|
8
|
+
@match = match
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def matches?(actual)
|
|
12
|
+
@actual = actual.application_description
|
|
13
|
+
|
|
14
|
+
if @match
|
|
15
|
+
return @actual == @match
|
|
16
|
+
else
|
|
17
|
+
return !@actual.nil?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def failure_message
|
|
22
|
+
if @match
|
|
23
|
+
"application should have a description '#{@match}' but got '#{@actual}'"
|
|
24
|
+
else
|
|
25
|
+
"application should have a description, got #{@match}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def negative_failure_message
|
|
30
|
+
if @match
|
|
31
|
+
"application should not have a description matching '#{@match}' but got '#{@actual}'"
|
|
32
|
+
else
|
|
33
|
+
"application should not have a description"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
module Matchers
|
|
4
|
+
def have_valid_metadata; RPCMetadata.new; end
|
|
5
|
+
|
|
6
|
+
class RPCMetadata
|
|
7
|
+
def matches?(actual)
|
|
8
|
+
actual = actual.meta
|
|
9
|
+
|
|
10
|
+
@msg = "Unknown error"
|
|
11
|
+
|
|
12
|
+
[:name, :description, :author, :license, :version, :url, :timeout].each do |item|
|
|
13
|
+
unless actual.include?(item)
|
|
14
|
+
@msg = "needs a '#{item}' item"
|
|
15
|
+
return false
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
[:name, :description, :author, :license, :version, :url].each do |item|
|
|
20
|
+
unless actual[item].is_a?(String)
|
|
21
|
+
@msg = "#{item} should be a string"
|
|
22
|
+
return false
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
unless actual[:timeout].is_a?(Numeric)
|
|
27
|
+
@msg = "timeout should be numeric"
|
|
28
|
+
return false
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
return true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def failure_message
|
|
35
|
+
"Invalid meta data: #{@msg}"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
module Matchers
|
|
4
|
+
def have_data_items(*items); RPCResultItems.new(items); end
|
|
5
|
+
|
|
6
|
+
class RPCResultItems
|
|
7
|
+
def initialize(expected)
|
|
8
|
+
@expected = expected.flatten.sort
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def matches?(actual)
|
|
12
|
+
[actual].flatten.each do |result|
|
|
13
|
+
result = result.results if result.is_a?(MCollective::RPC::Result)
|
|
14
|
+
|
|
15
|
+
@actual = result[:data].keys.sort
|
|
16
|
+
|
|
17
|
+
unless @actual == @expected
|
|
18
|
+
return false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def failure_message
|
|
26
|
+
"expected keys '#{@expected.join ', '}' but got '#{@actual.join ', '}'"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def negative_failure_message
|
|
30
|
+
"did not expect keys '#{@expected.join ', '}' but got '#{@actual.keys.join ', '}'"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
module Matchers
|
|
4
|
+
def rpc_success; RPCStatus.new(0); end
|
|
5
|
+
def rpc_aborted; RPCStatus.new(1); end
|
|
6
|
+
def rpc_unknown_action; RPCStatus.new(2); end
|
|
7
|
+
def rpc_missing_data; RPCStatus.new(3); end
|
|
8
|
+
def rpc_invalid_data; RPCStatus.new(4); end
|
|
9
|
+
def rpc_unknown; RPCStatus.new(5); end
|
|
10
|
+
|
|
11
|
+
alias be_successful rpc_success
|
|
12
|
+
alias be_aborted_error rpc_aborted
|
|
13
|
+
alias be_unknown_action_error rpc_unknown_action
|
|
14
|
+
alias be_missing_data_error rpc_missing_data
|
|
15
|
+
alias be_invalid_data_error rpc_invalid_data
|
|
16
|
+
alias be_unknown_error rpc_unknown
|
|
17
|
+
|
|
18
|
+
class RPCStatus
|
|
19
|
+
def initialize(code)
|
|
20
|
+
@code = code
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def matches?(actual)
|
|
24
|
+
[actual].flatten.each do |result|
|
|
25
|
+
result = result.results if result.is_a?(MCollective::RPC::Result)
|
|
26
|
+
|
|
27
|
+
@actual = result[:statuscode]
|
|
28
|
+
|
|
29
|
+
unless @actual == @code
|
|
30
|
+
return false
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def failure_message
|
|
36
|
+
"expected :statuscode == #{@code} but got '#{@actual}'"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def negative_failure_message
|
|
40
|
+
"expected :statucode != #{@code} but got '#{@actual}'"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Test
|
|
3
|
+
module Util
|
|
4
|
+
def create_facts_mock(factsource)
|
|
5
|
+
facts = Mocha::Mock.new
|
|
6
|
+
facts.stubs(:get_facts).returns(factsource)
|
|
7
|
+
|
|
8
|
+
factsource.each_pair do |k, v|
|
|
9
|
+
facts.stubs(:get_fact).with(k).returns(v)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
MCollective::PluginManager << {:type => "facts_plugin", :class => facts, :single_instance => false}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_config_mock(config)
|
|
16
|
+
cfg = Mocha::Mock.new
|
|
17
|
+
cfg.stubs(:configured).returns(true)
|
|
18
|
+
cfg.stubs(:rpcauthorization).returns(false)
|
|
19
|
+
cfg.stubs(:main_collective).returns("mcollective")
|
|
20
|
+
cfg.stubs(:collectives).returns(["production", "staging"])
|
|
21
|
+
cfg.stubs(:classesfile).returns("classes.txt")
|
|
22
|
+
cfg.stubs(:identity).returns("rspec_tests")
|
|
23
|
+
|
|
24
|
+
if config
|
|
25
|
+
config.each_pair do |k, v|
|
|
26
|
+
cfg.send(:stubs, k).returns(v)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if config.include?(:libdir)
|
|
30
|
+
[config[:libdir]].flatten.each do |dir|
|
|
31
|
+
$: << dir if File.exist?(dir)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
MCollective::Config.stubs(:instance).returns(cfg)
|
|
37
|
+
|
|
38
|
+
cfg
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def create_logger_mock
|
|
42
|
+
logger = Mocha::Mock.new(:logger)
|
|
43
|
+
|
|
44
|
+
[:log, :start, :debug, :info, :warn].each do |meth|
|
|
45
|
+
logger.stubs(meth)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
MCollective::Log.configure(logger)
|
|
49
|
+
|
|
50
|
+
logger
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create_connector_mock
|
|
54
|
+
connector = Mocha::Mock.new(:connector)
|
|
55
|
+
|
|
56
|
+
[:connect, :receive, :publish, :subscribe, :unsubscribe, :disconnect].each do |meth|
|
|
57
|
+
connector.stubs(meth)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
MCollective::PluginManager << {:type => "connector_plugin", :class => connector}
|
|
61
|
+
|
|
62
|
+
connector
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def load_application(application, application_file=nil)
|
|
66
|
+
classname = "MCollective::Application::#{application.capitalize}"
|
|
67
|
+
MCollective::PluginManager.delete("#{application}_application")
|
|
68
|
+
|
|
69
|
+
if application_file
|
|
70
|
+
raise "Cannot find application file #{application_file} for application #{application}" unless File.exist?(application_file)
|
|
71
|
+
load application_file
|
|
72
|
+
else
|
|
73
|
+
MCollective::PluginManager.loadclass(classname)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
MCollective::PluginManager.loadclass(classname)
|
|
77
|
+
|
|
78
|
+
MCollective::PluginManager << {:type => "#{application}_application", :class => classname, :single_instance => false}
|
|
79
|
+
MCollective::PluginManager["#{application}_application"]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def load_agent(agent, agent_file=nil)
|
|
83
|
+
classname = "MCollective::Agent::#{agent.capitalize}"
|
|
84
|
+
|
|
85
|
+
MCollective::PluginManager.delete("#{agent}_agent")
|
|
86
|
+
|
|
87
|
+
if agent_file
|
|
88
|
+
raise "Cannot find agent file #{agent_file} for agent #{agent}" unless File.exist?(agent_file)
|
|
89
|
+
load agent_file
|
|
90
|
+
else
|
|
91
|
+
MCollective::PluginManager.loadclass(classname)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Stub out startup_hook as this feature should probably
|
|
95
|
+
# be deprecated and it's really hard to test
|
|
96
|
+
|
|
97
|
+
klass = MCollective::Agent.const_get(agent.capitalize)
|
|
98
|
+
klass.any_instance.stubs(:startup_hook).returns(true)
|
|
99
|
+
|
|
100
|
+
MCollective::PluginManager << {:type => "#{agent}_agent", :class => classname, :single_instance => false}
|
|
101
|
+
MCollective::PluginManager["#{agent}_agent"]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def create_response(senderid, data = {}, statuscode = 0, statusmsg = "OK")
|
|
105
|
+
{:senderid => senderid, :body =>{:data => data}}
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mcollective-test
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease: false
|
|
5
|
+
segments:
|
|
6
|
+
- 0
|
|
7
|
+
- 1
|
|
8
|
+
- 2
|
|
9
|
+
version: 0.1.2
|
|
10
|
+
platform: ruby
|
|
11
|
+
authors:
|
|
12
|
+
- R.I.Pienaar
|
|
13
|
+
autorequire:
|
|
14
|
+
bindir: bin
|
|
15
|
+
cert_chain: []
|
|
16
|
+
|
|
17
|
+
date: 2011-06-21 00:00:00 +01:00
|
|
18
|
+
default_executable:
|
|
19
|
+
dependencies: []
|
|
20
|
+
|
|
21
|
+
description: Helpers, matchers and other utilities for writing agent, application and integration tests
|
|
22
|
+
email: rip@devco.net
|
|
23
|
+
executables: []
|
|
24
|
+
|
|
25
|
+
extensions: []
|
|
26
|
+
|
|
27
|
+
extra_rdoc_files: []
|
|
28
|
+
|
|
29
|
+
files:
|
|
30
|
+
- lib/mcollective/test/matchers/rpc_result_items.rb
|
|
31
|
+
- lib/mcollective/test/matchers/rpc_metadata.rb
|
|
32
|
+
- lib/mcollective/test/matchers/application_description.rb
|
|
33
|
+
- lib/mcollective/test/matchers/rpc_status.rb
|
|
34
|
+
- lib/mcollective/test/local_agent_test.rb
|
|
35
|
+
- lib/mcollective/test/matchers.rb
|
|
36
|
+
- lib/mcollective/test/application_test.rb
|
|
37
|
+
- lib/mcollective/test/remote_agent_test.rb
|
|
38
|
+
- lib/mcollective/test/util.rb
|
|
39
|
+
- lib/mcollective/test.rb
|
|
40
|
+
has_rdoc: true
|
|
41
|
+
homepage: https://github.com/ripienaar/mcollective-test/
|
|
42
|
+
licenses: []
|
|
43
|
+
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options: []
|
|
46
|
+
|
|
47
|
+
require_paths:
|
|
48
|
+
- lib
|
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
segments:
|
|
54
|
+
- 0
|
|
55
|
+
version: "0"
|
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
segments:
|
|
61
|
+
- 0
|
|
62
|
+
version: "0"
|
|
63
|
+
requirements: []
|
|
64
|
+
|
|
65
|
+
rubyforge_project:
|
|
66
|
+
rubygems_version: 1.3.6
|
|
67
|
+
signing_key:
|
|
68
|
+
specification_version: 3
|
|
69
|
+
summary: Test helper for MCollective
|
|
70
|
+
test_files: []
|
|
71
|
+
|