Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,14 @@ import com.mongodb.stitch.core.admin.Apps
import com.mongodb.stitch.core.admin.apps.AppResponse
import com.mongodb.stitch.core.admin.userRegistrations.sendConfirmation
import com.mongodb.stitch.core.auth.providers.userpassword.UserPasswordCredential
import com.mongodb.stitch.core.internal.net.NetworkMonitor
import com.mongodb.stitch.core.testutils.BaseStitchIntTest
import org.junit.After
import org.junit.Before
import java.util.concurrent.CopyOnWriteArrayList

open class BaseStitchAndroidIntTest : BaseStitchIntTest() {

private var clients: MutableList<StitchAppClient> = mutableListOf()

class TestNetworkMonitor : NetworkMonitor {
private var _connectedState = false
var connectedState: Boolean
set(value) {
_connectedState = value
listeners.forEach { it.onNetworkStateChanged() }
}
get() = _connectedState

private var listeners = CopyOnWriteArrayList<NetworkMonitor.StateListener>()

override fun isConnected(): Boolean {
return connectedState
}

override fun addNetworkStateListener(listener: NetworkMonitor.StateListener) {
listeners.add(listener)
}

override fun removeNetworkStateListener(listener: NetworkMonitor.StateListener) {
listeners.remove(listener)
}
}
companion object {
val testNetworkMonitor = TestNetworkMonitor()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ private StitchEvent(final String eventName,
final String data,
final Decoder<T> decoder) {
this.eventName = eventName;
if (data == null) {
this.data = null;
this.error = null;
return;
}

final StringBuilder decodedStringBuilder = new StringBuilder(data.length());
for (int chIdx = 0; chIdx < data.length(); chIdx++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ static BsonDocument toBsonDocument(final ChangeEvent<BsonDocument> value) {
removedFields);
asDoc.put(ChangeEventCoder.Fields.UPDATE_DESCRIPTION_FIELD, updateDescDoc);
}
asDoc.put(ChangeEventCoder.Fields.WRITE_PENDING_FIELD,
new BsonBoolean(value.hasUncommittedWrites));
return asDoc;
}

Expand Down Expand Up @@ -235,7 +237,7 @@ static ChangeEvent<BsonDocument> fromBsonDocument(final BsonDocument document) {
nsDoc.getString(ChangeEventCoder.Fields.NS_COLL_FIELD).getValue()),
document.getDocument(ChangeEventCoder.Fields.DOCUMENT_KEY_FIELD),
updateDescription,
nsDoc.getBoolean(
document.getBoolean(
ChangeEventCoder.Fields.WRITE_PENDING_FIELD,
BsonBoolean.FALSE).getValue());
}
Expand Down Expand Up @@ -303,7 +305,7 @@ private static final class Fields {
static final String UPDATE_DESCRIPTION_UPDATED_FIELDS_FIELD = "updatedFields";
static final String UPDATE_DESCRIPTION_REMOVED_FIELDS_FIELD = "removedFields";

static final String WRITE_PENDING_FIELD = "write_pending";
static final String WRITE_PENDING_FIELD = "writePending";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ public void swapSyncDirection(final boolean localToRemoteFirst) {
* @return whether or not the synchronization pass was successful.
*/
public boolean doSyncPass() {
if (!syncLock.tryLock()) {
if (!this.isConfigured || !syncLock.tryLock()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[q] is this what you think might solve the flakiness we're seeing in the configure test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is actually how the method should function. I don't believe this will solve any races.

return false;
}
try {
Expand Down Expand Up @@ -402,7 +402,7 @@ private void syncRemoteToLocal() {
// 2. Run remote to local (R2L) sync routine
for (final NamespaceSynchronizationConfig nsConfig : syncConfig) {
final Map<BsonValue, ChangeEvent<BsonDocument>> remoteChangeEvents =
instanceChangeStreamListener.getEventsForNamespace(nsConfig.getNamespace());
getEventsForNamespace(nsConfig.getNamespace());

final Set<BsonValue> unseenIds = nsConfig.getStaleDocumentIds();
final Set<BsonDocument> latestDocumentsFromStale =
Expand Down Expand Up @@ -1408,6 +1408,10 @@ public void removeWatcher(final MongoNamespace namespace,
instanceChangeStreamListener.removeWatcher(namespace, watcher);
}

Map<BsonValue, ChangeEvent<BsonDocument>> getEventsForNamespace(final MongoNamespace namespace) {
return instanceChangeStreamListener.getEventsForNamespace(namespace);
}

// ----- CRUD operations -----

/**
Expand Down Expand Up @@ -1744,7 +1748,7 @@ private void deleteOneFromRemote(
emitEvent(documentId, changeEventForLocalDelete(namespace, documentId, false));
}

void triggerListeningToNamespace(final MongoNamespace namespace) {
private void triggerListeningToNamespace(final MongoNamespace namespace) {
syncLock.lock();
try {
final NamespaceSynchronizationConfig nsConfig = this.syncConfig.getNamespaceConfig(namespace);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.mongodb.stitch.core.services.mongodb.remote.sync.internal

import com.mongodb.MongoNamespace
import org.bson.BsonArray
import org.bson.BsonBoolean
import org.bson.BsonDocument
import org.bson.BsonObjectId
import org.bson.BsonString
import org.junit.Assert.assertEquals
import org.junit.Test

class ChangeEventUnitTests {
private val namespace = MongoNamespace("foo", "bar")

@Test
fun testNew() {
val expectedFullDocument = BsonDocument("foo", BsonString("bar")).append("_id", BsonObjectId())
val expectedId = BsonDocument("_id", expectedFullDocument["_id"])
val expectedOperationType = ChangeEvent.OperationType.INSERT
val expectedNamespace = namespace
val expectedDocumentKey = BsonDocument("_id", expectedFullDocument["_id"])
val expectedUpdateDescription = ChangeEvent.UpdateDescription(
BsonDocument("foo", BsonString("bar")),
listOf("baz"))

val changeEvent = ChangeEvent(
expectedId,
expectedOperationType,
expectedFullDocument,
expectedNamespace,
expectedDocumentKey,
expectedUpdateDescription,
true
)

assertEquals(expectedId, changeEvent.id)
assertEquals(expectedOperationType, changeEvent.operationType)
assertEquals(expectedFullDocument, changeEvent.fullDocument)
assertEquals(expectedNamespace, changeEvent.namespace)
assertEquals(expectedDocumentKey, changeEvent.documentKey)
assertEquals(expectedUpdateDescription, changeEvent.updateDescription)
assertEquals(true, changeEvent.hasUncommittedWrites())
}

@Test
fun testOperationTypeFromRemote() {
assertEquals(
ChangeEvent.OperationType.INSERT,
ChangeEvent.OperationType.fromRemote("insert"))

assertEquals(
ChangeEvent.OperationType.UPDATE,
ChangeEvent.OperationType.fromRemote("update"))

assertEquals(
ChangeEvent.OperationType.REPLACE,
ChangeEvent.OperationType.fromRemote("replace"))

assertEquals(
ChangeEvent.OperationType.DELETE,
ChangeEvent.OperationType.fromRemote("delete"))

assertEquals(
ChangeEvent.OperationType.UNKNOWN,
ChangeEvent.OperationType.fromRemote("bad"))
}

@Test
fun testOperationTypeToRemote() {
assertEquals("insert", ChangeEvent.OperationType.INSERT.toRemote())
assertEquals("update", ChangeEvent.OperationType.UPDATE.toRemote())
assertEquals("replace", ChangeEvent.OperationType.REPLACE.toRemote())
assertEquals("delete", ChangeEvent.OperationType.DELETE.toRemote())
assertEquals("unknown", ChangeEvent.OperationType.UNKNOWN.toRemote())
}

@Test
fun testToBsonDocumentRoundTrip() {
val expectedFullDocument = BsonDocument("foo", BsonString("bar")).append("_id", BsonObjectId())
val expectedId = BsonDocument("_id", expectedFullDocument["_id"])
val expectedOperationType = ChangeEvent.OperationType.INSERT
val expectedNamespace = namespace
val expectedDocumentKey = BsonDocument("_id", expectedFullDocument["_id"])
val expectedUpdateDescription = ChangeEvent.UpdateDescription(
BsonDocument("foo", BsonString("bar")),
listOf("baz"))

val changeEvent = ChangeEvent(
expectedId,
expectedOperationType,
expectedFullDocument,
expectedNamespace,
expectedDocumentKey,
expectedUpdateDescription,
true)

val changeEventDocument = ChangeEvent.toBsonDocument(changeEvent)

assertEquals(expectedFullDocument, changeEventDocument["fullDocument"])
assertEquals(expectedId, changeEventDocument["_id"])
assertEquals(BsonString(expectedOperationType.toRemote()), changeEventDocument["operationType"])
assertEquals(
BsonDocument("db", BsonString(namespace.databaseName))
.append("coll", BsonString(namespace.collectionName)),
changeEventDocument["ns"])
assertEquals(expectedDocumentKey, changeEventDocument["documentKey"])
assertEquals(
BsonDocument("updatedFields", expectedUpdateDescription.updatedFields)
.append("removedFields", BsonArray(expectedUpdateDescription.removedFields.map { BsonString(it) })),
changeEventDocument["updateDescription"])
assertEquals(BsonBoolean(true), changeEventDocument["writePending"])

val changeEventFromDocument = ChangeEvent.fromBsonDocument(changeEventDocument)

assertEquals(expectedFullDocument, changeEventFromDocument.fullDocument)
assertEquals(expectedId, changeEventFromDocument.id)
assertEquals(expectedOperationType, changeEventFromDocument.operationType)
assertEquals(expectedDocumentKey, changeEventFromDocument.documentKey)
assertEquals(expectedUpdateDescription.updatedFields, changeEventFromDocument.updateDescription.updatedFields)
assertEquals(expectedUpdateDescription.removedFields, changeEventFromDocument.updateDescription.removedFields)
assertEquals(true, changeEventFromDocument.hasUncommittedWrites())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import com.mongodb.stitch.core.StitchAppClientInfo
import com.mongodb.stitch.core.internal.common.AuthMonitor
import com.mongodb.stitch.core.internal.common.BsonUtils
import com.mongodb.stitch.core.internal.net.NetworkMonitor
import com.mongodb.stitch.core.services.mongodb.remote.sync.internal.SyncUnitTestHarness.Companion.compareEvents
import com.mongodb.stitch.server.services.mongodb.local.internal.ServerEmbeddedMongoClientFactory
import org.bson.BsonDocument
import org.bson.BsonObjectId
import org.bson.BsonString
import org.bson.codecs.configuration.CodecRegistries
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Test

Expand Down Expand Up @@ -76,36 +77,36 @@ class CoreDocumentSynchronizationConfigUnitTests {
}

@Test
fun testStaleAndFrozen() {
fun testToBsonDocumentRoundTrip() {
var config = CoreDocumentSynchronizationConfig(coll, namespace, id)
coll.insertOne(config)

assertFalse(config.isStale)

config.isStale = true
val expectedTestVersion = BsonDocument("dummy", BsonString("version"))
val expectedEvent = ChangeEvent.changeEventForLocalDelete(namespace, id, false)
config.setSomePendingWrites(
1,
expectedTestVersion,
expectedEvent)
config.isFrozen = true
config.isStale = true

var doc = config.toBsonDocument()
val doc = config.toBsonDocument()

assertEquals(id, doc[CoreDocumentSynchronizationConfig.ConfigCodec.Fields.DOCUMENT_ID_FIELD])

assertTrue(doc.getBoolean(CoreDocumentSynchronizationConfig.ConfigCodec.Fields.IS_STALE).value)
assertTrue(doc.getBoolean(CoreDocumentSynchronizationConfig.ConfigCodec.Fields.IS_FROZEN).value)
assertEquals(expectedTestVersion,
doc[CoreDocumentSynchronizationConfig.ConfigCodec.Fields.LAST_KNOWN_REMOTE_VERSION_FIELD])
assertEquals(
BsonString("${namespace.databaseName}.${namespace.collectionName}"),
doc[CoreDocumentSynchronizationConfig.ConfigCodec.Fields.NAMESPACE_FIELD])
assertNotNull(doc[CoreDocumentSynchronizationConfig.ConfigCodec.Fields.LAST_UNCOMMITTED_CHANGE_EVENT])

config = CoreDocumentSynchronizationConfig(
coll, CoreDocumentSynchronizationConfig.fromBsonDocument(doc))

assertTrue(config.isStale)

config.isStale = false
config.setSomePendingWrites(
1,
ChangeEvent.changeEventForLocalInsert(
coll.namespace, BsonDocument("_id", BsonObjectId()), true))
config = CoreDocumentSynchronizationConfig.fromBsonDocument(doc)

doc = config.toBsonDocument()
// should be stale from set some pending writes
assertTrue(
doc.getBoolean(CoreDocumentSynchronizationConfig.ConfigCodec.Fields.IS_STALE).value)
assertFalse(
doc.getBoolean(CoreDocumentSynchronizationConfig.ConfigCodec.Fields.IS_FROZEN).value)
assertTrue(config.isFrozen)
assertEquals(namespace, config.namespace)
assertEquals(expectedTestVersion, config.lastKnownRemoteVersion)
compareEvents(expectedEvent, config.lastUncommittedChangeEvent)
assertEquals(id, config.documentId)
}
}
Loading