Skip to content

Commit

Permalink
add simantic versioning support
Browse files Browse the repository at this point in the history
  • Loading branch information
AmaliMatharaarachchi committed Mar 28, 2024
1 parent 678bbe7 commit 34b9b4e
Show file tree
Hide file tree
Showing 11 changed files with 678 additions and 417 deletions.
283 changes: 180 additions & 103 deletions adapter/internal/discovery/xds/semantic_versioning.go

Large diffs are not rendered by default.

209 changes: 66 additions & 143 deletions adapter/internal/discovery/xds/semantic_versioning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package xds

import (
"reflect"
"regexp"
"testing"

Expand Down Expand Up @@ -75,22 +74,22 @@ func TestGetVersionMatchRegex(t *testing.T) {
func TestGetMajorMinorVersionRangeRegex(t *testing.T) {
tests := []struct {
name string
semVersion semantic_version.SemVersion
semVersion *semantic_version.SemVersion
expectedResult string
}{
{
name: "Major and minor version only",
semVersion: semantic_version.SemVersion{Major: 1, Minor: 2},
semVersion: &semantic_version.SemVersion{Major: 1, Minor: 2},
expectedResult: "v1(?:\\.2)?",
},
{
name: "Major, minor, and patch version",
semVersion: semantic_version.SemVersion{Major: 1, Minor: 2, Patch: PtrInt(3)},
semVersion: &semantic_version.SemVersion{Major: 1, Minor: 2, Patch: PtrInt(3)},
expectedResult: "v1(?:\\.2(?:\\.3)?)?",
},
{
name: "Major version only",
semVersion: semantic_version.SemVersion{Major: 1},
semVersion: &semantic_version.SemVersion{Major: 1},
expectedResult: "v1(?:\\.0)?",
},
}
Expand All @@ -109,22 +108,22 @@ func TestGetMajorMinorVersionRangeRegex(t *testing.T) {
func TestGetMinorVersionRangeRegex(t *testing.T) {
tests := []struct {
name string
semVersion semantic_version.SemVersion
semVersion *semantic_version.SemVersion
expectedResult string
}{
{
name: "Major, minor, and patch version",
semVersion: semantic_version.SemVersion{Version: "v1.2.3", Major: 1, Minor: 2, Patch: PtrInt(3)},
semVersion: &semantic_version.SemVersion{Version: "v1.2.3", Major: 1, Minor: 2, Patch: PtrInt(3)},
expectedResult: "v1\\.2(?:\\.3)?",
},
{
name: "Major and minor version only",
semVersion: semantic_version.SemVersion{Version: "v1.2", Major: 1, Minor: 2},
semVersion: &semantic_version.SemVersion{Version: "v1.2", Major: 1, Minor: 2},
expectedResult: "v1\\.2",
},
{
name: "Major version only",
semVersion: semantic_version.SemVersion{Version: "v1", Major: 1},
semVersion: &semantic_version.SemVersion{Version: "v1", Major: 1},
expectedResult: "v1",
},
}
Expand Down Expand Up @@ -255,7 +254,7 @@ func TestIsSemanticVersioningEnabled(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {

conf.Envoy.EnableIntelligentRouting = tt.intelligentRoutingEnabled
result := isSemanticVersioningEnabled(tt.apiName, tt.apiVersion)
result := IsSemanticVersioningEnabled(tt.apiName, tt.apiVersion)

if result != tt.expectedResult {
t.Errorf("Expected result: %v, Got: %v", tt.expectedResult, result)
Expand All @@ -264,108 +263,27 @@ func TestIsSemanticVersioningEnabled(t *testing.T) {
}
}

func TestGetRoutesForAPIIdentifier(t *testing.T) {

orgAPIMap = map[string]map[string]*EnvoyInternalAPI{
"org1": {
"gw.com:apiID1": &EnvoyInternalAPI{
routes: []*routev3.Route{
{
Name: "route1",
},
{
Name: "route2",
},
},
},
"gw.com:apiID2": &EnvoyInternalAPI{
routes: []*routev3.Route{
{
Name: "route3",
},
},
},
},
"org2": {
"test.gw.com:apiID1": &EnvoyInternalAPI{
routes: []*routev3.Route{
{
Name: "route4",
},
},
},
},
}

tests := []struct {
name string
organizationID string
apiIdentifier string
expectedRoutes []*routev3.Route
expectedNumRoute int
}{
{
name: "Existing organization and API identifier",
organizationID: "org1",
apiIdentifier: "gw.com:apiID1",
expectedRoutes: []*routev3.Route{
{
Name: "route1",
},
{
Name: "route2",
},
},
expectedNumRoute: 2,
},
{
name: "Non-existing organization",
organizationID: "org3",
apiIdentifier: "dev.gw.com:apiID1",
expectedRoutes: []*routev3.Route{},
expectedNumRoute: 0,
},
{
name: "Non-existing API identifier",
organizationID: "org1",
apiIdentifier: "api3",
expectedRoutes: []*routev3.Route{},
expectedNumRoute: 0,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := getRoutesForAPIIdentifier(tt.organizationID, tt.apiIdentifier)

if len(result) != tt.expectedNumRoute {
t.Errorf("Expected number of routes: %d, Got: %d", tt.expectedNumRoute, len(result))
}

if len(result) > 0 {
if !reflect.DeepEqual(result, tt.expectedRoutes) {
t.Errorf("Expected routes: %v, Got: %v", tt.expectedRoutes, result)
}
}
})
}
}

func TestUpdateRoutingRulesOnAPIUpdate(t *testing.T) {

var apiID1 model.AdapterInternalAPI
apiID1.SetName("Test API")
apiID1.UUID = "apiID1"
apiID1.OrganizationID = "org1"
apiID1.SetVersion("v1.0")
apiID1ResourcePath := "^/test-api/v1\\.0/orders([/]{0,1})"

var apiID2 model.AdapterInternalAPI
apiID2.SetName("Mock API")
apiID2.UUID = "apiID2"
apiID2.OrganizationID = "org1"
apiID2.SetVersion("v1.1")
apiID2ResourcePath := "^/mock-api/v1\\.1/orders([/]{0,1})"

var apiID3 model.AdapterInternalAPI
apiID3.SetName("Test API")
apiID3.SetVersion("v1.1")
apiID3.OrganizationID = "org1"
apiID3.UUID = "apiID3"
apiID3ResourcePath := "^/test-api/v1\\.1/orders([/]{0,1})"

orgAPIMap = map[string]map[string]*EnvoyInternalAPI{
Expand All @@ -386,59 +304,61 @@ func TestUpdateRoutingRulesOnAPIUpdate(t *testing.T) {
}

tests := []struct {
name string
organizationID string
apiIdentifier string
apiName string
apiVersion string
vHost string
expectedRegex string
expectedRewrite string
finalRegex string
finalRewrite string
name string
api model.AdapterInternalAPI
organizationID string
apiRangeIdentifier string
apiIdentifier string
vhost string
expectedRegex string
expectedRewrite string
finalRegex string
finalRewrite string
}{
{
name: "Create an API with major version",
organizationID: "org1",
apiIdentifier: "gw.com:apiID1",
apiName: "Test API",
apiVersion: "v1.0",
vHost: "gw.com",
expectedRegex: "^/test-api/v1(?:\\.0)?/orders([/]{0,1})",
expectedRewrite: "^/test-api/v1(?:\\.0)?/orders([/]{0,1})",
finalRegex: apiID1ResourcePath,
finalRewrite: apiID1ResourcePath,
},
name: "Create an API with major version",
organizationID: "org1",
apiRangeIdentifier: "gw.com:Test API",
apiIdentifier: "gw.com:apiID1",
vhost: "gw.com",
api: apiID1,
expectedRegex: "^/test-api/v1(?:\\.0)?/orders([/]{0,1})",
expectedRewrite: "^/test-api/v1(?:\\.0)?/orders([/]{0,1})",
finalRegex: apiID1ResourcePath,
finalRewrite: apiID1ResourcePath,
},
// Expected final regex: ^/test-api/v1\.0/orders([/]{0,1}), Got: ^/test-api/v1(?:\.0)?/orders([/]{0,1})
{
name: "Create an API with major and minor version",
organizationID: "org1",
apiIdentifier: "gw.com:apiID2",
apiName: "Mock API",
apiVersion: "v1.1",
vHost: "gw.com",
expectedRegex: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
expectedRewrite: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRegex: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRewrite: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
name: "Create an API with major and minor version",
organizationID: "org1",
apiRangeIdentifier: "gw.com:Mock API",
apiIdentifier: "gw.com:apiID2",
vhost: "gw.com",
api: apiID2,
expectedRegex: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
expectedRewrite: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRegex: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRewrite: "^/mock-api/v1(?:\\.1)?/orders([/]{0,1})",
},
{
name: "Create an API with major and minor version",
organizationID: "org1",
apiIdentifier: "gw.com:apiID3",
apiName: "Test API",
apiVersion: "v1.1",
vHost: "gw.com",
expectedRegex: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
expectedRewrite: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRegex: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRewrite: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
name: "Create an API with major and minor version",
organizationID: "org1",
apiRangeIdentifier: "gw.com:Test API",
apiIdentifier: "gw.com:apiID3",
vhost: "gw.com",
api: apiID3,
expectedRegex: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
expectedRewrite: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRegex: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
finalRewrite: "^/test-api/v1(?:\\.1)?/orders([/]{0,1})",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

updateRoutingRulesOnAPIUpdate(tt.organizationID, tt.apiIdentifier, tt.apiName, tt.apiVersion, tt.vHost)
updateSemanticVersioningInMapForUpdateAPI(tt.organizationID,
map[string]struct{}{tt.apiRangeIdentifier: {}}, &tt.api)
updateSemRegexForNewAPI(tt.api, orgAPIMap[tt.organizationID][tt.apiIdentifier].routes, tt.vhost)
api1 := orgAPIMap[tt.organizationID][tt.apiIdentifier]
routes := api1.routes

Expand Down Expand Up @@ -539,16 +459,19 @@ func TestUpdateRoutingRulesOnAPIDelete(t *testing.T) {

var apiID1 model.AdapterInternalAPI
apiID1.SetName("Test API")
apiID1.UUID = "apiID1"
apiID1.SetVersion("v1.0")
apiID1ResourcePath := "^/test-api/v1\\.0/orders([/]{0,1})"

var apiID2 model.AdapterInternalAPI
apiID2.SetName("Mock API")
apiID2.UUID = "apiID2"
apiID2.SetVersion("v1.0")
apiID2ResourcePath := "^/mock-api/v1\\.0/orders([/]{0,1})"

var apiID3 model.AdapterInternalAPI
apiID3.SetName("Mock API")
apiID3.UUID = "apiID3"
apiID3.SetVersion("v1.5")
apiID3ResourcePath := "^/mock-api/v1(?:\\.5)?/orders([/]{0,1})"

Expand Down Expand Up @@ -581,22 +504,22 @@ func TestUpdateRoutingRulesOnAPIDelete(t *testing.T) {
{
name: "Delete latest major version",
organizationID: "org3",
apiIdentifier: "gw.com:apiID1",
apiIdentifier: "gw.com:Test API",
api: &apiID1,
deleteVersion: "v1.0",
},
{
name: "Delete latest minor version",
organizationID: "org4",
apiIdentifier: "gw.com:apiID3",
apiIdentifier: "gw.com:Mock API",
api: &apiID3,
deleteVersion: "v1.5",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
updateSemanticVersioning(tt.organizationID, map[string]struct{}{tt.apiIdentifier: {}})
RemoveAPIFromAllInternalMaps(tt.api.UUID)
if _, ok := orgIDLatestAPIVersionMap[tt.organizationID]; ok {
if _, ok := orgIDLatestAPIVersionMap[tt.organizationID][tt.apiIdentifier]; ok {
if _, ok := orgIDLatestAPIVersionMap[tt.organizationID][tt.apiIdentifier][tt.deleteVersion]; ok {
Expand Down
Loading

0 comments on commit 34b9b4e

Please sign in to comment.