chefspec-chef 9.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +30 -0
  3. data/LICENSE +22 -0
  4. data/Rakefile +85 -0
  5. data/chefspec-chef.gemspec +30 -0
  6. data/lib/chefspec/api/core.rb +217 -0
  7. data/lib/chefspec/api/described.rb +53 -0
  8. data/lib/chefspec/api/do_nothing.rb +26 -0
  9. data/lib/chefspec/api/include_any_recipe.rb +24 -0
  10. data/lib/chefspec/api/include_recipe.rb +28 -0
  11. data/lib/chefspec/api/link.rb +28 -0
  12. data/lib/chefspec/api/notifications.rb +40 -0
  13. data/lib/chefspec/api/reboot.rb +14 -0
  14. data/lib/chefspec/api/render_file.rb +37 -0
  15. data/lib/chefspec/api/state_attrs.rb +30 -0
  16. data/lib/chefspec/api/stubs.rb +183 -0
  17. data/lib/chefspec/api/stubs_for.rb +139 -0
  18. data/lib/chefspec/api/subscriptions.rb +37 -0
  19. data/lib/chefspec/api/user.rb +230 -0
  20. data/lib/chefspec/api.rb +39 -0
  21. data/lib/chefspec/berkshelf.rb +63 -0
  22. data/lib/chefspec/cacher.rb +64 -0
  23. data/lib/chefspec/coverage/filters.rb +82 -0
  24. data/lib/chefspec/coverage.rb +247 -0
  25. data/lib/chefspec/deprecations.rb +46 -0
  26. data/lib/chefspec/errors.rb +48 -0
  27. data/lib/chefspec/expect_exception.rb +51 -0
  28. data/lib/chefspec/extensions/chef/client.rb +21 -0
  29. data/lib/chefspec/extensions/chef/conditional.rb +16 -0
  30. data/lib/chefspec/extensions/chef/cookbook/gem_installer.rb +33 -0
  31. data/lib/chefspec/extensions/chef/cookbook_loader.rb +14 -0
  32. data/lib/chefspec/extensions/chef/cookbook_uploader.rb +12 -0
  33. data/lib/chefspec/extensions/chef/data_query.rb +49 -0
  34. data/lib/chefspec/extensions/chef/lwrp_base.rb +29 -0
  35. data/lib/chefspec/extensions/chef/provider.rb +39 -0
  36. data/lib/chefspec/extensions/chef/resource/freebsd_package.rb +17 -0
  37. data/lib/chefspec/extensions/chef/resource.rb +188 -0
  38. data/lib/chefspec/extensions/chef/run_context/cookbook_compiler.rb +84 -0
  39. data/lib/chefspec/extensions/chef/securable.rb +19 -0
  40. data/lib/chefspec/extensions/ohai/system.rb +11 -0
  41. data/lib/chefspec/extensions.rb +21 -0
  42. data/lib/chefspec/file_cache_path_proxy.rb +15 -0
  43. data/lib/chefspec/formatter.rb +282 -0
  44. data/lib/chefspec/librarian.rb +51 -0
  45. data/lib/chefspec/matchers/do_nothing_matcher.rb +52 -0
  46. data/lib/chefspec/matchers/include_any_recipe_matcher.rb +51 -0
  47. data/lib/chefspec/matchers/include_recipe_matcher.rb +46 -0
  48. data/lib/chefspec/matchers/link_to_matcher.rb +37 -0
  49. data/lib/chefspec/matchers/notifications_matcher.rb +143 -0
  50. data/lib/chefspec/matchers/render_file_matcher.rb +140 -0
  51. data/lib/chefspec/matchers/resource_matcher.rb +175 -0
  52. data/lib/chefspec/matchers/state_attrs_matcher.rb +71 -0
  53. data/lib/chefspec/matchers/subscribes_matcher.rb +72 -0
  54. data/lib/chefspec/matchers.rb +13 -0
  55. data/lib/chefspec/mixins/normalize.rb +22 -0
  56. data/lib/chefspec/policyfile.rb +69 -0
  57. data/lib/chefspec/renderer.rb +145 -0
  58. data/lib/chefspec/rspec.rb +21 -0
  59. data/lib/chefspec/runner.rb +8 -0
  60. data/lib/chefspec/server.rb +4 -0
  61. data/lib/chefspec/server_methods.rb +173 -0
  62. data/lib/chefspec/server_runner.rb +76 -0
  63. data/lib/chefspec/solo_runner.rb +516 -0
  64. data/lib/chefspec/stubs/command_registry.rb +11 -0
  65. data/lib/chefspec/stubs/command_stub.rb +37 -0
  66. data/lib/chefspec/stubs/data_bag_item_registry.rb +13 -0
  67. data/lib/chefspec/stubs/data_bag_item_stub.rb +25 -0
  68. data/lib/chefspec/stubs/data_bag_registry.rb +13 -0
  69. data/lib/chefspec/stubs/data_bag_stub.rb +23 -0
  70. data/lib/chefspec/stubs/registry.rb +32 -0
  71. data/lib/chefspec/stubs/search_registry.rb +13 -0
  72. data/lib/chefspec/stubs/search_stub.rb +25 -0
  73. data/lib/chefspec/stubs/stub.rb +38 -0
  74. data/lib/chefspec/util.rb +58 -0
  75. data/lib/chefspec/version.rb +3 -0
  76. data/lib/chefspec/zero_server.rb +142 -0
  77. data/lib/chefspec.rb +75 -0
  78. data/spec/spec_helper.rb +12 -0
  79. data/spec/support/hash.rb +35 -0
  80. data/spec/unit/cacher_spec.rb +70 -0
  81. data/spec/unit/coverage/filters_spec.rb +60 -0
  82. data/spec/unit/deprecations_spec.rb +52 -0
  83. data/spec/unit/errors_spec.rb +57 -0
  84. data/spec/unit/expect_exception_spec.rb +32 -0
  85. data/spec/unit/macros_spec.rb +119 -0
  86. data/spec/unit/matchers/do_nothing_matcher.rb +5 -0
  87. data/spec/unit/matchers/include_any_recipe_matcher_spec.rb +52 -0
  88. data/spec/unit/matchers/include_recipe_matcher_spec.rb +38 -0
  89. data/spec/unit/matchers/link_to_matcher_spec.rb +55 -0
  90. data/spec/unit/matchers/notifications_matcher_spec.rb +39 -0
  91. data/spec/unit/matchers/render_file_matcher_spec.rb +68 -0
  92. data/spec/unit/matchers/resource_matcher_spec.rb +5 -0
  93. data/spec/unit/matchers/state_attrs_matcher_spec.rb +68 -0
  94. data/spec/unit/matchers/subscribes_matcher_spec.rb +63 -0
  95. data/spec/unit/renderer_spec.rb +69 -0
  96. data/spec/unit/server_runner_spec.rb +28 -0
  97. data/spec/unit/solo_runner_spec.rb +171 -0
  98. data/spec/unit/stubs/command_registry_spec.rb +27 -0
  99. data/spec/unit/stubs/command_stub_spec.rb +61 -0
  100. data/spec/unit/stubs/data_bag_item_registry_spec.rb +39 -0
  101. data/spec/unit/stubs/data_bag_item_stub_spec.rb +36 -0
  102. data/spec/unit/stubs/data_bag_registry_spec.rb +39 -0
  103. data/spec/unit/stubs/data_bag_stub_spec.rb +35 -0
  104. data/spec/unit/stubs/registry_spec.rb +29 -0
  105. data/spec/unit/stubs/search_registry_spec.rb +39 -0
  106. data/spec/unit/stubs/search_stub_spec.rb +36 -0
  107. data/spec/unit/stubs/stub_spec.rb +64 -0
  108. data/templates/coverage/human.erb +22 -0
  109. data/templates/coverage/json.erb +8 -0
  110. data/templates/coverage/table.erb +14 -0
  111. data/templates/errors/cookbook_path_not_found.erb +3 -0
  112. data/templates/errors/erb_template_parse_error.erb +5 -0
  113. data/templates/errors/gem_load_error.erb +7 -0
  114. data/templates/errors/invalid_berkshelf_options.erb +4 -0
  115. data/templates/errors/may_need_to_specify_platform.erb +25 -0
  116. data/templates/errors/no_conversion_error.erb +1 -0
  117. data/templates/errors/not_stubbed.erb +7 -0
  118. data/templates/errors/shell_out_not_stubbed.erb +10 -0
  119. data/templates/errors/template_not_found.erb +9 -0
  120. metadata +221 -0
@@ -0,0 +1,25 @@
1
+ require_relative "stub"
2
+
3
+ module ChefSpec
4
+ module Stubs
5
+ class SearchStub < Stub
6
+ attr_reader :block
7
+ attr_reader :query
8
+ attr_reader :type
9
+
10
+ def initialize(type, query = "*:*", &block)
11
+ @type = type.to_s
12
+ @query = query
13
+ @block = block
14
+ end
15
+
16
+ def signature
17
+ if @block
18
+ "stub_search(#{@type.inspect}, #{@query.inspect}) { # Ruby code }"
19
+ else
20
+ "stub_search(#{@type.inspect}, #{@query.inspect}).and_return(#{@value})"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ module ChefSpec
2
+ module Stubs
3
+ class Stub
4
+ attr_reader :value
5
+
6
+ def and_return(value)
7
+ @value = value
8
+ self
9
+ end
10
+
11
+ def and_raise(exception)
12
+ @block = Proc.new { raise exception }
13
+ self
14
+ end
15
+
16
+ def result
17
+ if @block
18
+ recursively_mashify(@block.call)
19
+ else
20
+ recursively_mashify(@value)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def recursively_mashify(thing)
27
+ case thing
28
+ when Array
29
+ thing.collect { |item| recursively_mashify(item) }
30
+ when Hash
31
+ Mash.from_hash(thing)
32
+ else
33
+ thing
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,58 @@
1
+ module ChefSpec
2
+ module Util
3
+ extend self
4
+
5
+ #
6
+ # Covert the given CaMelCaSeD string to under_score. Graciously borrowed
7
+ # from http://stackoverflow.com/questions/1509915.
8
+ #
9
+ # @param [String] string
10
+ # the string to use for transformation
11
+ #
12
+ # @return [String]
13
+ #
14
+ def underscore(string)
15
+ string
16
+ .to_s
17
+ .gsub(/::/, "/")
18
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
19
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
20
+ .tr("-", "_")
21
+ .downcase
22
+ end
23
+
24
+ #
25
+ # Convert an underscored string to it's camelcase equivalent constant.
26
+ #
27
+ # @param [String] string
28
+ # the string to convert
29
+ #
30
+ # @return [String]
31
+ #
32
+ def camelize(string)
33
+ string
34
+ .to_s
35
+ .split("_")
36
+ .map(&:capitalize)
37
+ .join
38
+ end
39
+
40
+ #
41
+ # Truncate the given string to a certain number of characters.
42
+ #
43
+ # @param [String] string
44
+ # the string to truncate
45
+ # @param [Hash] options
46
+ # the list of options (such as +length+)
47
+ #
48
+ def truncate(string, options = {})
49
+ length = options[:length] || 30
50
+
51
+ if string.length > length
52
+ string[0..length - 3] + "..."
53
+ else
54
+ string
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module ChefSpec
2
+ VERSION = "9.3.4".freeze
3
+ end
@@ -0,0 +1,142 @@
1
+ require "chef_zero/server"
2
+
3
+ module ChefSpec
4
+ # Rather than create a ChefZero instance per test case, simply create one
5
+ # ChefZero instance and reset it for every test case.
6
+ class ZeroServer
7
+ class << self
8
+ extend Forwardable
9
+ def_delegators :instance, :setup!, :teardown!, :reset!, :upload_cookbooks!, :server, :load_data, :nuke!
10
+ end
11
+
12
+ include Singleton
13
+
14
+ attr_reader :server
15
+
16
+ # Create the ChefZero Server
17
+ def initialize
18
+ nuke!
19
+ end
20
+
21
+ #
22
+ # Start the ChefZero Server
23
+ #
24
+ def setup!
25
+ @server.start_background unless @server.running?
26
+ end
27
+
28
+ #
29
+ # Remove all the data we just loaded from the ChefZero server
30
+ #
31
+ def reset!
32
+ if RSpec.configuration.server_runner_clear_cookbooks
33
+ @server.clear_data
34
+ @cookbooks_uploaded = false
35
+ else
36
+ # If we don't want to do a full clear, iterate through each value that we
37
+ # set and manually remove it.
38
+ @data_loaded.each do |key, names|
39
+ if key == "data"
40
+ names.each { |n| @server.data_store.delete_dir(["organizations", "chef", key, n]) }
41
+ else
42
+ names.each { |n| @server.data_store.delete(["organizations", "chef", key, n]) }
43
+ end
44
+ end
45
+ end
46
+ @data_loaded = {}
47
+ end
48
+
49
+ #
50
+ # Really reset everything and reload the configuration
51
+ #
52
+ def nuke!
53
+ @server = ChefZero::Server.new(
54
+ # Set the log level from RSpec, defaulting to warn
55
+ log_level: RSpec.configuration.log_level || :warn,
56
+ port: RSpec.configuration.server_runner_port,
57
+
58
+ # Set the data store
59
+ data_store: data_store(RSpec.configuration.server_runner_data_store)
60
+ )
61
+ @cookbooks_uploaded = false
62
+ @data_loaded = {}
63
+ end
64
+
65
+ #
66
+ # Teardown the ChefZero Server
67
+ #
68
+ def teardown!
69
+ @server.stop if @server.running?
70
+ end
71
+
72
+ #
73
+ # Upload the cookbooks to the Chef Server.
74
+ #
75
+ def upload_cookbooks!
76
+ return if @cookbooks_uploaded
77
+
78
+ loader = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
79
+ loader.load_cookbooks
80
+ cookbook_uploader_for(loader).upload_cookbooks
81
+ @cookbooks_uploaded = true
82
+ end
83
+
84
+ #
85
+ # Load (and track) data sent to the server
86
+ #
87
+ # @param [String] name
88
+ # the name or id of the item to load
89
+ # @param [String, Symbol] key
90
+ # the key to load
91
+ # @param [Hash] data
92
+ # the data for the object, which will be converted to JSON and uploaded
93
+ # to the server
94
+ #
95
+ def load_data(name, key, data)
96
+ @data_loaded[key] ||= []
97
+ @data_loaded[key] << name
98
+ @server.load_data({ key => { name => data } })
99
+ end
100
+
101
+ private
102
+
103
+ #
104
+ # The uploader for the cookbooks.
105
+ #
106
+ # @param [Chef::CookbookLoader] loader
107
+ # the Chef cookbook loader
108
+ #
109
+ # @return [Chef::CookbookUploader]
110
+ #
111
+ def cookbook_uploader_for(loader)
112
+ Chef::CookbookUploader.new(loader.cookbooks)
113
+ end
114
+
115
+ #
116
+ # Generate the DataStore object to be passed in to the ChefZero::Server object
117
+ #
118
+ def data_store(option)
119
+ require "chef_zero/data_store/default_facade"
120
+
121
+ store = case option
122
+ when :in_memory
123
+ require "chef_zero/data_store/memory_store_v2"
124
+ ChefZero::DataStore::MemoryStoreV2.new
125
+ when :on_disk
126
+ require "tmpdir" unless defined?(Dir.mktmpdir)
127
+ require "chef_zero/data_store/raw_file_store"
128
+ ChefZero::DataStore::RawFileStore.new(Dir.mktmpdir)
129
+ else
130
+ raise ArgumentError, ":#{option} is not a valid server_runner_data_store option. Please use either :in_memory or :on_disk."
131
+ end
132
+
133
+ ChefZero::DataStore::DefaultFacade.new(store, "chef", true)
134
+ end
135
+ end
136
+ end
137
+
138
+ RSpec.configure do |config|
139
+ config.before(:suite) { ChefSpec::ZeroServer.setup! }
140
+ config.after(:each) { ChefSpec::ZeroServer.reset! }
141
+ config.after(:suite) { ChefSpec::ZeroServer.teardown! }
142
+ end
data/lib/chefspec.rb ADDED
@@ -0,0 +1,75 @@
1
+ require "rspec"
2
+
3
+ module ChefSpec
4
+ #
5
+ # Defines a new runner method on the Chef runner.
6
+ #
7
+ # @param [Symbol] resource_name
8
+ # the name of the resource to define a method
9
+ #
10
+ # @return [self]
11
+ #
12
+ def define_matcher(resource_name)
13
+ matchers[resource_name.to_sym] = Proc.new do |identity|
14
+ find_resource(resource_name, identity)
15
+ end
16
+
17
+ self
18
+ end
19
+ module_function :define_matcher
20
+
21
+ #
22
+ # The source root of the ChefSpec gem. This is useful when requiring files
23
+ # that are relative to the root of the project.
24
+ #
25
+ # @return [Pathname]
26
+ #
27
+ def root
28
+ @root ||= Pathname.new(File.expand_path("..", __dir__))
29
+ end
30
+ module_function :root
31
+
32
+ protected
33
+
34
+ #
35
+ # The list of custom defined matchers.
36
+ #
37
+ # @return [Hash<String, Proc>]
38
+ #
39
+ def matchers
40
+ @matchers ||= {}
41
+ end
42
+ module_function :matchers
43
+ end
44
+
45
+ require_relative "chefspec/extensions"
46
+
47
+ require_relative "chefspec/mixins/normalize"
48
+
49
+ require_relative "chefspec/stubs/command_registry"
50
+ require_relative "chefspec/stubs/command_stub"
51
+ require_relative "chefspec/stubs/data_bag_item_registry"
52
+ require_relative "chefspec/stubs/data_bag_item_stub"
53
+ require_relative "chefspec/stubs/data_bag_registry"
54
+ require_relative "chefspec/stubs/data_bag_stub"
55
+ require_relative "chefspec/stubs/registry"
56
+ require_relative "chefspec/stubs/stub"
57
+ require_relative "chefspec/stubs/search_registry"
58
+ require_relative "chefspec/stubs/search_stub"
59
+
60
+ require_relative "chefspec/api"
61
+ require_relative "chefspec/cacher"
62
+ require_relative "chefspec/coverage"
63
+ require_relative "chefspec/errors"
64
+ require_relative "chefspec/expect_exception"
65
+ require_relative "chefspec/formatter"
66
+ require_relative "chefspec/matchers"
67
+ require_relative "chefspec/renderer"
68
+ require_relative "chefspec/rspec"
69
+ require_relative "chefspec/server_runner"
70
+ require_relative "chefspec/solo_runner"
71
+ require_relative "chefspec/runner"
72
+ require_relative "chefspec/util"
73
+ require_relative "chefspec/version"
74
+
75
+ require_relative "chefspec/deprecations"
@@ -0,0 +1,12 @@
1
+ require "chefspec"
2
+ require "support/hash"
3
+
4
+ ChefSpec::Coverage.start! do
5
+ set_template "table.erb"
6
+ end
7
+
8
+ RSpec.configure do |config|
9
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
10
+ config.filter_run(focus: true)
11
+ config.run_all_when_everything_filtered = true
12
+ end
@@ -0,0 +1,35 @@
1
+ #
2
+ # An extension of a Hash that allows mash-style like lookups.
3
+ #
4
+ # @private
5
+ #
6
+ class Hash
7
+ # Like, seriously Windows?
8
+ undef_method(:timeout) if method_defined?(:timeout)
9
+
10
+ #
11
+ # Monkey-patch to allow mash-style look ups for tests
12
+ #
13
+ def method_missing(m, *args, &block)
14
+ if key?(m.to_sym)
15
+ self[m.to_sym]
16
+ elsif key?(m.to_s)
17
+ self[m.to_s]
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ #
24
+ # Monkey-patch to stdlib Hash to correspond to Mash-style lookup
25
+ #
26
+ # @see Hash#respond_to?
27
+ #
28
+ def respond_to?(m, include_private = false)
29
+ if key?(m.to_sym) || key?(m.to_s)
30
+ true
31
+ else
32
+ super
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,70 @@
1
+ require "spec_helper"
2
+ require "chefspec/cacher"
3
+
4
+ describe ChefSpec::Cacher do
5
+ let(:klass) do
6
+ Class.new(RSpec::Core::ExampleGroup) do
7
+ extend ChefSpec::Cacher
8
+
9
+ def self.metadata
10
+ { parent_example_group: { location: "spec" } }
11
+ end
12
+ end
13
+ end
14
+
15
+ let(:cache) { described_class.class_variable_get(:@@cache) }
16
+ let(:preserve_cache) { false }
17
+
18
+ before(:each) { described_class.class_variable_set(:@@cache, {}) unless preserve_cache }
19
+
20
+ describe "cached" do
21
+ it "lazily defines the results for the cache" do
22
+ klass.cached(:chef_run)
23
+ expect(klass).to be_method_defined(:chef_run)
24
+ end
25
+
26
+ it "adds the item to the cache when called" do
27
+ runner = double(:runner)
28
+ klass.cached(:chef_run) { runner }
29
+ klass.new.chef_run
30
+
31
+ expect(cache[Thread.current.object_id]).to have_key("spec.chef_run")
32
+ expect(cache[Thread.current.object_id]["spec.chef_run"]).to eq(runner)
33
+ end
34
+
35
+ context "when multithreaded environment" do
36
+ it "is thread safe" do
37
+ (1..2).each do |n|
38
+ Thread.new do
39
+ klass.cached(:chef_run) { n }
40
+ expect(klass.new.chef_run).to eq(n)
41
+ end.join
42
+ end
43
+ end
44
+ end
45
+
46
+ context "when example groups are defined by looping" do
47
+ let(:preserve_cache) { true }
48
+
49
+ %w{first second third}.each do |iteration|
50
+ context "on the #{iteration} iteration" do
51
+ context "in caching context" do
52
+ cached(:cached_iteration) { iteration }
53
+ it "caches the iteration for this context" do
54
+ expect(cached_iteration).to eq iteration
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "cached!" do
63
+ it "loads the value at runtime" do
64
+ expect(klass).to receive(:cached).with(:chef_run).once
65
+ expect(klass).to receive(:before).once
66
+
67
+ klass.cached!(:chef_run) {}
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,60 @@
1
+ require "spec_helper"
2
+
3
+ # Note: These specs don't use Berkshelf code directly as this project doesn't
4
+ # have a direct dependency on Berkshelf and loading it would impact the
5
+ # perfance of these specs. While not ideal, the test doubles provide enough of
6
+ # a standin for Berkshelf to exercise the `#matches?` behavior.
7
+ describe ChefSpec::Coverage::BerkshelfFilter do
8
+ let(:dependencies) do
9
+ [double("Berkshelf::Dependency", metadata?: true, name: "cookbookery")]
10
+ end
11
+ let(:berksfile) { double("Berkshelf::Berksfile", dependencies: dependencies) }
12
+ let(:resource) { Chef::Resource.new("theone") }
13
+ subject { described_class.new(berksfile) }
14
+
15
+ describe "#matches?" do
16
+ it "returns truthy if resource source_line is nil" do
17
+ expect(subject.matches?(resource)).to be_truthy
18
+ end
19
+
20
+ context "when resource#source_line is under target cookbook" do
21
+ it "normal unix path returns truthy" do
22
+ resource.source_line =
23
+ "/path/to/cookbooks/nope/recipes/default.rb:22"
24
+ expect(subject.matches?(resource)).to be_truthy
25
+ end
26
+
27
+ it "normal windows path returns truthy" do
28
+ resource.source_line =
29
+ 'C:\\path\\to\\cookbooks\\nope\\recipes\\default.rb:22'
30
+ expect(subject.matches?(resource)).to be_truthy
31
+ end
32
+
33
+ it "mixed windows path returns truthy" do
34
+ resource.source_line =
35
+ 'C:\\path\\to\\cookbooks/nope/recipes/default.rb:22'
36
+ expect(subject.matches?(resource)).to be_truthy
37
+ end
38
+ end
39
+
40
+ context "when resource#source_line is not under target cookbook" do
41
+ it "normal unix path returns falsey" do
42
+ resource.source_line =
43
+ "/path/to/cookbooks/cookbookery/recipes/default.rb:22"
44
+ expect(subject.matches?(resource)).to be_falsey
45
+ end
46
+
47
+ it "normal windows path returns falsey" do
48
+ resource.source_line =
49
+ 'C:\\path\\to\\cookbooks\\cookbookery\\recipes\\default.rb:22'
50
+ expect(subject.matches?(resource)).to be_falsey
51
+ end
52
+
53
+ it "mixed windows path returns falsey" do
54
+ resource.source_line =
55
+ 'C:\\path\\to\\cookbooks/cookbookery/recipes/default.rb:22'
56
+ expect(subject.matches?(resource)).to be_falsey
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe ChefSpec::Runner do
4
+ before do
5
+ allow_any_instance_of(ChefSpec::SoloRunner)
6
+ .to receive(:dry_run?)
7
+ .and_return(true)
8
+ allow(ChefSpec::Runner).to receive(:deprecated)
9
+ end
10
+
11
+ describe "#define_runner_method" do
12
+ before do
13
+ allow(ChefSpec).to receive(:define_matcher)
14
+ end
15
+
16
+ it "prints a deprecation" do
17
+ expect(ChefSpec::Runner).to receive(:deprecated)
18
+ .with("`ChefSpec::Runner.define_runner_method' is deprecated."\
19
+ " It is being used in the my_custom_resource resource matcher." \
20
+ " Please use `ChefSpec.define_matcher' instead.")
21
+ ChefSpec::Runner.define_runner_method(:my_custom_resource)
22
+ end
23
+
24
+ it "calls ChefSpec#define_matcher" do
25
+ expect(ChefSpec).to receive(:define_matcher).with(:my_custom_resource).once
26
+ ChefSpec::Runner.define_runner_method(:my_custom_resource)
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ describe ChefSpec::Server do
33
+ before do
34
+ allow(ChefSpec::Server).to receive(:deprecated)
35
+ end
36
+
37
+ it "prints a deprecation for any method called" do
38
+ expect(ChefSpec::Server).to receive(:deprecated)
39
+ .with("`ChefSpec::Server.any_method' is deprecated. There is no longer" \
40
+ " a global Chef Server instance. Please use a ChefSpec::SoloRunner" \
41
+ " instead. More documentation can be found in the ChefSpec README.")
42
+ expect {
43
+ ChefSpec::Server.any_method
44
+ }.to raise_error(ChefSpec::Error::NoConversionError)
45
+ end
46
+
47
+ it "raises non-conversion error for any method called" do
48
+ expect { ChefSpec::Server.any_method }
49
+ .to raise_error(ChefSpec::Error::NoConversionError)
50
+ end
51
+
52
+ end
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ module ChefSpec::Error
4
+ describe CommandNotStubbed do
5
+ let(:instance) { described_class.new(args: ["cat"]) }
6
+
7
+ it "raises an exception with the correct message" do
8
+ instance
9
+ expect { raise instance }.to( raise_error { |error|
10
+ expect(error).to be_a(described_class)
11
+ expect(error.message).to eq <<-EOH.gsub(/^ {10}/, "")
12
+ Executing a real command is disabled. Unregistered command:
13
+
14
+ command("cat")
15
+
16
+ You can stub this command with:
17
+
18
+ stub_command("cat").and_return(...)
19
+ EOH
20
+ })
21
+ end
22
+ end
23
+
24
+ describe CookbookPathNotFound do
25
+ let(:instance) { described_class.new }
26
+
27
+ it "raises an exception with the correct message" do
28
+ expect { raise instance }.to(raise_error { |error|
29
+ expect(error).to be_a(described_class)
30
+ expect(error.message).to eq <<-EOH.gsub(/^ {10}/, "")
31
+ I could not find or infer a cookbook_path from your current working directory.
32
+ Please make sure you put your specs (tests) under a directory named 'spec' or
33
+ manually set the cookbook path in the RSpec configuration.
34
+ EOH
35
+ })
36
+ end
37
+ end
38
+
39
+ describe GemLoadError do
40
+ let(:instance) { described_class.new(gem: "bacon", name: "bacon") }
41
+
42
+ it "raises an exception with the correct message" do
43
+ expect { raise instance }.to( raise_error { |error|
44
+ expect(error).to be_a(described_class)
45
+ expect(error.message).to eq <<-EOH.gsub(/^ {10}/, "")
46
+ I could not load the 'bacon' gem! You must have the gem installed
47
+ on your local system before you can use the bacon plugin.
48
+ You can install bacon by running:
49
+
50
+ gem install bacon
51
+
52
+ or add bacon to your Gemfile and run the `bundle` command to install.
53
+ EOH
54
+ })
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ describe ChefSpec::ExpectException do
4
+ context "when there have been no `raise_error` matchers" do
5
+ subject { described_class.new(Exception) }
6
+
7
+ it "does not match" do
8
+ allow(RSpec::Matchers::BuiltIn::RaiseError).to receive(:last_run).and_return(nil)
9
+ expect(subject.expected?).to be_falsy
10
+ end
11
+ end
12
+
13
+ context "when the last error does not match the expected type" do
14
+ subject { described_class.new(RuntimeError) }
15
+
16
+ it "does not match" do
17
+ last_error = double("last error", last_error_for_chefspec: ArgumentError)
18
+ allow(RSpec::Matchers::BuiltIn::RaiseError).to receive(:last_run).and_return(last_error)
19
+ expect(subject.expected?).to be_falsy
20
+ end
21
+ end
22
+
23
+ context "when the last error matches the expected type" do
24
+ subject { described_class.new(RuntimeError) }
25
+
26
+ it "does not match" do
27
+ last_error = double("last error", last_error_for_chefspec: RuntimeError)
28
+ allow(RSpec::Matchers::BuiltIn::RaiseError).to receive(:last_run).and_return(last_error)
29
+ expect(subject.expected?).to be_truthy
30
+ end
31
+ end
32
+ end