more ocm tests

This commit is contained in:
Viktor Scharf
2024-07-03 22:24:14 +02:00
parent 4b05f35d52
commit 97bce8edd4
11 changed files with 640 additions and 38 deletions

View File

@@ -80,6 +80,7 @@ class OcmHelper {
* @param string $user
* @param string $password
* @param string $token
* @param string $providerDomain
*
* @return ResponseInterface
* @throws GuzzleException
@@ -89,11 +90,12 @@ class OcmHelper {
string $xRequestId,
string $user,
string $password,
string $token
string $token,
string $providerDomain,
): ResponseInterface {
$body = [
"token" => $token,
"providerDomain" => 'ocis-server'
"providerDomain" => $providerDomain
];
$url = self::getFullUrl($baseUrl, 'accept-invite');
return HttpRequestHelper::post(

View File

@@ -364,6 +364,8 @@ default:
contexts:
- FeatureContext: *common_feature_context_params
- OcmContext:
- SharingNgContext:
- SpacesContext:
extensions:
rdx\behatvars\BehatVariablesExtension: ~

View File

@@ -307,5 +307,10 @@ The expected failures in this file are from features in the owncloud/ocis repo.
- [apiSpacesDavOperation/moveByFileId.feature:209](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L209)
### [OCM. sharing issues](https://github.com/owncloud/ocis/issues/9534)
- [apiOcm/share.feature:12](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiOcm/share.feature#L12)
- [apiOcm/share.feature:90](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiOcm/share.feature#L90)
- Note: always have an empty line at the end of this file.
The bash script that processes this file requires that the last line has a newline on the end.

View File

@@ -0,0 +1,137 @@
@ocm
Feature: accepting invitation
As a user
I can accept invitations from users of other ocis instances
Background:
Given user "Alice" has been created with default attributes and without skeleton files
And using server "REMOTE"
Given these users have been created with default attributes and without skeleton files:
| username |
| Brian |
| Carol |
Scenario: user accepts invitation
Given using server "LOCAL"
When "Alice" creates the federation share invitation
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"expiration",
"token"
],
"properties": {
"expiration": {
"type": "integer",
"pattern": "^[0-9]{10}$"
},
"token": {
"type": "string",
"pattern": "^%fed_invitation_token_pattern%$"
}
}
}
"""
When using server "REMOTE"
And "Brian" accepts the last federation share invitation
Then the HTTP status code should be "200"
Scenario: user accepts invitation sent with email and description
Given using server "LOCAL"
When "Alice" creates the federation share invitation with email "alice@example.com" and description "a share invitation from Alice"
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"expiration",
"token"
],
"properties": {
"expiration": {
"type": "integer",
"pattern": "^[0-9]{10}$"
},
"token": {
"type": "string",
"pattern": "^%fed_invitation_token_pattern%$"
}
}
}
"""
When using server "REMOTE"
And "Brian" accepts the last federation share invitation
Then the HTTP status code should be "200"
Scenario: two users can accept one invitation
Given using server "LOCAL"
And "Alice" has created the federation share invitation
When using server "REMOTE"
And "Brian" accepts the last federation share invitation
Then the HTTP status code should be "200"
And "Carol" accepts the last federation share invitation
Then the HTTP status code should be "200"
Scenario: user tries to accept the invitation twice
Given using server "LOCAL"
And "Alice" has created the federation share invitation
When using server "REMOTE"
And "Brian" accepts the last federation share invitation
Then the HTTP status code should be "200"
When "Brian" tries to accept the last federation share invitation
Then the HTTP status code should be "409"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"const": "ALREADY_EXIST"
},
"message": {
"const": "user already known"
}
}
}
"""
Scenario: users try to accept each other's invitation
Given using server "LOCAL"
And "Alice" has created the federation share invitation
And using server "REMOTE"
And "Brian" has accepted invitation
And "Brian" has created the federation share invitation
When using server "LOCAL"
And "Alice" tries to accept the last federation share invitation
Then the HTTP status code should be "409"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"const": "ALREADY_EXIST"
},
"message": {
"const": "user already known"
}
}
}
"""

View File

@@ -1,20 +0,0 @@
@ocm
Feature: an user shares resources usin ScienceMesh application
As a user
I want to share resources between different ocis instances
Background:
Given these users have been created with default attributes and without skeleton files:
| username |
| Alice |
And using server "REMOTE"
And user "Brian" has been created with default attributes and without skeleton files
Scenario: user generates invitation
Given using server "LOCAL"
When "Alice" generates invitation
Then the HTTP status code should be "200"
When using server "REMOTE"
And "Brian" accepts invitation
Then the HTTP status code should be "200"

View File

@@ -0,0 +1,212 @@
@ocm
Feature: search federation users
As a user
I can find federation users after accepting an invitation to share resources
Background:
Given these users have been created with default attributes and without skeleton files:
| username |
| Alice |
| Carol |
And using server "REMOTE"
And user "Brian" has been created with default attributes and without skeleton files
Scenario: users search for federation users by display name
Given using server "LOCAL"
And "Alice" has created the federation share invitation
And using server "REMOTE"
And "Brian" has accepted invitation
When user "Brian" searches for user "ali" using Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": {
"type": "object",
"required": [
"displayName",
"id"
],
"properties": {
"displayName": {
"const": "Alice Hansen"
},
"id": {
"type": "string",
"pattern": "^%user_id_pattern%$"
}
}
}
}
}
}
"""
And using server "LOCAL"
When user "Alice" searches for user "bri" using Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": {
"type": "object",
"required": [
"displayName",
"id"
],
"properties": {
"displayName": {
"const": "Brian Murphy"
},
"id": {
"type": "string",
"pattern": "^%user_id_pattern%$"
}
}
}
}
}
}
"""
Scenario: sers search for federation users by email
Given using server "LOCAL"
And "Alice" has created the federation share invitation
And using server "REMOTE"
And "Brian" has accepted invitation
When user "Brian" searches for user "%22alice@example.org%22" using Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": {
"type": "object",
"required": [
"displayName",
"id"
],
"properties": {
"displayName": {
"const": "Alice Hansen"
},
"id": {
"type": "string",
"pattern": "^%user_id_pattern%$"
}
}
}
}
}
}
"""
And using server "LOCAL"
When user "Alice" searches for user "%22brian@example.org%22" using Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": {
"type": "object",
"required": [
"displayName",
"id"
],
"properties": {
"displayName": {
"const": "Brian Murphy"
},
"id": {
"type": "string",
"pattern": "^%user_id_pattern%$"
}
}
}
}
}
}
"""
Scenario: sers search for federation users without federated connection
Given using server "LOCAL"
And "Alice" has created the federation share invitation
And using server "REMOTE"
And "Brian" has accepted invitation
When user "Brian" searches for user "%22carol@example.org%22" using Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 0,
"maxItems": 0
}
}
}
"""
And using server "LOCAL"
When user "Carol" searches for user "bria" using Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 0,
"maxItems": 0
}
}
}
"""
And using server "REMOTE"
# TODO try to find federation users after deleting federated conection

View File

@@ -0,0 +1,165 @@
@ocm
Feature: an user shares resources usin ScienceMesh application
As a user
I want to share resources between different ocis instances
Background:
Given user "Alice" has been created with default attributes and without skeleton files
And using server "REMOTE"
And user "Brian" has been created with default attributes and without skeleton files
Scenario: users shares folder to federation users after receiver accepted invitation
Given using server "LOCAL"
And "Alice" has created the federation share invitation
And using server "REMOTE"
And "Brian" has accepted invitation
And using server "LOCAL"
And user "Alice" has created folder "folderToShare"
When user "Alice" sends the following resource share invitation using the Graph API:
| resource | folderToShare |
| space | Personal |
| sharee | Brian |
| shareType | user |
| permissionsRole | Viewer |
Then the HTTP status code should be "200"
When using server "REMOTE"
And user "Brian" lists the shares shared with him using the Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": {
"type": "object",
"required": [
"@UI.Hidden",
"@client.synchronize",
"createdBy",
"name"
],
"properties": {
"@UI.Hidden":{
"type": "boolean",
"enum": [false]
},
"@client.synchronize":{
"type": "boolean",
"enum": [true]
},
"createdBy": {
"type": "object",
"required": [
"user"
],
"properties": {
"user": {
"type": "object",
"required": ["displayName", "id"],
"properties": {
"displayName": {
"type": "string",
"const": "Alice Hansen"
},
"id": {
"type": "string",
"pattern": "^%user_id_pattern%$"
}
}
}
}
},
"name": {
"const": "folderToShare"
}
}
}
}
}
}
"""
Scenario: users shares folder to federation users after accepting invitation
Given using server "LOCAL"
And "Alice" has created the federation share invitation
And using server "REMOTE"
And "Brian" has accepted invitation
And user "Brian" has created folder "folderToShare"
When user "Brian" sends the following resource share invitation using the Graph API:
| resource | folderToShare |
| space | Personal |
| sharee | Alice |
| shareType | user |
| permissionsRole | Viewer |
Then the HTTP status code should be "200"
When using server "LOCAL"
And user "Alice" lists the shares shared with her using the Graph API
Then the HTTP status code should be "200"
And the JSON data of the response should match
"""
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": {
"type": "object",
"required": [
"@UI.Hidden",
"@client.synchronize",
"createdBy",
"name"
],
"properties": {
"@UI.Hidden":{
"type": "boolean",
"enum": [false]
},
"@client.synchronize":{
"type": "boolean",
"enum": [true]
},
"createdBy": {
"type": "object",
"required": [
"user"
],
"properties": {
"user": {
"type": "object",
"required": ["displayName", "id"],
"properties": {
"displayName": {
"type": "string",
"const": "Brian Murphy"
},
"id": {
"type": "string",
"pattern": "^%user_id_pattern%$"
}
}
}
}
},
"name": {
"const": "folderToShare"
}
}
}
}
}
}
"""

View File

@@ -2250,6 +2250,14 @@ class FeatureContext extends BehatVariablesContext {
"getTusResourceLocation"
],
"parameter" => []
],
[
"code" => "%fed_invitation_token_pattern%",
"function" => [
__NAMESPACE__ . '\TestHelpers\GraphHelper',
"getUUIDv4Regex"
],
"parameter" => []
]
];
if ($user !== null) {

View File

@@ -22,11 +22,12 @@
use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\ResponseInterface;
use TestHelpers\OcisHelper;
use TestHelpers\OcmHelper;
/**
* Acceptance test steps related to testing sharing ng features
* Acceptance test steps related to testing federation share(ocm) features
*/
class OcmContext implements Context {
private FeatureContext $featureContext;
@@ -53,17 +54,40 @@ class OcmContext implements Context {
}
/**
* @When :user generates invitation
* @When :user generates invitation with email :email and description :description
* @return string
*/
public function getOcisDomain(): string {
return $this->extractDomain(\getenv('TEST_SERVER_URL'));
}
/**
* @return string
*/
public function getFedOcisDomain(): string {
return $this->extractDomain(\getenv('TEST_SERVER_FED_URL'));
}
/**
* @param string $url
*
* @return string
*/
public function extractDomain($url): string {
if (!$url) {
return "localhost";
}
return parse_url($url)["host"];
}
/**
* @param string $user
* @param string $email
* @param string $description
*
* @return void
* @return ResponseInterface
* @throws GuzzleException
*/
public function userGeneratesInvitation(string $user, $email = null, $description = null): void {
public function createInvitation(string $user, $email = null, $description = null): ResponseInterface {
$response = OcmHelper::createInvitation(
$this->featureContext->getBaseUrl(),
$this->featureContext->getStepLineRef(),
@@ -72,26 +96,84 @@ class OcmContext implements Context {
$email,
$description
);
$this->featureContext->setResponse($response);
$this->invitationToken = $this->featureContext->getJsonDecodedResponse($this->featureContext->getResponse())['token'];
$responseData = \json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (isset($responseData["token"])) {
$this->invitationToken = $responseData["token"];
} else {
throw new Exception(__METHOD__ . " response doesn't contain token");
}
return $response;
}
/**
* @When :user accepts invitation
* @When :user creates the federation share invitation
* @When :user creates the federation share invitation with email :email and description :description
*
* @param string $user
* @param string $email
* @param string $description
*
* @return void
* @throws GuzzleException
*/
public function userCreatesTheFederationShareInvitation(string $user, $email = null, $description = null): void {
$this->featureContext->setResponse($this->createInvitation($user, $email, $description));
}
/**
* @Given :user has created the federation share invitation
*
* @param string $user
*
* @return void
* @throws GuzzleException
*/
public function userAcceptsInvitation(string $user): void {
$response = OcmHelper::acceptInvitation(
public function userHasCreatedTheFederationShareInvitation(string $user): void {
$response = $this->createInvitation($user);
$this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response);
}
/**
* @param string $user
*
* @return ResponseInterface
* @throws GuzzleException
*/
public function acceptInvitation(string $user): ResponseInterface {
$providerDomain = ($this->featureContext->getCurrentServer() === "LOCAL") ? $this->getFedOcisDomain() : $this->getOcisDomain();
return OcmHelper::acceptInvitation(
$this->featureContext->getBaseUrl(),
$this->featureContext->getStepLineRef(),
$user,
$this->featureContext->getPasswordForUser($user),
$this->invitationToken
$this->invitationToken,
$providerDomain
);
$this->featureContext->setResponse($response);
}
/**
* @When :user accepts the last federation share invitation
* @When :user tries to accept the last federation share invitation
*
* @param string $user
*
* @return void
* @throws GuzzleException
*/
public function userAcceptsTheLastFederationShareInvitation(string $user): void {
$this->featureContext->setResponse($this->acceptInvitation($user));
}
/**
* @Given :user has accepted invitation
*
* @param string $user
*
* @return void
* @throws GuzzleException
*/
public function userHasAcceptedTheLastFederationShareInvitation(string $user): void {
$response = $this->acceptInvitation($user);
$this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response);
}
}

View File

@@ -83,6 +83,13 @@ trait Provisioning {
return $this->createdUsers;
}
/**
* @return array
*/
public function getAllCreatedUsers():array {
return array_merge($this->createdUsers, $this->createdRemoteUsers);
}
/**
* @return boolean
*/
@@ -107,8 +114,9 @@ trait Provisioning {
*/
public function getUserDisplayName(string $username):string {
$normalizedUsername = $this->normalizeUsername($username);
if (isset($this->createdUsers[$normalizedUsername]['displayname'])) {
$displayName = (string) $this->createdUsers[$normalizedUsername]['displayname'];
$users = $this->getAllCreatedUsers();
if (isset($users[$normalizedUsername]['displayname'])) {
$displayName = (string) $users[$normalizedUsername]['displayname'];
if ($displayName !== '') {
return $displayName;
}
@@ -124,7 +132,7 @@ trait Provisioning {
* @throws Exception
*/
public function getAttributeOfCreatedUser(string $user, string $attribute) {
$usersList = $this->getCreatedUsers();
$usersList = $this->getAllCreatedUsers();
$normalizedUsername = $this->normalizeUsername($user);
if (\array_key_exists($normalizedUsername, $usersList)) {
if (\array_key_exists($attribute, $usersList[$normalizedUsername])) {
@@ -1118,6 +1126,7 @@ trait Provisioning {
// See comment above about the LOCAL case. The logic is the same for the remote case.
if ($shouldExist || !\array_key_exists($normalizedUsername, $this->createdRemoteUsers)) {
$this->createdRemoteUsers[$normalizedUsername] = $userData;
$this->createdUsers[$normalizedUsername] = $userData;
}
}
}

View File

@@ -1,4 +1,4 @@
export OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE=${workspaceFolder}/tests/config/drone/providers.json
export OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE=tests/config/drone/providers.json
export OCM_OCM_INVITE_MANAGER_INSECURE=true
export OCM_OCM_SHARE_PROVIDER_INSECURE=true
export OCM_OCM_STORAGE_PROVIDER_INSECURE=true