From 296ef1bf97b81e186f8456bfdde697d6b2891390 Mon Sep 17 00:00:00 2001 From: TeoV Date: Thu, 15 Feb 2018 15:36:40 +0200 Subject: [PATCH] Avoid panic error for Attributes (Substitute:*none) and update test with new modify --- agents/fsagent.go | 3 + apier/v1/attributes_it_test.go | 163 +++++++++++++++++++---- apier/v1/filter_indexes_it_test.go | 8 +- apier/v1/filterindexecache_it_test.go | 162 +++++++++++----------- data/tariffplans/tutorial/Attributes.csv | 2 +- engine/attributes.go | 25 ++-- engine/attributes_test.go | 55 +++++--- engine/cdr.go | 3 + migrator/attributes_test.go | 4 +- migrator/migrator_it_test.go | 4 +- 10 files changed, 284 insertions(+), 145 deletions(-) diff --git a/agents/fsagent.go b/agents/fsagent.go index 40df42d50..85e11c46b 100644 --- a/agents/fsagent.go +++ b/agents/fsagent.go @@ -181,6 +181,9 @@ func (sm *FSsessions) onChannelPark(fsev FSEvent, connId string) { if authArgs.GetAttributes { if authReply.Attributes != nil { for _, fldName := range authReply.Attributes.AlteredFields { + if _, has := authReply.Attributes.CGREvent.Event[fldName]; !has { + continue //maybe removed + } if _, err := sm.conns[connId].SendApiCmd( fmt.Sprintf("uuid_setvar %s %s %s\n\n", fsev.GetUUID(), fldName, authReply.Attributes.CGREvent.Event[fldName])); err != nil { diff --git a/apier/v1/attributes_it_test.go b/apier/v1/attributes_it_test.go index 2cb7ab540..009da22a7 100644 --- a/apier/v1/attributes_it_test.go +++ b/apier/v1/attributes_it_test.go @@ -56,6 +56,7 @@ var sTestsAlsPrf = []func(t *testing.T){ testAttributeSProcessEvent, testAttributeSProcessEventWithNoneSubstitute, testAttributeSProcessEventWithNoneSubstitute2, + testAttributeSProcessEventWithNoneSubstitute3, testAttributeSGetAlsPrfBeforeSet, testAttributeSSetAlsPrf, testAttributeSUpdateAlsPrf, @@ -146,7 +147,7 @@ func testAttributeSGetAttributeForEvent(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSGetAttributeForEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ utils.Account: "1007", utils.Destination: "+491511231234", @@ -156,7 +157,7 @@ func testAttributeSGetAttributeForEvent(t *testing.T) { Tenant: ev.Tenant, ID: "ATTR_1", FilterIDs: []string{"*string:Account:1007"}, - Contexts: []string{utils.MetaRating}, + Contexts: []string{utils.MetaSessionS, utils.MetaCDRs}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 1, 14, 0, 0, 0, 0, time.UTC)}, Attributes: []*engine.Attribute{ @@ -199,7 +200,7 @@ func testAttributeSGetAttributeForEventNotFound(t *testing.T) { Tenant: ev.Tenant, ID: "ATTR_3", FilterIDs: []string{"*string:Account:dan"}, - Contexts: []string{utils.MetaRating}, + Contexts: []string{utils.MetaSessionS}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 1, 14, 0, 0, 0, 0, time.UTC)}, Attributes: []*engine.Attribute{ @@ -285,7 +286,7 @@ func testAttributeSProcessEvent(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ utils.Account: "1007", utils.Destination: "+491511231234", @@ -293,11 +294,11 @@ func testAttributeSProcessEvent(t *testing.T) { } eRply := &engine.AttrSProcessEventReply{ MatchedProfile: "ATTR_1", - AlteredFields: []string{"Subject", "Account"}, + AlteredFields: []string{utils.Subject, utils.Account}, CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ utils.Account: "1001", utils.Subject: "1001", @@ -307,14 +308,14 @@ func testAttributeSProcessEvent(t *testing.T) { } eRply2 := &engine.AttrSProcessEventReply{ MatchedProfile: "ATTR_1", - AlteredFields: []string{"Account", "Subject"}, + AlteredFields: []string{utils.Account, utils.Subject}, CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "1001", - "Subject": "1001", + utils.Account: "1001", + utils.Subject: "1001", "Destination": "+491511231234", }, }, @@ -334,7 +335,7 @@ func testAttributeSProcessEventWithNoneSubstitute(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSWithNoneSubstitute", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ utils.Account: "1008", utils.Destination: "+491511231234", @@ -343,7 +344,7 @@ func testAttributeSProcessEventWithNoneSubstitute(t *testing.T) { alsPrf = &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "AttributeWithNonSubstitute", - Contexts: []string{"*rating"}, + Contexts: []string{utils.MetaSessionS, utils.MetaCDRs}, FilterIDs: []string{"*string:Account:1008"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), @@ -351,14 +352,14 @@ func testAttributeSProcessEventWithNoneSubstitute(t *testing.T) { }, Attributes: []*engine.Attribute{ &engine.Attribute{ - FieldName: "Account", + FieldName: utils.Account, Initial: "1008", Substitute: "1001", Append: false, }, &engine.Attribute{ - FieldName: "Subject", - Initial: "*any", + FieldName: utils.Subject, + Initial: utils.ANY, Substitute: "*none", Append: true, }, @@ -373,11 +374,24 @@ func testAttributeSProcessEventWithNoneSubstitute(t *testing.T) { } eRply := &engine.AttrSProcessEventReply{ MatchedProfile: "AttributeWithNonSubstitute", - AlteredFields: []string{"Account"}, + AlteredFields: []string{utils.Account, utils.Subject}, CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSWithNoneSubstitute", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), + Event: map[string]interface{}{ + utils.Account: "1001", + utils.Destination: "+491511231234", + }, + }, + } + eRply2 := &engine.AttrSProcessEventReply{ + MatchedProfile: "AttributeWithNonSubstitute", + AlteredFields: []string{utils.Subject, utils.Account}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testAttributeSWithNoneSubstitute", + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ utils.Account: "1001", utils.Destination: "+491511231234", @@ -388,7 +402,8 @@ func testAttributeSProcessEventWithNoneSubstitute(t *testing.T) { if err := attrSRPC.Call(utils.AttributeSv1ProcessEvent, ev, &rplyEv); err != nil { t.Error(err) - } else if !reflect.DeepEqual(eRply, &rplyEv) { + } else if !reflect.DeepEqual(eRply, &rplyEv) && + !reflect.DeepEqual(eRply2, &rplyEv) { t.Errorf("Expecting: %s, received: %s", utils.ToJSON(eRply), utils.ToJSON(rplyEv)) } @@ -398,7 +413,7 @@ func testAttributeSProcessEventWithNoneSubstitute2(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSWithNoneSubstitute", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ utils.Account: "1008", utils.Subject: "1008", @@ -408,7 +423,7 @@ func testAttributeSProcessEventWithNoneSubstitute2(t *testing.T) { alsPrf = &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "AttributeWithNonSubstitute", - Contexts: []string{"*rating"}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"*string:Account:1008"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), @@ -416,15 +431,15 @@ func testAttributeSProcessEventWithNoneSubstitute2(t *testing.T) { }, Attributes: []*engine.Attribute{ &engine.Attribute{ - FieldName: "Account", + FieldName: utils.Account, Initial: "1008", Substitute: "1001", Append: false, }, &engine.Attribute{ - FieldName: "Subject", - Initial: "*any", - Substitute: "*none", + FieldName: utils.Subject, + Initial: utils.ANY, + Substitute: utils.META_NONE, Append: false, }, }, @@ -438,11 +453,24 @@ func testAttributeSProcessEventWithNoneSubstitute2(t *testing.T) { } eRply := &engine.AttrSProcessEventReply{ MatchedProfile: "AttributeWithNonSubstitute", - AlteredFields: []string{"Account"}, + AlteredFields: []string{"Account", "Subject"}, CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSWithNoneSubstitute", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), + Event: map[string]interface{}{ + utils.Account: "1001", + utils.Destination: "+491511231234", + }, + }, + } + eRply2 := &engine.AttrSProcessEventReply{ + MatchedProfile: "AttributeWithNonSubstitute", + AlteredFields: []string{utils.Subject, utils.Account}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testAttributeSWithNoneSubstitute", + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ utils.Account: "1001", utils.Destination: "+491511231234", @@ -453,7 +481,86 @@ func testAttributeSProcessEventWithNoneSubstitute2(t *testing.T) { if err := attrSRPC.Call(utils.AttributeSv1ProcessEvent, ev, &rplyEv); err != nil { t.Error(err) - } else if !reflect.DeepEqual(eRply, &rplyEv) { + } else if !reflect.DeepEqual(eRply, &rplyEv) && + !reflect.DeepEqual(eRply2, &rplyEv) { + t.Errorf("Expecting: %s, received: %s", + utils.ToJSON(eRply), utils.ToJSON(rplyEv)) + } +} + +func testAttributeSProcessEventWithNoneSubstitute3(t *testing.T) { + ev := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testAttributeSWithNoneSubstitute", + Context: utils.StringPointer(utils.MetaSessionS), + Event: map[string]interface{}{ + utils.Account: "1008", + utils.Destination: "+491511231234", + }, + } + alsPrf = &engine.AttributeProfile{ + Tenant: "cgrates.org", + ID: "AttributeWithNonSubstitute", + Contexts: []string{utils.MetaSessionS}, + FilterIDs: []string{"*string:Account:1008"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), + ExpiryTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), + }, + Attributes: []*engine.Attribute{ + &engine.Attribute{ + FieldName: utils.Account, + Initial: "1008", + Substitute: "1001", + Append: false, + }, + &engine.Attribute{ + FieldName: utils.Subject, + Initial: "1008", + Substitute: utils.META_NONE, + Append: false, + }, + }, + Weight: 20, + } + var result string + if err := attrSRPC.Call("ApierV1.SetAttributeProfile", alsPrf, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Error("Unexpected reply returned", result) + } + eRply := &engine.AttrSProcessEventReply{ + MatchedProfile: "AttributeWithNonSubstitute", + AlteredFields: []string{"Account", "Subject"}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testAttributeSWithNoneSubstitute", + Context: utils.StringPointer(utils.MetaSessionS), + Event: map[string]interface{}{ + utils.Account: "1001", + utils.Destination: "+491511231234", + }, + }, + } + eRply2 := &engine.AttrSProcessEventReply{ + MatchedProfile: "AttributeWithNonSubstitute", + AlteredFields: []string{utils.Subject, utils.Account}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testAttributeSWithNoneSubstitute", + Context: utils.StringPointer(utils.MetaSessionS), + Event: map[string]interface{}{ + utils.Account: "1001", + utils.Destination: "+491511231234", + }, + }, + } + var rplyEv engine.AttrSProcessEventReply + if err := attrSRPC.Call(utils.AttributeSv1ProcessEvent, + ev, &rplyEv); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eRply, &rplyEv) && + !reflect.DeepEqual(eRply2, &rplyEv) { t.Errorf("Expecting: %s, received: %s", utils.ToJSON(eRply), utils.ToJSON(rplyEv)) } @@ -463,7 +570,7 @@ func testAttributeSSetAlsPrf(t *testing.T) { alsPrf = &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "ApierTest", - Contexts: []string{"*rating"}, + Contexts: []string{utils.MetaSessionS, utils.MetaCDRs}, FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), diff --git a/apier/v1/filter_indexes_it_test.go b/apier/v1/filter_indexes_it_test.go index b32dbbd50..5c0c9d85d 100644 --- a/apier/v1/filter_indexes_it_test.go +++ b/apier/v1/filter_indexes_it_test.go @@ -1280,7 +1280,7 @@ func testV1FIdxSetAttributeProfileIndexes(t *testing.T) { alsPrf = &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "ApierTest", - Contexts: []string{"*rating"}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"FLTR_1"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), @@ -1392,7 +1392,7 @@ func testV1FIdxSetSecondAttributeProfileIndexes(t *testing.T) { alsPrf = &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "ApierTest2", - Contexts: []string{"*rating"}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"FLTR_2"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), @@ -1493,13 +1493,13 @@ func testV1FIdxRemoveAttributeProfile(t *testing.T) { t.Errorf("Error: %+v", reply2) } if err := tFIdxRpc.Call("ApierV1.RemAttributeProfile", - &ArgRemoveAttrProfile{Tenant: "cgrates.org", ID: "ApierTest", Contexts: []string{"*rating"}}, &resp); err != nil { + &ArgRemoveAttrProfile{Tenant: "cgrates.org", ID: "ApierTest", Contexts: []string{utils.MetaSessionS}}, &resp); err != nil { t.Error(err) } else if resp != utils.OK { t.Error("Unexpected reply returned", resp) } if err := tFIdxRpc.Call("ApierV1.RemAttributeProfile", - &ArgRemoveAttrProfile{Tenant: "cgrates.org", ID: "ApierTest2", Contexts: []string{"*rating"}}, &resp); err != nil { + &ArgRemoveAttrProfile{Tenant: "cgrates.org", ID: "ApierTest2", Contexts: []string{utils.MetaSessionS}}, &resp); err != nil { t.Error(err) } else if resp != utils.OK { t.Error("Unexpected reply returned", resp) diff --git a/apier/v1/filterindexecache_it_test.go b/apier/v1/filterindexecache_it_test.go index c949cbad8..e314dc9f7 100644 --- a/apier/v1/filterindexecache_it_test.go +++ b/apier/v1/filterindexecache_it_test.go @@ -196,7 +196,7 @@ func testV1FIdxCaSetThresholdProfile(t *testing.T) { ID: "TestFilter", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1001"}, }, @@ -305,7 +305,7 @@ func testV1FIdxCaUpdateThresholdProfile(t *testing.T) { ID: "TestFilter2", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1002"}, }, @@ -392,7 +392,7 @@ func testV1FIdxCaUpdateThresholdProfileFromTP(t *testing.T) { ID: "TestFilter3", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1003"}, }, @@ -575,7 +575,7 @@ func testV1FIdxCaSetStatQueueProfile(t *testing.T) { ID: "FLTR_1", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1001"}, }, @@ -720,7 +720,7 @@ func testV1FIdxCaUpdateStatQueueProfile(t *testing.T) { ID: "FLTR_2", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1002"}, }, @@ -796,7 +796,7 @@ func testV1FIdxCaUpdateStatQueueProfileFromTP(t *testing.T) { ID: "FLTR_3", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1003"}, }, @@ -930,10 +930,10 @@ func testV1FIdxCaProcessAttributeProfileEventWithNotFound(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "3009", - "Destination": "+492511231234", + utils.Account: "3009", + utils.Destination: "+492511231234", }, } var rplyEv engine.AttrSProcessEventReply @@ -953,12 +953,12 @@ func testV1FIdxCaSetAttributeProfile(t *testing.T) { ID: "TestFilter", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1009"}, }, &engine.FilterRule{ - FieldName: "Destination", + FieldName: utils.Destination, Type: "*string", Values: []string{"+491511231234"}, }, @@ -976,21 +976,21 @@ func testV1FIdxCaSetAttributeProfile(t *testing.T) { alsPrf := &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "TEST_PROFILE1", - Contexts: []string{"*rating"}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"TestFilter"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), }, Attributes: []*engine.Attribute{ &engine.Attribute{ - FieldName: "Account", - Initial: "*any", + FieldName: utils.Account, + Initial: utils.META_ANY, Substitute: "1001", Append: false, }, &engine.Attribute{ - FieldName: "Subject", - Initial: "*any", + FieldName: utils.Subject, + Initial: utils.META_ANY, Substitute: "1001", Append: true, }, @@ -1006,10 +1006,10 @@ func testV1FIdxCaSetAttributeProfile(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "1009", - "Destination": "+491511231234", + utils.Account: "1009", + utils.Destination: "+491511231234", }, } var rplyEv engine.AttrSProcessEventReply @@ -1019,7 +1019,7 @@ func testV1FIdxCaSetAttributeProfile(t *testing.T) { //test to make sure indexes are made as expected fldNameVal := map[string]string{"TEST_PROFILE1": ""} expectedRevIDX := map[string]utils.StringMap{"TEST_PROFILE1": {"*string:Account:1009": true, "*string:Destination:+491511231234": true}} - if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*rating", true), + if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*sessions", true), fldNameVal); err != nil { t.Error(err) } @@ -1033,10 +1033,10 @@ func testV1FIdxCaGetAttributeProfileFromTP(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "1007", - "Destination": "+491511231234", + utils.Account: "1007", + utils.Destination: "+491511231234", }, } var rplyEv engine.AttrSProcessEventReply @@ -1046,7 +1046,7 @@ func testV1FIdxCaGetAttributeProfileFromTP(t *testing.T) { //test to make sure indexes are made as expected idx := map[string]utils.StringMap{"ATTR_1": {"*string:Account:1007": true}} fldNameVal := map[string]string{"ATTR_1": ""} - if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*rating", true), + if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*sessions", true), fldNameVal); err != nil { t.Error(err) } @@ -1061,12 +1061,12 @@ func testV1FIdxCaUpdateAttributeProfile(t *testing.T) { ID: "TestFilter2", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"2009"}, }, &engine.FilterRule{ - FieldName: "Destination", + FieldName: utils.Destination, Type: "*string", Values: []string{"+492511231234"}, }, @@ -1084,20 +1084,20 @@ func testV1FIdxCaUpdateAttributeProfile(t *testing.T) { alsPrf := &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "TEST_PROFILE1", - Contexts: []string{"*rating"}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"TestFilter2"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), }, Attributes: []*engine.Attribute{ &engine.Attribute{ - FieldName: "Account", - Initial: "*any", + FieldName: utils.Account, + Initial: utils.META_ANY, Substitute: "1001", Append: false, }, &engine.Attribute{ - FieldName: "Subject", + FieldName: utils.Subject, Initial: "*any", Substitute: "1001", Append: true, @@ -1114,10 +1114,10 @@ func testV1FIdxCaUpdateAttributeProfile(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "2009", - "Destination": "+492511231234", + utils.Account: "2009", + utils.Destination: "+492511231234", }, } var rplyEv engine.AttrSProcessEventReply @@ -1127,7 +1127,7 @@ func testV1FIdxCaUpdateAttributeProfile(t *testing.T) { //test to make sure indexes are made as expected idx := map[string]utils.StringMap{"TEST_PROFILE1": {"*string:Account:2009": true, "*string:Destination:+492511231234": true}} fldNameVal := map[string]string{"TEST_PROFILE1": ""} - if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*rating", true), + if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*sessions", true), fldNameVal); err != nil { t.Error(err) } @@ -1142,12 +1142,12 @@ func testV1FIdxCaUpdateAttributeProfileFromTP(t *testing.T) { ID: "TestFilter3", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"3009"}, }, &engine.FilterRule{ - FieldName: "Destination", + FieldName: utils.Destination, Type: "*string", Values: []string{"+492511231234"}, }, @@ -1176,10 +1176,10 @@ func testV1FIdxCaUpdateAttributeProfileFromTP(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "3009", - "Destination": "+492511231234", + utils.Account: "3009", + utils.Destination: "+492511231234", }, } var rplyEv engine.AttrSProcessEventReply @@ -1189,7 +1189,7 @@ func testV1FIdxCaUpdateAttributeProfileFromTP(t *testing.T) { //test to make sure indexes are made as expected idx := map[string]utils.StringMap{"ATTR_1": {"*string:Account:3009": true, "*string:Destination:+492511231234": true}} fldNameVal := map[string]string{"ATTR_1": ""} - if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*rating", true), + if indexes, err = onStor.GetFilterReverseIndexes(engine.GetDBIndexKey(utils.AttributeProfilePrefix, "cgrates.org:*sessions", true), fldNameVal); err != nil { t.Error(err) } @@ -1203,10 +1203,10 @@ func testV1FIdxCaRemoveAttributeProfile(t *testing.T) { ev := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "3009", - "Destination": "+492511231234", + utils.Account: "3009", + utils.Destination: "+492511231234", }, } var rplyEv engine.AttrSProcessEventReply @@ -1217,10 +1217,10 @@ func testV1FIdxCaRemoveAttributeProfile(t *testing.T) { ev2 := &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "2009", - "Destination": "+492511231234", + utils.Account: "2009", + utils.Destination: "+492511231234", }, } if err := tFIdxCaRpc.Call(utils.AttributeSv1ProcessEvent, ev2, &rplyEv); err != nil { @@ -1228,7 +1228,7 @@ func testV1FIdxCaRemoveAttributeProfile(t *testing.T) { } //Remove threshold profile that was set form api if err := tFIdxCaRpc.Call("ApierV1.RemAttributeProfile", &ArgRemoveAttrProfile{Tenant: "cgrates.org", - ID: "TEST_PROFILE1", Contexts: []string{"*rating"}}, &resp); err != nil { + ID: "TEST_PROFILE1", Contexts: []string{utils.MetaSessionS}}, &resp); err != nil { t.Error(err) } else if resp != utils.OK { t.Error("Unexpected reply returned", resp) @@ -1242,7 +1242,7 @@ func testV1FIdxCaRemoveAttributeProfile(t *testing.T) { } //Remove threshold profile that was set form tariffplan if err := tFIdxCaRpc.Call("ApierV1.RemAttributeProfile", &ArgRemoveAttrProfile{Tenant: "cgrates.org", - ID: "ATTR_1", Contexts: []string{"*rating"}}, &resp); err != nil { + ID: "ATTR_1", Contexts: []string{utils.MetaSessionS}}, &resp); err != nil { t.Error(err) } else if resp != utils.OK { t.Error("Unexpected reply returned", resp) @@ -1277,9 +1277,9 @@ func testV1FIdxCaGetResourceProfileWithNotFound(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "1002", - "Subject": "1001", - "Destination": "1002"}, + utils.Account: "1002", + utils.Subject: "1001", + utils.Destination: "1002"}, }, Units: 6, } @@ -1302,17 +1302,17 @@ func testV1FIdxCaSetResourceProfile(t *testing.T) { ID: "FLTR_RES_RCFG1", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1001"}, }, &engine.FilterRule{ - FieldName: "Subject", + FieldName: utils.Subject, Type: "*string", Values: []string{"1002"}, }, &engine.FilterRule{ - FieldName: "Destination", + FieldName: utils.Destination, Type: "*string", Values: []string{"1001"}, }, @@ -1352,9 +1352,9 @@ func testV1FIdxCaSetResourceProfile(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "1001", - "Subject": "1002", - "Destination": "1001"}, + utils.Account: "1001", + utils.Subject: "1002", + utils.Destination: "1001"}, }, Units: 6, } @@ -1389,9 +1389,9 @@ func testV1FIdxCaGetResourceProfileFromTP(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "1001", - "Subject": "1002", - "Destination": "1001"}, + utils.Account: "1001", + utils.Subject: "1002", + utils.Destination: "1001"}, }, Units: 6, } @@ -1411,9 +1411,9 @@ func testV1FIdxCaGetResourceProfileFromTP(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "1002", - "Subject": "1001", - "Destination": "1002"}, + utils.Account: "1002", + utils.Subject: "1001", + utils.Destination: "1002"}, }, Units: 6, } @@ -1440,17 +1440,17 @@ func testV1FIdxCaUpdateResourceProfile(t *testing.T) { ID: "FLTR_RES_RCFG2", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"2002"}, }, &engine.FilterRule{ - FieldName: "Subject", + FieldName: utils.Subject, Type: "*string", Values: []string{"2001"}, }, &engine.FilterRule{ - FieldName: "Destination", + FieldName: utils.Destination, Type: "*string", Values: []string{"2002"}, }, @@ -1490,9 +1490,9 @@ func testV1FIdxCaUpdateResourceProfile(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "2002", - "Subject": "2001", - "Destination": "2002"}, + utils.Account: "2002", + utils.Subject: "2001", + utils.Destination: "2002"}, }, Units: 6, } @@ -1518,17 +1518,17 @@ func testV1FIdxCaUpdateResourceProfileFromTP(t *testing.T) { ID: "FLTR_RES_RCFG3", Rules: []*engine.FilterRule{ &engine.FilterRule{ - FieldName: "Account", + FieldName: utils.Account, Type: "*string", Values: []string{"1002"}, }, &engine.FilterRule{ - FieldName: "Subject", + FieldName: utils.Subject, Type: "*string", Values: []string{"1001"}, }, &engine.FilterRule{ - FieldName: "Destination", + FieldName: utils.Destination, Type: "*string", Values: []string{"1002"}, }, @@ -1562,9 +1562,9 @@ func testV1FIdxCaUpdateResourceProfileFromTP(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "1002", - "Subject": "1001", - "Destination": "1002"}, + utils.Account: "1002", + utils.Subject: "1001", + utils.Destination: "1002"}, }, Units: 6, } @@ -1591,9 +1591,9 @@ func testV1FIdxCaRemoveResourceProfile(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "2002", - "Subject": "2001", - "Destination": "2002"}, + utils.Account: "2002", + utils.Subject: "2001", + utils.Destination: "2002"}, }, Units: 6, } @@ -1612,9 +1612,9 @@ func testV1FIdxCaRemoveResourceProfile(t *testing.T) { CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]interface{}{ - "Account": "1002", - "Subject": "1001", - "Destination": "1002"}, + utils.Account: "1002", + utils.Subject: "1001", + utils.Destination: "1002"}, }, Units: 6, } diff --git a/data/tariffplans/tutorial/Attributes.csv b/data/tariffplans/tutorial/Attributes.csv index 720e2bdaf..a4dea7fc8 100644 --- a/data/tariffplans/tutorial/Attributes.csv +++ b/data/tariffplans/tutorial/Attributes.csv @@ -1,3 +1,3 @@ #Tenant,ID,Contexts,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Weight -cgrates.org,ATTR_1,*rating,*string:Account:1007,2014-01-14T00:00:00Z,Account,*any,1001,false,10 +cgrates.org,ATTR_1,*sessions;*cdrs,*string:Account:1007,2014-01-14T00:00:00Z,Account,*any,1001,false,10 cgrates.org,ATTR_1,,,,Subject,*any,1001,true, diff --git a/engine/attributes.go b/engine/attributes.go index 615dc9d25..2a186b4c1 100644 --- a/engine/attributes.go +++ b/engine/attributes.go @@ -135,6 +135,9 @@ type AttrSProcessEventReply struct { // format fldName1:fldVal1,fldName2:fldVal2 func (attrReply *AttrSProcessEventReply) Digest() (rplyDigest string) { for i, fld := range attrReply.AlteredFields { + if _, has := attrReply.CGREvent.Event[fld]; !has { + continue //maybe removed + } if i != 0 { rplyDigest += utils.FIELDS_SEP } @@ -151,30 +154,28 @@ func (alS *AttributeService) processEvent(ev *utils.CGREvent) (rply *AttrSProces return nil, err } rply = &AttrSProcessEventReply{MatchedProfile: attrPrf.ID, CGREvent: ev.Clone()} - for fldName, intialMp := range attrPrf.attributes { + for fldName, initialMp := range attrPrf.attributes { initEvValIf, has := ev.Event[fldName] - if !has { // we don't have initial in event, try append - if anyInitial, has := intialMp[utils.ANY]; has && anyInitial.Append { - if anyInitial.Substitute == interface{}(utils.META_NONE) { - delete(rply.CGREvent.Event, fldName) - } else { - rply.CGREvent.Event[fldName] = anyInitial.Substitute - rply.AlteredFields = append(rply.AlteredFields, fldName) - } + if !has { + anyInitial, hasAny := initialMp[utils.ANY] + if hasAny && anyInitial.Append && + initialMp[utils.ANY].Substitute != interface{}(utils.META_NONE) { + rply.CGREvent.Event[fldName] = anyInitial.Substitute } + rply.AlteredFields = append(rply.AlteredFields, fldName) continue } - attrVal, has := intialMp[initEvValIf] + attrVal, has := initialMp[initEvValIf] if !has { - attrVal, has = intialMp[utils.ANY] + attrVal, has = initialMp[utils.ANY] } if has { if attrVal.Substitute == interface{}(utils.META_NONE) { delete(rply.CGREvent.Event, fldName) } else { rply.CGREvent.Event[fldName] = attrVal.Substitute - rply.AlteredFields = append(rply.AlteredFields, fldName) } + rply.AlteredFields = append(rply.AlteredFields, fldName) } for _, valIface := range rply.CGREvent.Event { if valIface == interface{}(utils.MetaAttributes) { diff --git a/engine/attributes_test.go b/engine/attributes_test.go index 1f8de4271..e34977ddc 100644 --- a/engine/attributes_test.go +++ b/engine/attributes_test.go @@ -31,7 +31,7 @@ var ( expTimeAttributes = time.Now().Add(time.Duration(20 * time.Minute)) srv AttributeService dmAtr *DataManager - context = utils.MetaRating + context = utils.MetaSessionS mapSubstitutes = map[string]map[interface{}]*Attribute{ "FL1": map[interface{}]*Attribute{ "In1": &Attribute{ @@ -198,7 +198,7 @@ func TestAttributePopulateAttrService(t *testing.T) { filterS: &FilterS{dm: dmAtr}, } ref := NewFilterIndexer(dmAtr, utils.AttributeProfilePrefix, - utils.ConcatenatedKey(config.CgrConfig().DefaultTenant, utils.MetaRating)) + utils.ConcatenatedKey(config.CgrConfig().DefaultTenant, utils.MetaSessionS)) for _, atr := range atrPs { if err = dmAtr.SetAttributeProfile(atr, false); err != nil { t.Errorf("Error: %+v", err) @@ -321,6 +321,7 @@ func TestAttributeProfileForEvent(t *testing.T) { func TestAttributeProcessEvent(t *testing.T) { eRply := &AttrSProcessEventReply{ MatchedProfile: "attributeprofile1", + AlteredFields: []string{"FL1"}, CGREvent: sev, } atrp, err := srv.processEvent(sev) @@ -336,6 +337,7 @@ func TestAttributeProcessEvent(t *testing.T) { } eRply = &AttrSProcessEventReply{ MatchedProfile: "attributeprofile2", + AlteredFields: []string{"FL1"}, CGREvent: sev2, } atrp, err = srv.processEvent(sev2) @@ -351,6 +353,7 @@ func TestAttributeProcessEvent(t *testing.T) { } eRply = &AttrSProcessEventReply{ MatchedProfile: "attributeprofile3", + AlteredFields: []string{"FL1"}, CGREvent: sev3, } atrp, err = srv.processEvent(sev3) @@ -366,6 +369,7 @@ func TestAttributeProcessEvent(t *testing.T) { } eRply = &AttrSProcessEventReply{ MatchedProfile: "attributeprofile4", + AlteredFields: []string{"FL1"}, CGREvent: sev4, } atrp, err = srv.processEvent(sev4) @@ -384,15 +388,15 @@ func TestAttributeProcessEvent(t *testing.T) { func TestAttrSProcessEventReplyDigest(t *testing.T) { eRpl := &AttrSProcessEventReply{ MatchedProfile: "ATTR_1", - AlteredFields: []string{"Account", "Subject"}, + AlteredFields: []string{utils.Account, utils.Subject}, CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "1001", - "Subject": "1001", - "Destination": "+491511231234", + utils.Account: "1001", + utils.Subject: "1001", + utils.Destinations: "+491511231234", }, }, } @@ -410,11 +414,11 @@ func TestAttrSProcessEventReplyDigest2(t *testing.T) { CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "1001", - "Subject": "1001", - "Destination": "+491511231234", + utils.Account: "1001", + utils.Subject: "1001", + utils.Destinations: "+491511231234", }, }, } @@ -432,11 +436,11 @@ func TestAttrSProcessEventReplyDigest3(t *testing.T) { CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testAttributeSProcessEvent", - Context: utils.StringPointer(utils.MetaRating), + Context: utils.StringPointer(utils.MetaSessionS), Event: map[string]interface{}{ - "Account": "1001", - "Subject": "1001", - "Destination": "+491511231234", + utils.Account: "1001", + utils.Subject: "1001", + utils.Destinations: "+491511231234", }, }, } @@ -446,3 +450,24 @@ func TestAttrSProcessEventReplyDigest3(t *testing.T) { t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expRpl), utils.ToJSON(val)) } } + +func TestAttrSProcessEventReplyDigest4(t *testing.T) { + eRpl := &AttrSProcessEventReply{ + MatchedProfile: "ATTR_1", + AlteredFields: []string{"Subject"}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "testAttributeSProcessEvent", + Context: utils.StringPointer(utils.MetaSessionS), + Event: map[string]interface{}{ + utils.Account: "1001", + utils.Destinations: "+491511231234", + }, + }, + } + expRpl := "" + val := eRpl.Digest() + if !reflect.DeepEqual(val, expRpl) { + t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expRpl), utils.ToJSON(val)) + } +} diff --git a/engine/cdr.go b/engine/cdr.go index 6312c04f1..05611ac54 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -804,6 +804,9 @@ func (cdr *CDR) AsCGREvent() *utils.CGREvent { // UpdateFromCGREvent will update CDR with event fields from CGREvent func (cdr *CDR) UpdateFromCGREvent(cgrEv *utils.CGREvent, fields []string) (err error) { for _, fldName := range fields { + if _, has := cgrEv.Event[fldName]; !has { + continue //maybe removed + } switch fldName { case utils.OriginHost: if cdr.OriginHost, err = cgrEv.FieldAsString(fldName); err != nil { diff --git a/migrator/attributes_test.go b/migrator/attributes_test.go index a6d415411..b43799127 100644 --- a/migrator/attributes_test.go +++ b/migrator/attributes_test.go @@ -43,7 +43,7 @@ func Testv1AttributeProfileAsAttributeProfile(t *testing.T) { v1Attribute := &v1AttributeProfile{ Tenant: "cgrates.org", ID: "attributeprofile1", - Contexts: []string{utils.MetaRating}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"filter1"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), @@ -55,7 +55,7 @@ func Testv1AttributeProfileAsAttributeProfile(t *testing.T) { attrPrf := &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "attributeprofile1", - Contexts: []string{utils.MetaRating}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"filter1"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), diff --git a/migrator/migrator_it_test.go b/migrator/migrator_it_test.go index 6c1ee001d..486de0b3f 100644 --- a/migrator/migrator_it_test.go +++ b/migrator/migrator_it_test.go @@ -1826,7 +1826,7 @@ func testMigratorAttributeProfile(t *testing.T) { v1Attribute := &v1AttributeProfile{ Tenant: "cgrates.org", ID: "attributeprofile1", - Contexts: []string{utils.MetaRating}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"filter1"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), @@ -1838,7 +1838,7 @@ func testMigratorAttributeProfile(t *testing.T) { attrPrf := &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "attributeprofile1", - Contexts: []string{utils.MetaRating}, + Contexts: []string{utils.MetaSessionS}, FilterIDs: []string{"filter1"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),