run all tests with POSIX_WATCH_FS=true (#1342)

This commit is contained in:
Viktor Scharf
2025-08-15 13:44:35 +02:00
committed by GitHub
parent 69c0d21539
commit 28770fe20d
3 changed files with 211 additions and 22 deletions

View File

@@ -2089,7 +2089,7 @@ def opencloudServer(storage = "decomposed", accounts_hash_difficulty = 4, depend
},
"commands": [
"apt-get update",
"apt-get install -y inotify-tools",
"apt-get install -y inotify-tools xattr",
"%s init --insecure true" % dirs["opencloudBin"],
"cat $OC_CONFIG_DIR/opencloud.yaml",
"cp tests/config/woodpecker/app-registry.yaml $OC_CONFIG_DIR/app-registry.yaml",

View File

@@ -41,7 +41,12 @@ class CliContext implements Context {
*/
public static function getUsersStoragePath(): string {
$path = getenv('OC_STORAGE_PATH') ?: '/var/lib/opencloud/storage/users';
return $path . '/users';
// need for CI
$home = getenv('HOME');
$path = preg_replace('#^~/#', $home . '/', $path);
$path = str_replace('$HOME', $home, $path);
return rtrim($path, '/') . '/users';
}
/**
@@ -69,6 +74,51 @@ class CliContext implements Context {
$this->spacesContext = BehatHelper::getContext($scope, $environment, 'SpacesContext');
}
/**
* expects a file to exist at the given path
*
* @param string $path
* @param string|null $sizeGb
* @param int $maxSeconds
*
* @return void
*/
private function waitForPath(string $path, ?string $sizeGb = null, int $maxSeconds = 10): void {
$escapedPath = escapeshellarg($path);
for ($i = 0; $i < $maxSeconds * 5; $i++) {
if ($sizeGb) {
if (!preg_match('/^(\d+)gb$/i', $sizeGb, $matches)) {
throw new \InvalidArgumentException("Invalid size format: $sizeGb. Use formats like 1gb, 5gb.");
}
$targetBytes = (int)$matches[1] * 1024 * 1024 * 1024;
$body = [
"command" => "[ -f $escapedPath ] && stat -c%s $escapedPath || echo 0",
"raw" => true
];
$data = json_decode((string)CliHelper::runCommand($body)->getBody(), true);
if (isset($data['message']) && (int)trim($data['message']) >= $targetBytes) {
return;
}
} else {
$body = [
"command" => "ls $escapedPath >/dev/null 2>&1 && echo exists || echo not_exists",
"raw" => true
];
$response = CliHelper::runCommand($body);
$data = json_decode((string)$response->getBody(), true);
if (isset($data['message']) && trim($data['message']) === 'exists') {
return;
}
}
usleep(200000);
}
throw new \Exception("Timeout waiting for: $path");
}
/**
* @Given the administrator has stopped the server
*
@@ -468,11 +518,14 @@ class CliContext implements Context {
public function theAdministratorCreatesFolder(string $folder, string $user): void {
$userUuid = $this->featureContext->getUserIdByUserName($user);
$storagePath = $this->getUsersStoragePath();
$fullPath = "$storagePath/$userUuid/$folder";
$body = [
"command" => "mkdir -p $storagePath/$userUuid/$folder",
"command" => "mkdir -p $fullPath",
"raw" => true
];
$this->featureContext->setResponse(CliHelper::runCommand($body));
$this->waitForPath($fullPath);
sleep(1);
}
@@ -505,12 +558,96 @@ class CliContext implements Context {
public function theAdministratorCreatesFile(string $file, string $content, string $user): void {
$userUuid = $this->featureContext->getUserIdByUserName($user);
$storagePath = $this->getUsersStoragePath();
$fullPath = "$storagePath/$userUuid/$file";
$safeContent = escapeshellarg($content);
$body = [
"command" => "echo -n $safeContent > $storagePath/$userUuid/$file",
"command" => "echo -n $safeContent > $fullPath",
"raw" => true
];
$this->featureContext->setResponse(CliHelper::runCommand($body));
$this->waitForPath($fullPath);
sleep(1);
}
/**
* @When the administrator creates the file :file with size :size for user :user on the POSIX filesystem
*
* @param string $file
* @param string $size Example: "1gb", "5gb"
* @param string $user
*
* @return void
*/
public function theAdministratorCreatesLargeFileWithSize(string $file, string $size, string $user): void {
$userUuid = $this->featureContext->getUserIdByUserName($user);
$storagePath = $this->getUsersStoragePath();
$size = strtolower($size);
if (!preg_match('/^(\d+)gb$/', $size, $matches)) {
throw new \InvalidArgumentException("Invalid size format: $size. Use formats like 1gb, 5gb.");
}
$count = (int)$matches[1] * 1024; // 1GB = 1024M
$bs = '1M';
$filePath = "$storagePath/$userUuid/$file";
$body = [
"command" => "dd if=/dev/zero of=$filePath bs=$bs count=$count",
"raw" => true
];
$this->featureContext->setResponse(CliHelper::runCommand($body));
$this->waitForPath($filePath, $size, 15);
sleep(7);
}
/**
* @When the administrator creates :count files sequentially in the directory :dir for user :user on the POSIX filesystem
*
* @param int $count
* @param string $dir
* @param string $user
*
* @return void
*/
public function theAdministratorCreatesFilesSequentially(int $count, string $dir, string $user): void {
$userUuid = $this->featureContext->getUserIdByUserName($user);
$storagePath = $this->getUsersStoragePath() . "/$userUuid/$dir";
$cmd = '';
for ($i = 1; $i <= $count; $i++) {
$cmd .= "echo -n \"file $i content\" > $storagePath/file_$i.txt; ";
}
$body = [
"command" => $cmd,
"raw" => true
];
$this->featureContext->setResponse(CliHelper::runCommand($body));
$this->waitForPath("$storagePath/file_$count.txt");
sleep(3);
}
/**
* @When the administrator creates :count files in parallel in the directory :dir for user :user on the POSIX filesystem
*
* @param int $count
* @param string $dir
* @param string $user
*
* @return void
*/
public function theAdministratorCreatesFilesInParallel(int $count, string $dir, string $user): void {
$userUuid = $this->featureContext->getUserIdByUserName($user);
$storagePath = $this->getUsersStoragePath() . "/$userUuid/$dir";
$cmd = "mkdir -p $storagePath; ";
for ($i = 1; $i <= $count; $i++) {
$cmd .= "echo -n \"parallel file $i content\" > $storagePath/parallel_$i.txt & ";
}
$cmd .= "wait";
$body = [
"command" => $cmd,
"raw" => true
];
$this->featureContext->setResponse(CliHelper::runCommand($body));
$this->waitForPath("$storagePath/parallel_$count.txt");
sleep(1);
}
@@ -712,4 +849,23 @@ class CliContext implements Context {
$this->featureContext->setResponse(CliHelper::runCommand($body));
sleep(1);
}
/**
* @When the administrator checks the attribute :attribute of file :file for user :user on the POSIX filesystem
*
* @param string $attribute
* @param string $file
* @param string $user
*
* @return void
*/
public function theAdminChecksTheAttributeOfFileForUser(string $attribute, string $file, string $user): void {
$userUuid = $this->featureContext->getUserIdByUserName($user);
$storagePath = $this->getUsersStoragePath();
$body = [
"command" => "xattr -p -slz " . escapeshellarg($attribute) . " $storagePath/$userUuid/$file",
"raw" => true
];
$this->featureContext->setResponse(CliHelper::runCommand($body));
}
}

View File

@@ -4,26 +4,54 @@ Feature: create a resources using collaborative posixfs
Background:
Given the config "STORAGE_USERS_POSIX_WATCH_FS" has been set to "true"
And user "Alice" has been created with default attributes
And user "Alice" has created folder "/firstFolder"
Scenario: administrator lists the content of the POSIX storage
Given user "Alice" has uploaded file with content "content" to "test.txt"
When the administrator lists the content of the POSIX storage folder of user "Alice"
Then the command output should contain "firstFolder"
And the command output should contain "test.txt"
Scenario: create folder
Given user "Alice" has uploaded file with content "content" to "textfile.txt"
When the administrator creates the folder "myFolder" for user "Alice" on the POSIX filesystem
Then the command should be successful
When the administrator lists the content of the POSIX storage folder of user "Alice"
Then the command output should contain "myFolder"
And as "Alice" folder "/myFolder" should exist
Scenario: create nested folder
When the administrator creates the folder "deep/nested/structure/myFolder" for user "Alice" on the POSIX filesystem
Then the command should be successful
And as "Alice" folder "/deep/nested/structure/myFolder" should exist
Scenario: create file
Given user "Alice" has created folder "/folder"
When the administrator creates the file "test.txt" with content "content" for user "Alice" on the POSIX filesystem
Then the command should be successful
When the administrator lists the content of the POSIX storage folder of user "Alice"
Then the command output should contain "test.txt"
And the content of file "/test.txt" for user "Alice" should be "content"
Scenario: create large file
When the administrator creates the file "largefile.txt" with size "1gb" for user "Alice" on the POSIX filesystem
Then the command should be successful
And as "Alice" file "/largefile.txt" should exist
Scenario: creates files sequentially in a folder
When the administrator creates 50 files sequentially in the directory "firstFolder" for user "Alice" on the POSIX filesystem
Then the command should be successful
And the content of file "/firstFolder/file_1.txt" for user "Alice" should be "file 1 content"
And the content of file "/firstFolder/file_50.txt" for user "Alice" should be "file 50 content"
Scenario: creates files in parallel in a folder
When the administrator creates 100 files in parallel in the directory "firstFolder" for user "Alice" on the POSIX filesystem
Then the command should be successful
And the content of file "/firstFolder/parallel_1.txt" for user "Alice" should be "parallel file 1 content"
And the content of file "/firstFolder/parallel_100.txt" for user "Alice" should be "parallel file 100 content"
Scenario: edit file
Given user "Alice" has uploaded file with content "content" to "test.txt"
When the administrator puts the content "new" into the file "test.txt" in the POSIX storage folder of user "Alice"
@@ -37,11 +65,10 @@ Feature: create a resources using collaborative posixfs
Scenario: copy file to folder
Given user "Alice" has created folder "/folder"
And user "Alice" has uploaded file with content "content" to "test.txt"
When the administrator copies the file "test.txt" to the folder "folder" for user "Alice" on the POSIX filesystem
Given user "Alice" has uploaded file with content "content" to "test.txt"
When the administrator copies the file "test.txt" to the folder "firstFolder" for user "Alice" on the POSIX filesystem
Then the command should be successful
And the content of file "/folder/test.txt" for user "Alice" should be "content"
And the content of file "/firstFolder/test.txt" for user "Alice" should be "content"
Scenario: rename file
@@ -52,11 +79,10 @@ Feature: create a resources using collaborative posixfs
Scenario: move file to folder
Given user "Alice" has created folder "/folder"
And user "Alice" has uploaded file with content "content" to "test.txt"
When the administrator moves the file "test.txt" to the folder "folder" for user "Alice" on the POSIX filesystem
Given user "Alice" has uploaded file with content "content" to "test.txt"
When the administrator moves the file "test.txt" to the folder "firstFolder" for user "Alice" on the POSIX filesystem
Then the command should be successful
And the content of file "/folder/test.txt" for user "Alice" should be "content"
And the content of file "/firstFolder/test.txt" for user "Alice" should be "content"
And as "Alice" file "/test.txt" should not exist
@@ -68,11 +94,10 @@ Feature: create a resources using collaborative posixfs
Scenario: delete folder
Given user "Alice" has created folder "/folder"
And user "Alice" has uploaded file with content "content" to "/folder/test.txt"
When the administrator deletes the folder "folder" for user "Alice" on the POSIX filesystem
And user "Alice" has uploaded file with content "content" to "/firstFolder/test.txt"
When the administrator deletes the folder "firstFolder" for user "Alice" on the POSIX filesystem
Then the command should be successful
And as "Alice" folder "folder" should not exist
And as "Alice" folder "firstFolder" should not exist
Scenario: copy file from personal to project space
@@ -155,3 +180,11 @@ Feature: create a resources using collaborative posixfs
Then the command should be successful
And for user "Brian" the content of the file "textfile.txt" of the space "Shares" should be "contentnew"
And the public should be able to download file "textfile.txt" from the last link share with password "%public%" and the content should be "contentnew"
@issue-1100
Scenario: upload and rename file
When the administrator creates the file "test.txt" with content "content" for user "Alice" on the POSIX filesystem
And the administrator renames the file "test.txt" to "renamed.txt" for user "Alice" on the POSIX filesystem
And the administrator checks the attribute "user.oc.name" of file "renamed.txt" for user "Alice" on the POSIX filesystem
Then the command output should contain "renamed.txt"
And the content of file "/renamed.txt" for user "Alice" should be "content"