PageRenderTime 73ms CodeModel.GetById 19ms app.highlight 47ms RepoModel.GetById 2ms app.codeStats 0ms

/V4/PrismLibrary/Desktop/Prism.Tests/Modularity/ModuleManagerFixture.cs

#
C# | 542 lines | 434 code | 91 blank | 17 comment | 14 complexity | 6a6d819394ea7cf282c609bfa313e2b0 MD5 | raw file
  1//===================================================================================
  2// Microsoft patterns & practices
  3// Composite Application Guidance for Windows Presentation Foundation and Silverlight
  4//===================================================================================
  5// Copyright (c) Microsoft Corporation.  All rights reserved.
  6// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9// FITNESS FOR A PARTICULAR PURPOSE.
 10//===================================================================================
 11// The example companies, organizations, products, domain names,
 12// e-mail addresses, logos, people, places, and events depicted
 13// herein are fictitious.  No association with any real company,
 14// organization, product, domain name, email address, logo, person,
 15// places, or events is intended or should be inferred.
 16//===================================================================================
 17using System;
 18using System.Collections.Generic;
 19using Microsoft.Practices.Prism.Tests.Mocks;
 20using Microsoft.Practices.Prism;
 21using Microsoft.Practices.Prism.Logging;
 22using Microsoft.Practices.Prism.Modularity;
 23using Microsoft.VisualStudio.TestTools.UnitTesting;
 24using Moq;
 25
 26namespace Microsoft.Practices.Prism.Tests.Modularity
 27{
 28    [TestClass]
 29    public class ModuleManagerFixture
 30    {
 31        [TestMethod]
 32        [ExpectedException(typeof(ArgumentNullException))]
 33        public void NullLoaderThrows()
 34        {
 35            new ModuleManager(null, new MockModuleCatalog(), new MockLogger());
 36        }
 37
 38        [TestMethod]
 39        [ExpectedException(typeof(ArgumentNullException))]
 40        public void NullCatalogThrows()
 41        {
 42            new ModuleManager(new MockModuleInitializer(), null, new MockLogger());
 43        }
 44
 45        [TestMethod]
 46        [ExpectedException(typeof(ArgumentNullException))]
 47        public void NullLoggerThrows()
 48        {
 49            new ModuleManager(new MockModuleInitializer(), new MockModuleCatalog(), null);
 50        }       
 51
 52        [TestMethod]
 53        public void ShouldInvokeRetrieverForModules()
 54        {
 55            var loader = new MockModuleInitializer();
 56            var moduleInfo = CreateModuleInfo("needsRetrieval", InitializationMode.WhenAvailable);
 57            var catalog = new MockModuleCatalog { Modules = { moduleInfo } };
 58            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
 59            var moduleTypeLoader = new MockModuleTypeLoader();
 60            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };
 61
 62            manager.Run();
 63
 64            Assert.IsTrue(moduleTypeLoader.LoadedModules.Contains(moduleInfo));
 65        }
 66
 67        [TestMethod]
 68        public void ShouldInitializeModulesOnRetrievalCompleted()
 69        {
 70            var loader = new MockModuleInitializer();
 71            var backgroungModuleInfo = CreateModuleInfo("NeedsRetrieval", InitializationMode.WhenAvailable);
 72            var catalog = new MockModuleCatalog { Modules = { backgroungModuleInfo } };
 73            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
 74            var moduleTypeLoader = new MockModuleTypeLoader();
 75            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };            
 76            Assert.IsFalse(loader.InitializeCalled);
 77
 78            manager.Run();
 79
 80            Assert.IsTrue(loader.InitializeCalled);
 81            Assert.AreEqual(1, loader.InitializedModules.Count);
 82            Assert.AreEqual(backgroungModuleInfo, loader.InitializedModules[0]);
 83        }
 84
 85        [TestMethod]
 86        public void ShouldInitializeModuleOnDemand()
 87        {
 88            var loader = new MockModuleInitializer();
 89            var onDemandModule = CreateModuleInfo("NeedsRetrieval", InitializationMode.OnDemand);
 90            var catalog = new MockModuleCatalog { Modules = { onDemandModule } };
 91            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
 92            var moduleRetriever = new MockModuleTypeLoader();
 93            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleRetriever };
 94            manager.Run();
 95
 96            Assert.IsFalse(loader.InitializeCalled);
 97            Assert.AreEqual(0, moduleRetriever.LoadedModules.Count);
 98
 99            manager.LoadModule("NeedsRetrieval");
100
101            Assert.AreEqual(1, moduleRetriever.LoadedModules.Count);
102            Assert.IsTrue(loader.InitializeCalled);
103            Assert.AreEqual(1, loader.InitializedModules.Count);
104            Assert.AreEqual(onDemandModule, loader.InitializedModules[0]);
105        }
106
107        [TestMethod]
108        [ExpectedException(typeof(ModuleNotFoundException))]
109        public void InvalidOnDemandModuleNameThrows()
110        {
111            var loader = new MockModuleInitializer();
112
113            var catalog = new MockModuleCatalog { Modules = new List<ModuleInfo> { CreateModuleInfo("Missing", InitializationMode.OnDemand) } };
114
115            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
116            var moduleTypeLoader = new MockModuleTypeLoader();
117
118            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };
119            manager.Run();
120
121            manager.LoadModule("NonExistent");
122        }
123
124        [TestMethod]
125        [ExpectedException(typeof(ModuleNotFoundException))]
126        public void EmptyOnDemandModuleReturnedThrows()
127        {
128            var loader = new MockModuleInitializer();
129
130            var catalog = new MockModuleCatalog { CompleteListWithDependencies = modules => new List<ModuleInfo>() };
131            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
132            var moduleRetriever = new MockModuleTypeLoader();
133            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleRetriever };
134            manager.Run();
135
136            manager.LoadModule("NullModule");
137        }
138
139        [TestMethod]
140        public void ShouldNotLoadTypeIfModuleInitialized()
141        {
142            var loader = new MockModuleInitializer();
143            var alreadyPresentModule = CreateModuleInfo(typeof(MockModule), InitializationMode.WhenAvailable);
144            alreadyPresentModule.State = ModuleState.ReadyForInitialization;
145            var catalog = new MockModuleCatalog { Modules = { alreadyPresentModule } };
146            var manager = new ModuleManager(loader, catalog, new MockLogger());
147            var moduleTypeLoader = new MockModuleTypeLoader();
148            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };
149
150            manager.Run();
151
152            Assert.IsFalse(moduleTypeLoader.LoadedModules.Contains(alreadyPresentModule));
153            Assert.IsTrue(loader.InitializeCalled);
154            Assert.AreEqual(1, loader.InitializedModules.Count);
155            Assert.AreEqual(alreadyPresentModule, loader.InitializedModules[0]);
156        }
157
158        [TestMethod]
159        public void ShouldNotLoadSameModuleTwice()
160        {
161            var loader = new MockModuleInitializer();
162            var onDemandModule = CreateModuleInfo(typeof(MockModule), InitializationMode.OnDemand);
163            var catalog = new MockModuleCatalog { Modules = { onDemandModule } };
164            var manager = new ModuleManager(loader, catalog, new MockLogger());
165            manager.Run();
166            manager.LoadModule("MockModule");
167            loader.InitializeCalled = false;
168            manager.LoadModule("MockModule");
169
170            Assert.IsFalse(loader.InitializeCalled);
171        }
172
173        [TestMethod]
174        public void ShouldNotLoadModuleThatNeedsRetrievalTwice()
175        {
176            var loader = new MockModuleInitializer();
177            var onDemandModule = CreateModuleInfo("ModuleThatNeedsRetrieval", InitializationMode.OnDemand);
178            var catalog = new MockModuleCatalog { Modules = { onDemandModule } };
179            var manager = new ModuleManager(loader, catalog, new MockLogger());
180            var moduleTypeLoader = new MockModuleTypeLoader();
181            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };
182            manager.Run();
183            manager.LoadModule("ModuleThatNeedsRetrieval");
184            moduleTypeLoader.RaiseLoadModuleCompleted(new LoadModuleCompletedEventArgs(onDemandModule, null));
185            loader.InitializeCalled = false;
186
187            manager.LoadModule("ModuleThatNeedsRetrieval");
188
189            Assert.IsFalse(loader.InitializeCalled);
190        }
191
192        [TestMethod]
193        public void ShouldCallValidateCatalogBeforeGettingGroupsFromCatalog()
194        {
195            var loader = new MockModuleInitializer();
196            var catalog = new MockModuleCatalog();
197            var manager = new ModuleManager(loader, catalog, new MockLogger());
198            bool validateCatalogCalled = false;
199            bool getModulesCalledBeforeValidate = false;
200
201            catalog.ValidateCatalog = () => validateCatalogCalled = true;
202            catalog.CompleteListWithDependencies = f =>
203                                                     {
204                                                         if (!validateCatalogCalled)
205                                                         {
206                                                             getModulesCalledBeforeValidate = true;
207                                                         }
208
209                                                         return null;
210                                                     };
211            manager.Run();
212
213            Assert.IsTrue(validateCatalogCalled);
214            Assert.IsFalse(getModulesCalledBeforeValidate);
215        }
216
217        [TestMethod]
218        public void ShouldNotInitializeIfDependenciesAreNotMet()
219        {
220            var loader = new MockModuleInitializer();
221            var requiredModule = CreateModuleInfo("ModuleThatNeedsRetrieval1", InitializationMode.WhenAvailable);
222            requiredModule.ModuleName = "RequiredModule";
223            var dependantModuleInfo = CreateModuleInfo("ModuleThatNeedsRetrieval2", InitializationMode.WhenAvailable, "RequiredModule");
224
225            var catalog = new MockModuleCatalog { Modules = { requiredModule, dependantModuleInfo } };
226            catalog.GetDependentModules = m => new[] { requiredModule };
227
228            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
229            var moduleTypeLoader = new MockModuleTypeLoader();
230            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };
231
232            manager.Run();
233
234            moduleTypeLoader.RaiseLoadModuleCompleted(new LoadModuleCompletedEventArgs(dependantModuleInfo, null));            
235
236            Assert.IsFalse(loader.InitializeCalled);
237            Assert.AreEqual(0, loader.InitializedModules.Count);
238        }
239
240        [TestMethod]
241        public void ShouldInitializeIfDependenciesAreMet()
242        {
243            var initializer = new MockModuleInitializer();
244            var requiredModule = CreateModuleInfo("ModuleThatNeedsRetrieval1", InitializationMode.WhenAvailable);
245            requiredModule.ModuleName = "RequiredModule";
246            var dependantModuleInfo = CreateModuleInfo("ModuleThatNeedsRetrieval2", InitializationMode.WhenAvailable, "RequiredModule");
247
248            var catalog = new MockModuleCatalog { Modules = { requiredModule, dependantModuleInfo } };
249            catalog.GetDependentModules = delegate(ModuleInfo module)
250                                              {
251                                                  if (module == dependantModuleInfo)
252                                                      return new[] { requiredModule };
253                                                  else
254                                                      return null;
255                                              };
256
257            ModuleManager manager = new ModuleManager(initializer, catalog, new MockLogger());
258            var moduleTypeLoader = new MockModuleTypeLoader();
259            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };
260
261            manager.Run();
262
263            Assert.IsTrue(initializer.InitializeCalled);
264            Assert.AreEqual(2, initializer.InitializedModules.Count);
265        }
266
267        [TestMethod]
268        public void ShouldThrowOnRetrieverErrorAndWrapException()
269        {
270            var loader = new MockModuleInitializer();
271            var moduleInfo = CreateModuleInfo("NeedsRetrieval", InitializationMode.WhenAvailable);
272            var catalog = new MockModuleCatalog { Modules = { moduleInfo } };
273            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
274            var moduleTypeLoader = new MockModuleTypeLoader();
275
276            Exception retrieverException = new Exception();
277            moduleTypeLoader.LoadCompletedError = retrieverException;
278
279            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };            
280            Assert.IsFalse(loader.InitializeCalled);
281
282            try
283            {
284                manager.Run();
285            }
286            catch (Exception ex)
287            {
288                Assert.IsInstanceOfType(ex, typeof(ModuleTypeLoadingException));
289                Assert.AreEqual(moduleInfo.ModuleName, ((ModularityException)ex).ModuleName);
290                StringAssert.Contains(ex.Message, moduleInfo.ModuleName);
291                Assert.AreSame(retrieverException, ex.InnerException);
292                return;
293            }
294
295            Assert.Fail("Exception not thrown.");
296        }
297
298        [TestMethod]
299        [ExpectedException(typeof(ModuleTypeLoaderNotFoundException))]
300        public void ShouldThrowIfNoRetrieverCanRetrieveModule()
301        {
302            var loader = new MockModuleInitializer();
303            var catalog = new MockModuleCatalog { Modules = { CreateModuleInfo("ModuleThatNeedsRetrieval", InitializationMode.WhenAvailable) } };
304            ModuleManager manager = new ModuleManager(loader, catalog, new MockLogger());
305            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { new MockModuleTypeLoader() { canLoadModuleTypeReturnValue = false } };
306            manager.Run();
307        }
308
309        [TestMethod]
310        public void ShouldLogMessageOnModuleRetrievalError()
311        {
312            var loader = new MockModuleInitializer();
313            var moduleInfo = CreateModuleInfo("ModuleThatNeedsRetrieval", InitializationMode.WhenAvailable);
314            var catalog = new MockModuleCatalog { Modules = { moduleInfo } };
315            var logger = new MockLogger();
316            ModuleManager manager = new ModuleManager(loader, catalog, logger);
317            var moduleTypeLoader = new MockModuleTypeLoader();
318            moduleTypeLoader.LoadCompletedError = new Exception();
319            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { moduleTypeLoader };
320
321            try
322            {
323                manager.Run();
324            }
325            catch
326            {
327                // Ignore all errors to make sure logger is called even if errors thrown.
328            }
329
330            Assert.IsNotNull(logger.LastMessage);
331            StringAssert.Contains(logger.LastMessage, "ModuleThatNeedsRetrieval");
332            Assert.AreEqual<Category>(Category.Exception, logger.LastMessageCategory);
333        }
334
335        [TestMethod]
336        public void ShouldWorkIfModuleLoadsAnotherOnDemandModuleWhenInitializing()
337        {
338            var initializer = new StubModuleInitializer();
339            var onDemandModule = CreateModuleInfo(typeof(MockModule), InitializationMode.OnDemand);
340            onDemandModule.ModuleName = "OnDemandModule";
341            var moduleThatLoadsOtherModule = CreateModuleInfo(typeof(MockModule), InitializationMode.WhenAvailable);
342            var catalog = new MockModuleCatalog { Modules = { moduleThatLoadsOtherModule, onDemandModule } };
343            ModuleManager manager = new ModuleManager(initializer, catalog, new MockLogger());
344            
345            bool onDemandModuleWasInitialized = false;
346            initializer.Initialize = m =>
347                                     {
348                                         if (m == moduleThatLoadsOtherModule)
349                                         {
350                                             manager.LoadModule("OnDemandModule");
351                                         }
352                                         else if (m == onDemandModule)
353                                         {
354                                             onDemandModuleWasInitialized = true;
355                                         }
356                                     };
357
358            manager.Run();
359
360            Assert.IsTrue(onDemandModuleWasInitialized);
361        }
362
363        
364        [TestMethod]
365        public void ModuleManagerIsDisposable()
366        {
367            Mock<IModuleInitializer> mockInit = new Mock<IModuleInitializer>(); 
368            var moduleInfo = CreateModuleInfo("needsRetrieval", InitializationMode.WhenAvailable);
369            var catalog = new Mock<IModuleCatalog>();
370            ModuleManager manager = new ModuleManager(mockInit.Object, catalog.Object, new MockLogger());
371
372            IDisposable disposableManager = manager as IDisposable;
373            Assert.IsNotNull(disposableManager);
374        }
375        
376        [TestMethod]
377        public void DisposeDoesNotThrowWithNonDisposableTypeLoaders()
378        {
379            Mock<IModuleInitializer> mockInit = new Mock<IModuleInitializer>();
380            var moduleInfo = CreateModuleInfo("needsRetrieval", InitializationMode.WhenAvailable);
381            var catalog = new Mock<IModuleCatalog>();
382            ModuleManager manager = new ModuleManager(mockInit.Object, catalog.Object, new MockLogger());
383
384            var mockTypeLoader = new Mock<IModuleTypeLoader>();
385            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> {mockTypeLoader.Object};
386
387            try
388            {
389                manager.Dispose();
390            }
391            catch(Exception)
392            {
393                Assert.Fail();
394            }
395        }
396
397        [TestMethod]
398        public void DisposeCleansUpDisposableTypeLoaders()
399        {
400            Mock<IModuleInitializer> mockInit = new Mock<IModuleInitializer>();
401            var moduleInfo = CreateModuleInfo("needsRetrieval", InitializationMode.WhenAvailable);
402            var catalog = new Mock<IModuleCatalog>();
403            ModuleManager manager = new ModuleManager(mockInit.Object, catalog.Object, new MockLogger());
404
405            var mockTypeLoader = new Mock<IModuleTypeLoader>();
406            var disposableMockTypeLoader = mockTypeLoader.As<IDisposable>();
407            disposableMockTypeLoader.Setup(loader => loader.Dispose());
408
409            manager.ModuleTypeLoaders = new List<IModuleTypeLoader> { mockTypeLoader.Object };
410
411            manager.Dispose();
412
413            disposableMockTypeLoader.Verify(loader => loader.Dispose(), Times.Once());
414        }
415
416        [TestMethod]
417        public void DisposeDoesNotThrowWithMixedTypeLoaders()
418        {
419            Mock<IModuleInitializer> mockInit = new Mock<IModuleInitializer>();
420            var moduleInfo = CreateModuleInfo("needsRetrieval", InitializationMode.WhenAvailable);
421            var catalog = new Mock<IModuleCatalog>();
422            ModuleManager manager = new ModuleManager(mockInit.Object, catalog.Object, new MockLogger());
423
424            var mockTypeLoader1 = new Mock<IModuleTypeLoader>();
425
426            var mockTypeLoader = new Mock<IModuleTypeLoader>();
427            var disposableMockTypeLoader = mockTypeLoader.As<IDisposable>();
428            disposableMockTypeLoader.Setup(loader => loader.Dispose());
429
430            manager.ModuleTypeLoaders = new List<IModuleTypeLoader>() { mockTypeLoader1.Object, mockTypeLoader.Object };
431            
432            try
433            {
434                manager.Dispose();
435            }
436            catch (Exception)
437            {
438                Assert.Fail();
439            }
440
441            disposableMockTypeLoader.Verify(loader => loader.Dispose(), Times.Once());
442        }
443        private static ModuleInfo CreateModuleInfo(string name, InitializationMode initializationMode, params string[] dependsOn)
444        {
445            ModuleInfo moduleInfo = new ModuleInfo(name, name);
446            moduleInfo.InitializationMode = initializationMode;
447            moduleInfo.DependsOn.AddRange(dependsOn);
448            return moduleInfo;
449        }
450
451        private static ModuleInfo CreateModuleInfo(Type type, InitializationMode initializationMode, params string[] dependsOn)
452        {
453            ModuleInfo moduleInfo = new ModuleInfo(type.Name, type.AssemblyQualifiedName);
454            moduleInfo.InitializationMode = initializationMode;
455            moduleInfo.DependsOn.AddRange(dependsOn);
456            return moduleInfo;
457        }
458    }
459
460    internal class MockModule : IModule
461    {
462        public void Initialize()
463        {
464            throw new System.NotImplementedException();
465        }
466    }
467
468    internal class MockModuleCatalog : IModuleCatalog
469    {
470        public List<ModuleInfo> Modules = new List<ModuleInfo>();
471        public Func<ModuleInfo, IEnumerable<ModuleInfo>> GetDependentModules;
472
473        public Func<IEnumerable<ModuleInfo>, IEnumerable<ModuleInfo>> CompleteListWithDependencies;
474        public Action ValidateCatalog;
475
476        public void Initialize()
477        {
478            if (this.ValidateCatalog != null)
479            {
480                this.ValidateCatalog();
481            }
482        }
483
484        IEnumerable<ModuleInfo> IModuleCatalog.Modules
485        {
486            get { return this.Modules; }
487        }
488
489        IEnumerable<ModuleInfo> IModuleCatalog.GetDependentModules(ModuleInfo moduleInfo)
490        {
491            if (GetDependentModules == null)
492                return new List<ModuleInfo>();
493
494            return GetDependentModules(moduleInfo);
495        }
496
497        IEnumerable<ModuleInfo> IModuleCatalog.CompleteListWithDependencies(IEnumerable<ModuleInfo> modules)
498        {
499            if (CompleteListWithDependencies != null)
500                return CompleteListWithDependencies(modules);
501            return modules;
502        }
503
504
505        public void AddModule(ModuleInfo moduleInfo)
506        {
507            this.Modules.Add(moduleInfo);
508        }
509    }
510
511    internal class MockModuleInitializer : IModuleInitializer
512    {
513        public bool InitializeCalled;
514        public List<ModuleInfo> InitializedModules = new List<ModuleInfo>();
515
516        public void Initialize(ModuleInfo moduleInfo)
517        {
518            InitializeCalled = true;            
519            this.InitializedModules.Add(moduleInfo);
520        }
521    }
522
523    internal class StubModuleInitializer : IModuleInitializer
524    {
525        public Action<ModuleInfo> Initialize;
526
527        void IModuleInitializer.Initialize(ModuleInfo moduleInfo)
528        {
529            this.Initialize(moduleInfo);
530        }
531    }
532
533    internal class MockDelegateModuleInitializer : IModuleInitializer
534    {
535        public Action<ModuleInfo> LoadBody;
536
537        public void Initialize(ModuleInfo moduleInfo)
538        {
539            LoadBody(moduleInfo);
540        }
541    }
542}