Skip to content

Commit ed6c0e5

Browse files
Merge pull request #11277 from owncloud/check-base-path-is-accessible-or-not
[tests-only][full-ci] Add cli test for deleting stale uploads
2 parents 48808f6 + 6c9a98a commit ed6c0e5

File tree

3 files changed

+277
-11
lines changed

3 files changed

+277
-11
lines changed

.drone.star

+14-7
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,12 @@ pipelineVolumeGo = \
363363
"temp": {},
364364
}
365365

366+
stepVolumeOcisStorage = \
367+
{
368+
"name": "storage",
369+
"path": "/root/.ocis",
370+
}
371+
366372
# minio mc environment variables
367373
MINIO_MC_ENV = {
368374
"CACHE_BUCKET": S3_CACHE_BUCKET,
@@ -1030,7 +1036,7 @@ def localApiTestPipeline(ctx):
10301036
restoreBuildArtifactCache(ctx, "ocis-binary-amd64", "ocis/bin") +
10311037
(tikaService() if params["tikaNeeded"] else []) +
10321038
(waitForServices("online-offices", ["collabora:9980", "onlyoffice:443", "fakeoffice:8080"]) if params["collaborationServiceNeeded"] else []) +
1033-
ocisServer(storage, params["accounts_hash_difficulty"], extra_server_environment = params["extraServerEnvironment"], with_wrapper = True, tika_enabled = params["tikaNeeded"]) +
1039+
ocisServer(storage, params["accounts_hash_difficulty"], extra_server_environment = params["extraServerEnvironment"], with_wrapper = True, tika_enabled = params["tikaNeeded"], volumes = ([stepVolumeOcisStorage] if name.startswith("cli") else [])) +
10341040
(waitForClamavService() if params["antivirusNeeded"] else []) +
10351041
(waitForEmailService() if params["emailNeeded"] else []) +
10361042
(ocisServer(storage, params["accounts_hash_difficulty"], deploy_type = "federation", extra_server_environment = params["extraServerEnvironment"]) if params["federationServer"] else []) +
@@ -1049,6 +1055,10 @@ def localApiTestPipeline(ctx):
10491055
"refs/pull/**",
10501056
],
10511057
},
1058+
"volumes": [{
1059+
"name": "storage",
1060+
"temp": {},
1061+
}],
10521062
}
10531063
pipelines.append(pipeline)
10541064
return pipelines
@@ -1120,6 +1130,7 @@ def localApiTests(ctx, name, suites, storage = "ocis", extra_environment = {}, w
11201130
"" if with_remote_php else "cat %s/expected-failures-without-remotephp.md >> %s" % (test_dir, expected_failures_file),
11211131
"make -C %s test-acceptance-api" % (dirs["base"]),
11221132
],
1133+
"volumes": [stepVolumeOcisStorage],
11231134
}]
11241135

11251136
def cs3ApiTests(ctx, storage, accounts_hash_difficulty = 4):
@@ -1525,12 +1536,8 @@ def multiServiceE2ePipeline(ctx):
15251536
for item in storage_users_environment:
15261537
storage_users2_environment[item] = storage_users_environment[item]
15271538

1528-
storage_volume = [{
1529-
"name": "storage",
1530-
"path": "/root/.ocis",
1531-
}]
1532-
storage_users_services = startOcisService("storage-users", "storageusers1", storage_users1_environment, storage_volume) + \
1533-
startOcisService("storage-users", "storageusers2", storage_users2_environment, storage_volume) + \
1539+
storage_users_services = startOcisService("storage-users", "storageusers1", storage_users1_environment, [stepVolumeOcisStorage]) + \
1540+
startOcisService("storage-users", "storageusers2", storage_users2_environment, [stepVolumeOcisStorage]) + \
15341541
ocisHealthCheck("storage-users", ["storageusers1:9159", "storageusers2:9159"])
15351542

15361543
for _, suite in config["e2eMultiService"].items():

tests/acceptance/bootstrap/CliContext.php

+181-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
2424
use Behat\Behat\Context\Context;
25+
use Behat\Gherkin\Node\PyStringNode;
2526
use Behat\Gherkin\Node\TableNode;
2627
use GuzzleHttp\Exception\GuzzleException;
2728
use PHPUnit\Framework\Assert;
@@ -295,10 +296,8 @@ public function theAdministratorRemovesTheVersionsOfFilesInSpaceUsingSpaceId(str
295296
* @return void
296297
*/
297298
public function theCommandShouldBeSuccessful(string $successfulOrNot): void {
298-
$response = $this->featureContext->getResponse();
299-
$this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response);
300-
301-
$jsonResponse = $this->featureContext->getJsonDecodedResponse($response);
299+
$this->featureContext->theHTTPStatusCodeShouldBe(200);
300+
$jsonResponse = $this->featureContext->getJsonDecodedResponse();
302301

303302
$expectedStatus = 'OK';
304303
$expectedExitCode = 0;
@@ -480,6 +479,16 @@ public function cleanUploadsSessions(): void {
480479
Assert::assertEquals("200", $response->getStatusCode(), "Failed to clean upload sessions");
481480
}
482481

482+
/**
483+
* @AfterScenario @cli-stale-uploads
484+
*
485+
* @return void
486+
*/
487+
public function cleanUpStaleUploads(): void {
488+
$response = $this->deleteStaleUploads();
489+
$this->featureContext->theHTTPStatusCodeShouldBe(200, "Failed to cleanup stale upload", $response);
490+
}
491+
483492
/**
484493
* @When /^the administrator triggers "([^"]*)" email notifications using the CLI$/
485494
*
@@ -496,4 +505,172 @@ public function theAdministratorTriggersEmailNotificationsUsingTheCLI(string $in
496505

497506
$this->featureContext->setResponse(CliHelper::runCommand($body));
498507
}
508+
509+
/**
510+
* @Given the administrator has created stale upload
511+
*
512+
* @return void
513+
*/
514+
public function theAdministratorHasCreatedStaleUpload(): void {
515+
$folderPath = $this->featureContext->getStorageUsersRoot() . "/uploads";
516+
$infoFiles = glob($folderPath . '/*.info');
517+
foreach ($infoFiles as $file) {
518+
if (!unlink($file)) {
519+
Assert::fail("Fail to delete info file");
520+
}
521+
}
522+
}
523+
524+
/**
525+
* @param string|null $spaceId
526+
*
527+
* @return ResponseInterface
528+
* @throws GuzzleException
529+
*/
530+
protected function listStaleUploads(?string $spaceId = null): ResponseInterface {
531+
$command = "storage-users uploads delete-stale-nodes --dry-run=true";
532+
533+
if ($spaceId !== null) {
534+
$command .= " --spaceid=$spaceId";
535+
}
536+
537+
$body = [
538+
"command" => $command
539+
];
540+
return CliHelper::runCommand($body);
541+
}
542+
543+
/**
544+
* @param string|null $spaceId
545+
*
546+
* @return ResponseInterface
547+
* @throws GuzzleException
548+
*/
549+
protected function deleteStaleUploads(?string $spaceId = null): ResponseInterface {
550+
$command = "storage-users uploads delete-stale-nodes --dry-run=false";
551+
if ($spaceId !== null) {
552+
$command .= " --spaceid=$spaceId";
553+
}
554+
555+
$body = [
556+
"command" => $command
557+
];
558+
return CliHelper::runCommand($body);
559+
}
560+
561+
/**
562+
* @When the administrator lists all the stale uploads
563+
*
564+
* @return void
565+
*/
566+
public function theAdministratorListsAllTheStaleUploads(): void {
567+
$this->featureContext->setResponse($this->listStaleUploads());
568+
}
569+
570+
/**
571+
* @When the administrator lists all the stale uploads of space :space owned by user :user
572+
*
573+
* @param string $spaceName
574+
* @param string $user
575+
*
576+
* @return void
577+
*/
578+
public function theAdministratorListsTheStaleUploadsOfSpace(
579+
string $spaceName,
580+
string $user
581+
): void {
582+
$space = $this->spacesContext->getSpaceByName(
583+
$user,
584+
$spaceName
585+
);
586+
$spaceOwnerId = $space["owner"]["user"]["id"];
587+
$this->featureContext->setResponse($this->listStaleUploads($spaceOwnerId));
588+
}
589+
590+
/**
591+
* @Then the CLI response should contain the following message:
592+
*
593+
* @param PyStringNode $content
594+
*
595+
* @return void
596+
*/
597+
public function theCLIResponseShouldContainTheseMessage(PyStringNode $content): void {
598+
$response = $this->featureContext->getJsonDecodedResponseBodyContent();
599+
$expectedMessage = str_replace("\r\n", "\n", trim($content->getRaw()));
600+
$actualMessage = str_replace("\r\n", "\n", trim($response->message ?? ''));
601+
602+
Assert::assertSame(
603+
$expectedMessage,
604+
$actualMessage,
605+
"Expected cli output to be $expectedMessage but found $actualMessage"
606+
);
607+
}
608+
609+
/**
610+
* @When the administrator deletes all the stale uploads
611+
*
612+
* @return void
613+
*/
614+
public function theAdministratorDeletesAllTheStaleUploads(): void {
615+
$this->featureContext->setResponse($this->deleteStaleUploads());
616+
}
617+
618+
/**
619+
* @When the administrator deletes all the stale uploads of space :spaceName owned by user :user
620+
*
621+
* @param string $spaceName
622+
* @param string $user
623+
*
624+
* @return void
625+
*/
626+
public function theAdministratorDeletesTheStaleUploadsOfSpaceOwnedByUser(
627+
string $spaceName,
628+
string $user
629+
): void {
630+
$space = $this->spacesContext->getSpaceByName(
631+
$user,
632+
$spaceName
633+
);
634+
$spaceOwnerId = $space["owner"]["user"]["id"];
635+
$this->featureContext->setResponse($this->deleteStaleUploads($spaceOwnerId));
636+
}
637+
638+
/**
639+
* @Then there should be :number stale uploads
640+
* @Then there should be :number stale uploads of space :spaceName owned by user :user
641+
*
642+
* @param int $number
643+
* @param string|null $spaceName
644+
* @param string|null $user
645+
*
646+
* @return void
647+
* @throws GuzzleException
648+
*/
649+
public function thereShouldBeStaleUploadsOfSpaceOwnedByUser(
650+
int $number,
651+
string $spaceName='',
652+
string $user=''
653+
): void {
654+
$spaceOwnerId = null;
655+
if ($spaceName !== '' && $user !== '') {
656+
$space = $this->spacesContext->getSpaceByName(
657+
$user,
658+
$spaceName
659+
);
660+
$spaceOwnerId = $space["owner"]["user"]["id"];
661+
}
662+
663+
$response = $this->listStaleUploads($spaceOwnerId);
664+
$jsonDecodedResponse = $this->featureContext->getJsonDecodedResponseBodyContent($response);
665+
$this->featureContext->theHTTPStatusCodeShouldBe(200, "", $response);
666+
667+
$expectedMessage = "Total stale nodes: $number";
668+
669+
Assert::assertStringContainsString(
670+
$expectedMessage,
671+
$jsonDecodedResponse->message ?? '',
672+
"Expected message to contain '$expectedMessage', but got: " . ($jsonDecodedResponse->message ?? 'null')
673+
);
674+
675+
}
499676
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
@env-config @cli-stale-uploads
2+
Feature: stale upload via CLI command
3+
As a user
4+
I want to manage stale uploads
5+
So that I clean up stale uploads from storage
6+
7+
Background:
8+
Given user "Alice" has been created with default attributes
9+
And user "Brian" has been created with default attributes
10+
11+
12+
Scenario: list and delete all stale uploads
13+
Given the config "POSTPROCESSING_DELAY" has been set to "10s"
14+
And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
15+
And user "Alice" has created a space "staleuploads" with the default quota using the Graph API
16+
And user "Alice" has uploaded a file "filesForUpload/testavatar.jpg" to "/testavatar.jpg" in space "staleuploads"
17+
And user "Brian" has uploaded file "filesForUpload/textfile.txt" to "textfile.txt"
18+
And the administrator has stopped the server
19+
And the administrator has created stale upload
20+
And the administrator has started the server
21+
When the administrator lists all the stale uploads
22+
Then the command should be successful
23+
And the CLI response should contain the following message:
24+
"""
25+
Scanning all spaces for stale processing nodes...
26+
Total stale nodes: 2
27+
"""
28+
When the administrator deletes all the stale uploads
29+
Then the command should be successful
30+
And the CLI response should contain the following message:
31+
"""
32+
Scanning all spaces for stale processing nodes...
33+
Total stale nodes: 2
34+
"""
35+
And there should be "0" stale uploads
36+
37+
38+
Scenario: list and delete all stale uploads of a specific space
39+
Given user "Alice" has created folder "FolderToShare"
40+
And using spaces DAV path
41+
And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
42+
And user "Alice" has created a space "staleuploads" with the default quota using the Graph API
43+
And using SharingNG
44+
And the config "POSTPROCESSING_DELAY" has been set to "10s"
45+
And user "Alice" has sent the following resource share invitation:
46+
| resource | FolderToShare |
47+
| space | Personal |
48+
| sharee | Brian |
49+
| shareType | user |
50+
| permissionsRole | Uploader |
51+
And user "Brian" has uploaded a file "filesForUpload/testavatar.png" to "FolderToShare/testavatar.png" in space "Shares"
52+
And user "Alice" has uploaded file "filesForUpload/testavatar.png" to "testavatar.png"
53+
And user "Alice" has uploaded a file "filesForUpload/testavatar.jpg" to "/testavatar.jpg" in space "staleuploads"
54+
And the administrator has stopped the server
55+
And the administrator has created stale upload
56+
And the administrator has started the server
57+
When the administrator lists all the stale uploads of space "Personal" owned by user "Alice"
58+
Then the command should be successful
59+
And the CLI response should contain the following message:
60+
"""
61+
Total stale nodes: 2
62+
"""
63+
When the administrator lists all the stale uploads of space "staleuploads" owned by user "Alice"
64+
Then the command should be successful
65+
And the CLI response should contain the following message:
66+
"""
67+
Total stale nodes: 1
68+
"""
69+
When the administrator deletes all the stale uploads of space "Personal" owned by user "Alice"
70+
Then the command should be successful
71+
And the CLI response should contain the following message:
72+
"""
73+
Total stale nodes: 2
74+
"""
75+
And there should be "0" stale uploads of space "Personal" owned by user "Alice"
76+
When the administrator deletes all the stale uploads of space "staleuploads" owned by user "Alice"
77+
Then the command should be successful
78+
And the CLI response should contain the following message:
79+
"""
80+
Total stale nodes: 1
81+
"""
82+
And there should be "0" stale uploads of space "Personal" owned by user "Alice"

0 commit comments

Comments
 (0)