diff --git a/apier/v1/trends.go b/apier/v1/trends.go index 755e94298..890541a77 100644 --- a/apier/v1/trends.go +++ b/apier/v1/trends.go @@ -41,6 +41,16 @@ func (apierSv1 *APIerSv1) GetTrendProfile(ctx *context.Context, arg *utils.Tenan return } +// GetTrendProfiles returns a list of Trendprofiles +func (apierSv1 *APIerSv1) GetTrendProfiles(ctx *context.Context, arg *engine.TrendProfilesAPI, reply *[]*engine.TrendProfile) (err error) { + tr, err := apierSv1.DataManager.GetTrendProfiles(arg.Tenant, arg.TpIDs) + if err != nil { + return utils.APIErrorHandler(err) + } + *reply = tr + return +} + // GetTrendProfileIDs returns list of trendProfile IDs registered for a tenant func (apierSv1 *APIerSv1) GetTrendProfileIDs(ctx *context.Context, args *utils.PaginatorWithTenant, trPrfIDs *[]string) (err error) { tnt := args.Tenant diff --git a/apier/v1/trends_it_test.go b/apier/v1/trends_it_test.go index 132417143..8dd617586 100644 --- a/apier/v1/trends_it_test.go +++ b/apier/v1/trends_it_test.go @@ -38,6 +38,7 @@ var ( trendCfg *config.CGRConfig trendRPC *birpc.Client trendProfile *engine.TrendProfileWithAPIOpts + trendProfile2 *engine.TrendProfileWithAPIOpts trendConfigDIR string sTestsTrend = []func(t *testing.T){ @@ -49,6 +50,7 @@ var ( testTrendSLoadAdd, testTrendSetTrendProfile, testTrendSGetTrendProfileIDs, + testTrendSGetTrendProfiles, testTrendSUpdateTrendProfile, testTrendSRemTrendProfile, testTrendSKillEngine, @@ -111,7 +113,7 @@ func testTrendSRPCConn(t *testing.T) { } } func testTrendSLoadAdd(t *testing.T) { - trendProfile := &engine.TrendProfileWithAPIOpts{ + trendProfile = &engine.TrendProfileWithAPIOpts{ TrendProfile: &engine.TrendProfile{ Tenant: "cgrates.org", ID: "TR_AVG", @@ -133,25 +135,25 @@ func testTrendSetTrendProfile(t *testing.T) { reply *engine.TrendProfileWithAPIOpts result string ) - trendProfile = &engine.TrendProfileWithAPIOpts{ + trendProfile2 = &engine.TrendProfileWithAPIOpts{ TrendProfile: &engine.TrendProfile{ Tenant: "cgrates.org", ID: "Trend1", - ThresholdIDs: []string{"THD1", "THD2"}}, + ThresholdIDs: []string{"THD1"}}, } if err := trendRPC.Call(context.Background(), utils.APIerSv1GetTrendProfile, &utils.TenantID{Tenant: "cgrates.org", ID: "Trend1"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Fatal(err) } - if err := trendRPC.Call(context.Background(), utils.APIerSv1SetTrendProfile, trendProfile, &result); err != nil { + if err := trendRPC.Call(context.Background(), utils.APIerSv1SetTrendProfile, trendProfile2, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Errorf("Expected: %v,Received: %v", utils.OK, result) } if err := trendRPC.Call(context.Background(), utils.APIerSv1GetTrendProfile, &utils.TenantID{Tenant: "cgrates.org", ID: "Trend1"}, &reply); err != nil { t.Error(err) - } else if diff := cmp.Diff(trendProfile, reply, cmpopts.SortSlices(func(a, b string) bool { return a < b })); diff != utils.EmptyString { + } else if diff := cmp.Diff(trendProfile2, reply, cmpopts.SortSlices(func(a, b string) bool { return a < b })); diff != utils.EmptyString { t.Errorf("Unnexpected profile (-expected +got):\n%s", diff) } } @@ -165,6 +167,52 @@ func testTrendSGetTrendProfileIDs(t *testing.T) { } } +func testTrendSGetTrendProfiles(t *testing.T) { + trendPrf := &engine.TrendProfileWithAPIOpts{ + TrendProfile: &engine.TrendProfile{ + Tenant: "tenant1", + ID: "Trend_Last", + StatID: "Stat1", + Schedule: "*now", + }} + var result string + if err := trendRPC.Call(context.Background(), utils.APIerSv1SetTrendProfile, trendPrf, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Errorf("Expected: %v,Received: %v", utils.OK, result) + } + expRes := []*engine.TrendProfile{ + trendPrf.TrendProfile, + trendProfile.TrendProfile, + trendProfile2.TrendProfile, + } + var tResult []*engine.TrendProfile + if err := trendRPC.Call(context.Background(), utils.APIerSv1GetTrendProfiles, engine.TrendProfilesAPI{}, &tResult); err != nil { + t.Error(err) + } else if diff := cmp.Diff(expRes, tResult, cmpopts.SortSlices(func(a, b *engine.TrendProfile) bool { return a.ID < b.ID })); diff != utils.EmptyString { + t.Errorf("Unnexpected profiles (-expected +got):\n%s", diff) + } + + expRes = []*engine.TrendProfile{ + trendProfile.TrendProfile, + trendProfile2.TrendProfile, + } + if err := trendRPC.Call(context.Background(), utils.APIerSv1GetTrendProfiles, engine.TrendProfilesAPI{Tenant: "cgrates.org"}, &tResult); err != nil { + t.Error(err) + } else if diff := cmp.Diff(expRes, tResult, cmpopts.SortSlices(func(a, b *engine.TrendProfile) bool { return a.ID < b.ID })); diff != utils.EmptyString { + t.Errorf("Unnexpected profiles (-expected +got):\n%s", diff) + } + + expRes = []*engine.TrendProfile{ + trendProfile2.TrendProfile, + } + if err := trendRPC.Call(context.Background(), utils.APIerSv1GetTrendProfiles, engine.TrendProfilesAPI{Tenant: "cgrates.org", TpIDs: []string{"Trend1"}}, &tResult); err != nil { + t.Error(err) + } else if diff := cmp.Diff(expRes, tResult, cmpopts.SortSlices(func(a, b *engine.TrendProfile) bool { return a.ID < b.ID })); diff != utils.EmptyString { + t.Errorf("Unnexpected profiles (-expected +got):\n%s", diff) + } +} + func testTrendSUpdateTrendProfile(t *testing.T) { var ( reply *engine.TrendProfileWithAPIOpts @@ -175,10 +223,11 @@ func testTrendSUpdateTrendProfile(t *testing.T) { } if err := trendRPC.Call(context.Background(), utils.APIerSv1GetTrendProfile, &utils.TenantID{Tenant: "cgrates.org", ID: "Trend1"}, &reply); err != nil { t.Error(err) - } else if diff := cmp.Diff(trendProfile, reply, cmpopts.SortSlices(func(a, b string) bool { return a < b })); diff != utils.EmptyString { + } else if diff := cmp.Diff(trendProfile2, reply, cmpopts.SortSlices(func(a, b string) bool { return a < b })); diff != utils.EmptyString { t.Errorf("Unnexpected profile (-expected +got):\n%s", diff) } } + func testTrendSRemTrendProfile(t *testing.T) { var ( resp string @@ -190,7 +239,6 @@ func testTrendSRemTrendProfile(t *testing.T) { } else if resp != utils.OK { t.Error("Unexpected reply returned", resp) } - if err := trendRPC.Call(context.Background(), utils.APIerSv1GetTrendProfile, &utils.TenantID{Tenant: "cgrates.org", ID: "Trend1"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { diff --git a/engine/datamanager.go b/engine/datamanager.go index 555550ae7..9cdef9e7e 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -1428,6 +1428,48 @@ func (dm *DataManager) GetTrendProfile(tenant, id string, cacheRead, cacheWrite return } +func (dm *DataManager) GetTrendProfiles(tenant string, tpIDs []string) (tps []*TrendProfile, err error) { + prfx := utils.TrendsProfilePrefix + if tenant != utils.EmptyString { + prfx += tenant + utils.ConcatenatedKeySep + } + var tp *TrendProfile + if tenant == utils.EmptyString || len(tpIDs) == 0 { + var keys []string + keys, err = dm.dataDB.GetKeysForPrefix(prfx) + if err != nil { + return + } + if len(keys) == 0 { + return nil, utils.ErrNotFound + } + for _, key := range keys { + indx := strings.Index(key, utils.ConcatenatedKeySep) + if len(prfx) == len(utils.TrendsProfilePrefix) { + tenant = key[len(utils.TrendsProfilePrefix):indx] + } + id := key[indx+1:] + tp, err = dm.GetTrendProfile(tenant, id, true, false, utils.NonTransactional) + if err != nil { + return + } + tps = append(tps, tp) + } + return + } + for _, tpID := range tpIDs { + tp, err = dm.GetTrendProfile(tenant, tpID, true, false, utils.NonTransactional) + if err == utils.ErrNotFound { + continue + } + if err != nil { + return + } + tps = append(tps, tp) + } + return +} + func (dm *DataManager) SetTrendProfile(trp *TrendProfile) (err error) { if dm == nil { return utils.ErrNoDatabaseConn diff --git a/engine/trends.go b/engine/trends.go index 0e001753e..60a6f148d 100644 --- a/engine/trends.go +++ b/engine/trends.go @@ -48,6 +48,11 @@ type TrendProfileWithAPIOpts struct { APIOpts map[string]any } +type TrendProfilesAPI struct { + Tenant string + TpIDs []string +} + func (srp *TrendProfile) TenantID() string { return utils.ConcatenatedKey(srp.Tenant, srp.ID) } diff --git a/utils/consts.go b/utils/consts.go index 479a38ad9..6cc9987ec 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -1681,6 +1681,7 @@ const ( APIerSv1RemoveTrendProfile = "APIerSv1.RemoveTrendProfile" APIerSv1GetTrendProfile = "APIerSv1.GetTrendProfile" APIerSv1GetTrendProfileIDs = "APIerSv1.GetTrendProfileIDs" + APIerSv1GetTrendProfiles = "APIerSv1.GetTrendProfiles" TrendSv1Ping = "TrendSv1.Ping" )