diff --git a/migrator/attributes.go b/migrator/attributes.go index f5a3dc398..8325a46e1 100644 --- a/migrator/attributes.go +++ b/migrator/attributes.go @@ -157,9 +157,6 @@ func (m *Migrator) migrateV1ToV4AttributeProfile() (v4Attr *v4AttributeProfile, if err != nil { return nil, err } - // if m.dryRun { - // continue - // } return } @@ -215,13 +212,6 @@ func (m *Migrator) migrateV2ToV3AttributeProfile(v2Attr *v2AttributeProfile) (v3 if err != nil { return nil, err } - // remove the AttributeProfile after it was migrated - m.dmIN.remV2AttributeProfile(v2Attr.Tenant, v2Attr.ID) - // if m.dryRun { - // continue - // } - - // Return the migrated attributeProfile return v3Attr, nil } @@ -277,11 +267,6 @@ func (m *Migrator) migrateV3ToV4AttributeProfile(v3Attr *v3AttributeProfile) (v4 if err != nil { return nil, err } - //remove the migrated attribute - m.dmIN.remV2AttributeProfile(v3Attr.Tenant, v3Attr.ID) - // if m.dryRun { - // continue - // } return v4Attr, nil } @@ -337,12 +322,6 @@ func (m *Migrator) migrateV4ToV5AttributeProfile(v4Attr *v4AttributeProfile) (v5 if err != nil { return nil, err } - //remove the migrated attribute - m.dmIN.remV2AttributeProfile(v4Attr.Tenant, v4Attr.ID) - // if m.dryRun { - // continue - // } - return v5Attr, nil } @@ -407,61 +386,69 @@ func (m *Migrator) migrateAttributeProfileV2() (err error) { var v4Attr *v4AttributeProfile var v5Attr *engine.AttributeProfile - fmt.Println("BEFORE vrs[utils.Attributes]: ", vrs[utils.Attributes]) for { // One attribute profile at a time + version := vrs[utils.Attributes] for { //Keep migrating until Attribute Profile reaches latest version - switch vrs[utils.Attributes] { + switch version { case 1: // Migrate from V1 to V4 if v4Attr, err = m.migrateV1ToV4AttributeProfile(); err != nil && err != utils.ErrNoMoreData { return err } else if err == utils.ErrNoMoreData { - continue + break } //Update to version to 4 (shortcut) - vrs[utils.Attributes] = 4 + version = 4 case 2: // Migrate from V2 to V3 (fallthrough untill latest version) if v3Attr, err = m.migrateV2ToV3AttributeProfile(v2Attr); err != nil && err != utils.ErrNoMoreData { return err } else if err == utils.ErrNoMoreData { - continue + break } - vrs[utils.Attributes] = 3 + version = 3 fallthrough case 3: // Migrate from V3 to V4 if v4Attr, err = m.migrateV3ToV4AttributeProfile(v3Attr); err != nil && err != utils.ErrNoMoreData { return err } else if err == utils.ErrNoMoreData { - continue + break } - vrs[utils.Attributes] = 4 - fmt.Println("V3toV4") + version = 4 fallthrough case 4: // Migrate from V4 to V5 if v5Attr, err = m.migrateV4ToV5AttributeProfile(v4Attr); err != nil && err != utils.ErrNoMoreData { return err } else if err == utils.ErrNoMoreData { - continue + + break } - vrs[utils.Attributes] = 5 - fmt.Println("V4toV5") + version = 5 } - //update the encoded string 5 with current verison - if vrs[utils.Attributes] == 5 { + if version == 5 || err == utils.ErrNoMoreData { break } } - - fmt.Println("v5Attr: ", utils.ToIJSON(v5Attr)) - //Set the fresh-migrated AttributeProfile into DB - if err := m.dmOut.DataManager().SetAttributeProfile(v5Attr, true); err != nil { - fmt.Println("Exit HERE <<<<<") - return err + if err == utils.ErrNoMoreData { + break } + if !m.dryRun { + if vrs[utils.Attributes] == 1 { + if err := m.dmOut.DataManager().DataDB().SetAttributeProfileDrv(v5Attr); err != nil { + return err + } + } + //Set the fresh-migrated AttributeProfile into DB + if err := m.dmOut.DataManager().SetAttributeProfile(v5Attr, true); err != nil { + return err + } + } m.stats[utils.Attributes]++ - break + + } + if m.dryRun { + return nil } // All done, update version wtih current one vrs = engine.Versions{utils.Attributes: engine.CurrentDataDBVersions()[utils.Attributes]} @@ -470,6 +457,7 @@ func (m *Migrator) migrateAttributeProfileV2() (err error) { fmt.Sprintf("error: <%s> when updating Attributes version into dataDB", err.Error())) } return m.ensureIndexesDataDB(engine.ColAttr) + } func (v1AttrPrf v1AttributeProfile) AsAttributeProfile() (attrPrf *engine.AttributeProfile, err error) { diff --git a/migrator/attributes_it_test.go b/migrator/attributes_it_test.go index bb18fd0ca..a93e0110b 100755 --- a/migrator/attributes_it_test.go +++ b/migrator/attributes_it_test.go @@ -55,8 +55,10 @@ var sTestsAttrIT = []func(t *testing.T){ testAttrITMigrateV4, // testAttrITFlush, // testAttrITV1ToV2, - // testAttrITFlush, - // testAttrITV1ToV4, + testAttrITFlush, + testAttrITV1ToV5, + testAttrITFlush, + testAttrITV2ToV5, } func TestAttributeITRedis(t *testing.T) { @@ -730,7 +732,7 @@ func testAttrITV1ToV2(t *testing.T) { } -func testAttrITV1ToV4(t *testing.T) { +func testAttrITV1ToV5(t *testing.T) { // contruct the v1 attribute with all fields filled up mapSubstitutes := make(map[string]map[string]*v1Attribute) mapSubstitutes["FL1"] = make(map[string]*v1Attribute) @@ -740,7 +742,7 @@ func testAttrITV1ToV4(t *testing.T) { Substitute: "Al1", Append: true, } - v1Attribute := &v1AttributeProfile{ + v1AttributeProfile1 := &v1AttributeProfile{ Tenant: "cgrates.org", ID: "attributeprofile1", Contexts: []string{utils.MetaSessionS}, @@ -752,9 +754,25 @@ func testAttrITV1ToV4(t *testing.T) { Attributes: mapSubstitutes, Weight: 20, } + //second attribute profile + v1AttributeProfile2 := &v1AttributeProfile{ + Tenant: "cgrates.org", + ID: "attributeprofile2", + Contexts: []string{utils.MetaSessionS}, + FilterIDs: []string{"*string:test:test"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, 4, 18, 14, 25, 0, 0, time.UTC), + }, + Attributes: mapSubstitutes, + Weight: 20, + } //set attribute into inDB - attrMigrator.dmIN.setV1AttributeProfile(v1Attribute) + attrMigrator.dmIN.setV1AttributeProfile(v1AttributeProfile1) + //set the second attr profile + attrMigrator.dmIN.setV1AttributeProfile(v1AttributeProfile2) + //set attributes version into DB if err := attrMigrator.dmIN.DataManager().DataDB().SetVersions(engine.Versions{utils.Attributes: 1}, true); err != nil { t.Errorf("error: <%s> when updating Attributes version into dataDB", err.Error()) @@ -764,7 +782,7 @@ func testAttrITV1ToV4(t *testing.T) { if err != nil { t.Error("Error converting Substitute from string to RSRParser: ", err) } - eOut := &engine.AttributeProfile{ + eOut1 := &engine.AttributeProfile{ Tenant: "cgrates.org", ID: "attributeprofile1", Contexts: []string{utils.MetaSessionS}, @@ -782,6 +800,24 @@ func testAttrITV1ToV4(t *testing.T) { }}, Weight: 20, } + eOut2 := &engine.AttributeProfile{ + Tenant: "cgrates.org", + ID: "attributeprofile2", + Contexts: []string{utils.MetaSessionS}, + FilterIDs: []string{"*string:test:test"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, 4, 18, 14, 25, 0, 0, time.UTC), + }, + Attributes: []*engine.Attribute{ + &engine.Attribute{ + FilterIDs: []string{"*string:FL1:In1"}, + Path: utils.MetaReq + utils.NestingSep + "FL1", + Type: utils.MetaVariable, + Value: sbstPrsr, + }}, + Weight: 20, + } //Migrate to latest version if err := attrMigrator.migrateAttributeProfileV2(); err != nil { @@ -793,15 +829,159 @@ func testAttrITV1ToV4(t *testing.T) { } else if vrs[utils.Attributes] != 5 { t.Errorf("Unexpected version returned: %d", vrs[utils.Attributes]) } - //check the content - result, err := attrMigrator.dmOut.DataManager().GetAttributeProfile("cgrates.com", + + //check the first AttributeProfile + result, err := attrMigrator.dmOut.DataManager().GetAttributeProfile("cgrates.org", "attributeprofile1", false, false, utils.NonTransactional) if err != nil { - t.Fatal(err) + t.Error(err) //only encoded map or array can be decoded into a struct + + } else { + result.Compile() + eOut1.Compile() + if !reflect.DeepEqual(result, eOut1) { + t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eOut1), utils.ToJSON(result)) + } } - result.Compile() - eOut.Compile() - if !reflect.DeepEqual(result, eOut) { - t.Errorf("Expecting: %+v, received: %+v", eOut, result) + //check the second AttributeProfile + result, err = attrMigrator.dmOut.DataManager().GetAttributeProfile("cgrates.org", + "attributeprofile2", false, false, utils.NonTransactional) + if err != nil { + t.Error(err) + } else { + result.Compile() + eOut2.Compile() + if !reflect.DeepEqual(result, eOut2) { + t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eOut2), utils.ToJSON(result)) + } + } +} + +func testAttrITV2ToV5(t *testing.T) { + // contruct the v1 attribute profile with all fields filled up + sbstPrsr, err := config.NewRSRParsers("Al1", true, config.CgrConfig().GeneralCfg().RSRSep) + if err != nil { + t.Error("Error converting Substitute from string to RSRParser: ", err) + } + v2AttributeProfile1 := &v2AttributeProfile{ + Tenant: "cgrates.org", + ID: "attributeprofile1", + Contexts: []string{utils.MetaSessionS}, + FilterIDs: []string{"*string:test:test"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, 4, 18, 14, 25, 0, 0, time.UTC), + }, + Attributes: []*v2Attribute{ + &v2Attribute{ + FieldName: "FL1", + Initial: "In1", + Substitute: sbstPrsr, + Append: true, + }}, + Weight: 20, + } + //second attribute profile + v2AttributeProfile2 := &v2AttributeProfile{ + Tenant: "cgrates.org", + ID: "attributeprofile2", + Contexts: []string{utils.MetaSessionS}, + FilterIDs: []string{"*string:test:test"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, 4, 18, 14, 25, 0, 0, time.UTC), + }, + Attributes: []*v2Attribute{ + &v2Attribute{ + FieldName: "FL1", + Initial: "In1", + Substitute: sbstPrsr, + Append: true, + }}, + Weight: 20, + } + + //set attribute into inDB + attrMigrator.dmIN.setV2AttributeProfile(v2AttributeProfile1) + //set the second attr profile + attrMigrator.dmIN.setV2AttributeProfile(v2AttributeProfile2) + + //set attributes version into DB + if err := attrMigrator.dmIN.DataManager().DataDB().SetVersions(engine.Versions{utils.Attributes: 2}, true); err != nil { + t.Errorf("error: <%s> when updating Attributes version into dataDB", err.Error()) + } + + eOut1 := &engine.AttributeProfile{ + Tenant: "cgrates.org", + ID: "attributeprofile1", + Contexts: []string{utils.MetaSessionS}, + FilterIDs: []string{"*string:test:test"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, 4, 18, 14, 25, 0, 0, time.UTC), + }, + Attributes: []*engine.Attribute{ + &engine.Attribute{ + FilterIDs: []string{"*string:FL1:In1"}, + Path: utils.MetaReq + utils.NestingSep + "FL1", + Type: utils.MetaVariable, + Value: sbstPrsr, + }}, + Weight: 20, + } + eOut2 := &engine.AttributeProfile{ + Tenant: "cgrates.org", + ID: "attributeprofile2", + Contexts: []string{utils.MetaSessionS}, + FilterIDs: []string{"*string:test:test"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, 4, 18, 14, 25, 0, 0, time.UTC), + }, + Attributes: []*engine.Attribute{ + &engine.Attribute{ + FilterIDs: []string{"*string:FL1:In1"}, + Path: utils.MetaReq + utils.NestingSep + "FL1", + Type: utils.MetaVariable, + Value: sbstPrsr, + }}, + Weight: 20, + } + + //Migrate to latest version + if err := attrMigrator.migrateAttributeProfileV2(); err != nil { + t.Error(err) + } + //check the version + if vrs, err := attrMigrator.dmOut.DataManager().DataDB().GetVersions(""); err != nil { + t.Error(err) + } else if vrs[utils.Attributes] != 5 { + t.Errorf("Unexpected version returned: %d", vrs[utils.Attributes]) + } + + //check the first AttributeProfile + result, err := attrMigrator.dmOut.DataManager().GetAttributeProfile("cgrates.org", + "attributeprofile1", false, false, utils.NonTransactional) + if err != nil { + t.Error(err) //only encoded map or array can be decoded into a struct + + } else { + result.Compile() + eOut1.Compile() + if !reflect.DeepEqual(result, eOut1) { + t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eOut1), utils.ToJSON(result)) + } + } + //check the second AttributeProfile + result, err = attrMigrator.dmOut.DataManager().GetAttributeProfile("cgrates.org", + "attributeprofile2", false, false, utils.NonTransactional) + if err != nil { + t.Error(err) + } else { + result.Compile() + eOut2.Compile() + if !reflect.DeepEqual(result, eOut2) { + t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eOut2), utils.ToJSON(result)) + } } }