mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
tests: add Appwrite->Appwrite row onDuplicate test with tolerant poller
This commit is contained in:
@@ -762,8 +762,12 @@ trait MigrationsBase
|
||||
}
|
||||
|
||||
/**
|
||||
* Appwrite → Appwrite row migration honoring onDuplicate=skip and onDuplicate=upsert.
|
||||
* Exercises the row-buffer dispatch path via cross-project migration rather than CSV/JSON upload.
|
||||
* Appwrite → Appwrite row re-migration honoring onDuplicate=skip and onDuplicate=upsert.
|
||||
*
|
||||
* onDuplicate only gates the row-write path in DestinationAppwrite. Re-running the
|
||||
* migration with the full resource tree (database/table/column/row) always errors
|
||||
* on schema creation because destination already has those. This test accepts those
|
||||
* schema-level errors as expected noise and asserts row-level correctness directly.
|
||||
*/
|
||||
public function testAppwriteMigrationRowsOnDuplicate(): void
|
||||
{
|
||||
@@ -778,7 +782,6 @@ trait MigrationsBase
|
||||
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
|
||||
];
|
||||
|
||||
// Source setup: database + table + column + row
|
||||
$data = $this->setupMigrationTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
@@ -797,7 +800,7 @@ trait MigrationsBase
|
||||
Resource::TYPE_ROW,
|
||||
];
|
||||
|
||||
// First migration: destination is empty, all resources copied
|
||||
// First migration: destination is empty, strict completion expected.
|
||||
$first = $this->performMigrationSync([
|
||||
'resources' => $resources,
|
||||
'endpoint' => $this->webEndpoint,
|
||||
@@ -806,51 +809,80 @@ trait MigrationsBase
|
||||
]);
|
||||
$this->assertEquals('completed', $first['status']);
|
||||
|
||||
// Mutate destination row so we can prove skip preserves it
|
||||
// Mutate destination row to prove onDuplicate=skip preserves it.
|
||||
$mutate = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId, $destHeaders, [
|
||||
'data' => ['name' => 'Mutated'],
|
||||
]);
|
||||
$this->assertEquals(200, $mutate['headers']['status-code']);
|
||||
$this->assertEquals('Mutated', $mutate['body']['name']);
|
||||
|
||||
// Second migration with onDuplicate=skip: destination row must keep 'Mutated'
|
||||
$second = $this->performMigrationSync([
|
||||
// Re-migration with onDuplicate=skip. Overall status is expected to be 'failed'
|
||||
// because schema re-create errors (database/table/column already exist) — those
|
||||
// are orthogonal to onDuplicate which only affects row writes. Assert row-level
|
||||
// success counter instead.
|
||||
$this->runMigrationAssertingRowSuccess([
|
||||
'resources' => $resources,
|
||||
'endpoint' => $this->webEndpoint,
|
||||
'projectId' => $this->getProject()['$id'],
|
||||
'apiKey' => $this->getProject()['apiKey'],
|
||||
'onDuplicate' => 'skip',
|
||||
]);
|
||||
$this->assertEquals('completed', $second['status']);
|
||||
|
||||
$rowAfterSkip = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId, $destHeaders);
|
||||
$this->assertEquals(200, $rowAfterSkip['headers']['status-code']);
|
||||
$this->assertEquals('Mutated', $rowAfterSkip['body']['name'], 'onDuplicate=skip must not overwrite destination row');
|
||||
|
||||
// Third migration with onDuplicate=upsert: destination row must be restored to 'Original'
|
||||
$third = $this->performMigrationSync([
|
||||
// Re-migration with onDuplicate=upsert. Same status-tolerant approach; assert
|
||||
// destination row was restored to source value.
|
||||
$this->runMigrationAssertingRowSuccess([
|
||||
'resources' => $resources,
|
||||
'endpoint' => $this->webEndpoint,
|
||||
'projectId' => $this->getProject()['$id'],
|
||||
'apiKey' => $this->getProject()['apiKey'],
|
||||
'onDuplicate' => 'upsert',
|
||||
]);
|
||||
$this->assertEquals('completed', $third['status']);
|
||||
|
||||
$rowAfterUpsert = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId, $destHeaders);
|
||||
$this->assertEquals(200, $rowAfterUpsert['headers']['status-code']);
|
||||
$this->assertEquals('Original', $rowAfterUpsert['body']['name'], 'onDuplicate=upsert must restore source value');
|
||||
|
||||
// Cleanup on destination
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, $destHeaders);
|
||||
|
||||
// Cleanup on source
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, $sourceHeaders);
|
||||
|
||||
self::$cachedDatabaseData = [];
|
||||
self::$cachedTableData = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for Appwrite→Appwrite re-migrations where onDuplicate applies only to rows.
|
||||
* Accepts migration stages of 'finished' regardless of overall status, then asserts
|
||||
* the row-level counter has zero errors (and at least one success).
|
||||
*
|
||||
* @param array<string,mixed> $body
|
||||
*/
|
||||
private function runMigrationAssertingRowSuccess(array $body): void
|
||||
{
|
||||
$migration = $this->client->call(Client::METHOD_POST, '/migrations/appwrite', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getDestinationProject()['$id'],
|
||||
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
|
||||
], $body);
|
||||
$this->assertEquals(202, $migration['headers']['status-code']);
|
||||
|
||||
$this->assertEventually(function () use ($migration) {
|
||||
$response = $this->client->call(Client::METHOD_GET, '/migrations/' . $migration['body']['$id'], [
|
||||
'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('finished', $response['body']['stage']);
|
||||
$this->assertArrayHasKey(Resource::TYPE_ROW, $response['body']['statusCounters']);
|
||||
$this->assertEquals(0, $response['body']['statusCounters'][Resource::TYPE_ROW]['error']);
|
||||
$this->assertGreaterThanOrEqual(1, $response['body']['statusCounters'][Resource::TYPE_ROW]['success']);
|
||||
}, 60_000, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user