diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 32aaddc2..0461aa4a 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -27,6 +27,7 @@ class FeatureContext extends BehatContext protected $applicationTester; protected $filesystem; protected $workingDir; + protected $currentWorkspaceName = 'default'; /** * Initializes context. @@ -45,13 +46,13 @@ public function beforeScenario() chdir($this->workingDir); $this->filesystem = new Filesystem(); - $session = $this->getSession(); - $session->save(); + $session = $this->getSession(null, true); $this->applicationTester = new ApplicationTester($this->application); $this->applicationTester->run(array( '--transport' => 'jackrabbit', '--no-interaction' => true, + '--unsupported' => true, // test all the commands, even if they are unsupported (we test for the fail) ), array( 'interactive' => true, )); @@ -69,8 +70,19 @@ public static function cleanTestFolders() $fs->remove(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'phpcr-shell'); } - private function getSession($workspaceName = 'default') + private function getSession($workspaceName = null, $force = false) { + if ($workspaceName === null) { + $workspaceName = $this->currentWorkspaceName; + } + + static $sessions = array(); + + if (false === $force && isset($sessions[$workspaceName])) { + $session = $sessions[$workspaceName]; + return $session; + } + $params = array( 'jackalope.jackrabbit_uri' => 'http://localhost:8080/server/', ); @@ -79,9 +91,9 @@ private function getSession($workspaceName = 'default') $repository = $factory->getRepository($params); $credentials = new SimpleCredentials('admin', 'admin'); - $session = $repository->login($credentials, $workspaceName); + $sessions[$workspaceName] = $repository->login($credentials, $workspaceName); - return $session; + return $sessions[$workspaceName]; } private function getOutput() @@ -184,7 +196,7 @@ public function iShouldSeeTheFollowing(PyStringNode $string) public function theFixturesAreLoaded($arg1) { $fixtureFile = $this->getFixtureFilename($arg1); - $session = $this->getSession(); + $session = $this->getSession(null, true); NodeHelper::purgeWorkspace($session); $session->save(); $session->importXml('/', $fixtureFile, 0); @@ -407,7 +419,7 @@ public function theNodeAtShouldNotHaveTheMixin($arg1, $arg2) */ public function thereShouldNotExistANodeAt($arg1) { - $session = $this->getSession(); + $session = $this->getSession(null, true); try { $session->getNode($arg1); @@ -506,7 +518,11 @@ public function thereExistsAWorkspace($arg1) { $session = $this->getSession(); $workspace = $session->getWorkspace(); - $workspace->createWorkspace($arg1); + try { + $workspace->createWorkspace($arg1); + } catch (\Exception $e) { + // already exists.. + } } /** @@ -522,12 +538,13 @@ public function thereShouldNotExistAWorkspaceCalled($arg1) } /** - * @Given /^the "([^"]*)" fixtures are loaded into a workspace "([^"]*)"$/ + * @Given /^the "([^"]*)" fixtures are loaded into workspace "([^"]*)"$/ */ - public function theFixturesAreLoadedIntoAWorkspace($arg1, $arg2) + public function theFixturesAreLoadedIntoWorkspace($arg1, $arg2) { + $this->theCurrentWorkspaceIs($arg2); $fixtureFile = $this->getFixtureFilename($arg1); - $session = $this->getSession($arg2); + $session = $this->getSession(); NodeHelper::purgeWorkspace($session); $session->save(); $session->importXml('/', $fixtureFile, 0); @@ -545,7 +562,6 @@ public function theNodeTypeIsLoaded($arg1) $workspace = $session->getWorkspace(); $nodeTypeManager = $workspace->getNodeTypeManager(); $nodeTypeManager->registerNodeTypesCnd($cnd, true); - $session->save(); } /** @@ -603,6 +619,33 @@ public function theCurrentNodeIs($arg1) $this->executeCommand(sprintf('cd %s', $arg1)); } + /** + * @Given /^the current workspace is "([^"]*)"$/ + */ + public function theCurrentWorkspaceIs($arg1) + { + $this->thereExistsAWorkspace($arg1); + $this->currentWorkspaceName = $arg1; + } + + /** + * @Given /^the current workspace is empty/ + */ + public function theCurrentWorkspaceIsEmpty() + { + $session = $this->getSession(); + NodeHelper::purgeWorkspace($session); + $session->save(); + } + + /** + * @Given /^I refresh the session/ + */ + public function iRefreshTheSession() + { + $this->executeCommand('session:refresh'); + } + /** * @Given /^the primary type of "([^"]*)" should be "([^"]*)"$/ */ @@ -615,17 +658,29 @@ public function thePrimaryTypeOfShouldBe($arg1, $arg2) } /** - * @Given /^the node at "([^"]*)" should have the property "([^"]*)" with type "([^"]*)"$/ + * @Given /^the node at "([^"]*)" should have the property "([^"]*)" with value "([^"]*)"$/ */ - public function theNodeAtShouldHaveThePropertyWithType($arg1, $arg2, $arg3) + public function theNodeAtShouldHaveThePropertyWithValue($arg1, $arg2, $arg3) { $session = $this->getSession(); $node = $session->getNode($arg1); $property = $node->getProperty($arg2); - $propertyType = $property->getType(); + $propertyType = $property->getValue(); PHPUnit_Framework_Assert::assertEquals($arg3, $propertyType); } + /** + * @Given /^I set the value of property "([^"]*)" on node "([^"]*)" to "([^"]*)"$/ + */ + public function iSetTheValueOfPropertyOnNodeTo($arg1, $arg2, $arg3) + { + $session = $this->getSession(); + $node = $session->getNode($arg2); + $property = $node->getProperty($arg1); + $property->setValue($arg3); + $session->save(); + } + /** * @Given /^the node at "([^"]*)" has the mixin "([^"]*)"$/ */ @@ -644,7 +699,7 @@ public function iCloneNodeFromTo($arg1, $arg2, $arg3) { $session = $this->getSession(); $workspace = $session->getWorkspace(); - $workspace->cloneFrom($arg2, $arg1, $arg3, false); + $workspace->cloneFrom($arg2, $arg1, $arg3, true); } /** diff --git a/features/fixtures/cms.xml b/features/fixtures/cms.xml new file mode 100644 index 00000000..3a52a3c0 --- /dev/null +++ b/features/fixtures/cms.xml @@ -0,0 +1,43 @@ + + + + + nt:unstructured + + + + + nt:unstructured + + + + nt:unstructured + + + mix:referenceable + + + 13543fc6-1abf-4708-bfcc-e49511754b40 + + + Article 1 + + + + + + diff --git a/features/fixtures/example.cnd b/features/fixtures/example.cnd index 6e84d8b1..55ed3745 100644 --- a/features/fixtures/example.cnd +++ b/features/fixtures/example.cnd @@ -1,2 +1,4 @@ - + + [ns:NodeType] > nt:unstructured +orderable query diff --git a/features/node_workspace_corresponding.feature b/features/node_corresponding.feature similarity index 64% rename from features/node_workspace_corresponding.feature rename to features/node_corresponding.feature index dbcc79ff..d81579fe 100644 --- a/features/node_workspace_corresponding.feature +++ b/features/node_corresponding.feature @@ -5,13 +5,17 @@ Feature: Display the path of any corresponding node in a given workspace Background: Given that I am logged in as "testuser" + And the current workspace is "default" And the "session_data.xml" fixtures are loaded + And the current workspace is "default_1" + And the "session_data.xml" fixtures are loaded + And the current workspace is "default" Scenario: Rename a node - Given the current node is "/tests_general_base" + Given the current node is "/tests_general_base/idExample" And I execute the "node:corresponding default" command Then the command should not fail And I should see the following: """ - /foobar + /tests_general_base/idExample """ diff --git a/features/node_create.feature b/features/node_create.feature index 3ed86e3f..fdf4ce7c 100644 --- a/features/node_create.feature +++ b/features/node_create.feature @@ -23,12 +23,12 @@ Feature: Create a node And the primary type of "/testfile" should be "nt:folder" Scenario: Create a new node at a non-root current node no matching child type - Given the current node is "/tests_general_base" + Given the current node is "/tests_general_base/emptyExample" And I execute the "node:create testcreate" command Then the command should fail And I should see the following: """ - No matching child node definition found for `testcreate' in type `nt:folder' for node '/tests_general_base'. Please specify the type explicitly + No matching child node definition found for `testcreate' """ Scenario: Create a new node at a non-root current node @@ -37,11 +37,3 @@ Feature: Create a node And I save the session Then the command should not fail And there should exist a node at "/tests_general_base/testcreate" - - Scenario: Attempt to create an empty node - Given I execute the "node:create" command - Then the command should fail - And I should see the following: - """ - Name can not be empty - """ diff --git a/features/node_info.feature b/features/node_info.feature index d237bca5..8faa0c48 100644 --- a/features/node_info.feature +++ b/features/node_info.feature @@ -7,7 +7,7 @@ Feature: Show information about node Given that I am logged in as "testuser" And the "session_data.xml" fixtures are loaded - Scenario: Rename a node + Scenario: Show node information Given the current node is "/tests_general_base" And I execute the "node:info --no-ansi" command Then the command should not fail @@ -17,7 +17,7 @@ Feature: Show information about node | Path | /tests_general_base | | UUID | N/A | | Index | 1 | - | Primary node type | nt:folder | + | Primary node type | nt:unstructured | | Mixin node types | | | Checked out? | [ERROR] Not implemented by jackalope | | Locked? | [ERROR] Not implemented by jackalope | diff --git a/features/node_list.feature b/features/node_list.feature index e7440fa9..dc737c2e 100644 --- a/features/node_list.feature +++ b/features/node_list.feature @@ -19,16 +19,14 @@ Feature: List properites and chidren of current node | numberPropertyNode/ | nt:file | | | NumberPropertyNodeToCompare1/ | nt:file | | | NumberPropertyNodeToCompare2/ | nt:file | | - | jcr:createdBy | STRING | admin | - | jcr:primaryType | NAME | nt:folder | + | jcr:primaryType | NAME | nt:unstructured | Scenario: List the properties Given the current node is "/tests_general_base" And I execute the "node:list --properties --no-ansi" command Then the command should not fail And I should see a table containing the following rows: - | jcr:createdBy | STRING | admin | - | jcr:primaryType | NAME | nt:folder | + | jcr:primaryType | NAME | nt:unstructured | Scenario: List the children nodes Given the current node is "/tests_general_base" diff --git a/features/node_rename.feature b/features/node_rename.feature index ceb7b731..cf39e278 100644 --- a/features/node_rename.feature +++ b/features/node_rename.feature @@ -8,7 +8,8 @@ Feature: Rename a node And the "session_data.xml" fixtures are loaded Scenario: Rename a node - Given the current node is "/tests_general_base" + Given the current node is "/tests_general_base/idExample" And I execute the "node:rename foobar" command + And I save the session Then the command should not fail And there should exist a node at "/tests_general_base/foobar" diff --git a/features/node_set.feature b/features/node_set.feature index 4fc5e547..c52036da 100644 --- a/features/node_set.feature +++ b/features/node_set.feature @@ -11,7 +11,8 @@ Feature: Set a node property Scenario Outline: Set a property Given I execute the "" command Then the command should not fail - And the node at "/properties" should have the property "" with type "" + And I save the session + And the node at "/properties" should have the property "" with value "" Examples: | command | name | type | diff --git a/features/node_set_primary_type.feature b/features/node_set_primary_type.feature index 2a3cd2fe..36fb011f 100644 --- a/features/node_set_primary_type.feature +++ b/features/node_set_primary_type.feature @@ -9,5 +9,9 @@ Feature: Set the nodes primary type Scenario: List the properties and children of the current node Given the current node is "/tests_general_base" - And I execute the "node:type:set-primary nt:unstructured --no-ansi" command - Then the command should not fail + And I execute the "node:set-primary-type nt:unstructured --no-ansi" command + Then the command should fail + And I should see the following: + """ + Not implemented + """ diff --git a/features/node_shared_remove.feature b/features/node_shared_remove.feature index 187e7389..ca20ed87 100644 --- a/features/node_shared_remove.feature +++ b/features/node_shared_remove.feature @@ -5,12 +5,13 @@ Feature: Remove the current node from any shared set to which it belongs Background: Given that I am logged in as "testuser" - And the "session_data.xml" fixtures are loaded - And the node at "/tests_general_base/daniel/leech" has the mixin "mix:shareable" - And I clone node "/tests_general_base/daniel/leech" from "default" to "/tests_general_base/bar" + And the current workspace is "default_1" + And the "cms.xml" fixtures are loaded + And the current workspace is "default" + And I clone node "/cms/articles/article1" from "default_1" to "/foobar" Scenario: Remove the current node and all of its shared paths - Given the current node is "/tests_general_base/daniel" + Given the current node is "/foobar" And I execute the "node:shared:remove" command Then the command should fail And I should see the following: diff --git a/features/node_shared_show.feature b/features/node_shared_show.feature index e1b14a9d..8c02b4b4 100644 --- a/features/node_shared_show.feature +++ b/features/node_shared_show.feature @@ -5,12 +5,13 @@ Feature: Show the current nodes shared set Background: Given that I am logged in as "testuser" - And the "session_data.xml" fixtures are loaded - And the node at "/tests_general_base/daniel/leech" has the mixin "mix:shareable" - And I clone node "/tests_general_base/daniel/leech" from "default" to "/tests_general_base/bar" + And the current workspace is "default_1" + And the "cms.xml" fixtures are loaded + And the current workspace is "default" + And I clone node "/cms/articles/article1" from "default_1" to "/foobar" Scenario: Show the current nodes shared set - Given the current node is "/tests_general_base/daniel/leech" + Given the current node is "/foobar" And I execute the "node:shared:show" command Then the command should fail And I should see the following: diff --git a/features/node_type_edit.feature b/features/node_type_edit.feature index 9bb70105..7f9180fb 100644 --- a/features/node_type_edit.feature +++ b/features/node_type_edit.feature @@ -7,7 +7,7 @@ Feature: Edit a node type Given that I am logged in as "testuser" And the "example.cnd" node type is loaded - Scenario Outline: Edit a property + Scenario Outline: Edit a node type Given the "EDITOR" environment variable is set to "cat" And I execute the "" command Then the command should not fail @@ -40,8 +40,10 @@ Feature: Edit a node type Scenario: Create a new node type Given I have an editor which produces the following: """ - + + [ns:somenewtype] > nt:unstructured + orderable query """ And I execute the "node-type:edit ns:somenewtype --no-interaction" command Then the command should not fail @@ -55,4 +57,5 @@ Feature: Edit a node type Then the command should not fail And I should see the following: """ - gt + Editor emptied the CND file, doing nothing + """ diff --git a/features/node_update.feature b/features/node_update.feature new file mode 100644 index 00000000..cbb9e8b9 --- /dev/null +++ b/features/node_update.feature @@ -0,0 +1,18 @@ +Feature: Update the current node from the node to which it corresponds in the given workspace + In order to update the current node from the node to which it corresponds in the given workspace + As a user that is logged into the shell + I need to be able to do that + + Background: + Given the current workspace is "default_1" + And the "cms.xml" fixtures are loaded + And I set the value of property "title" on node "/cms/articles/article1" to "this is a test" + And the current workspace is "default" + And I clone node "/cms/articles/article1" from "default_1" to "/foobar" + + Scenario: Update a node + Given the current node is "/foobar" + And I execute the "node:update default_1" command + Then the command should not fail + And I save the session + And the node at "/foobar" should have the property "title" with value "this is a test" diff --git a/features/node_workspace_update.feature b/features/node_workspace_update.feature deleted file mode 100644 index def4d8c9..00000000 --- a/features/node_workspace_update.feature +++ /dev/null @@ -1,13 +0,0 @@ -Feature: Update the current node from the node to which it corresponds in the given workspace - In order to update the current node from the node to which it corresponds in the given workspace - As a user that is logged into the shell - I need to be able to do that - - Background: - Given that I am logged in as "testuser" - And the "session_data.xml" fixtures are loaded - - Scenario: Rename a node - Given the current node is "/tests_general_base" - And I execute the "node:update default" command - Then the command should not fail diff --git a/features/repository_capability_list.feature b/features/repository_capability_list.feature deleted file mode 100644 index 0e7b7153..00000000 --- a/features/repository_capability_list.feature +++ /dev/null @@ -1,11 +0,0 @@ -Feature: List the capabilities of the current repository - In order to show the capabilities of the current repository - As a logged in user - I want to be able to execute a command which lists the repository descriptors - - Scenario: Listing the capabilities - Given that I am logged in as "testuser" - And I execute the "repository:capability:list" command - Then the command should not fail - And I should see a table containing the following rows: - | Key | Value | diff --git a/features/session_import.feature b/features/session_import.feature index 56bf7338..96ab74b9 100644 --- a/features/session_import.feature +++ b/features/session_import.feature @@ -6,6 +6,8 @@ Feature: Import repository data from an XML file Background: Given the file "data.xml" contains the contents of "session_data.xml" And that I am logged in as "testuser" + And the current workspace is "default" + And the current workspace is empty Scenario: Import XML non existing file Given I execute the "session:import / does-not-exist.xml" command @@ -24,15 +26,16 @@ Feature: Import repository data from an XML file | /tests_general_base/multiValueProperty/deepnode | Scenario Outline: Specifying UUID behavior - Given I execute the "session:import / data.xml --uuid-behavior=" command + Given I create a node at "" + And I execute the "session:import data.xml --uuid-behavior=" command Then the command should not fail Examples: - | uuid_behavior | - | create-new | - | collision-remove-existing | - | collision-replace-existing | - | collision-throw | + | path | uuid_behavior | + | /a | create-new | + | /b | collision-remove-existing | + | /c | collision-replace-existing | + | /d | collision-throw | Scenario: Specify invalid UUID behavior Given I execute the "session:import / data.xml --uuid-behavior=invalid" command diff --git a/features/session_login.feature b/features/session_login.feature index e5b7adc5..698b0f11 100644 --- a/features/session_login.feature +++ b/features/session_login.feature @@ -1,12 +1,28 @@ -Feature: Logout of the session - In order to disconnect from the session +Feature: Login to the session + In order to reconnect as a different user from a session As a user logged into the shell - I need to be able to disconnect from the session + I need to be able to execute a command which does that Background: Given that I am logged in as "testuser" - Scenario: Logout + Scenario: Login unauthorized (not existing) Given I execute the "session:login foobar barfoo" command + Then the command should fail + And I should see the following: + """ + Unauthorized + """ + + Scenario: Login existing + Given I execute the "session:login admin admin" command + Then the command should not fail + + Scenario: Login existing + Given I execute the "session:login admin admin default_1" command Then the command should not fail - And I should be logged into the session + And I execute the "session:info" command + Then I should see the following: + """ + default_1 + """ diff --git a/features/session_namespace_set.feature b/features/session_namespace_set.feature index 27bac5c1..5038f65e 100644 --- a/features/session_namespace_set.feature +++ b/features/session_namespace_set.feature @@ -9,4 +9,8 @@ Feature: Set a namespace URI alias Scenario: Register a new namespace alias Given I execute the "session:namespace:set foobar http://www.example.com/foobar" command - Then the command should fail with message "TODO: implement session scope remapping of namespaces" + Then the command should fail + And I should see the following: + """ + TODO: implement session scope remapping of namespaces + """ diff --git a/features/session_node_move.feature b/features/session_node_move.feature index dce184f9..5c8ae11a 100644 --- a/features/session_node_move.feature +++ b/features/session_node_move.feature @@ -8,8 +8,8 @@ Feature: Move a node in the current session And the "session_data.xml" fixtures are loaded Scenario: Move node - Given I execute the "session:node:move /tests_general_base/index.txt /foobar.txt" command + Given I execute the "session:node:move /tests_general_base/index.txt /foobar" command Then the command should not fail - And I save the session - And there should exist a node at "/foobar.txt" + And I execute the "session:save" command + And there should exist a node at "/foobar" And there should not exist a node at "/tests_general_base/index.txt" diff --git a/features/session_node_show.feature b/features/session_node_show.feature index d546d45f..3b64cc49 100644 --- a/features/session_node_show.feature +++ b/features/session_node_show.feature @@ -12,5 +12,4 @@ Feature: Display a detailed view of a single node Then the command should not fail And I should see a table containing the following rows: | Property / Node Name | Type / Node Type | Value | - | - jcr:primaryType | NAME | nt:folder | - | multiValueProperty/ | nt:folder | jcr:uuid: 14e18ef3-be20-4985-bee9-7bb4763b31de, jcr:... | + | - jcr:primaryType | NAME | nt:unstructured | diff --git a/features/session_property_edit.feature b/features/session_property_edit.feature index 9d052e15..bc4d6cb5 100644 --- a/features/session_property_edit.feature +++ b/features/session_property_edit.feature @@ -14,17 +14,6 @@ Feature: Edit a single property Examples: | command | - | session:property:edit /properties/uri | - | session:property:edit /properties/double | - | session:property:edit /properties/binary | - | session:property:edit /properties/long | - | session:property:edit /properties/reference | - | session:property:edit /properties/date | - | session:property:edit /properties/path | - | session:property:edit /properties/string | - | session:property:edit /properties/weakreference | - | session:property:edit /properties/decimal | - | session:property:edit /properties/multivalue 0| | session:property:edit /properties/multivalue 1| Scenario: Edit multivalue property, no index diff --git a/features/session_property_remove.feature b/features/session_property_remove.feature index b49e3c6a..95b61e94 100644 --- a/features/session_property_remove.feature +++ b/features/session_property_remove.feature @@ -5,14 +5,13 @@ Feature: Remove a single property at a specified path Background: Given that I am logged in as "testuser" - And the "session_data.xml" fixtures are loaded + And the "cms.xml" fixtures are loaded Scenario: Remove a property - Given there exists a property at "/tests_general_base/idExample/jcr:content/foo" - And I execute the "session:property:remove /tests_general_base/idExample/jcr:content/foo" command + Given I execute the "session:property:remove /cms/articles/article1/title" command Then the command should not fail And I save the session - And there should not exist a property at "/tests_general_base/idExample/jcr:content/foo" + And there should not exist a property at "/cms/articles/article1/title" Scenario: Try and remove a node And I execute the "session:property:remove /tests_general_base" command diff --git a/features/workspace_create.feature b/features/workspace_create.feature index 93bfdc4d..675515eb 100644 --- a/features/workspace_create.feature +++ b/features/workspace_create.feature @@ -5,9 +5,11 @@ Feature: Create a new workspace Background: Given that I am logged in as "testuser" - And there does not exist a workspace called "footest" - Scenario: Create a workspace - Given I execute the "workspace:create footest" command - Then the command should not fail - And there should exist a workspace called "test" + # Jackrabbit does not allow dropping workspaces, so we cannot reliably + # test creating workspaces. + # + # Scenario: Create a workspace + # Given I execute the "workspace:create footest" command + # Then the command should not fail + # And there should exist a workspace called "test" diff --git a/features/workspace_delete.feature b/features/workspace_delete.feature index 05e369de..51765ffb 100644 --- a/features/workspace_delete.feature +++ b/features/workspace_delete.feature @@ -9,5 +9,8 @@ Feature: Delete a workspace Scenario: Delete a workspace Given there exists a workspace "test" And I execute the "workspace:delete test" command - Then the command should not fail - And there should not exist a workspace called "test" + Then the command should fail + And I should see the following: + """ + Can not delete a workspace as jackrabbit can not do it + """ diff --git a/features/workspace_node_clone.feature b/features/workspace_node_clone.feature index d32f46a3..64551500 100644 --- a/features/workspace_node_clone.feature +++ b/features/workspace_node_clone.feature @@ -5,22 +5,22 @@ Feature: Clone a node from a given workspace to the current workspace Background: Given that I am logged in as "testuser" - And the "session_data.xml" fixtures are loaded into a workspace "test" + And the current workspace is "default_1" + And the "cms.xml" fixtures are loaded + And the current workspace is "default" + And the "cms.xml" fixtures are loaded - Scenario: Clone node - Given the "all_property_types.xml" fixtures are loaded into a workspace "default" - And I execute the "workspace:node:clone test /tests_general_base/index.txt /index.txt" command - Then the command should not fail - And I save the session - And there should exist a node at "/index.txt" + # Scenario: Clone node + # Given the current workspace is "default" + # And I execute the "workspace:node:clone default_1 /cms/articles/article1 /cms/clone" command + # Then the command should not fail + # And I save the session + # And there should exist a node at "/cms/clone" Scenario: Clone onto existing - Given the "session_data.xml" fixtures are loaded into a workspace "default" - And I execute the "workspace:node:clone test /tests_general_base/index.txt /tests_general_base/index.txt" command + Given I execute the "workspace:node:clone default_1 /cms/articles/article1 /cms/articles" command Then the command should fail - And there should exist a node at "/tests_general_base/index.txt" Scenario: Clone onto existing but remove - Given the "session_data.xml" fixtures are loaded into a workspace "default" - And I execute the "workspace:node:clone --remove-existing test / /" command + Given I execute the "workspace:node:clone --remove-existing default_1 /cms/articles/article1 /cms/articles/article1" command Then the command should not fail diff --git a/features/workspace_node_copy.feature b/features/workspace_node_copy.feature index 11268f32..dea07b62 100644 --- a/features/workspace_node_copy.feature +++ b/features/workspace_node_copy.feature @@ -5,8 +5,11 @@ Feature: Copy a node from a given workspace to the current workspace Background: Given that I am logged in as "testuser" - And the "session_data.xml" fixtures are loaded into a workspace "test" - And the "all_property_types.xml" fixtures are loaded into a workspace "default" + And the current workspace is "default_1" + And the "session_data.xml" fixtures are loaded + And the "all_property_types.xml" fixtures are loaded + And the current workspace is "default" + And I purge the current workspace Scenario: Copy node from a different workspace Given I execute the "workspace:node:copy /tests_general_base/index.txt /index.txt test" command diff --git a/features/workspace_use.feature b/features/workspace_use.feature new file mode 100644 index 00000000..c9e6d226 --- /dev/null +++ b/features/workspace_use.feature @@ -0,0 +1,17 @@ +Feature: Switch to given workspace + In order to change the current workspace + As a user logged into the shell + I want to execute a commad that does that + + Background: + Given that I am logged in as "testuser" + And there exists a workspace "foobar" + + Scenario: List workspaces + Given I execute the "workspace:use foobar" command + Then the command should not fail + And I execute the "session:info" command + Then I should see the following: + """ + foobar + """ diff --git a/src/PHPCR/Shell/Console/Application/ShellApplication.php b/src/PHPCR/Shell/Console/Application/ShellApplication.php index abbea9f6..67f591d6 100644 --- a/src/PHPCR/Shell/Console/Application/ShellApplication.php +++ b/src/PHPCR/Shell/Console/Application/ShellApplication.php @@ -29,6 +29,7 @@ use PHPCR\Shell\Console\Command\SessionExportViewCommand; use PHPCR\Shell\Console\Command\SessionImportXMLCommand; use PHPCR\Shell\Console\Command\SessionInfoCommand; +use PHPCR\Shell\Console\Command\SessionLoginCommand; use PHPCR\Shell\Console\Command\SessionLogoutCommand; use PHPCR\Shell\Console\Command\SessionNamespaceListCommand; use PHPCR\Shell\Console\Command\SessionNamespaceSetCommand; @@ -71,8 +72,10 @@ use PHPCR\Shell\Console\Command\VersionRemoveCommand; use PHPCR\Shell\Console\Command\VersionCheckpointCommand; use PHPCR\Shell\Console\Command\NodeCreateCommand; +use PHPCR\Shell\Console\Command\NodeCorrespondingCommand; use PHPCR\Shell\Console\Command\NodeDefinitionCommand; use PHPCR\Shell\Console\Command\NodeSetCommand; +use PHPCR\Shell\Console\Command\NodeSetPrimaryTypeCommand; use PHPCR\Shell\Console\Command\NodeRenameCommand; use PHPCR\Shell\Console\Command\NodeMixinAddCommand; use PHPCR\Shell\Console\Command\NodeMixinRemoveCommand; @@ -80,6 +83,7 @@ use PHPCR\Shell\Console\Command\NodeLifecycleFollowCommand; use PHPCR\Shell\Console\Command\NodeLifecycleListCommand; use PHPCR\Shell\Console\Command\NodeListCommand; +use PHPCR\Shell\Console\Command\NodeUpdateCommand; use PHPCR\Shell\Console\Command\NodeReferencesCommand; use PHPCR\Shell\Console\Command\NodeSharedShowCommand; use PHPCR\Shell\Console\Command\NodeSharedRemoveCommand; @@ -138,15 +142,15 @@ public function init() $this->transports[$transport->getName()] = $transport;; } - $session = $this->getSession($this->sessionInput); + $session = $this->initSession(); - $this->getHelperSet()->set(new EditorHelper($session)); + $this->getHelperSet()->set(new EditorHelper($this->session)); $this->getHelperSet()->set(new PhpcrConsoleDumperHelper()); - $this->getHelperSet()->set(new PhpcrHelper($session)); + $this->getHelperSet()->set(new PhpcrHelper($this->session)); $this->getHelperSet()->set(new ResultFormatterHelper()); $this->getHelperSet()->set(new TextHelper()); - $this->getHelperSet()->set(new NodeHelper($session)); - $this->getHelperSet()->set(new RepositoryHelper($session->getRepository())); + $this->getHelperSet()->set(new NodeHelper($this->session)); + $this->getHelperSet()->set(new RepositoryHelper($this->session->getRepository())); // add new commands $this->add(new AccessControlPrivilegeListCommand()); @@ -155,6 +159,7 @@ public function init() $this->add(new SessionImpersonateCommand()); $this->add(new SessionImportXMLCommand()); $this->add(new SessionInfoCommand()); + $this->add(new SessionLoginCommand()); $this->add(new SessionLogoutCommand()); $this->add(new SessionNamespaceListCommand()); $this->add(new SessionNamespaceSetCommand()); @@ -193,8 +198,10 @@ public function init() $this->add(new VersionCheckpointCommand()); $this->add(new VersionCheckinCommand()); $this->add(new NodeCreateCommand()); + $this->add(new NodeCorrespondingCommand()); $this->add(new NodeDefinitionCommand()); $this->add(new NodeSetCommand()); + $this->add(new NodeSetPrimaryTypeCommand()); $this->add(new NodeRenameCommand()); $this->add(new NodeMixinAddCommand()); $this->add(new NodeMixinRemoveCommand()); @@ -202,6 +209,7 @@ public function init() $this->add(new NodeLifecycleFollowCommand()); $this->add(new NodeLifecycleListCommand()); $this->add(new NodeListCommand()); + $this->add(new NodeUpdateCommand()); $this->add(new NodeReferencesCommand()); $this->add(new NodeSharedShowCommand()); $this->add(new NodeSharedRemoveCommand()); @@ -284,6 +292,18 @@ public function changeWorkspace($workspaceName) $this->initSession($this->sessionInput); } + public function relogin($username, $password, $workspaceName = null) + { + $this->session->logout(); + $this->sessionInput->setOption('phpcr-username', $username); + $this->sessionInput->setOption('phpcr-password', $password); + + if ($workspaceName) { + $this->sessionInput->setOption('phpcr-workspace', $workspaceName); + } + $this->initSession($this->sessionInput); + } + private function getTransport(InputInterface $input) { $transportName = $input->getOption('transport'); @@ -360,4 +380,17 @@ public function renderException($e, $output) $output->writeln(sprintf('%s', $e->getMessage())); } while ($e = $e->getPrevious()); } + + public function add(Command $command) + { + if ($command instanceof PhpcrShellCommand) { + $showUnsupported = $this->sessionInput->getOption('unsupported'); + + if ($showUnsupported || $command->isSupported($this->getHelperSet()->get('repository'))) { + return parent::add($command); + } + } else { + parent::add($command); + } + } } diff --git a/src/PHPCR/Shell/Console/Command/NodeCorrespondingCommand.php b/src/PHPCR/Shell/Console/Command/NodeCorrespondingCommand.php new file mode 100644 index 00000000..54d3ece6 --- /dev/null +++ b/src/PHPCR/Shell/Console/Command/NodeCorrespondingCommand.php @@ -0,0 +1,37 @@ +setName('node:corresponding'); + $this->setDescription('Show the path for the current nodes corresponding path in named workspace'); + $this->addArgument('workspaceName', InputArgument::REQUIRED, 'The name of the workspace'); + $this->setHelp(<<getHelper('phpcr')->getSession(); + $workspaceName = $input->getArgument('workspaceName'); + $currentNode = $session->getCurrentNode(); + $correspondingPath = $currentNode->getCorrespondingNodePath($workspaceName); + $output->writeln($correspondingPath); + } +} diff --git a/src/PHPCR/Shell/Console/Command/NodeListCommand.php b/src/PHPCR/Shell/Console/Command/NodeListCommand.php index 1de31c65..807cb8f3 100644 --- a/src/PHPCR/Shell/Console/Command/NodeListCommand.php +++ b/src/PHPCR/Shell/Console/Command/NodeListCommand.php @@ -82,7 +82,7 @@ private function renderProperties($currentNode, $table) $table->addRow(array( '' . $name . '', '' . $this->formatter->getPropertyTypeName($property->getType()) . '', - '' . $this->textHelper->truncate($this->formatter->formatValue($property), 55) . '', + $this->textHelper->truncate($this->formatter->formatValue($property), 55), )); } } diff --git a/src/PHPCR/Shell/Console/Command/NodeSetPrimaryTypeCommand.php b/src/PHPCR/Shell/Console/Command/NodeSetPrimaryTypeCommand.php new file mode 100644 index 00000000..866df51b --- /dev/null +++ b/src/PHPCR/Shell/Console/Command/NodeSetPrimaryTypeCommand.php @@ -0,0 +1,43 @@ +setName('node:set-primary-type'); + $this->setDescription('Set the primary type of the current node'); + $this->addArgument('nodeTypeName', null, InputArgument::REQUIRED, null, 'New primary node type name'); + $this->setHelp(<<getHelper('phpcr')->getSession(); + $nodeTypeName = $input->getArgument('nodeTypeName'); + + $currentNode = $session->getCurrentNode(); + $currentNode->setPrimaryType($nodeTypeName); + } +} diff --git a/src/PHPCR/Shell/Console/Command/NodeUpdateCommand.php b/src/PHPCR/Shell/Console/Command/NodeUpdateCommand.php new file mode 100644 index 00000000..3f2e540e --- /dev/null +++ b/src/PHPCR/Shell/Console/Command/NodeUpdateCommand.php @@ -0,0 +1,47 @@ +setName('node:update'); + $this->setDescription('Updates a node corresponding to the current one in the given workspace'); + $this->addArgument('srcWorkspace', null, InputArgument::REQUIRED, 'The name of the source workspace'); + $this->setHelp(<<getHelper('phpcr')->getSession(); + $srcWorkspace = $input->getArgument('srcWorkspace'); + $currentNode = $session->getCurrentNode(); + $currentNode->update($srcWorkspace); + } +} diff --git a/src/PHPCR/Shell/Console/Command/PhpcrShellCommand.php b/src/PHPCR/Shell/Console/Command/PhpcrShellCommand.php index b682b8cd..1c33712e 100644 --- a/src/PHPCR/Shell/Console/Command/PhpcrShellCommand.php +++ b/src/PHPCR/Shell/Console/Command/PhpcrShellCommand.php @@ -3,6 +3,7 @@ namespace PHPCR\Shell\Console\Command; use Symfony\Component\Console\Command\Command; +use PHPCR\Shell\Console\Helper\RepositoryHelper; class PhpcrShellCommand extends Command { @@ -19,17 +20,27 @@ public function dequiresDescriptor($descriptorKey, $value = null) $this->descriptorDequires[$descriptorKey] = $value; } - public function isEnabled() + public function getDescriptorRequires() + { + return $this->descriptorRequires; + } + + public function getDescriptorDequires() + { + return $this->descriptorDequires; + } + + public function isSupported(RepositoryHelper $repositoryHelper) { foreach ($this->descriptorRequires as $key => $value) { - $has = $this->getHelper('repository')->hasDescriptor($key, $value); + $has = $repositoryHelper->hasDescriptor($key, $value); if (!$has) { return false; } } foreach ($this->descriptorDequires as $key => $value) { - $has = $this->getHelper('repository')->hasDescriptor($key, $value); + $has = $repositoryHelper->hasDescriptor($key, $value); if ($has) { return false; @@ -38,4 +49,10 @@ public function isEnabled() return true; } + + public function getDescriptor() + { + + return true; + } } diff --git a/src/PHPCR/Shell/Console/Command/SessionLoginCommand.php b/src/PHPCR/Shell/Console/Command/SessionLoginCommand.php new file mode 100644 index 00000000..ed519490 --- /dev/null +++ b/src/PHPCR/Shell/Console/Command/SessionLoginCommand.php @@ -0,0 +1,31 @@ +setName('session:login'); + $this->setDescription('Login or (relogin) to a session'); + $this->addArgument('userId', InputArgument::REQUIRED, 'Unique identifier of user'); + $this->addArgument('password', InputArgument::REQUIRED, 'Password'); + $this->addArgument('workspaceName', InputArgument::OPTIONAL, 'Optional workspace name'); + $this->setHelp(<<getArgument('userId'); + $password = $input->getArgument('password'); + $workspaceName = $input->getArgument('workspaceName'); + $this->getApplication()->relogin($username, $password, $workspaceName); + } +} diff --git a/src/PHPCR/Shell/Console/Command/ShellCommand.php b/src/PHPCR/Shell/Console/Command/ShellCommand.php index 63ec3962..c93e4a97 100644 --- a/src/PHPCR/Shell/Console/Command/ShellCommand.php +++ b/src/PHPCR/Shell/Console/Command/ShellCommand.php @@ -42,6 +42,7 @@ public function configure() new InputOption('--db-driver', '-dd', InputOption::VALUE_REQUIRED, 'Database Transport.', 'pdo_mysql'), new InputOption('--db-path', '-dP', InputOption::VALUE_REQUIRED, 'Database Path.'), new InputOption('--no-interaction', null, InputOption::VALUE_NONE, 'Turn off interaction (for testing purposes)'), + new InputOption('--unsupported', null, InputOption::VALUE_NONE, 'Show all commands, including commands not supported by the repository'), new InputOption('--repo-url', '-url', InputOption::VALUE_REQUIRED, 'URL of repository (e.g. for jackrabbit).', 'http://localhost:8080/server/' ), diff --git a/src/PHPCR/Shell/Console/Command/WorkspaceNodeCloneCommand.php b/src/PHPCR/Shell/Console/Command/WorkspaceNodeCloneCommand.php index 60ee7a34..cbdcc596 100644 --- a/src/PHPCR/Shell/Console/Command/WorkspaceNodeCloneCommand.php +++ b/src/PHPCR/Shell/Console/Command/WorkspaceNodeCloneCommand.php @@ -57,11 +57,13 @@ protected function configure() public function execute(InputInterface $input, OutputInterface $output) { $session = $this->getHelper('phpcr')->getSession(); + $srcWorkspace = $input->getArgument('srcWorkspace'); $srcAbsPath = $input->getArgument('srcAbsPath'); $destAbsPath = $input->getArgument('destAbsPath'); - $srcWorkspace = $input->getArgument('srcWorkspace'); $removeExisting = $input->getOption('remove-existing'); + // todo: Check to ensure that source node has the referenceable mixin + $workspace = $session->getWorkspace(); $workspace->cloneFrom($srcWorkspace, $srcAbsPath, $destAbsPath, $removeExisting); } diff --git a/tests/PHPCR/Shell/Application/ShellApplicationTest.php b/tests/PHPCR/Shell/Application/ShellApplicationTest.php index ef7dd9a3..1395f1ef 100644 --- a/tests/PHPCR/Shell/Application/ShellApplicationTest.php +++ b/tests/PHPCR/Shell/Application/ShellApplicationTest.php @@ -12,9 +12,6 @@ public function setUp() $this->transport = $this->getMock( 'PHPCR\Shell\Console\TransportInterface' ); - $this->transport->expects($this->once()) - ->method('getName') - ->will($this->returnValue('test')); $this->sessionInput = $this->getMock( 'Symfony\Component\Console\Input\InputInterface' @@ -39,15 +36,9 @@ public function setUp() $this->repository = $this->getMock( 'PHPCR\RepositoryInterface' ); - $this->repository->expects($this->once()) - ->method('login') - ->will($this->returnValue($this->session)); - - $this->transport->expects($this->once()) - ->method('getRepository') - ->will($this->returnValue($this->repository)); $this->application = new ShellApplication('phpcr','v0.test', $this->sessionInput, array($this->transport)); + $this->application->setSessionInput($this->sessionInput); $this->application->setAutoExit(false); } diff --git a/tests/PHPCR/Shell/Helper/RepositoryHelperTest.php b/tests/PHPCR/Shell/Helper/RepositoryHelperTest.php new file mode 100644 index 00000000..76cd83a6 --- /dev/null +++ b/tests/PHPCR/Shell/Helper/RepositoryHelperTest.php @@ -0,0 +1,61 @@ +repository = $this->getMock('PHPCR\RepositoryInterface'); + $this->helper = new RepositoryHelper($this->repository); + } + + public function testHasDescriptor() + { + $descriptors = array( + 'foobar' => true, + 'barfoo' => true, + 'zoobar' => false, + 'true' => 'true', + 'false' => 'false', + ); + + $this->repository->expects($this->once()) + ->method('getDescriptorKeys') + ->will($this->returnValue(array_keys($descriptors))); + + $this->repository->expectS($this->any()) + ->method('getDescriptor') + ->will($this->returnCallback(function ($k) use ($descriptors) { + return $descriptors[$k]; + })); + + $res = $this->helper->hasDescriptor('zoobar', false); + $this->assertTrue($res); + + $res = $this->helper->hasDescriptor('foobar'); + $this->assertTrue($res); + + $res = $this->helper->hasDescriptor('asdasd'); + $this->assertFalse($res); + + $res = $this->helper->hasDescriptor(''); + $this->assertFalse($res); + + $res = $this->helper->hasDescriptor('foobar', 'asdasd'); + $this->assertFalse($res); + + $res = $this->helper->hasDescriptor('true', true); + $this->assertTrue($res); + + $res = $this->helper->hasDescriptor('false', false); + $this->assertTrue($res); + } +} +