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.
@@ -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,15 @@
1
+ module MCollective
2
+ module Test
3
+ class RemoteAgentTest
4
+ attr_reader :agent, :plugin
5
+
6
+ include MCollective::RPC
7
+
8
+ def initialize(agent)
9
+ @agent = agent.to_s
10
+ @plugin = rpcclient(agent)
11
+ @plugin.progress = false
12
+ end
13
+ end
14
+ end
15
+ 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
+