コード例 #1
0
    def test_odids(self):

        # FRS 10.4 setting originID and destinationID

        # 1) Creating the dictionary
        mission = TAMission.new('nl.1234')
        self.assertEqual(mission.odIDs_dictionary, {'d': [None, None]})

        # 2) Reading and writing
        mission.nominalDate = now_cet().date()
        mission.odIDs_dictionary['d'] = ['nl.asd', 'nl.ehv']
        mission.origin_id = 'nl.asd'
        mission.destination_id = 'nl.ehv'
        self.assertFalse(mission.needs_datastore_put)
        mission.put()
        mission = TAMission.get('nl.1234')
        self.assertEqual(mission.origin_id, 'nl.asd')
        self.assertEqual(mission.destination_id, 'nl.ehv')
        self.assertEqual(mission.get_odIDs_string(0), 'nl.asd-nl.ehv')
        self.assertEqual(len(mission.odIDs_dictionary), 1)

        mission.set_odIDs_string(5, 'nl.asd-nl.ht')
        mission.set_odIDs_string(6, '-')
        self.assertTrue(mission.needs_datastore_put)
        self.assertEqual(mission.get_odIDs_for_weekday(5), ['nl.asd', 'nl.ht'])
        self.assertEqual(mission.get_odIDs_for_weekday(6), [None, None])
        self.assertEqual(len(mission.odIDs_dictionary), 3)

        # 3) Optimizing the dictionary
        for weekday in range(6):
            mission.set_odIDs_string(weekday, 'nl.asd-nl.mt')
        self.assertEqual(len(mission.odIDs_dictionary), 8)
        mission.optimize_odIDs_dictionary()
        self.assertEqual(len(mission.odIDs_dictionary), 2)
        self.assertTrue(mission.needs_datastore_put)
コード例 #2
0
 def update_stops_from_file(self, filename):
     stops_file = open(filename, 'r')
     array = json.load(stops_file)
     for element in array:
         mission = TAMission.get(str(element['id']))
         stop = TAStop.fromRepr(element['payload'])
         mission.update_stop(stop)
コード例 #3
0
    def change_offsets(self, deltaOffsets):
        new_list = [[], []]
        processed_objects   = []
        processed_missions  = {}
        processed_points    = {}
        
        for point in self.points:
            point.upArrival += deltaOffsets[Direction.up]
            point.upDeparture += deltaOffsets[Direction.up]
            point.downArrival += deltaOffsets[Direction.down]
            point.downDeparture += deltaOffsets[Direction.down]
            processed_points[point.id] = point
            processed_objects.append(point)

        for direction in (Direction.up, Direction.down):
            if deltaOffsets[direction]:
                for missionID in self.all_mission_ids(direction):
                    mission = TAMission.get(missionID)
                    old_offset = datetime(2002, 2, 2).replace(hour=mission.offset_time.hour, minute=mission.offset_time.minute)
                    new_offset = round_mission_offset(old_offset - timedelta(minutes=deltaOffsets[direction]))
                    mission.offset_time = new_offset.time()
                    new_list[direction].append((mission.offset_time, mission.number))
                    processed_missions[missionID] = mission
                    processed_objects.append(mission)

        self._missions_list = new_list
        memcache.set_multi(processed_points, namespace='TAScheduledPoint')
        memcache.set_multi(processed_missions, namespace='TAMission')
        db.put(processed_objects)
        self.cache_set()
コード例 #4
0
def correctedOffsetUTC(archivedMission):
    ''' Replaces the offset time as stored in the TAArchivedMission with that from the corresponding TAMission,
        while retaining the date.
        '''
    originalMission = TAMission.get('%s.%d' % (archivedMission.country, archivedMission.baseNumber))
    offsetCET = mark_cet(datetime.combine(archivedMission.offset_CET.date(), originalMission.offset))
    return utc_from_cet(offsetCET)
コード例 #5
0
 def xml_missions(self):
     element = self.xml
     missions_tag = XMLElement('missions')
     for missionID in self.planned_mission_ids:
         mission = TAMission.get(missionID)
         missions_tag.add(mission.xml)
     element.add(missions_tag)
     return element
コード例 #6
0
    def test_mission_management(self):
        TASeries.import_xml('TestTASeries.data/series_005.xml')
        series = TASeries.get('nl.005')

        self.assertEqual(
            series.nr_of_missions, 12,
            "FRS 9.6.1 TASeries must show how much missions it contains")
        mission = TAMission.get('nl.300527', create=True)
        mission.put()
        series = TASeries.get('nl.005')
        self.assertEqual(
            series.nr_of_missions, 13,
            "FRS 9.6.2 TASeries must make it possible to add a new mission")
        expected = [
            'nl.523', 'nl.527', 'nl.300527', 'nl.531', 'nl.535', 'nl.539',
            'nl.543'
        ]
        result = series.all_mission_ids(Direction.up)
        self.assertEqual(
            expected, result,
            "FRS 9.6.3 TASeries must provide all missions belonging to a series.\nExpected: %s\nResult:   %s"
            % (expected, result))
        now = datetime(2011, 1, 11, 11, 11)
        expected = ['nl.527', 'nl.300527', 'nl.531', 'nl.535', 'nl.539']
        result = series.current_mission_ids(Direction.up, now)
        self.assertEqual(
            expected, result,
            "FRS 9.6.4 TASeries must provide its current missions.\nExpected: %s\nResult:   %s"
            % (expected, result))
        expected = ['nl.528', 'nl.532', 'nl.536']
        result = series.current_mission_ids(Direction.down, now)
        self.assertEqual(
            expected, result,
            "FRS 9.6.4 TASeries must provide its current missions.\nExpected: %s\nResult:   %s"
            % (expected, result))
        searchStart = datetime(2011, 1, 11, 8, 8)
        searchSpan = timedelta(hours=2)
        expected = [(datetime(2011, 1, 11, 8, 50), 'nl.527'),
                    (datetime(2011, 1, 11, 8, 50), 'nl.300527'),
                    (datetime(2011, 1, 11, 9, 50), 'nl.531')]
        result = series.relevant_mission_tuples('nl.ut',
                                                searchStart,
                                                searchSpan,
                                                destinationID='nl.zl')
        self.assertEqual(
            expected, result,
            "FRS 9.6.5 TASeries must provide a list of relevant missions.\nExpected: %s\nResult:   %s"
            % (expected, result))
        expected = [(datetime(2011, 1, 11, 8, 18), 'nl.524'),
                    (datetime(2011, 1, 11, 9, 18), 'nl.528')]
        result = series.relevant_mission_tuples('nl.zl',
                                                searchStart,
                                                searchSpan,
                                                destinationID='nl.ut')
        self.assertEqual(
            expected, result,
            "FRS 9.6.5 TASeries must provide a list of relevant missions.\nExpected: %s\nResult:   %s"
            % (expected, result))
コード例 #7
0
    def get(self):
        increase_counter('req_mission')
        mission_id = self.request.get('id')
        if not self.validateID(mission_id): return

        mission = TAMission.get(mission_id)
        if not mission:
            self.reject()
            return
        output_string = json.dumps(mission.repr)
        self.response.out.write(output_string)
コード例 #8
0
 def get_missions(self, direction, current=False):
     array = []
     if current:
         id_list = self.current_mission_ids(direction)
     else:
         id_list = self.all_mission_ids(direction)
     for missionID in id_list:
         mission = TAMission.get(missionID)
         if not mission:
             continue
         array.append(mission)
     return array
コード例 #9
0
 def statistics(cls, now=None):
     if now is None:
         now = now_cet()
     status_hist = {}
     delay_hist = {}
     for seriesID in TASeries.all_ids():
         series = TASeries.get(seriesID)
         for mission_id in series.current_mission_ids(Direction.up, now) + series.current_mission_ids(Direction.down, now):
             mission = TAMission.get(mission_id)
             status, delay = mission.status_at_time(now)
             data = MissionStatuses.s[status]
             status_hist[data] = status_hist.get(data, 0) + 1
             if status == MissionStatuses.running:
                 data = '%.0f' % delay
                 delay_hist[data] = delay_hist.get(data, 0) + 1
     return {'status': status_hist, 'delay': delay_hist, 'counter': counter_dict()}
コード例 #10
0
    def test_revoke_stops(self):
        """
        FRS 10.10 Revoking stops

        """
        # Load sample data:
        TSStation.update_stations('TestTAMission.data/stations.xml')
        TASeries.import_xml('TestTAMission.data/series.xml')

        mission = TAMission.get('nl.3046')
        mission.activate_mission(mark_cet(datetime(2013, 2, 18, 2)))
        self.assertEqual(len(mission.stops), 5)
        self.assertEqual(mission.origin_id, 'nl.ah')
        self.assertEqual(mission.destination_id, 'nl.asd')
        mission.put()

        # STEP 10a revoke Ede
        self.post_stops_from_file('TestTAMission.data/step_10_10a.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(len(mission.stops), 4)
        self.assertEqual(mission.origin_id, 'nl.ah')
        self.assertEqual(mission.destination_id, 'nl.asd')

        # ...and set a delay for Arnhem - this must not cause an error when revoking Arnhem
        self.assertEqual(mission.first_stop.station_id, 'nl.ah')
        self.assertEqual(mission.first_stop.delay_dep, 15.0)

        # STEP 10b revoke Arnhem
        self.post_stops_from_file('TestTAMission.data/step_10_10b.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(len(mission.stops), 3)
        self.assertEqual(mission.origin_id, 'nl.klp')

        # STEP 10c revoke Utrecht and Veenendaal De Klomp
        self.post_stops_from_file('TestTAMission.data/step_10_10c.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(len(mission.stops), 0)
        self.assertEqual(mission.origin_id, None)
        self.assertEqual(mission.destination_id, None)

        mission = TAMission.get('nl.3046')
        mission.activate_mission(mark_cet(datetime(2013, 2, 19, 2)))
        self.assertEqual(len(mission.stops), 8)
        self.assertEqual(mission.origin_id, 'nl.ah')
        self.assertEqual(mission.destination_id, 'nl.amr')
        mission.put()

        # STEP 10d reset Arnhem
        self.post_stops_from_file('TestTAMission.data/step_10_10d.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(len(mission.stops), 5)
        self.assertEqual(mission.origin_id, 'nl.ah')
        self.assertEqual(mission.destination_id, 'nl.asd')
        self.assertEqual(mission.stops[4].status,
                         StopStatuses.finalDestination)
コード例 #11
0
    def test_object_fetch(self):

        # Create sample data:
        missionData = ['nl.2641', 'nl.2642', 'nl.2643']
        for id in missionData:
            mission = TAMission.new(id)
            mission.put()

            # Fetch object url and parse as JSON:
            response = self.missionApp.get('/TAMission/%s' % id)
            dictionary = json.loads(response.body)
            self.assertEqual(dictionary['id'], id)

        # Fetch the catalog:
        response = self.missionApp.get('/TAMission')
        self.assertEqual(response.body, '["nl.2641", "nl.2642", "nl.2643"]')
コード例 #12
0
 def processMissions(self, missionIDs, direction, table):
     if self.deltaOffset[direction]:
         for missionID in missionIDs:
             # Change mission offset time:
             mission = TAMission.get(missionID)
             oldOffset = datetime(2002, 2, 2).replace(hour=mission.offset.hour, minute=mission.offset.minute)
             newOffset = round_mission_offset(oldOffset - timedelta(minutes=self.deltaOffset[direction]), self.round[direction])
             mission.offset = newOffset.time()
             
             # Add mission to queue for saveChanges
             self.processedMissions[missionID] = mission
             self.processedObjects.append(mission)
             
             # Report the changes:
             row = table.add_row()
             row.add_to_cell(0, missionID)
             row.add_to_cell(1, '%s %s %s' % (oldOffset.strftime('%H:%M'),
                                              change_string(-self.deltaOffset[direction]),
                                              newOffset.strftime('%H:%M')))
コード例 #13
0
    def test_import_export(self):
        """
        FRS 9.2 Importing and exporting a series

        """
        TASeries.import_xml('TestTASeries.data/series_basic.xml')

        # Supplementary missions must not appear in xml output
        mission = TAMission.get('nl.300546', create=True)
        mission.put()
        series = TASeries.get('nl.005')
        self.assertEqual(
            series.name, '500',
            "FRS 9.1.1 A TASeries name property must provide the series number in hundreds"
        )

        # FRS 9.3.1 A TASeries object must provide its contents in xml-format.
        input_xml = open('TestTASeries.data/series_basic.xml', 'r').read()
        output_xml = series.xml_document.write(lf=True)
        self.assertEqual(input_xml.strip(), output_xml.strip())
コード例 #14
0
    def startElement(self, name, attrs):
        self.data = []
        if name == 'series':
            id = attrs['id']
            logging.info('import series: %s', id)
            self.series = TASeries.new(id)
            self.series.type = attrs.get('type')
            self.routePoints = {}
        
        if self.series:
            if name == 'station':
                point = TAScheduledPoint.new_with(self.series.id, attrs['id'])
                point.km = float(attrs['km'])
                stationName = attrs.get('name', None)
                if stationName: point.stationName = stationName
                self.routePoints[attrs['id']] = point
            
            if name == 'up':
                point = self.routePoints[attrs['station']]
                point.upArrival = minutes_from_string(attrs['arr'])
                point.upDeparture = minutes_from_string(attrs['dep'])
                point.set_platform_string(Direction.up, attrs.get('platform', '-'))
            
            if name == 'down':
                point = self.routePoints[attrs['station']]
                point.downArrival = minutes_from_string(attrs['arr'])
                point.downDeparture = minutes_from_string(attrs['dep'])
                point.set_platform_string(Direction.down, attrs.get('platform', '-'))

            if name == 'mission':
                self.mission = TAMission.new(attrs['id'])
                self.mission.series_id = self.series.id
                self.mission.offset_string = attrs['offset']

            if self.mission:
                if name == 'od':
                    origin = attrs['from']
                    if origin == 'None': origin = None
                    destination = attrs['to']
                    if destination == 'None': destination = None
                    self.mission.odIDs_dictionary[str(attrs['day'])] = [origin, destination]
コード例 #15
0
 def analyzeOffset(self, missionIDs):
     self.offset = [None, None]
     self.data=[[], []]
     
     firstHalfHist = dict()
     firstHalfItems = 0
     secondHalfHist = dict()
     secondHalfItems = 0
     for missionID in missionIDs:
         mission = TAMission.get(missionID)
         num = mission.number
         if bool(num % 2): num -= 1
         key = mission.offset.minute
         if bool(num % 4):
             firstHalfHist[key] = firstHalfHist.get(key, 0) + 1
             firstHalfItems += 1
         else:
             secondHalfHist[key] = secondHalfHist.get(key, 0) + 1
             secondHalfItems += 1
     self.generateData(FIRST_HALF, firstHalfHist, firstHalfItems)
     self.generateData(SECND_HALF, secondHalfHist, secondHalfItems)
コード例 #16
0
    def perform(self):
        instruction = self.request.get('inst')

        if instruction == 'fetch':
            if self.resource:
                self.resource.import_schedule()
                self.response.out.write('<a href=\"/console/series?id=%s\">terug naar serie</a>' % self.resource.id)
            else:
                TASeries.import_xml('series.data/series.xml')
                self.redirect('/console/series')
            return

        if not self.resource:
            logging.warning('Resource not found.')
            return

        if instruction == 'new_day':
            now_string = self.request.get('now')
            if now_string:
                now = cet_from_string(self.request.get('now'))
            else:
                now = now_cet()
            self.resource.activate_new_day(now)

        elif instruction == 'delete_point':
            sender = self.request.get('sender')
            self.resource.delete_point(sender)
            self.response.out.write('<a href=\"/console/series?id=%s\">terug naar serie</a>' % self.resource.id)

        elif instruction == 'optimize_odids':
            changed_missions = []
            for mission in self.resource.up_missions + self.resource.down_missions:
                mission.optimize_odIDs_dictionary()
                if mission.needs_datastore_put:
                    changed_missions.append(mission)
            memcache.set_multi(TAMission.dictionary_from_list(changed_missions), namespace='TAMission')
            db.put(changed_missions)
            self.response.out.write('<a href=\"/console/missions?kind=pattern&series=%s\">terug naar serie</a>' %
                                    self.resource.id)
コード例 #17
0
    def test_new_day(self):
        """
        FRS 9.5 Activating new day
        FRS 9.8 Providing statistics
        """
        TSStation.update_stations('TestTASeries.data/stations_020.xml')
        TASeries.import_xml('TestTASeries.data/series_020.xml')

        supplementary_mission = TAMission.new('nl.302020')
        supplementary_mission.offset_cet = datetime(2013, 5, 17, 8, 0)
        series = TASeries.get('nl.020')
        series.add_mission(supplementary_mission)
        self.assertEqual(
            series.nr_of_missions, 14,
            "A supplementary mission must be added to the series")

        response = self.seriesApp.post('/TASeries/nl.020', {
            'inst': 'new_day',
            'now': '2013-05-18T02:00:00+0100'
        })
        self.assertEqual(response.status, '200 OK')
        series = TASeries.get('nl.020')
        self.assertEqual(series.nr_of_missions, 13,
                         "FRS 9.5.2 Supplementary missions must be removed")

        mission_2024 = TAMission.get('nl.2024')
        self.assertEqual(
            len(mission_2024.stops), 3,
            "FRS 9.5.3 Stops for the next day must be added to the mission")

        point_gd = TAScheduledPoint.get('nl.020_gd')
        self.assertEqual(point_gd.scheduled_times, (26, 27, 33, 34))
        self.assertEqual(point_gd.platform_list, [['10'], ['5']])

        self.update_stops_from_file('TestTASeries.data/stops_020.json')

        # FRS 9.8.1 TASeries must provide statistics
        result = TASeries.statistics(mark_cet(datetime(2013, 5, 18, 8, 30)))
        expected = {
            'status': {
                'running': 2
            },
            'delay': {
                '0': 1,
                '2': 1
            },
            'counter': {
                'mission_changes': 13,
                'mission_no_changes': 0,
                'mission_small_changes': 0,
                'req_api_success': 0,
                'req_api_total': 0,
                'req_avt_answered': 0,
                'req_avt_denied': 0,
                'req_check_confirmed': 0,
                'req_check_denied': 0,
                'req_check_refetched': 0,
                'req_check_revoked': 0,
                'req_departures': 0,
                'req_mission': 0,
                'req_prio_answered': 0,
                'req_prio_denied': 0,
                'req_trajectory': 0
            }
        }
        self.assertEqual(expected, result)

        response = self.seriesApp.post('/TASeries/nl.020', {
            'inst': 'new_day',
            'now': '2013-05-19T02:00:00+0100'
        })
        self.assertEqual(response.status, '200 OK')
        self.assertEqual(series.nr_of_missions, 13)

        chart = TAChart.get('nl.020_201320')
        expected = {
            'pattern_up': {
                'nl.gvc': {
                    '9': 2
                },
                'nl.gd': {
                    '30': 2
                },
                'nl.ut': {
                    '46': 2
                }
            },
            'pattern_down': {
                'nl.gd': {
                    '35': 11
                },
                'nl.gvc': {
                    '52': 11
                },
                'nl.ut': {
                    '14': 11
                }
            },
            'delay_up': {
                'nl.gvc': {
                    '0.0': 2
                },
                'nl.gd': {
                    '2.0': 2
                },
                'nl.ut': {
                    '0.0': 2
                }
            },
            'delay_down': {
                'nl.gd': {
                    '0.0': 8,
                    '2.0': 3
                },
                'nl.gvc': {
                    '0.0': 11
                },
                'nl.ut': {
                    '0.0': 11
                }
            },
            'platform_up': {
                'nl.gvc': {
                    '5': 2
                },
                'nl.gd': {
                    '4': 2
                },
                'nl.ut': {}
            },
            'platform_down': {
                'nl.gd': {
                    '8': 10,
                    '10': 1
                },
                'nl.gvc': {},
                'nl.ut': {
                    '9': 11
                }
            }
        }
        result = chart._dataDictionary
        self.assertEqual(
            expected, result,
            "FRS 9.5.1 Data over the past day must be processed in a chart.\nExpected: %s\nResult:   %s"
            % (expected, result))

        mission_2024 = TAMission.get('nl.2024')
        self.assertEqual(
            len(mission_2024.stops), 0,
            "FRS 9.5.3 Stops for the next day must be added to the mission")

        point_gd = TAScheduledPoint.get('nl.020_gd')
        self.assertEqual(
            point_gd.scheduled_times, (26, 27, 34, 35),
            "FRS 9.5.4 TAChart must verify points and modify when needed.")
        self.assertEqual(
            point_gd.platform_list, [['8'], ['4']],
            "FRS 9.5.4 TAChart must verify points and modify when needed.")

        # FRS 9.9 TASeries must delete references to a station
        taskq = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME)
        taskq.FlushQueue('default')
        series = TASeries.get('nl.020')
        self.assertEqual(len(series.points), 3)

        response = self.seriesApp.post('/TASeries/nl.020', {
            'inst': 'delete_point',
            'sender': 'nl.gd'
        })
        self.assertEqual(response.status, '200 OK')
        series = TASeries.get('nl.020')
        self.assertEqual(len(series.points), 2)
        tasks = taskq.GetTasks('default')
        self.assertEqual(len(tasks), 13)
コード例 #18
0
 def receive(self, dictionary):
     stop = TAStop.fromRepr(dictionary)
     mission = TAMission.get(self.resource_id, create=True)
     mission.update_stop(stop)
コード例 #19
0
    def test_discover_mission(self):
        # Load sample data:
        TSStation.update_stations('TestTAMission.data/stations.xml')
        TASeries.import_xml('TestTAMission.data/series.xml')

        # FRS 10.6 Discover new mission, from scratch
        self.post_stops_from_file('TestTAMission.data/step_10_6a.json')
        mission_orphan = TAMission.get('nl.9046')
        self.assertNotEqual(mission_orphan, None,
                            "FRS 10.6.1 TAMission must receive updates")
        self.assertEqual(len(mission_orphan.stops), 1,
                         "FRS 10.6.2 TAMission must create new mission")

        self.post_stops_from_file('TestTAMission.data/step_10_6b.json')
        self.post_stops_from_file('TestTAMission.data/step_10_6c.json')
        mission_orphan = TAMission.get('nl.9046')
        self.assertEqual(len(mission_orphan.stops), 3,
                         "FRS 10.6.3 TAMission must insert new stops")
        self.assertEqual(
            mission_orphan.stops[0].station_id, 'nl.ah',
            "FRS 10.6.3 TAMission must place stops in the right order")
        self.assertEqual(
            mission_orphan.stops[1].station_id, 'nl.klp',
            "FRS 10.6.3 TAMission must place stops in the right order")
        self.assertEqual(
            mission_orphan.stops[2].station_id, 'nl.ut',
            "FRS 10.6.3 TAMission must place stops in the right order")

        for stop in mission_orphan.stops:
            self.assertEqual(
                stop.status, StopStatuses.announced,
                "FRS 10.6.4 Updated stops must get 'announced' as status")

        memcache.delete('nl.9046', namespace='TAMission')
        mission_orphan = TAMission.get('nl.9046')
        self.assertEqual(
            len(mission_orphan.stops), 3,
            "FRS 10.6.5 After significant changes, missions must be stored in the datastore"
        )

        # FRS 10.7 Discover new mission, from series
        series = TASeries.get('nl.030')
        series.activate_new_day(mark_cet(datetime(2013, 2, 19, 2, 0)))

        # Check sample data
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(mission_44, None)

        # STEP 7a: insert Veenendaal De Klomp
        self.post_stops_from_file('TestTAMission.data/step_10_7a.json')
        mission_44 = TAMission.get('nl.3044')
        self.log_mission(mission_44)

        self.assertEqual(mission_44.series.id, 'nl.030')
        self.assertEqual(mission_44.offset_time.strftime('%H:%M'), '13:00')
        self.assertEqual(mission_44.origin_id, 'nl.klp')
        self.assertEqual(mission_44.destination_id, 'nl.asd')

        # FRS 10.7.3 Mission must create stops
        self.assertEqual(len(mission_44.stops), 3)
        stop_klp = mission_44.stops[0]
        self.assertEqual(stop_klp.station_id, 'nl.klp')
        self.assertEqual(stop_klp.status, StopStatuses.announced)
        self.assertEqual(stop_klp.departure.strftime('%H:%M'), '13:46')
        self.assertEqual(mission_44.stops[1].station_id, 'nl.ut')
        self.assertEqual(mission_44.stops[1].status, StopStatuses.planned)
        self.assertEqual(mission_44.stops[2].station_id, 'nl.asd')
        self.assertEqual(mission_44.stops[2].status,
                         StopStatuses.finalDestination)
        self.assertEqual(mission_44.odIDs, ['nl.klp', 'nl.asd'])

        # STEP 7b: insert Arnhem
        self.post_stops_from_file('TestTAMission.data/step_10_7b.json')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(mission_44.origin_id, 'nl.ah')
        self.assertEqual(mission_44.destination_id, 'nl.asd')

        # FRS 10.7.4 Mission must insert new stops prior to current stops
        self.assertEqual(len(mission_44.stops), 5)
        self.assertEqual(mission_44.stops[0].station_id, 'nl.ah')
        self.assertEqual(mission_44.stops[0].status, StopStatuses.announced)
        self.assertEqual(mission_44.stops[1].station_id, 'nl.ed')
        self.assertEqual(mission_44.stops[1].status, StopStatuses.planned)
        self.assertEqual(mission_44.stops[4].station_id, 'nl.asd')
        self.assertEqual(mission_44.stops[4].status,
                         StopStatuses.finalDestination)
        self.assertEqual(mission_44.odIDs, ['nl.ah', 'nl.asd'])

        # STEP 7c: update Ede Wageningen (should already be there)
        self.post_stops_from_file('TestTAMission.data/step_10_7c.json')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(mission_44.origin_id, 'nl.ah')
        self.assertEqual(mission_44.destination_id, 'nl.asd')

        # FRS 10.7.5 Mission must update stops
        self.assertEqual(len(mission_44.stops), 5)
        self.assertEqual(mission_44.stops[1].station_id, 'nl.ed')
        self.assertEqual(mission_44.stops[1].status, StopStatuses.announced)

        # FRS 10.7.6 Update from planned to announced may not cause datastore put
        memcache.delete('nl.3044', namespace='TAMission')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(len(mission_44.stops), 5)
        self.assertEqual(mission_44.stops[1].station_id, 'nl.ed')
        self.assertEqual(mission_44.stops[1].status, StopStatuses.planned)

        # STEP 7Rc: revoke Ede Wageningen
        self.post_stops_from_file('TestTAMission.data/step_10_7Rc.json')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(len(mission_44.stops), 4)

        # STEP 7c again: update Ede Wageningen, inserting a scheduled stop may not cause resetting of origin
        self.post_stops_from_file('TestTAMission.data/step_10_7c.json')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(len(mission_44.stops), 5)
        self.assertEqual(mission_44.origin_id, 'nl.ah')
        self.assertEqual(mission_44.destination_id, 'nl.asd')

        # STEP 7d: update Utrecht (should already be there)
        self.post_stops_from_file('TestTAMission.data/step_10_7d.json')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(mission_44.origin_id, 'nl.ah')
        self.assertEqual(mission_44.destination_id, 'nl.asd')

        self.assertEqual(len(mission_44.stops), 5)
        self.assertEqual(mission_44.stops[3].station_id, 'nl.ut')
        self.assertEqual(mission_44.stops[3].status, StopStatuses.announced)

        # STEP 7e: update Amsterdam (should already be there)
        self.post_stops_from_file('TestTAMission.data/step_10_7e.json')
        mission_44 = TAMission.get('nl.3044')

        # FRS 10.7.7 Mission must insert new stops after current stops
        self.assertEqual(len(mission_44.stops), 8)
        self.assertEqual(mission_44.stops[4].station_id, 'nl.asd')
        self.assertEqual(mission_44.stops[6].station_id, 'nl.zd')
        self.assertEqual(mission_44.stops[7].station_id, 'nl.amr')

        #FRS 10.7.8 Satus of last_stop must be finalDestination
        self.assertEqual(mission_44.stops[4].status, StopStatuses.announced)
        self.assertEqual(mission_44.stops[6].status, StopStatuses.planned)
        self.assertEqual(mission_44.stops[7].status,
                         StopStatuses.finalDestination)
        self.assertEqual(mission_44.odIDs, ['nl.ah', 'nl.amr'])

        # STEP 7f: insert Amstel (intermediate station, not in series)
        self.post_stops_from_file('TestTAMission.data/step_10_7f.json')
        mission_44 = TAMission.get('nl.3044')

        # FRS 10.7.9 Mission must receive intermediate stop
        self.assertEqual(len(mission_44.stops), 9)
        self.assertEqual(mission_44.stops[4].station_id, 'nl.asa')
        self.assertEqual(mission_44.odIDs, ['nl.ah', 'nl.amr'])

        # STEP 7g: insert Nijmegen (starting station, not in series)
        self.post_stops_from_file('TestTAMission.data/step_10_7g.json')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(mission_44.odIDs, ['nl.ah', 'nl.amr'])

        # FRS 10.7.10 Mission must receive new starting station
        self.assertEqual(len(mission_44.stops), 10)
        self.assertEqual(mission_44.stops[0].station_id, 'nl.nm')

        # STEP 7h: update Alkmaar (destination of series, but indicating a further destination)
        self.post_stops_from_file('TestTAMission.data/step_10_7h.json')
        mission_44 = TAMission.get('nl.3044')

        # FRS 10.7.11 Mission must receive finalDestination outside of series
        self.assertEqual(len(mission_44.stops), 10)
        self.assertEqual(mission_44.stops[9].station_id, 'nl.amr')
        self.assertEqual(mission_44.stops[9].status, StopStatuses.announced)
        self.assertEqual(mission_44.odIDs, ['nl.ah', 'nl.amr'])

        # STEP 7i: insert Schagen (after Alkmaar, not in series)
        self.post_stops_from_file('TestTAMission.data/step_10_7i.json')
        mission_44 = TAMission.get('nl.3044')

        # FRS 10.7.12/13 Mission must receive extra intermediate stop
        self.assertEqual(len(mission_44.stops), 11)
        self.assertEqual(mission_44.stops[10].station_id, 'nl.sgn')
        self.assertEqual(mission_44.stops[10].status, StopStatuses.extra)
        self.assertEqual(mission_44._odIDsDictionary, {
            '1': ['nl.ah', 'nl.amr'],
            'd': [None, None]
        })

        # STEP 7j: insert Veenendaal De Klomp for the next day
        self.post_stops_from_file('TestTAMission.data/step_10_7j.json')
        mission_44 = TAMission.get('nl.3044')
        self.assertEqual(mission_44.stops[3].station_id, 'nl.klp')
        self.assertEqual(mission_44.stops[3].departure.replace(tzinfo=None),
                         datetime(2013, 2, 19, 13, 46))

        # test counters
        self.assertEqual(read_counter('mission_changes'), 12)
        self.assertEqual(read_counter('mission_small_changes'), 2)
        self.assertEqual(read_counter('mission_no_changes'), 0)
コード例 #20
0
    def test_disruptions(self):
        # Load sample data:
        TSStation.update_stations('TestTAMission.data/stations.xml')
        TASeries.import_xml('TestTAMission.data/series.xml')
        mission = TAMission.get('nl.3046')
        self.assertNotEqual(mission, None)
        mission.activate_mission(mark_cet(datetime(2013, 2, 19, 2)))
        mission.put()
        taskq = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME)
        taskq.FlushQueue('default')

        # STEP 8a De Klomp +8
        self.post_stops_from_file('TestTAMission.data/step_10_8a.json')
        mission = TAMission.get('nl.3046')

        self.assertEqual(mission.stops[2].station_id, 'nl.klp')
        self.assertEqual(mission.stops[2].delay_dep, 8.0,
                         "FRS 10.8.1 Stop must receive delay in update")
        self.assertEqual(
            mission.next_stop_index(mark_cet(datetime(2013, 2, 19, 14, 0))), 0,
            "FRS 10.8.2 Stop must indicate current position")
        self.assertEqual(
            mission.next_stop_index(mark_cet(datetime(2013, 2, 19, 14, 20))),
            2, "FRS 10.8.2 Stop must indicate current position")
        self.assertEqual(
            mission.next_stop_index(mark_cet(datetime(2013, 2, 19, 14, 25))),
            3, "FRS 10.8.2 Stop must indicate current position")
        self.assertEqual(mission.delay, 0.0,
                         "FRS 10.8.5 Only nextStop must set mission delay")

        tasks = taskq.GetTasks('default')
        self.assertEqual(
            len(tasks), 1,
            "FRS 10.8.3 After receiving delay mission must queue task for current next stop"
        )
        task0 = tasks[0]
        self.assertEqual(task0['url'], '/agent/station/nl.ah')
        self.assertEqual(task0['name'], '19_1300_41_prio_3046')
        taskq.FlushQueue('default')

        # STEP 8b Arnhem +10
        self.post_stops_from_file('TestTAMission.data/step_10_8b.json')
        mission = TAMission.get('nl.3046')

        self.assertEqual(mission.stops[0].station_id, 'nl.ah')
        self.assertEqual(mission.stops[0].delay_dep, 5.0,
                         "FRS 10.8.1 Stop must receive delay in update")
        self.assertEqual(mission.stops[1].station_id, 'nl.ed')
        self.assertAlmostEqual(
            mission.stops[1].delay_dep,
            4.0,
            places=1,
            msg="FRS 10.8.4 Mission must adapt delay in next stops")
        self.assertAlmostEqual(
            mission.stops[2].delay_dep,
            8.0,
            places=1,
            msg="FRS 10.8.6 With increasing delay, values may only be increased"
        )
        self.assertEqual(mission.stops[3].station_id, 'nl.ut')
        self.assertAlmostEqual(
            mission.stops[3].delay_dep,
            0.4,
            places=1,
            msg="FRS 10.8.4 Mission must adapt delay in next stops")
        self.assertEqual(mission.stops[4].station_id, 'nl.asd')
        self.assertEqual(mission.stops[4].delay_dep, 0.0,
                         "FRS 10.8.1 Stop must receive delay in update")
        self.assertEqual(mission.delay, 5.0,
                         "FRS 10.8.5 nextStop must set mission delay")

        tasks = taskq.GetTasks('default')
        self.assertEqual(len(tasks), 6)
        task0 = tasks[0]
        self.assertEqual(task0['url'], '/agent/station/nl.ed')
        self.assertEqual(task0['name'], '19_1309_xx_prio_3046')
        taskq.FlushQueue('default')

        # STEP 8c Arnhem +15
        self.post_stops_from_file('TestTAMission.data/step_10_8c.json')
        mission = TAMission.get('nl.3046')

        self.assertAlmostEqual(
            mission.stops[1].delay_dep,
            14.0,
            places=1,
            msg="FRS 10.8.4 Mission must adapt delay in next stops")
        self.assertAlmostEqual(
            mission.stops[2].delay_dep,
            13.5,
            places=1,
            msg="FRS 10.8.4 Mission must adapt delay in next stops")

        tasks = taskq.GetTasks('default')
        self.assertEqual(len(tasks), 5)
        taskq.FlushQueue('default')

        # STEP 8d Arnhem +0
        self.post_stops_from_file('TestTAMission.data/step_10_8d.json')
        mission = TAMission.get('nl.3046')

        for stop in mission.stops:
            self.assertEqual(stop.delay_dep, 0.0)
        self.assertEqual(mission.delay, 0.0,
                         "FRS 10.8.5 nextStop must set mission delay")

        # STEP 9a Zaandam canceled
        self.post_stops_from_file('TestTAMission.data/step_10_9a.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(mission.stops[6].station_id, 'nl.zd')
        self.assertEqual(mission.stops[6].status, StopStatuses.canceled,
                         "FRS 10.9.1 Stop must be marked canceled")

        tasks = taskq.GetTasks('default')
        self.assertEqual(
            len(tasks), 1,
            "FRS 10.9.2 Must send priority update to neighbour station")
        task0 = tasks[0]
        self.assertEqual(task0['url'], '/agent/station/nl.ass')
        taskq.FlushQueue('default')

        # STEP 9b Zaandam reconfirmed
        self.post_stops_from_file('TestTAMission.data/step_10_9b.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(mission.stops[6].status, StopStatuses.announced,
                         "FRS 10.9.3 Stop must be marked announced")

        tasks = taskq.GetTasks('default')
        self.assertEqual(
            len(tasks), 2,
            "FRS 10.9.4 Must send priority update to neighbour station")

        task0 = tasks[0]
        self.assertEqual(task0['url'], '/agent/station/nl.asd')
        task1 = tasks[1]
        self.assertEqual(task1['url'], '/agent/station/nl.ass')
        taskq.FlushQueue('default')

        # STEP 9c altDestination for orphaned mission and non-existing altDestination (may not cause errors)
        self.post_stops_from_file('TestTAMission.data/step_10_9c.json')

        # STEP 9d Utrecht says Amsterdam is altDestination
        self.post_stops_from_file('TestTAMission.data/step_10_9d.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(mission.stops[4].status, StopStatuses.altDestination,
                         "FRS 10.9.5 Stop must be shortened")
        for index in range(5, 8):
            self.assertEqual(mission.stops[index].status,
                             StopStatuses.canceled,
                             "FRS 10.9.5 Stop must be shortened")

        tasks = taskq.GetTasks('default')
        self.assertEqual(
            len(tasks), 1,
            "FRS 10.9.6 Must send priority update to altered Destination")
        task0 = tasks[0]
        self.assertEqual(task0['url'], '/agent/station/nl.asd')

        # STEP 9e Amsterdam says Alkmaar is finalDestination > FRS 10.9.7
        self.post_stops_from_file('TestTAMission.data/step_10_9e.json')
        mission = TAMission.get('nl.3046')
        self.assertEqual(mission.stops[4].status, StopStatuses.announced)
        self.assertEqual(mission.stops[5].status, StopStatuses.planned)
        self.assertEqual(mission.stops[6].status, StopStatuses.planned)
        self.assertEqual(mission.stops[7].status,
                         StopStatuses.finalDestination)

        # STEP 9f
        self.post_stops_from_file('TestTAMission.data/step_10_9f.json')
        mission = TAMission.get('nl.3046')
        self.log_mission(mission)
        mission_s = TAMission.get('nl.303046')
        self.log_mission(mission_s)

        # STEP 9g
        self.post_stops_from_file('TestTAMission.data/step_10_9g.json')
        mission = TAMission.get('nl.3046')
        self.log_mission(mission)
        mission_s = TAMission.get('nl.303046')
        self.log_mission(mission_s)

        # test counters
        self.assertEqual(read_counter('mission_changes'), 15)
        self.assertEqual(read_counter('mission_small_changes'), 0)
        self.assertEqual(read_counter('mission_no_changes'), 0)
コード例 #21
0
    def test_activate_mission(self):
        """
        FRS 10.5 Activating a mission and maintaining its status

        """
        # Load sample data:
        TSStation.update_stations('TestTAMission.data/stations.xml')
        TASeries.import_xml('TestTAMission.data/series.xml')

        taskq = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME)

        # FRS 10.5.1 If not specified, activate_mission must set nominalDate to the current date
        now = now_cet().replace(hour=2)
        mission = TAMission.get('nl.3046')
        mission.activate_mission()
        self.assertEqual(mission.nominalDate, now.date())
        taskq.FlushQueue('default')

        # FRS 10.5.2/3 activate_mission must generate origin_id, destination_id and stops
        test_set = ((mark_cet(datetime(2013, 2, 24, 2)), None,
                     0), (mark_cet(datetime(2013, 2, 18, 2)), 'nl.asd', 5),
                    (mark_cet(datetime(2013, 2, 19, 2)), 'nl.amr', 8))
        for (testDate, destination, nr_of_stops) in test_set:
            mission.activate_mission(testDate)
            self.assertEqual(mission.destination_id, destination)
            self.assertEqual(len(mission.stops), nr_of_stops)
        mission.put()
        self.assertEqual(mission.origin_id, 'nl.ah')
        self.assertEqual(mission.last_stop.arrival_string, '15:48')

        # FRS 10.5.4 activated stops must get 'planned' status, last stop 'finalDestination'
        for index in range(0, 6):
            self.assertEqual(mission.stops[index].status, StopStatuses.planned)
        self.assertEqual(mission.stops[7].status,
                         StopStatuses.finalDestination)

        # FRS 10.5.5 TAMission must queue a check-task while awaking a mission.
        tasks = taskq.GetTasks('default')
        self.assertEqual(len(tasks), 2)
        self.assertEqual(tasks[1]['url'], '/TAMission/nl.3046')
        self.assertEqual(tasks[1]['name'], '19_1231_xx_check_3046')
        taskq.FlushQueue('default')

        # FRS 10.5.6 Mission must check announcement of stops
        check_time = mark_cet(datetime(2013, 2, 19, 13, 41, 22))
        mission.stops[0].status = StopStatuses.announced
        mission.check_mission_announcements(check_time)
        tasks = taskq.GetTasks('default')
        self.assertEqual(len(tasks), 2)
        self.assertEqual(tasks[0]['url'], '/agent/station/nl.ed')
        self.assertEqual(tasks[0]['name'], '19_1241_25_check_3046')
        self.assertEqual(tasks[1]['url'], '/TAMission/nl.3046')
        self.assertEqual(tasks[1]['name'], '19_1246_xx_check_3046')
        taskq.FlushQueue('default')

        check_time = mark_cet(datetime(2013, 2, 19, 14, 02, 22))
        mission.stops[0].status = StopStatuses.planned
        mission.stops[1].status = StopStatuses.announced
        mission.stops[2].status = StopStatuses.announced
        mission.stops[3].status = StopStatuses.announced
        mission.stops[4].status = StopStatuses.announced
        mission.check_mission_announcements(check_time)
        tasks = taskq.GetTasks('default')
        self.assertEqual(len(tasks), 1)
        self.assertEqual(tasks[0]['url'], '/TAMission/nl.3046')
        self.assertEqual(tasks[0]['name'], '19_1348_xx_check_3046')

        # FRS 10.5.7 Mission must provide status and delay
        (status,
         delay) = mission.status_at_time(mark_cet(datetime(2013, 2, 19, 14,
                                                           0)))
        self.assertEqual(status, MissionStatuses.inactive)
        self.assertEqual(delay, 0)
        mission.first_stop.status = StopStatuses.announced
        (status,
         delay) = mission.status_at_time(mark_cet(datetime(2013, 2, 19, 14,
                                                           0)))
        self.assertEqual(delay, 0)
        self.assertEqual(status, MissionStatuses.announced)
        (status, delay) = mission.status_at_time(
            mark_cet(datetime(2013, 2, 19, 14, 30)))
        self.assertEqual(status, MissionStatuses.running)
        self.assertEqual(delay, 0)
        (status, delay) = mission.status_at_time(
            mark_cet(datetime(2013, 2, 19, 15, 49)))
        self.assertEqual(mission.est_arrival_cet,
                         mark_cet(datetime(2013, 2, 19, 15, 48)))
        self.assertEqual(status, MissionStatuses.arrived)
        self.assertEqual(MissionStatuses.s[status], 'arrived')
        self.assertEqual(delay, 0)
コード例 #22
0
    def get(self):
        mission_id = self.request.get('mission')
        series_id = self.request.get('series')

        if mission_id:
            the_mission = TAMission.get(mission_id)

            if the_mission.up:
                label = 'heen'
            else:
                label = 'terug'
            document = ConsoleDocument('Trein %d (%s)' % (the_mission.number, label))
            the_series = the_mission.series
            if the_series:
                label = '%d treinen in serie %s' % (the_series.nr_of_missions, the_series.name)
                document.add_reference('/console/missions?kind=active&series=%s' % the_series.id, label)
            table = document.add_table('stops_table', ['s', 'A', 'V', 'dV', 'station', 'perron'])
            for the_stop in the_mission.stops:
                row = table.add_row()
                row.add_to_cell(0, the_stop.status)
                row.add_to_cell(1, the_stop.arrival_string)
                row.add_to_cell(2, the_stop.departure_string)
                delay = the_stop.delay_dep
                if delay > 0:
                    row.add_to_cell(3, '+%d' % delay)
                else:
                    row.add_to_cell(3, '-')
                row.add_link_to_cell(4, '/console/departures?station=%s' % the_stop.station.code, the_stop.station.name)
                if the_stop.platformChange:
                    row.add_to_cell(5, '%s <<' % the_stop.platform)
                else:
                    row.add_to_cell(5, the_stop.platform)
            self.response.out.write(document.write())

        elif series_id:
            the_series = TASeries.get(series_id)
            up = self.request.get('direction') != 'down'
            if up:
                label = 'heen'
                reverse = 'down'
                reverse_label = 'toon terugrichting'
                points_list = the_series.points
            else:
                label = 'terug'
                reverse = 'up'
                reverse_label = 'toon heenrichting'
                points_list = reversed(the_series.points)

            document = ConsoleDocument('Treinserie %s (%s)' % (the_series.name, label))
            document.add_reference('/console/schedule?series=%s&direction=%s' % (series_id, reverse),reverse_label)
            table = document.add_table('stops_table', ['km', 'station', 'aankomst', 'vertrek', 'perron', 'Jan', 'Feb'])
            for point in points_list:
                row = table.add_row()
                row.add_to_cell(0, '%.1f' % point.km)
                row.add_to_cell(1, point.stationName)
                if up:
                    row.add_to_cell(2, str(point.upArrival))
                    row.add_to_cell(3, str(point.upDeparture))
                    row.add_to_cell(4, point.platform_string(Direction.up))
                    avarage, delay = point.delayStats(Direction.up, 1)
                    if avarage != None:
                        row.add_to_cell(5, '%.1f - %.1f' % (avarage, delay))
                    avarage, delay = point.delayStats(Direction.up, 2)
                    if avarage != None:
                        row.add_to_cell(6, '%.1f - %.1f' % (avarage, delay))
                else:
                    row.add_to_cell(2, str(point.downArrival))
                    row.add_to_cell(3, str(point.downDeparture))
                    row.add_to_cell(4, point.platform_string(Direction.down))
                    avarage, delay = point.delayStats(Direction.down, 1)
                    if avarage != None:
                        row.add_to_cell(5, '%.1f - %.1f' % (avarage, delay))
                    avarage, delay = point.delayStats(Direction.down, 2)
                    if avarage != None:
                        row.add_to_cell(6, '%.1f - %.1f' % (avarage, delay))
            self.response.out.write(document.write())
コード例 #23
0
    def test_mission_basics(self):

        # Create series
        series_d14 = TASeries.new('eu.d14')
        series_d14.put()
        series123 = TASeries.new('nl.123')
        series123.put()
        memcache.delete('nl.123', namespace='TASeries')

        # Create international train
        mission241 = TAMission.get('eu.241', create=True)
        mission241.nominalDate = date(2010, 1, 31)
        mission241.offset_time = time(12, 0)
        self.assertTrue(
            mission241.needs_datastore_put,
            "FRS 10.3.7 After changing offset_time mission must be marked as needs_datastore_put"
        )
        mission241.put()

        # Create standard up train
        mission12301 = TAMission.get(code='12301', create=True)
        mission12301.offset_cet = mark_cet(datetime(2010, 1, 31, 14))
        mission12301.delay = 5.0
        self.assertTrue(
            mission12301.needs_datastore_put,
            "FRS 10.3.7 After changing offset_time mission must be marked as needs_datastore_put"
        )
        mission12301.put()

        series123 = mission12301.series
        self.assertEqual(series123.id, 'nl.123')

        # Create orphaned down train
        mission12402 = TAMission.get(code='12402', create=True)
        mission12402.put()

        # Create supplementary mission
        mission312301 = TAMission.get(code='312301', create=True)
        self.assertFalse(mission312301.needs_datastore_put,
                         "Supplementary mission need no datastore put")

        # FRS 10.1 Mission creation
        self.assertNotEqual(
            mission12301, None,
            "FRS 10.1.1 A mission must be created with the get command")
        self.assertEqual(
            mission241.series_id, 'eu.d14',
            "FRS 10.1.2 Trainnumbers lower than 500 must be international trains"
        )
        self.assertEqual(
            mission12301.series_id, 'nl.123',
            "FRS 10.1.3 At creation, the correct series must be assigned")
        self.assertEqual(
            mission312301.series_id, 'nl.123',
            "FRS 10.1.3 At creation, the correct series must be assigned")
        self.assertEqual(
            mission12402.series_id, 'orphan',
            "FRS 10.1.3 When the corresponding series does not exist, the mission must be marked as orphan"
        )

        # FRS 10.2 Properties deduced from train number
        self.assertTrue(mission12301.up,
                        "FRS 10.2.1 Missions with odd numbers are running up")
        self.assertFalse(
            mission12402.up,
            "FRS 10.2.1 Missions with even numbers are running down")
        self.assertEqual(
            mission241.ordinal, 1,
            "FRS 10.2.2 In international trains the last digit is the ordinal")
        self.assertEqual(
            mission12402.ordinal, 2,
            "FRS 10.2.2 In normal trains the last two digits are the ordinal")
        self.assertEqual(mission241.series_number, 24,
                         "FRS 10.2.3 TAMission must deduce the series number")
        self.assertEqual(mission12301.series_number, 123,
                         "FRS 10.2.3 TAMission must deduce the series number")
        self.assertEqual(mission312301.series_number, 123,
                         "FRS 10.2.3 TAMission must deduce the series number")
        self.assertEqual(
            mission12301.base_number, 12301,
            "FRS 10.2.4 The last five digits form the base number")
        self.assertEqual(
            mission312301.base_number, 12301,
            "FRS 10.2.4 The last five digits form the base number")
        self.assertFalse(
            mission12301.supplementary,
            "FRS 10.2.5 Missions with five digit numbers are not supplementary"
        )
        self.assertEqual(
            mission312301.supplementary, 3,
            "FRS 10.2.5 Missions with six digit numbers are supplementary")

        # FRS 10.3 Setting nominalDate and offset_time
        self.assertEqual(mission12301.nominalDate, date(2010, 1, 31),
                         "FRS 10.3.1 TAMission must provide nominalDate")
        self.assertEqual(mission12301.date_string, '31-01-2010',
                         "FRS 10.3.2 TAMission must provide dateString")
        self.assertEqual(mission12301.offset_time, time(14),
                         "FRS 10.3.3 TAMission must provide offset_time")
        self.assertEqual(mission12301.offset_string, '14:00',
                         "FRS 10.3.4 TAMission must provide offsetString")
        self.assertEqual(mission241.offset_cet,
                         mark_cet(datetime(2010, 1, 31, 12)),
                         "FRS 10.3.5 TAMission must provide offset_cet")

        self.assertEqual(
            mission312301.offset_time, time(14),
            "Supplementary mission must copy original mission offset")
        self.assertEqual(mission312301.delay, 0.0)

        testSet = (('09:57', '09:57'), ('09:58', '10:00'), ('10:02', '10:00'),
                   ('10:03', '10:03'), ('10:27', '10:27'), ('10:28', '10:30'),
                   ('10:32', '10:30'), ('10:33', '10:33'))
        for (timeIn, timeOut) in testSet:
            mission12301.offset_cet = mark_cet(
                datetime.strptime('2010-01-31T' + timeIn, '%Y-%m-%dT%H:%M'))
            self.assertEqual(
                mission12301.offset_string, timeOut,
                "FRS 10.3.6 offset_time must be rounded within two minutes %s -> %s"
                % (timeIn, timeOut))

        # Missions must be registered correctly
        series_d14 = TASeries.get('eu.d14')
        self.assertEqual(series_d14.all_mission_ids(Direction.up), ['eu.241'])
        series123 = TASeries.get('nl.123')
        self.assertEqual(series123.all_mission_ids(Direction.up),
                         ['nl.12301', 'nl.312301'])