Files
cgrates/general_tests/ranking_schedule_it_test.go
ionutboangiu 5f47df6927 close db connections in test flush helpers
Previously, database connections would stay alive until "go test"
would finish, sometimes leading to max conn errors.
2025-05-29 15:41:53 +02:00

226 lines
8.5 KiB
Go

//go:build integration
// +build integration
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package general_tests
import (
"fmt"
"path"
"slices"
"testing"
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
func TestRankingSchedule(t *testing.T) {
var rnkConfigDir string
switch *utils.DBType {
case utils.MetaInternal, utils.MetaPostgres:
t.SkipNow()
case utils.MetaMySQL:
rnkConfigDir = "ranking_mysql"
case utils.MetaMongo:
rnkConfigDir = "ranking_mongo"
default:
t.Fatal("Unkwown database type")
}
ng := engine.TestEngine{
ConfigPath: path.Join(*utils.DataDir, "conf", "samples", rnkConfigDir),
PreserveStorDB: true,
PreserveDataDB: true,
PreStartHook: func(t testing.TB, c *config.CGRConfig) {
engine.FlushDBs(t, c, true, true)
engine.LoadCSVsWithCGRLoader(t, c.ConfigPath, path.Join(*utils.DataDir, "tariffplans", "tutrankings"), nil, nil, "-caches_address=")
},
}
client, _ := ng.Run(t)
t.Run("ProcessStats", func(t *testing.T) {
var reply []string
for i := 1; i <= 4; i++ {
if err := client.Call(context.Background(), utils.StatSv1ProcessEvent, &utils.CGREvent{
Tenant: "cgrates.org",
ID: fmt.Sprintf("event%d", i),
Event: map[string]any{
utils.AccountField: fmt.Sprintf("100%d", i),
utils.AnswerTime: time.Date(2024, 8, 22, 14, 25, 0, 0, time.UTC),
utils.Usage: time.Duration(1800+60) / time.Duration(i) * time.Second,
utils.Cost: 20.0 + float64((i*7)%10)/2,
utils.PDD: time.Duration(10+i*2) * time.Second,
}}, &reply); err != nil {
t.Error(err)
}
}
})
time.Sleep(1 * time.Second)
t.Run("GetRankings", func(t *testing.T) {
var rnk engine.Ranking
sortedStatIds := []string{"Stats3", "Stats2", "Stats1", "Stats4"}
if err := client.Call(context.Background(), utils.RankingSv1GetRanking, &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RANK1"}}, &rnk); err != nil {
t.Error(err)
} else if len(rnk.SortedStatIDs) == 0 {
t.Error("no ranked statIDs")
} else if !slices.Equal(sortedStatIds, rnk.SortedStatIDs) {
t.Errorf("expected sorted statIDs %v, got %v", sortedStatIds, rnk.SortedStatIDs)
}
sortedStatIds = []string{"Stats4", "Stats1", "Stats2", "Stats3"}
if err := client.Call(context.Background(), utils.RankingSv1GetRanking, &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RANK2"}}, &rnk); err != nil {
t.Error(err)
} else if len(rnk.SortedStatIDs) == 0 {
t.Error("no ranked statIDs")
} else if !slices.Equal(sortedStatIds, rnk.SortedStatIDs) {
t.Errorf("expected sorted statIDs %v, got %v", sortedStatIds, rnk.SortedStatIDs)
}
})
t.Run("SetRankingProfile", func(t *testing.T) {
rankingProfile := &engine.RankingProfileWithAPIOpts{
RankingProfile: &engine.RankingProfile{
Tenant: "cgrates.org",
ID: "RANK3",
Schedule: "@every 1s",
StatIDs: []string{"Stats2", "Stats3", "Stats1"},
Sorting: "*desc",
SortingParameters: []string{"*acd", "*pdd:false", "*acc"},
},
}
var result string
if err := client.Call(context.Background(), utils.APIerSv1SetRankingProfile, rankingProfile, &result); err != nil {
t.Error(err)
} else if result != utils.OK {
t.Error("Unexpected reply returned", result)
}
})
t.Run("ScheduleManualRankings", func(t *testing.T) {
var scheduled int
if err := client.Call(context.Background(), utils.RankingSv1ScheduleQueries, &utils.ArgScheduleRankingQueries{TenantIDWithAPIOpts: utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org"}}, RankingIDs: []string{"RANK3"}}, &scheduled); err != nil {
t.Error(err)
} else if scheduled != 1 {
t.Errorf("Expected 1 scheduled rankings, got %d", scheduled)
}
var schedRankings []utils.ScheduledRanking
if err := client.Call(context.Background(), utils.RankingSv1GetSchedule, &utils.ArgScheduledRankings{RankingIDPrefixes: []string{"RANK3"}, TenantIDWithAPIOpts: utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org"}}}, &schedRankings); err != nil {
t.Error(err)
} else if len(schedRankings) == 0 {
t.Errorf("Expected scheduled rankings")
} else {
for _, schedRanking := range schedRankings {
if schedRanking.Next.IsZero() {
t.Errorf("Expected to have a scheduled time got %v", schedRanking.Next)
}
}
}
})
time.Sleep(time.Second)
t.Run("GetRankings", func(t *testing.T) {
sortedStatIds := []string{"Stats1", "Stats2", "Stats3"}
var rnk engine.Ranking
if err := client.Call(context.Background(), utils.RankingSv1GetRanking, &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RANK3"}}, &rnk); err != nil {
t.Error(err)
} else if len(rnk.SortedStatIDs) == 0 {
t.Error("no ranked statIDs")
} else if !slices.Equal(sortedStatIds, rnk.SortedStatIDs) {
t.Errorf("expected sorted statIDs %v, got %v", sortedStatIds, rnk.SortedStatIDs)
}
})
t.Run("RankingSetConfig", func(t *testing.T) {
var reply string
// store interval is set to 0
if err := client.Call(context.Background(), utils.ConfigSv1SetConfig, &config.SetConfigArgs{
Tenant: "cgrates.org",
Config: map[string]any{
"rankings": map[string]any{
"enabled": true,
"store_interval": "0",
"stats_conns": []string{"*localhost"},
},
},
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
})
t.Run("SetRankingProfile", func(t *testing.T) {
rankingProfile := &engine.RankingProfileWithAPIOpts{
RankingProfile: &engine.RankingProfile{
Tenant: "cgrates.org",
ID: "RANK4",
Schedule: "@every 1s",
StatIDs: []string{"Stats2", "Stats3", "Stats1"},
Sorting: "*desc",
SortingParameters: []string{"*pdd:false", "*acd"},
},
}
var result string
if err := client.Call(context.Background(), utils.APIerSv1SetRankingProfile, rankingProfile, &result); err != nil {
t.Error(err)
} else if result != utils.OK {
t.Error("Unexpected reply returned", result)
}
})
t.Run("ScheduleManualRankings", func(t *testing.T) {
var scheduled int
if err := client.Call(context.Background(), utils.RankingSv1ScheduleQueries, &utils.ArgScheduleRankingQueries{TenantIDWithAPIOpts: utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org"}}, RankingIDs: []string{"RANK4"}}, &scheduled); err != nil {
t.Error(err)
} else if scheduled != 1 {
t.Errorf("Expected 1 scheduled rankings, got %d", scheduled)
}
var schedRankings []utils.ScheduledRanking
if err := client.Call(context.Background(), utils.RankingSv1GetSchedule, &utils.ArgScheduledRankings{RankingIDPrefixes: []string{"RANK4"}, TenantIDWithAPIOpts: utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org"}}}, &schedRankings); err != nil {
t.Error(err)
} else if len(schedRankings) == 0 {
t.Errorf("Expected scheduled rankings")
} else {
for _, schedRanking := range schedRankings {
if schedRanking.Next.IsZero() {
t.Errorf("Expected to have a scheduled time got %v", schedRanking.Next)
}
}
}
})
time.Sleep(time.Second)
t.Run("GetRankings", func(t *testing.T) {
var reply string
if err := client.Call(context.Background(), utils.CacheSv1Clear, &utils.AttrCacheIDsWithAPIOpts{}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error("Calling CacheSv1.ReloadCache got reply: ", reply)
}
var rnk engine.Ranking
if err := client.Call(context.Background(), utils.RankingSv1GetRanking, &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RANK4"}}, &rnk); err != nil {
t.Error(err)
} else if len(rnk.SortedStatIDs) != 0 || !rnk.LastUpdate.IsZero() {
t.Error("expected updated ranking not set in db")
}
})
}