// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. #if !NO_REMOTING using System; using System.IO; using System.Reactive.Concurrency; using System.Reactive.PlatformServices; using System.Runtime.CompilerServices; using System.Threading; #if NUNIT using NUnit.Framework; using TestClassAttribute = NUnit.Framework.TestFixtureAttribute; using TestMethodAttribute = NUnit.Framework.TestAttribute; using TestInitializeAttribute = NUnit.Framework.SetUpAttribute; #else using Microsoft.VisualStudio.TestTools.UnitTesting; #endif namespace ReactiveTests.Tests { [TestClass] [Serializable] public class DefaultConcurrencyAbstractionLayerTest { private AppDomain _domain; [TestInitialize] public void Init() { if (_domain == null) { var cur = Utils.GetTestBaseDirectory(); var sub = Path.Combine(cur, "NoCAL"); if (!Directory.Exists(sub)) { Directory.CreateDirectory(sub); foreach (var file in Directory.GetFiles(cur)) { var fn = Path.GetFileName(file); if (!file.Contains("PlatformServices")) File.Copy(Path.Combine(cur, fn), Path.Combine(sub, fn)); } } _domain = AppDomain.CreateDomain("Default_CAL", null, new AppDomainSetup { ApplicationBase = sub }); } } private void Run(CrossAppDomainDelegate a) { _domain.DoCallBack(a); } [TestMethod] public void Sleep() { var ran = new MarshalByRefCell(); _domain.SetData("state", ran); Run(() => { Scheduler.Immediate.Schedule(TimeSpan.FromMilliseconds(1), () => { var state = (MarshalByRefCell)_domain.GetData("state"); state.Value = true; }); }); Assert.IsTrue(ran.Value); } [TestMethod] public void QueueUserWorkItem() { var e = new MarshalByRefCell { Value = new ManualResetEvent(false) }; _domain.SetData("state", e); Run(() => { Scheduler.Default.Schedule(() => { var state = (MarshalByRefCell)_domain.GetData("state"); state.Value.Set(); }); }); e.Value.WaitOne(); } [TestMethod] public void StartTimer() { var e = new MarshalByRefCell { Value = new ManualResetEvent(false) }; _domain.SetData("state", e); Run(() => { Scheduler.Default.Schedule(TimeSpan.FromMilliseconds(10), () => { var state = (MarshalByRefCell)_domain.GetData("state"); state.Value.Set(); }); }); e.Value.WaitOne(); } [TestMethod] public void StartTimer_Cancel() { Run(() => { Scheduler.Default.Schedule(TimeSpan.FromSeconds(60), () => { throw new InvalidOperationException("This shouldn't have happened!"); }).Dispose(); }); } [TestMethod] public void StartPeriodicTimer() { var e = new MarshalByRefCell { Value = new ManualResetEvent(false) }; _domain.SetData("state", e); Run(() => { var n = 0; Scheduler.Default.SchedulePeriodic(TimeSpan.FromMilliseconds(10), () => { var state = (MarshalByRefCell)_domain.GetData("state"); if (n++ == 10) state.Value.Set(); }); }); e.Value.WaitOne(); } [TestMethod] public void StartPeriodicTimer_Cancel() { Run(() => { Scheduler.Default.SchedulePeriodic(TimeSpan.FromSeconds(60), () => { throw new InvalidOperationException("This shouldn't have happened!"); }).Dispose(); }); } [TestMethod] public void StartPeriodicTimer_Fast() { var e = new MarshalByRefCell { Value = new ManualResetEvent(false) }; _domain.SetData("state", e); Run(() => { var n = 0; Scheduler.Default.SchedulePeriodic(TimeSpan.Zero, () => { var state = (MarshalByRefCell)_domain.GetData("state"); if (n++ == 10) state.Value.Set(); }); }); e.Value.WaitOne(); } [TestMethod] public void StartPeriodicTimer_Fast_Cancel() { var e = new MarshalByRefCell { Value = new ManualResetEvent(false) }; _domain.SetData("set_cancel", e); Run(() => { var n = 0; var schedule = Scheduler.Default.SchedulePeriodic(TimeSpan.Zero, () => { _domain.SetData("value", n++); }); _domain.SetData("cancel", new MarshalByRefAction(schedule.Dispose)); var setCancel = (MarshalByRefCell)_domain.GetData("set_cancel"); setCancel.Value.Set(); }); e.Value.WaitOne(); var value = (int)_domain.GetData("value"); var cancel = (MarshalByRefAction)_domain.GetData("cancel"); cancel.Invoke(); Thread.Sleep(TimeSpan.FromMilliseconds(50)); var newValue = (int)_domain.GetData("value"); Assert.IsTrue(newValue >= value); Thread.Sleep(TimeSpan.FromMilliseconds(50)); value = (int)_domain.GetData("value"); Assert.AreEqual(newValue, value); } [TestMethod] public void CreateThread() { var e = new MarshalByRefCell { Value = new ManualResetEvent(false) }; _domain.SetData("state", e); var r = new MarshalByRefCell { Value = "" }; _domain.SetData("res", r); Run(() => { var state = (MarshalByRefCell)_domain.GetData("state"); var res = (MarshalByRefCell)_domain.GetData("res"); var svc = (IServiceProvider)Scheduler.Default; var per = (ISchedulerPeriodic)svc.GetService(typeof(ISchedulerPeriodic)); if (per == null) { res.Value = "Failed to get ISchedulerPeriodic."; state.Value.Set(); return; } var slr = (ISchedulerLongRunning)svc.GetService(typeof(ISchedulerLongRunning)); if (slr == null) { res.Value = "Failed to get ISchedulerLongRunning."; state.Value.Set(); return; } var success = false; try { slr.ScheduleLongRunning(42, null); } catch (ArgumentNullException) { success = true; } if (!success) { res.Value = "Failed null check ScheduleLongRunnign."; state.Value.Set(); return; } state.Value.Set(); #if !NO_THREAD var w = new ManualResetEvent(false); var d = slr.ScheduleLongRunning(cancel => { while (!cancel.IsDisposed) ; w.Set(); }); Thread.Sleep(50); d.Dispose(); w.WaitOne(); #else state.Value.Set(); #endif }); e.Value.WaitOne(); Assert.IsTrue(string.IsNullOrEmpty(r.Value)); } #if !NO_TPL [TestMethod] public void Cant_Locate_Scheduler() { if (!Utils.IsRunningWithPortableLibraryBinaries()) { Cant_Locate_Scheduler_NoPlib(); } } [MethodImpl(MethodImplOptions.NoInlining)] private void Cant_Locate_Scheduler_NoPlib() { var e = new MarshalByRefCell(); _domain.SetData("state", e); Run(() => { var state = (MarshalByRefCell)_domain.GetData("state"); try { Scheduler.TaskPool.Schedule(() => { }); } catch (Exception ex) { state.Value = ex; } }); Assert.IsTrue(e.Value != null && e.Value is NotSupportedException); } #endif #if !NO_PERF && !NO_STOPWATCH [TestMethod] public void Stopwatch() { var e = new MarshalByRefCell(); _domain.SetData("state", e); Run(() => { var state = (MarshalByRefCell)_domain.GetData("state"); var sw = Scheduler.Default.StartStopwatch(); var fst = sw.Elapsed; Thread.Sleep(100); var snd = sw.Elapsed; state.Value = snd > fst; }); Assert.IsTrue(e.Value); } #endif [TestMethod] public void EnsureLoaded() { Assert.IsTrue(EnlightenmentProvider.EnsureLoaded()); } } public class MarshalByRefCell : MarshalByRefObject { public T Value; } public class MarshalByRefAction : MarshalByRefObject { private readonly Action _action; public MarshalByRefAction(Action action) { _action = action; } public void Invoke() { _action(); } } } #endif