From 95604203c496eb30fe965e3faa8b1b8452f853a4 Mon Sep 17 00:00:00 2001 From: DanB Date: Wed, 10 Feb 2016 15:14:10 +0100 Subject: [PATCH 1/4] Users returning USERS_NOT_FOUND error for better error handling --- agents/dmtagent.go | 2 +- engine/users.go | 2 +- engine/users_test.go | 2 +- utils/consts.go | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index a3624a99a..8dfef11c9 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -139,7 +139,7 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro var unauthorizedResultCode bool if err != nil { utils.Logger.Debug(fmt.Sprintf("Received error from rater: %+v", err)) - if strings.HasSuffix(err.Error(), utils.ErrAccountNotFound.Error()) { // 5030 in case of AccountNotFound + if strings.HasSuffix(err.Error(), utils.ErrAccountNotFound.Error()) || strings.HasSuffix(err.Error(), utils.ErrUsersNotFound.Error()) { // 5030 in case of AccountNotFound if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, "5030", false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Reply-Code, error: %s", ccr.diamMessage, err)) diff --git a/engine/users.go b/engine/users.go index 69dcc2ef4..caa435558 100644 --- a/engine/users.go +++ b/engine/users.go @@ -495,5 +495,5 @@ func LoadUserProfile(in interface{}, extraFields string) error { utils.SetMapExtraFields(in, m, extraFields) return nil } - return utils.ErrNotFound + return utils.ErrUsersNotFound } diff --git a/engine/users_test.go b/engine/users_test.go index e21a926dd..45df6a58e 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -708,7 +708,7 @@ func TestUsersExternalCDRGetLoadUserProfileExtraFieldsNotFound(t *testing.T) { } err := LoadUserProfile(ur, "ExtraFields") - if err != utils.ErrNotFound { + if err != utils.ErrUsersNotFound { t.Error("Error detecting err in loading user profile: ", err) } } diff --git a/utils/consts.go b/utils/consts.go index 6f413f1f3..9dd06ee16 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -28,6 +28,7 @@ var ( ErrUnauthorizedDestination = errors.New("UNAUTHORIZED_DESTINATION") ErrRatingPlanNotFound = errors.New("RATING_PLAN_NOT_FOUND") ErrAccountNotFound = errors.New("ACCOUNT_NOT_FOUND") + ErrUsersNotFound = errors.New("USERS_NOT_FOUND") ) const ( From 1f41970e86ac02cfb09ef68078754ec52f6ac054 Mon Sep 17 00:00:00 2001 From: DanB Date: Wed, 10 Feb 2016 15:19:39 +0100 Subject: [PATCH 2/4] USERS_NOT_FOUND -> USER_NOT_FOUND for consistency --- agents/dmtagent.go | 2 +- engine/users.go | 2 +- engine/users_test.go | 2 +- utils/consts.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index 8dfef11c9..bdf119ba1 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -139,7 +139,7 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro var unauthorizedResultCode bool if err != nil { utils.Logger.Debug(fmt.Sprintf("Received error from rater: %+v", err)) - if strings.HasSuffix(err.Error(), utils.ErrAccountNotFound.Error()) || strings.HasSuffix(err.Error(), utils.ErrUsersNotFound.Error()) { // 5030 in case of AccountNotFound + if strings.HasSuffix(err.Error(), utils.ErrAccountNotFound.Error()) || strings.HasSuffix(err.Error(), utils.ErrUserNotFound.Error()) { // 5030 in case of AccountNotFound if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, "5030", false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Reply-Code, error: %s", ccr.diamMessage, err)) diff --git a/engine/users.go b/engine/users.go index caa435558..66d573de2 100644 --- a/engine/users.go +++ b/engine/users.go @@ -495,5 +495,5 @@ func LoadUserProfile(in interface{}, extraFields string) error { utils.SetMapExtraFields(in, m, extraFields) return nil } - return utils.ErrUsersNotFound + return utils.ErrUserNotFound } diff --git a/engine/users_test.go b/engine/users_test.go index 45df6a58e..442b22411 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -708,7 +708,7 @@ func TestUsersExternalCDRGetLoadUserProfileExtraFieldsNotFound(t *testing.T) { } err := LoadUserProfile(ur, "ExtraFields") - if err != utils.ErrUsersNotFound { + if err != utils.ErrUserNotFound { t.Error("Error detecting err in loading user profile: ", err) } } diff --git a/utils/consts.go b/utils/consts.go index 9dd06ee16..c7d6e2d74 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -28,7 +28,7 @@ var ( ErrUnauthorizedDestination = errors.New("UNAUTHORIZED_DESTINATION") ErrRatingPlanNotFound = errors.New("RATING_PLAN_NOT_FOUND") ErrAccountNotFound = errors.New("ACCOUNT_NOT_FOUND") - ErrUsersNotFound = errors.New("USERS_NOT_FOUND") + ErrUserNotFound = errors.New("USER_NOT_FOUND") ) const ( From 9b8adb7c83b53c7fd2e087159e77185567c1935a Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 11 Feb 2016 20:42:05 +0100 Subject: [PATCH 3/4] Fix handling of account and user not found in diameter code --- agents/dmtagent.go | 2 +- agents/dmtagent_it_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index bdf119ba1..65933da0f 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -157,7 +157,7 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro } } - if ccr.CCRequestType != 3 && ccr.CCRequestType != 4 && maxUsage == 0 { // Not enough balance, RFC demands 4012 + if ccr.CCRequestType != 3 && ccr.CCRequestType != 4 && maxUsage == 0 && !unauthorizedResultCode { // Not enough balance, RFC demands 4012 if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, "4012", false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Reply-Code, error: %s", ccr.diamMessage, err)) diff --git a/agents/dmtagent_it_test.go b/agents/dmtagent_it_test.go index 6d1dc1fe0..559043d95 100644 --- a/agents/dmtagent_it_test.go +++ b/agents/dmtagent_it_test.go @@ -500,6 +500,40 @@ func TestDmtAgentSendCCRSMSWrongAccount(t *testing.T) { } } +// cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"' +func TestDmtAgentSendCCRInitWrongAccount(t *testing.T) { + if !*testIntegration { + return + } + cdr := &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, + OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", + Tenant: "cgrates.org", Category: "call", Account: "non_existent", Subject: "non_existent", Destination: "1004", Supplier: "SUPPL1", + SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(0) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + } + ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, + daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) + m, err := ccr.AsDiameterMessage() + if err != nil { + t.Error(err) + } + if err := dmtClient.SendMessage(m); err != nil { + t.Error(err) + } + time.Sleep(time.Duration(100) * time.Millisecond) + msg := dmtClient.ReceivedMessage() // Discard the received message so we can test next one + if msg == nil { + t.Fatal("No message returned") + } + if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil { + t.Error(err) + } else if len(avps) == 0 { + t.Error("Result-Code") + } else if strResult := avpValAsString(avps[0]); strResult != "5030" { // Result-Code set in the template + t.Errorf("Expecting 5030, received: %s", strResult) + } +} + func TestDmtAgentCdrs(t *testing.T) { if !*testIntegration { return From 84f9af6043be9e6214225327996439dfbf41df63 Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 11 Feb 2016 21:10:21 +0100 Subject: [PATCH 4/4] Diameter SMS - credit insufficient should produce 4012 --- agents/dmtagent.go | 19 +++++++++++++------ sessionmanager/smgeneric.go | 2 +- utils/consts.go | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index 65933da0f..904d105f8 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -136,7 +136,7 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro } } } - var unauthorizedResultCode bool + var populatedResultCode bool if err != nil { utils.Logger.Debug(fmt.Sprintf("Received error from rater: %+v", err)) if strings.HasSuffix(err.Error(), utils.ErrAccountNotFound.Error()) || strings.HasSuffix(err.Error(), utils.ErrUserNotFound.Error()) { // 5030 in case of AccountNotFound @@ -145,7 +145,14 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Reply-Code, error: %s", ccr.diamMessage, err)) return nil } - unauthorizedResultCode = true + populatedResultCode = true + } else if strings.HasSuffix(err.Error(), utils.ErrCreditInsufficient.Error()) { + if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, "4012", + false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { + utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Reply-Code, error: %s", ccr.diamMessage, err)) + return nil + } + populatedResultCode = true } else { if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, strconv.Itoa(DiameterRatingFailed), false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { @@ -157,21 +164,21 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro } } - if ccr.CCRequestType != 3 && ccr.CCRequestType != 4 && maxUsage == 0 && !unauthorizedResultCode { // Not enough balance, RFC demands 4012 + if ccr.CCRequestType != 3 && ccr.CCRequestType != 4 && maxUsage == 0 && !populatedResultCode { // Not enough balance, RFC demands 4012 if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, "4012", false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Reply-Code, error: %s", ccr.diamMessage, err)) return nil } - unauthorizedResultCode = true - } else if !unauthorizedResultCode { + populatedResultCode = true + } else if !populatedResultCode { if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, strconv.Itoa(diam.Success), false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Reply-Code, error: %s", ccr.diamMessage, err)) return nil } } - if ccr.CCRequestType != 3 && ccr.CCRequestType != 4 && !unauthorizedResultCode { // For terminate or previously marked unauthorized, we don't add granted-service-unit AVP + if ccr.CCRequestType != 3 && ccr.CCRequestType != 4 && !populatedResultCode { // For terminate or previously marked unauthorized, we don't add granted-service-unit AVP if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Granted-Service-Unit", "CC-Time"}, strconv.FormatFloat(maxUsage, 'f', 0, 64), false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { utils.Logger.Err(fmt.Sprintf(" Processing message: %+v set CCA Granted-Service-Unit, error: %s", ccr.diamMessage, err)) diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index 59ac17337..bdc79807b 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -220,7 +220,7 @@ func (self *SMGeneric) ChargeEvent(gev SMGenericEvent, clnt *rpc2.Client) (maxDu } sR.CallCosts = append(sR.CallCosts, cc) // Save it so we can revert on issues if ccDur := cc.GetDuration(); ccDur == 0 { - err = errors.New("INSUFFICIENT_FUNDS") + err = utils.ErrCreditInsufficient break } else if ccDur < maxDur { maxDur = ccDur diff --git a/utils/consts.go b/utils/consts.go index c7d6e2d74..b8ede4078 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -29,6 +29,7 @@ var ( ErrRatingPlanNotFound = errors.New("RATING_PLAN_NOT_FOUND") ErrAccountNotFound = errors.New("ACCOUNT_NOT_FOUND") ErrUserNotFound = errors.New("USER_NOT_FOUND") + ErrCreditInsufficient = errors.New("CREDIT_INSUFFICIENT") ) const (