def test_exceptions(self): # L needs year, month and daya params self.assertRaises(ValueError, WeekdaySetBuilder().build, "1L") self.assertRaises(ValueError, WeekdaySetBuilder(year=2016, month=10, day=4).build, "0#6") self.assertRaises(ValueError, WeekdaySetBuilder(year=2016, month=10, day=4).build, "0#0")
def build_schedule_from_maintenance_window(period_str): """ Builds a Instance running schedule based on an RDS preferred maintenance windows string in format ddd:hh:mm-ddd:hh:mm :param period_str: rds maintenance windows string :return: Instance running schedule with timezone UTC """ # get elements of period start_string, stop_string = period_str.split("-") start_day_string, start_hhmm_string = start_string.split(":", 1) stop_day_string, stop_hhmm_string = stop_string.split(":", 1) # weekday set builder weekdays_builder = WeekdaySetBuilder() start_weekday = weekdays_builder.build(start_day_string) start_time = SchedulerConfigBuilder.get_time_from_string(start_hhmm_string) end_time = SchedulerConfigBuilder.get_time_from_string(stop_hhmm_string) # windows with now day overlap, can do with one period for schedule if start_day_string == stop_day_string: periods = [ { "period": RunningPeriod(name=MAINTENANCE_PERIOD_NAME, begintime=start_time, endtime=end_time, weekdays=start_weekday) }] else: # window with day overlap, need two periods for schedule end_time_day1 = SchedulerConfigBuilder.get_time_from_string("23:59") begin_time_day2 = SchedulerConfigBuilder.get_time_from_string("00:00") stop_weekday = weekdays_builder.build(stop_day_string) periods = [ { "period": RunningPeriod(name=MAINTENANCE_PERIOD_NAME + "-{}".format(start_day_string), begintime=start_time, endtime=end_time_day1, weekdays=start_weekday), "instancetype": None }, { "period": RunningPeriod(name=MAINTENANCE_PERIOD_NAME + "-{}".format(stop_day_string), begintime=begin_time_day2, endtime=end_time, weekdays=stop_weekday), "instancetype": None }] # create schedule with period(s) and timezone UTC schedule = InstanceSchedule(name=MAINTENANCE_SCHEDULE_NAME, periods=periods, timezone="UTC", enforced=True) return schedule
def _build_period(cls, period_configuration, dt): def get_periodname(config): period_name = config.get(configuration.NAME) if not period_name: raise ValueError(MSG_NAME_MISSING_IN_PERIOD.format(config)) return period_name # reads a start and end time from config def get_begin_and_end(period_name, config): begin = SchedulerConfigBuilder.get_time_from_string( config.get(configuration.BEGINTIME)) end = SchedulerConfigBuilder.get_time_from_string( config.get(configuration.ENDTIME)) if (begin and end) and begin > end: raise ValueError( MSG_BEGIN_MUST_BEFORE_END.format(begin, end, period_name)) return begin, end def build_period_config_set(period_config, set_builder, config_name): config_set = period_config.get(config_name) if config_set: return set_builder.build(config_set) else: return None name = get_periodname(period_configuration) begin_time, end_time = get_begin_and_end(name, period_configuration) week_days = build_period_config_set( period_configuration, WeekdaySetBuilder(year=dt.year, month=dt.month, day=dt.day), configuration.WEEKDAYS) months = build_period_config_set(period_configuration, MonthSetBuilder(), configuration.MONTHS) monthdays = build_period_config_set( period_configuration, MonthdaySetBuilder(year=dt.year, month=dt.month), configuration.MONTHDAYS) return RunningPeriod(name=name, begintime=begin_time, endtime=end_time, weekdays=week_days, months=months, monthdays=monthdays)
def test_weekday_numbered(self): for year in [2016, 2017]: for month in range(1, 13): weekday, days_in_month = calendar.monthrange(year, month) for day in range(1, days_in_month + 1): num = int((day - 1) / 7) + 1 builder = WeekdaySetBuilder(year=year, month=month, day=day) tested_by_name = builder.build(calendar.day_abbr[weekday] + "#" + str(num)) self.assertEquals(tested_by_name, {weekday}) tested_by_value = builder.build( str(weekday) + "#" + str(num)) self.assertEquals(tested_by_value, {weekday}) for other_weekday in range(0, 7): if other_weekday != weekday: tested_by_name = builder.build( calendar.day_abbr[other_weekday] + "#" + str(num)) self.assertEquals(tested_by_name, set()) tested_by_value = builder.build( str(other_weekday) + "#" + str(num)) self.assertEquals(tested_by_value, set()) for other_num in range(1, 6): if num != other_num: tested_by_name = builder.build( calendar.day_abbr[weekday] + "#" + str(other_num)) self.assertEquals(tested_by_name, set()) tested_by_value = builder.build( str(weekday) + "#" + str(other_num)) self.assertEquals(tested_by_value, set()) weekday = (weekday + 1) % 7
def test_L_wildcard(self): for year in [2016, 2017]: for month in range(1, 13): weekday, days_in_month = calendar.monthrange(year, month) for tested_on_day in range(1, days_in_month + 1): builder = WeekdaySetBuilder(year=year, month=month, day=tested_on_day) # test by name of weekday day_num_l = calendar.day_abbr[weekday] + "L" tested_by_name = builder.build(day_num_l) # test by number of weekday day_value_l = str(weekday) + "L" tested_by_value = builder.build(day_value_l) # everything before last week should be empty set if tested_on_day <= (days_in_month - 7): self.assertEquals(tested_by_name, set()) self.assertEquals(tested_by_value, set()) else: # in last week the set should contain the day self.assertEquals(tested_by_name, {weekday}) self.assertEquals(tested_by_value, {weekday}) # test if ofther weekdays on that day return empty set for d in range(0, 6): if d != weekday: day_num_l = calendar.day_abbr[d] + "L" day_value_l = str(d) + "L" self.assertEquals(builder.build(day_num_l), set()) self.assertEqual(builder.build(day_value_l), set()) weekday = (weekday + 1) % 7
def _validate_period(self, **period): result = {} def is_valid_time(s): return re.match(ConfigAdmin.TIME_REGEX, s) is not None # allowed and validated parameters valid_parameters = [ configuration.BEGINTIME, configuration.ENDTIME, configuration.WEEKDAYS, configuration.MONTHDAYS, configuration.MONTHS, configuration.NAME, configuration.DESCRIPTION ] for attr in period: # indicates type for config entry if attr == ConfigAdmin.TYPE_ATTR: continue # parameter is allowed? if attr not in valid_parameters: raise ValueError( ERR_PERIOD_UNKNOWN_PARAMETER.format( attr, str(valid_parameters))) # remove None values if period[attr] is None or len(str(period[attr])) == 0: continue # period name if attr == configuration.NAME: result[attr] = period[attr] continue # description if attr == configuration.DESCRIPTION: result[attr] = period[attr] continue # validate start and end types times if attr in [configuration.BEGINTIME, configuration.ENDTIME]: time_str = period[attr] if not is_valid_time(time_str): raise ValueError( ERR_PERIOD_INVALID_TIME.format(attr, time_str)) result[attr] = str( datetime.strptime(time_str, configuration.TIME_FORMAT_STRING).time() )[0:len(configuration.TIME_FORMAT_STRING)] if configuration.BEGINTIME in result and configuration.ENDTIME in result: begintime = datetime.strptime( result[configuration.BEGINTIME], configuration.TIME_FORMAT_STRING).time() endtime = datetime.strptime( result[configuration.ENDTIME], configuration.TIME_FORMAT_STRING).time() if begintime > endtime: raise ValueError( ERR_PERIOD_BEGIN_LATER_THAN_END.format( result[configuration.BEGINTIME], result[configuration.ENDTIME])) continue # check weekdays, monthdays and month sets if attr in [ configuration.WEEKDAYS, configuration.MONTHDAYS, configuration.MONTHS ]: temp = self._ensure_set(period[attr]) if len(temp) == 0: continue # validate month if attr == configuration.MONTHS: # noinspection PyPep8 try: MonthSetBuilder().build(temp) result[attr] = temp continue except: raise ValueError( ERR_PERIOD_INVALID_MONTHS.format(str( period[attr]))) # validate weekdays if attr == configuration.WEEKDAYS: try: wdb = WeekdaySetBuilder(year=2016, month=12, day=31) wdb.build(temp) result[attr] = temp continue except Exception as ex: raise ValueError( ERR_PERIOD_INVALID_WEEKDAYS.format( str(period[attr]), ex)) # validate monthdays if attr == configuration.MONTHDAYS: # noinspection PyPep8 try: MonthdaySetBuilder(year=2016, month=12).build(temp) result[attr] = temp continue except: raise ValueError( ERR_PERIOD_INVALID_MONTHDAYS.format( str(period[attr]))) if configuration.NAME not in result: raise ValueError(ERR_NAME_PARAM_MISSING) for condition in [ configuration.BEGINTIME, configuration.ENDTIME, configuration.WEEKDAYS, configuration.MONTHS, configuration.MONTHDAYS ]: if condition in result: break else: raise ValueError(ERR_NO_PERIODS) result[ConfigAdmin.TYPE_ATTR] = configuration.PERIOD return result
def test_name(self): for i, day_name in enumerate(calendar.day_abbr): self.assertEqual(WeekdaySetBuilder().build(day_name), {i}) for i, day_name in enumerate(calendar.day_name): self.assertEqual(WeekdaySetBuilder().build(day_name), {i})
def test_value(self): for i in range(0, len(calendar.day_abbr) - 1): self.assertEqual(WeekdaySetBuilder().build(str(i)), {i})