Ctrl K
ComunidadGuías…

test/knowledge-db-import.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var test = require("node:test");
var assert = require("node:assert/strict");
var fs = require("fs");
var os = require("os");
var path = require("path");
var child = require("child_process");
var Datastore = require("@seald-io/nedb");
var serviceModule = require("../lib/knowledge-db-service");
var imports = require("../lib/knowledge-db-import");
var storageModule = require("../lib/knowledge-db-storage-nedb-maintenance");
var sequence = 0;
function op() { return "import_" + Date.now() + "_" + (++sequence); }
function fixture(t, options) {
  var root = fs.mkdtempSync(path.join(os.tmpdir(), "clay-import-"));
  t.after(function () { fs.rmSync(root, { recursive: true, force: true }); });
  return { root: root, filename: path.join(root, "knowledge", ".clay-db", "databases.db"), service: serviceModule.createKnowledgeDbService(Object.assign({ projectDir: root }, options)) };
}
function schema(extra) { return [{ id: "fld_title00", name: "Title", type: "title", required: true }].concat(extra || []); }
async function database(service, name, extra) { return (await service.create({ name: name, schema: schema(extra), operationId: op() })).database; }
function row(key, values) { return { sourceKey: String(key), sourcePayload: { key: String(key), original: values }, values: values }; }
async function request(service, db, rows, namespace) {
  var revision = (await service.read({ databaseId: db.id })).database.revision;
  return service.importRecords({ databaseId: db.id, expectedDatabaseRevision: revision, sourceNamespace: namespace || "synthetic", rows: rows, operationId: op() });
}
async function rejects(work, code) { await assert.rejects(async function () { return work(); }, function (cause) { return cause.code === code; }); }
async function scan(service, db, count) {
  var cursor = null; var ids = new Set();
  do { var page = await service.query({ databaseId: db.id, limit: 100, cursor: cursor }); assert.equal(page.totals.count, count); page.records.forEach(function (record) { assert.ok(!ids.has(record.id)); ids.add(record.id); }); cursor = page.nextCursor; } while (cursor);
  assert.equal(ids.size, count);
}
function isolated(script, args) {
  return JSON.parse(child.execFileSync(process.execPath, ["-e", script, path.resolve(__dirname, "../lib/knowledge-db-service.js")].concat(args), { encoding: "utf8", maxBuffer: 1024 * 1024 }));
}

test("production import covers vocabulary, finance relationships, exact scans and isolated restart/backup replay", async function (t) {
  var f = fixture(t, { projectSummary: function () {} }); var service = f.service; var writes = 0; var aggregateBytes = 0; var original = Datastore.prototype.updateAsync;
  Datastore.prototype.updateAsync = function (query, value, options) { if (this.filename === f.filename) { writes++; aggregateBytes = Math.max(aggregateBytes, Buffer.byteLength(JSON.stringify(value))); } return original.call(this, query, value, options); };
  t.after(function () { Datastore.prototype.updateAsync = original; });
  var vocabulary = await database(service, "Vocabulary", [{ id: "fld_notes00", name: "Definition", type: "text" }]);
  var initialWrites = writes; var start = Date.now(); var firstRows; var firstResult; var firstRequest;
  for (var offset = 0; offset < 8563; offset += 100) {
    var rows = [];
    for (var i = offset; i < Math.min(offset + 100, 8563); i++) rows.push(row(i, { fld_title00: "Synthetic word " + i, fld_notes00: "A synthetic definition with context.\n\tUsage example " + i + ": " + "meaning ".repeat(20) }));
    var revision = (await service.read({ databaseId: vocabulary.id })).database.revision;
    var args = { databaseId: vocabulary.id, expectedDatabaseRevision: revision, sourceNamespace: "vocabulary", rows: rows, operationId: op() };
    var result = await service.importRecords(args);
    assert.equal(result.createdCount, rows.length); assert.equal(result.databaseRevision, revision + 1);
    if (!offset) { firstRows = rows; firstResult = result; firstRequest = args; }
  }
  assert.equal(writes - initialWrites, 172);
  t.diagnostic("8563 vocabulary aggregate bytes: " + aggregateBytes);
  var exactReplay = await service.importRecords(firstRequest); assert.deepEqual(exactReplay.mappings, firstResult.mappings); assert.equal(exactReplay.databaseRevision, firstResult.databaseRevision); assert.equal(writes - initialWrites, 172);
  assert.equal((await service.query({ databaseId: vocabulary.id })).totals.count, 8563);
  var firstId = firstResult.mappings[0].recordId;
  await service.updateRecord({ databaseId: vocabulary.id, recordId: firstId, expectedRevision: 1, values: { fld_notes00: "Human correction\n\tkept" }, operationId: op() });
  await service.archiveRecord({ databaseId: vocabulary.id, recordId: firstResult.mappings[1].recordId, expectedRevision: 1, operationId: op() });
  var beforeReplay = writes; var replay = await request(service, vocabulary, firstRows, "vocabulary"); assert.equal(replay.createdCount, 0); assert.equal(writes, beforeReplay + 1);
  assert.equal((await service.readRecord({ databaseId: vocabulary.id, recordId: firstId })).record.values.fld_notes00, "Human correction\n\tkept");
  assert.equal((await service.query({ databaseId: vocabulary.id, archived: true })).totals.count, 1);
  await scan(service, vocabulary, 8562);
  var progress = await service.readImportProgress({ databaseId: vocabulary.id, sourceNamespace: "vocabulary", limit: 100 }); assert.equal(progress.total, 8563); assert.equal(progress.nextOffset, 100);
  var mappingCount = 0; var mappingOffset = 0;
  do { var mappings = await service.readImportProgress({ databaseId: vocabulary.id, sourceNamespace: "vocabulary", offset: mappingOffset }); mappingCount += mappings.mappings.length; mappingOffset = mappings.nextOffset; } while (mappingOffset !== null);
  assert.equal(mappingCount, 8563);
  var categories = await database(service, "Categories"); var spenders = await database(service, "Spenders");
  var category = await request(service, categories, [row("food", { fld_title00: "Food" }), row("travel", { fld_title00: "Travel" })], "categories");
  await request(service, spenders, [row("person", { fld_title00: "Synthetic person" })], "spenders");
  var finance = await database(service, "Transactions", [{ id: "fld_amount0", name: "Amount", type: "number" }, { id: "fld_category", name: "Category", type: "reference", target: "record", targetDatabaseId: categories.id }, { id: "fld_spender", name: "Spender", type: "reference", target: "record", targetDatabaseId: spenders.id }]);
  var financeRows = []; var expectedSum = 0;
  for (var j = 0; j < 537; j++) { expectedSum += j; financeRows.push(row(j, { fld_title00: "Transaction " + j, fld_amount0: j, fld_category: { type: "record", sourceNamespace: "categories", sourceKey: "food" }, fld_spender: { type: "record", sourceNamespace: "spenders", sourceKey: "person" } })); }
  var financeWrites = writes;
  for (var n = 0; n < financeRows.length; n += 100) await request(service, finance, financeRows.slice(n, n + 100), "finance");
  assert.equal(writes - financeWrites, 12); await scan(service, finance, 537);
  var totals = await service.query({ databaseId: finance.id }); assert.equal(totals.totals.sums.fld_amount0, expectedSum); assert.equal(totals.records[0].references.length, 2); assert.ok(totals.records[0].references.every(function (reference) { return reference.status === "available"; }));
  await service.archiveRecord({ databaseId: categories.id, recordId: category.mappings[0].recordId, expectedRevision: 1, operationId: op() });
  assert.equal((await service.query({ databaseId: finance.id })).records[0].references[0].status, "archived");
  var current = (await service.read({ databaseId: vocabulary.id })).database;
  var ordinary = await service.createRecord({ databaseId: current.id, expectedDatabaseRevision: current.revision, values: { fld_title00: "Normal CRUD", fld_notes00: "After import" }, operationId: op() });
  var updated = await service.updateRecord({ databaseId: current.id, recordId: ordinary.record.id, expectedRevision: 1, values: { fld_notes00: "Updated" }, operationId: op() }); assert.equal(updated.record.revision, 2);
  var storageStatus = await service.readStorageStatus();
  assert.equal(storageStatus.maintenancePending, false); assert.ok(storageStatus.compactions > 0);
  assert.ok(storageStatus.journalBytes <= Math.max(storageModule.MIN_COMPACTION_BYTES, storageStatus.liveBytes * 4));
  assert.ok(storageStatus.peakJournalBytes <= Math.max(storageModule.MIN_COMPACTION_BYTES, storageStatus.liveBytes * 4));
  var replayFile = path.join(f.root, "replay.json"); fs.writeFileSync(replayFile, JSON.stringify({ databaseId: vocabulary.id, firstId: firstId, rows: firstRows, oldOperationId: firstRequest.operationId, count: 8563 }));
  var restartScript = 'var fs = require("fs"); var assert = require("assert/strict"); var mod = require(process.argv[1]); var data = JSON.parse(fs.readFileSync(process.argv[3])); Date.now = function () { return Number(process.argv[4]); }; (async function () { var s = mod.createKnowledgeDbService({projectDir:process.argv[2]}); var db = (await s.read({databaseId:data.databaseId})).database; var result = await s.importRecords({databaseId:db.id, expectedDatabaseRevision:db.revision, operationId:"resume_"+Date.now()+"_fresh", sourceNamespace:"vocabulary", rows:data.rows}); assert.equal(result.createdCount,0); assert.equal(result.replayedCount,100); assert.equal((await s.read({databaseId:db.id})).database.revision,db.revision); var record = await s.readRecord({databaseId:db.id,recordId:data.firstId}); assert.equal(record.record.values.fld_notes00,"Human correction\\n\\tkept"); assert.equal(record.history.length,1); assert.equal((await s.query({databaseId:db.id})).totals.count,data.count); await assert.rejects(async function(){return s.importRecords({databaseId:db.id, expectedDatabaseRevision:db.revision, operationId:data.oldOperationId, sourceNamespace:"vocabulary", rows:data.rows});},function(e){return e.code==="OPERATION_EXPIRED";}); process.stdout.write(JSON.stringify({count:data.count, replayed:result.replayedCount})); })().catch(function(e){console.error(e);process.exit(1);});';
  var future = String(Date.now() + serviceModule.IDEMPOTENCY_WINDOW_MS + 10000);
  assert.equal(isolated(restartScript, [f.root, replayFile, future]).replayed, 100);
  var backup = fs.mkdtempSync(path.join(os.tmpdir(), "clay-import-backup-")); t.after(function () { fs.rmSync(backup, { recursive: true, force: true }); });
  fs.cpSync(path.join(f.root, "knowledge"), path.join(backup, "knowledge"), { recursive: true });
  assert.equal(isolated(restartScript, [backup, replayFile, future]).count, 8563);
  t.diagnostic(JSON.stringify({ rows: 8563, financeRows: 537, elapsedMs: Date.now() - start, maximumAggregateBytes: aggregateBytes, peakJournalBytes: storageStatus.peakJournalBytes, finalJournalBytes: storageStatus.journalBytes, afterRestartFileBytes: fs.statSync(f.filename).size, liveBytes: storageStatus.liveBytes, compactions: storageStatus.compactions, vocabularyCanonicalWrites: 86, vocabularyProjectionWrites: 86, financeCanonicalWrites: 6, financeProjectionWrites: 6 }));
});

test("import validates every row atomically, same-batch forward references, conflicts, revisions and archives", async function (t) {
  var f = fixture(t); var s = f.service; var db = await database(s, "References", [{ id: "fld_related", name: "Related", type: "reference", target: "record" }]);
  var rows = [row("first", { fld_title00: "First", fld_related: { type: "record", sourceNamespace: "synthetic", sourceKey: "second" } }), row("second", { fld_title00: "Second" })];
  var original = await request(s, db, rows); var detail = await s.readRecord({ databaseId: db.id, recordId: original.mappings[0].recordId }); assert.equal(detail.record.values.fld_related.id, original.mappings[1].recordId); assert.equal(detail.record.references[0].status, "available");
  var revision = (await s.read({ databaseId: db.id })).database.revision;
  await rejects(function () { return s.importRecords({ databaseId: db.id, expectedDatabaseRevision: 1, sourceNamespace: "synthetic", rows: rows, operationId: op() }); }, "STALE");
  var changed = JSON.parse(JSON.stringify(rows)); changed[0].sourcePayload.newContent = true;
  await rejects(function () { return request(s, db, changed); }, "IMPORT_SOURCE_CONFLICT");
  var changedValues = JSON.parse(JSON.stringify(rows)); changedValues[0].values.fld_title00 = "Changed";
  await rejects(function () { return request(s, db, changedValues); }, "IMPORT_SOURCE_CONFLICT");
  await rejects(function () { return request(s, db, [row("third", { fld_title00: "Third" }), row("invalid", { fld_title00: 42 })]); }, "INVALID");
  await rejects(function () { return request(s, db, [row("third", { fld_title00: "Third" }), row("missing", { fld_title00: "Missing", fld_related: { type: "record", sourceNamespace: "synthetic", sourceKey: "absent" } })]); }, "FORBIDDEN_REFERENCE");
  await rejects(function () { return request(s, db, [row("external", { fld_title00: "External", fld_related: { type: "record", databaseId: "db_outside123", id: "rec_outside1" } })]); }, "FORBIDDEN_REFERENCE");
  assert.equal((await s.read({ databaseId: db.id })).database.revision, revision); assert.equal((await s.readImportProgress({ databaseId: db.id, sourceNamespace: "synthetic" })).total, 2); assert.equal((await s.query({ databaseId: db.id })).totals.count, 2);
  var archived = await s.archiveRecord({ databaseId: db.id, recordId: original.mappings[1].recordId, expectedRevision: 1, operationId: op() });
  await request(s, db, rows); assert.ok((await s.readRecord({ databaseId: db.id, recordId: archived.record.id })).record.archivedAt);
  var recovered = await s.recoverRecord({ databaseId: db.id, recordId: archived.record.id, expectedRevision: 2, operationId: op() }); assert.equal(recovered.record.archivedAt, null); assert.equal((await s.readRecord({ databaseId: db.id, recordId: archived.record.id })).history.length, 2);
  revision = (await s.read({ databaseId: db.id })).database.revision; await s.archive({ databaseId: db.id, expectedRevision: revision, operationId: op() });
  await rejects(function () { return s.importRecords({ databaseId: db.id, expectedDatabaseRevision: revision + 1, sourceNamespace: "synthetic", rows: rows, operationId: op() }); }, "ARCHIVED");
  assert.equal((await s.readImportProgress({ databaseId: db.id, sourceNamespace: "synthetic" })).total, 2);
});

test("finite batch, byte and aggregate envelopes and multiline text validation", async function (t) {
  var f = fixture(t, { maxAggregateBytes: 8000 }); var s = f.service; var db = await database(s, "Limits", [{ id: "fld_notes00", name: "Text", type: "text" }]);
  await rejects(function () { return request(s, db, new Array(101).fill(row("one", { fld_title00: "One" }))); }, "IMPORT_BATCH_LIMIT");
  await rejects(function () { return request(s, db, []); }, "IMPORT_BATCH_LIMIT");
  var huge = row("huge", { fld_title00: "Huge" }); huge.sourcePayload = "x".repeat(imports.MAX_BATCH_BYTES);
  await rejects(function () { return request(s, db, [huge]); }, "IMPORT_BYTES_LIMIT");
  var large = row("large", { fld_title00: "Large", fld_notes00: "x".repeat(7000) });
  await assert.rejects(async function () { return request(s, db, [large]); }, function (cause) { return cause.code === "LIMIT" && /8000 byte aggregate/.test(cause.message); });
  await rejects(function () { return request(s, db, [row("nul", { fld_title00: "Nul", fld_notes00: "a\u0000b" })]); }, "INVALID");
  await rejects(function () { return request(s, db, [row("control", { fld_title00: "Control", fld_notes00: "a\u000bb" })]); }, "INVALID");
  await rejects(function () { return request(s, db, [row("title", { fld_title00: "Title\n" })]); }, "INVALID");
  var text = " \n\tNarrative\r\nEnd\t "; var result = await request(s, db, [row("text", { fld_title00: "Text", fld_notes00: text })]); assert.equal((await s.readRecord({ databaseId: db.id, recordId: result.mappings[0].recordId })).record.values.fld_notes00, text);
  await rejects(function () { return request(s, db, [row("blank", { fld_title00: " " })]); }, "INVALID");
  var bad = row("json", { fld_title00: "Bad" }); bad.sourcePayload = { number: Infinity }; await rejects(function () { return request(s, db, [bad]); }, "INVALID");
  bad.sourcePayload = {}; bad.sourcePayload.self = bad.sourcePayload; await rejects(function () { return request(s, db, [bad]); }, "INVALID");
  await rejects(function () { return s.readImportProgress({ databaseId: db.id, sourceNamespace: "synthetic", limit: 101 }); }, "INVALID");
  assert.equal((await s.query({ databaseId: db.id })).totals.count, 1);
});

test("failed NeDB persistence leaves no in-memory import mappings or receipts and can retry", async function (t) {
  var f = fixture(t); var s = f.service; var db = await database(s, "Failure"); var original = Datastore.prototype.updateAsync; var fail = true;
  Datastore.prototype.updateAsync = function (query, value, options) {
    if (this.filename !== f.filename || !fail) return original.call(this, query, value, options);
    fail = false; var persistence = this.persistence; var persist = persistence.persistNewStateAsync;
    persistence.persistNewStateAsync = async function () { throw new Error("injected disk failure"); };
    return original.call(this, query, value, options).finally(function () { persistence.persistNewStateAsync = persist; });
  };
  t.after(function () { Datastore.prototype.updateAsync = original; });
  var args = { databaseId: db.id, expectedDatabaseRevision: db.revision, sourceNamespace: "synthetic", rows: [row("one", { fld_title00: "One" })], operationId: op() };
  await assert.rejects(s.importRecords(args), /injected disk failure/);
  assert.equal((await s.read({ databaseId: db.id })).database.revision, db.revision); assert.equal((await s.readImportProgress({ databaseId: db.id, sourceNamespace: "synthetic" })).total, 0); assert.equal((await s.query({ databaseId: db.id })).totals.count, 0);
  var result = await s.importRecords(args); assert.equal(result.createdCount, 1); assert.equal((await s.importRecords(args)).mappings[0].recordId, result.mappings[0].recordId);
});

test("measured 20000 row capacity retains finite bounds and live receipt budget", async function (t) {
  var f = fixture(t, { projectSummary: function () {} }); var s = f.service; var db = await database(s, "Capacity"); var start = Date.now(); var writes = 0; var largest = 0; var original = Datastore.prototype.updateAsync;
  Datastore.prototype.updateAsync = function (query, value, options) { if (this.filename === f.filename) { writes++; largest = Math.max(largest, Buffer.byteLength(JSON.stringify(value))); } return original.call(this, query, value, options); };
  t.after(function () { Datastore.prototype.updateAsync = original; });
  for (var offset = 0; offset < 20000; offset += 100) {
    var rows = []; for (var i = offset; i < offset + 100; i++) rows.push(row(i, { fld_title00: "Synthetic entry " + i }));
    try { await request(s, db, rows); } catch (cause) { t.diagnostic(JSON.stringify({ acceptedRows: offset, largestAggregateBytes: largest, elapsedMs: Date.now() - start, nextError: cause.message })); throw cause; }
  }
  assert.equal(writes, 400); var page = await s.query({ databaseId: db.id }); assert.equal(page.totals.count, 20000);
  await rejects(function () { return request(s, db, [row("overflow", { fld_title00: "Overflow" })]); }, "LIMIT");
  var current = (await s.read({ databaseId: db.id })).database;
  await rejects(function () { return s.createRecord({ databaseId: db.id, expectedDatabaseRevision: current.revision, values: { fld_title00: "Overflow CRUD" }, operationId: op() }); }, "LIMIT");
  await s.updateRecord({ databaseId: db.id, recordId: page.records[0].id, expectedRevision: 1, values: { fld_title00: "Corrected capacity entry" }, operationId: op() });
  assert.equal((await s.readImportProgress({ databaseId: db.id, sourceNamespace: "synthetic" })).total, 20000);
  var storageStatus = await s.readStorageStatus();
  assert.equal(storageStatus.maintenancePending, false); assert.ok(storageStatus.compactions > 0);
  assert.ok(storageStatus.journalBytes <= Math.max(storageModule.MIN_COMPACTION_BYTES, storageStatus.liveBytes * 4));
  assert.ok(storageStatus.peakJournalBytes <= Math.max(storageModule.MIN_COMPACTION_BYTES, storageStatus.liveBytes * 4));
  t.diagnostic(JSON.stringify({ rows: 20000, canonicalImportWrites: 200, projectionImportWrites: 200, aggregateBytes: largest, elapsedMs: Date.now() - start, peakJournalBytes: storageStatus.peakJournalBytes, finalJournalBytes: storageStatus.journalBytes, liveBytes: storageStatus.liveBytes, compactions: storageStatus.compactions, aggregateLimitBytes: serviceModule.MAX_AGGREGATE_BYTES }));
});

test("import survives ambiguous persisted success and keeps bounded summary projection behavior", async function (t) {
  var summaries = 0; var f = fixture(t, { projectSummary: function () { summaries++; } }); var s = f.service; var db = await database(s, "Ambiguous failure"); var original = Datastore.prototype.updateAsync; var fail = true;
  Datastore.prototype.updateAsync = function (query, value, options) {
    if (this.filename !== f.filename || !fail) return original.call(this, query, value, options);
    fail = false; var persistence = this.persistence; var persist = persistence.persistNewStateAsync;
    persistence.persistNewStateAsync = async function (docs) { await persist.call(this, docs); throw new Error("injected failure after append"); };
    return original.call(this, query, value, options).finally(function () { persistence.persistNewStateAsync = persist; });
  };
  t.after(function () { Datastore.prototype.updateAsync = original; });
  var args = { databaseId: db.id, expectedDatabaseRevision: db.revision, sourceNamespace: "synthetic", rows: [row("one", { fld_title00: "One" })], operationId: op() };
  await assert.rejects(s.importRecords(args), /injected failure after append/);
  var retried = await s.importRecords(args); assert.equal(retried.createdCount, 1); assert.equal(retried.databaseRevision, db.revision + 1); assert.equal(retried.projectionPending, true);
  assert.equal((await s.query({ databaseId: db.id })).totals.count, 1); assert.equal((await s.readImportProgress({ databaseId: db.id, sourceNamespace: "synthetic" })).total, 1);
  assert.equal(summaries, 1); await s.retryProjection({ databaseId: db.id }); assert.equal(summaries, 2);
  var writes = 0; Datastore.prototype.updateAsync = function (query, value, options) { if (this.filename === f.filename) writes++; return original.call(this, query, value, options); };
  var batch = []; for (var i = 0; i < 100; i++) batch.push(row("batch-" + i, { fld_title00: "Batch " + i }));
  var added = await request(s, db, batch); assert.equal(added.createdCount, 100); assert.equal(writes, 2); assert.equal(summaries, 3); assert.equal(added.projectionPending, false);
  await request(s, db, batch); assert.equal(writes, 3); assert.equal(summaries, 3);
});

test("imports serialize revision checks, snapshot input, separate namespaces and reject operation reuse", async function (t) {
  var f = fixture(t); var s = f.service; var db = await database(s, "Concurrency");
  var args = { databaseId: db.id, expectedDatabaseRevision: 1, sourceNamespace: "first-source", rows: [row("key", { fld_title00: "Original" })], operationId: op() };
  var pending = s.importRecords(args); args.rows[0].values.fld_title00 = "Caller changed input";
  var competing = s.importRecords({ databaseId: db.id, expectedDatabaseRevision: 1, sourceNamespace: "second-source", rows: [row("key", { fld_title00: "Competing" })], operationId: op() });
  var results = await Promise.allSettled([pending, competing]); assert.equal(results[0].status, "fulfilled"); assert.equal(results[1].reason.code, "STALE");
  var first = results[0].value; assert.equal((await s.readRecord({ databaseId: db.id, recordId: first.mappings[0].recordId })).record.values.fld_title00, "Original");
  await rejects(function () { return s.importRecords(args); }, "IDEMPOTENCY_MISMATCH");
  var replayArgs = { databaseId: db.id, expectedDatabaseRevision: 2, sourceNamespace: "first-source", rows: [row("key", { fld_title00: "Original" })], operationId: op() };
  var replay = await s.importRecords(replayArgs); assert.equal(replay.createdCount, 0); assert.equal(replay.databaseRevision, 2);
  assert.deepEqual((await s.importRecords(replayArgs)).mappings, replay.mappings);
  replayArgs.rows.push(row("extra", { fld_title00: "Extra" }));
  await rejects(function () { return s.importRecords(replayArgs); }, "IDEMPOTENCY_MISMATCH");
  var second = await request(s, db, [row("key", { fld_title00: "Other source" })], "second-source"); assert.notEqual(second.mappings[0].recordId, first.mappings[0].recordId);
  var mixed = await request(s, db, [row("key", { fld_title00: "Original" }), row("new", { fld_title00: "New" })], "first-source"); assert.equal(mixed.createdCount, 1); assert.equal(mixed.replayedCount, 1); assert.equal(mixed.mappings[0].recordId, first.mappings[0].recordId);
  await rejects(function () { return request(s, db, [row("uncommitted", { fld_title00: "Uncommitted" }), row("key", { fld_title00: "Changed source" })], "first-source"); }, "IMPORT_SOURCE_CONFLICT");
  assert.equal((await s.query({ databaseId: db.id })).totals.count, 3); assert.equal((await s.readImportProgress({ databaseId: db.id, sourceNamespace: "first-source" })).total, 2);
  await rejects(function () { return request(s, db, [row("duplicate", { fld_title00: "A" }), row("duplicate", { fld_title00: "A" })]); }, "INVALID");
  await rejects(function () { return s.create({ name: "Name\n", operationId: op() }); }, "INVALID");
});