Files
cgrates/analyzers/analyzers_it_test.go
ionutboangiu 2c1a90c9c6 Optimize and fix unstable tests
Revise backup loop tests to not rely on time.Sleep anymore and remove
unused fields from them.

Removed 3ns TTL from tpreader test dataDB configuration that caused in-
consistent results.

Ensure connManager cache is reloaded in filter tests. Before they could
cause deadlocks.

Remove redundant inits, global vars and setup tests for debit and
accounts tests.

Optimize some analyzers tests.
2024-04-11 18:23:57 +02:00

276 lines
7.8 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 analyzers
import (
"errors"
"os"
"path"
"reflect"
"sort"
"testing"
"time"
"github.com/cgrates/birpc"
"github.com/cgrates/birpc/context"
"github.com/cgrates/birpc/jsonrpc"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/sessions"
"github.com/cgrates/cgrates/utils"
)
var (
anzCfgPath string
anzCfg *config.CGRConfig
anzRPC *birpc.Client
anzBiRPC *birpc.BirpcClient
sTestsAlsPrf = []func(t *testing.T){
testAnalyzerSInitCfg,
testAnalyzerSInitDataDb,
testAnalyzerSResetStorDb,
testAnalyzerSStartEngine,
testAnalyzerSRPCConn,
testAnalyzerSLoadTarrifPlans,
testAnalyzerSChargerSv1ProcessEvent,
testAnalyzerSV1Search,
testAnalyzerSV1Search2,
testAnalyzerSV1SearchWithContentFilters,
testAnalyzerSV1BirPCSession,
testAnalyzerSKillEngine,
}
)
func newRPCClient(cfg *config.ListenCfg) (c *birpc.Client, err error) {
switch *utils.Encoding {
case utils.MetaJSON:
return jsonrpc.Dial(utils.TCP, cfg.RPCJSONListen)
case utils.MetaGOB:
return birpc.Dial(utils.TCP, cfg.RPCGOBListen)
default:
return nil, errors.New("UNSUPPORTED_RPC")
}
}
// Test start here
func TestAnalyzerSIT(t *testing.T) {
switch *utils.DBType {
case utils.MetaMongo:
case utils.MetaInternal, utils.MetaMySQL, utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("unsupported dbtype value")
}
for _, stest := range sTestsAlsPrf {
t.Run("TestAnalyzerSIT", stest)
}
}
func testAnalyzerSInitCfg(t *testing.T) {
var err error
if err := os.RemoveAll("/tmp/analyzers/"); err != nil {
t.Fatal(err)
}
if err = os.MkdirAll("/tmp/analyzers/", 0700); err != nil {
t.Fatal(err)
}
anzCfgPath = path.Join(*utils.DataDir, "conf", "samples", "analyzers")
anzCfg, err = config.NewCGRConfigFromPath(anzCfgPath)
if err != nil {
t.Error(err)
}
}
func testAnalyzerSInitDataDb(t *testing.T) {
if err := engine.InitDataDb(anzCfg); err != nil {
t.Fatal(err)
}
}
// Wipe out the cdr database
func testAnalyzerSResetStorDb(t *testing.T) {
if err := engine.InitStorDb(anzCfg); err != nil {
t.Fatal(err)
}
}
// Start CGR Engine
func testAnalyzerSStartEngine(t *testing.T) {
if _, err := engine.StopStartEngine(anzCfgPath, *utils.WaitRater); err != nil {
t.Fatal(err)
}
}
// Connect rpc client to rater
func testAnalyzerSRPCConn(t *testing.T) {
srv, err := birpc.NewService(new(smock), utils.AgentV1, true)
if err != nil {
t.Fatal(err)
}
anzRPC, err = newRPCClient(anzCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
if err != nil {
t.Fatal(err)
}
anzBiRPC, err = utils.NewBiJSONrpcClient(anzCfg.SessionSCfg().ListenBijson, srv)
if err != nil {
t.Fatal(err)
}
}
func testAnalyzerSLoadTarrifPlans(t *testing.T) {
var reply string
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*utils.DataDir, "tariffplans", "tutorial")}
if err := anzRPC.Call(context.Background(), utils.APIerSv1LoadTariffPlanFromFolder, attrs, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error("Unexpected reply returned", reply)
}
}
func testAnalyzerSChargerSv1ProcessEvent(t *testing.T) {
cgrEv := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "event1",
Event: map[string]any{
utils.AccountField: "1010",
utils.Subject: "Something_inter",
utils.Destination: "999",
},
}
var result2 []*engine.ChrgSProcessEventReply
processedEv := []*engine.ChrgSProcessEventReply{
{
ChargerSProfile: "DEFAULT",
AlteredFields: []string{"*req.RunID"},
CGREvent: &utils.CGREvent{
Tenant: "cgrates.org",
ID: "event1",
Event: map[string]any{
"Account": "1010",
"Destination": "999",
"RunID": "*default",
"Subject": "Something_inter",
},
APIOpts: map[string]any{"*subsys": "*chargers"},
},
},
{
ChargerSProfile: "Raw",
AttributeSProfiles: []string{"*constant:*req.RequestType:*none"},
AlteredFields: []string{"*req.RunID", "*req.RequestType"},
CGREvent: &utils.CGREvent{
Tenant: "cgrates.org",
ID: "event1",
Event: map[string]any{
"Account": "1010",
"Destination": "999",
"RequestType": "*none",
"RunID": "*raw",
"Subject": "Something_inter",
},
APIOpts: map[string]any{
"*subsys": "*chargers",
utils.OptsAttributesProfileIDs: []any{"*constant:*req.RequestType:*none"},
},
},
},
}
if err := anzRPC.Call(context.Background(), utils.ChargerSv1ProcessEvent, cgrEv, &result2); err != nil {
t.Fatal(err)
}
sort.Slice(result2, func(i, j int) bool {
return result2[i].ChargerSProfile < result2[j].ChargerSProfile
})
if !reflect.DeepEqual(result2, processedEv) {
t.Errorf("Expecting : %s, \n received: %s", utils.ToJSON(processedEv), utils.ToJSON(result2))
}
}
func testAnalyzerSV1Search(t *testing.T) {
// need to wait in order for the log gorutine to execute
time.Sleep(10 * time.Millisecond)
var result []map[string]any
if err := anzRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &QueryArgs{HeaderFilters: `+RequestEncoding:\*internal +RequestMethod:AttributeSv1\.ProcessEvent`}, &result); err != nil {
t.Error(err)
} else if len(result) != 1 {
t.Errorf("Unexpected result: %s", utils.ToJSON(result))
}
}
func testAnalyzerSV1Search2(t *testing.T) {
var result []map[string]any
if err := anzRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &QueryArgs{HeaderFilters: `+RequestEncoding:\*json +RequestMethod:ChargerSv1\.ProcessEvent`}, &result); err != nil {
t.Error(err)
} else if len(result) != 1 {
t.Errorf("Unexpected result: %s", utils.ToJSON(result))
}
}
func testAnalyzerSV1SearchWithContentFilters(t *testing.T) {
var result []map[string]any
if err := anzRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &QueryArgs{
HeaderFilters: `+RequestEncoding:\*json`,
ContentFilters: []string{"*string:~*req.Event.Account:1010"},
}, &result); err != nil {
t.Error(err)
} else if len(result) != 1 {
t.Errorf("Unexpected result: %s", utils.ToJSON(result))
}
}
func testAnalyzerSV1BirPCSession(t *testing.T) {
var rply string
anzBiRPC.Call(context.Background(), utils.SessionSv1STIRIdentity,
&sessions.V1STIRIdentityArgs{}, &rply) // only call to register the birpc
if err := anzRPC.Call(context.Background(), utils.SessionSv1DisconnectPeer, &utils.DPRArgs{}, &rply); err == nil ||
err.Error() != utils.ErrPartiallyExecuted.Error() {
t.Fatal(err)
}
time.Sleep(10 * time.Millisecond)
var result []map[string]any
if err := anzRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &QueryArgs{HeaderFilters: `+RequestEncoding:\*birpc_json +RequestMethod:"AgentV1.DisconnectPeer"`}, &result); err != nil {
t.Error(err)
} else if len(result) != 1 {
t.Errorf("Unexpected result: %s", utils.ToJSON(result))
}
}
func testAnalyzerSKillEngine(t *testing.T) {
if err := engine.KillEngine(100); err != nil {
t.Error(err)
}
if err := os.RemoveAll(anzCfg.AnalyzerSCfg().DBPath); err != nil {
t.Fatal(err)
}
}
type smock struct{}
func (*smock) DisconnectPeer(ctx *context.Context,
args *utils.DPRArgs, reply *string) error {
return utils.ErrNotFound
}