mcollective-test 0.1.2

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