package org.apache.kafka.connect.mongodb; import com.mongodb.*; import com.mongodb.client.MongoDatabase; import de.flapdoodle.embed.mongo.MongodExecutable; import de.flapdoodle.embed.mongo.MongodProcess; import de.flapdoodle.embed.mongo.MongodStarter; import de.flapdoodle.embed.mongo.config.IMongodConfig; import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; import de.flapdoodle.embed.mongo.config.Net; import de.flapdoodle.embed.mongo.config.Storage; import de.flapdoodle.embed.mongo.distribution.Version; import de.flapdoodle.embed.process.runtime.Network; import junit.framework.TestCase; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.kafka.connect.source.SourceRecord; import org.apache.kafka.connect.source.SourceTaskContext; import org.apache.kafka.connect.storage.OffsetStorageReader; import org.bson.Document; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Test; import org.powermock.api.easymock.PowerMock; import java.io.File; import java.util.*; /** * @author Andrea Patelli */ public class MongodbSourceTaskTest extends TestCase { private static String REPLICATION_PATH = "/tmp/mongo"; private MongodbSourceTask task; private SourceTaskContext context; private OffsetStorageReader offsetStorageReader; private Map<String, String> sourceProperties; private MongodExecutable mongodExecutable; private MongodProcess mongod; private MongodStarter mongodStarter; private IMongodConfig mongodConfig; private MongoClient mongoClient; private Map<String, Long> offsets; private long totalWrittenDocuments; private List<String> collections = new ArrayList<String>() {{ add("test1"); add("test2"); add("test3"); }}; @Override public void setUp() { offsets = new HashMap<>(); totalWrittenDocuments = 0; try { super.setUp(); mongodStarter = MongodStarter.getDefaultInstance(); mongodConfig = new MongodConfigBuilder() .version(Version.Main.V3_2) .replication(new Storage(REPLICATION_PATH, "rs0", 1024)) .net(new Net(12345, Network.localhostIsIPv6())) .build(); mongodExecutable = mongodStarter.prepare(mongodConfig); mongod = mongodExecutable.start(); mongoClient = new MongoClient(new ServerAddress("localhost", 12345)); MongoDatabase adminDatabase = mongoClient.getDatabase("admin"); BasicDBObject replicaSetSetting = new BasicDBObject(); replicaSetSetting.put("_id", "rs0"); BasicDBList members = new BasicDBList(); DBObject host = new BasicDBObject(); host.put("_id", 0); host.put("host", "127.0.0.1:12345"); members.add(host); replicaSetSetting.put("members", members); adminDatabase.runCommand(new BasicDBObject("isMaster", 1)); adminDatabase.runCommand(new BasicDBObject("replSetInitiate", replicaSetSetting)); MongoDatabase db = mongoClient.getDatabase("mydb"); db.createCollection("test1"); db.createCollection("test2"); db.createCollection("test3"); } catch (Exception e) { // Assert.assertTrue(false); } task = new MongodbSourceTask(); offsetStorageReader = PowerMock.createMock(OffsetStorageReader.class); context = PowerMock.createMock(SourceTaskContext.class); task.initialize(context); sourceProperties = new HashMap<>(); sourceProperties.put("host", "localhost"); sourceProperties.put("port", Integer.toString(12345)); sourceProperties.put("batch.size", Integer.toString(100)); sourceProperties.put("schema.name", "schema"); sourceProperties.put("topic.prefix", "prefix"); sourceProperties.put("databases", "mydb.test1,mydb.test2,mydb.test3"); } @Test public void testInsertWithNullOffsets() { try { expectOffsetLookupReturnNone(); replay(); task.start(sourceProperties); MongoDatabase db = mongoClient.getDatabase("mydb"); Integer numberOfDocuments = new Random().nextInt(new Random().nextInt(100000)); for (int i = 0; i < numberOfDocuments; i++) { Document newDocument = new Document() .append(RandomStringUtils.random(new Random().nextInt(100), true, false), new Random().nextInt()); db.getCollection(collections.get(new Random().nextInt(3))).insertOne(newDocument); } List<SourceRecord> records = new ArrayList<>(); List<SourceRecord> pollRecords; do { pollRecords = task.poll(); for(SourceRecord r : pollRecords) { records.add(r); offsets.putAll((Map<String, Long>)r.sourceOffset()); } } while (!pollRecords.isEmpty()); totalWrittenDocuments += records.size(); Assert.assertEquals(totalWrittenDocuments, records.size()); } catch (Exception e) { System.out.println("------------------------EXCEPTION-------------------------"); e.printStackTrace(); Assert.assertTrue(false); System.out.println("---------------------------END----------------------------"); } } @Test public void testInsertWithOffsets() { try { expectOffsetLookupReturnOffset(collections); replay(); task.start(sourceProperties); MongoDatabase db = mongoClient.getDatabase("mydb"); Integer numberOfDocuments = new Random().nextInt(new Random().nextInt(100000)); for (int i = 0; i < numberOfDocuments; i++) { Document newDocument = new Document() .append(RandomStringUtils.random(new Random().nextInt(100), true, false), new Random().nextInt()); db.getCollection(collections.get(new Random().nextInt(3))).insertOne(newDocument); } List<SourceRecord> records = new ArrayList<>(); List<SourceRecord> pollRecords; do { pollRecords = task.poll(); for(SourceRecord r : pollRecords) { records.add(r); offsets.putAll((Map<String, Long>)r.sourceOffset()); } } while (!pollRecords.isEmpty()); totalWrittenDocuments += records.size(); Assert.assertEquals(totalWrittenDocuments, records.size()); } catch (Exception e) { System.out.println("------------------------EXCEPTION-------------------------"); e.printStackTrace(); Assert.assertTrue(false); System.out.println("---------------------------END----------------------------"); } } @Override public void tearDown() { try { super.tearDown(); mongod.stop(); mongodExecutable.stop(); System.out.println("DELETING OPLOG"); FileUtils.deleteDirectory(new File(REPLICATION_PATH)); } catch (Exception e) { } } private void replay() { PowerMock.replayAll(); } private void expectOffsetLookupReturnNone() { EasyMock.expect(context.offsetStorageReader()).andReturn(offsetStorageReader); EasyMock.expect(offsetStorageReader.offsets(EasyMock.anyObject(List.class))).andReturn(new HashMap<Map<String, String>, Map<String, Object>>(0)); } private void expectOffsetLookupReturnOffset(List<String> databases) { Map<Map<String, String>, Map<String, Long>> offsetMap = new HashMap<>(); for (int i = 0; i < databases.size(); i++) { offsetMap.put( Collections.singletonMap("mongodb", databases.get(i)), Collections.singletonMap(databases.get(i), offsets.get(databases.get(i))) ); } EasyMock.expect(context.offsetStorageReader()).andReturn(offsetStorageReader); EasyMock.expect(offsetStorageReader.offsets(EasyMock.anyObject(List.class))).andReturn(offsetMap); } }