public void Teardown()
        {
            if (_cacheHandler != null)
            {
                _cacheHandler.Unbind();
            }
            _cacheHandler = null;

            ServerRegistrarResolver.Reset();
            ServerMessengerResolver.Reset();
            CacheRefreshersResolver.Reset();
        }
        public void Teardown()
        {
            if (_cacheHandler != null)
            {
                _cacheHandler.Unbind();
            }
            _cacheHandler = null;

            _onPublishedAssertAction       = null;
            content.HttpContextItemsGetter = null;
            ContentService.Published      -= OnPublishedAssert;
            SafeXmlReaderWriter.Cloning    = null;

            ServerRegistrarResolver.Reset();
            ServerMessengerResolver.Reset();
            CacheRefreshersResolver.Reset();
        }
        public void TestNoScope()
        {
            content.TestingUpdateSitemapProvider = false;

            var settings    = SettingsForTests.GenerateMockSettings();
            var contentMock = Mock.Get(settings.Content);

            contentMock.Setup(x => x.XmlCacheEnabled).Returns(false);
            SettingsForTests.ConfigureSettings(settings);

            var contentType = new ContentType(-1)
            {
                Alias = "contenttype", Name = "test"
            };

            ApplicationContext.Services.ContentTypeService.Save(contentType);

            _cacheHandler = new CacheRefresherEventHandler(true);
            _cacheHandler.OnApplicationStarted(null, ApplicationContext);

            var xml = content.Instance.XmlContent;

            Assert.IsNotNull(xml);
            var beforeXml = xml.OuterXml;
            var item      = new Content("name", -1, contentType);

            ApplicationContext.Services.ContentService.SaveAndPublishWithStatus(item);

            Console.WriteLine("Xml Before:");
            Console.WriteLine(xml.OuterXml);
            Assert.AreEqual(beforeXml, xml.OuterXml);

            xml = content.Instance.XmlContent;
            Assert.IsNotNull(xml);
            Console.WriteLine("Xml After:");
            Console.WriteLine(xml.OuterXml);
            var node = xml.GetElementById(item.Id.ToString());

            Assert.IsNotNull(node);
        }
        public void Can_Find_All_Event_Handlers()
        {
            var definitions = new IEventDefinition[]
            {
                //I would test these but they are legacy events and we don't need them for deploy, when we migrate to new/better events we can wire up the check
                //Permission.New += PermissionNew;
                //Permission.Updated += PermissionUpdated;
                //Permission.Deleted += PermissionDeleted;
                //PermissionRepository<IContent>.AssignedPermissions += CacheRefresherEventHandler_AssignedPermissions;

                new EventDefinition <IApplicationTreeService, EventArgs>(null, ServiceContext.ApplicationTreeService, new EventArgs(), "Deleted"),
                new EventDefinition <IApplicationTreeService, EventArgs>(null, ServiceContext.ApplicationTreeService, new EventArgs(), "Updated"),
                new EventDefinition <IApplicationTreeService, EventArgs>(null, ServiceContext.ApplicationTreeService, new EventArgs(), "New"),

                new EventDefinition <ISectionService, EventArgs>(null, ServiceContext.SectionService, new EventArgs(), "Deleted"),
                new EventDefinition <ISectionService, EventArgs>(null, ServiceContext.SectionService, new EventArgs(), "New"),

                new EventDefinition <IUserService, SaveEventArgs <IUser> >(null, ServiceContext.UserService, new SaveEventArgs <IUser>(Enumerable.Empty <IUser>())),
                new EventDefinition <IUserService, DeleteEventArgs <IUser> >(null, ServiceContext.UserService, new DeleteEventArgs <IUser>(Enumerable.Empty <IUser>())),
                new EventDefinition <IUserService, SaveEventArgs <IUserGroup> >(null, ServiceContext.UserService, new SaveEventArgs <IUserGroup>(Enumerable.Empty <IUserGroup>())),
                new EventDefinition <IUserService, DeleteEventArgs <IUserGroup> >(null, ServiceContext.UserService, new DeleteEventArgs <IUserGroup>(Enumerable.Empty <IUserGroup>())),

                new EventDefinition <ILocalizationService, SaveEventArgs <IDictionaryItem> >(null, ServiceContext.LocalizationService, new SaveEventArgs <IDictionaryItem>(Enumerable.Empty <IDictionaryItem>())),
                new EventDefinition <ILocalizationService, DeleteEventArgs <IDictionaryItem> >(null, ServiceContext.LocalizationService, new DeleteEventArgs <IDictionaryItem>(Enumerable.Empty <IDictionaryItem>())),

                new EventDefinition <IDataTypeService, SaveEventArgs <IDataTypeDefinition> >(null, ServiceContext.DataTypeService, new SaveEventArgs <IDataTypeDefinition>(Enumerable.Empty <IDataTypeDefinition>())),
                new EventDefinition <IDataTypeService, DeleteEventArgs <IDataTypeDefinition> >(null, ServiceContext.DataTypeService, new DeleteEventArgs <IDataTypeDefinition>(Enumerable.Empty <IDataTypeDefinition>())),

                new EventDefinition <IFileService, SaveEventArgs <Stylesheet> >(null, ServiceContext.FileService, new SaveEventArgs <Stylesheet>(Enumerable.Empty <Stylesheet>())),
                new EventDefinition <IFileService, DeleteEventArgs <Stylesheet> >(null, ServiceContext.FileService, new DeleteEventArgs <Stylesheet>(Enumerable.Empty <Stylesheet>())),

                new EventDefinition <IDomainService, SaveEventArgs <IDomain> >(null, ServiceContext.DomainService, new SaveEventArgs <IDomain>(Enumerable.Empty <IDomain>())),
                new EventDefinition <IDomainService, DeleteEventArgs <IDomain> >(null, ServiceContext.DomainService, new DeleteEventArgs <IDomain>(Enumerable.Empty <IDomain>())),

                new EventDefinition <ILocalizationService, SaveEventArgs <ILanguage> >(null, ServiceContext.LocalizationService, new SaveEventArgs <ILanguage>(Enumerable.Empty <ILanguage>())),
                new EventDefinition <ILocalizationService, DeleteEventArgs <ILanguage> >(null, ServiceContext.LocalizationService, new DeleteEventArgs <ILanguage>(Enumerable.Empty <ILanguage>())),

                new EventDefinition <IContentTypeService, SaveEventArgs <IContentType> >(null, ServiceContext.ContentTypeService, new SaveEventArgs <IContentType>(Enumerable.Empty <IContentType>())),
                new EventDefinition <IContentTypeService, DeleteEventArgs <IContentType> >(null, ServiceContext.ContentTypeService, new DeleteEventArgs <IContentType>(Enumerable.Empty <IContentType>())),
                new EventDefinition <IContentTypeService, SaveEventArgs <IMediaType> >(null, ServiceContext.ContentTypeService, new SaveEventArgs <IMediaType>(Enumerable.Empty <IMediaType>())),
                new EventDefinition <IContentTypeService, DeleteEventArgs <IMediaType> >(null, ServiceContext.ContentTypeService, new DeleteEventArgs <IMediaType>(Enumerable.Empty <IMediaType>())),

                new EventDefinition <IMemberTypeService, SaveEventArgs <IMemberType> >(null, ServiceContext.MemberTypeService, new SaveEventArgs <IMemberType>(Enumerable.Empty <IMemberType>())),
                new EventDefinition <IMemberTypeService, DeleteEventArgs <IMemberType> >(null, ServiceContext.MemberTypeService, new DeleteEventArgs <IMemberType>(Enumerable.Empty <IMemberType>())),

                new EventDefinition <IFileService, SaveEventArgs <ITemplate> >(null, ServiceContext.FileService, new SaveEventArgs <ITemplate>(Enumerable.Empty <ITemplate>())),
                new EventDefinition <IFileService, DeleteEventArgs <ITemplate> >(null, ServiceContext.FileService, new DeleteEventArgs <ITemplate>(Enumerable.Empty <ITemplate>())),

                new EventDefinition <IMacroService, SaveEventArgs <IMacro> >(null, ServiceContext.MacroService, new SaveEventArgs <IMacro>(Enumerable.Empty <IMacro>())),
                new EventDefinition <IMacroService, DeleteEventArgs <IMacro> >(null, ServiceContext.MacroService, new DeleteEventArgs <IMacro>(Enumerable.Empty <IMacro>())),

                new EventDefinition <IMemberService, SaveEventArgs <IMember> >(null, ServiceContext.MemberService, new SaveEventArgs <IMember>(Enumerable.Empty <IMember>())),
                new EventDefinition <IMemberService, DeleteEventArgs <IMember> >(null, ServiceContext.MemberService, new DeleteEventArgs <IMember>(Enumerable.Empty <IMember>())),

                new EventDefinition <IMemberGroupService, SaveEventArgs <IMemberGroup> >(null, ServiceContext.MemberGroupService, new SaveEventArgs <IMemberGroup>(Enumerable.Empty <IMemberGroup>())),
                new EventDefinition <IMemberGroupService, DeleteEventArgs <IMemberGroup> >(null, ServiceContext.MemberGroupService, new DeleteEventArgs <IMemberGroup>(Enumerable.Empty <IMemberGroup>())),

                new EventDefinition <IMediaService, SaveEventArgs <IMedia> >(null, ServiceContext.MediaService, new SaveEventArgs <IMedia>(Enumerable.Empty <IMedia>())),
                new EventDefinition <IMediaService, DeleteEventArgs <IMedia> >(null, ServiceContext.MediaService, new DeleteEventArgs <IMedia>(Enumerable.Empty <IMedia>())),
                new EventDefinition <IMediaService, MoveEventArgs <IMedia> >(null, ServiceContext.MediaService, new MoveEventArgs <IMedia>(new MoveEventInfo <IMedia>(null, "", -1)), "Moved"),
                new EventDefinition <IMediaService, MoveEventArgs <IMedia> >(null, ServiceContext.MediaService, new MoveEventArgs <IMedia>(new MoveEventInfo <IMedia>(null, "", -1)), "Trashed"),
                new EventDefinition <IMediaService, RecycleBinEventArgs>(null, ServiceContext.MediaService, new RecycleBinEventArgs(Guid.NewGuid(), new Dictionary <int, IEnumerable <Property> >(), true)),

                new EventDefinition <IContentService, SaveEventArgs <IContent> >(null, ServiceContext.ContentService, new SaveEventArgs <IContent>(Enumerable.Empty <IContent>()), "Saved"),
                new EventDefinition <IContentService, SaveEventArgs <IContent> >(null, ServiceContext.ContentService, new SaveEventArgs <IContent>(Enumerable.Empty <IContent>()), "SavedBlueprint"),
                new EventDefinition <IContentService, DeleteEventArgs <IContent> >(null, ServiceContext.ContentService, new DeleteEventArgs <IContent>(Enumerable.Empty <IContent>()), "Deleted"),
                new EventDefinition <IContentService, DeleteEventArgs <IContent> >(null, ServiceContext.ContentService, new DeleteEventArgs <IContent>(Enumerable.Empty <IContent>()), "DeletedBlueprint"),
                new EventDefinition <IContentService, CopyEventArgs <IContent> >(null, ServiceContext.ContentService, new CopyEventArgs <IContent>(null, null, -1)),
                new EventDefinition <IContentService, MoveEventArgs <IContent> >(null, ServiceContext.ContentService, new MoveEventArgs <IContent>(new MoveEventInfo <IContent>(null, "", -1)), "Trashed"),
                new EventDefinition <IContentService, RecycleBinEventArgs>(null, ServiceContext.ContentService, new RecycleBinEventArgs(Guid.NewGuid(), new Dictionary <int, IEnumerable <Property> >(), true)),
                new EventDefinition <IContentService, PublishEventArgs <IContent> >(null, ServiceContext.ContentService, new PublishEventArgs <IContent>(Enumerable.Empty <IContent>()), "Published"),
                new EventDefinition <IContentService, PublishEventArgs <IContent> >(null, ServiceContext.ContentService, new PublishEventArgs <IContent>(Enumerable.Empty <IContent>()), "UnPublished"),

                new EventDefinition <IPublicAccessService, SaveEventArgs <PublicAccessEntry> >(null, ServiceContext.PublicAccessService, new SaveEventArgs <PublicAccessEntry>(Enumerable.Empty <PublicAccessEntry>())),
                new EventDefinition <IPublicAccessService, DeleteEventArgs <PublicAccessEntry> >(null, ServiceContext.PublicAccessService, new DeleteEventArgs <PublicAccessEntry>(Enumerable.Empty <PublicAccessEntry>())),

                new EventDefinition <IRelationService, SaveEventArgs <IRelationType> >(null, ServiceContext.RelationService, new SaveEventArgs <IRelationType>(Enumerable.Empty <IRelationType>())),
                new EventDefinition <IRelationService, DeleteEventArgs <IRelationType> >(null, ServiceContext.RelationService, new DeleteEventArgs <IRelationType>(Enumerable.Empty <IRelationType>())),

                new EventDefinition <IRelationService, SaveEventArgs <IRelationType> >(null, ServiceContext.RelationService, new SaveEventArgs <IRelationType>(Enumerable.Empty <IRelationType>())),
                new EventDefinition <IRelationService, DeleteEventArgs <IRelationType> >(null, ServiceContext.RelationService, new DeleteEventArgs <IRelationType>(Enumerable.Empty <IRelationType>())),
            };

            foreach (var definition in definitions)
            {
                var found = CacheRefresherEventHandler.FindHandler(definition);
                Assert.IsNotNull(found, "Couldn't find method for " + definition.EventName + " on " + definition.Sender.GetType());
            }
        }
        public void DefaultRepositoryCachePolicy(bool complete)
        {
            var scopeProvider = DatabaseContext.ScopeProvider;
            var service       = ApplicationContext.Services.UserService;
            var globalCache   = ApplicationContext.ApplicationCache.IsolatedRuntimeCache.GetOrCreateCache(typeof(IUser));

            var user = (IUser) new User("name", "email", "username", "rawPassword");

            service.Save(user);

            // global cache contains the entity
            var globalCached = (IUser)globalCache.GetCacheItem(GetCacheIdKey <IUser>(user.Id), () => null);

            Assert.IsNotNull(globalCached);
            Assert.AreEqual(user.Id, globalCached.Id);
            Assert.AreEqual("name", globalCached.Name);

            _cacheHandler = new CacheRefresherEventHandler(true);
            _cacheHandler.OnApplicationStarted(null, ApplicationContext);

            Assert.IsNull(scopeProvider.AmbientScope);
            using (var scope = scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped))
            {
                Assert.IsInstanceOf <Scope>(scope);
                Assert.IsNotNull(scopeProvider.AmbientScope);
                Assert.AreSame(scope, scopeProvider.AmbientScope);

                // scope has its own isolated cache
                var scopedCache = scope.IsolatedRuntimeCache.GetOrCreateCache(typeof(IUser));
                Assert.AreNotSame(globalCache, scopedCache);

                user.Name = "changed";
                service.Save(user);

                // scoped cache contains the "new" entity
                var scopeCached = (IUser)scopedCache.GetCacheItem(GetCacheIdKey <IUser>(user.Id), () => null);
                Assert.IsNotNull(scopeCached);
                Assert.AreEqual(user.Id, scopeCached.Id);
                Assert.AreEqual("changed", scopeCached.Name);

                // global cache is unchanged
                globalCached = (IUser)globalCache.GetCacheItem(GetCacheIdKey <IUser>(user.Id), () => null);
                Assert.IsNotNull(globalCached);
                Assert.AreEqual(user.Id, globalCached.Id);
                Assert.AreEqual("name", globalCached.Name);

                if (complete)
                {
                    scope.Complete();
                }
            }
            Assert.IsNull(scopeProvider.AmbientScope);

            globalCached = (IUser)globalCache.GetCacheItem(GetCacheIdKey <IUser>(user.Id), () => null);
            if (complete)
            {
                // global cache has been cleared
                Assert.IsNull(globalCached);
            }
            else
            {
                // global cache has *not* been cleared
                Assert.IsNotNull(globalCached);
            }

            // get again, updated if completed
            user = service.GetUserById(user.Id);
            Assert.AreEqual(complete ? "changed" : "name", user.Name);

            // global cache contains the entity again
            globalCached = (IUser)globalCache.GetCacheItem(GetCacheIdKey <IUser>(user.Id), () => null);
            Assert.IsNotNull(globalCached);
            Assert.AreEqual(user.Id, globalCached.Id);
            Assert.AreEqual(complete ? "changed" : "name", globalCached.Name);
        }
        public void SingleItemsOnlyRepositoryCachePolicy(bool complete)
        {
            var scopeProvider = DatabaseContext.ScopeProvider;
            var service       = ApplicationContext.Services.LocalizationService;
            var globalCache   = ApplicationContext.ApplicationCache.IsolatedRuntimeCache.GetOrCreateCache(typeof(IDictionaryItem));

            var lang = (ILanguage) new Language("fr-FR");

            service.Save(lang);

            var item = (IDictionaryItem) new DictionaryItem("item-key");

            item.Translations = new IDictionaryTranslation[]
            {
                new DictionaryTranslation(lang.Id, "item-value"),
            };
            service.Save(item);

            // global cache contains the entity
            var globalCached = (IDictionaryItem)globalCache.GetCacheItem(GetCacheIdKey <IDictionaryItem>(item.Id), () => null);

            Assert.IsNotNull(globalCached);
            Assert.AreEqual(item.Id, globalCached.Id);
            Assert.AreEqual("item-key", globalCached.ItemKey);

            _cacheHandler = new CacheRefresherEventHandler(true);
            _cacheHandler.OnApplicationStarted(null, ApplicationContext);

            Assert.IsNull(scopeProvider.AmbientScope);
            using (var scope = scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped))
            {
                Assert.IsInstanceOf <Scope>(scope);
                Assert.IsNotNull(scopeProvider.AmbientScope);
                Assert.AreSame(scope, scopeProvider.AmbientScope);

                // scope has its own isolated cache
                var scopedCache = scope.IsolatedRuntimeCache.GetOrCreateCache(typeof(IDictionaryItem));
                Assert.AreNotSame(globalCache, scopedCache);

                item.ItemKey = "item-changed";
                service.Save(item);

                // scoped cache contains the "new" entity
                var scopeCached = (IDictionaryItem)scopedCache.GetCacheItem(GetCacheIdKey <IDictionaryItem>(item.Id), () => null);
                Assert.IsNotNull(scopeCached);
                Assert.AreEqual(item.Id, scopeCached.Id);
                Assert.AreEqual("item-changed", scopeCached.ItemKey);

                // global cache is unchanged
                globalCached = (IDictionaryItem)globalCache.GetCacheItem(GetCacheIdKey <IDictionaryItem>(item.Id), () => null);
                Assert.IsNotNull(globalCached);
                Assert.AreEqual(item.Id, globalCached.Id);
                Assert.AreEqual("item-key", globalCached.ItemKey);

                if (complete)
                {
                    scope.Complete();
                }
            }
            Assert.IsNull(scopeProvider.AmbientScope);

            globalCached = (IDictionaryItem)globalCache.GetCacheItem(GetCacheIdKey <IDictionaryItem>(item.Id), () => null);
            if (complete)
            {
                // global cache has been cleared
                Assert.IsNull(globalCached);
            }
            else
            {
                // global cache has *not* been cleared
                Assert.IsNotNull(globalCached);
            }

            // get again, updated if completed
            item = service.GetDictionaryItemById(item.Id);
            Assert.AreEqual(complete ? "item-changed" : "item-key", item.ItemKey);

            // global cache contains the entity again
            globalCached = (IDictionaryItem)globalCache.GetCacheItem(GetCacheIdKey <IDictionaryItem>(item.Id), () => null);
            Assert.IsNotNull(globalCached);
            Assert.AreEqual(item.Id, globalCached.Id);
            Assert.AreEqual(complete ? "item-changed" : "item-key", globalCached.ItemKey);
        }
        public void FullDataSetRepositoryCachePolicy(bool complete)
        {
            var scopeProvider = DatabaseContext.ScopeProvider;
            var service       = ApplicationContext.Services.LocalizationService;
            var globalCache   = ApplicationContext.ApplicationCache.IsolatedRuntimeCache.GetOrCreateCache(typeof(ILanguage));

            var lang = (ILanguage) new Language("fr-FR");

            service.Save(lang);

            // global cache has been flushed, reload
            var globalFullCached = (IEnumerable <ILanguage>)globalCache.GetCacheItem(GetCacheTypeKey <ILanguage>(), () => null);

            Assert.IsNull(globalFullCached);
            var reload = service.GetLanguageById(lang.Id);

            // global cache contains the entity
            globalFullCached = (IEnumerable <ILanguage>)globalCache.GetCacheItem(GetCacheTypeKey <ILanguage>(), () => null);
            Assert.IsNotNull(globalFullCached);
            var globalCached = globalFullCached.First(x => x.Id == lang.Id);

            Assert.IsNotNull(globalCached);
            Assert.AreEqual(lang.Id, globalCached.Id);
            Assert.AreEqual("fr-FR", globalCached.IsoCode);

            _cacheHandler = new CacheRefresherEventHandler(true);
            _cacheHandler.OnApplicationStarted(null, ApplicationContext);

            Assert.IsNull(scopeProvider.AmbientScope);
            using (var scope = scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped))
            {
                Assert.IsInstanceOf <Scope>(scope);
                Assert.IsNotNull(scopeProvider.AmbientScope);
                Assert.AreSame(scope, scopeProvider.AmbientScope);

                // scope has its own isolated cache
                var scopedCache = scope.IsolatedRuntimeCache.GetOrCreateCache(typeof(ILanguage));
                Assert.AreNotSame(globalCache, scopedCache);

                lang.IsoCode = "de-DE";
                service.Save(lang);

                // scoped cache has been flushed, reload
                var scopeFullCached = (IEnumerable <ILanguage>)scopedCache.GetCacheItem(GetCacheTypeKey <ILanguage>(), () => null);
                Assert.IsNull(scopeFullCached);
                reload = service.GetLanguageById(lang.Id);

                // scoped cache contains the "new" entity
                scopeFullCached = (IEnumerable <ILanguage>)scopedCache.GetCacheItem(GetCacheTypeKey <ILanguage>(), () => null);
                Assert.IsNotNull(scopeFullCached);
                var scopeCached = scopeFullCached.First(x => x.Id == lang.Id);
                Assert.IsNotNull(scopeCached);
                Assert.AreEqual(lang.Id, scopeCached.Id);
                Assert.AreEqual("de-DE", scopeCached.IsoCode);

                // global cache is unchanged
                globalFullCached = (IEnumerable <ILanguage>)globalCache.GetCacheItem(GetCacheTypeKey <ILanguage>(), () => null);
                Assert.IsNotNull(globalFullCached);
                globalCached = globalFullCached.First(x => x.Id == lang.Id);
                Assert.IsNotNull(globalCached);
                Assert.AreEqual(lang.Id, globalCached.Id);
                Assert.AreEqual("fr-FR", globalCached.IsoCode);

                if (complete)
                {
                    scope.Complete();
                }
            }
            Assert.IsNull(scopeProvider.AmbientScope);

            globalFullCached = (IEnumerable <ILanguage>)globalCache.GetCacheItem(GetCacheTypeKey <ILanguage>(), () => null);
            if (complete)
            {
                // global cache has been cleared
                Assert.IsNull(globalFullCached);
            }
            else
            {
                // global cache has *not* been cleared
                Assert.IsNotNull(globalFullCached);
            }

            // get again, updated if completed
            lang = service.GetLanguageById(lang.Id);
            Assert.AreEqual(complete ? "de-DE" : "fr-FR", lang.IsoCode);

            // global cache contains the entity again
            globalFullCached = (IEnumerable <ILanguage>)globalCache.GetCacheItem(GetCacheTypeKey <ILanguage>(), () => null);
            Assert.IsNotNull(globalFullCached);
            globalCached = globalFullCached.First(x => x.Id == lang.Id);
            Assert.IsNotNull(globalCached);
            Assert.AreEqual(lang.Id, globalCached.Id);
            Assert.AreEqual(complete ? "de-DE" : "fr-FR", lang.IsoCode);
        }
        public void TestScopeMany(bool complete)
        {
            content.TestingUpdateSitemapProvider = false;

            var settings    = SettingsForTests.GenerateMockSettings();
            var contentMock = Mock.Get(settings.Content);

            contentMock.Setup(x => x.XmlCacheEnabled).Returns(false);
            SettingsForTests.ConfigureSettings(settings);

            var contentType = new ContentType(-1)
            {
                Alias = "contenttype", Name = "test"
            };

            ApplicationContext.Services.ContentTypeService.Save(contentType);

            _cacheHandler = new CacheRefresherEventHandler(true);
            _cacheHandler.OnApplicationStarted(null, ApplicationContext);

            var xml = content.Instance.XmlContent;

            Assert.IsNotNull(xml);
            var       beforeXml      = xml;
            var       beforeOuterXml = beforeXml.OuterXml;
            var       item           = new Content("name", -1, contentType);
            const int count          = 10;
            var       ids            = new int[count];
            var       clones         = 0;

            SafeXmlReaderWriter.Cloning = () => { clones++; };

            Console.WriteLine("Xml Before:");
            Console.WriteLine(xml.OuterXml);

            using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
            {
                ApplicationContext.Services.ContentService.SaveAndPublishWithStatus(item);

                for (var i = 0; i < count; i++)
                {
                    var temp = new Content("content_" + i, -1, contentType);
                    ApplicationContext.Services.ContentService.SaveAndPublishWithStatus(temp);
                    ids[i] = temp.Id;
                }

                // this should never change
                Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml);

                xml = content.Instance.XmlContent;
                Assert.IsNotNull(xml);
                Console.WriteLine("Xml InScope (before complete):");
                Console.WriteLine(xml.OuterXml);
                Assert.AreEqual(beforeOuterXml, xml.OuterXml);

                if (complete)
                {
                    scope.Complete();
                }

                xml = content.Instance.XmlContent;
                Assert.IsNotNull(xml);
                Console.WriteLine("Xml InScope (after complete):");
                Console.WriteLine(xml.OuterXml);
                Assert.AreEqual(beforeOuterXml, xml.OuterXml);
            }

            var scopeProvider = ApplicationContext.Current.ScopeProvider as IScopeProviderInternal;

            Assert.IsNotNull(scopeProvider);
            // ambient scope may be null, or maybe not, depending on whether the code that
            // was called did proper scoped work, or some direct (NoScope) use of the database
            Assert.IsNull(scopeProvider.AmbientContext);

            // limited number of clones!
            Assert.AreEqual(complete ? 1 : 0, clones);

            // this should never change
            Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml);

            xml = content.Instance.XmlContent;
            Assert.IsNotNull(xml);
            Console.WriteLine("Xml After:");
            Console.WriteLine(xml.OuterXml);
            if (complete)
            {
                var node = xml.GetElementById(item.Id.ToString());
                Assert.IsNotNull(node);

                for (var i = 0; i < 10; i++)
                {
                    node = xml.GetElementById(ids[i].ToString());
                    Assert.IsNotNull(node);
                }
            }
            else
            {
                Assert.AreEqual(beforeOuterXml, xml.OuterXml); // nothing has changed!
            }
        }
        public void TestScope(bool complete)
        {
            content.TestingUpdateSitemapProvider = false;

            var httpContextItems = new Hashtable();

            content.HttpContextItemsGetter = () => httpContextItems;

            var settings    = SettingsForTests.GenerateMockSettings();
            var contentMock = Mock.Get(settings.Content);

            contentMock.Setup(x => x.XmlCacheEnabled).Returns(false);
            SettingsForTests.ConfigureSettings(settings);

            var contentType = new ContentType(-1)
            {
                Alias = "contenttype", Name = "test"
            };

            ApplicationContext.Services.ContentTypeService.Save(contentType);

            _cacheHandler = new CacheRefresherEventHandler(true);
            _cacheHandler.OnApplicationStarted(null, ApplicationContext);

            var xml = content.Instance.XmlContent;

            Assert.IsNotNull(xml);
            Assert.AreSame(xml, httpContextItems[content.XmlContextContentItemKey]);
            var beforeXml      = xml;
            var beforeOuterXml = beforeXml.OuterXml;
            var item           = new Content("name", -1, contentType);

            Console.WriteLine("Xml Before:");
            Console.WriteLine(xml.OuterXml);

            var evented = 0;

            _onPublishedAssertAction = () =>
            {
                evented++;
                xml = content.Instance.XmlContent;
                Assert.IsNotNull(xml);
                Assert.AreNotSame(beforeXml, xml);
                Console.WriteLine("Xml Event:");
                Console.WriteLine(xml.OuterXml);
                var node = xml.GetElementById(item.Id.ToString());
                Assert.IsNotNull(node);
            };

            ContentService.Published += OnPublishedAssert;

            using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
            {
                ApplicationContext.Services.ContentService.SaveAndPublishWithStatus(item); // should create an xml clone
                item.Name = "changed";
                ApplicationContext.Services.ContentService.SaveAndPublishWithStatus(item); // should re-use the xml clone

                // this should never change
                Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml);

                // this does not change, other thread don't see the changes
                xml = content.Instance.XmlContentInternal;
                Assert.IsNotNull(xml);
                Assert.AreSame(beforeXml, xml);
                Console.WriteLine("XmlInternal During:");
                Console.WriteLine(xml.OuterXml);
                Assert.AreEqual(beforeOuterXml, xml.OuterXml);

                // this does not change during the scope (only in events)
                // because it is the events that trigger the changes
                xml = content.Instance.XmlContent;
                Assert.IsNotNull(xml);
                Assert.AreSame(beforeXml, xml);

                // note
                // this means that, as long as ppl don't create scopes, they'll see their
                // changes right after SaveAndPublishWithStatus, but if they create scopes,
                // they will have to wail until the scope is completed, ie wait until the
                // events trigger, to use eg GetUrl etc

                if (complete)
                {
                    scope.Complete();
                }
            }

            //The reason why there is only 1 event occuring is because we are publishing twice for the same event for the same
            //object and the scope deduplicates the events (uses the latest)
            Assert.AreEqual(complete ? 1 : 0, evented);

            // this should never change
            Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml);

            xml = content.Instance.XmlContent;
            Assert.IsNotNull(xml);
            Console.WriteLine("Xml After:");
            Console.WriteLine(xml.OuterXml);
            if (complete)
            {
                var node = xml.GetElementById(item.Id.ToString());
                Assert.IsNotNull(node);
            }
            else
            {
                Assert.AreSame(beforeXml, xml);
                Assert.AreEqual(beforeOuterXml, xml.OuterXml); // nothing has changed!
            }
        }