diff options
author | Ho-Sheng Hsiao <hosh@opscode.com> | 2013-03-04 19:15:44 -0800 |
---|---|---|
committer | John Keiser <jkeiser@opscode.com> | 2013-06-07 13:12:28 -0700 |
commit | 01120b3a61cb3d110ec28c022693730d78c330ca (patch) | |
tree | 66ac79690a5f38fc579d0a02e85d478e02579bb3 /spec/integration | |
parent | 47cf3e01ea6fb581f0d8c2d9b37a66c02690d92a (diff) | |
download | chef-01120b3a61cb3d110ec28c022693730d78c330ca.tar.gz |
[SPEC] Refactored diff, upload, and download spec to have explicit inputs
Diffstat (limited to 'spec/integration')
-rw-r--r-- | spec/integration/knife/diff_spec.rb | 649 | ||||
-rw-r--r-- | spec/integration/knife/download_spec.rb | 961 | ||||
-rw-r--r-- | spec/integration/knife/upload_spec.rb | 1155 |
3 files changed, 2049 insertions, 716 deletions
diff --git a/spec/integration/knife/diff_spec.rb b/spec/integration/knife/diff_spec.rb index 5391ca5522..573160ba3a 100644 --- a/spec/integration/knife/diff_spec.rb +++ b/spec/integration/knife/diff_spec.rb @@ -5,46 +5,97 @@ describe 'knife diff' do extend IntegrationSupport include KnifeSupport - when_the_chef_server "has one of each thing" do - one_of_each_resource_in_chef_server - - when_the_repository 'has only top-level directories' do - directory 'clients' - directory 'cookbooks' - directory 'data_bags' - directory 'environments' - directory 'nodes' - directory 'roles' - directory 'users' - - without_versioned_cookbooks do - it 'knife diff reports everything as deleted' do - knife('diff --name-status /').should_succeed <<EOM -D\t/cookbooks/x -D\t/data_bags/x -D\t/environments/_default.json -D\t/environments/x.json -D\t/roles/x.json -EOM - end - end # without versioned cookbooks + context 'without versioned cookbooks' do + when_the_chef_server "has one of each thing" do + client 'x', '{}' + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } + data_bag 'x', { 'y' => '{}' } + environment 'x', '{}' + node 'x', '{}' + role 'x', '{}' + user 'x', '{}' + + when_the_repository 'has only top-level directories' do + directory 'clients' + directory 'cookbooks' + directory 'data_bags' + directory 'environments' + directory 'nodes' + directory 'roles' + directory 'users' - with_versioned_cookbooks do it 'knife diff reports everything as deleted' do knife('diff --name-status /').should_succeed <<EOM -D\t/cookbooks/x-1.0.0 +D\t/cookbooks/x D\t/data_bags/x D\t/environments/_default.json D\t/environments/x.json D\t/roles/x.json EOM - end - end # with versioned cookbooks + end end - when_the_repository 'has an identical copy of each resource' do - with_all_types_of_repository_layouts do - one_of_each_resource_in_repository + when_the_repository 'has an identical copy of each thing' do + file 'clients/x.json', <<EOM +{} +EOM + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/y.json', <<EOM +{ + "id": "y" +} +EOM + file 'environments/_default.json', <<EOM +{ + "name": "_default", + "description": "The default Chef environment", + "cookbook_versions": { + }, + "json_class": "Chef::Environment", + "chef_type": "environment", + "default_attributes": { + }, + "override_attributes": { + } +} +EOM + file 'environments/x.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "x", + "override_attributes": { + } +} +EOM + file 'nodes/x.json', <<EOM +{} +EOM + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + file 'users/x.json', <<EOM +{} +EOM it 'knife diff reports no differences' do knife('diff /').should_succeed '' @@ -57,41 +108,33 @@ EOM it 'knife diff /environments/*.txt reports an error' do knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n" end - end # with all types of repository layouts - end # when the repository has an identical copy of each resource - when_the_repository 'has a different role file' do - with_all_types_of_repository_layouts do - one_of_each_resource_in_repository - file 'roles/x.json', <<EOM + context 'except the role file' do + file 'roles/x.json', <<EOM { "foo": "bar" } EOM - it 'knife diff reports the role as different' do - knife('diff --name-status /').should_succeed <<EOM + it 'knife diff reports the role as different' do + knife('diff --name-status /').should_succeed <<EOM M\t/roles/x.json EOM + end end - end # with all types of repository layouts - end # when the repository has a different role file - - when_the_repository 'has resources not present in the server' do - file 'clients/y.json', {} - file 'data_bags/x/z.json', {} - file 'data_bags/y/zz.json', {} - file 'environments/y.json', {} - file 'nodes/y.json', {} - file 'roles/y.json', {} - file 'users/y.json', {} - - without_versioned_cookbooks do - one_of_each_resource_in_repository - file 'cookbooks/x/blah.rb', '' - file 'cookbooks/y/metadata.rb', 'version "1.0.0"' - it 'knife diff reports the new files as added' do - knife('diff --name-status /').should_succeed <<EOM + context 'as well as one extra copy of each thing' do + file 'clients/y.json', {} + file 'cookbooks/x/blah.rb', '' + file 'cookbooks/y/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/z.json', {} + file 'data_bags/y/zz.json', {} + file 'environments/y.json', {} + file 'nodes/y.json', {} + file 'roles/y.json', {} + file 'users/y.json', {} + + it 'knife diff reports the new files as added' do + knife('diff --name-status /').should_succeed <<EOM A\t/cookbooks/x/blah.rb A\t/cookbooks/y A\t/data_bags/x/z.json @@ -99,89 +142,45 @@ A\t/data_bags/y A\t/environments/y.json A\t/roles/y.json EOM - end - - context 'when cwd is the data_bags directory' do - cwd 'data_bags' - it 'knife diff reports different data bags' do - knife('diff --name-status').should_succeed <<EOM -A\tx/z.json -A\ty -EOM - end - it 'knife diff * reports different data bags' do - knife('diff --name-status *').should_succeed <<EOM -A\tx/z.json -A\ty -EOM end - end # when cwd is the data_bags directory - end # without versioned cookbooks - - with_versioned_cookbooks do - one_of_each_resource_in_repository - file 'cookbooks/x-1.0.0/blah.rb', '' - file 'cookbooks/y-1.0.0/metadata.rb', ['name "y"', 'version "1.0.0"'].join("\n") - it 'knife diff reports the new files as added' do - knife('diff --name-status /').should_succeed <<EOM -A\t/cookbooks/x-1.0.0/blah.rb -A\t/cookbooks/y-1.0.0 -A\t/data_bags/x/z.json -A\t/data_bags/y -A\t/environments/y.json -A\t/roles/y.json -EOM - end - - context 'when cwd is the data_bags directory' do - cwd 'data_bags' - it 'knife diff reports different data bags' do - knife('diff --name-status').should_succeed <<EOM + context 'when cwd is the data_bags directory' do + cwd 'data_bags' + it 'knife diff reports different data bags' do + knife('diff --name-status').should_succeed <<EOM A\tx/z.json A\ty EOM end - it 'knife diff * reports different data bags' do - knife('diff --name-status *').should_succeed <<EOM + it 'knife diff * reports different data bags' do + knife('diff --name-status *').should_succeed <<EOM A\tx/z.json A\ty EOM + end end - end # when cwd is the data_bags directory - end # with versioned cookbooks - end # when the repository has resources not present in the server + end + end - when_the_repository 'is empty' do - it 'knife diff reports everything as deleted' do - knife('diff --name-status /').should_succeed <<EOM + when_the_repository 'is empty' do + it 'knife diff reports everything as deleted' do + knife('diff --name-status /').should_succeed <<EOM D\t/cookbooks D\t/data_bags D\t/environments D\t/roles EOM - end - end - end - - when_the_repository 'has a cookbook' do - # TODO: make this DSL lazy-eval so we don't have to do stuff like this - def self.repository_has_a_cookbook - if metadata[:versioned_cookbooks] - file 'cookbooks/x-1.0.0/metadata.rb', ['name "x"', 'version "1.0.0"'] - file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', '' - else - file 'cookbooks/x/metadata.rb', ['name "x"', 'version "1.0.0"'] - file 'cookbooks/x/onlyin1.0.0.rb', '' + end end end - when_the_chef_server 'has a later version for the cookbook' do - cookbook 'x', '1.0.0', { 'metadata.rb' => ['name "x"', 'version "1.0.0"'].join("\n"), 'onlyin1.0.0.rb' => ''} - cookbook 'x', '1.0.1', { 'metadata.rb' => ['name "x"', 'version "1.0.1"'].join("\n"), 'onlyin1.0.1.rb' => '' } + when_the_repository 'has a cookbook' do + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x/onlyin1.0.0.rb', '' - without_versioned_cookbooks do - repository_has_a_cookbook + when_the_chef_server 'has a later version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } it 'knife diff /cookbooks/x shows differences' do knife('diff --name-status /cookbooks/x').should_succeed <<EOM @@ -197,87 +196,321 @@ M\t/cookbooks/x/metadata.rb A\t/cookbooks/x/onlyin1.0.0.rb EOM end - end # without versioned cookbooks + end - with_versioned_cookbooks do - repository_has_a_cookbook + when_the_chef_server 'has an earlier version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } + it 'knife diff /cookbooks/x shows no differences' do + knife('diff --name-status /cookbooks/x').should_succeed '' + end + end - it 'knife diff /cookbooks shows differences' do - knife('diff --name-status /cookbooks').should_succeed <<EOM -D\t/cookbooks/x-1.0.1 + when_the_chef_server 'has a later version for the cookbook, and no current version' do + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } + + it 'knife diff /cookbooks/x shows the differences' do + knife('diff --name-status /cookbooks/x').should_succeed <<EOM +M\t/cookbooks/x/metadata.rb +D\t/cookbooks/x/onlyin1.0.1.rb +A\t/cookbooks/x/onlyin1.0.0.rb EOM end + end - it 'knife diff --diff-filter=MAT does not show deleted files' do - # No difference - knife('diff --diff-filter=MAT --name-status /cookbooks').should_succeed '' + when_the_chef_server 'has an earlier version for the cookbook, and no current version' do + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } + + it 'knife diff /cookbooks/x shows the differences' do + knife('diff --name-status /cookbooks/x').should_succeed <<EOM +M\t/cookbooks/x/metadata.rb +D\t/cookbooks/x/onlyin0.9.9.rb +A\t/cookbooks/x/onlyin1.0.0.rb +EOM end - end # withversioned cookbooks - end # when the chef server has a later version for the cookbook + end + end - when_the_chef_server 'has an earlier version for the cookbook' do - cookbook 'x', '1.0.0', { 'metadata.rb' => ['name "x"', 'version "1.0.0"'].join("\n"), 'onlyin1.0.0.rb' => '' } - cookbook 'x', '0.9.9', { 'metadata.rb' => ['name "x"', 'version "0.9.9"'].join("\n"), 'onlyin0.9.9.rb' => '' } + context 'json diff tests' do + when_the_repository 'has an empty environment file' do + file 'environments/x.json', {} + when_the_chef_server 'has an empty environment' do + environment 'x', {} + it 'knife diff returns no differences' do + knife('diff /environments/x.json').should_succeed '' + end + end + when_the_chef_server 'has an environment with a different value' do + environment 'x', { 'description' => 'hi' } + it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do + knife('diff /environments/x.json').should_succeed(/ + { +- "name": "x", +- "description": "hi" +\+ "name": "x" + } +/) + end + end + end - without_versioned_cookbooks do - repository_has_a_cookbook - it 'knife diff /cookbooks/x shows no differences' do - knife('diff --name-status /cookbooks/x').should_succeed '' + when_the_repository 'has an environment file with a value in it' do + file 'environments/x.json', { 'description' => 'hi' } + when_the_chef_server 'has an environment with the same value' do + environment 'x', { 'description' => 'hi' } + it 'knife diff returns no differences' do + knife('diff /environments/x.json').should_succeed '' + end + end + when_the_chef_server 'has an environment with no value' do + environment 'x', {} + it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do + knife('diff /environments/x.json').should_succeed(/ + { +- "name": "x" +\+ "name": "x", +\+ "description": "hi" + } +/) + end + end + when_the_chef_server 'has an environment with a different value' do + environment 'x', { 'description' => 'lo' } + it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do + knife('diff /environments/x.json').should_succeed(/ + { + "name": "x", +- "description": "lo" +\+ "description": "hi" + } +/) + end end end + end - with_versioned_cookbooks do - repository_has_a_cookbook - it 'knife diff /cookbooks shows no differences' do - knife('diff --name-status /cookbooks').should_succeed <<EOM -D\t/cookbooks/x-0.9.9 -EOM + when_the_chef_server 'has an environment' do + environment 'x', {} + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife diff reports an error and does a textual diff' do + knife('diff /environments/x.json').should_succeed(/- "name": "x"/, :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n") end end end + end # without versioned cookbooks + + with_versioned_cookbooks do + when_the_chef_server "has one of each thing" do + client 'x', '{}' + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } + data_bag 'x', { 'y' => '{}' } + environment 'x', '{}' + node 'x', '{}' + role 'x', '{}' + user 'x', '{}' + + when_the_repository 'has only top-level directories' do + directory 'clients' + directory 'cookbooks' + directory 'data_bags' + directory 'environments' + directory 'nodes' + directory 'roles' + directory 'users' - when_the_chef_server 'has a later version for the cookbook, and no current version' do - cookbook 'x', '1.0.1', { 'metadata.rb' => ['name "x"', 'version "1.0.1"'].join("\n"), 'onlyin1.0.1.rb' => '' } + it 'knife diff reports everything as deleted' do + knife('diff --name-status /').should_succeed <<EOM +D\t/cookbooks/x-1.0.0 +D\t/data_bags/x +D\t/environments/_default.json +D\t/environments/x.json +D\t/roles/x.json +EOM + end + end - without_versioned_cookbooks do - repository_has_a_cookbook - it 'knife diff /cookbooks/x shows the differences' do - knife('diff --name-status /cookbooks/x').should_succeed <<EOM -M\t/cookbooks/x/metadata.rb -D\t/cookbooks/x/onlyin1.0.1.rb -A\t/cookbooks/x/onlyin1.0.0.rb + when_the_repository 'has an identical copy of each thing' do + file 'clients/x.json', <<EOM +{} +EOM + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/y.json', <<EOM +{ + "id": "y" +} +EOM + file 'environments/_default.json', <<EOM +{ + "name": "_default", + "description": "The default Chef environment", + "cookbook_versions": { + }, + "json_class": "Chef::Environment", + "chef_type": "environment", + "default_attributes": { + }, + "override_attributes": { + } +} +EOM + file 'environments/x.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "x", + "override_attributes": { + } +} +EOM + file 'nodes/x.json', <<EOM +{} +EOM + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + file 'users/x.json', <<EOM +{} +EOM + + it 'knife diff reports no differences' do + knife('diff /').should_succeed '' + end + + it 'knife diff /environments/nonexistent.json reports an error' do + knife('diff /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n" + end + + it 'knife diff /environments/*.txt reports an error' do + knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n" + end + + context 'except the role file' do + file 'roles/x.json', <<EOM +{ + "foo": "bar" +} +EOM + it 'knife diff reports the role as different' do + knife('diff --name-status /').should_succeed <<EOM +M\t/roles/x.json EOM + end + end + + context 'as well as one extra copy of each thing' do + file 'clients/y.json', {} + file 'cookbooks/x-1.0.0/blah.rb', '' + file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"' + file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/z.json', {} + file 'data_bags/y/zz.json', {} + file 'environments/y.json', {} + file 'nodes/y.json', {} + file 'roles/y.json', {} + file 'users/y.json', {} + + it 'knife diff reports the new files as added' do + knife('diff --name-status /').should_succeed <<EOM +A\t/cookbooks/x-1.0.0/blah.rb +A\t/cookbooks/x-2.0.0 +A\t/cookbooks/y-1.0.0 +A\t/data_bags/x/z.json +A\t/data_bags/y +A\t/environments/y.json +A\t/roles/y.json +EOM + end + + context 'when cwd is the data_bags directory' do + cwd 'data_bags' + it 'knife diff reports different data bags' do + knife('diff --name-status').should_succeed <<EOM +A\tx/z.json +A\ty +EOM + end + it 'knife diff * reports different data bags' do + knife('diff --name-status *').should_succeed <<EOM +A\tx/z.json +A\ty +EOM + end + end end end - with_versioned_cookbooks do - repository_has_a_cookbook - it 'knife diff /cookbooks shows the differences' do + when_the_repository 'is empty' do + it 'knife diff reports everything as deleted' do + knife('diff --name-status /').should_succeed <<EOM +D\t/cookbooks +D\t/data_bags +D\t/environments +D\t/roles +EOM + end + end + end + + when_the_repository 'has a cookbook' do + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', '' + + when_the_chef_server 'has a later version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } + + it 'knife diff /cookbooks shows differences' do knife('diff --name-status /cookbooks').should_succeed <<EOM D\t/cookbooks/x-1.0.1 -A\t/cookbooks/x-1.0.0 EOM end + + it 'knife diff --diff-filter=MAT does not show deleted files' do + knife('diff --diff-filter=MAT --name-status /cookbooks').should_succeed '' + end end - end - when_the_chef_server 'has an earlier version for the cookbook, and no current version' do - cookbook 'x', '0.9.9', { 'metadata.rb' => ['name "x"', 'version "0.9.9"'].join("\n"), 'onlyin0.9.9.rb' => '' } + when_the_chef_server 'has an earlier version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } + it 'knife diff /cookbooks shows the differences' do + knife('diff --name-status /cookbooks').should_succeed "D\t/cookbooks/x-0.9.9\n" + end + end - without_versioned_cookbooks do - repository_has_a_cookbook + when_the_chef_server 'has a later version for the cookbook, and no current version' do + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } - it 'knife diff /cookbooks/x shows the differences' do - knife('diff --name-status /cookbooks/x').should_succeed <<EOM -M\t/cookbooks/x/metadata.rb -D\t/cookbooks/x/onlyin0.9.9.rb -A\t/cookbooks/x/onlyin1.0.0.rb + it 'knife diff /cookbooks shows the differences' do + knife('diff --name-status /cookbooks').should_succeed <<EOM +D\t/cookbooks/x-1.0.1 +A\t/cookbooks/x-1.0.0 EOM end end - with_versioned_cookbooks do - repository_has_a_cookbook + when_the_chef_server 'has an earlier version for the cookbook, and no current version' do + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } it 'knife diff /cookbooks shows the differences' do knife('diff --name-status /cookbooks').should_succeed <<EOM @@ -286,74 +519,74 @@ A\t/cookbooks/x-1.0.0 EOM end end - end # when the chef server has an earlier version for the cookbook and no current version - end + end - context 'json diff tests' do - when_the_repository 'has an empty environment file' do - file 'environments/x.json', {} - when_the_chef_server 'has an empty environment' do - environment 'x', {} - it 'knife diff returns no differences' do - knife('diff /environments/x.json').should_succeed '' + context 'json diff tests' do + when_the_repository 'has an empty environment file' do + file 'environments/x.json', {} + when_the_chef_server 'has an empty environment' do + environment 'x', {} + it 'knife diff returns no differences' do + knife('diff /environments/x.json').should_succeed '' + end end - end - when_the_chef_server 'has an environment with a different value' do - environment 'x', { 'description' => 'hi' } - it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ + when_the_chef_server 'has an environment with a different value' do + environment 'x', { 'description' => 'hi' } + it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do + knife('diff /environments/x.json').should_succeed(/ { - "name": "x", - "description": "hi" \+ "name": "x" } /) + end end end - end - when_the_repository 'has an environment file with a value in it' do - file 'environments/x.json', { 'description' => 'hi' } - when_the_chef_server 'has an environment with the same value' do - environment 'x', { 'description' => 'hi' } - it 'knife diff returns no differences' do - knife('diff /environments/x.json').should_succeed '' + when_the_repository 'has an environment file with a value in it' do + file 'environments/x.json', { 'description' => 'hi' } + when_the_chef_server 'has an environment with the same value' do + environment 'x', { 'description' => 'hi' } + it 'knife diff returns no differences' do + knife('diff /environments/x.json').should_succeed '' + end end - end - when_the_chef_server 'has an environment with no value' do - environment 'x', {} - it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ + when_the_chef_server 'has an environment with no value' do + environment 'x', {} + it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do + knife('diff /environments/x.json').should_succeed(/ { - "name": "x" \+ "name": "x", \+ "description": "hi" } /) + end end - end - when_the_chef_server 'has an environment with a different value' do - environment 'x', { 'description' => 'lo' } - it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ + when_the_chef_server 'has an environment with a different value' do + environment 'x', { 'description' => 'lo' } + it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do + knife('diff /environments/x.json').should_succeed(/ { "name": "x", - "description": "lo" \+ "description": "hi" } /) + end end end end - end - - when_the_chef_server 'has an environment' do - environment 'x', {} - when_the_repository 'has an environment with bad JSON' do - file 'environments/x.json', '{' - it 'knife diff reports an error and does a textual diff' do - knife('diff /environments/x.json').should_succeed(/- "name": "x"/, :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n") + + when_the_chef_server 'has an environment' do + environment 'x', {} + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife diff reports an error and does a textual diff' do + knife('diff /environments/x.json').should_succeed(/- "name": "x"/, :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n") + end end end - end + end # without versioned cookbooks end diff --git a/spec/integration/knife/download_spec.rb b/spec/integration/knife/download_spec.rb index 306fd6677d..ee120fb474 100644 --- a/spec/integration/knife/download_spec.rb +++ b/spec/integration/knife/download_spec.rb @@ -6,20 +6,27 @@ describe 'knife download' do extend IntegrationSupport include KnifeSupport - when_the_chef_server "has one of each thing" do - one_of_each_resource_in_chef_server - - when_the_repository 'has only top-level directories' do - directory 'clients' - directory 'cookbooks' - directory 'data_bags' - directory 'environments' - directory 'nodes' - directory 'roles' - directory 'users' - - it 'knife download downloads everything' do - knife('download /').should_succeed <<EOM + context 'without versioned cookbooks' do + when_the_chef_server "has one of each thing" do + client 'x', '{}' + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } + data_bag 'x', { 'y' => '{}' } + environment 'x', '{}' + node 'x', '{}' + role 'x', '{}' + user 'x', '{}' + + when_the_repository 'has only top-level directories' do + directory 'clients' + directory 'cookbooks' + directory 'data_bags' + directory 'environments' + directory 'nodes' + directory 'roles' + directory 'users' + + it 'knife download downloads everything' do + knife('download /').should_succeed <<EOM Created /cookbooks/x Created /cookbooks/x/metadata.rb Created /data_bags/x @@ -28,27 +35,84 @@ Created /environments/_default.json Created /environments/x.json Created /roles/x.json EOM - knife('diff --name-status /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end end - end # when the repository has only top-level directories - when_the_repository 'has an identical copy of each resource' do - one_of_each_resource_in_repository + when_the_repository 'has an identical copy of each thing' do + file 'clients/x.json', <<EOM +{} +EOM + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/y.json', <<EOM +{ + "id": "y" +} +EOM + file 'environments/_default.json', <<EOM +{ + "name": "_default", + "description": "The default Chef environment", + "cookbook_versions": { + }, + "json_class": "Chef::Environment", + "chef_type": "environment", + "default_attributes": { + }, + "override_attributes": { + } +} +EOM + file 'environments/x.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "x", + "override_attributes": { + } +} +EOM + file 'nodes/x.json', <<EOM +{} +EOM + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + file 'users/x.json', <<EOM +{} +EOM - it 'knife download makes no changes' do - knife('download /').should_succeed '' - knife('diff --name-status /').should_succeed '' - end + it 'knife download makes no changes' do + knife('download /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end - it 'knife download --purge makes no changes' do - knife('download --purge /').should_succeed '' - knife('diff --name-status /').should_succeed '' - end - end # when the repository has an identical copy of each resource + it 'knife download --purge makes no changes' do + knife('download --purge /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end - when_the_repository 'has a different role file' do - one_of_each_resource_in_repository - file 'roles/x.json', <<EOM + context 'except the role file' do + file 'roles/x.json', <<EOM { "chef_type": "role", "default_attributes": { @@ -65,15 +129,14 @@ EOM ] } EOM - it 'knife download changes the role' do - knife('download /').should_succeed "Updated /roles/x.json\n" - knife('diff --name-status /').should_succeed '' - end - end # when the repository has a different role file + it 'knife download changes the role' do + knife('download /').should_succeed "Updated /roles/x.json\n" + knife('diff --name-status /').should_succeed '' + end + end - when_the_repository 'has a semantically equivalent role file' do - one_of_each_resource_in_repository - file 'roles/x.json', <<EOM + context 'except the role file is textually different, but not ACTUALLY different' do + file 'roles/x.json', <<EOM { "chef_type": "role", "default_attributes": { @@ -90,20 +153,63 @@ EOM ] } EOM - it 'knife download / does not change anything' do - knife('download /').should_succeed '' - knife('diff --name-status /').should_succeed '' - end - end + it 'knife download / does not change anything' do + knife('download /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end + end - when_the_repository 'has resources not present in the server' do - without_versioned_cookbooks do - one_of_each_resource_in_repository - extra_resources_in_repository + context 'as well as one extra copy of each thing' do + file 'clients/y.json', { 'name' => 'y' } + file 'cookbooks/x/blah.rb', '' + file 'cookbooks/y/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/z.json', <<EOM +{ + "id": "z" +} +EOM + file 'data_bags/y/zz.json', <<EOM +{ + "id": "zz" +} +EOM + file 'environments/y.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "y", + "override_attributes": { + } +} +EOM + file 'nodes/y.json', { 'name' => 'y' } + file 'roles/y.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "y", + "override_attributes": { + }, + "run_list": [ - it 'knife download does nothing' do - knife('download /').should_succeed '' - knife('diff --name-status /').should_succeed <<EOM + ] +} +EOM + file 'users/y.json', { 'name' => 'y' } + + it 'knife download does nothing' do + knife('download /').should_succeed '' + knife('diff --name-status /').should_succeed <<EOM A\t/cookbooks/x/blah.rb A\t/cookbooks/y A\t/data_bags/x/z.json @@ -111,10 +217,10 @@ A\t/data_bags/y A\t/environments/y.json A\t/roles/y.json EOM - end + end - it 'knife download --purge deletes the extra files' do - knife('download --purge /').should_succeed <<EOM + it 'knife download --purge deletes the extra files' do + knife('download --purge /').should_succeed <<EOM Deleted extra entry /cookbooks/x/blah.rb (purge is on) Deleted extra entry /cookbooks/y (purge is on) Deleted extra entry /data_bags/x/z.json (purge is on) @@ -122,45 +228,14 @@ Deleted extra entry /data_bags/y (purge is on) Deleted extra entry /environments/y.json (purge is on) Deleted extra entry /roles/y.json (purge is on) EOM - knife('diff --name-status /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end end - end # without versioned cookbooks - - with_versioned_cookbooks do - one_of_each_resource_in_repository - extra_resources_in_repository - - it 'knife download does nothing' do - knife('download /').should_succeed '' - knife('diff --name-status /').should_succeed <<EOM -A\t/cookbooks/x-1.0.0/blah.rb -A\t/cookbooks/x-2.0.0 -A\t/cookbooks/y-1.0.0 -A\t/data_bags/x/z.json -A\t/data_bags/y -A\t/environments/y.json -A\t/roles/y.json -EOM - end - - it 'knife download --purge deletes the extra files' do - knife('download --purge /').should_succeed <<EOM -Deleted extra entry /cookbooks/x-1.0.0/blah.rb (purge is on) -Deleted extra entry /cookbooks/x-2.0.0 (purge is on) -Deleted extra entry /cookbooks/y-1.0.0 (purge is on) -Deleted extra entry /data_bags/x/z.json (purge is on) -Deleted extra entry /data_bags/y (purge is on) -Deleted extra entry /environments/y.json (purge is on) -Deleted extra entry /roles/y.json (purge is on) -EOM - knife('diff --name-status /').should_succeed '' - end - end # without versioned cookbooks - end # when the repository has resources not present in the server + end - when_the_repository 'is empty' do - it 'knife download creates the extra files' do - knife('download /').should_succeed <<EOM + when_the_repository 'is empty' do + it 'knife download creates the extra files' do + knife('download /').should_succeed <<EOM Created /cookbooks Created /cookbooks/x Created /cookbooks/x/metadata.rb @@ -173,37 +248,37 @@ Created /environments/x.json Created /roles Created /roles/x.json EOM - knife('diff --name-status /').should_succeed '' - end + knife('diff --name-status /').should_succeed '' + end - context 'when current directory is top level' do - cwd '.' - it 'knife download with no parameters reports an error' do - knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/ + context 'when current directory is top level' do + cwd '.' + it 'knife download with no parameters reports an error' do + knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/ + end end end - end # when the repository is empty - end # when the chef server has one of each resource + end - # Test download of an item when the other end doesn't even have the container - when_the_repository 'is empty' do - when_the_chef_server 'has two data bag items' do - data_bag 'x', { 'y' => {}, 'z' => {} } + # Test download of an item when the other end doesn't even have the container + when_the_repository 'is empty' do + when_the_chef_server 'has two data bag items' do + data_bag 'x', { 'y' => {}, 'z' => {} } - it 'knife download of one data bag item itself succeeds' do - knife('download /data_bags/x/y.json').should_succeed <<EOM + it 'knife download of one data bag item itself succeeds' do + knife('download /data_bags/x/y.json').should_succeed <<EOM Created /data_bags Created /data_bags/x Created /data_bags/x/y.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/z.json EOM + end end end - end - when_the_repository 'has three data bag items' do + when_the_repository 'has three data bag items' do file 'data_bags/x/deleted.json', <<EOM { "id": "deleted" @@ -220,106 +295,104 @@ EOM } EOM - when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do - data_bag 'x', { - 'added' => {}, - 'modified' => { 'foo' => 'bar' }, - 'unmodified' => {} - } + when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do + data_bag 'x', { + 'added' => {}, + 'modified' => { 'foo' => 'bar' }, + 'unmodified' => {} + } - it 'knife download of the modified file succeeds' do - knife('download /data_bags/x/modified.json').should_succeed <<EOM + it 'knife download of the modified file succeeds' do + knife('download /data_bags/x/modified.json').should_succeed <<EOM Updated /data_bags/x/modified.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/added.json A\t/data_bags/x/deleted.json EOM - end - it 'knife download of the unmodified file does nothing' do - knife('download /data_bags/x/unmodified.json').should_succeed '' - knife('diff --name-status /data_bags').should_succeed <<EOM + end + it 'knife download of the unmodified file does nothing' do + knife('download /data_bags/x/unmodified.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/added.json M\t/data_bags/x/modified.json A\t/data_bags/x/deleted.json EOM - end - it 'knife download of the added file succeeds' do - knife('download /data_bags/x/added.json').should_succeed <<EOM + end + it 'knife download of the added file succeeds' do + knife('download /data_bags/x/added.json').should_succeed <<EOM Created /data_bags/x/added.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM M\t/data_bags/x/modified.json A\t/data_bags/x/deleted.json EOM - end - it 'knife download of the deleted file does nothing' do - knife('download /data_bags/x/deleted.json').should_succeed '' - knife('diff --name-status /data_bags').should_succeed <<EOM + end + it 'knife download of the deleted file does nothing' do + knife('download /data_bags/x/deleted.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/added.json M\t/data_bags/x/modified.json A\t/data_bags/x/deleted.json EOM - end - it 'knife download --purge of the deleted file deletes it' do - knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM + end + it 'knife download --purge of the deleted file deletes it' do + knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM Deleted extra entry /data_bags/x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/added.json M\t/data_bags/x/modified.json EOM - end - it 'knife download of the entire data bag downloads everything' do - knife('download /data_bags/x').should_succeed <<EOM + end + it 'knife download of the entire data bag downloads everything' do + knife('download /data_bags/x').should_succeed <<EOM Created /data_bags/x/added.json Updated /data_bags/x/modified.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM A\t/data_bags/x/deleted.json EOM - end - it 'knife download --purge of the entire data bag downloads everything' do - knife('download --purge /data_bags/x').should_succeed <<EOM + end + it 'knife download --purge of the entire data bag downloads everything' do + knife('download --purge /data_bags/x').should_succeed <<EOM Created /data_bags/x/added.json Updated /data_bags/x/modified.json Deleted extra entry /data_bags/x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed '' - end - context 'when cwd is the /data_bags directory' do - cwd 'data_bags' - it 'knife download fails' do - knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/ + knife('diff --name-status /data_bags').should_succeed '' end - it 'knife download --purge . downloads everything' do - knife('download --purge .').should_succeed <<EOM + context 'when cwd is the /data_bags directory' do + cwd 'data_bags' + it 'knife download fails' do + knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/ + end + it 'knife download --purge . downloads everything' do + knife('download --purge .').should_succeed <<EOM Created x/added.json Updated x/modified.json Deleted extra entry x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed '' - end - it 'knife download --purge * downloads everything' do - knife('download --purge *').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed '' + end + it 'knife download --purge * downloads everything' do + knife('download --purge *').should_succeed <<EOM Created x/added.json Updated x/modified.json Deleted extra entry x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed '' + knife('diff --name-status /data_bags').should_succeed '' + end end end end - end - - - when_the_chef_server 'has a modified, added and deleted file for the cookbook' do - cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'y.rb' => 'hi' } when_the_repository 'has a cookbook' do - without_versioned_cookbooks do - file 'cookbooks/x/metadata.rb', 'version "1.0.0"' - file 'cookbooks/x/z.rb', '' + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x/z.rb', '' + + when_the_chef_server 'has a modified, added and deleted file for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'y.rb' => 'hi' } it 'knife download of a modified file succeeds' do knife('download /cookbooks/x/metadata.rb').should_succeed "Updated /cookbooks/x/metadata.rb\n" @@ -355,7 +428,7 @@ EOM Updated /cookbooks/x/metadata.rb Created /cookbooks/x/y.rb EOM - knife('diff --name-status /cookbooks').should_succeed <<EOM + knife('diff --name-status /cookbooks').should_succeed <<EOM A\t/cookbooks/x/z.rb EOM end @@ -368,62 +441,8 @@ EOM knife('diff --name-status /cookbooks').should_succeed '' end end - - with_versioned_cookbooks do - file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' - file 'cookbooks/x-1.0.0/z.rb', '' - - it 'knife download of a modified file succeeds' do - knife('download /cookbooks/x-1.0.0/metadata.rb').should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n" - knife('diff --name-status /cookbooks').should_succeed <<EOM -D\t/cookbooks/x-1.0.0/y.rb -A\t/cookbooks/x-1.0.0/z.rb -EOM - end - it 'knife download of a deleted file does nothing' do - knife('download /cookbooks/x-1.0.0/z.rb').should_succeed '' - knife('diff --name-status /cookbooks').should_succeed <<EOM -M\t/cookbooks/x-1.0.0/metadata.rb -D\t/cookbooks/x-1.0.0/y.rb -A\t/cookbooks/x-1.0.0/z.rb -EOM - end - it 'knife download --purge of a deleted file succeeds' do - knife('download --purge /cookbooks/x-1.0.0/z.rb').should_succeed "Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)\n" - knife('diff --name-status /cookbooks').should_succeed <<EOM -M\t/cookbooks/x-1.0.0/metadata.rb -D\t/cookbooks/x-1.0.0/y.rb -EOM - end - it 'knife download of an added file succeeds' do - knife('download /cookbooks/x-1.0.0/y.rb').should_succeed "Created /cookbooks/x-1.0.0/y.rb\n" - knife('diff --name-status /cookbooks').should_succeed <<EOM -M\t/cookbooks/x-1.0.0/metadata.rb -A\t/cookbooks/x-1.0.0/z.rb -EOM - end - it 'knife download of the cookbook itself succeeds' do - knife('download /cookbooks/x-1.0.0').should_succeed <<EOM -Updated /cookbooks/x-1.0.0/metadata.rb -Created /cookbooks/x-1.0.0/y.rb -EOM - knife('diff --name-status /cookbooks').should_succeed <<EOM -A\t/cookbooks/x-1.0.0/z.rb -EOM - end - it 'knife download --purge of the cookbook itself succeeds' do - knife('download --purge /cookbooks/x-1.0.0').should_succeed <<EOM -Updated /cookbooks/x-1.0.0/metadata.rb -Created /cookbooks/x-1.0.0/y.rb -Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on) -EOM - knife('diff --name-status /cookbooks').should_succeed '' - end - end end - end - without_versioned_cookbooks do when_the_repository 'has a cookbook' do file 'cookbooks/x/metadata.rb', 'version "1.0.0"' file 'cookbooks/x/onlyin1.0.0.rb', 'old_text' @@ -479,9 +498,475 @@ EOM end end end + + when_the_chef_server 'has an environment' do + environment 'x', {} + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife download succeeds' do + knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n", :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end + end + + when_the_repository 'has the same environment with the wrong name in the file' do + file 'environments/x.json', { 'name' => 'y' } + it 'knife download succeeds' do + knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end + end + + when_the_repository 'has the same environment with no name in the file' do + file 'environments/x.json', { 'description' => 'hi' } + it 'knife download succeeds' do + knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end + end + end end # without versioned cookbooks with_versioned_cookbooks do + when_the_chef_server "has one of each thing" do + client 'x', '{}' + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } + data_bag 'x', { 'y' => '{}' } + environment 'x', '{}' + node 'x', '{}' + role 'x', '{}' + user 'x', '{}' + + when_the_repository 'has only top-level directories' do + directory 'clients' + directory 'cookbooks' + directory 'data_bags' + directory 'environments' + directory 'nodes' + directory 'roles' + directory 'users' + + it 'knife download downloads everything' do + knife('download /').should_succeed <<EOM +Created /cookbooks/x-1.0.0 +Created /cookbooks/x-1.0.0/metadata.rb +Created /data_bags/x +Created /data_bags/x/y.json +Created /environments/_default.json +Created /environments/x.json +Created /roles/x.json +EOM + knife('diff --name-status /').should_succeed '' + end + end + + when_the_repository 'has an identical copy of each thing' do + file 'clients/x.json', <<EOM +{} +EOM + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/y.json', <<EOM +{ + "id": "y" +} +EOM + file 'environments/_default.json', <<EOM +{ + "name": "_default", + "description": "The default Chef environment", + "cookbook_versions": { + }, + "json_class": "Chef::Environment", + "chef_type": "environment", + "default_attributes": { + }, + "override_attributes": { + } +} +EOM + file 'environments/x.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "x", + "override_attributes": { + } +} +EOM + file 'nodes/x.json', <<EOM +{} +EOM + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + file 'users/x.json', <<EOM +{} +EOM + + it 'knife download makes no changes' do + knife('download /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end + + it 'knife download --purge makes no changes' do + knife('download --purge /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end + + context 'except the role file' do + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "blarghle", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + it 'knife download changes the role' do + knife('download /').should_succeed "Updated /roles/x.json\n" + knife('diff --name-status /').should_succeed '' + end + end + + context 'except the role file is textually different, but not ACTUALLY different' do + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "description": "", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + it 'knife download / does not change anything' do + knife('download /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end + end + + context 'as well as one extra copy of each thing' do + file 'clients/y.json', { 'name' => 'y' } + file 'cookbooks/x-1.0.0/blah.rb', '' + file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"' + file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/z.json', <<EOM +{ + "id": "z" +} +EOM + file 'data_bags/y/zz.json', <<EOM +{ + "id": "zz" +} +EOM + file 'environments/y.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "y", + "override_attributes": { + } +} +EOM + file 'nodes/y.json', { 'name' => 'y' } + file 'roles/y.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "y", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + file 'users/y.json', { 'name' => 'y' } + + it 'knife download does nothing' do + knife('download /').should_succeed '' + knife('diff --name-status /').should_succeed <<EOM +A\t/cookbooks/x-1.0.0/blah.rb +A\t/cookbooks/x-2.0.0 +A\t/cookbooks/y-1.0.0 +A\t/data_bags/x/z.json +A\t/data_bags/y +A\t/environments/y.json +A\t/roles/y.json +EOM + end + + it 'knife download --purge deletes the extra files' do + knife('download --purge /').should_succeed <<EOM +Deleted extra entry /cookbooks/x-1.0.0/blah.rb (purge is on) +Deleted extra entry /cookbooks/x-2.0.0 (purge is on) +Deleted extra entry /cookbooks/y-1.0.0 (purge is on) +Deleted extra entry /data_bags/x/z.json (purge is on) +Deleted extra entry /data_bags/y (purge is on) +Deleted extra entry /environments/y.json (purge is on) +Deleted extra entry /roles/y.json (purge is on) +EOM + knife('diff --name-status /').should_succeed '' + end + end + end + + when_the_repository 'is empty' do + it 'knife download creates the extra files' do + knife('download /').should_succeed <<EOM +Created /cookbooks +Created /cookbooks/x-1.0.0 +Created /cookbooks/x-1.0.0/metadata.rb +Created /data_bags +Created /data_bags/x +Created /data_bags/x/y.json +Created /environments +Created /environments/_default.json +Created /environments/x.json +Created /roles +Created /roles/x.json +EOM + knife('diff --name-status /').should_succeed '' + end + + context 'when current directory is top level' do + cwd '.' + it 'knife download with no parameters reports an error' do + knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/ + end + end + end + end + + # Test download of an item when the other end doesn't even have the container + when_the_repository 'is empty' do + when_the_chef_server 'has two data bag items' do + data_bag 'x', { 'y' => {}, 'z' => {} } + + it 'knife download of one data bag item itself succeeds' do + knife('download /data_bags/x/y.json').should_succeed <<EOM +Created /data_bags +Created /data_bags/x +Created /data_bags/x/y.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/z.json +EOM + end + end + end + + when_the_repository 'has three data bag items' do + file 'data_bags/x/deleted.json', <<EOM +{ + "id": "deleted" +} +EOM + file 'data_bags/x/modified.json', <<EOM +{ + "id": "modified" +} +EOM + file 'data_bags/x/unmodified.json', <<EOM +{ + "id": "unmodified" +} +EOM + + when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do + data_bag 'x', { + 'added' => {}, + 'modified' => { 'foo' => 'bar' }, + 'unmodified' => {} + } + + it 'knife download of the modified file succeeds' do + knife('download /data_bags/x/modified.json').should_succeed <<EOM +Updated /data_bags/x/modified.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/added.json +A\t/data_bags/x/deleted.json +EOM + end + it 'knife download of the unmodified file does nothing' do + knife('download /data_bags/x/unmodified.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/added.json +M\t/data_bags/x/modified.json +A\t/data_bags/x/deleted.json +EOM + end + it 'knife download of the added file succeeds' do + knife('download /data_bags/x/added.json').should_succeed <<EOM +Created /data_bags/x/added.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +M\t/data_bags/x/modified.json +A\t/data_bags/x/deleted.json +EOM + end + it 'knife download of the deleted file does nothing' do + knife('download /data_bags/x/deleted.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/added.json +M\t/data_bags/x/modified.json +A\t/data_bags/x/deleted.json +EOM + end + it 'knife download --purge of the deleted file deletes it' do + knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM +Deleted extra entry /data_bags/x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/added.json +M\t/data_bags/x/modified.json +EOM + end + it 'knife download of the entire data bag downloads everything' do + knife('download /data_bags/x').should_succeed <<EOM +Created /data_bags/x/added.json +Updated /data_bags/x/modified.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +A\t/data_bags/x/deleted.json +EOM + end + it 'knife download --purge of the entire data bag downloads everything' do + knife('download --purge /data_bags/x').should_succeed <<EOM +Created /data_bags/x/added.json +Updated /data_bags/x/modified.json +Deleted extra entry /data_bags/x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed '' + end + context 'when cwd is the /data_bags directory' do + cwd 'data_bags' + it 'knife download fails' do + knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/ + end + it 'knife download --purge . downloads everything' do + knife('download --purge .').should_succeed <<EOM +Created x/added.json +Updated x/modified.json +Deleted extra entry x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed '' + end + it 'knife download --purge * downloads everything' do + knife('download --purge *').should_succeed <<EOM +Created x/added.json +Updated x/modified.json +Deleted extra entry x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed '' + end + end + end + end + + when_the_repository 'has a cookbook' do + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x-1.0.0/z.rb', '' + + when_the_chef_server 'has a modified, added and deleted file for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'y.rb' => 'hi' } + + it 'knife download of a modified file succeeds' do + knife('download /cookbooks/x-1.0.0/metadata.rb').should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n" + knife('diff --name-status /cookbooks').should_succeed <<EOM +D\t/cookbooks/x-1.0.0/y.rb +A\t/cookbooks/x-1.0.0/z.rb +EOM + end + it 'knife download of a deleted file does nothing' do + knife('download /cookbooks/x-1.0.0/z.rb').should_succeed '' + knife('diff --name-status /cookbooks').should_succeed <<EOM +M\t/cookbooks/x-1.0.0/metadata.rb +D\t/cookbooks/x-1.0.0/y.rb +A\t/cookbooks/x-1.0.0/z.rb +EOM + end + it 'knife download --purge of a deleted file succeeds' do + knife('download --purge /cookbooks/x-1.0.0/z.rb').should_succeed "Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)\n" + knife('diff --name-status /cookbooks').should_succeed <<EOM +M\t/cookbooks/x-1.0.0/metadata.rb +D\t/cookbooks/x-1.0.0/y.rb +EOM + end + it 'knife download of an added file succeeds' do + knife('download /cookbooks/x-1.0.0/y.rb').should_succeed "Created /cookbooks/x-1.0.0/y.rb\n" + knife('diff --name-status /cookbooks').should_succeed <<EOM +M\t/cookbooks/x-1.0.0/metadata.rb +A\t/cookbooks/x-1.0.0/z.rb +EOM + end + it 'knife download of the cookbook itself succeeds' do + knife('download /cookbooks/x-1.0.0').should_succeed <<EOM +Updated /cookbooks/x-1.0.0/metadata.rb +Created /cookbooks/x-1.0.0/y.rb +EOM + knife('diff --name-status /cookbooks').should_succeed <<EOM +A\t/cookbooks/x-1.0.0/z.rb +EOM + end + it 'knife download --purge of the cookbook itself succeeds' do + knife('download --purge /cookbooks/x-1.0.0').should_succeed <<EOM +Updated /cookbooks/x-1.0.0/metadata.rb +Created /cookbooks/x-1.0.0/y.rb +Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on) +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + end + end + when_the_repository 'has a cookbook' do file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', 'old_text' @@ -504,7 +989,7 @@ EOM when_the_chef_server 'has an earlier version for the cookbook' do cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } - it 'knife download /cookbooks/x downloads the updated file' do + it 'knife download /cookbooks downloads the updated file' do knife('download --purge /cookbooks').should_succeed <<EOM Created /cookbooks/x-0.9.9 Created /cookbooks/x-0.9.9/metadata.rb @@ -532,7 +1017,7 @@ EOM when_the_chef_server 'has an earlier version for the cookbook, and no current version' do cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } - it 'knife download /cookbooks/x downloads the old version' do + it 'knife download --purge /cookbooks downloads the old version and deletes the new version' do knife('download --purge /cookbooks').should_succeed <<EOM Created /cookbooks/x-0.9.9 Created /cookbooks/x-0.9.9/metadata.rb @@ -543,32 +1028,32 @@ EOM end end end - end # with versioned cookbooks - when_the_chef_server 'has an environment' do - environment 'x', {} - when_the_repository 'has an environment with bad JSON' do - file 'environments/x.json', '{' - it 'knife download succeeds' do - knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n", :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" - knife('diff --name-status /environments/x.json').should_succeed '' + when_the_chef_server 'has an environment' do + environment 'x', {} + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife download succeeds' do + knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n", :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end end - end - when_the_repository 'has the same environment with the wrong name in the file' do - file 'environments/x.json', { 'name' => 'y' } - it 'knife download succeeds' do - knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" - knife('diff --name-status /environments/x.json').should_succeed '' + when_the_repository 'has the same environment with the wrong name in the file' do + file 'environments/x.json', { 'name' => 'y' } + it 'knife download succeeds' do + knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end end - end - when_the_repository 'has the same environment with no name in the file' do - file 'environments/x.json', { 'description' => 'hi' } - it 'knife download succeeds' do - knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" - knife('diff --name-status /environments/x.json').should_succeed '' + when_the_repository 'has the same environment with no name in the file' do + file 'environments/x.json', { 'description' => 'hi' } + it 'knife download succeeds' do + knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end end end - end + end # with versioned cookbooks end diff --git a/spec/integration/knife/upload_spec.rb b/spec/integration/knife/upload_spec.rb index 78506a58ed..1cc2e6ca88 100644 --- a/spec/integration/knife/upload_spec.rb +++ b/spec/integration/knife/upload_spec.rb @@ -6,22 +6,25 @@ describe 'knife upload' do extend IntegrationSupport include KnifeSupport - # TODO: Put this in common - let(:versioned_cookbooks?) { self.class.metadata[:versioned_cookbooks] } - - when_the_chef_server "has one of each thing" do - one_of_each_resource_in_chef_server - - when_the_repository 'has only top-level directories' do - directory 'clients' - directory 'cookbooks' - directory 'data_bags' - directory 'environments' - directory 'nodes' - directory 'roles' - directory 'users' - - without_versioned_cookbooks do + context 'without versioned cookbooks' do + when_the_chef_server "has one of each thing" do + client 'x', '{}' + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } + data_bag 'x', { 'y' => '{}' } + environment 'x', '{}' + node 'x', '{}' + role 'x', '{}' + user 'x', '{}' + + when_the_repository 'has only top-level directories' do + directory 'clients' + directory 'cookbooks' + directory 'data_bags' + directory 'environments' + directory 'nodes' + directory 'roles' + directory 'users' + it 'knife upload does nothing' do knife('upload /').should_succeed '' knife('diff --name-status /').should_succeed <<EOM @@ -31,55 +34,85 @@ D\t/environments/_default.json D\t/environments/x.json D\t/roles/x.json EOM - end + end - it 'knife upload --purge deletes everything' do - knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n") + it 'knife upload --purge deletes everything' do + knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n") Deleted extra entry /cookbooks/x (purge is on) Deleted extra entry /data_bags/x (purge is on) Deleted extra entry /environments/x.json (purge is on) Deleted extra entry /roles/x.json (purge is on) EOM - knife('diff --name-status /').should_succeed <<EOM + knife('diff --name-status /').should_succeed <<EOM D\t/environments/_default.json EOM - end + end end - with_versioned_cookbooks do - it 'knife upload does nothing' do - knife('upload /').should_succeed '' - knife('diff --name-status /').should_succeed <<EOM -D\t/cookbooks/x-1.0.0 -D\t/data_bags/x -D\t/environments/_default.json -D\t/environments/x.json -D\t/roles/x.json + when_the_repository 'has an identical copy of each thing' do + file 'clients/x.json', <<EOM +{} EOM - end - - it 'knife upload --purge deletes everything' do - knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n") -Deleted extra entry /cookbooks/x-1.0.0 (purge is on) -Deleted extra entry /data_bags/x (purge is on) -Deleted extra entry /environments/x.json (purge is on) -Deleted extra entry /roles/x.json (purge is on) + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/y.json', <<EOM +{ + "id": "y" +} EOM - knife('diff --name-status /').should_succeed <<EOM -D\t/environments/_default.json + file 'environments/_default.json', <<EOM +{ + "name": "_default", + "description": "The default Chef environment", + "cookbook_versions": { + }, + "json_class": "Chef::Environment", + "chef_type": "environment", + "default_attributes": { + }, + "override_attributes": { + } +} EOM - end - end - end # when the repository has only top-level directories - - when_the_repository 'matches the resources on the server' do - with_all_types_of_repository_layouts do - one_of_each_resource_in_repository + file 'environments/x.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "x", + "override_attributes": { + } +} +EOM + file 'nodes/x.json', <<EOM +{} +EOM + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ - let(:cookbook_name) { versioned_cookbooks? ? 'x-1.0.0' : 'x' } + ] +} +EOM + file 'users/x.json', <<EOM +{} +EOM it 'knife upload makes no changes' do - knife("upload /cookbooks/#{cookbook_name}").should_succeed '' + knife('upload /cookbooks/x').should_succeed '' knife('diff --name-status /').should_succeed '' end @@ -87,13 +120,9 @@ EOM knife('upload --purge /').should_succeed '' knife('diff --name-status /').should_succeed '' end - end # with all types of repository layouts - end # when the repository matches the resources on the server - when_the_repository 'has a different role file' do - with_all_types_of_repository_layouts do - one_of_each_resource_in_repository - file 'roles/x.json', <<EOM + context 'except the role file' do + file 'roles/x.json', <<EOM { "chef_type": "role", "default_attributes": { @@ -110,17 +139,14 @@ EOM ] } EOM - it 'knife upload changes the role' do - knife('upload /').should_succeed "Updated /roles/x.json\n" - knife('diff --name-status /').should_succeed '' + it 'knife upload changes the role' do + knife('upload /').should_succeed "Updated /roles/x.json\n" + knife('diff --name-status /').should_succeed '' + end end - end # with all types of repository layouts - end # when the repository has a different role file - when_the_repository 'has a semantically equivalent role file' do - with_all_types_of_repository_layouts do - one_of_each_resource_in_repository - file 'roles/x.json', <<EOM + context 'except the role file is textually different, but not ACTUALLY different' do + file 'roles/x.json', <<EOM { "chef_type": "role", "default_attributes": { @@ -137,55 +163,76 @@ EOM ] } EOM - it 'knife upload / does not change anything' do - knife('upload /').should_succeed '' - knife('diff --name-status /').should_succeed '' + it 'knife upload / does not change anything' do + knife('upload /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end end - end # with all types of repository layouts - end # when the repository has a semantically equivalent role file - - when_the_repository 'has resources not present in the server' do - without_versioned_cookbooks do - one_of_each_resource_in_repository - extra_resources_in_repository - it 'knife upload adds the new files' do - knife('upload /').should_succeed <<EOM -Updated /cookbooks/x -Created /cookbooks/y -Created /data_bags/x/z.json -Created /data_bags/y -Created /data_bags/y/zz.json -Created /environments/y.json -Created /roles/y.json + context 'as well as one extra copy of each thing' do + file 'clients/y.json', { 'name' => 'y' } + file 'cookbooks/x/blah.rb', '' + file 'cookbooks/y/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/z.json', <<EOM +{ + "id": "z" +} EOM - knife('diff --name-status /').should_succeed '' - end - end # without versioned cookbooks + file 'data_bags/y/zz.json', <<EOM +{ + "id": "zz" +} +EOM + file 'environments/y.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "y", + "override_attributes": { + } +} +EOM + file 'nodes/y.json', { 'name' => 'y' } + file 'roles/y.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "y", + "override_attributes": { + }, + "run_list": [ - with_versioned_cookbooks do - one_of_each_resource_in_repository - extra_resources_in_repository + ] +} +EOM + file 'users/y.json', { 'name' => 'y' } - it 'knife upload adds the new files' do - knife('upload /').should_succeed <<EOM -Updated /cookbooks/x-1.0.0 -Created /cookbooks/x-2.0.0 -Created /cookbooks/y-1.0.0 + it 'knife upload adds the new files' do + knife('upload /').should_succeed <<EOM +Updated /cookbooks/x +Created /cookbooks/y Created /data_bags/x/z.json Created /data_bags/y Created /data_bags/y/zz.json Created /environments/y.json Created /roles/y.json EOM - - knife('diff --name-status /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end end - end # with versioned cookbooks - end # when the repository has resources not present in the server + end - when_the_repository 'is empty' do - with_all_types_of_repository_layouts do + when_the_repository 'is empty' do it 'knife upload does nothing' do knife('upload /').should_succeed '' knife('diff --name-status /').should_succeed <<EOM @@ -216,317 +263,885 @@ EOM it 'knife upload with no parameters reports an error' do knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/ end - end # when current directory is top level - end # with all types of repository layouts - end # when the directory is empty - end - - # Test upload of an item when the other end doesn't even have the container - when_the_chef_server 'is empty' do - when_the_repository 'has two data bag items' do - file 'data_bags/x/y.json', <<EOM + end + end + end + + # Test upload of an item when the other end doesn't even have the container + when_the_chef_server 'is empty' do + when_the_repository 'has two data bag items' do + file 'data_bags/x/y.json', <<EOM { "id": "y" } EOM - file 'data_bags/x/z.json', <<EOM + file 'data_bags/x/z.json', <<EOM { "id": "z" } EOM - it 'knife upload of one data bag item itself succeeds' do - knife('upload /data_bags/x/y.json').should_succeed <<EOM + it 'knife upload of one data bag item itself succeeds' do + knife('upload /data_bags/x/y.json').should_succeed <<EOM Created /data_bags/x Created /data_bags/x/y.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM A\t/data_bags/x/z.json EOM + end end end - end - when_the_chef_server 'has three data bag items' do - data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} } - when_the_repository 'has a modified, unmodified, added and deleted data bag item' do - file 'data_bags/x/added.json', <<EOM + when_the_chef_server 'has three data bag items' do + data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} } + when_the_repository 'has a modified, unmodified, added and deleted data bag item' do + file 'data_bags/x/added.json', <<EOM { "id": "added" } EOM - file 'data_bags/x/modified.json', <<EOM + file 'data_bags/x/modified.json', <<EOM { "id": "modified", "foo": "bar" } EOM - file 'data_bags/x/unmodified.json', <<EOM + file 'data_bags/x/unmodified.json', <<EOM { "id": "unmodified" } EOM - it 'knife upload of the modified file succeeds' do - knife('upload /data_bags/x/modified.json').should_succeed <<EOM + it 'knife upload of the modified file succeeds' do + knife('upload /data_bags/x/modified.json').should_succeed <<EOM Updated /data_bags/x/modified.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/deleted.json A\t/data_bags/x/added.json EOM - end - it 'knife upload of the unmodified file does nothing' do - knife('upload /data_bags/x/unmodified.json').should_succeed '' - knife('diff --name-status /data_bags').should_succeed <<EOM + end + it 'knife upload of the unmodified file does nothing' do + knife('upload /data_bags/x/unmodified.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/deleted.json M\t/data_bags/x/modified.json A\t/data_bags/x/added.json EOM - end - it 'knife upload of the added file succeeds' do - knife('upload /data_bags/x/added.json').should_succeed <<EOM + end + it 'knife upload of the added file succeeds' do + knife('upload /data_bags/x/added.json').should_succeed <<EOM Created /data_bags/x/added.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/deleted.json M\t/data_bags/x/modified.json EOM - end - it 'knife upload of the deleted file does nothing' do - knife('upload /data_bags/x/deleted.json').should_succeed '' - knife('diff --name-status /data_bags').should_succeed <<EOM + end + it 'knife upload of the deleted file does nothing' do + knife('upload /data_bags/x/deleted.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/deleted.json M\t/data_bags/x/modified.json A\t/data_bags/x/added.json EOM - end - it 'knife upload --purge of the deleted file deletes it' do - knife('upload --purge /data_bags/x/deleted.json').should_succeed <<EOM + end + it 'knife upload --purge of the deleted file deletes it' do + knife('upload --purge /data_bags/x/deleted.json').should_succeed <<EOM Deleted extra entry /data_bags/x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM M\t/data_bags/x/modified.json A\t/data_bags/x/added.json EOM - end - it 'knife upload of the entire data bag uploads everything' do - knife('upload /data_bags/x').should_succeed <<EOM + end + it 'knife upload of the entire data bag uploads everything' do + knife('upload /data_bags/x').should_succeed <<EOM Created /data_bags/x/added.json Updated /data_bags/x/modified.json EOM - knife('diff --name-status /data_bags').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed <<EOM D\t/data_bags/x/deleted.json EOM - end - it 'knife upload --purge of the entire data bag uploads everything' do - knife('upload --purge /data_bags/x').should_succeed <<EOM + end + it 'knife upload --purge of the entire data bag uploads everything' do + knife('upload --purge /data_bags/x').should_succeed <<EOM Created /data_bags/x/added.json Updated /data_bags/x/modified.json Deleted extra entry /data_bags/x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed '' - end - context 'when cwd is the /data_bags directory' do - cwd 'data_bags' - it 'knife upload fails' do - knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/ + knife('diff --name-status /data_bags').should_succeed '' end - it 'knife upload --purge . uploads everything' do - knife('upload --purge .').should_succeed <<EOM + context 'when cwd is the /data_bags directory' do + cwd 'data_bags' + it 'knife upload fails' do + knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/ + end + it 'knife upload --purge . uploads everything' do + knife('upload --purge .').should_succeed <<EOM Created x/added.json Updated x/modified.json Deleted extra entry x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed '' - end - it 'knife upload --purge * uploads everything' do - knife('upload --purge *').should_succeed <<EOM + knife('diff --name-status /data_bags').should_succeed '' + end + it 'knife upload --purge * uploads everything' do + knife('upload --purge *').should_succeed <<EOM Created x/added.json Updated x/modified.json Deleted extra entry x/deleted.json (purge is on) EOM - knife('diff --name-status /data_bags').should_succeed '' + knife('diff --name-status /data_bags').should_succeed '' + end end end end - end - - # Cookbook upload is a funny thing ... direct cookbook upload works, but - # upload of a file is designed not to work at present. Make sure that is the - # case. - when_the_chef_server 'has a cookbook' do - cookbook 'x', '1.0.0', { 'metadata.rb' => ['name "x"', 'version "1.0.0"'].join("\n"), 'z.rb' => '' } - when_the_repository 'has a modified, extra and missing file for the cookbook' do - file 'cookbooks/x/metadata.rb', ['name "x"', 'version "1.0.0"'].join("\n") - file 'cookbooks/x/y.rb', 'hi' - it 'knife upload of any individual file fails' do - knife('upload /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb cannot be updated.\n" - knife('upload /cookbooks/x/y.rb').should_fail "ERROR: /cookbooks/x cannot have a child created under it.\n" - knife('upload --purge /cookbooks/x/z.rb').should_fail "ERROR: /cookbooks/x/z.rb cannot be deleted.\n" - end - # TODO this is a bit of an inconsistency: if we didn't specify --purge, - # technically we shouldn't have deleted missing files. But ... cookbooks - # are a special case. - it 'knife upload of the cookbook itself succeeds' do - knife('upload /cookbooks/x').should_succeed <<EOM + + # Cookbook upload is a funny thing ... direct cookbook upload works, but + # upload of a file is designed not to work at present. Make sure that is the + # case. + when_the_chef_server 'has a cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'z.rb' => '' } + when_the_repository 'has a modified, extra and missing file for the cookbook' do + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x/y.rb', 'hi' + it 'knife upload of any individual file fails' do + knife('upload /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb cannot be updated.\n" + knife('upload /cookbooks/x/y.rb').should_fail "ERROR: /cookbooks/x cannot have a child created under it.\n" + knife('upload --purge /cookbooks/x/z.rb').should_fail "ERROR: /cookbooks/x/z.rb cannot be deleted.\n" + end + # TODO this is a bit of an inconsistency: if we didn't specify --purge, + # technically we shouldn't have deleted missing files. But ... cookbooks + # are a special case. + it 'knife upload of the cookbook itself succeeds' do + knife('upload /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed '' - end - it 'knife upload --purge of the cookbook itself succeeds' do - knife('upload /cookbooks/x').should_succeed <<EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + it 'knife upload --purge of the cookbook itself succeeds' do + knife('upload /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed '' + knife('diff --name-status /cookbooks').should_succeed '' + end end - end - when_the_repository 'has a missing file for the cookbook' do - file 'cookbooks/x/metadata.rb', ['name "x"', 'version "1.0.0"'].join("\n") - it 'knife upload of the cookbook succeeds' do - knife('upload /cookbooks/x').should_succeed <<EOM + when_the_repository 'has a missing file for the cookbook' do + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + it 'knife upload of the cookbook succeeds' do + knife('upload /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed '' + knife('diff --name-status /cookbooks').should_succeed '' + end end - end - when_the_repository 'has an extra file for the cookbook' do - file 'cookbooks/x/metadata.rb', ['name "x"', 'version "1.0.0"'].join("\n") - file 'cookbooks/x/z.rb', '' - file 'cookbooks/x/blah.rb', '' - it 'knife upload of the cookbook succeeds' do - knife('upload /cookbooks/x').should_succeed <<EOM + when_the_repository 'has an extra file for the cookbook' do + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x/z.rb', '' + file 'cookbooks/x/blah.rb', '' + it 'knife upload of the cookbook succeeds' do + knife('upload /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed '' + knife('diff --name-status /cookbooks').should_succeed '' + end end end - end - when_the_repository 'has a cookbook' do - file 'cookbooks/x/metadata.rb', ['name "x"', 'version "1.0.0"'].join("\n") - file 'cookbooks/x/onlyin1.0.0.rb', 'old_text' + when_the_repository 'has a cookbook' do + file 'cookbooks/x/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x/onlyin1.0.0.rb', 'old_text' - when_the_chef_server 'has a later version for the cookbook' do - cookbook 'x', '1.0.0', { 'metadata.rb' => ['name "x"', 'version "1.0.0"'].join("\n"), 'onlyin1.0.0.rb' => '' } - cookbook 'x', '1.0.1', { 'metadata.rb' => ['name "x"', 'version "1.0.1"'].join("\n"), 'onlyin1.0.1.rb' => 'hi' } + when_the_chef_server 'has a later version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } - it 'knife upload /cookbooks/x uploads the local version' do - knife('diff --name-status /cookbooks').should_succeed <<EOM + it 'knife upload /cookbooks/x uploads the local version' do + knife('diff --name-status /cookbooks').should_succeed <<EOM M\t/cookbooks/x/metadata.rb D\t/cookbooks/x/onlyin1.0.1.rb A\t/cookbooks/x/onlyin1.0.0.rb EOM - knife('upload --purge /cookbooks/x').should_succeed <<EOM + knife('upload --purge /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed <<EOM + knife('diff --name-status /cookbooks').should_succeed <<EOM M\t/cookbooks/x/metadata.rb D\t/cookbooks/x/onlyin1.0.1.rb A\t/cookbooks/x/onlyin1.0.0.rb EOM + end end - end - when_the_chef_server 'has an earlier version for the cookbook' do - cookbook 'x', '1.0.0', { 'metadata.rb' => ['name "x"', 'version "1.0.0"'].join("\n"), 'onlyin1.0.0.rb' => ''} - cookbook 'x', '0.9.9', { 'metadata.rb' => ['name "x"', 'version "0.9.9"'].join("\n"), 'onlyin0.9.9.rb' => 'hi' } - it 'knife upload /cookbooks/x uploads the local version' do - knife('upload --purge /cookbooks/x').should_succeed <<EOM + when_the_chef_server 'has an earlier version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } + it 'knife upload /cookbooks/x uploads the local version' do + knife('upload --purge /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed '' + knife('diff --name-status /cookbooks').should_succeed '' + end end - end - when_the_chef_server 'has a later version for the cookbook, and no current version' do - cookbook 'x', '1.0.1', { 'metadata.rb' => ['name "x"', 'version "1.0.1"'].join("\n"), 'onlyin1.0.1.rb' => 'hi' } + when_the_chef_server 'has a later version for the cookbook, and no current version' do + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } - it 'knife upload /cookbooks/x uploads the local version' do - knife('diff --name-status /cookbooks').should_succeed <<EOM + it 'knife upload /cookbooks/x uploads the local version' do + knife('diff --name-status /cookbooks').should_succeed <<EOM M\t/cookbooks/x/metadata.rb D\t/cookbooks/x/onlyin1.0.1.rb A\t/cookbooks/x/onlyin1.0.0.rb EOM - knife('upload --purge /cookbooks/x').should_succeed <<EOM + knife('upload --purge /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed <<EOM + knife('diff --name-status /cookbooks').should_succeed <<EOM M\t/cookbooks/x/metadata.rb D\t/cookbooks/x/onlyin1.0.1.rb A\t/cookbooks/x/onlyin1.0.0.rb EOM + end end - end - when_the_chef_server 'has an earlier version for the cookbook, and no current version' do - cookbook 'x', '0.9.9', { 'metadata.rb' => ['name "x"', 'version "0.9.9"'].join("\n"), 'onlyin0.9.9.rb' => 'hi' } + when_the_chef_server 'has an earlier version for the cookbook, and no current version' do + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } - it 'knife upload /cookbooks/x uploads the new version' do - knife('upload --purge /cookbooks/x').should_succeed <<EOM + it 'knife upload /cookbooks/x uploads the new version' do + knife('upload --purge /cookbooks/x').should_succeed <<EOM Updated /cookbooks/x EOM - knife('diff --name-status /cookbooks').should_succeed '' + knife('diff --name-status /cookbooks').should_succeed '' + end end end - end - when_the_chef_server 'has an environment' do - environment 'x', {} - when_the_repository 'has an environment with bad JSON' do - file 'environments/x.json', '{' - it 'knife upload tries and fails' do - knife('upload /environments/x.json').should_fail "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\nERROR: /environments/x.json failed to write: Parse error reading JSON: A JSON text must at least contain two octets!\n" - knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n", :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" + when_the_chef_server 'has an environment' do + environment 'x', {} + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife upload tries and fails' do + knife('upload /environments/x.json').should_fail "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\nERROR: /environments/x.json failed to write: Parse error reading JSON: A JSON text must at least contain two octets!\n" + knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n", :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" + end + end + + when_the_repository 'has the same environment with the wrong name in the file' do + file 'environments/x.json', { 'name' => 'y' } + it 'knife upload fails' do + knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name in remote/environments/x.json/x.json must be 'x' (is 'y')\n" + knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n" + end + end + + when_the_repository 'has the same environment with no name in the file' do + file 'environments/x.json', { 'description' => 'hi' } + it 'knife upload succeeds' do + knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end end end - when_the_repository 'has the same environment with the wrong name in the file' do - file 'environments/x.json', { 'name' => 'y' } - it 'knife upload fails' do - knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name in remote/environments/x.json/x.json must be 'x' (is 'y')\n" - knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n" + when_the_chef_server 'is empty' do + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife upload tries and fails' do + knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Parse error reading JSON creating child 'x.json': A JSON text must at least contain two octets!\n" + knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" + end + end + + when_the_repository 'has an environment with the wrong name in the file' do + file 'environments/x.json', { 'name' => 'y' } + it 'knife upload fails' do + knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Name in remote/environments/x.json must be 'x' (is 'y')\n" + knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" + end + end + + when_the_repository 'has an environment with no name in the file' do + file 'environments/x.json', { 'description' => 'hi' } + it 'knife upload succeeds' do + knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end + end + + when_the_repository 'has a data bag with no id in the file' do + file 'data_bags/bag/x.json', { 'foo' => 'bar' } + it 'knife upload succeeds' do + knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n" + knife('diff --name-status /data_bags/bag/x.json').should_succeed '' + end end end + end # without versioned cookbooks + + with_versioned_cookbooks do + when_the_chef_server "has one of each thing" do + client 'x', '{}' + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } + data_bag 'x', { 'y' => '{}' } + environment 'x', '{}' + node 'x', '{}' + role 'x', '{}' + user 'x', '{}' - when_the_repository 'has the same environment with no name in the file' do - file 'environments/x.json', { 'description' => 'hi' } - it 'knife upload succeeds' do - knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n" - knife('diff --name-status /environments/x.json').should_succeed '' + when_the_repository 'has only top-level directories' do + directory 'clients' + directory 'cookbooks' + directory 'data_bags' + directory 'environments' + directory 'nodes' + directory 'roles' + directory 'users' + + it 'knife upload does nothing' do + knife('upload /').should_succeed '' + knife('diff --name-status /').should_succeed <<EOM +D\t/cookbooks/x-1.0.0 +D\t/data_bags/x +D\t/environments/_default.json +D\t/environments/x.json +D\t/roles/x.json +EOM + end + + it 'knife upload --purge deletes everything' do + knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n") +Deleted extra entry /cookbooks/x-1.0.0 (purge is on) +Deleted extra entry /data_bags/x (purge is on) +Deleted extra entry /environments/x.json (purge is on) +Deleted extra entry /roles/x.json (purge is on) +EOM + knife('diff --name-status /').should_succeed <<EOM +D\t/environments/_default.json +EOM + end + end + + when_the_repository 'has an identical copy of each thing' do + file 'clients/x.json', <<EOM +{} +EOM + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/y.json', <<EOM +{ + "id": "y" +} +EOM + file 'environments/_default.json', <<EOM +{ + "name": "_default", + "description": "The default Chef environment", + "cookbook_versions": { + }, + "json_class": "Chef::Environment", + "chef_type": "environment", + "default_attributes": { + }, + "override_attributes": { + } +} +EOM + file 'environments/x.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "x", + "override_attributes": { + } +} +EOM + file 'nodes/x.json', <<EOM +{} +EOM + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + file 'users/x.json', <<EOM +{} +EOM + + it 'knife upload makes no changes' do + knife('upload /cookbooks/x-1.0.0').should_succeed '' + knife('diff --name-status /').should_succeed '' + end + + it 'knife upload --purge makes no changes' do + knife('upload --purge /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end + + context 'except the role file' do + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "blarghle", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + it 'knife upload changes the role' do + knife('upload /').should_succeed "Updated /roles/x.json\n" + knife('diff --name-status /').should_succeed '' + end + end + + context 'except the role file is textually different, but not ACTUALLY different' do + file 'roles/x.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "x", + "description": "", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + it 'knife upload / does not change anything' do + knife('upload /').should_succeed '' + knife('diff --name-status /').should_succeed '' + end + end + + context 'as well as one extra copy of each thing' do + file 'clients/y.json', { 'name' => 'y' } + file 'cookbooks/x-1.0.0/blah.rb', '' + file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"' + file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"' + file 'data_bags/x/z.json', <<EOM +{ + "id": "z" +} +EOM + file 'data_bags/y/zz.json', <<EOM +{ + "id": "zz" +} +EOM + file 'environments/y.json', <<EOM +{ + "chef_type": "environment", + "cookbook_versions": { + }, + "default_attributes": { + }, + "description": "", + "json_class": "Chef::Environment", + "name": "y", + "override_attributes": { + } +} +EOM + file 'nodes/y.json', { 'name' => 'y' } + file 'roles/y.json', <<EOM +{ + "chef_type": "role", + "default_attributes": { + }, + "description": "", + "env_run_lists": { + }, + "json_class": "Chef::Role", + "name": "y", + "override_attributes": { + }, + "run_list": [ + + ] +} +EOM + file 'users/y.json', { 'name' => 'y' } + + it 'knife upload adds the new files' do + knife('upload /').should_succeed <<EOM +Updated /cookbooks/x-1.0.0 +Created /cookbooks/x-2.0.0 +Created /cookbooks/y-1.0.0 +Created /data_bags/x/z.json +Created /data_bags/y +Created /data_bags/y/zz.json +Created /environments/y.json +Created /roles/y.json +EOM + knife('diff --name-status /').should_succeed '' + end + end + end + + when_the_repository 'is empty' do + it 'knife upload does nothing' do + knife('upload /').should_succeed '' + knife('diff --name-status /').should_succeed <<EOM +D\t/cookbooks +D\t/data_bags +D\t/environments +D\t/roles +EOM + end + + it 'knife upload --purge deletes nothing' do + knife('upload --purge /').should_fail <<EOM +ERROR: /cookbooks cannot be deleted. +ERROR: /data_bags cannot be deleted. +ERROR: /environments cannot be deleted. +ERROR: /roles cannot be deleted. +EOM + knife('diff --name-status /').should_succeed <<EOM +D\t/cookbooks +D\t/data_bags +D\t/environments +D\t/roles +EOM + end + + context 'when current directory is top level' do + cwd '.' + it 'knife upload with no parameters reports an error' do + knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/ + end + end end end - end - when_the_chef_server 'is empty' do - when_the_repository 'has an environment with bad JSON' do - file 'environments/x.json', '{' - it 'knife upload tries and fails' do - knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Parse error reading JSON creating child 'x.json': A JSON text must at least contain two octets!\n" - knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" + # Test upload of an item when the other end doesn't even have the container + when_the_chef_server 'is empty' do + when_the_repository 'has two data bag items' do + file 'data_bags/x/y.json', <<EOM +{ + "id": "y" +} +EOM + file 'data_bags/x/z.json', <<EOM +{ + "id": "z" +} +EOM + it 'knife upload of one data bag item itself succeeds' do + knife('upload /data_bags/x/y.json').should_succeed <<EOM +Created /data_bags/x +Created /data_bags/x/y.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +A\t/data_bags/x/z.json +EOM + end end end - when_the_repository 'has an environment with the wrong name in the file' do - file 'environments/x.json', { 'name' => 'y' } - it 'knife upload fails' do - knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Name in remote/environments/x.json must be 'x' (is 'y')\n" - knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" + when_the_chef_server 'has three data bag items' do + data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} } + when_the_repository 'has a modified, unmodified, added and deleted data bag item' do + file 'data_bags/x/added.json', <<EOM +{ + "id": "added" +} +EOM + file 'data_bags/x/modified.json', <<EOM +{ + "id": "modified", + "foo": "bar" +} +EOM + file 'data_bags/x/unmodified.json', <<EOM +{ + "id": "unmodified" +} +EOM + it 'knife upload of the modified file succeeds' do + knife('upload /data_bags/x/modified.json').should_succeed <<EOM +Updated /data_bags/x/modified.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/deleted.json +A\t/data_bags/x/added.json +EOM + end + it 'knife upload of the unmodified file does nothing' do + knife('upload /data_bags/x/unmodified.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/deleted.json +M\t/data_bags/x/modified.json +A\t/data_bags/x/added.json +EOM + end + it 'knife upload of the added file succeeds' do + knife('upload /data_bags/x/added.json').should_succeed <<EOM +Created /data_bags/x/added.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/deleted.json +M\t/data_bags/x/modified.json +EOM + end + it 'knife upload of the deleted file does nothing' do + knife('upload /data_bags/x/deleted.json').should_succeed '' + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/deleted.json +M\t/data_bags/x/modified.json +A\t/data_bags/x/added.json +EOM + end + it 'knife upload --purge of the deleted file deletes it' do + knife('upload --purge /data_bags/x/deleted.json').should_succeed <<EOM +Deleted extra entry /data_bags/x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +M\t/data_bags/x/modified.json +A\t/data_bags/x/added.json +EOM + end + it 'knife upload of the entire data bag uploads everything' do + knife('upload /data_bags/x').should_succeed <<EOM +Created /data_bags/x/added.json +Updated /data_bags/x/modified.json +EOM + knife('diff --name-status /data_bags').should_succeed <<EOM +D\t/data_bags/x/deleted.json +EOM + end + it 'knife upload --purge of the entire data bag uploads everything' do + knife('upload --purge /data_bags/x').should_succeed <<EOM +Created /data_bags/x/added.json +Updated /data_bags/x/modified.json +Deleted extra entry /data_bags/x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed '' + end + context 'when cwd is the /data_bags directory' do + cwd 'data_bags' + it 'knife upload fails' do + knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/ + end + it 'knife upload --purge . uploads everything' do + knife('upload --purge .').should_succeed <<EOM +Created x/added.json +Updated x/modified.json +Deleted extra entry x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed '' + end + it 'knife upload --purge * uploads everything' do + knife('upload --purge *').should_succeed <<EOM +Created x/added.json +Updated x/modified.json +Deleted extra entry x/deleted.json (purge is on) +EOM + knife('diff --name-status /data_bags').should_succeed '' + end + end end end - when_the_repository 'has an environment with no name in the file' do - file 'environments/x.json', { 'description' => 'hi' } - it 'knife upload succeeds' do - knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n" - knife('diff --name-status /environments/x.json').should_succeed '' + # Cookbook upload is a funny thing ... direct cookbook upload works, but + # upload of a file is designed not to work at present. Make sure that is the + # case. + when_the_chef_server 'has a cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'z.rb' => '' } + when_the_repository 'has a modified, extra and missing file for the cookbook' do + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x-1.0.0/y.rb', 'hi' + it 'knife upload of any individual file fails' do + knife('upload /cookbooks/x-1.0.0/metadata.rb').should_fail "ERROR: /cookbooks/x-1.0.0/metadata.rb cannot be updated.\n" + knife('upload /cookbooks/x-1.0.0/y.rb').should_fail "ERROR: /cookbooks/x-1.0.0 cannot have a child created under it.\n" + knife('upload --purge /cookbooks/x-1.0.0/z.rb').should_fail "ERROR: /cookbooks/x-1.0.0/z.rb cannot be deleted.\n" + end + # TODO this is a bit of an inconsistency: if we didn't specify --purge, + # technically we shouldn't have deleted missing files. But ... cookbooks + # are a special case. + it 'knife upload of the cookbook itself succeeds' do + knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM +Updated /cookbooks/x-1.0.0 +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + it 'knife upload --purge of the cookbook itself succeeds' do + knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM +Updated /cookbooks/x-1.0.0 +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + end + when_the_repository 'has a missing file for the cookbook' do + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + it 'knife upload of the cookbook succeeds' do + knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM +Updated /cookbooks/x-1.0.0 +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + end + when_the_repository 'has an extra file for the cookbook' do + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x-1.0.0/z.rb', '' + file 'cookbooks/x-1.0.0/blah.rb', '' + it 'knife upload of the cookbook succeeds' do + knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM +Updated /cookbooks/x-1.0.0 +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end end end - when_the_repository 'has a data bag with no id in the file' do - file 'data_bags/bag/x.json', { 'foo' => 'bar' } - it 'knife upload succeeds' do - knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n" - knife('diff --name-status /data_bags/bag/x.json').should_succeed '' + when_the_repository 'has a cookbook' do + file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' + file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', 'old_text' + + when_the_chef_server 'has a later version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } + + it 'knife upload /cookbooks uploads the local version' do + knife('diff --name-status /cookbooks').should_succeed <<EOM +M\t/cookbooks/x-1.0.0/onlyin1.0.0.rb +D\t/cookbooks/x-1.0.1 +EOM + knife('upload --purge /cookbooks').should_succeed <<EOM +Updated /cookbooks/x-1.0.0 +Deleted extra entry /cookbooks/x-1.0.1 (purge is on) +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + end + + when_the_chef_server 'has an earlier version for the cookbook' do + cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } + it 'knife upload /cookbooks uploads the local version' do + knife('upload --purge /cookbooks').should_succeed <<EOM +Updated /cookbooks/x-1.0.0 +Deleted extra entry /cookbooks/x-0.9.9 (purge is on) +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + end + + when_the_chef_server 'has a later version for the cookbook, and no current version' do + cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } + + it 'knife upload /cookbooks/x uploads the local version' do + knife('diff --name-status /cookbooks').should_succeed <<EOM +D\t/cookbooks/x-1.0.1 +A\t/cookbooks/x-1.0.0 +EOM + knife('upload --purge /cookbooks').should_succeed <<EOM +Created /cookbooks/x-1.0.0 +Deleted extra entry /cookbooks/x-1.0.1 (purge is on) +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + end + + when_the_chef_server 'has an earlier version for the cookbook, and no current version' do + cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } + + it 'knife upload /cookbooks/x uploads the new version' do + knife('upload --purge /cookbooks').should_succeed <<EOM +Created /cookbooks/x-1.0.0 +Deleted extra entry /cookbooks/x-0.9.9 (purge is on) +EOM + knife('diff --name-status /cookbooks').should_succeed '' + end + end + end + + when_the_chef_server 'has an environment' do + environment 'x', {} + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife upload tries and fails' do + knife('upload /environments/x.json').should_fail "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\nERROR: /environments/x.json failed to write: Parse error reading JSON: A JSON text must at least contain two octets!\n" + knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n", :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" + end + end + + when_the_repository 'has the same environment with the wrong name in the file' do + file 'environments/x.json', { 'name' => 'y' } + it 'knife upload fails' do + knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name in remote/environments/x.json/x.json must be 'x' (is 'y')\n" + knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n" + end + end + + when_the_repository 'has the same environment with no name in the file' do + file 'environments/x.json', { 'description' => 'hi' } + it 'knife upload succeeds' do + knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end end end - end + + when_the_chef_server 'is empty' do + when_the_repository 'has an environment with bad JSON' do + file 'environments/x.json', '{' + it 'knife upload tries and fails' do + knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Parse error reading JSON creating child 'x.json': A JSON text must at least contain two octets!\n" + knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" + end + end + + when_the_repository 'has an environment with the wrong name in the file' do + file 'environments/x.json', { 'name' => 'y' } + it 'knife upload fails' do + knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Name in remote/environments/x.json must be 'x' (is 'y')\n" + knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" + end + end + + when_the_repository 'has an environment with no name in the file' do + file 'environments/x.json', { 'description' => 'hi' } + it 'knife upload succeeds' do + knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n" + knife('diff --name-status /environments/x.json').should_succeed '' + end + end + + when_the_repository 'has a data bag with no id in the file' do + file 'data_bags/bag/x.json', { 'foo' => 'bar' } + it 'knife upload succeeds' do + knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n" + knife('diff --name-status /data_bags/bag/x.json').should_succeed '' + end + end + end + end # with versioned cookbooks + end |