diff options
Diffstat (limited to 'features')
63 files changed, 1014 insertions, 176 deletions
diff --git a/features/api/cookbooks/list_cookbooks_api.feature b/features/api/cookbooks/list_cookbooks_api.feature new file mode 100644 index 0000000000..8888cfa3ce --- /dev/null +++ b/features/api/cookbooks/list_cookbooks_api.feature @@ -0,0 +1,19 @@ +@api @cookbooks @list_cookbooks +Feature: List cookbooks via the REST API + In order to know what cookbooks are loaded on the Chef Server + As a Developer + I want to list all the cookbooks + + Scenario: List cookbooks + Given a 'registration' named 'bobo' exists + When I 'GET' the path '/cookbooks' + Then the inflated responses key 'manage_files' should exist + And the inflated responses key 'manage_files' should match 'http://[^/]+/organizations/clownco/cookbooks/manage_files' + And the inflated responses key 'delayed_notifications' should exist + And the inflated responses key 'delayed_notifications' should match 'http://[^/]+/organizations/clownco/cookbooks/delayed_notifications' + + Scenario: List cookbooks with a wrong private key + Given a 'registration' named 'bobo' exists + When I 'GET' the path '/cookbooks' using a wrong private key + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/cookbooks/show_cookbook_api.feature b/features/api/cookbooks/show_cookbook_api.feature new file mode 100644 index 0000000000..48e19a2981 --- /dev/null +++ b/features/api/cookbooks/show_cookbook_api.feature @@ -0,0 +1,32 @@ +@api @cookbooks @show_cookbook +Feature: Show a cookbook via the REST API + In order to know what the details are for a cookbook + As a Developer + I want to show the details for a specific cookbook + + Scenario: Show a cookbook + Given a 'registration' named 'bobo' exists + When I 'GET' the path '/cookbooks/show_cookbook' + Then the inflated responses key 'name' should match 'show_cookbook' + Then the inflated responses key 'files' should match '^\[.+\]$' as json + Then the inflated responses key 'recipes' should match '^\[.+\]$' as json + Then the inflated responses key 'metadata' should match '^\{.+\}$' as json + Then the inflated responses key 'attributes' should match '^\[.+\]$' as json + Then the inflated responses key 'libraries' should match '^\[.+\]$' as json + Then the inflated responses key 'definitions' should match '^\[.+\]$' as json + Then the inflated responses key 'templates' should match '^\[.+\]$' as json + + Scenario: Show a missing cookbook + Given a 'registration' named 'bobo' exists + When I download the 'frabjabtasticaliciousmonkeyman' cookbook + Then the response code should be '404' + + Scenario: Show a cookbook with a wrong private key + Given a 'registration' named 'bobo' exists + When I 'GET' the path '/cookbooks/show_cookbook' using a wrong private key + Then I should get a '401 "Unauthorized"' exception + + Scenario: Show a cookbook without authenticating + When I 'GET' the path '/cookbooks/show_cookbook' + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/cookbooks/show_cookbook_attributes_api.feature b/features/api/cookbooks/show_cookbook_attributes_api.feature new file mode 100644 index 0000000000..8e4fc0cd1a --- /dev/null +++ b/features/api/cookbooks/show_cookbook_attributes_api.feature @@ -0,0 +1,21 @@ +@api @cookbooks +Feature: Show a cookbooks attribute files via the REST API + In order to know what the details are for a cookbooks attribute files + As a Developer + I want to show the attribute files for a specific cookbook + + Scenario: Show a cookbooks attribute files + Given a 'registration' named 'bobo' exists + When I 'GET' the path '/cookbooks/show_cookbook/attributes' + Then the inflated response should match '^[.+]$' as json + + Scenario: Show a missing cookbook + Given a 'registration' named 'bobo' exists + When I 'GET' the path '/cookbooks/frabjabtasticaliciousmonkeyman/attributes' + Then I should get a '404 "Not Found"' exception + + Scenario: Show a cookbooks attribute files with a wrong private key + Given a 'registration' named 'bobo' exists + When I 'GET' the path '/cookbooks/show_cookbook/attributes' using a wrong private key + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/data/create_data_bag_api.feature b/features/api/data/create_data_bag_api.feature new file mode 100644 index 0000000000..c76018b2f0 --- /dev/null +++ b/features/api/data/create_data_bag_api.feature @@ -0,0 +1,26 @@ +@api @data @api_data +Feature: Create a data bag via the REST API + In order to create data bags programatically + As a Devleoper + I want to create data bags via the REST API + + Scenario: Create a new data bag + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' + When I authenticate as 'bobo' + And I 'POST' the 'data_bag' to the path '/data' + And the inflated responses key 'uri' should match '^http://.+/data/users$' + + Scenario: Create a data bag that already exists + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' + When I authenticate as 'bobo' + And I 'POST' the 'data_bag' to the path '/data' + And I 'POST' the 'data_bag' to the path '/data' + Then I should get a '403 "Forbidden"' exception + + Scenario: Create a new data bag without authenticating + Given a 'data_bag' named 'webserver' + When I 'POST' the 'data_bag' to the path '/data' + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/data/create_data_bag_item_api.feature b/features/api/data/create_data_bag_item_api.feature new file mode 100644 index 0000000000..ebd9637b2b --- /dev/null +++ b/features/api/data/create_data_bag_item_api.feature @@ -0,0 +1,29 @@ +@api @data @api_data @api_data_item +Feature: Create a data bag item via the REST API + In order to store an item in a data bag programatically + As a Devleoper + I want to store data bag items via the REST API + + Scenario: Create a new data bag item + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' + When I authenticate as 'bobo' + And I 'PUT' the 'data_bag_item' to the path '/data/users/francis' + Then the inflated responses key 'id' should match '^francis$' + + Scenario: Update a data bag item that already exists + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'francis_extra' + When I authenticate as 'bobo' + And I 'PUT' the 'data_bag_item' to the path '/data/users/francis' + Then the inflated responses key 'id' should match '^francis$' + And the inflated responses key 'extra' should match '^majority$' + + Scenario: Create a new data bag without authenticating + Given a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' + When I 'PUT' the 'data_bag_item' to the path '/data/users/francis' + Then I should get a '401 "Unauthorized"' exception diff --git a/features/api/data/delete_data_bag_api.feature b/features/api/data/delete_data_bag_api.feature new file mode 100644 index 0000000000..560d1e3ea6 --- /dev/null +++ b/features/api/data/delete_data_bag_api.feature @@ -0,0 +1,34 @@ +@api @data @api_data @api_data_delete +Feature: Delete a Data Bag via the REST API + In order to remove a Data Bag + As a Developer + I want to delete a Data Bag via the REST API + + Scenario: Delete a Data Bag + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + When I authenticate as 'bobo' + And I 'DELETE' the path '/data/users' + Then the inflated response should respond to 'name' with 'users' + + Scenario: Delete a Data Bag that does not exist + Given a 'registration' named 'bobo' exists + And there are no Data Bags + When I authenticate as 'bobo' + When I 'DELETE' the path '/data/users' + Then I should get a '404 "Not Found"' exception + + Scenario: Delete a Data Bag that has items in it + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + When I authenticate as 'bobo' + And I 'DELETE' the path '/data/users' + Then the inflated response should respond to 'name' with 'users' + And the data_bag named 'users' should not have an item named 'francis' + + Scenario: Delete a Data Bag without authenticating + Given a 'data_bag' named 'users' exists + When I 'DELETE' the path '/data/users' + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/data/delete_data_bag_item.feature b/features/api/data/delete_data_bag_item.feature new file mode 100644 index 0000000000..057c2e55ec --- /dev/null +++ b/features/api/data/delete_data_bag_item.feature @@ -0,0 +1,27 @@ +@api @data @api_data @api_data_item +Feature: Delete a Data Bag Item via the REST API + In order to remove a Data Bag Item + As a Developer + I want to delete a Data Bag Item via the REST API + + Scenario: Delete a Data Bag Item + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + When I authenticate as 'bobo' + And I 'DELETE' the path '/data/users/francis' + Then the inflated responses key 'id' should match '^francis$' + + Scenario: Delete a Data Bag Item that does not exist + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + When I authenticate as 'bobo' + When I 'DELETE' the path '/data/users/francis' + Then I should get a '404 "Not Found"' exception + + Scenario: Delete a Data Bag Item without authenticating + Given a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + When I 'DELETE' the path '/data/users/francis' + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/data/list_data_bags.feature b/features/api/data/list_data_bags.feature new file mode 100644 index 0000000000..97929d7747 --- /dev/null +++ b/features/api/data/list_data_bags.feature @@ -0,0 +1,34 @@ +@api @data @api_data +Feature: List data bags via the REST API + In order to know what data bags exists programatically + As a Developer + I want to list all the data bags + + Scenario: List data bags when none have been created + Given a 'registration' named 'bobo' exists + And there are no data bags + When I authenticate as 'bobo' + And I 'GET' the path '/data' + Then the inflated response should be an empty array + + Scenario: List data bags when one has been created + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + When I authenticate as 'bobo' + And I 'GET' the path '/data' + Then the inflated response should include '^http://.+/data/users$' + + Scenario: List data bags when two have been created + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag' named 'rubies' exists + When I authenticate as 'bobo' + And I 'GET' the path '/data' + Then the inflated response should be '2' items long + And the inflated response should include '^http://.+/data/users$' + And the inflated response should include '^http://.+/data/rubies$' + + Scenario: List data bags when you are not authenticated + When I 'GET' the path '/data' + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/data/show_data_bag_api.feature b/features/api/data/show_data_bag_api.feature new file mode 100644 index 0000000000..d27f64093a --- /dev/null +++ b/features/api/data/show_data_bag_api.feature @@ -0,0 +1,44 @@ +@api @data @api_data +Feature: Show a data_bag via the REST API + In order to know what the details are for a data_bag + As a Developer + I want to show the details for a specific data_bag + + Scenario: Show a data_bag with no entries in it + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + When I authenticate as 'bobo' + And I 'GET' the path '/data/users' + Then the inflated response should be an empty array + + Scenario: Show a data_bag with one entry in it + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + When I authenticate as 'bobo' + And I 'GET' the path '/data/users' + Then the inflated response should include '/data/users/francis' + + Scenario: Show a data_bag with two entries in it + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists + When I authenticate as 'bobo' + And I 'GET' the path '/data/users' + Then the inflated response should include '/data/users/francis' + And the inflated response should include '/data/users/axl_rose' + + Scenario: Show a missing data_bag + Given a 'registration' named 'bobo' exists + And there are no data_bags + When I authenticate as 'bobo' + And I 'GET' the path '/data/users' + Then I should get a '404 "Not Found"' exception + + Scenario: Show a data_bag without authenticating + Given a 'data_bag' named 'users' exists + And I 'GET' the path '/data/users' + Then I should get a '401 "Unauthorized"' exception + + diff --git a/features/api/data/show_data_bag_item_api.feature b/features/api/data/show_data_bag_item_api.feature new file mode 100644 index 0000000000..fd0e474224 --- /dev/null +++ b/features/api/data/show_data_bag_item_api.feature @@ -0,0 +1,28 @@ +@api @data @api_data @api_data_item +Feature: Show a data_bag item via the REST API + In order to know what the data is for an item in a data_bag + As a Developer + I want to retrieve an item from a data_bag + + Scenario: Show a data_bag item + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + When I authenticate as 'bobo' + And I 'GET' the path '/data/users/francis' + Then the inflated responses key 'id' should match '^francis$' + + Scenario: Show a missing data_bag item + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + When I authenticate as 'bobo' + And I 'GET' the path '/data/users/francis' + Then I should get a '404 "Not Found"' exception + + Scenario: Show a data_bag item without authenticating + Given a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And I 'GET' the path '/data/users/francis' + Then I should get a '401 "Unauthorized"' exception + + diff --git a/features/api/nodes/cookbook_sync_api.feature b/features/api/nodes/cookbook_sync_api.feature new file mode 100644 index 0000000000..3d39796166 --- /dev/null +++ b/features/api/nodes/cookbook_sync_api.feature @@ -0,0 +1,25 @@ +@api @nodes @cookbook_sync @api_nodes +Feature: Synchronize cookbooks to the edge + In order to configure my nodes centrally + As a Developer + I want to synchronize the cookbooks from the server to the edge nodes + + Scenario: Retrieve the list of cookbook files to synchronize + Given a 'registration' named 'bobo' exists + And a 'node' named 'sync' exists + When I 'GET' the path '/nodes/sync/cookbooks' + And the inflated responses key 'node_cookbook_sync' should exist + And the inflated responses key 'node_cookbook_sync' should match '"recipes":' as json + And the inflated responses key 'node_cookbook_sync' should match 'default.rb' as json + And the inflated responses key 'node_cookbook_sync' should match '"definitions":' as json + And the inflated responses key 'node_cookbook_sync' should match 'def_file.rb' as json + And the inflated responses key 'node_cookbook_sync' should match '"libraries":' as json + And the inflated responses key 'node_cookbook_sync' should match 'lib_file.rb' as json + And the inflated responses key 'node_cookbook_sync' should match '"attributes":' as json + And the inflated responses key 'node_cookbook_sync' should match 'attr_file.rb' as json + + Scenario: Retrieve the list of cookbook files to synchronize with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'node' named 'sync' exists + When I 'GET' the path '/nodes/sync/cookbooks' using a wrong private key + Then I should get a '401 "Unauthorized"' exception
\ No newline at end of file diff --git a/features/api/nodes/create_node_api.feature b/features/api/nodes/create_node_api.feature index 5012a8a357..ec5bbb73be 100644 --- a/features/api/nodes/create_node_api.feature +++ b/features/api/nodes/create_node_api.feature @@ -1,4 +1,4 @@ -@api @nodes @nodes_create +@api @api_nodes @nodes_create Feature: Create a node via the REST API In order to create nodes programatically As a Devleoper @@ -7,19 +7,19 @@ Feature: Create a node via the REST API Scenario: Create a new node Given a 'registration' named 'bobo' exists And a 'node' named 'webserver' - When I authenticate as 'bobo' - And I 'POST' the 'node' to the path '/nodes' + When I 'POST' the 'node' to the path '/nodes' And the inflated responses key 'uri' should match '^http://.+/nodes/webserver$' Scenario: Create a node that already exists Given a 'registration' named 'bobo' exists And an 'node' named 'webserver' - When I authenticate as 'bobo' - And I 'POST' the 'node' to the path '/nodes' + When I 'POST' the 'node' to the path '/nodes' And I 'POST' the 'node' to the path '/nodes' Then I should get a '403 "Forbidden"' exception - - Scenario: Create a new node without authenticating - Given a 'node' named 'webserver' - When I 'POST' the 'node' to the path '/nodes' + + Scenario: Create a node with a wrong private key + Given a 'registration' named 'bobo' exists + And an 'node' named 'webserver' + When I 'POST' the 'node' to the path '/nodes' using a wrong private key Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/nodes/delete_node_api.feature b/features/api/nodes/delete_node_api.feature index 7addc6e790..46c027561d 100644 --- a/features/api/nodes/delete_node_api.feature +++ b/features/api/nodes/delete_node_api.feature @@ -1,4 +1,4 @@ -@api @nodes @nodes_delete +@api @api_nodes @nodes_delete Feature: Delete a node via the REST API In order to remove a node As a Developer @@ -7,19 +7,18 @@ Feature: Delete a node via the REST API Scenario: Delete a node Given a 'registration' named 'bobo' exists And a 'node' named 'webserver' exists - When I authenticate as 'bobo' - And I 'DELETE' the path '/nodes/webserver' + When I 'DELETE' the path '/nodes/webserver' Then the inflated response should respond to 'name' with 'webserver' Scenario: Delete a node that does not exist Given a 'registration' named 'bobo' exists And there are no nodes - When I authenticate as 'bobo' When I 'DELETE' the path '/nodes/webserver' Then I should get a '404 "Not Found"' exception - Scenario: Delete a node without authenticating - Given a 'node' named 'webserver' - When I 'DELETE' the path '/nodes/webserver' + Scenario: Delete a node with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'node' named 'webserver' exists + When I 'DELETE' the path '/nodes/webserver' using a wrong private key Then I should get a '401 "Unauthorized"' exception diff --git a/features/api/nodes/list_nodes_api.feature b/features/api/nodes/list_nodes_api.feature index 4489c4d49a..7127720947 100644 --- a/features/api/nodes/list_nodes_api.feature +++ b/features/api/nodes/list_nodes_api.feature @@ -1,4 +1,4 @@ -@api @nodes @nodes_list +@api @api_nodes @nodes_list Feature: List nodes via the REST API In order to know what nodes exists programatically As a Developer @@ -7,28 +7,26 @@ Feature: List nodes via the REST API Scenario: List nodes when none have been created Given a 'registration' named 'bobo' exists And there are no nodes - When I authenticate as 'bobo' - And I 'GET' the path '/nodes' + When I 'GET' the path '/nodes' Then the inflated response should be an empty array Scenario: List nodes when one has been created Given a 'registration' named 'bobo' exists Given a 'node' named 'webserver' exists - When I authenticate as 'bobo' - And I 'GET' the path '/nodes' + When I 'GET' the path '/nodes' Then the inflated response should include '^http://.+/nodes/webserver$' - + Scenario: List nodes when two have been created Given a 'registration' named 'bobo' exists And a 'node' named 'webserver' exists And a 'node' named 'dbserver' exists - When I authenticate as 'bobo' - And I 'GET' the path '/nodes' + When I 'GET' the path '/nodes' Then the inflated response should be '2' items long And the inflated response should include '^http://.+/nodes/webserver$' And the inflated response should include '^http://.+/nodes/dbserver$' - Scenario: List nodes when you are not authenticated - When I 'GET' the path '/nodes' + Scenario: List nodes none have been created with a wrong private key + Given a 'registration' named 'bobo' exists + And there are no cookbooks + When I 'GET' the path '/nodes' using a wrong private key Then I should get a '401 "Unauthorized"' exception - diff --git a/features/api/nodes/show_node_api.feature b/features/api/nodes/show_node_api.feature index 8a2ab2990d..e26d127a06 100644 --- a/features/api/nodes/show_node_api.feature +++ b/features/api/nodes/show_node_api.feature @@ -1,4 +1,4 @@ -@api @nodes @nodes_show +@api @api_nodes @nodes_show Feature: Show a node via the REST API In order to know what the details are for a node As a Developer @@ -7,19 +7,18 @@ Feature: Show a node via the REST API Scenario: Show a node Given a 'registration' named 'bobo' exists And a 'node' named 'webserver' exists - When I authenticate as 'bobo' - And I 'GET' the path '/nodes/webserver' + When I 'GET' the path '/nodes/webserver' Then the inflated response should respond to 'name' with 'webserver' Scenario: Show a missing node Given a 'registration' named 'bobo' exists And there are no nodes - When I authenticate as 'bobo' - And I 'GET' the path '/nodes/bobo' + When I 'GET' the path '/nodes/bobo' Then I should get a '404 "Not Found"' exception - Scenario: Show a node without authenticating - Given a 'node' named 'webserver' exists - And I 'GET' the path '/nodes/webserver' + Scenario: Show a node with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'node' named 'webserver' exists + When I 'GET' the path '/nodes/webserver' using a wrong private key Then I should get a '401 "Unauthorized"' exception diff --git a/features/api/nodes/update_node_api.feature b/features/api/nodes/update_node_api.feature index ecf512f64f..4f6ad41f1b 100644 --- a/features/api/nodes/update_node_api.feature +++ b/features/api/nodes/update_node_api.feature @@ -1,4 +1,4 @@ -@api @nodes @nodes_update +@api @api_nodes @nodes_update Feature: Update a node In order to keep my node data up-to-date As a Developer @@ -8,7 +8,6 @@ Feature: Update a node Given a 'registration' named 'bobo' exists And a 'node' named 'webserver' exists And sending the method '<method>' to the 'node' with '<updated_value>' - When I authenticate as 'bobo' When I 'PUT' the 'node' to the path '/nodes/webserver' Then the inflated response should respond to '<method>' with '<updated_value>' When I 'GET' the path '/nodes/webserver' @@ -19,9 +18,10 @@ Feature: Update a node | run_list | [ "recipe[one]", "recipe[two]" ] | | snakes | really arent so bad | - Scenario: Update a node without authenticating - Given a 'node' named 'webserver' - And sending the method 'snakes' to the 'node' with 'night train' - When I 'PUT' the 'node' to the path '/nodes/webserver' - Then I should get a '401 "Unauthorized"' exception + Scenario Outline: Update a node with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'node' named 'webserver' exists + And sending the method 'run_list' to the 'node' with '[ "recipe[one]", "recipe[two]" ]' + When I 'PUT' the 'node' to the path '/nodes/webserver' using a wrong private key + Then I should get a '401 "Unauthorized"' exception diff --git a/features/api/roles/create_role_api.feature b/features/api/roles/create_role_api.feature index 7b04b64294..4282400c7f 100644 --- a/features/api/roles/create_role_api.feature +++ b/features/api/roles/create_role_api.feature @@ -1,4 +1,4 @@ -@api @roles @roles_create +@api @api_roles @roles_create Feature: Create a role via the REST API In order to create roles programatically As a Devleoper @@ -7,20 +7,18 @@ Feature: Create a role via the REST API Scenario: Create a new role Given a 'registration' named 'bobo' exists And a 'role' named 'webserver' - When I authenticate as 'bobo' - And I 'POST' the 'role' to the path '/roles' + When I 'POST' the 'role' to the path '/roles' And the inflated responses key 'uri' should match '^http://.+/roles/webserver$' Scenario: Create a role that already exists Given a 'registration' named 'bobo' exists And an 'role' named 'webserver' - When I authenticate as 'bobo' - And I 'POST' the 'role' to the path '/roles' + When I 'POST' the 'role' to the path '/roles' And I 'POST' the 'role' to the path '/roles' Then I should get a '403 "Forbidden"' exception - Scenario: Create a new role without authenticating - Given a 'role' named 'webserver' - When I 'POST' the 'role' to the path '/roles' + Scenario: Create a new role with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'role' named 'webserver' + When I 'POST' the 'role' to the path '/roles' using a wrong private key Then I should get a '401 "Unauthorized"' exception - diff --git a/features/api/roles/delete_role_api.feature b/features/api/roles/delete_role_api.feature index c6504741f9..0dab4128af 100644 --- a/features/api/roles/delete_role_api.feature +++ b/features/api/roles/delete_role_api.feature @@ -1,4 +1,4 @@ -@api @roles @roles_delete +@api @api_roles @roles_delete Feature: Delete a Role via the REST API In order to remove a role As a Developer @@ -7,19 +7,18 @@ Feature: Delete a Role via the REST API Scenario: Delete a Role Given a 'registration' named 'bobo' exists And a 'role' named 'webserver' exists - When I authenticate as 'bobo' - And I 'DELETE' the path '/roles/webserver' + When I 'DELETE' the path '/roles/webserver' Then the inflated response should respond to 'name' with 'webserver' Scenario: Delete a Role that does not exist Given a 'registration' named 'bobo' exists And there are no roles - When I authenticate as 'bobo' When I 'DELETE' the path '/roles/webserver' Then I should get a '404 "Not Found"' exception - - Scenario: Delete a Role without authenticating - Given a 'role' named 'webserver' - When I 'DELETE' the path '/roles/webserver' + + Scenario: Delete a Role with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'role' named 'webserver' exists + When I 'DELETE' the path '/roles/webserver' using a wrong private key Then I should get a '401 "Unauthorized"' exception diff --git a/features/api/roles/list_roles_api.feature b/features/api/roles/list_roles_api.feature index edc96e0869..72251d2251 100644 --- a/features/api/roles/list_roles_api.feature +++ b/features/api/roles/list_roles_api.feature @@ -1,4 +1,4 @@ -@api @roles @roles_list +@api @api_roles @roles_list Feature: List roles via the REST API In order to know what roles exists programatically As a Developer @@ -6,30 +6,29 @@ Feature: List roles via the REST API Scenario: List roles when none have been created Given a 'registration' named 'bobo' exists - And there are no roles - When I authenticate as 'bobo' - And I 'GET' the path '/roles' - Then the inflated response should be an empty array + And there are no roles + When I 'GET' the path '/roles' + Then the inflated response should be '1' items long Scenario: List roles when one has been created Given a 'registration' named 'bobo' exists Given a 'role' named 'webserver' exists - When I authenticate as 'bobo' - And I 'GET' the path '/roles' + When I 'GET' the path '/roles' Then the inflated response should include '^http://.+/roles/webserver$' Scenario: List roles when two have been created Given a 'registration' named 'bobo' exists And a 'role' named 'webserver' exists And a 'role' named 'db' exists - When I authenticate as 'bobo' - And I 'GET' the path '/roles' + When I 'GET' the path '/roles' Then the inflated response should be '3' items long And the inflated response should include '^http://.+/roles/role_test$' And the inflated response should include '^http://.+/roles/webserver$' And the inflated response should include '^http://.+/roles/db$' - Scenario: List roles when you are not authenticated - When I 'GET' the path '/roles' + Scenario: List roles when none have been created with a wrong private key + Given a 'registration' named 'bobo' exists + And there are no roles + When I 'GET' the path '/roles' using a wrong private key Then I should get a '401 "Unauthorized"' exception diff --git a/features/api/roles/show_roles_api.feature b/features/api/roles/show_roles_api.feature index 70fe4aad60..5a7a5e2734 100644 --- a/features/api/roles/show_roles_api.feature +++ b/features/api/roles/show_roles_api.feature @@ -1,4 +1,4 @@ -@api @roles @roles_show +@api @api_roles @roles_show Feature: Show a role via the REST API In order to know what the details are for a Role As a Developer @@ -7,20 +7,18 @@ Feature: Show a role via the REST API Scenario: Show a role Given a 'registration' named 'bobo' exists And a 'role' named 'webserver' exists - When I authenticate as 'bobo' - And I 'GET' the path '/roles/webserver' + When I 'GET' the path '/roles/webserver' Then the inflated response should respond to 'name' with 'webserver' Scenario: Show a missing role Given a 'registration' named 'bobo' exists And there are no roles - When I authenticate as 'bobo' - And I 'GET' the path '/roles/bobo' + When I 'GET' the path '/roles/bobo' Then I should get a '404 "Not Found"' exception - Scenario: Show a role without authenticating - Given a 'role' named 'webserver' exists - And I 'GET' the path '/roles/webserver' + Scenario: Show a role with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'role' named 'webserver' exists + When I 'GET' the path '/roles/webserver' using a wrong private key Then I should get a '401 "Unauthorized"' exception - diff --git a/features/api/roles/update_roles_api.feature b/features/api/roles/update_roles_api.feature index 90a6282577..ea72f68c05 100644 --- a/features/api/roles/update_roles_api.feature +++ b/features/api/roles/update_roles_api.feature @@ -1,4 +1,4 @@ -@api @roles @roles_update +@api @api_roles @roles_update Feature: Update a role In order to keep my role data up-to-date As a Developer @@ -8,7 +8,6 @@ Feature: Update a role Given a 'registration' named 'bobo' exists And a 'role' named 'webserver' exists And sending the method '<method>' to the 'role' with '<updated_value>' - When I authenticate as 'bobo' When I 'PUT' the 'role' to the path '/roles/webserver' Then the inflated response should respond to '<method>' with '<updated_value>' When I 'GET' the path '/roles/webserver' @@ -21,9 +20,9 @@ Feature: Update a role | default_attributes | { "a": "d" } | | override_attributes | { "c": "e" } | - Scenario: Update a role without authenticating - Given a 'role' named 'webserver' - And sending the method 'description' to the 'role' with 'Is easy' - When I 'PUT' the 'role' to the path '/roles/webserver' + Scenario Outline: Update a role with a wrong private key + Given a 'registration' named 'bobo' exists + And a 'role' named 'webserver' exists + And sending the method '<method>' to the 'role' with '<updated_value>' + When I 'PUT' the 'role' to the path '/roles/webserver' using a wrong private key Then I should get a '401 "Unauthorized"' exception - diff --git a/features/api/search/list_search.feature b/features/api/search/list_search.feature new file mode 100644 index 0000000000..198f065f12 --- /dev/null +++ b/features/api/search/list_search.feature @@ -0,0 +1,29 @@ +@api @data @api_search @api_search_list +Feature: List search endpoints via the REST API + In order to know what search endpoints exist programatically + As a Developer + I want to list all the search indexes + + Scenario: List search indexes when no data bags have been created + Given a 'registration' named 'bobo' exists + And there are no data bags + When I authenticate as 'bobo' + And I 'GET' the path '/search' + Then the inflated response should include '^http://(.+)/search/node$' + And the inflated response should include '^http://(.+)/search/role$' + And the inflated response should be '2' items long + + Scenario: List search indexes when a data bag has been created + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + When I authenticate as 'bobo' + And I 'GET' the path '/search' + Then the inflated response should include '^http://(.+)/search/node$' + And the inflated response should include '^http://(.+)/search/role$' + And the inflated response should include '^http://(.+)/search/users$' + And the inflated response should be '3' items long + + Scenario: List search indexes when you are not authenticated + When I 'GET' the path '/search' + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/api/search/show_search.feature b/features/api/search/show_search.feature new file mode 100644 index 0000000000..292d043b0d --- /dev/null +++ b/features/api/search/show_search.feature @@ -0,0 +1,115 @@ +@api @data @api_search @api_search_show +Feature: Search data via the REST API + In order to know about objects in the system + As a Developer + I want to search the objects + + Scenario: Search for objects when none have been created + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + When I authenticate as 'bobo' + And I 'GET' the path '/search/users' + Then the inflated responses key 'rows' should be '0' items long + And the inflated responses key 'start' should be the integer '0' + And the inflated responses key 'total' should be the integer '0' + + Scenario: Search for objects when one has been created + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And I wait for '10' seconds + When I authenticate as 'bobo' + And I 'GET' the path '/search/users' + Then the inflated responses key 'rows' item '0' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '0' key 'id' should be 'francis' + And the inflated responses key 'start' should be the integer '0' + And the inflated responses key 'total' should be the integer '1' + + Scenario: Search for objects when two have been created + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists + And I wait for '10' seconds + When I authenticate as 'bobo' + And I 'GET' the path '/search/users' + Then the inflated responses key 'rows' item '0' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '0' key 'id' should be 'francis' + And the inflated responses key 'rows' item '1' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '1' key 'id' should be 'axl_rose' + And the inflated responses key 'start' should be the integer '0' + And the inflated responses key 'total' should be the integer '2' + + Scenario: Search for objects with a manual ascending sort order + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists + And I wait for '10' seconds + When I authenticate as 'bobo' + And I 'GET' the path '/search/users?sort=id+asc' + Then the inflated responses key 'rows' item '0' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '0' key 'id' should be 'axl_rose' + And the inflated responses key 'rows' item '1' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '1' key 'id' should be 'francis' + And the inflated responses key 'start' should be the integer '0' + And the inflated responses key 'total' should be the integer '2' + + Scenario: Search for objects with a manual descending sort order + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists + And I wait for '10' seconds + When I authenticate as 'bobo' + And I 'GET' the path '/search/users?sort=id+desc' + Then the inflated responses key 'rows' item '0' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '0' key 'id' should be 'francis' + And the inflated responses key 'rows' item '1' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '1' key 'id' should be 'axl_rose' + And the inflated responses key 'start' should be the integer '0' + And the inflated responses key 'total' should be the integer '2' + + Scenario: Search for objects and page through the results + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists + And I wait for '10' seconds + When I authenticate as 'bobo' + And I 'GET' the path '/search/users?rows=1&sort=id+asc' + Then the inflated responses key 'rows' item '0' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '0' key 'id' should be 'axl_rose' + And the inflated responses key 'rows' should be '1' items long + And the inflated responses key 'start' should be the integer '0' + And the inflated responses key 'total' should be the integer '2' + When I 'GET' the path '/search/users?rows=1&start=1&sort=id+asc' + Then the inflated responses key 'rows' item '0' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '0' key 'id' should be 'francis' + And the inflated responses key 'rows' should be '1' items long + And the inflated responses key 'start' should be the integer '1' + And the inflated responses key 'total' should be the integer '2' + + Scenario: Search for a subset of objects + Given a 'registration' named 'bobo' exists + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists + And I wait for '10' seconds + When I authenticate as 'bobo' + And I 'GET' the path '/search/users?q=id:axl_rose' + Then the inflated responses key 'rows' item '0' should be a kind of 'Chef::DataBagItem' + And the inflated responses key 'rows' item '0' key 'id' should be 'axl_rose' + And the inflated responses key 'start' should be the integer '0' + And the inflated responses key 'total' should be the integer '1' + + Scenario: Search for a type of object that does not exist + Given a 'registration' named 'bobo' exists + When I authenticate as 'bobo' + And I 'GET' the path '/search/funkensteins' + Then I should get a '404 "Not Found"' exception + + Scenario: Search for objects when you are not authenticated + When I 'GET' the path '/search/users' + Then I should get a '401 "Unauthorized"' exception + diff --git a/features/data/config/client.rb b/features/data/config/client.rb index ab10d750df..5e51b26c82 100644 --- a/features/data/config/client.rb +++ b/features/data/config/client.rb @@ -6,9 +6,15 @@ log_location STDOUT file_cache_path File.join(tmpdir, "cache") ssl_verify_mode :verify_none registration_url "http://127.0.0.1:4000" -openid_url "http://127.0.0.1:4001" +openid_url "http://127.0.0.1:4000" template_url "http://127.0.0.1:4000" remotefile_url "http://127.0.0.1:4000" search_url "http://127.0.0.1:4000" -role_url "http://127.0.0.1:4000" -couchdb_database 'chef_integration' +role_url "http://127.0.0.1:4000" +client_url "http://127.0.0.1:4000" +chef_server_url "http://127.0.0.1:4000" +validation_client_name "validator" +systmpdir = File.expand_path(File.join(Dir.tmpdir, "chef_integration")) +validation_key File.join(systmpdir, "validation.pem") +client_key File.join(systmpdir, "client.pem") + diff --git a/features/data/config/server.rb b/features/data/config/server.rb index 51a7bacef0..cc7db3a232 100644 --- a/features/data/config/server.rb +++ b/features/data/config/server.rb @@ -6,17 +6,30 @@ log_location STDOUT file_cache_path File.join(tmpdir, "cache") ssl_verify_mode :verify_none registration_url "http://127.0.0.1:4000" -openid_url "http://127.0.0.1:4001" +openid_url "http://127.0.0.1:4000" template_url "http://127.0.0.1:4000" remotefile_url "http://127.0.0.1:4000" search_url "http://127.0.0.1:4000" -role_url "http://127.0.0.1:4000" +role_url "http://127.0.0.1:4000" +chef_server_url "http://127.0.0.1:4000" +client_url "http://127.0.0.1:4000" cookbook_path File.join(supportdir, "cookbooks") openid_store_path File.join(tmpdir, "openid", "store") openid_cstore_path File.join(tmpdir, "openid", "cstore") search_index_path File.join(tmpdir, "search_index") role_path File.join(supportdir, "roles") -validation_token 'ceelo' couchdb_database 'chef_integration' +systmpdir = File.expand_path(File.join(Dir.tmpdir, "chef_integration")) + +validation_client_name "validator" +validation_key File.join(systmpdir, "validation.pem") +client_key File.join(systmpdir, "client.pem") + +solr_jetty_path File.join(supportdir, "solr", "jetty") +solr_heap_size "250M" +solr_data_path File.join(supportdir, "solr", "data") +solr_home_path File.join(supportdir, "solr", "home") +solr_heap_size "256M" + Chef::Log::Formatter.show_time = true diff --git a/features/data/cookbooks/integration_setup/recipes/default.rb b/features/data/cookbooks/integration_setup/recipes/default.rb index 0ada2aa485..fc913b4502 100644 --- a/features/data/cookbooks/integration_setup/recipes/default.rb +++ b/features/data/cookbooks/integration_setup/recipes/default.rb @@ -19,7 +19,7 @@ directory node[:int][:tmpdir] do owner "root" - mode 1777 + mode "1777" action :create end diff --git a/features/data/cookbooks/node_cookbook_sync/README.rdoc b/features/data/cookbooks/node_cookbook_sync/README.rdoc new file mode 100644 index 0000000000..8d774805b9 --- /dev/null +++ b/features/data/cookbooks/node_cookbook_sync/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/features/data/cookbooks/node_cookbook_sync/attributes/attr_file.rb b/features/data/cookbooks/node_cookbook_sync/attributes/attr_file.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/node_cookbook_sync/attributes/attr_file.rb diff --git a/features/data/cookbooks/node_cookbook_sync/definitions/def_file.rb b/features/data/cookbooks/node_cookbook_sync/definitions/def_file.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/node_cookbook_sync/definitions/def_file.rb diff --git a/features/data/cookbooks/node_cookbook_sync/libraries/lib_file.rb b/features/data/cookbooks/node_cookbook_sync/libraries/lib_file.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/node_cookbook_sync/libraries/lib_file.rb diff --git a/features/data/cookbooks/node_cookbook_sync/metadata.rb b/features/data/cookbooks/node_cookbook_sync/metadata.rb new file mode 100644 index 0000000000..850a993fbb --- /dev/null +++ b/features/data/cookbooks/node_cookbook_sync/metadata.rb @@ -0,0 +1,6 @@ +maintainer "Opscode" +maintainer_email "do_not_reply@opscode.com" +license "Apache 2.0" +description "Installs/Configures node_cookbook_sync" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" diff --git a/features/data/cookbooks/node_cookbook_sync/recipes/default.rb b/features/data/cookbooks/node_cookbook_sync/recipes/default.rb new file mode 100644 index 0000000000..7912164bf3 --- /dev/null +++ b/features/data/cookbooks/node_cookbook_sync/recipes/default.rb @@ -0,0 +1,18 @@ +# +# Cookbook Name:: node_cookbook_sync +# Recipe:: default +# +# Copyright 2009, Opscode +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/features/data/cookbooks/search/recipes/search_data.rb b/features/data/cookbooks/search/recipes/search_data.rb index 6113da356f..6deefed9b3 100644 --- a/features/data/cookbooks/search/recipes/search_data.rb +++ b/features/data/cookbooks/search/recipes/search_data.rb @@ -17,11 +17,12 @@ # limitations under the License. # -node.save -sleep 5 -search(:node, "*") do |entry| - Chef::Log.error(entry.inspect) - entry["search_files"].each do |filename| - file "#{node[:tmpdir]}/#{filename}" - end +# We have to sleep at least 10 seconds to confirm that the data has made it +# into the index. We can only rely on this because we are in a test environment +# in real-land Chef, the index is only eventually consistent.. and may take a +# variable amount of time. +sleep 10 +search(:users, "*:*") do |entry| + file "#{node[:tmpdir]}/#{entry["id"]}" end + diff --git a/features/steps/couchdb_steps.rb b/features/data/cookbooks/search/recipes/search_data_noblock.rb index be8b84db0a..6fb9de6d81 100644 --- a/features/steps/couchdb_steps.rb +++ b/features/data/cookbooks/search/recipes/search_data_noblock.rb @@ -1,7 +1,8 @@ # -# Author:: Adam Jacob (<adam@opscode.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. -# License:: Apache License, Version 2.0 +# Cookbook Name:: search +# Recipe:: default +# +# Copyright 2009, Opscode # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,18 +17,16 @@ # limitations under the License. # -Before do - system("mkdir -p #{tmpdir}") - cdb = Chef::CouchDB.new(Chef::Config[:couchdb_url]) - cdb.create_db - Chef::Node.create_design_document - Chef::Role.create_design_document - Chef::Role.sync_from_disk_to_couchdb - Chef::OpenIDRegistration.create_design_document -end +# We have to sleep at least 10 seconds to confirm that the data has made it +# into the index. We can only rely on this because we are in a test environment +# in real-land Chef, the index is only eventually consistent.. and may take a +# variable amount of time. + -After do - r = Chef::REST.new(Chef::Config[:couchdb_url]) - r.delete_rest("#{Chef::Config[:couchdb_database]}/") - system("rm -rf #{tmpdir}") +sleep 10 +objects, start, rows = search(:users, "*:*") + +objects.each do |entry| + file "#{node[:tmpdir]}/#{entry["id"]}" end + diff --git a/features/data/cookbooks/show_cookbook/README.rdoc b/features/data/cookbooks/show_cookbook/README.rdoc new file mode 100644 index 0000000000..8d774805b9 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/features/data/cookbooks/show_cookbook/attributes/attr_file.rb b/features/data/cookbooks/show_cookbook/attributes/attr_file.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/attributes/attr_file.rb diff --git a/features/data/cookbooks/show_cookbook/definitions/def_file.rb b/features/data/cookbooks/show_cookbook/definitions/def_file.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/definitions/def_file.rb diff --git a/features/data/cookbooks/show_cookbook/files/default/prime_time.txt b/features/data/cookbooks/show_cookbook/files/default/prime_time.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/files/default/prime_time.txt diff --git a/features/data/cookbooks/show_cookbook/files/host-latte/prime_time.txt b/features/data/cookbooks/show_cookbook/files/host-latte/prime_time.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/files/host-latte/prime_time.txt diff --git a/features/data/cookbooks/show_cookbook/files/mac_os_x-10.5/prime_time.txt b/features/data/cookbooks/show_cookbook/files/mac_os_x-10.5/prime_time.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/files/mac_os_x-10.5/prime_time.txt diff --git a/features/data/cookbooks/show_cookbook/files/mac_os_x/prime_time.txt b/features/data/cookbooks/show_cookbook/files/mac_os_x/prime_time.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/files/mac_os_x/prime_time.txt diff --git a/features/data/cookbooks/show_cookbook/libraries/lib_file.rb b/features/data/cookbooks/show_cookbook/libraries/lib_file.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/libraries/lib_file.rb diff --git a/features/data/cookbooks/show_cookbook/metadata.rb b/features/data/cookbooks/show_cookbook/metadata.rb new file mode 100644 index 0000000000..6f06805f62 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/metadata.rb @@ -0,0 +1,6 @@ +maintainer "Opscode" +maintainer_email "do_not_reply@opscode.com" +license "Apache 2.0" +description "Installs/Configures show_cookbook" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0" diff --git a/features/data/cookbooks/show_cookbook/recipes/default.rb b/features/data/cookbooks/show_cookbook/recipes/default.rb new file mode 100644 index 0000000000..6f972192cb --- /dev/null +++ b/features/data/cookbooks/show_cookbook/recipes/default.rb @@ -0,0 +1,18 @@ +# +# Cookbook Name:: show_cookbook +# Recipe:: default +# +# Copyright 2009, Opscode +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/features/data/cookbooks/show_cookbook/templates/default/prime_time.txt.erb b/features/data/cookbooks/show_cookbook/templates/default/prime_time.txt.erb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/templates/default/prime_time.txt.erb diff --git a/features/data/cookbooks/show_cookbook/templates/host-latte/prime_time.txt.erb b/features/data/cookbooks/show_cookbook/templates/host-latte/prime_time.txt.erb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/templates/host-latte/prime_time.txt.erb diff --git a/features/data/cookbooks/show_cookbook/templates/mac_os_x-10.5/prime_time.txt.erb b/features/data/cookbooks/show_cookbook/templates/mac_os_x-10.5/prime_time.txt.erb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/templates/mac_os_x-10.5/prime_time.txt.erb diff --git a/features/data/cookbooks/show_cookbook/templates/mac_os_x/prime_time.txt.erb b/features/data/cookbooks/show_cookbook/templates/mac_os_x/prime_time.txt.erb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/features/data/cookbooks/show_cookbook/templates/mac_os_x/prime_time.txt.erb diff --git a/features/language/delayed_notifications.feature b/features/language/delayed_notifications.feature index bc874f0f5e..511711c930 100644 --- a/features/language/delayed_notifications.feature +++ b/features/language/delayed_notifications.feature @@ -1,3 +1,4 @@ +@language Feature: Delayed Notifications In order to not impact the system we are configuring unduly As a developer diff --git a/features/provider/directory/create_directories.feature b/features/provider/directory/create_directories.feature index 0d2ab35ab9..b2ac1b157c 100644 --- a/features/provider/directory/create_directories.feature +++ b/features/provider/directory/create_directories.feature @@ -1,3 +1,4 @@ +@provider @provider_directory Feature: Create Directories In order to save time As a Developer diff --git a/features/provider/directory/delete_directories.feature b/features/provider/directory/delete_directories.feature index 1867e6c43c..e98ec2140e 100644 --- a/features/provider/directory/delete_directories.feature +++ b/features/provider/directory/delete_directories.feature @@ -1,3 +1,4 @@ +@provider @provider_directory Feature: Delete Directories In order to save time As a Developer diff --git a/features/provider/execute/run_commands.feature b/features/provider/execute/run_commands.feature index 96a7a36da9..28dd70482a 100644 --- a/features/provider/execute/run_commands.feature +++ b/features/provider/execute/run_commands.feature @@ -1,3 +1,4 @@ +@provider @provider_execute Feature: Run Commands In order to utilize the plethora of useful command line utilities As a Developer diff --git a/features/provider/file/manage_files.feature b/features/provider/file/manage_files.feature index 4034fb0f31..762fff3c62 100644 --- a/features/provider/file/manage_files.feature +++ b/features/provider/file/manage_files.feature @@ -1,3 +1,4 @@ +@provider @provider_file Feature: Manage Files In order to save time As a Developer diff --git a/features/search/search_data.feature b/features/search/search_data.feature index 26b256b077..f6544b7f2e 100644 --- a/features/search/search_data.feature +++ b/features/search/search_data.feature @@ -4,11 +4,25 @@ Feature: Search Data As a Developer I want to search the data - Scenario: Search the node index + Scenario: Search the user index Given a validated node And it includes the recipe 'search::search_data' + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists When I run the chef-client Then the run should exit '0' - And a file named 'search_one.txt' should exist - And a file named 'search_two.txt' should exist + And a file named 'francis' should exist + And a file named 'axl_rose' should exist + + Scenario: Search the user index without a block + Given a validated node + And it includes the recipe 'search::search_data_noblock' + And a 'data_bag' named 'users' exists + And a 'data_bag_item' named 'francis' exists + And a 'data_bag_item' named 'axl_rose' exists + When I run the chef-client + Then the run should exit '0' + And a file named 'francis' should exist + And a file named 'axl_rose' should exist diff --git a/features/steps/cookbook_steps.rb b/features/steps/cookbook_steps.rb index 202b4c0eda..1c5c0276ae 100644 --- a/features/steps/cookbook_steps.rb +++ b/features/steps/cookbook_steps.rb @@ -1,5 +1,6 @@ # # Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Chris Walters (<cw@opscode.com>) # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # @@ -51,3 +52,4 @@ When /^I run the rake task to generate cookbook metadata$/ do end end end + diff --git a/features/steps/fixture_steps.rb b/features/steps/fixture_steps.rb index 6c9e8c9ed1..5239e5d762 100644 --- a/features/steps/fixture_steps.rb +++ b/features/steps/fixture_steps.rb @@ -1,19 +1,53 @@ +require 'ostruct' + Before do @fixtures = { + 'signing_caller' =>{ + :user_id=>'bobo', :secret_key => "/tmp/poop.pem" + }, 'registration' => { 'bobo' => Proc.new do - r = Chef::OpenIDRegistration.new - r.name = "bobo" - r.set_password('tclown') - r.validated = true - r.admin = true - r + + OpenStruct.new({ :save => true }) + #Chef::CouchDB.new(Chef::Config[:couchdb_url], "chef_integration")) + end + }, + 'data_bag' => { + 'users' => Proc.new do + b = Chef::DataBag.new(Chef::CouchDB.new(nil, "chef_integration")) + b.name "users" + b + end, + 'rubies' => Proc.new do + b = Chef::DataBag.new(Chef::CouchDB.new(nil, "chef_integration")) + b.name "rubies" + b + end + }, + 'data_bag_item' => { + 'francis' => Proc.new do + i = Chef::DataBagItem.new(Chef::CouchDB.new(nil, "chef_integration")) + i.data_bag "users" + i.raw_data = { "id" => "francis" } + i + end, + 'francis_extra' => Proc.new do + i = Chef::DataBagItem.new(Chef::CouchDB.new(nil, "chef_integration")) + i.data_bag "users" + i.raw_data = { "id" => "francis", "extra" => "majority" } + i + end, + 'axl_rose' => Proc.new do + i = Chef::DataBagItem.new(Chef::CouchDB.new(nil, "chef_integration")) + i.data_bag "users" + i.raw_data = { "id" => "axl_rose" } + i end }, 'role' => { 'webserver' => Proc.new do - r = Chef::Role.new + r = Chef::Role.new(Chef::CouchDB.new(nil, "chef_integration")) r.name "webserver" r.description "monkey" r.recipes("role::webserver", "role::base") @@ -22,7 +56,7 @@ Before do r end, 'db' => Proc.new do - r = Chef::Role.new + r = Chef::Role.new(Chef::CouchDB.new(nil, "chef_integration")) r.name "db" r.description "monkey" r.recipes("role::db", "role::base") @@ -33,7 +67,7 @@ Before do }, 'node' => { 'webserver' => Proc.new do - n = Chef::Node.new + n = Chef::Node.new(Chef::CouchDB.new(nil, "chef_integration")) n.name 'webserver' n.run_list << "tacos" n.snakes "on a plane" @@ -41,17 +75,34 @@ Before do n end, 'dbserver' => Proc.new do - n = Chef::Node.new + n = Chef::Node.new(Chef::CouchDB.new(nil, "chef_integration")) n.name 'dbserver' n.run_list << "oracle" n.just "kidding - who uses oracle?" n + end, + 'sync' => Proc.new do + n = Chef::Node.new(Chef::CouchDB.new(nil, "chef_integration")) + n.name 'sync' + n.run_list << "node_cookbook_sync" + n end } } @stash = {} end +def sign_request(http_method, private_key, user_id, body = "") + timestamp = Time.now.utc.iso8601 + sign_obj = Mixlib::Auth::SignedHeaderAuth.signing_object( + :http_method=>http_method, + :body=>body, + :user_id=>user_id, + :timestamp=>timestamp) + signed = sign_obj.sign(private_key).merge({:host => "localhost"}) + signed.inject({}){|memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo} +end + def get_fixture(stash_name, stash_key) fixy = @fixtures[stash_name][stash_key] if fixy.kind_of?(Proc) @@ -62,20 +113,35 @@ def get_fixture(stash_name, stash_key) end Given /^an? '(.+)' named '(.+)'$/ do |stash_name, stash_key| - @stash[stash_name] = get_fixture(stash_name, stash_key) + # BUGBUG: I need to reference fixtures individually, but the fixtures, as written, store under the type, not the fixture's identifier and I don't currently have time to re-write the tests + + key = case stash_name + when 'file','hash' + stash_key + else + stash_name + end + @stash[key] = get_fixture(stash_name, stash_key) end -Given /^an? '(.+)' named '(.+)' exists$/ do |stash_name, stash_key| +Given /^an? '(.+)' named '(.+)' exists$/ do |stash_name, stash_key| @stash[stash_name] = get_fixture(stash_name, stash_key) - if @stash[stash_name].respond_to?(:save) - @stash[stash_name].save - else - request("/#{stash_name.pluralize}", { - :method => "POST", - "HTTP_ACCEPT" => 'application/json', - "CONTENT_TYPE" => 'application/json', - :input => @stash[stash_name].to_json - }) + + if stash_name == 'registration' + r = Chef::REST.new(Chef::Config[:registration_url], Chef::Config[:validation_user], Chef::Config[:validation_key]) + r.register("bobo", "#{tmpdir}/bobo.pem") + @rest = Chef::REST.new(Chef::Config[:registration_url], 'bobo', "#{tmpdir}/bobo.pem") + else + if @stash[stash_name].respond_to?(:save)#stash_name == "registration" + @stash[stash_name].save + else + request("#{stash_name.pluralize}", { + :method => "POST", + "HTTP_ACCEPT" => 'application/json', + "CONTENT_TYPE" => 'application/json', + :input => @stash[stash_name].to_json + }.merge(sign_request("POST", OpenSSL::PKey::RSA.new(IO.read("#{tmpdir}/client.pem")), "bobo"))) + end end end @@ -98,3 +164,7 @@ Given /^there are no (.+)$/ do |stash_name| Chef::Role.list(true).each { |r| r.destroy } end end + +Given /^I wait for '(\d+)' seconds$/ do |time| + sleep time.to_i +end diff --git a/features/steps/node_steps.rb b/features/steps/node_steps.rb index d1aa9a0045..3f4f76b870 100644 --- a/features/steps/node_steps.rb +++ b/features/steps/node_steps.rb @@ -20,15 +20,15 @@ # Given ### Given /^a validated node$/ do - client.validation_token = Chef::Config[:validation_token] = 'ceelo' + client.determine_node_name client.register - client.authenticate client.build_node client.node.recipes << "integration_setup" end Given /^it includes the recipe '(.+)'$/ do |recipe| self.recipe = recipe + Chef::Log.error("It's like this we have: #{Chef::Config[:chef_server_url]}") client.node.recipes << recipe client.save_node end diff --git a/features/steps/request_steps.rb b/features/steps/request_steps.rb index 156fc88b3a..892195e80e 100644 --- a/features/steps/request_steps.rb +++ b/features/steps/request_steps.rb @@ -1,21 +1,55 @@ -When /^I '(.+)' the path '(.+)'$/ do |http_method, request_uri| +When /^I '([^']*)' (?:to )?the path '([^']*)'$/ do |http_method, request_uri| begin self.response = rest.send("#{http_method}_rest".downcase.to_sym, request_uri) - self.inflated_response = self.response + self.inflated_response = self.response rescue + Chef::Log.debug("Caught exception in request: #{$!.message}") self.exception = $! end end +When /^I '([^']*)' to the path '(.+)'$/ do |http_method, request_uri| + When "I '#{http_method}' the path '#{request_uri}'" +end + +When /^I '(.+)' the path '(.+)' using a wrong private key$/ do |http_method, request_uri| + key = OpenSSL::PKey::RSA.generate(2048) + File.open(File.join(tmpdir, 'false_key.pem'), "w") { |f| f.print key } + @rest = Chef::REST.new(Chef::Config[:chef_server_url], 'snakebite' , File.join(tmpdir, 'false_key.pem')) + + When "I '#{http_method}' the path '#{request_uri}'" +end + When /^I '(.+)' the '(.+)' to the path '(.+)'$/ do |http_method, stash_key, request_uri| begin - self.response = rest.send("#{http_method}_rest".downcase.to_sym, request_uri, stash[stash_key]) + self.response = rest.send("#{http_method.to_s.downcase}_rest".downcase.to_sym, request_uri, stash[stash_key]) self.inflated_response = response rescue self.exception = $! end end +When /^I '(.+)' the '(.+)' to the path '(.+)' using a wrong private key$/ do |http_method, stash_key, request_uri| + key = OpenSSL::PKey::RSA.generate(2048) + File.open(File.join(tmpdir, 'false_key.pem'), "w") { |f| f.print key } + @rest = Chef::REST.new(Chef::Config[:chef_server_url], 'snakebite' , File.join(tmpdir, 'false_key.pem')) + + When "I '#{http_method}' the '#{stash_key}' to the path '#{request_uri}'" +end + +When /^I delete local private key/ do + Chef::FileCache.delete("private_key.pem") +end + +When /^I register '(.+)'$/ do |user| + begin + rest = Chef::REST.new(Chef::Config[:registration_url]) + rest.register("bobo") + rescue + self.exception = $! + end +end + When /^I authenticate as '(.+)'$/ do |reg| begin rest.authenticate(reg, 'tclown') @@ -24,3 +58,59 @@ When /^I authenticate as '(.+)'$/ do |reg| end end + + + +# When /^I '(.+)' the path '(.+)'$/ do |http_method, request_uri| +# begin +# #if http_method.downcase == 'get' +# # self.response = @rest.get_rest(request_uri) +# #else +# #puts "test test test \n\n\n\n\n\n\n" +# @response = @rest.send("#{http_method}_rest".downcase.to_sym, request_uri) +# #end +# puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +# puts @response +# puts @response['content-type'] +# #puts self.response +# #puts self.response.inspect +# #self.inflated_response = self.response +# @inflated_response = @response#JSON.parse(response.body.to_s) +# puts "~~~~~~~~INFLATED RESPONSE~~~~~~~~~~~~" +# puts @inflated_response +# rescue +# self.exception = $! +# end +# end +# +# When /^I '(.+)' the '(.+)' to the path '(.+)'$/ do |http_method, stash_key, request_uri| +# begin +# #if http_method.downcase == 'post' +# # puts "post request" +# # self.response = @rest.post_rest(request_uri, @stash[stash_key]) +# # puts self.response +# #else +# puts "This is the request -- @stash[stash_key]:" +# puts @stash[stash_key].to_s +# @response = @rest.send("#{http_method}_rest".downcase.to_sym, request_uri, @stash[stash_key]) +# #end +# puts "This is the response:" +# #puts self.response.body.to_s +# puts @response +# #self.inflated_response = response +# @inflated_response = @response#JSON.parse(self.response.body.to_s) +# puts "~~~~~~~~INFLATED RESPONSE~~~~~~~~~~~~" +# puts @inflated_response +# rescue +# self.exception = $! +# end +# end +# +# When /^I authenticate as '(.+)'$/ do |reg| +# begin +# rest.authenticate(reg, 'tclown') +# rescue +# self.exception = $! +# end +# end +# diff --git a/features/steps/response_steps.rb b/features/steps/response_steps.rb index 3f3ef28459..0c0fc2d6ab 100644 --- a/features/steps/response_steps.rb +++ b/features/steps/response_steps.rb @@ -3,70 +3,101 @@ Then /^I should get a '(.+)' exception$/ do |exception| end Then /^the response code should be '(.+)'$/ do |response_code| - response.status.should == response_code.to_i + self.response.status.should == response_code.to_i +end + +Then /^the inflated responses key '(.+)' should be the integer '(\d+)'$/ do |key, int| + inflated_response[key].should == int.to_i end Then /^the inflated responses key '(.+)' should match '(.+)'$/ do |key, regex| - inflated_response[key].should =~ /#{regex}/ + puts self.inflated_response.inspect if ENV['DEBUG'] + self.inflated_response[key].should =~ /#{regex}/m +end + +Then /^the inflated responses key '(.+)' should match '(.+)' as json$/ do |key, regex| + puts self.inflated_response.inspect if ENV["DEBUG"] + self.inflated_response[key].to_json.should =~ /#{regex}/m +end + +Then /^the inflated responses key '(.+)' item '(\d+)' should be a kind of '(.+)'$/ do |key, index, constant| + inflated_response[key][index.to_i].should be_a_kind_of(eval(constant)) +end + +Then /^the inflated responses key '(.+)' item '(\d+)' key '(.+)' should be '(.+)'$/ do |key, index, sub_key, to_equal| + inflated_response[key][index.to_i][sub_key].should == to_equal +end + +Then /^the inflated responses key '(.+)' should be '(\d+)' items long$/ do |key, length| + inflated_response[key].length.should == length.to_i end Then /^the inflated responses key '(.+)' should not exist$/ do |key| - inflated_response.has_key?(key).should == false + self.inflated_response.has_key?(key).should == false end Then /^the inflated responses key '(.+)' should exist$/ do |key| - inflated_response.has_key?(key).should == true + self.inflated_response.has_key?(key).should == true end Then /^the inflated response should be an empty array$/ do - inflated_response.should == [] + self.inflated_response.should == [] end Then /^the inflated response should include '(.+)'$/ do |entry| - inflated_response.detect { |n| n =~ /#{entry}/ }.should be(true) + self.inflated_response.detect { |n| n =~ /#{entry}/ }.should be(true) end Then /^the inflated response should be '(.+)' items long$/ do |length| - inflated_response.length.should == length.to_i + self.inflated_response.length.should == length.to_i end Then /^the '(.+)' header should match '(.+)'$/ do |header, regex| - response.headers[header].should =~ /#{regex}/ + self.response.headers[header].should =~ /#{regex}/ end Then /^the inflated responses key '(.+)' should include '(.+)'$/ do |key, regex| - inflated_response[key].detect { |n| n =~ /#{regex}/ }.should be(true) + self.inflated_response[key].detect { |n| n =~ /#{regex}/ }.should be(true) end Then /^the inflated response should match the '(.+)'$/ do |stash_name| stash[stash_name].each do |k,v| - inflated_response[k.to_s].should == v + self.inflated_response[k.to_s].should == v end end Then /^the inflated response should be the '(.+)'$/ do |stash_key| - stash[stash_key].should == inflated_response + stash[stash_key].should == self.inflated_response end Then /^the inflated response should be a kind of '(.+)'$/ do |thing| - inflated_response.should be_a_kind_of(thing) + self.inflated_response.should be_a_kind_of(thing) end Then /^the inflated response should respond to '(.+)' with '(.+)'$/ do |method, to_match| to_match = JSON.parse(to_match) if to_match =~ /^\[|\{/ - inflated_response.send(method.to_sym).should == to_match + self.inflated_response.send(method.to_sym).should == to_match end Then /^the inflated response should respond to '(.+)' and match '(.+)'$/ do |method, to_match| - inflated_response.send(method.to_sym).should == to_match + self.inflated_response.send(method.to_sym).should == to_match end Then /^the fields in the inflated response should match the '(.+)'$/ do |stash_name| - inflated_response.each do |k,v| + self.inflated_response.each do |k,v| unless k =~ /^_/ || k == 'couchrest-type' stash[stash_name][k.to_sym].should == v end end end +Then /^the data_bag named '(.+)' should not have an item named '(.+)'$/ do |data_bag, item| + exists = true + begin + Chef::DataBagItem.load(data_bag, item, @couchdb) + rescue + exists = false + end + exists.should == false +end diff --git a/features/steps/run_client_steps.rb b/features/steps/run_client_steps.rb index 815c5c7148..25726f59aa 100644 --- a/features/steps/run_client_steps.rb +++ b/features/steps/run_client_steps.rb @@ -24,7 +24,7 @@ When /^I run the chef\-client$/ do @chef_args ||= "" @config_file ||= File.expand_path(File.join(File.dirname(__FILE__), '..', 'data', 'config', 'client.rb')) status = Chef::Mixin::Command.popen4( - "chef-client -l #{@log_level} -c #{@config_file} #{@chef_args}") do |p, i, o, e| + "#{File.join(File.dirname(__FILE__), "..", "..", "chef", "bin", "chef-client")} -l #{@log_level} -c #{@config_file} #{@chef_args}") do |p, i, o, e| @stdout = o.gets(nil) @stderr = e.gets(nil) end @@ -76,7 +76,7 @@ openid_url "http://127.0.0.1:4001" template_url "http://127.0.0.1:4000" remotefile_url "http://127.0.0.1:4000" search_url "http://127.0.0.1:4000" -couchdb_database 'chef_integration' +couchdb_database 'chef' CONFIG @config_file = File.expand_path(File.join(File.dirname(__FILE__), '..', 'data', 'config', 'client-with-logging.rb')) @@ -86,12 +86,11 @@ CONFIG self.cleanup_files << @config_file - @status = Chef::Mixin::Command.popen4("chef-client -c #{@config_file}") do |p, i, o, e| + + @status = Chef::Mixin::Command.popen4("#{File.join(File.dirname(__FILE__), "..", "..", "chef", "bin", "chef-client")} -l #{@log_level} -c #{@config_file} #{@chef_args}") do |p, i, o, e| @stdout = o.gets(nil) @stderr = e.gets(nil) end - - end ### diff --git a/features/steps/run_solo.rb b/features/steps/run_solo.rb index e5397b853d..b2b244cfb6 100644 --- a/features/steps/run_solo.rb +++ b/features/steps/run_solo.rb @@ -26,7 +26,7 @@ When /^I run chef-solo with the '(.+)' recipe$/ do |recipe_name| cleanup_files << config_file binary_path = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'chef', 'bin', 'chef-solo')) - command = "chef-solo -c #{config_file} -j #{dna_file}" + command = "#{binary_path} -c #{config_file} -j #{dna_file}" command += " -l debug" if ENV['LOG_LEVEL'] == 'debug' # Run it diff --git a/features/steps/webrat_steps.rb b/features/steps/webrat_steps.rb index c7f78a5406..b152a1501d 100644 --- a/features/steps/webrat_steps.rb +++ b/features/steps/webrat_steps.rb @@ -36,4 +36,4 @@ end When /^I attach the file at "(.*)" to "(.*)" $/ do |path, field| attach_file(field, path) end -
\ No newline at end of file + diff --git a/features/support/env.rb b/features/support/env.rb index 2a5b217d29..ca60753df2 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -16,7 +16,7 @@ # limitations under the License. # -%w{chef chef-server chef-server-slice}.each do |inc_dir| +%w{chef chef-server chef-server-slice chef-solr}.each do |inc_dir| $: << File.join(File.dirname(__FILE__), '..', '..', inc_dir, 'lib') end @@ -25,22 +25,92 @@ require 'spec' require 'chef' require 'chef/config' require 'chef/client' +require 'chef/data_bag' +require 'chef/data_bag_item' +require 'chef/solr' require 'tmpdir' require 'merb-core' require 'merb_cucumber/world/webrat' +require 'opscode/audit' +require 'chef/streaming_cookbook_uploader' def Spec.run? ; true; end -Chef::Config.from_file(File.join(File.dirname(__FILE__), '..', 'data', 'config', 'server.rb')) -Chef::Config[:log_level] = :error -Ohai::Config[:log_level] = :error +ENV['LOG_LEVEL'] ||= 'error' + +def setup_logging + Chef::Config.from_file(File.join(File.dirname(__FILE__), '..', 'data', 'config', 'server.rb')) + Merb.logger.auto_flush = true + if ENV['DEBUG'] == 'true' || ENV['LOG_LEVEL'] == 'debug' + Chef::Config[:log_level] = :debug + Chef::Log.level(:debug) + Merb.logger.set_log(STDOUT, :debug) + else + Chef::Config[:log_level] = ENV['LOG_LEVEL'].to_sym + Chef::Log.level(ENV['LOG_LEVEL'].to_sym) + Merb.logger.set_log(STDOUT, ENV['LOG_LEVEL'].to_sym) + end + Nanite::Log.logger = Mixlib::Auth::Log.logger = Ohai::Log.logger = Chef::Log.logger +end + +def setup_nanite + Chef::Config[:nanite_identity] = "chef-integration-test" + Chef::Nanite.in_event { Chef::Log.debug("Nanite is up!") } + Chef::Log.debug("Waiting for Nanites to register with us as a mapper") + sleep 10 +end + +def delete_databases + c = Chef::REST.new(Chef::Config[:couchdb_url], nil, nil) + %w{chef_integration}.each do |db| + begin + c.delete_rest("#{db}/") + rescue + end + end +end -if ENV['DEBUG'] = 'true' - Merb.logger.set_log(STDOUT, :debug) if ENV['DEBUG'] = 'true' -else - Merb.logger.set_log(STDOUT, :error) +def create_databases + Chef::Log.info("Creating bootstrap databases") + cdb = Chef::CouchDB.new(Chef::Config[:couchdb_url], "chef_integration") + cdb.create_db + Chef::Node.create_design_document + Chef::Role.create_design_document + Chef::DataBag.create_design_document + Chef::Role.sync_from_disk_to_couchdb end + +def create_validation +# TODO: Create the validation certificate here + File.open("#{Dir.tmpdir}/validation.pem", "w") do |f| + f.print response["private_key"] + end +end + +def prepare_replicas + c = Chef::REST.new(Chef::Config[:couchdb_url], nil, nil) + c.put_rest("chef_integration_safe/", nil) + c.post_rest("_replicate", { "source" => "#{Chef::Config[:couchdb_url]}/chef_integration", "target" => "#{Chef::Config[:couchdb_url]}/chef_integration_safe" }) + c.delete_rest("chef_integration") +end + +at_exit do + c = Chef::REST.new(Chef::Config[:couchdb_url], nil, nil) + c.delete_rest("chef_integration_safe") + File.unlink(File.join(Dir.tmpdir, "validation.pem")) +end + +### +# Pre-testing setup +### +setup_logging +setup_nanite +delete_databases +create_databases +create_validation +prepare_replicas + Merb.start_environment( :merb_root => File.join(File.dirname(__FILE__), "..", "..", "chef-server"), :testing => true, @@ -55,6 +125,11 @@ Spec::Runner.configure do |config| config.include(Merb::Test::ControllerHelper) end +Chef::Log.info("Ready to run tests") + +### +# The Cucumber World +### module ChefWorld attr_accessor :recipe, :cookbook, :response, :inflated_response, :log_level, :chef_args, :config_file, :stdout, :stderr, :status, :exception @@ -64,7 +139,7 @@ module ChefWorld end def rest - @rest ||= Chef::REST.new('http://localhost:4000') + @rest ||= Chef::REST.new('http://localhost:4000/organizations/clownco', nil, nil) end def tmpdir @@ -91,7 +166,23 @@ end World(ChefWorld) +Before do + system("mkdir -p #{tmpdir}") + system("cp -r #{File.join(Dir.tmpdir, "validation.pem")} #{File.join(tmpdir, "validation.pem")}") + Chef::CouchDB.new(Chef::Config[:couchdb_url], "chef_integration").create_db + c = Chef::REST.new(Chef::Config[:couchdb_url], nil, nil) + c.post_rest("_replicate", { + "source" => "#{Chef::Config[:couchdb_url]}/chef_integration_safe", + "target" => "#{Chef::Config[:couchdb_url]}/chef_integration" + }) +end + After do + r = Chef::REST.new(Chef::Config[:couchdb_url], nil, nil) + r.delete_rest("chef_integration/") + s = Chef::Solr.new + s.solr_delete_by_query("*:*") + s.solr_commit cleanup_files.each do |file| system("rm #{file}") end @@ -104,5 +195,6 @@ After do end data_tmp = File.join(File.dirname(__FILE__), "..", "data", "tmp") system("rm -rf #{data_tmp}/*") + system("rm -rf #{tmpdir}") end |