Skip to content

Commit

Permalink
Add unit tests for update and delete methods in sem versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
pubudu538 committed Feb 27, 2024
1 parent e8dbcf7 commit d24aa49
Showing 1 changed file with 356 additions and 0 deletions.
356 changes: 356 additions & 0 deletions adapter/internal/discovery/xds/semantic_versioning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
package xds

import (
"reflect"
"regexp"
"testing"

routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
envoy_type_matcherv3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
"github.com/wso2/apk/adapter/config"
"github.com/wso2/apk/adapter/internal/oasparser/model"
semantic_version "github.com/wso2/apk/adapter/pkg/semanticversion"
)

Expand Down Expand Up @@ -322,6 +326,358 @@ func TestIsVHostMatched(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.SetVersion("v1.0")
apiID1ResourcePath := "^/test-api/v1\\.0/orders([/]{0,1})"

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

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

orgAPIMap = map[string]map[string]*EnvoyInternalAPI{
"org1": {
"gw.com:apiID1": &EnvoyInternalAPI{
adapterInternalAPI: apiID1,
routes: generateRoutes(apiID1ResourcePath),
},
"gw.com:apiID2": &EnvoyInternalAPI{
adapterInternalAPI: apiID2,
routes: generateRoutes(apiID2ResourcePath),
},
"gw.com:apiID3": &EnvoyInternalAPI{
adapterInternalAPI: apiID3,
routes: generateRoutes(apiID3ResourcePath),
},
},
}

orgIDAPIvHostsMap = map[string]map[string][]string{
"org1": {
"api1": {"gw.com", "api.example.com"},
"api2": {"test.com"},
},
}

tests := []struct {
name string
organizationID string
apiIdentifier string
apiName string
apiVersion 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 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",
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})",
},
}

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

updateRoutingRulesOnAPIUpdate(tt.organizationID, tt.apiIdentifier, tt.apiName, tt.apiVersion, tt.vHost)
api1 := orgAPIMap[tt.organizationID][tt.apiIdentifier]
routes := api1.routes

if routes[0].GetMatch().GetSafeRegex().GetRegex() != tt.expectedRegex {
t.Errorf("Expected regex: %s, Got: %s", tt.expectedRegex, routes[0].GetMatch().GetSafeRegex().GetRegex())
}
if routes[0].GetRoute().GetRegexRewrite().GetPattern().GetRegex() != tt.expectedRewrite {
t.Errorf("Expected rewrite pattern: %s, Got: %s", tt.expectedRewrite, routes[0].GetRoute().GetRegexRewrite().GetPattern().GetRegex())
}
})
}

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

api1 := orgAPIMap[tt.organizationID][tt.apiIdentifier]
routes := api1.routes

if routes[0].GetMatch().GetSafeRegex().GetRegex() != tt.finalRegex {
t.Errorf("Expected final regex: %s, Got: %s", tt.finalRegex, routes[0].GetMatch().GetSafeRegex().GetRegex())
}
if routes[0].GetRoute().GetRegexRewrite().GetPattern().GetRegex() != tt.finalRewrite {
t.Errorf("Expected final rewrite pattern: %s, Got: %s", tt.finalRewrite, routes[0].GetRoute().GetRegexRewrite().GetPattern().GetRegex())
}
})
}
}

func generateRoutes(resourcePath string) []*routev3.Route {

var routes []*routev3.Route
match := &routev3.RouteMatch{
PathSpecifier: &routev3.RouteMatch_SafeRegex{
SafeRegex: &envoy_type_matcherv3.RegexMatcher{
Regex: resourcePath,
},
},
}

action := &routev3.Route_Route{
Route: &routev3.RouteAction{
RegexRewrite: &envoy_type_matcherv3.RegexMatchAndSubstitute{
Pattern: &envoy_type_matcherv3.RegexMatcher{
Regex: resourcePath,
},
Substitution: "/bar",
},
},
}

route := routev3.Route{
Name: "example-route",
Match: match,
Action: action,
Metadata: nil,
Decorator: nil,
}

return append(routes, &route)
}

func TestUpdateRoutingRulesOnAPIDelete(t *testing.T) {

orgIDLatestAPIVersionMap = map[string]map[string]map[string]semantic_version.SemVersion{
"org3": {
"gw.com:Test API": {
"v1": {
Version: "v1.0",
Major: 1,
Minor: 0,
Patch: nil,
},
},
},
"org4": {
"gw.com:Mock API": {
"v1.0": {
Version: "v1.0",
Major: 1,
Minor: 0,
Patch: nil,
},
"v1.5": {
Version: "v1.5",
Major: 1,
Minor: 5,
Patch: nil,
},
"v1": {
Version: "v1.5",
Major: 1,
Minor: 5,
Patch: nil,
},
},
},
}

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

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

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

orgAPIMap = map[string]map[string]*EnvoyInternalAPI{
"org3": {
"gw.com:apiID1": &EnvoyInternalAPI{
adapterInternalAPI: apiID1,
routes: generateRoutes(apiID1ResourcePath),
},
},
"org4": {
"gw.com:apiID2": &EnvoyInternalAPI{
adapterInternalAPI: apiID2,
routes: generateRoutes(apiID2ResourcePath),
},
"gw.com:apiID3": &EnvoyInternalAPI{
adapterInternalAPI: apiID3,
routes: generateRoutes(apiID3ResourcePath),
},
},
}

tests := []struct {
name string
organizationID string
apiIdentifier string
api model.AdapterInternalAPI
deleteVersion string
}{
{
name: "Delete latest major version",
organizationID: "org3",
apiIdentifier: "gw.com:apiID1",
api: apiID1,
deleteVersion: "v1.0",
},
{
name: "Delete latest minor version",
organizationID: "org4",
apiIdentifier: "gw.com:apiID3",
api: apiID3,
deleteVersion: "v1.5",
},
}

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

if _, ok := orgIDLatestAPIVersionMap[tt.organizationID]; ok {
if _, ok := orgIDLatestAPIVersionMap[tt.organizationID][tt.apiIdentifier]; ok {
if _, ok := orgIDLatestAPIVersionMap[tt.organizationID][tt.apiIdentifier][tt.deleteVersion]; ok {
t.Errorf("API deletion is not successful: %s", tt.deleteVersion)
}
}
}
})
}
}

// PtrInt returns a pointer to an integer value
func PtrInt(i int) *int {
return &i
Expand Down

0 comments on commit d24aa49

Please sign in to comment.