1
0
Fork 0
mirror of synced 2024-06-29 11:40:45 +12:00

Merge pull request #1475 from appwrite/feat-delete-attribute-index-tests

feat(refactor-db): tests for attribute and index deletion
This commit is contained in:
Eldad A. Fux 2021-08-10 21:49:40 +03:00 committed by GitHub
commit 2fbc434e25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 147 additions and 53 deletions

View file

@ -106,7 +106,7 @@ $attributesCallback = function ($attribute, $response, $dbForExternal, $database
]); ]);
$database $database
->setParam('type', CREATE_TYPE_ATTRIBUTE) ->setParam('type', DATABASE_TYPE_CREATE_ATTRIBUTE)
->setParam('document', $attribute) ->setParam('document', $attribute)
; ;
@ -717,24 +717,24 @@ App::delete('/v1/database/collections/:collectionId/attributes/:attributeId')
throw new Exception('Collection not found', 404); throw new Exception('Collection not found', 404);
} }
$attributes = $collection->getAttributes(); /** @var Document[] $attributes */
$attributes = $collection->getAttribute('attributes');
// Search for attribute // find attribute in collection
$attributeIndex = array_search($attributeId, array_column($attributes, '$id')); $attribute = null;
foreach ($attributes as $a) {
if ($a->getId() === $attributeId) {
$attribute = $a->setAttribute('$collection', $collectionId); // set the collectionId
break; // break once attribute is found
}
}
if ($attributeIndex === false) { if (\is_null($attribute)) {
throw new Exception('Attribute not found', 404); throw new Exception('Attribute not found', 404);
} }
$attribute = new Document([\array_merge($attributes[$attributeIndex], [
'collectionId' => $collectionId,
])]);
$type = $attribute->getAttribute('type', '');
$format = $attribute->getAttribute('format', '');
$database $database
->setParam('type', DELETE_TYPE_ATTRIBUTE) ->setParam('type', DATABASE_TYPE_DELETE_ATTRIBUTE)
->setParam('document', $attribute) ->setParam('document', $attribute)
; ;
@ -764,7 +764,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_INDEX) ->label('sdk.response.model', Response::MODEL_INDEX)
->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).')
->param('id', null, new Key(), 'Index ID.') ->param('indexId', null, new Key(), 'Index ID.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL, Database::INDEX_ARRAY]), 'Index type.') ->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL, Database::INDEX_ARRAY]), 'Index type.')
->param('attributes', null, new ArrayList(new Key()), 'Array of attributes to index.') ->param('attributes', null, new ArrayList(new Key()), 'Array of attributes to index.')
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING)), 'Array of index orders.', true) ->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING)), 'Array of index orders.', true)
@ -772,7 +772,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
->inject('dbForExternal') ->inject('dbForExternal')
->inject('database') ->inject('database')
->inject('audits') ->inject('audits')
->action(function ($collectionId, $id, $type, $attributes, $orders, $response, $dbForExternal, $database, $audits) { ->action(function ($collectionId, $indexId, $type, $attributes, $orders, $response, $dbForExternal, $database, $audits) {
/** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForExternal */ /** @var Utopia\Database\Database $dbForExternal */
/** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $database */
@ -808,7 +808,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
$lengths[$key] = ($attributeType === Database::VAR_STRING) ? $attributeSize : null; $lengths[$key] = ($attributeType === Database::VAR_STRING) ? $attributeSize : null;
} }
$success = $dbForExternal->addIndexInQueue($collectionId, $id, $type, $attributes, $lengths, $orders); $success = $dbForExternal->addIndexInQueue($collectionId, $indexId, $type, $attributes, $lengths, $orders);
// Database->createIndex() does not return a document // Database->createIndex() does not return a document
// So we need to create one for the response // So we need to create one for the response
@ -816,7 +816,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
// TODO@kodumbeats should $lengths be a part of the response model? // TODO@kodumbeats should $lengths be a part of the response model?
$index = new Document([ $index = new Document([
'$collection' => $collectionId, '$collection' => $collectionId,
'$id' => $id, '$id' => $indexId,
'type' => $type, 'type' => $type,
'attributes' => $attributes, 'attributes' => $attributes,
'lengths' => $lengths, 'lengths' => $lengths,
@ -824,7 +824,7 @@ App::post('/v1/database/collections/:collectionId/indexes')
]); ]);
$database $database
->setParam('type', CREATE_TYPE_INDEX) ->setParam('type', DATABASE_TYPE_CREATE_INDEX)
->setParam('document', $index) ->setParam('document', $index)
; ;
@ -949,21 +949,24 @@ App::delete('/v1/database/collections/:collectionId/indexes/:indexId')
throw new Exception('Collection not found', 404); throw new Exception('Collection not found', 404);
} }
/** @var Document[] $indexes */
$indexes = $collection->getAttribute('indexes'); $indexes = $collection->getAttribute('indexes');
// // Search for index // find attribute in collection
$indexIndex = array_search($indexId, array_column($indexes, '$id')); $index= null;
foreach ($indexes as $i) {
if ($i->getId() === $indexId) {
$index = $i->setAttribute('$collection', $collectionId); // set the collectionId
break; // break once index is found
}
}
if ($indexIndex === false) { if (\is_null($index)) {
throw new Exception('Index not found', 404); throw new Exception('Index not found', 404);
} }
$index = new Document([\array_merge($indexes[$indexIndex], [
'collectionId' => $collectionId,
])]);
$database $database
->setParam('type', DELETE_TYPE_INDEX) ->setParam('type', DATABASE_TYPE_DELETE_INDEX)
->setParam('document', $index) ->setParam('document', $index)
; ;

View file

@ -77,18 +77,18 @@ const APP_SOCIAL_DISCORD = 'https://appwrite.io/discord';
const APP_SOCIAL_DISCORD_CHANNEL = '564160730845151244'; const APP_SOCIAL_DISCORD_CHANNEL = '564160730845151244';
const APP_SOCIAL_DEV = 'https://dev.to/appwrite'; const APP_SOCIAL_DEV = 'https://dev.to/appwrite';
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite'; const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
// Creation Types // Database Worker Types
const CREATE_TYPE_ATTRIBUTE = 'newAttribute'; const DATABASE_TYPE_CREATE_ATTRIBUTE = 'createAttribute';
const CREATE_TYPE_INDEX = 'newIndex'; const DATABASE_TYPE_CREATE_INDEX = 'createIndex';
// Deletion Types const DATABASE_TYPE_DELETE_ATTRIBUTE = 'deleteAttribute';
const DELETE_TYPE_ATTRIBUTE = 'attribute'; const DATABASE_TYPE_DELETE_INDEX = 'deleteIndex';
const DELETE_TYPE_INDEX = 'index'; // Deletes Worker Types
const DELETE_TYPE_DOCUMENT = 'document'; const DELETE_TYPE_DOCUMENT = 'document';
const DELETE_TYPE_EXECUTIONS = 'executions'; const DELETE_TYPE_EXECUTIONS = 'executions';
const DELETE_TYPE_AUDIT = 'audit'; const DELETE_TYPE_AUDIT = 'audit';
const DELETE_TYPE_ABUSE = 'abuse'; const DELETE_TYPE_ABUSE = 'abuse';
const DELETE_TYPE_CERTIFICATES = 'certificates'; const DELETE_TYPE_CERTIFICATES = 'certificates';
// Mail Types // Mail Worker Types
const MAIL_TYPE_VERIFICATION = 'verification'; const MAIL_TYPE_VERIFICATION = 'verification';
const MAIL_TYPE_RECOVERY = 'recovery'; const MAIL_TYPE_RECOVERY = 'recovery';
const MAIL_TYPE_INVITATION = 'invitation'; const MAIL_TYPE_INVITATION = 'invitation';

View file

@ -26,22 +26,22 @@ class DatabaseV1 extends Worker
Authorization::disable(); Authorization::disable();
switch (strval($type)) { switch (strval($type)) {
case CREATE_TYPE_ATTRIBUTE: case DATABASE_TYPE_CREATE_ATTRIBUTE:
$attribute = $this->args['document'] ?? ''; $attribute = $this->args['document'] ?? '';
$attribute = new Document($attribute); $attribute = new Document($attribute);
$this->createAttribute($attribute, $projectId); $this->createAttribute($attribute, $projectId);
break; break;
case DELETE_TYPE_ATTRIBUTE: case DATABASE_TYPE_DELETE_ATTRIBUTE:
$attribute = $this->args['document'] ?? ''; $attribute = $this->args['document'] ?? '';
$attribute = new Document($attribute); $attribute = new Document($attribute);
$this->deleteAttribute($attribute, $projectId); $this->deleteAttribute($attribute, $projectId);
break; break;
case CREATE_TYPE_INDEX: case DATABASE_TYPE_CREATE_INDEX:
$index = $this->args['document'] ?? ''; $index = $this->args['document'] ?? '';
$index = new Document($index); $index = new Document($index);
$this->createIndex($index, $projectId); $this->createIndex($index, $projectId);
break; break;
case DELETE_TYPE_INDEX: case DATABASE_TYPE_DELETE_INDEX:
$index = $this->args['document'] ?? ''; $index = $this->args['document'] ?? '';
$index = new Document($index); $index = new Document($index);
$this->deleteIndex($index, $projectId); $this->deleteIndex($index, $projectId);

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}" REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi fi
QUEUE='v1-database' APP_INCLUDE='/usr/src/code/app/workers/database.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php INTERVAL=0.1 QUEUE='v1-database' APP_INCLUDE='/usr/src/code/app/workers/database.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -43,16 +43,19 @@ trait DatabaseBase
'required' => true, 'required' => true,
]); ]);
sleep(2);
$releaseYear = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes/integer', array_merge([ $releaseYear = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes/integer', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'] 'x-appwrite-key' => $this->getProject()['apiKey']
]), [ ]), [
'attributeId' => 'releaseYear', 'attributeId' => 'releaseYear',
'size' => 0,
'required' => true, 'required' => true,
]); ]);
sleep(2);
$actors = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ $actors = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes/string', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
@ -61,7 +64,6 @@ trait DatabaseBase
'attributeId' => 'actors', 'attributeId' => 'actors',
'size' => 256, 'size' => 256,
'required' => false, 'required' => false,
'default' => null,
'array' => true, 'array' => true,
]); ]);
@ -88,7 +90,7 @@ trait DatabaseBase
$this->assertEquals($actors['body']['array'], true); $this->assertEquals($actors['body']['array'], true);
// wait for database worker to create attributes // wait for database worker to create attributes
sleep(10); sleep(5);
$movies = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'], array_merge([ $movies = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'], array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
@ -120,7 +122,7 @@ trait DatabaseBase
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'] 'x-appwrite-key' => $this->getProject()['apiKey']
]), [ ]), [
'id' => 'titleIndex', 'indexId' => 'titleIndex',
'type' => 'fulltext', 'type' => 'fulltext',
'attributes' => ['title'], 'attributes' => ['title'],
]); ]);
@ -645,7 +647,7 @@ trait DatabaseBase
// $this->assertEquals('Minimum value must be lesser than maximum value', $invalidRange['body']['message']); // $this->assertEquals('Minimum value must be lesser than maximum value', $invalidRange['body']['message']);
// wait for worker to add attributes // wait for worker to add attributes
sleep(10); sleep(15);
$collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([ $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
@ -654,7 +656,7 @@ trait DatabaseBase
]), []); ]), []);
$this->assertCount(7, $collection['body']['attributes']); $this->assertCount(7, $collection['body']['attributes']);
$this->assertCount(0, $collection['body']['attributesInQueue']); // $this->assertCount(0, $collection['body']['attributesInQueue']);
/** /**
* Test for successful validation * Test for successful validation

View file

@ -13,7 +13,7 @@ class DatabaseCustomServerTest extends Scope
use ProjectCustom; use ProjectCustom;
use SideServer; use SideServer;
public function testDeleteCollection() public function testDeleteAttribute(): array
{ {
/** /**
* Test for SUCCESS * Test for SUCCESS
@ -54,7 +54,59 @@ class DatabaseCustomServerTest extends Scope
'required' => true, 'required' => true,
]); ]);
// wait for database worker to finish creating attributes $unneeded = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'attributeId' => 'unneeded',
'size' => 256,
'required' => true,
]);
// Wait for database worker to finish creating attributes
sleep(5);
$index = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'indexId' => 'key_lastName',
'type' => 'key',
'attributes' => [
'lastName',
],
]);
// Wait for database worker to finish creating index
sleep(5);
$collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $actors['body']['$id'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), []);
$unneededId = $unneeded['body']['$id'];
$this->assertEquals($collection['body']['$id'], $firstName['body']['$collection']);
$this->assertEquals($collection['body']['$id'], $lastName['body']['$collection']);
$this->assertIsArray($collection['body']['attributes']);
$this->assertCount(3, $collection['body']['attributes']);
$this->assertEquals($collection['body']['attributes'][0]['$id'], $firstName['body']['$id']);
$this->assertEquals($collection['body']['attributes'][1]['$id'], $lastName['body']['$id']);
$this->assertEquals($collection['body']['attributes'][2]['$id'], $unneeded['body']['$id']);
$this->assertCount(1, $collection['body']['indexes']);
$this->assertEquals($collection['body']['indexes'][0]['$id'], $index['body']['$id']);
// Delete attribute
$this->client->call(Client::METHOD_DELETE, '/database/collections/' . $actors ['body']['$id'] . '/attributes/' . $unneededId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
sleep(5); sleep(5);
$collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $actors['body']['$id'], array_merge([ $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $actors['body']['$id'], array_merge([
@ -70,8 +122,45 @@ class DatabaseCustomServerTest extends Scope
$this->assertEquals($collection['body']['attributes'][0]['$id'], $firstName['body']['$id']); $this->assertEquals($collection['body']['attributes'][0]['$id'], $firstName['body']['$id']);
$this->assertEquals($collection['body']['attributes'][1]['$id'], $lastName['body']['$id']); $this->assertEquals($collection['body']['attributes'][1]['$id'], $lastName['body']['$id']);
return [
'collectionId' => $actors['body']['$id'],
'indexId' => $index['body']['$id'],
];
}
/**
* @depends testDeleteAttribute
*/
public function testDeleteIndex($data): array
{
$index = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $data['collectionId'] . '/indexes/'. $data['indexId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
// Wait for database worker to finish deleting index
sleep(5);
$collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['collectionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), []);
$this->assertCount(0, $collection['body']['indexes']);
return $data;
}
/**
* @depends testDeleteIndex
*/
public function testDeleteCollection($data)
{
$collectionId = $data['collectionId'];
// Add Documents to the collection // Add Documents to the collection
$document1 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/documents', array_merge([ $document1 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/documents', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
@ -84,7 +173,7 @@ class DatabaseCustomServerTest extends Scope
'write' => ['user:'.$this->getUser()['$id']], 'write' => ['user:'.$this->getUser()['$id']],
]); ]);
$document2 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/documents', array_merge([ $document2 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/documents', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
@ -98,7 +187,7 @@ class DatabaseCustomServerTest extends Scope
]); ]);
$this->assertEquals($document1['headers']['status-code'], 201); $this->assertEquals($document1['headers']['status-code'], 201);
$this->assertEquals($document1['body']['$collection'], $actors['body']['$id']); $this->assertEquals($document1['body']['$collection'], $collectionId);
$this->assertIsArray($document1['body']['$read']); $this->assertIsArray($document1['body']['$read']);
$this->assertIsArray($document1['body']['$write']); $this->assertIsArray($document1['body']['$write']);
$this->assertCount(1, $document1['body']['$read']); $this->assertCount(1, $document1['body']['$read']);
@ -107,7 +196,7 @@ class DatabaseCustomServerTest extends Scope
$this->assertEquals($document1['body']['lastName'], 'Holland'); $this->assertEquals($document1['body']['lastName'], 'Holland');
$this->assertEquals($document2['headers']['status-code'], 201); $this->assertEquals($document2['headers']['status-code'], 201);
$this->assertEquals($document2['body']['$collection'], $actors['body']['$id']); $this->assertEquals($document2['body']['$collection'], $collectionId);
$this->assertIsArray($document2['body']['$read']); $this->assertIsArray($document2['body']['$read']);
$this->assertIsArray($document2['body']['$write']); $this->assertIsArray($document2['body']['$write']);
$this->assertCount(1, $document2['body']['$read']); $this->assertCount(1, $document2['body']['$read']);
@ -116,7 +205,7 @@ class DatabaseCustomServerTest extends Scope
$this->assertEquals($document2['body']['lastName'], 'Jackson'); $this->assertEquals($document2['body']['lastName'], 'Jackson');
// Delete the actors collection // Delete the actors collection
$response = $this->client->call(Client::METHOD_DELETE, '/database/collections/'.$actors['body']['$id'], array_merge([ $response = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $collectionId , array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'] 'x-appwrite-key' => $this->getProject()['apiKey']
@ -126,7 +215,7 @@ class DatabaseCustomServerTest extends Scope
$this->assertEquals($response['body'],""); $this->assertEquals($response['body'],"");
// Try to get the collection and check if it has been deleted // Try to get the collection and check if it has been deleted
$response = $this->client->call(Client::METHOD_GET, '/database/collections/'.$actors['body']['$id'], array_merge([ $response = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId , array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'] 'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders())); ], $this->getHeaders()));

View file

@ -63,7 +63,7 @@ class WebhooksCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'] 'x-appwrite-key' => $this->getProject()['apiKey']
]), [ ]), [
'id' => 'fullname', 'indexId' => 'fullname',
'type' => 'key', 'type' => 'key',
'attributes' => ['lastName', 'firstName'], 'attributes' => ['lastName', 'firstName'],
'orders' => ['ASC', 'ASC'], 'orders' => ['ASC', 'ASC'],