mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Add more validation tests
This commit is contained in:
@@ -52,6 +52,7 @@ class Update extends TransactionsUpdate
|
||||
->param('rollback', false, new Boolean(), 'Rollback transaction?', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('transactionState')
|
||||
->inject('queueForDeletes')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForStatsUsage')
|
||||
|
||||
@@ -159,6 +159,51 @@ class Operation extends Validator
|
||||
}
|
||||
}
|
||||
|
||||
// Bulk operation specific validations
|
||||
$action = $value['action'];
|
||||
|
||||
// BulkUpdate and BulkDelete require queries
|
||||
if (\in_array($action, ['bulkUpdate', 'bulkDelete'])) {
|
||||
if (!\array_key_exists('data', $value) || !\is_array($value['data'])) {
|
||||
$this->description = "Key 'data' must be an array for {$action}";
|
||||
return false;
|
||||
}
|
||||
if (!\array_key_exists('queries', $value['data'])) {
|
||||
$this->description = "Key 'queries' is required in data for {$action}";
|
||||
return false;
|
||||
}
|
||||
if (!\is_array($value['data']['queries'])) {
|
||||
$this->description = "Key 'queries' must be an array for {$action}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// BulkUpdate requires both queries and data
|
||||
if ($action === 'bulkUpdate') {
|
||||
if (!\array_key_exists('data', $value['data'])) {
|
||||
$this->description = "Key 'data' is required in data for {$action}";
|
||||
return false;
|
||||
}
|
||||
if (!\is_array($value['data']['data'])) {
|
||||
$this->description = "Key 'data.data' must be an array for {$action}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment and Decrement require specific keys
|
||||
if (\in_array($action, ['increment', 'decrement'])) {
|
||||
if (!\array_key_exists('data', $value) || !\is_array($value['data'])) {
|
||||
$this->description = "Key 'data' must be an array for {$action}";
|
||||
return false;
|
||||
}
|
||||
// Get the attribute key name based on type
|
||||
$attributeKey = $this->type === 'tablesdb' ? 'column' : 'attribute';
|
||||
if (!\array_key_exists($attributeKey, $value['data'])) {
|
||||
$this->description = "Key '{$attributeKey}' is required in data for {$action}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4225,4 +4225,355 @@ trait TransactionsBase
|
||||
sort($remainingIds);
|
||||
$this->assertEquals(['doc_6', 'doc_7', 'doc_8'], $remainingIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation for invalid operation inputs
|
||||
*/
|
||||
public function testCreateOperationsValidation(): void
|
||||
{
|
||||
// Create database and collection for testing
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'ValidationTestDatabase'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'ValidationTest',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Add required attribute
|
||||
$attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $attribute['headers']['status-code']);
|
||||
|
||||
// Wait for attribute to be ready
|
||||
sleep(2);
|
||||
|
||||
// Create transaction
|
||||
$transaction = $this->client->call(Client::METHOD_POST, '/databases/transactions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(201, $transaction['headers']['status-code']);
|
||||
$transactionId = $transaction['body']['$id'];
|
||||
|
||||
// Test 1: Invalid action type
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'invalidAction',
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'documentId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 2: Missing required action field
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'documentId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 3: Missing required databaseId field
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'collectionId' => $collectionId,
|
||||
'documentId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 4: Missing documentId for create operation
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 5: Missing data for create operation
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'documentId' => ID::unique()
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 6: BulkCreate with non-array data
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'bulkCreate',
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'data' => 'not an array'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 7: BulkUpdate with missing queries
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'bulkUpdate',
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'data' => [
|
||||
'data' => ['name' => 'Updated']
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 8: Empty operations array
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => []
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 9: Operations not an array
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => 'not an array'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation for committing/rolling back transactions
|
||||
*/
|
||||
public function testCommitRollbackValidation(): void
|
||||
{
|
||||
// Create transaction
|
||||
$transaction = $this->client->call(Client::METHOD_POST, '/databases/transactions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(201, $transaction['headers']['status-code']);
|
||||
$transactionId = $transaction['body']['$id'];
|
||||
|
||||
// Test 1: Missing both commit and rollback
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/databases/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 2: Both commit and rollback set to true
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/databases/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true,
|
||||
'rollback' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 3: Invalid transaction ID
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/databases/transactions/invalid_id", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
// Commit the transaction
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/databases/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
// Test 4: Attempt to commit already committed transaction
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/databases/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation for non-existent resources
|
||||
*/
|
||||
public function testNonExistentResources(): void
|
||||
{
|
||||
// Create database and transaction
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'ResourceTestDatabase'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$transaction = $this->client->call(Client::METHOD_POST, '/databases/transactions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(201, $transaction['headers']['status-code']);
|
||||
$transactionId = $transaction['body']['$id'];
|
||||
|
||||
// Test 1: Non-existent database
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => 'nonExistentDatabase',
|
||||
'collectionId' => 'someCollection',
|
||||
'documentId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
// Test 2: Non-existent collection
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => 'nonExistentCollection',
|
||||
'documentId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4225,4 +4225,453 @@ trait TransactionsBase
|
||||
sort($remainingIds);
|
||||
$this->assertEquals(['row_6', 'row_7', 'row_8'], $remainingIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation for invalid operation inputs
|
||||
*/
|
||||
public function testCreateOperationsValidation(): void
|
||||
{
|
||||
// Create database and table for testing
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'ValidationTestDatabase'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$table = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'ValidationTest',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $table['headers']['status-code']);
|
||||
$tableId = $table['body']['$id'];
|
||||
|
||||
// Add required column
|
||||
$column = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $column['headers']['status-code']);
|
||||
|
||||
// Wait for column to be ready
|
||||
sleep(2);
|
||||
|
||||
// Create transaction
|
||||
$transaction = $this->client->call(Client::METHOD_POST, '/tablesdb/transactions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(201, $transaction['headers']['status-code']);
|
||||
$transactionId = $transaction['body']['$id'];
|
||||
|
||||
// Test 1: Invalid action type
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'invalidAction',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'rowId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 2: Missing required action field
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'rowId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 3: Missing required databaseId field
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'tableId' => $tableId,
|
||||
'rowId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 4: Missing required tableId field
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => $databaseId,
|
||||
'rowId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 5: Missing rowId for create operation
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 6: Missing data for create operation
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'rowId' => ID::unique()
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 7: BulkCreate with non-array data
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'bulkCreate',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'data' => 'not an array'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 8: BulkUpdate with missing queries
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'bulkUpdate',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'data' => [
|
||||
'data' => ['name' => 'Updated']
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 9: BulkUpdate with invalid query format
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'bulkUpdate',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'data' => [
|
||||
'queries' => 'not an array',
|
||||
'data' => ['name' => 'Updated']
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 10: BulkDelete with missing queries
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'bulkDelete',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'data' => []
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 11: Increment with missing attribute
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'increment',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'rowId' => ID::unique(),
|
||||
'data' => ['value' => 1]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 12: Decrement with invalid value type
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'decrement',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'attribute' => 'counter',
|
||||
'value' => 'not a number'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 13: Empty operations array
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => []
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 14: Operations not an array
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => 'not an array'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation for committing/rolling back transactions
|
||||
*/
|
||||
public function testCommitRollbackValidation(): void
|
||||
{
|
||||
// Create transaction
|
||||
$transaction = $this->client->call(Client::METHOD_POST, '/tablesdb/transactions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(201, $transaction['headers']['status-code']);
|
||||
$transactionId = $transaction['body']['$id'];
|
||||
|
||||
// Test 1: Missing both commit and rollback
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 2: Both commit and rollback set to true
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true,
|
||||
'rollback' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 3: Invalid transaction ID
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/invalid_id", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
// Commit the transaction
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
// Test 4: Attempt to commit already committed transaction
|
||||
$response = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'commit' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation for non-existent resources
|
||||
*/
|
||||
public function testNonExistentResources(): void
|
||||
{
|
||||
// Create database and transaction
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'ResourceTestDatabase'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$transaction = $this->client->call(Client::METHOD_POST, '/tablesdb/transactions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(201, $transaction['headers']['status-code']);
|
||||
$transactionId = $transaction['body']['$id'];
|
||||
|
||||
// Test 1: Non-existent database
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => 'nonExistentDatabase',
|
||||
'tableId' => 'someTable',
|
||||
'rowId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
// Test 2: Non-existent table
|
||||
$response = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'operations' => [
|
||||
[
|
||||
'action' => 'create',
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => 'nonExistentTable',
|
||||
'rowId' => ID::unique(),
|
||||
'data' => ['name' => 'Test']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user