From 236558137dd72cbc0c77dc98bd7f9c0f387f1c71 Mon Sep 17 00:00:00 2001 From: TeoV Date: Thu, 7 May 2020 15:07:50 +0300 Subject: [PATCH] SetActionPlan verify default timingIDs first ( + tests ) --- apier/v1/apier.go | 84 ++++++++++++++++++++++++++---- apier/v1/apier2_it_test.go | 101 +++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 9 deletions(-) diff --git a/apier/v1/apier.go b/apier/v1/apier.go index f3c0e477d..8743d983a 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -669,14 +669,19 @@ func (apiv1 *APIerSv1) SetActionPlan(attrs AttrSetActionPlan, reply *string) (er return 0, fmt.Errorf("%s:%s", utils.ErrBrokenReference.Error(), apiAtm.ActionsId) } timing := new(engine.RITiming) - timing.Years.Parse(apiAtm.Years, ";") - timing.Months.Parse(apiAtm.Months, ";") - timing.MonthDays.Parse(apiAtm.MonthDays, ";") - timing.WeekDays.Parse(apiAtm.WeekDays, ";") - if !verifyFormat(apiAtm.Time) { - return 0, fmt.Errorf("%s:%s", utils.ErrUnsupportedFormat.Error(), apiAtm.Time) + if dfltTiming, isDefault := checkDefaultTiming(apiAtm.Time); isDefault { + timing = dfltTiming + } else { + timing.Years.Parse(apiAtm.Years, ";") + timing.Months.Parse(apiAtm.Months, ";") + timing.MonthDays.Parse(apiAtm.MonthDays, ";") + timing.WeekDays.Parse(apiAtm.WeekDays, ";") + if !verifyFormat(apiAtm.Time) { + return 0, fmt.Errorf("%s:%s", utils.ErrUnsupportedFormat.Error(), apiAtm.Time) + } + timing.StartTime = apiAtm.Time } - timing.StartTime = apiAtm.Time + ap.ActionTimings = append(ap.ActionTimings, &engine.ActionTiming{ Uuid: utils.GenUUID(), Weight: apiAtm.Weight, @@ -729,8 +734,6 @@ func (apiv1 *APIerSv1) SetActionPlan(attrs AttrSetActionPlan, reply *string) (er func verifyFormat(tStr string) bool { if tStr == utils.EmptyString || - tStr == utils.MetaEveryMinute || - tStr == utils.MetaHourly || tStr == utils.ASAP { return true } @@ -752,6 +755,69 @@ func verifyFormat(tStr string) bool { return true } +// checkDefaultTiming will check the tStr if it's of the the default timings ( the same as in TPReader ) +// and will compute it properly +func checkDefaultTiming(tStr string) (rTm *engine.RITiming, isDefault bool) { + startTime := time.Now().Format("15:04:05") + switch tStr { + case utils.MetaEveryMinute: + return &engine.RITiming{ + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{}, + StartTime: utils.ConcatenatedKey(utils.Meta, utils.Meta, strconv.Itoa(time.Now().Second())), + EndTime: "", + }, true + case utils.MetaHourly: + return &engine.RITiming{ + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{}, + StartTime: utils.ConcatenatedKey(utils.Meta, strconv.Itoa(time.Now().Minute()), strconv.Itoa(time.Now().Second())), + EndTime: "", + }, true + case utils.MetaDaily: + return &engine.RITiming{ + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{}, + StartTime: startTime, + EndTime: ""}, true + case utils.MetaWeekly: + return &engine.RITiming{ + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{time.Now().Weekday()}, + StartTime: startTime, + EndTime: "", + }, true + case utils.MetaMonthly: + return &engine.RITiming{ + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{time.Now().Day()}, + WeekDays: utils.WeekDays{}, + StartTime: startTime, + EndTime: "", + }, true + case utils.MetaYearly: + return &engine.RITiming{ + Years: utils.Years{}, + Months: utils.Months{time.Now().Month()}, + MonthDays: utils.MonthDays{time.Now().Day()}, + WeekDays: utils.WeekDays{}, + StartTime: startTime, + EndTime: "", + }, true + default: + return nil, false + } +} + type AttrGetActionPlan struct { ID string } diff --git a/apier/v1/apier2_it_test.go b/apier/v1/apier2_it_test.go index 5d35c8888..0b3bce3f0 100644 --- a/apier/v1/apier2_it_test.go +++ b/apier/v1/apier2_it_test.go @@ -28,6 +28,8 @@ import ( "testing" "time" + "github.com/cgrates/cgrates/scheduler" + "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/dispatchers" "github.com/cgrates/cgrates/engine" @@ -57,6 +59,7 @@ var ( testAPIerGetRatingPlanCost3, testAPIerGetActionPlanIDs, testAPIerGetRatingPlanIDs, + testAPIerSetActionPlanDfltTime, testAPIerKillEngine, } ) @@ -314,6 +317,104 @@ func testAPIerGetRatingPlanIDs(t *testing.T) { } } +func testAPIerSetActionPlanDfltTime(t *testing.T) { + var reply1 string + hourlyAP := &AttrSetActionPlan{ + Id: "AP_HOURLY", + ActionPlan: []*AttrActionPlan{ + &AttrActionPlan{ + ActionsId: "ACT_TOPUP_RST_10", + Time: utils.MetaHourly, + Weight: 20.0, + }, + }, + ReloadScheduler: true, + } + if err := apierRPC.Call(utils.APIerSv1SetActionPlan, hourlyAP, &reply1); err != nil { + t.Error("Got error on APIerSv1.SetActionPlan: ", err.Error()) + } else if reply1 != utils.OK { + t.Errorf("Calling APIerSv1.SetActionPlan received: %s", reply1) + } + dailyAP := &AttrSetActionPlan{ + Id: "AP_DAILY", + ActionPlan: []*AttrActionPlan{ + &AttrActionPlan{ + ActionsId: "ACT_TOPUP_RST_10", + Time: utils.MetaDaily, + Weight: 20.0, + }, + }, + ReloadScheduler: true, + } + if err := apierRPC.Call(utils.APIerSv1SetActionPlan, dailyAP, &reply1); err != nil { + t.Error("Got error on APIerSv1.SetActionPlan: ", err.Error()) + } else if reply1 != utils.OK { + t.Errorf("Calling APIerSv1.SetActionPlan received: %s", reply1) + } + weeklyAP := &AttrSetActionPlan{ + Id: "AP_WEEKLY", + ActionPlan: []*AttrActionPlan{ + &AttrActionPlan{ + ActionsId: "ACT_TOPUP_RST_10", + Time: utils.MetaWeekly, + Weight: 20.0, + }, + }, + ReloadScheduler: true, + } + if err := apierRPC.Call(utils.APIerSv1SetActionPlan, weeklyAP, &reply1); err != nil { + t.Error("Got error on APIerSv1.SetActionPlan: ", err.Error()) + } else if reply1 != utils.OK { + t.Errorf("Calling APIerSv1.SetActionPlan received: %s", reply1) + } + monthlyAP := &AttrSetActionPlan{ + Id: "AP_MONTHLY", + ActionPlan: []*AttrActionPlan{ + &AttrActionPlan{ + ActionsId: "ACT_TOPUP_RST_10", + Time: utils.MetaMonthly, + Weight: 20.0, + }, + }, + ReloadScheduler: true, + } + if err := apierRPC.Call(utils.APIerSv1SetActionPlan, monthlyAP, &reply1); err != nil { + t.Error("Got error on APIerSv1.SetActionPlan: ", err.Error()) + } else if reply1 != utils.OK { + t.Errorf("Calling APIerSv1.SetActionPlan received: %s", reply1) + } + var rply []*scheduler.ScheduledAction + if err := apierRPC.Call(utils.APIerSv1GetScheduledActions, + scheduler.ArgsGetScheduledActions{}, &rply); err != nil { + t.Error("Unexpected error: ", err) + } else { + for _, schedAct := range rply { + switch schedAct.ActionPlanID { + case "AP_WEEKLY": + if schedAct.NextRunTime.Before(time.Now().Add(167*time.Hour+59*time.Minute+58*time.Second)) || + schedAct.NextRunTime.After(time.Now().Add(168*time.Hour+1*time.Second)) { + t.Errorf("Expected the nextRuntime to be after 1 week,but received: <%+v>", utils.ToJSON(schedAct)) + } + case "AP_DAILY": + if schedAct.NextRunTime.Before(time.Now().Add(23*time.Hour+59*time.Minute+58*time.Second)) || + schedAct.NextRunTime.After(time.Now().Add(24*time.Hour+1*time.Second)) { + t.Errorf("Expected the nextRuntime to be after 1 day,but received: <%+v>", utils.ToJSON(schedAct)) + } + case "AP_HOURLY": + if schedAct.NextRunTime.Before(time.Now().Add(59*time.Minute+58*time.Second)) || + schedAct.NextRunTime.After(time.Now().Add(1*time.Hour+1*time.Second)) { + t.Errorf("Expected the nextRuntime to be after 1 hour,but received: <%+v>", utils.ToJSON(schedAct)) + } + case "AP_MONTHLY": + if schedAct.NextRunTime.Before(time.Now().AddDate(0, 1, 0).Add(-1*time.Second)) || + schedAct.NextRunTime.After(time.Now().AddDate(0, 1, 0).Add(1*time.Second)) { + t.Errorf("Expected the nextRuntime to be after 1 month,but received: <%+v>", utils.ToJSON(schedAct)) + } + } + } + } +} + func testAPIerKillEngine(t *testing.T) { if err := engine.KillEngine(*waitRater); err != nil { t.Error(err)