Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 169 additions & 2 deletions tests/lib/Files/Storage/Wrapper/QuotaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OC\Files\Storage\Local;
use OC\Files\Storage\Wrapper\Quota;
use OCP\Files;
use OCP\Files\FileInfo;
use OCP\Files\NotEnoughSpaceException;
use OCP\ITempManager;
use OCP\Server;
Expand Down Expand Up @@ -60,6 +61,28 @@ public function testFilePutContentsNotEnoughSpace(): void {
$this->assertFalse($instance->file_put_contents('files/foo', 'foobar'));
}

public function testFilePutContentsRejectsExactQuotaLimit(): void {
$instance = $this->getLimitedStorage(3);

// Quota currently uses a strict "<" comparison, so an exact fit is
// rejected rather than accepted.
$this->assertFalse($instance->file_put_contents('files/foo', 'foo'));
}

public function testSizedWriteStreamRejectsExactQuotaLimit(): void {
$instance = $this->getLimitedStorage(3);
$stream = fopen('php://temp', 'w+');
fwrite($stream, 'foo');
rewind($stream);

$this->expectException(NotEnoughSpaceException::class);
try {
$instance->writeStream('files/test.txt', $stream, 3);
} finally {
fclose($stream);
}
}

public function testCopyNotEnoughSpace(): void {
$instance = $this->getLimitedStorage(9);
$this->assertEquals(6, $instance->file_put_contents('files/foo', 'foobar'));
Expand Down Expand Up @@ -97,6 +120,51 @@ public function testFreeSpaceWithUnknownDiskSpace(): void {
$this->assertEquals(6, $instance->free_space(''));
}

public function testQuotaCallbackIsUsedAndCached(): void {
$storage = new Local(['datadir' => $this->tmpDir]);
$storage->mkdir('files');
$storage->getScanner()->scan('');

$callbackCalls = 0;
$instance = new Quota([
'storage' => $storage,
'quotaCallback' => static function () use (&$callbackCalls): int {
$callbackCalls++;
return 9;
},
]);

$this->assertSame(9, $instance->getQuota());
$this->assertSame(9, $instance->getQuota());
$this->assertSame(1, $callbackCalls);
}

public function testUnlimitedQuotaDelegatesToWrappedStorage(): void {
$instance = $this->getLimitedStorage(FileInfo::SPACE_UNLIMITED);

$this->assertSame(
100,
$instance->file_put_contents('files/foo', str_repeat('x', 100))
);
}

public function testNegativeQuotaDelegatesToWrappedStorage(): void {
$instance = $this->getLimitedStorage(-1);

$this->assertSame(
100,
$instance->file_put_contents('files/foo', str_repeat('x', 100))
);
}

public function testQuotaCanBeDisabled(): void {
$instance = $this->getLimitedStorage(0);
$instance->enableQuota(false);

$this->assertSame(3, $instance->file_put_contents('files/foo', 'foo'));
$this->assertSame('foo', $instance->file_get_contents('files/foo'));
}

public function testFreeSpaceWithUsedSpaceAndEncryption(): void {
$instance = $this->getLimitedStorage(9);
$instance->getCache()->put(
Expand Down Expand Up @@ -214,7 +282,6 @@ public function testInstanceOfStorageWrapper(): void {

public function testNoMkdirQuotaZero(): void {
$instance = $this->getLimitedStorage(0.0);
$this->assertFalse($instance->mkdir('files'));
$this->assertFalse($instance->mkdir('files/foobar'));
}

Expand All @@ -226,6 +293,28 @@ public function testMkdirQuotaZeroTrashbin(): void {
$this->assertTrue($instance->mkdir('cache'));
}

public function testCacheAndUploadsBypassQuota(): void {
$instance = $this->getLimitedStorage(0.0);

$this->assertTrue($instance->mkdir('uploads'));
$this->assertSame(3, $instance->file_put_contents('uploads/foo', 'foo'));
$this->assertSame('foo', $instance->file_get_contents('uploads/foo'));

$this->assertSame(3, $instance->file_put_contents('cache/foo', 'foo'));
$this->assertSame('foo', $instance->file_get_contents('cache/foo'));
}

public function testPartFilesBypassQuotaWhenOpenedForWriting(): void {
$instance = $this->getLimitedStorage(0.0);
$stream = $instance->fopen('files/foo.part', 'w');

$this->assertIsResource($stream);
$this->assertSame(3, fwrite($stream, 'foo'));
fclose($stream);

$this->assertSame('foo', $instance->file_get_contents('files/foo.part'));
}

public function testNoTouchQuotaZero(): void {
$instance = $this->getLimitedStorage(0.0);
$this->assertFalse($instance->touch('foobar'));
Expand All @@ -242,13 +331,91 @@ public function testNoWriteStreamQuota(): void {
$stream = fopen('php://temp', 'w+');
fwrite($stream, 'foo');
rewind($stream);
$instance->writeStream('files/test.txt', $stream);
$this->assertSame(3, $instance->writeStream('files/test.txt', $stream));
fclose($stream);

$this->assertSame('foo', $instance->file_get_contents('files/test.txt'));

$stream = fopen('php://temp', 'w+');
fwrite($stream, 'foobar');
rewind($stream);
$this->expectException(NotEnoughSpaceException::class);
$instance->writeStream('files/test.txt', $stream);
fclose($stream);
}

public function testSizedWriteStreamWithEnoughSpace(): void {
$instance = $this->getLimitedStorage(5);
$stream = fopen('php://temp', 'w+');
fwrite($stream, 'foo');
rewind($stream);

$this->assertSame(
3,
$instance->writeStream('files/test.txt', $stream, 3)
);
fclose($stream);

$this->assertSame('foo', $instance->file_get_contents('files/test.txt'));
}

public function testSizedWriteStreamRejectsWhenSizeReachesFreeSpace(): void {
$instance = $this->getLimitedStorage(3);
$stream = fopen('php://temp', 'w+');
fwrite($stream, 'foo');
rewind($stream);

try {
$this->expectException(NotEnoughSpaceException::class);
$instance->writeStream('files/test.txt', $stream, 3);
} finally {
fclose($stream);
}
}

public function testCopyFromStorageHonorsQuota(): void {
$instance = $this->getLimitedStorage(3);
$sourceDir = Server::get(ITempManager::class)->getTemporaryFolder();

try {
$sourceStorage = new Local(['datadir' => $sourceDir]);
$sourceStorage->file_put_contents('source.txt', 'foo');
$sourceStorage->getScanner()->scan('');

$this->assertFalse(
$instance->copyFromStorage(
$sourceStorage,
'source.txt',
'files/target.txt'
)
);
$this->assertFalse($instance->file_exists('files/target.txt'));
} finally {
Files::rmdirr($sourceDir);
}
}

public function testMoveFromStorageHonorsQuota(): void {
$instance = $this->getLimitedStorage(3);
$sourceDir = Server::get(ITempManager::class)->getTemporaryFolder();

try {
$sourceStorage = new Local(['datadir' => $sourceDir]);
$sourceStorage->file_put_contents('source.txt', 'foo');
$sourceStorage->getScanner()->scan('');

$this->assertFalse(
$instance->moveFromStorage(
$sourceStorage,
'source.txt',
'files/target.txt'
)
);
$this->assertTrue($sourceStorage->file_exists('source.txt'));
$this->assertFalse($instance->file_exists('files/target.txt'));
} finally {
Files::rmdirr($sourceDir);
}
}

public function testNoWriteStreamQuotaZero(): void {
Expand Down
23 changes: 23 additions & 0 deletions tests/lib/HelperStorageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,29 @@ public function testGetStorageInfoIncludingExtStorage(): void {
$config->setUserValue($this->user, 'files', 'quota', 'default');
}

/**
* Test that the quota wrapper includes mounted storage when configured.
*/
public function testQuotaIncludesExternalStorage(): void {
$homeStorage = new Temporary([]);
$homeStorage->file_put_contents('test.txt', '01234');
$homeStorage->getScanner()->scan('');

$quotaStorage = new Quota([
'storage' => $homeStorage,
'quota' => 25,
'include_external_storage' => true,
]);
Filesystem::mount($quotaStorage, [], '/' . $this->user . '/files');

$externalStorage = new Temporary([]);
$externalStorage->file_put_contents('extfile.txt', 'abcdefghijklmnopq');
$externalStorage->getScanner()->scan('');
Filesystem::mount($externalStorage, [], '/' . $this->user . '/files/ext');

$this->assertSame(3, $quotaStorage->free_space(''));
}

/**
* Test getting the storage info excluding extra mount points
* when user has no quota set, even when quota ext storage option
Expand Down
Loading