spec/fbspec.rb (120 lines of code) (raw):
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
#
# Copyright (c) 2016-present, Facebook, Inc.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'chefspec'
require 'chefspec/lib/chefspec/matchers/render_file_matcher.rb'
$VERBOSE = nil
module FB
class Spec
def self.fbspec_init(cookbook_path, platforms)
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end
config.mock_with :rspec do |c|
c.syntax = [:should, :expect]
end
config.cookbook_path = cookbook_path
end
FB::Spec.configure do |config|
config.default_platforms = platforms['default']
config.extra_platforms = platforms['extra']
config.all_platforms = platforms['default'].merge(platforms['extra'])
end
end
class << self
attr_accessor :configuration
end
def self.configure
self.configuration ||= Configuration.new
yield(configuration)
end
class Configuration
attr_accessor :default_platforms
attr_accessor :extra_platforms
attr_accessor :all_platforms
def initialize
@default_platforms = {}
@extra_platforms = {}
@all_platforms = {}
end
end
class Testcase
include RSpec::Matchers
def initialize(config)
@config = config
end
# Local sites should monkeypatch this method if necessary
def chef_run_block_extras(_node); end
def chef_run(**extra_args)
extra_args[:step_into] ||= []
extra_args[:step_into] << 'whyrun_safe_ruby_block'
extra_args[:step_into].uniq!
runner_args = {
:platform => @config['platform'],
:version => @config['version'],
:os_name => 'xxxx',
}.merge(extra_args)
ChefSpec::SoloRunner.new(runner_args) do |node|
chef_run_block_extras(node)
yield(node) if block_given?
end
end
def fixture_path(path, name)
File.join(
File.dirname(caller(2..2).first.split(':').first),
'fixtures', path, name
)
end
def platform
@config[:os_name]
end
def fixture(name)
# look in fb_cookbooks/spec/fixtures/centos6/
profile_path = fixture_path(
self.platform.to_s, name
)
# look in fb_cookbook/spec/fixtures/default/ (fallback)
default_path = fixture_path('default', name)
path = File.exist?(profile_path) ? profile_path : default_path
begin
File.read(path)
rescue StandardError
puts "Fixture #{name} not found " +
"(tried: #{profile_path}, #{default_path})"
raise
end
end
end
class Runner
def initialize(config, &block)
RSpec.describe config[:described_recipe] do
config[:supported].each do |platform|
FB::Spec.configuration.all_platforms[platform].each do |os|
os[:os_name] = platform
tags = config[:supported].map do |x|
{ x => false }
end.reduce({}, :merge)
tags[platform] = true
config[:xxx] = 1
context "#{platform} (#{os['version']})", tags do
instance_exec(
FB::Spec::Testcase.new(os),
&block
)
end
end
end
end
end
end
end
end
def recipe(name, options = [], &block)
if options.include?(:supported)
supported = [*options[:supported]].map(&:to_sym)
else
supported = FB::Spec.configuration.default_platforms.keys
end
if options.include?(:unsupported)
supported -= [*options[:unsupported]].map(&:to_sym)
end
FB::Spec::Runner.new(
{ :supported => supported, :described_recipe => name },
&block
)
end