Example #1
0
            /// <summary>
            /// Ermittelt zu allen erlaubten Geräten die eindeutigen Kennungen.
            /// </summary>
            /// <param name="scheduler">Die zugehörige Planungsinstanz.</param>
            /// <returns>Gesetzt, wenn mindestens ein Gerät erlaubt ist.</returns>
            public bool PrepareResourceMap(RecordingScheduler scheduler)
            {
                // Reset
                AllowedResources = null;

                // Check mode
                var resources = Definition.Resources;

                if (resources != null)
                {
                    if (resources.Length > 0)
                    {
                        AllowedResources = Definition.Resources.Where(r => (r != null) && scheduler.Resources.Contains(r)).ToArray();
                    }
                }

                // Create full map
                if (AllowedResources == null)
                {
                    AllowedResources = scheduler.Resources.ToArray();
                }

                // Report
                return(AllowedResources.Length > 0);
            }
        public void Will_Use_Resource_With_Highest_Priority_When_Explicit_Binding_Is_Used()
        {
            // Create plan
            var source1 = SourceMock.Create( "s1" );
            var source2 = SourceMock.Create( "s2" );
            var res1 = ResourceMock.Create( "r1", source1, source2 ).SetPriority( 5 );
            var res2 = ResourceMock.Create( "r2", source1, source2 ).SetPriority( 6 );
            var res3 = ResourceMock.Create( "r3", source1, source2 ).SetPriority( 0 );
            var refTime = DateTime.UtcNow;
            var plan1 = RecordingDefinition.Create( false, "A1", Guid.NewGuid(), new[] { res1 }, source1, refTime.AddMinutes( 100 ), TimeSpan.FromMinutes( 20 ) );
            var plan2 = RecordingDefinition.Create( false, "A2", Guid.NewGuid(), new[] { res1 }, source1, refTime.AddMinutes( 110 ), TimeSpan.FromMinutes( 20 ) );
            var plan3 = RecordingDefinition.Create( false, "A3", Guid.NewGuid(), null, source2, refTime.AddMinutes( 130 ), TimeSpan.FromMinutes( 20 ) );

            // Create component under test
            var componentUnderTest =
                new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase )
                    {
                        { res1 },
                        { res2 },
                        { res3 },
                        { plan1 },
                        { plan2 },
                        { plan3 },
                    };

            // Load
            var schedules = componentUnderTest.GetSchedules( refTime ).ToArray();

            // Validate
            Assert.AreEqual( 3, schedules.Length, "#schedule" );
            Assert.AreSame( res1, schedules[0].Resource, "resource 0" );
            Assert.AreSame( res1, schedules[1].Resource, "resource 1" );
            Assert.AreSame( res2, schedules[2].Resource, "resource 2" );
        }
        public void Will_Choose_Highest_Priority_Source_For_Single_Plan_Item()
        {
            // Create plan
            var plan = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Create( "s1" ), DateTime.UtcNow.AddHours( 1 ), TimeSpan.FromMinutes( 20 ) );
            var best = ResourceMock.Create( "r3", SourceMock.Create( "s1" ) ).SetPriority( 6 );
            var times = plan.GetTimes( DateTime.UtcNow ).Select( s => s.Planned ).ToArray();

            // Create component under test
            var componentUnderTest =
                new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase )
                    {
                        { ResourceMock.Create( "r1", SourceMock.Create( "s1" ) ).SetPriority( 1 ) },
                        { best },
                        { ResourceMock.Create( "r2", SourceMock.Create( "s1" ) ).SetPriority( -1 ) },
                        { plan },
                    };

            // Load
            var schedules = componentUnderTest.GetSchedules( DateTime.UtcNow ).ToArray();

            // Validate
            Assert.AreEqual( 1, schedules.Length, "Schedules" );
            Assert.AreSame( best, schedules[0].Resource, "Resource" );
            Assert.AreSame( plan, schedules[0].Definition, "Plan" );
            Assert.AreEqual( times.Single(), schedules[0].Time, "Time" );
            Assert.IsFalse( schedules[0].StartsLate, "Late" );
        }
        public void Individual_Decryption_Counter_Must_Not_Be_Negative()
        {
            // Create the component under test
            var componentUnderTest = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase );

            // Register device
            componentUnderTest.Add( ResourceMock.Create( "a" ).SetEncryptionLimit( -1 ) );
        }
        public void A_Resource_Must_Not_Be_Null()
        {
            // Create the component under test
            var componentUnderTest = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase );

            // Register a null resource
            componentUnderTest.Add( default( IScheduleResource ) );
        }
        public void Can_Add_Multiple_Resources()
        {
            // Create the component under test
            var componentUnderTest = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase );

            // Register devices
            for (int i = 0; i < 100; i++)
                componentUnderTest.Add( ResourceMock.Create( i.ToString( "00" ) ) );
        }
        public void No_Resource_Can_Be_Used_Twice()
        {
            // Create the component under test
            var componentUnderTest = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase );
            var resource = ResourceMock.Create( "a" );

            // Register devices
            componentUnderTest.Add( resource );
            componentUnderTest.Add( resource );
        }
        public void Decrypted_Source_Requires_Decryption_Resource()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test1", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 90 ) );
            var plan2 = RecordingDefinition.Create( false, "test2", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 90 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { FreeTVDevice, plan1, plan2 };

            // Resolve
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 2, schedules.Length, "Schedule" );
            Assert.IsNull( schedules[0].Resource, "Resource 1" );
            Assert.AreSame( FreeTVDevice, schedules[1].Resource, "Resource 2" );
        }
        public void Two_Decrypted_Recordings_On_Same_Group_Require_Two_Decryption_Devices()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 100 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source4Group1Pay, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 10 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { PayTVDevice1, PayTVDevice2, plan1, plan2 };

            // Process
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 2, schedules.Length, "Schedules" );
            Assert.IsNotNull( schedules[0].Resource, "Resource 1" );
            Assert.IsNotNull( schedules[1].Resource, "Resource 2" );
            Assert.AreNotSame( schedules[0].Resource, schedules[1].Resource, "Resources" );
        }
        public void Will_Skip_Recording_If_Unable_To_Decrypt()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test1", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 100 ) );
            var plan2 = RecordingDefinition.Create( false, "test2", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 100 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { FreeTVDevice, plan1, plan2 };

            // Process
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 2, schedules.Length, "Schedules" );
            Assert.IsNull( schedules[0].Resource, "Resource 1" );
            Assert.AreSame( FreeTVDevice, schedules[1].Resource, "Resource 2" );
            Assert.IsFalse( schedules[1].StartsLate, "Late 2" );
        }
        public void Can_Join_Recordings_Even_If_Planning_Creates_Separate_Blocks()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "A1", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddMinutes( 60 ), TimeSpan.FromMinutes( 120 ) );
            var plan2 = RecordingDefinition.Create( false, "A2", Guid.NewGuid(), null, SourceMock.Source2Group1Free, TimeBias.AddMinutes( 165 ), TimeSpan.FromMinutes( 60 ) );
            var plan3 = RecordingDefinition.Create( false, "B1", Guid.NewGuid(), null, SourceMock.Source1Group2Free, TimeBias.AddMinutes( 150 ), TimeSpan.FromMinutes( 120 ) );
            var plan4 = RecordingDefinition.Create( false, "C1", Guid.NewGuid(), null, SourceMock.Source1Group3Free, TimeBias.AddMinutes( 120 ), TimeSpan.FromMinutes( 120 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { Device1, Device2, plan1, plan2, plan3, plan4 };

            // Resolve
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 4, schedules.Length, "Schedule" );

            // Process all
            foreach (var schedule in schedules)
                Assert.AreEqual( ReferenceEquals( schedule.Definition, plan3 ), schedule.StartsLate, "Late {0}", schedule.Definition.Name );
        }
        public void An_Unknown_Source_Can_Not_Be_Recorded()
        {
            // Create recordings
            var plan = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Create( "unknown" ), TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 90 ) );

            // Create component under test
            var cut =
                new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase )
                    {
                        { FreeTVDevice },
                        { plan },
                    };

            // Resolve
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 1, schedules.Length, "Schedules" );
            Assert.AreSame( null, schedules[0].Resource, "Resource" );
            Assert.AreSame( plan, schedules[0].Definition, "Plan" );
        }
        /// <summary>
        /// Ermittelt den aktuellen Aufzeichnungsplan.
        /// </summary>
        /// <param name="scheduler">Die zu verwendende Zeitplanungsinstanz.</param>
        /// <param name="referenceTime">Der Bezugspunkt für die Planung.</param>
        /// <param name="disabled">Alle deaktivierte Aufträge und Aufgaben.</param>
        /// <param name="limit">Die Anzahl der zu berücksichtigenden Planungselemente.</param>
        /// <returns>Die Liste der nächsten Aufzeichnungen.</returns>
        private PlanContext GetPlan( RecordingScheduler scheduler, DateTime referenceTime, Func<Guid, bool> disabled, int limit )
        {
            // Create a new plan context
            var context = new PlanContext( m_started.Values );

            // Configure it
            m_site.AddRegularJobs( scheduler, disabled, this, context );

            // Enable all
            if (disabled == null)
                disabled = identifier => false;

            // Do the sort
            context.LoadPlan( scheduler.GetSchedules( referenceTime, m_tasks.Where( task => !disabled( task.UniqueIdentifier ) ).ToArray() ).Take( limit ) );

            // Report
            return context;
        }
        public void A_Recording_May_Be_Discarded_If_Overlapping_Occurs_On_Different_Groups()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test1", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 90 ) );
            var plan2 = RecordingDefinition.Create( false, "test2", Guid.NewGuid(), null, SourceMock.Source1Group2Free, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 10 ) );

            // Create component under test
            var cut =
                new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase )
                    {
                        { FreeTVDevice },
                        { plan2 },
                        { plan1 },
                    };

            // Resolve
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 2, schedules.Length, "Schedules" );
            Assert.IsNull( schedules[0].Resource, "Resource 1" );
            Assert.AreSame( FreeTVDevice, schedules[1].Resource, "Resource 2" );
            Assert.AreSame( plan2, schedules[0].Definition, "Plan 1" );
            Assert.AreSame( plan1, schedules[1].Definition, "Plan 2" );
            Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
            Assert.IsFalse( schedules[1].StartsLate, "Late 2" );
        }
        public void Will_Detect_Recordings_On_Same_Source_As_One()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "testA", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddMinutes( 60 ), TimeSpan.FromMinutes( 90 ) );
            var plan2 = RecordingDefinition.Create( false, "testB", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddMinutes( 90 ), TimeSpan.FromMinutes( 40 ) );
            var plan3 = RecordingDefinition.Create( false, "testC", Guid.NewGuid(), null, SourceMock.Source2Group1Free, TimeBias.AddMinutes( 100 ), TimeSpan.FromMinutes( 40 ) );

            // Load current
            var device = (ResourceMock) FreeTVDevice;
            var limit = device.SourceLimit;
            try
            {
                // Create component under test
                var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { device.SetSourceLimit( 2 ), plan1, plan2, plan3 };

                // Resolve
                var schedules = cut.GetSchedules( TimeBias ).ToArray();

                // Validate
                Assert.AreEqual( 3, schedules.Length, "Schedules" );
                Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
                Assert.IsFalse( schedules[1].StartsLate, "Late 2" );
                Assert.IsFalse( schedules[2].StartsLate, "Late 3" );
            }
            finally
            {
                // Reset
                device.SetSourceLimit( limit );
            }
        }
        public void Restricted_Resource_Can_Not_Serve_Three_Records_At_A_Time()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 90 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source2Group1Free, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 70 ) );
            var plan3 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source3Group1Free, TimeBias.AddHours( 2.25 ), TimeSpan.FromMinutes( 90 ) );

            // Load current
            var device = (ResourceMock) FreeTVDevice;
            var limit = device.SourceLimit;
            try
            {
                // Create component under test
                var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { device.SetSourceLimit( 2 ), plan1, plan2, plan3 };

                // Resolve
                var schedules = cut.GetSchedules( TimeBias ).ToArray();

                // Validate
                Assert.AreEqual( 3, schedules.Length, "Schedules" );
                Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
                Assert.IsFalse( schedules[1].StartsLate, "Late 2" );
                Assert.IsTrue( schedules[2].StartsLate, "Late 3" );
            }
            finally
            {
                // Reset
                device.SetSourceLimit( limit );
            }
        }
        public void Same_Source_Does_Not_Require_Additional_Decyrption_Slot()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 100 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 100 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { PayTVDevice1, plan1, plan2 };

            // Process
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 2, schedules.Length, "Schedules" );
            Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
            Assert.IsFalse( schedules[1].StartsLate, "Late 2" );
        }
        public void Performance_Of_A_Real_Life_Scenario()
        {
            // Get the path to the test directories
            var jobDirectory = @"*TBD*";
            var profileDirectory = Environment.ExpandEnvironmentVariables( @"%AllUsersProfile%\DVBNETProfiles" );

            // Helper - will be reused
            var job = new XmlDocument();

            // Sources
            var sourceMap = new Dictionary<string, SourceMock>( StringComparer.InvariantCultureIgnoreCase );
            var profileMap = new Dictionary<string, XmlDocument>( StringComparer.InvariantCultureIgnoreCase );
            var groupMap = new Dictionary<object, Guid>();
            var plan = new List<IRecordingDefinition>();

            // Process all job files
            foreach (var jobPath in Directory.EnumerateFiles( jobDirectory, "*.j39" ))
            {
                // Load to document
                job.Load( jobPath );

                // Common data
                var autoSelect = bool.Parse( job.SelectSingleNode( "VCRJob/AutomaticResourceSelection" ).InnerText );
                var defaultSource = job.SelectSingleNode( "VCRJob/Source" );
                var profileName = defaultSource.InnerText.Substring( defaultSource.InnerText.LastIndexOf( '@' ) + 1 );
                var jobName = job.SelectSingleNode( "VCRJob/Name" ).InnerText;

                // Load the profile once
                XmlDocument profile;
                if (!profileMap.TryGetValue( profileName, out profile ))
                {
                    // Create
                    profile = new XmlDocument();

                    // Load
                    profile.Load( Path.Combine( profileDirectory, profileName + ".dnp" ) );

                    // Remapping
                    for (; ; )
                    {
                        // Create a new namespace table
                        var namespaces = new XmlNamespaceManager( profile.NameTable );

                        // Add us
                        namespaces.AddNamespace( "dvbnet", "http://psimarron.net/DVBNET/Profiles" );

                        // Check for remap
                        var loadFrom = profile.SelectSingleNode( "//dvbnet:UseSourcesFrom", namespaces );
                        if (loadFrom == null)
                            break;

                        // Load the name
                        var refProfileName = loadFrom.InnerText;
                        if (string.IsNullOrEmpty( refProfileName ))
                            break;

                        // Reload
                        if (profileMap.TryGetValue( refProfileName, out profile ))
                            continue;

                        // Create
                        profile = new XmlDocument();

                        // Load
                        profile.Load( Path.Combine( profileDirectory, refProfileName + ".dnp" ) );

                        // Remember
                        profileMap.Add( refProfileName, profile );
                    }

                    // Remember
                    profileMap.Add( profileName, profile );
                }

                // Create a new namespace table
                var profileNamespaces = new XmlNamespaceManager( profile.NameTable );

                // Add us
                profileNamespaces.AddNamespace( "dvbnet", "http://psimarron.net/DVBNET/Profiles" );

                // Validate
                Assert.IsTrue( autoSelect, "Auto Select" );

                // Process all schedules
                foreach (XmlElement schedule in job.SelectNodes( "VCRJob/Schedule" ))
                {
                    // Extract data
                    var repeat = schedule.SelectSingleNode( "Days" ).InnerText.Split( ' ' ).Where( d => !string.IsNullOrEmpty( d ) ).Select( d => (DayOfWeek) Enum.Parse( typeof( DayOfWeek ), d ) ).ToArray();
                    var firstStart = DateTime.Parse( schedule.SelectSingleNode( "FirstStart" ).InnerText, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind );
                    var lastDay = DateTime.Parse( schedule.SelectSingleNode( "LastDay" ).InnerText, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind );
                    var duration = TimeSpan.FromMinutes( uint.Parse( schedule.SelectSingleNode( "Duration" ).InnerText ) );
                    var source = (XmlElement) (schedule.SelectSingleNode( "Source" ) ?? defaultSource);
                    var id = Guid.Parse( schedule.SelectSingleNode( "UniqueID" ).InnerText );
                    var scheduleName = schedule.SelectSingleNode( "Name" ).InnerText;
                    var sourceName = source.GetAttribute( "name" );

                    // Find the real source
                    SourceMock realSource;
                    if (!sourceMap.TryGetValue( sourceName, out realSource ))
                    {
                        // Split name
                        var split = sourceName.LastIndexOf( '[' );
                        var stationName = sourceName.Substring( 0, split ).TrimEnd();
                        var providerName = sourceName.Substring( split + 1 ).TrimEnd( ']' );

                        // Locate the station
                        var station = (XmlElement) profile.SelectSingleNode( "//dvbnet:Station[@name='" + stationName + "' and @provider='" + providerName + "']", profileNamespaces );
                        var encrypted = bool.Parse( station.GetAttribute( "scrambled" ) );
                        var group = station.ParentNode;

                        // Unique group identifier
                        Guid groupIdentifier;
                        if (!groupMap.TryGetValue( group, out groupIdentifier ))
                            groupMap.Add( group, groupIdentifier = Guid.NewGuid() );

                        // Create the source entry
                        sourceMap.Add( sourceName, realSource = SourceMock.Create( sourceName, groupIdentifier, encrypted ) );
                    }

                    // Get the full name
                    if (string.IsNullOrEmpty( scheduleName ))
                        scheduleName = jobName;
                    else if (!string.IsNullOrEmpty( jobName ))
                        scheduleName = jobName + " (" + scheduleName + ")";

                    // Create the request
                    if (repeat.Length > 0)
                        plan.Add( RecordingDefinition.Create( schedule, scheduleName, id, null, realSource, firstStart, duration, lastDay, repeat ) );
                    else
                        plan.Add( RecordingDefinition.Create( schedule, scheduleName, id, null, realSource, firstStart, duration ) );
                }
            }

            // Create component under test
            var componentUnderTest = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase );
            var sources = sourceMap.Values.ToArray();

            // Add resources - hard coded, should be taken from configuration in some future version
            for (var i = 0; i++ < 4; )
                componentUnderTest.Add( ResourceMock.Create( "duo" + i.ToString( "0" ), sources ).SetEncryptionLimit( 1 ) );

            // Add the plan
            foreach (var recording in plan)
                componentUnderTest.Add( recording );

            // Process
            var refTime = new DateTime( 2013, 10, 26, 12, 0, 0, DateTimeKind.Utc );
            var timer = Stopwatch.StartNew();
            var all = componentUnderTest.GetSchedules( refTime ).Take( 1000 ).ToArray();
            var elapsed = timer.Elapsed;

            // Report
            Console.WriteLine( "{0:N3}ms", elapsed.TotalMilliseconds );

            // Validate
            Assert.AreEqual( 1000, all.Length, "#jobs" );
        }
            /// <summary>
            /// Ermittelt zu allen erlaubten Geräten die eindeutigen Kennungen.
            /// </summary>
            /// <param name="scheduler">Die zugehörige Planungsinstanz.</param>
            /// <returns>Gesetzt, wenn mindestens ein Gerät erlaubt ist.</returns>
            public bool PrepareResourceMap( RecordingScheduler scheduler )
            {
                // Reset
                AllowedResources = null;

                // Check mode
                var resources = Definition.Resources;
                if (resources != null)
                    if (resources.Length > 0)
                        AllowedResources = Definition.Resources.Where( r => (r != null) && scheduler.Resources.Contains( r ) ).ToArray();

                // Create full map
                if (AllowedResources == null)
                    AllowedResources = scheduler.Resources.ToArray();

                // Report
                return (AllowedResources.Length > 0);
            }
        public void Decryption_Group_May_Allow_Using_Two_Resources_At_The_Same_Time()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 100 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source4Group1Pay, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 100 ) );

            // Create group
            var group =
                new DecryptionGroup
                {
                    ScheduleResources = new[] { PayTVDevice1, PayTVDevice2 },
                    MaximumParallelSources = 2,
                };

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { PayTVDevice1, PayTVDevice2, plan1, plan2, group };

            // Process
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 2, schedules.Length, "Schedules" );
            Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
            Assert.IsFalse( schedules[1].StartsLate, "Late 2" );
        }
        public void Two_Recordings_Of_The_Same_Group_Can_Be_Recorded_Simultanously()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 90 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source2Group1Free, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 60 ) );

            // Create component under test
            var cut =
                new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase )
                    {
                        { FreeTVDevice },
                        { plan1 },
                        { plan2 },
                    };

            // Resolve
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 2, schedules.Length, "Schedules" );
            Assert.AreSame( FreeTVDevice, schedules[0].Resource, "Resource 1" );
            Assert.AreSame( FreeTVDevice, schedules[1].Resource, "Resource 2" );
            Assert.AreSame( plan1, schedules[0].Definition, "Plan 1" );
            Assert.AreSame( plan2, schedules[1].Definition, "Plan 2" );
            Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
            Assert.IsFalse( schedules[1].StartsLate, "Late 2" );
        }
        public void A_Repeating_Recording_Can_Have_Exceptions()
        {
            // Create recordings
            var repeatStart = TimeBias.AddHours( 1 );
            var repeatStartLocal = repeatStart.ToLocalTime();
            var plan =
                RecordingDefinition.Create
                    (
                        false,
                        "test",
                        Guid.NewGuid(),
                        null,
                        SourceMock.Source1Group1Free,
                        repeatStart,
                        TimeSpan.FromMinutes( 90 ),
                        DateTime.MaxValue.Date,
                        Enum.GetValues( typeof( DayOfWeek ) ).Cast<DayOfWeek>().ToArray()
                    );
            var exception1 =
                new PlanException
                {
                    ExceptionDate = repeatStartLocal.AddDays( 12 ).Date,
                    DurationDelta = TimeSpan.FromMinutes( -10 ),
                    StartDelta = TimeSpan.FromMinutes( 10 ),
                };
            var exception2 =
                new PlanException
                {
                    ExceptionDate = repeatStartLocal.AddDays( 22 ).Date,
                    DurationDelta = TimeSpan.FromMinutes( 10 ),
                };
            var exception3 =
                new PlanException
                {
                    ExceptionDate = repeatStartLocal.AddDays( 24 ).Date,
                    DurationDelta = TimeSpan.FromMinutes( -100 ),
                };

            // Create component under test
            var cut =
                new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase )
                    {
                        { FreeTVDevice },
                        { plan, exception1, exception2, exception3 },
                    };

            // Load 
            var schedules = cut.GetSchedules( TimeBias ).Take( 30 ).ToArray();

            // Check
            for (int i = 30; i-- > 0;)
                if (i == 12)
                {
                    // Validate
                    Assert.AreEqual( schedules[i].Time.Start, repeatStart.AddDays( i ).AddMinutes( 10 ), "Start {0}", i );
                    Assert.AreEqual( schedules[i].Time.Duration, TimeSpan.FromMinutes( 80 ), "Duration {0}", i );
                }
                else if (i == 22)
                {
                    // Validate
                    Assert.AreEqual( schedules[i].Time.Start, repeatStart.AddDays( i ), "Start {0}", i );
                    Assert.AreEqual( schedules[i].Time.Duration, TimeSpan.FromMinutes( 100 ), "Duration {0}", i );
                }
                else
                {
                    // Correct
                    var day = (i < 24) ? i : i + 1;

                    // Validate
                    Assert.AreEqual( schedules[i].Time.Start, repeatStart.AddDays( day ), "Start {0}", i );
                    Assert.AreEqual( schedules[i].Time.Duration, TimeSpan.FromMinutes( 90 ), "Duration {0}", i );
                }
        }
        public void The_Number_Of_Recordings_Per_Plan_Is_Limited()
        {
            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { FreeTVDevice };

            // Add all plans
            for (int i = 0; i <= RecordingScheduler.MaximumRecordingsInPlan; i++)
            {
                // Create recording
                var plan = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddHours( i ), TimeSpan.FromMinutes( 90 ) );

                // Add it
                cut.Add( plan );
            }

            // Resolve
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( RecordingScheduler.MaximumRecordingsInPlan + 1, (uint) schedules.Length, "Schedules" );

            // Check all
            for (int i = 0; i < RecordingScheduler.MaximumRecordingsInPlan; i++)
            {
                // Load
                var schedule = schedules[i];

                // Validate
                Assert.AreSame( FreeTVDevice, schedule.Resource, "Resource {0}", i );
                Assert.AreEqual( TimeBias.AddHours( i ), schedule.Time.Start, "Start {0}", i );
                Assert.AreEqual( TimeSpan.FromMinutes( 90 ), schedule.Time.Duration, "Duration {0}", i );
                Assert.IsFalse( schedule.StartsLate, "Late {0}", i );
            }

            // Load the last
            var last = schedules[RecordingScheduler.MaximumRecordingsInPlan];

            // Validate - internal planning is not touched
            Assert.AreSame( FreeTVDevice, last.Resource, "Resource" );
            Assert.AreEqual( TimeBias.AddHours( RecordingScheduler.MaximumRecordingsInPlan ), last.Time.Start, "Start" );
            Assert.AreEqual( TimeSpan.FromMinutes( 90 ), last.Time.Duration, "Duration" );
            Assert.IsFalse( last.StartsLate, "Late" );
        }
        public void Free_Recording_Must_Use_Best_Fit_Resource()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source5Group1Pay, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 100 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source4Group1Pay, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 100 ) );
            var plan3 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group2Free, TimeBias.AddHours( 2 ).AddMinutes( 10 ), TimeSpan.FromMinutes( 100 ) );

            // Attach to the device
            var device = (ResourceMock) PayTVDevice1;
            var prio = device.AbsolutePriority;

            // Must reset
            try
            {
                // Create component under test but make the device to choose the one with the least priority
                var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { device.SetPriority( -100 ), PayTVDevice2, plan1, plan2, plan3 };

                // Process
                var schedules = cut.GetSchedules( TimeBias ).ToArray();

                // Validate
                Assert.AreEqual( 3, schedules.Length, "Schedules" );
                Assert.AreSame( device, schedules[2].Resource, "Resource" );
            }
            finally
            {
                // Reset
                device.SetPriority( prio );
            }
        }
        public void May_Require_Three_Resources_On_Bad_Mixture_Of_Three_Recordings()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 100 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source4Group1Pay, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 100 ) );
            var plan3 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group2Free, TimeBias.AddHours( 2 ).AddMinutes( 10 ), TimeSpan.FromMinutes( 100 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { FreeTVDevice, PayTVDevice1, PayTVDevice2, plan1, plan2, plan3 };

            // Process
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 3, schedules.Length, "Schedules" );
            Assert.AreNotSame( FreeTVDevice, schedules[0].Resource, "Resource 1" );
            Assert.AreNotSame( FreeTVDevice, schedules[1].Resource, "Resource 2" );
            Assert.AreSame( FreeTVDevice, schedules[2].Resource, "Resource 3" );
        }
        public void A_Repeating_Recording_May_Be_Overlapped_By_A_Single_Recording()
        {
            // Create recordings
            var repeatStart = TimeBias.AddHours( 1 );
            var repeatStartLocal = repeatStart.ToLocalTime();
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Free, repeatStart, TimeSpan.FromMinutes( 90 ), DateTime.MaxValue.Date, repeatStartLocal.DayOfWeek );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group2Free, repeatStart.AddDays( 7 ).AddMinutes( -10 ), TimeSpan.FromMinutes( 60 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { FreeTVDevice, plan2, plan1, };

            // Load first repeats
            var schedules = cut.GetSchedules( TimeBias ).Take( 3 ).ToArray();

            // Validate
            Assert.AreEqual( 3, schedules.Length, "Schedules" );
            Assert.AreSame( plan1, schedules[0].Definition, "Plan 1" );
            Assert.AreSame( FreeTVDevice, schedules[0].Resource, "Resource 1" );
            Assert.AreSame( plan2, schedules[1].Definition, "Plan 2" );
            Assert.AreSame( FreeTVDevice, schedules[1].Resource, "Resource 2" );
            Assert.AreEqual( repeatStart.AddDays( 7 ).AddMinutes( -10 ), schedules[1].Time.Start, "Start 2" );
            Assert.AreEqual( TimeSpan.FromMinutes( 60 ), schedules[1].Time.Duration, "Duration 2" );
            Assert.AreSame( plan1, schedules[2].Definition, "Plan 3" );
            Assert.AreSame( FreeTVDevice, schedules[2].Resource, "Resource 3" );
            Assert.IsTrue( schedules[2].StartsLate, "Late" );
            Assert.AreEqual( repeatStart.AddDays( 7 ).AddMinutes( 50 ), schedules[2].Time.Start, "Start 3" );
            Assert.AreEqual( TimeSpan.FromMinutes( 40 ), schedules[2].Time.Duration, "Duration 3" );
        }
        public void High_Priority_Device_Will_Be_Ignored_If_Not_Able_To_Decrypt()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Pay, TimeBias.AddHours( 1 ), TimeSpan.FromMinutes( 100 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source4Group1Pay, TimeBias.AddHours( 2 ), TimeSpan.FromMinutes( 10 ) );

            // Attach to the free device
            var device = (ResourceMock) FreeTVDevice;
            var prio = device.AbsolutePriority;

            // With reset
            try
            {
                // Create component under test
                var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { device.SetPriority( 100 ), PayTVDevice1, PayTVDevice2, plan1, plan2 };

                // Process
                var schedules = cut.GetSchedules( TimeBias ).ToArray();

                // Validate
                Assert.AreEqual( 2, schedules.Length, "Schedules" );
                Assert.IsNotNull( schedules[0].Resource, "Resource 1" );
                Assert.AreNotSame( device, schedules[0].Resource, "Resource 1 Free" );
                Assert.IsNotNull( schedules[1].Resource, "Resource 2" );
                Assert.AreNotSame( device, schedules[1].Resource, "Resource 2 Free" );
                Assert.AreNotSame( schedules[0].Resource, schedules[1].Resource, "Resources" );
            }
            finally
            {
                // Back to normal
                device.SetPriority( prio );
            }
        }
        public void Will_Keep_Time_Order_When_Planning()
        {
            // Create recordings
            var plan1 = RecordingDefinition.Create( false, "testA", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddMinutes( 60 ), TimeSpan.FromMinutes( 60 ) );
            var plan2 = RecordingDefinition.Create( false, "testB", Guid.NewGuid(), null, SourceMock.Source1Group2Free, TimeBias.AddMinutes( 90 ), TimeSpan.FromMinutes( 60 ) );
            var plan3 = RecordingDefinition.Create( false, "testC", Guid.NewGuid(), null, SourceMock.Source2Group1Free, TimeBias.AddMinutes( 100 ), TimeSpan.FromMinutes( 100 ) );

            // Create component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { FreeTVDevice, plan1, plan2, plan3 };

            // Resolve
            var schedules = cut.GetSchedules( TimeBias ).ToArray();

            // Validate
            Assert.AreEqual( 3, schedules.Length, "Schedules" );
            Assert.AreEqual( "testA", schedules[0].Definition.Name, "Name 1" );
            Assert.AreEqual( "testB", schedules[1].Definition.Name, "Name 2" );
            Assert.AreEqual( "testC", schedules[2].Definition.Name, "Name 3" );
            Assert.AreSame( FreeTVDevice, schedules[0].Resource, "Resource 1" );
            Assert.AreSame( FreeTVDevice, schedules[1].Resource, "Resource 2" );
            Assert.AreSame( FreeTVDevice, schedules[2].Resource, "Resource 3" );
            Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
            Assert.IsTrue( schedules[1].StartsLate, "Late 2" );
            Assert.IsTrue( schedules[2].StartsLate, "Late 3" );
        }
Example #29
0
        public void Scheduler_Reports_Task_Times_If_No_Recording_Is_Available()
        {
            // Create the component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { TaskDevice, OtherDevice };

            // Load some
            var schedules = cut.GetSchedules( TimeBias, Task ).Take( 100 ).ToArray();

            // Validate
            Assert.AreEqual( 100, schedules.Length, "Schedules" );
            Assert.AreEqual( TimeBias, schedules[0].Time.Start, "Start 0" );
            Assert.AreEqual( TimeBias.ToLocalTime().Date.AddDays( 49 ).AddHours( 20 ).ToUniversalTime(), schedules[99].Time.Start, "Start 99" );
        }
Example #30
0
        /// <summary>
        /// Registriert diese Aufzeichnung in einer Planungsinstanz.
        /// </summary>
        /// <param name="scheduler">Die zu verwendende Planungsinstanz.</param>
        /// <param name="job">Der zugehörige Auftrag.</param>
        /// <param name="devices">Die Liste der Geräte, auf denen die Aufzeichnung ausgeführt werden darf.</param>
        /// <param name="findSource">Dient zum Prüfen einer Quelle.</param>
        /// <param name="disabled">Alle deaktivierten Aufträge.</param>
        /// <param name="context">Die aktuelle Planungsumgebung.</param>
        /// <exception cref="ArgumentNullException">Es wurden nicht alle Parameter angegeben.</exception>
        public void AddToScheduler( RecordingScheduler scheduler, VCRJob job, IScheduleResource[] devices, Func<SourceSelection, SourceSelection> findSource, Func<Guid, bool> disabled, PlanContext context )
        {
            // Validate
            if (scheduler == null)
                throw new ArgumentNullException( nameof( scheduler ) );
            if (job == null)
                throw new ArgumentNullException( nameof( job ) );
            if (findSource == null)
                throw new ArgumentNullException( nameof( findSource ) );

            // Let VCR.NET choose a profile to do the work
            if (job.AutomaticResourceSelection)
                devices = null;

            // Create the source selection
            var persistedSource = Source ?? job.Source;
            var selection = findSource( persistedSource );

            // Station no longer available
            if (selection == null)
                if (persistedSource != null)
                    selection =
                        new SourceSelection
                        {
                            DisplayName = persistedSource.DisplayName,
                            ProfileName = persistedSource.ProfileName,
                            Location = persistedSource.Location,
                            Group = persistedSource.Group,
                            Source =
                                new Station
                                {
                                    TransportStream = persistedSource.Source?.TransportStream ?? 0,
                                    Network = persistedSource.Source?.Network ?? 0,
                                    Service = persistedSource.Source?.Service ?? 0,
                                    Name = persistedSource.DisplayName,
                                },
                        };

            // See if we are allowed to process
            var identifier = UniqueID.Value;
            if (disabled != null)
                if (disabled( identifier ))
                    return;

            // Load all
            var name = string.IsNullOrEmpty( Name ) ? job.Name : $"{job.Name} ({Name})";
            var source = ProfileScheduleResource.CreateSource( selection );
            var duration = TimeSpan.FromMinutes( Duration );
            var noStartBefore = NoStartBefore;
            var start = FirstStart;

            // Check repetition
            var repeat = CreateRepeatPattern();
            if (repeat == null)
            {
                // Only if not being recorded
                if (!noStartBefore.HasValue)
                    scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration ) );
            }
            else
            {
                // See if we have to adjust the start day
                if (noStartBefore.HasValue)
                {
                    // Attach to the limit - actually we shift it a bit further assuming that we did have no large exception towards the past and the duration is moderate
                    var startAfter = noStartBefore.Value.AddHours( 12 );
                    var startAfterDay = startAfter.ToLocalTime().Date;

                    // Localize the start time
                    var startTime = start.ToLocalTime().TimeOfDay;

                    // First adjust
                    start = (startAfterDay + startTime).ToUniversalTime();

                    // One more day
                    if (start < startAfter)
                        start = (startAfterDay.AddDays( 1 ) + startTime).ToUniversalTime();
                }

                // Read the rest
                var exceptions = Exceptions.Select( e => e.ToPlanException( duration ) ).ToArray();
                var endDay = LastDay.GetValueOrDefault( MaxMovableDay );

                // A bit more complex
                if (start.Date <= endDay.Date)
                    scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration, endDay, repeat ), exceptions );
            }
        }
Example #31
0
        public void Recording_Has_Priority_Over_Task()
        {
            // Create the recording
            var plan1 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddMinutes( 15 ), TimeSpan.FromMinutes( 80 ) );
            var plan2 = RecordingDefinition.Create( false, "test", Guid.NewGuid(), null, SourceMock.Source1Group1Free, TimeBias.AddHours( 3 ), TimeSpan.FromMinutes( 100 ) );

            // Create the component under test
            var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) { TaskDevice, plan1, plan2 };

            // Load some
            var schedules = cut.GetSchedules( TimeBias, Task ).Take( 5 ).ToArray();

            // Validate
            Assert.AreEqual( 5, schedules.Length, "Schedules" );
            Assert.AreSame( plan1, schedules[0].Definition, "Definition 1" );
            Assert.IsFalse( schedules[0].StartsLate, "Late 1" );
            Assert.AreSame( Task, schedules[1].Definition, "Definition 2" );
            Assert.IsTrue( schedules[1].StartsLate, "Late 2" );
            Assert.AreSame( Task, schedules[2].Definition, "Definition 3" );
            Assert.IsFalse( schedules[2].StartsLate, "Late 3" );
            Assert.AreEqual( TimeBias.ToLocalTime().Date.AddHours( 20 ).ToUniversalTime(), schedules[2].Time.Start, "Start 3" );
            Assert.AreSame( plan2, schedules[3].Definition, "Definition 4" );
            Assert.IsFalse( schedules[3].StartsLate, "Late 4" );
            Assert.AreSame( Task, schedules[4].Definition, "Definition 5" );
            Assert.IsFalse( schedules[4].StartsLate, "Late 5" );
            Assert.AreEqual( TimeBias.ToLocalTime().Date.AddDays( 1 ).AddHours( 10 ).ToUniversalTime(), schedules[4].Time.Start, "Start 5" );
        }