/* 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see */ package agents import ( "fmt" "reflect" "testing" "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/sessions" "github.com/cgrates/cgrates/utils" "github.com/cgrates/radigo" ) func TestRadAgentSessionSClientIface(t *testing.T) { _ = sessions.BiRPCClient(new(RadiusAgent)) } func TestNewRadiusAgentFailDict(t *testing.T) { cfg := config.NewDefaultCGRConfig() cfg.RadiusAgentCfg().ClientDictionaries = map[string][]string{ "badpath": {"bad/path"}, } exp := "stat bad/path: no such file or directory" if _, err := NewRadiusAgent(cfg, nil, nil, nil); err == nil || err.Error() != exp { t.Errorf("Expected error <%v>, received <%v>", exp, err) } } func TestNewRadiusAgentOK(t *testing.T) { cfg := config.NewDefaultCGRConfig() exp := &RadiusAgent{ cgrCfg: cfg, } if rcv, err := NewRadiusAgent(cfg, nil, nil, nil); err != nil { if err.Error() == "stat /usr/share/cgrates/radius/dict/: no such file or directory" { t.SkipNow() // skipping if running in gitactions } t.Error(err) } else if exp.RWMutex != rcv.RWMutex || exp.cgrCfg != rcv.cgrCfg || exp.connMgr != rcv.connMgr || exp.filterS != rcv.filterS || exp.dacCfg != rcv.dacCfg || exp.WaitGroup != rcv.WaitGroup { t.Errorf("Expected <%+v>,\nreceived\n<%+v>", exp, rcv) } } func TestNewRadiusDAClientCfgOK(t *testing.T) { radAgCfg := &config.RadiusAgentCfg{ ClientDaAddresses: map[string]config.DAClientOpts{ "udp://127.0.0.1:1813": { Transport: "udp", Host: "127.0.0.1", Port: 1813, }, }, } dicts := &radigo.Dictionaries{} secrets := &radigo.Secrets{} exp := radiusDAClientCfg{} expDicts := make(map[string]*radigo.Dictionary, len(radAgCfg.ClientDaAddresses)) expSecrets := make(map[string]string, len(radAgCfg.ClientDaAddresses)) for client := range radAgCfg.ClientDaAddresses { expDicts[client] = dicts.GetInstance(client) exp.dicts = radigo.NewDictionaries(expDicts) expSecrets[client] = secrets.GetSecret(client) exp.secrets = radigo.NewSecrets(expSecrets) } if rcv := newRadiusDAClientCfg(dicts, secrets, radAgCfg); !reflect.DeepEqual(exp, rcv) { rcvStr := map[string]string{ "dicts": fmt.Sprint(rcv.dicts), "secrets": fmt.Sprint(rcv.secrets), } expStr := map[string]any{ "dicts": fmt.Sprint(exp.dicts), "secrets": fmt.Sprint(exp.secrets), } t.Errorf("Expected <%+v>,\nreceived\n<%+v>", expStr, rcvStr) } } func TestRadagentV1DisconnectPeer(t *testing.T) { TestAgent := &RadiusAgent{} ctx := context.Background() args := &utils.DPRArgs{} var reply *string err := TestAgent.V1DisconnectPeer(ctx, args, reply) if err != utils.ErrNotImplemented { t.Errorf("Expected error %v, got %v", utils.ErrNotImplemented, err) } } func TestRadagentV1GetActiveSessionIDs(t *testing.T) { TestAgent := &RadiusAgent{} ctx := context.Background() clientId := "test-client-id" var sessionIDs []*sessions.SessionID err := TestAgent.V1GetActiveSessionIDs(ctx, clientId, &sessionIDs) if err != utils.ErrNotImplemented { t.Errorf("Expected error %v, got %v", utils.ErrNotImplemented, err) } } func TestRadagentV1WarnDisconnect(t *testing.T) { agent := &RadiusAgent{} err := agent.V1WarnDisconnect(context.Background(), map[string]any{}, nil) if err == nil { t.Errorf("Expected error 'not implemented', got nil") } else if err.Error() != utils.ErrNotImplemented.Error() { t.Errorf("Expected error 'not implemented', got '%v'", err.Error()) } } func TestRadagentDaRequestAddress(t *testing.T) { type testCase struct { name string remoteAddr string dynAuthAddrs map[string]config.DAClientOpts expectedAddr string expectedHost string expectedErr error } testCases := []testCase{ { name: "Empty dynAuthAddresses", remoteAddr: "testhost:1234", dynAuthAddrs: map[string]config.DAClientOpts{}, expectedAddr: "", expectedHost: "", expectedErr: utils.ErrNotFound, }, { name: "Matching remote host", remoteAddr: "matchinghost:5678", dynAuthAddrs: map[string]config.DAClientOpts{ "matchinghost": {Host: "targethost", Port: 8080}, }, expectedAddr: "targethost:8080", expectedHost: "matchinghost", expectedErr: nil, }, { name: "Non-matching remote host", remoteAddr: "nonmatchinghost:9012", dynAuthAddrs: map[string]config.DAClientOpts{ "otherhost": {Host: "yetanotherhost", Port: 3000}, }, expectedAddr: "", expectedHost: "", expectedErr: utils.ErrNotFound, }, { name: "Invalid remote address format", remoteAddr: "invalidformat", dynAuthAddrs: map[string]config.DAClientOpts{}, expectedAddr: "", expectedHost: "", expectedErr: utils.ErrNotFound, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { addr, host, err := daRequestAddress(tc.remoteAddr, tc.dynAuthAddrs) if err != tc.expectedErr { t.Errorf("Error does not match: expected %v, got %v", tc.expectedErr, err) } if addr != tc.expectedAddr { t.Errorf("Address does not match: expected %v, got %v", tc.expectedAddr, addr) } if host != tc.expectedHost { t.Errorf("Host does not match: expected %v, got %v", tc.expectedHost, host) } }) } }