예제 #1
0
        public void SynchronizeAction_LFDataChanged_GlossChanged()
        {
            // Setup
            TestEnvironment.CopyFwProjectTo(testProjectCode, _lDSettings.WebWorkDirectory);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);
            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry        = originalMongoData.First(e => e.Guid == _testEntryGuid);
            string     unchangedGloss = lfEntry.Senses[0].Gloss["en"].Value;
            string     lfChangedGloss = unchangedGloss + " - changed in LF";

            lfEntry.Senses[0].Gloss["en"].Value = lfChangedGloss;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry, Is.Not.Null);
            Assert.That(lDFdoEntry.SensesOS.Count, Is.EqualTo(2));
            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(unchangedGloss));

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);

            sutSynchronize.Run(_lfProject);

            // Verify
            Assert.That(GetGlossFromFdo(_testEntryGuid, 2), Is.EqualTo(lfChangedGloss));
            Assert.That(GetGlossFromMongoDb(_testEntryGuid, expectedDeletedEntries: 0),
                        Is.EqualTo(lfChangedGloss));
            Assert.That(GetGlossFromLanguageDepot(_testEntryGuid, 2), Is.EqualTo(lfChangedGloss));
        }
예제 #2
0
        public void SynchronizeAction_LFDataDeleted_EntryRemoved()
        {
            // Setup
            TestEnvironment.CopyFwProjectTo(testProjectCode, _lDSettings.WebWorkDirectory);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry = originalMongoData.First(e => e.Guid == _testEntryGuid);
            DateTime   originalLfDateModified = lfEntry.DateModified;

            string unchangedGloss = lfEntry.Senses[0].Gloss["en"].Value;

            // Don't use _mongoConnection.RemoveRecord to delete the entry.  LF uses the "IsDeleted" field
            lfEntry.IsDeleted = true;
            // The LF PHP code would have updated DateModified when it deleted the record, so simulate that here
            lfEntry.DateModified = DateTime.UtcNow;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);
            IEnumerable <LfLexEntry> updatedMongoData = _mongoConnection.GetLfLexEntries();

            Assert.That(updatedMongoData.First(e => e.Guid == _testEntryGuid).IsDeleted, Is.True);

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(unchangedGloss));
            DateTime originalLdDateModified = lDFdoEntry.DateModified;

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify
            IEnumerable <LfLexEntry> receivedMongoData = _mongoConnection.GetLfLexEntries();

            Assert.That(receivedMongoData, Is.Not.Null);
            Assert.That(receivedMongoData, Is.Not.Empty);
            // Deleting entries in LF should *not* remove them, just set the isDeleted flag
            Assert.That(receivedMongoData.Count(), Is.EqualTo(originalNumOfFdoEntries));
            var entry = receivedMongoData.FirstOrDefault(e => e.Guid == _testEntryGuid);

            Assert.That(entry, Is.Not.Null);
            Assert.That(entry.IsDeleted, Is.EqualTo(true));
            DateTime updatedLfDateModified = entry.DateModified;

            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLfDateModified));
            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLdDateModified));

            var cache = _lfProject.FieldWorksProject.Cache;

            Assert.That(() => cache.ServiceLocator.GetObject(_testEntryGuid),
                        Throws.InstanceOf <KeyNotFoundException>());
            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
예제 #3
0
        public void SynchronizeAction_LFEntryDeletedLDDataChanged_LDWins()
        {
            // Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry = originalMongoData.First(e => e.Guid == _testEntryGuid);
            DateTime   originalLfDateModified = lfEntry.DateModified;

            string unchangedGloss = lfEntry.Senses[0].Gloss["en"].Value;
            string fwChangedGloss = unchangedGloss + " - changed in FW";

            // Don't use _mongoConnection.RemoveRecord to delete the entry.  LF uses the "IsDeleted" field
            lfEntry.IsDeleted = true;
            var modificationTimestamp = DateTime.UtcNow;

            lfEntry.AuthorInfo.ModifiedDate = modificationTimestamp;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);
            IEnumerable <LfLexEntry> updatedMongoData = _mongoConnection.GetLfLexEntries();

            Assert.That(updatedMongoData.Count(), Is.EqualTo(originalNumOfFdoEntries));
            Assert.That(updatedMongoData.First(e => e.Guid == _testEntryGuid).IsDeleted, Is.True);

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(fwChangedGloss));
            DateTime originalLdDateModified = lDFdoEntry.DateModified;

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify LD modified entry remains and LF marks not deleted
            Assert.That(GetGlossFromMongoDb(_testEntryGuid), Is.EqualTo(fwChangedGloss));
            Assert.That(GetGlossFromLanguageDepot(_testEntryGuid, 2), Is.EqualTo(fwChangedGloss));
            LfLexEntry updatedLfEntry = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);

            Assert.That(updatedLfEntry.IsDeleted, Is.False);
            DateTime updatedLfDateModified = updatedLfEntry.DateModified;

            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLfDateModified));
            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLdDateModified));
            Assert.That(updatedLfDateModified, Is.GreaterThan(modificationTimestamp));
            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
예제 #4
0
        public void SynchronizeAction_LFDataChangedLDEntryDeleted_LFWins()
        {
            // Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry = originalMongoData.First(e => e.Guid == _testDeletedEntryGuid);
            DateTime   originalLfDateModified = lfEntry.DateModified;

            Assert.That(lfEntry.Senses.Count, Is.EqualTo(1));
            const string lfCreatedGloss = "new English gloss - added in LF";
            const string fwChangedGloss = "English gloss - changed in FW";

            // LF adds a gloss to the entry that LD is deleting
            lfEntry.Senses[0].Gloss         = LfMultiText.FromSingleStringMapping("en", lfCreatedGloss);
            lfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache = _lDProject.FieldWorksProject.Cache;

            Assert.That(() => lDcache.ServiceLocator.GetObject(_testDeletedEntryGuid),
                        Throws.InstanceOf <KeyNotFoundException>());
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(fwChangedGloss));
            DateTime originalLdDateModified = lDFdoEntry.DateModified;

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify modified LF entry wins
            Assert.That(GetGlossFromMongoDb(_testDeletedEntryGuid, originalNumOfFdoEntries + 1, 0),
                        Is.EqualTo(lfCreatedGloss));
            Assert.That(GetGlossFromMongoDb(_testEntryGuid, originalNumOfFdoEntries + 1, 0),
                        Is.EqualTo(fwChangedGloss));
            Assert.That(GetGlossFromLanguageDepot(_testDeletedEntryGuid, 1), Is.EqualTo(lfCreatedGloss));
            LfLexEntry updatedLfEntry        = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);
            DateTime   updatedLfDateModified = updatedLfEntry.DateModified;

            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLfDateModified));
            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLdDateModified));
            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
예제 #5
0
 public void Teardown()
 {
     if (_lfProject != null)
     {
         LanguageForgeProject.DisposeFwProject(_lfProject);
     }
     if (_lDProject != null)
     {
         LanguageDepotMock.DisposeFwProject(_lDProject);
     }
     _languageDepotFolder?.Dispose();
     _env.Dispose();
     _mongoConnection.Reset();
 }
예제 #6
0
        public void SynchronizeAction_LFDataChangedLDDataChanged_LFWins()
        {
            //Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry = originalMongoData.First(e => e.Guid == _testEntryGuid);
            DateTime   originalLfDateModified           = lfEntry.DateModified;
            DateTime   originalLfAuthorInfoModifiedDate = lfEntry.AuthorInfo.ModifiedDate;

            string unchangedGloss = lfEntry.Senses[0].Gloss["en"].Value;
            string fwChangedGloss = unchangedGloss + " - changed in FW";
            string lfChangedGloss = unchangedGloss + " - changed in LF";

            lfEntry.Senses[0].Gloss["en"].Value = lfChangedGloss;
            lfEntry.AuthorInfo.ModifiedDate     = DateTime.UtcNow;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(fwChangedGloss));
            DateTime originalLdDateModified = lDFdoEntry.DateModified;

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify
            Assert.That(GetGlossFromMongoDb(_testEntryGuid), Is.EqualTo(lfChangedGloss));
            LfLexEntry updatedLfEntry                  = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);
            DateTime   updatedLfDateModified           = updatedLfEntry.DateModified;
            DateTime   updatedLfAuthorInfoModifiedDate = updatedLfEntry.AuthorInfo.ModifiedDate;

            // LF had the same data previously; however it's a merge conflict so DateModified
            // got updated
            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLfDateModified));
            // But the FDO modified date (AuthorInfo.ModifiedDate in LF) should be updated.
            Assert.That(updatedLfAuthorInfoModifiedDate, Is.GreaterThan(originalLfAuthorInfoModifiedDate));
            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLdDateModified));
            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
예제 #7
0
        public void SynchronizeAction_LDDataChanged_GlossChanged()
        {
            // Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);
            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry        = originalMongoData.First(e => e.Guid == _testEntryGuid);
            string     unchangedGloss = lfEntry.Senses[0].Gloss["en"].Value;
            string     ldChangedGloss = unchangedGloss + " - changed in FW";

            lfEntry = originalMongoData.First(e => e.Guid == _testDeletedEntryGuid);
            Assert.That(lfEntry.Lexeme["qaa-x-kal"].Value, Is.EqualTo("ken"));

            int createdEntryCount = originalMongoData.Count(e => e.Guid == _testCreatedEntryGuid);

            Assert.That(createdEntryCount, Is.EqualTo(0));

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(ldChangedGloss));

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);

            sutSynchronize.Run(_lfProject);

            // Verify
            Assert.That(GetGlossFromFdo(_testEntryGuid, 2), Is.EqualTo(ldChangedGloss));
            Assert.That(GetGlossFromMongoDb(_testEntryGuid), Is.EqualTo(ldChangedGloss));

            IEnumerable <LfLexEntry> receivedMongoData = _mongoConnection.GetLfLexEntries();

            lfEntry = receivedMongoData.First(e => e.Guid == _testCreatedEntryGuid);
            Assert.That(lfEntry.Lexeme["qaa-x-kal"].Value, Is.EqualTo("Ira"));

            int deletedEntryCount = receivedMongoData.Count(e => e.Guid == _testDeletedEntryGuid && !e.IsDeleted);

            Assert.That(deletedEntryCount, Is.EqualTo(0));

            Assert.That(GetGlossFromLanguageDepot(_testEntryGuid, 2), Is.EqualTo(ldChangedGloss));
        }
예제 #8
0
        public void SynchronizeAction_LFDataChangedLDOtherDataChanged_ModifiedDateUpdated()
        {
            //Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            var lfEntry = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);
            var originalLfDateModified           = lfEntry.DateModified;
            var originalLfAuthorInfoModifiedDate = lfEntry.AuthorInfo.ModifiedDate;

            lfEntry.Note = LfMultiText.FromSingleStringMapping("en", "A note from LF");
            lfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            var fwChangedGloss = lfEntry.Senses[0].Gloss["en"].Value + " - changed in FW";

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(fwChangedGloss));

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify
            Assert.That(GetGlossFromMongoDb(_testEntryGuid), Is.EqualTo(fwChangedGloss));
            var updatedLfEntry = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);

            // LF and LD changed the same entry but different fields, so we want to see the
            // DateModified change so that LF will re-process the entry.
            Assert.That(updatedLfEntry.DateModified, Is.GreaterThan(originalLfDateModified));
            // The FDO modified date (AuthorInfo.ModifiedDate in LF) should be updated.
            Assert.That(updatedLfEntry.AuthorInfo.ModifiedDate, Is.GreaterThan(originalLfAuthorInfoModifiedDate));

            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
예제 #9
0
        public void SynchronizeAction_LFDataDeletedLDDataChanged_LDWins()
        {
            //Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            var lfEntry = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);
            var originalLfDateModified           = lfEntry.DateModified;
            var originalLfAuthorInfoModifiedDate = lfEntry.AuthorInfo.ModifiedDate;

            lfEntry.Senses.Remove(lfEntry.Senses[0]);
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            const string fwChangedGloss = "English gloss - changed in FW";

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(fwChangedGloss));

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify
            Assert.That(GetGlossFromMongoDb(_testEntryGuid), Is.EqualTo(fwChangedGloss));
            Assert.That(GetGlossFromLanguageDepot(_testEntryGuid, 2), Is.EqualTo(fwChangedGloss));
            var updatedLfEntry = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);

            Assert.That(updatedLfEntry.IsDeleted, Is.False);
            DateTime updatedLfDateModified = updatedLfEntry.DateModified;

            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLfDateModified));
            Assert.That(updatedLfDateModified, Is.GreaterThan(timeBeforeRun));
            Assert.That(updatedLfEntry.AuthorInfo.ModifiedDate, Is.GreaterThan(originalLfAuthorInfoModifiedDate));
            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
예제 #10
0
        public void SynchronizeAction_CustomReferenceAtomicField_DoesNotThrowExceptionDuringSync()
        {
            // Setup
            // Buggy code path needs us to change the field writing system to a "magic" ws (it's 0 in the original data/testlangproj project)
            var lcmMetaData  = _lfProject.FieldWorksProject.Cache.MetaDataCacheAccessor as SIL.LCModel.Infrastructure.IFwMetaDataCacheManaged;
            int listRef_flid = lcmMetaData.GetFieldIds().FirstOrDefault(flid => lcmMetaData.GetFieldLabel(flid) == "Cust Single ListRef");

            Assert.AreNotEqual(0, listRef_flid, "Cust Single ListRef field not found in test data");
            string fieldLabel = lcmMetaData.GetFieldLabel(listRef_flid);
            string fieldHelp  = lcmMetaData.GetFieldHelp(listRef_flid);
            int    wsid       = SIL.LCModel.DomainServices.WritingSystemServices.kwsAnal;

            lcmMetaData.UpdateCustomField(listRef_flid, fieldHelp, wsid, fieldLabel);

            TestEnvironment.CopyFwProjectTo(testProjectCode, _lDSettings.WebWorkDirectory);

            _lfProject.IsInitialClone = true;
            _transferLcmToMongo.Run(_lfProject);

            // To look at Mongo optionlist before test runs, uncomment this block
            // var x = _mongoConnection.GetLfOptionLists().FirstOrDefault(l => l.Code == "domain-type");
            // if (x != null) {
            //  foreach (LfOptionListItem item in x.Items) {
            //      Console.WriteLine($"{item.Guid} ({item.Key}) => {item.Value}");
            //  }
            // }

            // Buggy code path requires that there not be a GUID in the Mongo data
            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry = originalMongoData.First(e => e.Guid == _testEntryGuid);

            lfEntry.CustomFieldGuids.Remove("customField_entry_Cust_Single_ListRef");

            DateTime originalLfDateModified           = lfEntry.DateModified;
            DateTime originalLfAuthorInfoModifiedDate = lfEntry.AuthorInfo.ModifiedDate;

            lfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDLcmEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;
            var data       = (SIL.LCModel.Application.ISilDataAccessManaged)lDcache.DomainDataByFlid;
            int ownedHvo   = data.get_ObjectProp(lDLcmEntry.Hvo, listRef_flid);

            Assert.AreNotEqual(0, ownedHvo, "Custom field value in test data was invalid during setup");
            Assert.IsTrue(data.get_IsValidObject(ownedHvo), "Custom field value in test data was invalid during setup");
            ICmObject referencedObject = lDcache.GetAtomicPropObject(ownedHvo);

            Assert.IsNotNull(referencedObject, "Custom field in test data referenced invalid CmObject during setup");
            DateTime originalLdDateModified = lDLcmEntry.DateModified;

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify
            LfLexEntry updatedLfEntry  = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);
            var        updatedLcmEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            ownedHvo = data.get_ObjectProp(updatedLcmEntry.Hvo, listRef_flid);
            Assert.AreNotEqual(0, ownedHvo, "Custom field value in test data was invalid after running sync");
            Assert.IsTrue(data.get_IsValidObject(ownedHvo), "Custom field value in test data was invalid after running sync");
            referencedObject = lDcache.GetAtomicPropObject(ownedHvo);
            Assert.IsNotNull(referencedObject, "Custom field in test data referenced invalid CmObject after running sync");
            var poss = referencedObject as ICmPossibility;

            // TODO: Write another test to check on the abbrev hierarchy, because we may have a bug here (LfMerge not doing correct optionlist keys for hierarchical items)
            // Console.WriteLine($"Abbrev hierarchy: {poss.AbbrevHierarchyString}");
            Assert.IsNotNull(poss, "Custom field value in test data did not reference a CmPossibility object after running sync");
        }