diff options
author | John Keiser <jkeiser@opscode.com> | 2014-04-21 15:35:34 -0700 |
---|---|---|
committer | John Keiser <jkeiser@opscode.com> | 2014-04-21 15:35:34 -0700 |
commit | 16ee59c619a0f40f17b9c64a0e2be6a19140df9d (patch) | |
tree | e858cf9c92428c54d15e16d2e8136643bab2d797 | |
parent | 30a1b6b918902fa526ed77c185a2928cb2a3f640 (diff) | |
download | chef-zero-16ee59c619a0f40f17b9c64a0e2be6a19140df9d.tar.gz |
Add ability to run specs against existing Chef::ChefFS
-rw-r--r-- | lib/chef_zero/data_store/memory_store.rb | 165 | ||||
-rw-r--r-- | lib/chef_zero/data_store/memory_store_v2.rb | 185 | ||||
-rw-r--r-- | lib/chef_zero/data_store/v1_to_v2_adapter.rb | 133 | ||||
-rw-r--r-- | lib/chef_zero/data_store/v2_to_v1_adapter.rb | 107 | ||||
-rw-r--r-- | spec/run.rb | 28 |
5 files changed, 409 insertions, 209 deletions
diff --git a/lib/chef_zero/data_store/memory_store.rb b/lib/chef_zero/data_store/memory_store.rb index aba052d..eac2534 100644 --- a/lib/chef_zero/data_store/memory_store.rb +++ b/lib/chef_zero/data_store/memory_store.rb @@ -16,172 +16,17 @@ # limitations under the License. # -require 'chef_zero/data_store/data_already_exists_error' -require 'chef_zero/data_store/data_not_found_error' -require 'chef_zero/data_store/interface_v2' +require 'chef_zero/data_store/v2_to_v1_adapter' +require 'chef_zero/data_store/memory_store_v2' module ChefZero module DataStore - class MemoryStore < ChefZero::DataStore::InterfaceV2 + class MemoryStore < ChefZero::DataStore::V2ToV1Adapter def initialize + super + @real_store = ChefZero::DataStore::MemoryStoreV2.new clear end - - def interface_version - 2 - end - - def clear - @data = {} - - create_dir([], 'organizations') - end - - def create_org - org = { - 'clients' => { - 'chef-validator' => '{ "validator": true }', - 'chef-webui' => '{ "admin": true }' - }, - 'cookbooks' => {}, - 'data' => {}, - 'environments' => { - '_default' => '{ "description": "The default Chef environment" }' - }, - 'file_store' => { - 'checksums' => {} - }, - 'nodes' => {}, - 'roles' => {}, - 'sandboxes' => {}, - 'users' => { - 'admin' => '{ "admin": "true" }' - } - } - end - - def create_dir(path, name, *options) - parent = _get(path, options.include?(:recursive)) - - if parent.has_key?(name) - if !options.include?(:recursive) - raise DataAlreadyExistsError.new(path + [name]) - end - else - _create_dir(path, parent, name) - end - end - - def create(path, name, data, *options) - if !data.is_a?(String) - raise "set only works with strings" - end - - parent = _get(path, options.include?(:create_dir)) - - if parent.has_key?(name) - raise DataAlreadyExistsError.new(path + [name]) - end - parent[name] = data - end - - def get(path, request=nil) - value = _get(path) - if value.is_a?(Hash) - raise "get() called on directory #{path.join('/')}" - end - value - end - - def set(path, data, *options) - if !data.is_a?(String) - raise "set only works with strings: #{path} = #{data.inspect}" - end - - # Get the parent - parent = _get(path[0..-2], options.include?(:create_dir)) - - if !options.include?(:create) && !parent[path[-1]] - raise DataNotFoundError.new(path) - end - parent[path[-1]] = data - end - - def delete(path) - parent = _get(path[0,path.length-1]) - if !parent.has_key?(path[-1]) - raise DataNotFoundError.new(path) - end - if !parent[path[-1]].is_a?(String) - raise "delete only works with strings: #{path}" - end - parent.delete(path[-1]) - end - - def delete_dir(path, *options) - parent = _get(path[0,path.length-1]) - if !parent.has_key?(path[-1]) - raise DataNotFoundError.new(path) - end - if !parent[path[-1]].is_a?(Hash) - raise "delete_dir only works with directories: #{path}" - end - parent.delete(path[-1]) - end - - def list(path) - dir = _get(path) - if !dir.is_a? Hash - raise "list only works with directories (#{path} = #{dir.class}" - end - dir.keys.sort - end - - def exists?(path) - begin - get(path) - return true - rescue DataNotFoundError - return false - end - end - - def exists_dir?(path) - begin - dir = _get(path) - if !dir.is_a? Hash - raise "exists_dir? only works with directories (#{path} = #{dir.class}" - end - return true - rescue DataNotFoundError - return false - end - end - - private - - def _get(path, create_dir=false) - value = @data - path.each_with_index do |path_part, index| - if !value.has_key?(path_part) - if create_dir - _create_dir(path[0,index], value, path_part) - else - raise DataNotFoundError.new(path[0,index+1]) - end - end - value = value[path_part] - end - value - end - - def _create_dir(parent_path, parent, name) - if parent_path == [ 'organizations' ] - parent[name] = create_org - else - parent[name] = {} - end - end end end end diff --git a/lib/chef_zero/data_store/memory_store_v2.rb b/lib/chef_zero/data_store/memory_store_v2.rb new file mode 100644 index 0000000..97402c1 --- /dev/null +++ b/lib/chef_zero/data_store/memory_store_v2.rb @@ -0,0 +1,185 @@ +# +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2013 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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 'chef_zero/data_store/data_already_exists_error' +require 'chef_zero/data_store/data_not_found_error' +require 'chef_zero/data_store/interface_v2' + +module ChefZero + module DataStore + class MemoryStoreV2 < ChefZero::DataStore::InterfaceV2 + def initialize + clear + end + + attr_reader :data + + def clear + @data = {} + + create_dir([], 'organizations') + end + + def create_org + org = { + 'clients' => { + 'chef-validator' => '{ "validator": true }', + 'chef-webui' => '{ "admin": true }' + }, + 'cookbooks' => {}, + 'data' => {}, + 'environments' => { + '_default' => '{ "description": "The default Chef environment" }' + }, + 'file_store' => { + 'checksums' => {} + }, + 'nodes' => {}, + 'roles' => {}, + 'sandboxes' => {}, + 'users' => { + 'admin' => '{ "admin": "true" }' + } + } + end + + def create_dir(path, name, *options) + parent = _get(path, options.include?(:recursive)) + + if parent.has_key?(name) + if !options.include?(:recursive) + raise DataAlreadyExistsError.new(path + [name]) + end + else + _create_dir(path, parent, name) + end + end + + def create(path, name, data, *options) + if !data.is_a?(String) + raise "set only works with strings" + end + + parent = _get(path, options.include?(:create_dir)) + + if parent.has_key?(name) + raise DataAlreadyExistsError.new(path + [name]) + end + parent[name] = data + end + + def get(path, request=nil) + value = _get(path) + if value.is_a?(Hash) + raise "get() called on directory #{path.join('/')}" + end + value + end + + def set(path, data, *options) + if !data.is_a?(String) + raise "set only works with strings: #{path} = #{data.inspect}" + end + + # Get the parent + parent = _get(path[0..-2], options.include?(:create_dir)) + + if !options.include?(:create) && !parent[path[-1]] + raise DataNotFoundError.new(path) + end + parent[path[-1]] = data + end + + def delete(path) + parent = _get(path[0,path.length-1]) + if !parent.has_key?(path[-1]) + raise DataNotFoundError.new(path) + end + if !parent[path[-1]].is_a?(String) + raise "delete only works with strings: #{path}" + end + parent.delete(path[-1]) + end + + def delete_dir(path, *options) + parent = _get(path[0,path.length-1]) + if !parent.has_key?(path[-1]) + raise DataNotFoundError.new(path) + end + if !parent[path[-1]].is_a?(Hash) + raise "delete_dir only works with directories: #{path}" + end + parent.delete(path[-1]) + end + + def list(path) + dir = _get(path) + if !dir.is_a? Hash + raise "list only works with directories (#{path} = #{dir.class}" + end + dir.keys.sort + end + + def exists?(path) + begin + get(path) + return true + rescue DataNotFoundError + return false + end + end + + def exists_dir?(path) + begin + dir = _get(path) + if !dir.is_a? Hash + raise "exists_dir? only works with directories (#{path} = #{dir.class}" + end + return true + rescue DataNotFoundError + return false + end + end + + private + + def _get(path, create_dir=false) + value = @data + path.each_with_index do |path_part, index| + if !value.has_key?(path_part) + if create_dir + _create_dir(path[0,index], value, path_part) + else + raise DataNotFoundError.new(path[0,index+1]) + end + end + value = value[path_part] + end + value + end + + def _create_dir(parent_path, parent, name) + if parent_path == [ 'organizations' ] + parent[name] = create_org + else + parent[name] = {} + end + end + end + end +end diff --git a/lib/chef_zero/data_store/v1_to_v2_adapter.rb b/lib/chef_zero/data_store/v1_to_v2_adapter.rb index aaa3b64..cdc3020 100644 --- a/lib/chef_zero/data_store/v1_to_v2_adapter.rb +++ b/lib/chef_zero/data_store/v1_to_v2_adapter.rb @@ -8,15 +8,19 @@ module ChefZero @single_org = single_org # Handle defaults per V2 specification @defaults = { - 'clients' => { - 'chef-validator' => '{ "validator": true }', - 'chef-webui' => '{ "admin": true }' - }, - 'environments' => { - '_default' => '{ "description": "The default Chef environment" }' - }, - 'users' => { - 'admin' => '{ "admin": "true" }' + 'organizations' => { + single_org => { + 'clients' => { + 'chef-validator' => '{ "validator": true }', + 'chef-webui' => '{ "admin": true }' + }, + 'environments' => { + '_default' => '{ "description": "The default Chef environment" }' + }, + 'users' => { + 'admin' => '{ "admin": "true" }' + } + } } } end @@ -30,70 +34,139 @@ module ChefZero def create_dir(path, name, *options) return nil if skip_organizations(path, name) - real_store.create_dir(path[2..-1], name, *options) + if using_default?(path, name) + raise DataAlreadyExistsError.new(path + [name]) + end + fix_exceptions do + real_store.create_dir(path[2..-1], name, *options) + end end def create(path, name, data, *options) return nil if skip_organizations(path, name) + if using_default?(path, name) + raise DataAlreadyExistsError.new(path + [name]) + end remove_default(path, name) - real_store.create(path[2..-1], name, data, *options) + + fix_exceptions do + real_store.create(path[2..-1], name, data, *options) + end end def get(path, request=nil) return nil if skip_organizations(path) - begin - real_store.get(path[2..-1], request) - rescue DataNotFoundError - if path.size == 2 && @defaults[path[0]] && @defaults[path[0]][path[1]] - @defaults[path[0]][path[1]] - else - raise + if using_default?(path) + get_default(path) + else + fix_exceptions do + real_store.get(path[2..-1], request) end end end def set(path, data, *options) return nil if skip_organizations(path) - remove_default(path, name) - real_store.set(path[2..-1], data, *options) + remove_default(path) + fix_exceptions do + real_store.set(path[2..-1], data, *options) + end end def delete(path) return nil if skip_organizations(path) remove_default(path) - real_store.delete(path[2..-1]) + fix_exceptions do + real_store.delete(path[2..-1]) + end end def delete_dir(path, *options) return nil if skip_organizations(path) - real_store.delete_dir(path[2..-1], *options) + fix_exceptions do + real_store.delete_dir(path[2..-1], *options) + end end def list(path) return nil if skip_organizations(path) - real_store.list(path[2..-1]) + fix_exceptions do + result = real_store.list(path[2..-1]) + if using_default?(path) + result ||= [] + get_default(path).keys.each do |value| + result << value if !result.include?(value) + end + end + result + end end def exists?(path) return nil if skip_organizations(path) - if path.size == 2 && @defaults[path[0]] && @defaults[path[0]][path[1]] - @defaults[path[0]][path[1]] + if using_default?(path) + true else - real_store.exists?(path[2..-1]) + fix_exceptions do + real_store.exists?(path[2..-1]) + end end end def exists_dir?(path) return nil if skip_organizations(path) - real_store.exists_dir?(path[2..-1]) + if using_default?(path) + true + else + fix_exceptions do + real_store.exists_dir?(path[2..-1]) + end + end end private - def remove_default(path, name = nil) + def using_default?(path, name = nil) path = path + [name] if name - if path.size == 2 && @defaults[path[0]] && @defaults[path[0]][path[1]] - @defaults[path[0]].delete(path[1]) + result = @defaults + path.each do |part| + return false if !result.has_key?(part) + result = result[part] + end + !result.nil? + end + + def get_default(path, name = nil) + path = path + [name] if name + result = @defaults + path.each do |part| + return nil if !result.has_key?(part) + result = result[part] + end + result + end + + def remove_default(path, name = nil) + dir = name ? path[0..-2] : path + default = @defaults + dir.each do |part| + return if !default.has_key?(part) + default = default[part] + end + + name = name || path.last + if name + default.delete(name) + end + end + + def fix_exceptions + begin + yield + rescue DataAlreadyExistsError => e + raise DataAlreadyExistsError.new([ 'organizations', single_org ] + e.path, e) + rescue DataNotFoundError => e + raise DataNotFoundError.new([ 'organizations', single_org ] + e.path, e) end end diff --git a/lib/chef_zero/data_store/v2_to_v1_adapter.rb b/lib/chef_zero/data_store/v2_to_v1_adapter.rb new file mode 100644 index 0000000..6bc72c0 --- /dev/null +++ b/lib/chef_zero/data_store/v2_to_v1_adapter.rb @@ -0,0 +1,107 @@ +# +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2014 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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 'chef_zero/data_store/interface_v1' + +module ChefZero + module DataStore + class V2ToV1Adapter < ChefZero::DataStore::InterfaceV1 + def initialize + @single_org = 'chef' + end + + attr_reader :real_store + attr_reader :single_org + + def clear + real_store.clear + real_store.create_dir([ 'organizations' ], single_org) + end + + def create_dir(path, name, *options) + fix_exceptions do + real_store.create_dir(fix_path(path), name, *options) + end + end + + def create(path, name, data, *options) + fix_exceptions do + real_store.create(fix_path(path), name, data, *options) + end + end + + def get(path, request=nil) + fix_exceptions do + real_store.get(fix_path(path), request) + end + end + + def set(path, data, *options) + fix_exceptions do + real_store.set(fix_path(path), data, *options) + end + end + + def delete(path) + fix_exceptions do + real_store.delete(fix_path(path)) + end + end + + def delete_dir(path, *options) + fix_exceptions do + real_store.delete_dir(fix_path(path), *options) + end + end + + def list(path) + fix_exceptions do + real_store.list(fix_path(path)) + end + end + + def exists?(path) + fix_exceptions do + real_store.exists?(fix_path(path)) + end + end + + def exists_dir?(path) + fix_exceptions do + real_store.exists_dir?(fix_path(path)) + end + end + + protected + + def fix_exceptions + begin + yield + rescue DataAlreadyExistsError => e + raise DataAlreadyExistsError.new(e.path[2..-1], e) + rescue DataNotFoundError => e + raise DataNotFoundError.new(e.path[2..-1], e) + end + end + + def fix_path(path) + [ 'organizations', single_org ] + path + end + end + end +end diff --git a/spec/run.rb b/spec/run.rb index d538c2f..768e0a0 100644 --- a/spec/run.rb +++ b/spec/run.rb @@ -8,12 +8,12 @@ require 'rspec/core' tmpdir = nil def start_server(chef_repo_path) - # Create the chef repo - Dir.mkdir(chef_repo_path) + Dir.mkdir(chef_repo_path) if !File.exists?(chef_repo_path) + # 11.6 and below had a bug where it couldn't create the repo children automatically if Chef::VERSION.to_f < 11.8 %w(clients cookbooks data_bags environments nodes roles users).each do |child| - Dir.mkdir("#{chef_repo_path}/#{child}") + Dir.mkdir("#{chef_repo_path}/#{child}") if !File.exists?("#{chef_repo_path}/#{child}") end end @@ -22,7 +22,7 @@ def start_server(chef_repo_path) Chef::Config.chef_repo_path = chef_repo_path chef_fs = Chef::ChefFS::Config.new.local_fs data_store = Chef::ChefFS::ChefFSDataStore.new(chef_fs) - server = ChefZero::Server.new(:port => 8889, :data_store => data_store) + server = ChefZero::Server.new(:port => 8889, :data_store => data_store)#, :log_level => :debug) server.start_background server end @@ -38,21 +38,9 @@ begin # Create chef repository tmpdir = Dir.mktmpdir chef_repo_path = "#{tmpdir}/repo" - server = start_server(chef_repo_path) - - # Delete everything before each test - RSpec.configure do |config| - config.before(:each) do - # Stop the old server - if server - server.stop - server = nil - FileUtils.rm_rf(chef_repo_path) - end - server = start_server(chef_repo_path) - end - end + # Capture setup data into master_chef_repo_path + server = start_server(chef_repo_path) else server = ChefZero::Server.new(:port => 8889) @@ -63,6 +51,8 @@ begin require 'pedant' require 'pedant/opensource' + #Pedant::Config.rerun = true + Pedant.config.suite = 'api' Pedant.config[:config_file] = 'spec/support/pedant.rb' Pedant.setup([ @@ -85,7 +75,7 @@ begin end end - server.stop + server.stop if server.running? ensure FileUtils.remove_entry_secure(tmpdir) if tmpdir end |