summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2014-04-21 15:35:34 -0700
committerJohn Keiser <jkeiser@opscode.com>2014-04-21 15:35:34 -0700
commit16ee59c619a0f40f17b9c64a0e2be6a19140df9d (patch)
treee858cf9c92428c54d15e16d2e8136643bab2d797
parent30a1b6b918902fa526ed77c185a2928cb2a3f640 (diff)
downloadchef-zero-16ee59c619a0f40f17b9c64a0e2be6a19140df9d.tar.gz
Add ability to run specs against existing Chef::ChefFS
-rw-r--r--lib/chef_zero/data_store/memory_store.rb165
-rw-r--r--lib/chef_zero/data_store/memory_store_v2.rb185
-rw-r--r--lib/chef_zero/data_store/v1_to_v2_adapter.rb133
-rw-r--r--lib/chef_zero/data_store/v2_to_v1_adapter.rb107
-rw-r--r--spec/run.rb28
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