Search in sources :

Example 1 with Operation

use of io.debezium.data.Envelope.Operation in project debezium by debezium.

the class ReplicatorIT method shouldReplicateContent.

@Test
public void shouldReplicateContent() throws InterruptedException {
    Testing.Print.disable();
    // Update the configuration to add a collection filter ...
    useConfiguration(config.edit().with(MongoDbConnectorConfig.MAX_FAILED_CONNECTIONS, 1).with(MongoDbConnectorConfig.COLLECTION_WHITELIST, "dbA.contacts").build());
    TestHelper.cleanDatabase(primary, "dbA");
    // ------------------------------------------------------------------------------
    // ADD A DOCUMENT
    // ------------------------------------------------------------------------------
    // Add a document to the 'contacts' database ...
    primary.execute("shouldCreateContactsDatabase", mongo -> {
        Testing.debug("Populating the 'dbA.contacts' collection");
        // Create a database and a collection in that database ...
        MongoDatabase db = mongo.getDatabase("dbA");
        MongoCollection<Document> contacts = db.getCollection("contacts");
        InsertOneOptions insertOptions = new InsertOneOptions().bypassDocumentValidation(true);
        contacts.insertOne(Document.parse("{ \"name\":\"Jon Snow\"}"), insertOptions);
        assertThat(db.getCollection("contacts").count()).isEqualTo(1);
        // Read the collection to make sure we can find our document ...
        Bson filter = Filters.eq("name", "Jon Snow");
        FindIterable<Document> movieResults = db.getCollection("contacts").find(filter);
        try (MongoCursor<Document> cursor = movieResults.iterator()) {
            assertThat(cursor.tryNext().getString("name")).isEqualTo("Jon Snow");
            assertThat(cursor.tryNext()).isNull();
        }
        Testing.debug("Completed document to 'dbA.contacts' collection");
    });
    // Start the replicator ...
    List<SourceRecord> records = new LinkedList<>();
    Replicator replicator = new Replicator(context, replicaSet, records::add, (x) -> {
    });
    Thread thread = new Thread(replicator::run);
    thread.start();
    // Sleep for 2 seconds ...
    Thread.sleep(2000);
    // ------------------------------------------------------------------------------
    // ADD A SECOND DOCUMENT
    // ------------------------------------------------------------------------------
    // Add more documents to the 'contacts' database ...
    final Object[] expectedNames = { "Jon Snow", "Sally Hamm" };
    primary.execute("shouldCreateContactsDatabase", mongo -> {
        Testing.debug("Populating the 'dbA.contacts' collection");
        // Create a database and a collection in that database ...
        MongoDatabase db = mongo.getDatabase("dbA");
        MongoCollection<Document> contacts = db.getCollection("contacts");
        InsertOneOptions insertOptions = new InsertOneOptions().bypassDocumentValidation(true);
        contacts.insertOne(Document.parse("{ \"name\":\"Sally Hamm\"}"), insertOptions);
        assertThat(db.getCollection("contacts").count()).isEqualTo(2);
        // Read the collection to make sure we can find our documents ...
        FindIterable<Document> movieResults = db.getCollection("contacts").find();
        Set<String> foundNames = new HashSet<>();
        try (MongoCursor<Document> cursor = movieResults.iterator()) {
            while (cursor.hasNext()) {
                String name = cursor.next().getString("name");
                foundNames.add(name);
            }
        }
        assertThat(foundNames).containsOnly(expectedNames);
        Testing.debug("Completed document to 'dbA.contacts' collection");
    });
    // For for a minimum number of events or max time ...
    // both documents
    int numEventsExpected = 2;
    long stop = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(3);
    while (records.size() < numEventsExpected && System.currentTimeMillis() < stop) {
        Thread.sleep(100);
    }
    // ------------------------------------------------------------------------------
    // STOP REPLICATOR AND VERIFY WE FOUND A TOTAL OF 2 EVENTS
    // ------------------------------------------------------------------------------
    replicator.stop();
    // Verify each record is valid and that we found the two records we expect ...
    final Set<String> foundNames = new HashSet<>();
    records.forEach(record -> {
        VerifyRecord.isValid(record);
        Struct value = (Struct) record.value();
        String after = value.getString("after");
        Document afterDoc = Document.parse(after);
        foundNames.add(afterDoc.getString("name"));
        Operation op = Operation.forCode(value.getString("op"));
        assertThat(op == Operation.READ || op == Operation.CREATE).isTrue();
    });
    assertThat(records.size()).isEqualTo(2);
    assertThat(foundNames).containsOnly(expectedNames);
    // ------------------------------------------------------------------------------
    // RESTART REPLICATOR FROM SAME POSITON
    // ------------------------------------------------------------------------------
    reuseConfiguration(config);
    // Start the replicator again ...
    records = new LinkedList<>();
    replicator = new Replicator(context, replicaSet, records::add, (x) -> {
    });
    thread = new Thread(replicator::run);
    thread.start();
    // Sleep for 2 seconds ...
    Thread.sleep(2000);
    // Stop the replicator ...
    replicator.stop();
    // We should not have found any new records ...
    records.forEach(record -> {
        VerifyRecord.isValid(record);
    });
    assertThat(records.isEmpty()).isTrue();
    // ------------------------------------------------------------------------------
    // START REPLICATOR AND ALSO REMOVE A DOCUMENT
    // ------------------------------------------------------------------------------
    // Update the configuration and don't use a collection filter ...
    reuseConfiguration(config.edit().with(MongoDbConnectorConfig.MAX_FAILED_CONNECTIONS, 1).build());
    // Start the replicator again ...
    records = new LinkedList<>();
    replicator = new Replicator(context, replicaSet, records::add, (x) -> {
    });
    thread = new Thread(replicator::run);
    thread.start();
    // Sleep for 2 seconds ...
    Thread.sleep(2000);
    // Remove Jon Snow ...
    AtomicReference<ObjectId> jonSnowId = new AtomicReference<>();
    primary.execute("removeJonSnow", mongo -> {
        MongoDatabase db = mongo.getDatabase("dbA");
        MongoCollection<Document> contacts = db.getCollection("contacts");
        // Read the collection to make sure we can find our document ...
        Bson filter = Filters.eq("name", "Jon Snow");
        FindIterable<Document> movieResults = db.getCollection("contacts").find(filter);
        try (MongoCursor<Document> cursor = movieResults.iterator()) {
            Document doc = cursor.tryNext();
            assertThat(doc.getString("name")).isEqualTo("Jon Snow");
            assertThat(cursor.tryNext()).isNull();
            jonSnowId.set(doc.getObjectId("_id"));
            assertThat(jonSnowId.get()).isNotNull();
        }
        // Remove the document by filter ...
        contacts.deleteOne(Filters.eq("name", "Jon Snow"));
        Testing.debug("Removed the Jon Snow document from 'dbA.contacts' collection");
    });
    // For for a minimum number of events or max time ...
    // just one delete event
    numEventsExpected = 1;
    stop = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(3);
    while (records.size() < numEventsExpected && System.currentTimeMillis() < stop) {
        Thread.sleep(100);
    }
    // Stop the replicator ...
    replicator.stop();
    // Verify each record is valid and that we found the one new DELETE record we expect ...
    Set<ObjectId> foundIds = new HashSet<>();
    records.forEach(record -> {
        VerifyRecord.isValid(record);
        Struct key = (Struct) record.key();
        ObjectId id = (ObjectId) (JSON.parse(key.getString("id")));
        foundIds.add(id);
        if (record.value() != null) {
            Struct value = (Struct) record.value();
            Operation op = Operation.forCode(value.getString("op"));
            assertThat(op).isEqualTo(Operation.DELETE);
        }
    });
    // 1 delete and 1 tombstone
    assertThat(records.size()).isEqualTo(2);
    // ------------------------------------------------------------------------------
    // START REPLICATOR TO PERFORM SNAPSHOT
    // ------------------------------------------------------------------------------
    // Update the configuration and don't use a collection filter ...
    useConfiguration(config);
    // Start the replicator again ...
    records = new LinkedList<>();
    replicator = new Replicator(context, replicaSet, records::add, (x) -> {
    });
    thread = new Thread(replicator::run);
    thread.start();
    // Sleep for 2 seconds ...
    Thread.sleep(2000);
    // Stop the replicator ...
    replicator.stop();
    // Verify each record is valid and that we found the two records we expect ...
    foundNames.clear();
    records.forEach(record -> {
        VerifyRecord.isValid(record);
        Struct value = (Struct) record.value();
        String after = value.getString("after");
        Document afterDoc = Document.parse(after);
        foundNames.add(afterDoc.getString("name"));
        Operation op = Operation.forCode(value.getString("op"));
        assertThat(op).isEqualTo(Operation.READ);
    });
    // We should not have found any new records ...
    assertThat(records.size()).isEqualTo(1);
    Object[] allExpectedNames = { "Sally Hamm" };
    assertThat(foundNames).containsOnly(allExpectedNames);
}
Also used : Document(org.bson.Document) MongoCollection(com.mongodb.client.MongoCollection) Set(java.util.Set) Test(org.junit.Test) MongoDatabase(com.mongodb.client.MongoDatabase) AtomicReference(java.util.concurrent.atomic.AtomicReference) SourceRecord(org.apache.kafka.connect.source.SourceRecord) HashSet(java.util.HashSet) TimeUnit(java.util.concurrent.TimeUnit) Bson(org.bson.conversions.Bson) Filters(com.mongodb.client.model.Filters) Operation(io.debezium.data.Envelope.Operation) List(java.util.List) Testing(io.debezium.util.Testing) Assertions.assertThat(org.fest.assertions.Assertions.assertThat) MongoCursor(com.mongodb.client.MongoCursor) FindIterable(com.mongodb.client.FindIterable) Struct(org.apache.kafka.connect.data.Struct) ObjectId(org.bson.types.ObjectId) JSON(com.mongodb.util.JSON) InsertOneOptions(com.mongodb.client.model.InsertOneOptions) VerifyRecord(io.debezium.data.VerifyRecord) LinkedList(java.util.LinkedList) InsertOneOptions(com.mongodb.client.model.InsertOneOptions) Operation(io.debezium.data.Envelope.Operation) Document(org.bson.Document) SourceRecord(org.apache.kafka.connect.source.SourceRecord) Bson(org.bson.conversions.Bson) Struct(org.apache.kafka.connect.data.Struct) MongoDatabase(com.mongodb.client.MongoDatabase) HashSet(java.util.HashSet) ObjectId(org.bson.types.ObjectId) AtomicReference(java.util.concurrent.atomic.AtomicReference) LinkedList(java.util.LinkedList) Test(org.junit.Test)

Aggregations

FindIterable (com.mongodb.client.FindIterable)1 MongoCollection (com.mongodb.client.MongoCollection)1 MongoCursor (com.mongodb.client.MongoCursor)1 MongoDatabase (com.mongodb.client.MongoDatabase)1 Filters (com.mongodb.client.model.Filters)1 InsertOneOptions (com.mongodb.client.model.InsertOneOptions)1 JSON (com.mongodb.util.JSON)1 Operation (io.debezium.data.Envelope.Operation)1 VerifyRecord (io.debezium.data.VerifyRecord)1 Testing (io.debezium.util.Testing)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Set (java.util.Set)1 TimeUnit (java.util.concurrent.TimeUnit)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Struct (org.apache.kafka.connect.data.Struct)1 SourceRecord (org.apache.kafka.connect.source.SourceRecord)1 Document (org.bson.Document)1 Bson (org.bson.conversions.Bson)1