* updated migration tests

* database dsn fetching
* removed dsn from response models
This commit is contained in:
ArnabChatterjee20k
2025-10-14 21:13:26 +05:30
parent e2ddb0d6d0
commit 3a60bb306c
7 changed files with 531 additions and 21 deletions
+6 -1
View File
@@ -196,7 +196,12 @@ Server::setResource('getDatabasesDB', function (Cache $cache, Registry $register
return function (Document $database, ?Document $projectDocument = null) use ($cache, $register, $project): Database {
$projectDocument ??= $project;
$databaseType = $database->getAttribute('database', '');
$databaseDSN = new DSN($databaseType);
try {
$databaseDSN = new DSN($databaseType);
} catch (\InvalidArgumentException) {
$databaseDSN = new DSN('mysql://'.$databaseType);
}
try {
$dsn = new DSN($projectDocument->getAttribute('database'));
Generated
+4 -4
View File
@@ -4345,12 +4345,12 @@
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "e8faed3943b0f1dee8ecfc679a5dc85f9af727d5"
"reference": "b77e8c2ced7f6dc412dc2669b43a719fba19fcd6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/e8faed3943b0f1dee8ecfc679a5dc85f9af727d5",
"reference": "e8faed3943b0f1dee8ecfc679a5dc85f9af727d5",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/b77e8c2ced7f6dc412dc2669b43a719fba19fcd6",
"reference": "b77e8c2ced7f6dc412dc2669b43a719fba19fcd6",
"shasum": ""
},
"require": {
@@ -4393,7 +4393,7 @@
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/feat-documents-db"
},
"time": "2025-10-14T07:52:31+00:00"
"time": "2025-10-14T15:02:00+00:00"
},
{
"name": "utopia-php/mongo",
@@ -32,8 +32,9 @@ class Create extends Action
return 'createDatabase';
}
protected function getDatabaseDSN(string $region = 'default'): string
protected function getDatabaseDSN(Document $project): string
{
$region = $project->getAttribute('region');
$databases = [];
$databaseKeys = [];
/**
@@ -49,10 +50,8 @@ class Create extends Action
$dbScheme = System::getEnv('_APP_DB_HOST_DOCUMENTSDB', 'mongodb');
break;
default:
$databases = Config::getParam('pools-database', []);
$databaseKeys = System::getEnv('_APP_DATABASE_KEYS', '');
$databaseOverride = System::getEnv('_APP_DATABASE_OVERRIDE');
$dbScheme = System::getEnv('_APP_DB_HOST', 'mysql');
// legacy/tablesdb case where projects having the location of the database
return $project->getAttribute('database');
}
if ($region !== 'default') {
@@ -142,7 +141,7 @@ class Create extends Action
'enabled' => $enabled,
'search' => implode(' ', [$databaseId, $name]),
'type' => $this->getDatabaseType(),
'database' => $this->getDatabaseDSN($project->getAttribute('region'))
'database' => $this->getDatabaseDSN($project)
]));
} catch (DuplicateException) {
throw new Exception(Exception::DATABASE_ALREADY_EXISTS);
+1 -1
View File
@@ -164,9 +164,9 @@ class Migrations extends Action
$credentials['projectId'],
$credentials['endpoint'] === 'http://localhost/v1' ? 'http://appwrite/v1' : $credentials['endpoint'],
$credentials['apiKey'],
$getDatabasesDB,
SourceAppwrite::SOURCE_DATABASE,
$projectDB,
$getDatabasesDB,
),
CSV::getName() => new CSV(
$resourceId,
@@ -46,14 +46,7 @@ class Database extends Model
'default' => 'legacy',
'example' => 'legacy',
'enum' => ['legacy', 'tablesdb', 'documentsdb'],
])
->addRule('database', [
'type' => self::TYPE_STRING,
'description' => 'Database DSN.',
'default' => '',
'example' => 'mariadb://appwrite',
])
;
]);
}
/**
@@ -82,7 +82,11 @@ class Document extends Any
{
$document->removeAttribute('$collection');
$document->removeAttribute('$tenant');
$document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0));
$sequence = $document->getAttribute('$sequence', 0);
// to support both -> uuids(mongodb) and numeric ids(mariadb/mysql)
if (is_numeric($sequence)) {
$document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0));
}
foreach ($document->getAttributes() as $attribute) {
if (\is_array($attribute)) {
@@ -1194,4 +1194,513 @@ trait MigrationsBase
'x-appwrite-project' => $this->getProject()['$id'],
], $body);
}
/**
* DocumentsDB (schemaless)
*/
public function testAppwriteMigrationDocumentsDBDatabase(): array
{
$response = $this->client->call(Client::METHOD_POST, '/documentsdb', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'databaseId' => ID::unique(),
'name' => 'DocsDB - Migration DB'
]);
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['$id']);
$databaseId = $response['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_DOCUMENTSDB_DATABASE,
],
'endpoint' => 'http://localhost/v1',
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertEquals([Resource::TYPE_DOCUMENTSDB_DATABASE], $result['resources']);
$this->assertArrayHasKey(Resource::TYPE_DOCUMENTSDB_DATABASE, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['warning']);
$response = $this->client->call(Client::METHOD_GET, '/documentsdb/' . $databaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($databaseId, $response['body']['$id']);
$this->assertEquals('DocsDB - Migration DB', $response['body']['name']);
// Cleanup on destination
$this->client->call(Client::METHOD_DELETE, '/documentsdb/' . $databaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
return [
'databaseId' => $databaseId,
];
}
/**
* @depends testAppwriteMigrationDocumentsDBDatabase
*/
public function testAppwriteMigrationDocumentsDBCollection(array $data): array
{
$databaseId = $data['databaseId'];
$collection = $this->client->call(Client::METHOD_POST, '/documentsdb/' . $databaseId . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'collectionId' => ID::unique(),
'name' => 'DocsDB - Movies',
]);
$this->assertEquals(201, $collection['headers']['status-code']);
$collectionId = $collection['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_DOCUMENTSDB_DATABASE,
Resource::TYPE_COLLECTION, // collections in DocumentsDB map to tables in migration
],
'endpoint' => 'http://localhost/v1',
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
foreach ([Resource::TYPE_DOCUMENTSDB_DATABASE, Resource::TYPE_COLLECTION] as $resource) {
$this->assertArrayHasKey($resource, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][$resource]['error']);
$this->assertEquals(0, $result['statusCounters'][$resource]['pending']);
$this->assertEquals(1, $result['statusCounters'][$resource]['success']);
$this->assertEquals(0, $result['statusCounters'][$resource]['processing']);
$this->assertEquals(0, $result['statusCounters'][$resource]['warning']);
}
$response = $this->client->call(Client::METHOD_GET, '/documentsdb/' . $databaseId . '/collections/' . $collectionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']);
$this->assertEquals($collectionId, $response['body']['$id']);
$this->assertEquals('DocsDB - Movies', $response['body']['name']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/documentsdb/' . $databaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
return [
'databaseId' => $databaseId,
'collectionId' => $collectionId,
];
}
/**
* @depends testAppwriteMigrationDocumentsDBCollection
*/
public function testAppwriteMigrationDocumentsDBDocument(array $data): void
{
$databaseId = $data['databaseId'];
$collectionId = $data['collectionId'];
$document = $this->client->call(Client::METHOD_POST, '/documentsdb/' . $databaseId . '/collections/' . $collectionId . '/documents', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'documentId' => ID::unique(),
'data' => [
'title' => 'Migration Test Movie',
'releaseYear' => 1999,
]
]);
$this->assertEquals(201, $document['headers']['status-code']);
$documentId = $document['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_DOCUMENTSDB_DATABASE,
Resource::TYPE_COLLECTION,
Resource::TYPE_DOCUMENT,
],
'endpoint' => 'http://localhost/v1',
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
foreach ([Resource::TYPE_DOCUMENTSDB_DATABASE] as $resource) {
$this->assertArrayHasKey($resource, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][$resource]['error']);
$this->assertEquals(0, $result['statusCounters'][$resource]['pending']);
$this->assertEquals(1, $result['statusCounters'][$resource]['success']);
}
$response = $this->client->call(Client::METHOD_GET, '/documentsdb/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']);
$this->assertEquals($documentId, $response['body']['$id']);
$this->assertEquals('Migration Test Movie', $response['body']['title']);
$this->assertEquals(1999, $response['body']['releaseYear']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/documentsdb/' . $databaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/documentsdb/' . $databaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
}
/**
* Migrate a project that contains both SQL Databases (/databases) and
* schemaless DocumentsDB (/documentsdb) in a single run and verify results.
* Uses a dedicated isolated source project to avoid interference from other tests.
*/
public function testAppwriteMigrationMixedDatabases(): void
{
// Create a fresh isolated source project for this test
$sourceProject = $this->getProject(true);
// ====== Create SQL Database (/databases) with table, column, and row ======
$sql = $this->client->call(Client::METHOD_POST, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
], [
'databaseId' => ID::unique(),
'name' => 'Mixed SQL DB',
]);
$this->assertEquals(201, $sql['headers']['status-code']);
$this->assertNotEmpty($sql['body']['$id']);
$sqlDatabaseId = $sql['body']['$id'];
// Create Table in SQL Database
$table = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $sqlDatabaseId . '/tables', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
], [
'tableId' => ID::unique(),
'name' => 'Products',
]);
$this->assertEquals(201, $table['headers']['status-code']);
$tableId = $table['body']['$id'];
// Create Column in Table
$column = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $sqlDatabaseId . '/tables/' . $tableId . '/columns/string', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
], [
'key' => 'productName',
'size' => 255,
'required' => true,
]);
$this->assertEquals(202, $column['headers']['status-code']);
// Wait for column to be ready
$this->assertEventually(function () use ($sqlDatabaseId, $tableId, $sourceProject) {
$response = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $sqlDatabaseId . '/tables/' . $tableId . '/columns/productName', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('available', $response['body']['status']);
}, 5000, 500);
// Create Row in Table
$row = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $sqlDatabaseId . '/tables/' . $tableId . '/rows', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
], [
'rowId' => ID::unique(),
'data' => [
'productName' => 'Laptop',
],
]);
$this->assertEquals(201, $row['headers']['status-code']);
$rowId = $row['body']['$id'];
// ====== Create DocumentsDB (/documentsdb) with collection and document ======
$docs = $this->client->call(Client::METHOD_POST, '/documentsdb', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
], [
'databaseId' => ID::unique(),
'name' => 'Mixed DocsDB',
]);
$this->assertEquals(201, $docs['headers']['status-code']);
$this->assertNotEmpty($docs['body']['$id']);
$docsDatabaseId = $docs['body']['$id'];
// Create Collection in DocumentsDB
$collection = $this->client->call(Client::METHOD_POST, '/documentsdb/' . $docsDatabaseId . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
], [
'collectionId' => ID::unique(),
'name' => 'Users',
]);
$this->assertEquals(201, $collection['headers']['status-code']);
$collectionId = $collection['body']['$id'];
// Create Document in Collection
$document = $this->client->call(Client::METHOD_POST, '/documentsdb/' . $docsDatabaseId . '/collections/' . $collectionId . '/documents', [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
], [
'documentId' => ID::unique(),
'data' => [
'name' => 'John Doe',
'email' => 'john@example.com',
],
]);
$this->assertEquals(201, $document['headers']['status-code']);
$documentId = $document['body']['$id'];
// ====== Perform migration including both database kinds with all child resources ======
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_DATABASE,
Resource::TYPE_TABLE,
Resource::TYPE_COLUMN,
Resource::TYPE_ROW,
Resource::TYPE_DOCUMENTSDB_DATABASE,
Resource::TYPE_COLLECTION,
Resource::TYPE_DOCUMENT,
],
'endpoint' => 'http://localhost/v1',
'projectId' => $sourceProject['$id'],
'apiKey' => $sourceProject['apiKey'],
]);
// ====== Assert migration result ======
$this->assertEquals('completed', $result['status']);
$this->assertEquals('Appwrite', $result['source']);
$this->assertEquals('Appwrite', $result['destination']);
$this->assertEquals([
Resource::TYPE_DATABASE,
Resource::TYPE_TABLE,
Resource::TYPE_COLUMN,
Resource::TYPE_ROW,
Resource::TYPE_DOCUMENTSDB_DATABASE,
Resource::TYPE_COLLECTION,
Resource::TYPE_DOCUMENT,
], $result['resources']);
// Assert SQL Database counters
$this->assertArrayHasKey(Resource::TYPE_DATABASE, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DATABASE]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DATABASE]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_DATABASE]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DATABASE]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DATABASE]['warning']);
// Assert Table counters
$this->assertArrayHasKey(Resource::TYPE_TABLE, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TABLE]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TABLE]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_TABLE]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TABLE]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TABLE]['warning']);
// Assert Column counters
$this->assertArrayHasKey(Resource::TYPE_COLUMN, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLUMN]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLUMN]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_COLUMN]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLUMN]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLUMN]['warning']);
// Assert Row counters
$this->assertArrayHasKey(Resource::TYPE_ROW, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_ROW]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_ROW]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_ROW]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_ROW]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_ROW]['warning']);
// Assert DocumentsDB counters
$this->assertArrayHasKey(Resource::TYPE_DOCUMENTSDB_DATABASE, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENTSDB_DATABASE]['warning']);
// Assert Collection counters
$this->assertArrayHasKey(Resource::TYPE_COLLECTION, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLLECTION]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLLECTION]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_COLLECTION]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLLECTION]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_COLLECTION]['warning']);
// Assert Document counters
$this->assertArrayHasKey(Resource::TYPE_DOCUMENT, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENT]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENT]['pending']);
$this->assertEquals(1, $result['statusCounters'][Resource::TYPE_DOCUMENT]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENT]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_DOCUMENT]['warning']);
// Ensure only expected counters exist (7 total)
$this->assertCount(7, $result['statusCounters']);
// ====== Validate on destination: SQL Database resources ======
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $sqlDatabaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($sqlDatabaseId, $response['body']['$id']);
$this->assertEquals('Mixed SQL DB', $response['body']['name']);
// Validate Table
$response = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $sqlDatabaseId . '/tables/' . $tableId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($tableId, $response['body']['$id']);
$this->assertEquals('Products', $response['body']['name']);
// Validate Column
$response = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $sqlDatabaseId . '/tables/' . $tableId . '/columns/productName', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('productName', $response['body']['key']);
$this->assertEquals(255, $response['body']['size']);
$this->assertEquals(true, $response['body']['required']);
// Validate Row
$response = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $sqlDatabaseId . '/tables/' . $tableId . '/rows/' . $rowId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($rowId, $response['body']['$id']);
$this->assertEquals('Laptop', $response['body']['productName']);
// ====== Validate on destination: DocumentsDB resources ======
$response = $this->client->call(Client::METHOD_GET, '/documentsdb/' . $docsDatabaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($docsDatabaseId, $response['body']['$id']);
$this->assertEquals('Mixed DocsDB', $response['body']['name']);
// Validate Collection
$response = $this->client->call(Client::METHOD_GET, '/documentsdb/' . $docsDatabaseId . '/collections/' . $collectionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($collectionId, $response['body']['$id']);
$this->assertEquals('Users', $response['body']['name']);
// Validate Document
$response = $this->client->call(Client::METHOD_GET, '/documentsdb/' . $docsDatabaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($documentId, $response['body']['$id']);
$this->assertEquals('John Doe', $response['body']['name']);
$this->assertEquals('john@example.com', $response['body']['email']);
// ====== Cleanup both destinations ======
$this->client->call(Client::METHOD_DELETE, '/databases/' . $sqlDatabaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/documentsdb/' . $docsDatabaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
// ====== Cleanup sources ======
$this->client->call(Client::METHOD_DELETE, '/databases/' . $sqlDatabaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/documentsdb/' . $docsDatabaseId, [
'content-type' => 'application/json',
'x-appwrite-project' => $sourceProject['$id'],
'x-appwrite-key' => $sourceProject['apiKey'],
]);
}
}