github.com/Axway/agent-sdk@v1.1.101/pkg/apic/specparser_test.go (about)

     1  package apic
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"gopkg.in/yaml.v3"
    10  )
    11  
    12  func createSpecParser(specFile, specType string) (SpecResourceParser, error) {
    13  	specFileDescriptor, _ := os.Open(specFile)
    14  	specData, _ := io.ReadAll(specFileDescriptor)
    15  	specParser := NewSpecResourceParser(specData, specType)
    16  	err := specParser.Parse()
    17  	return specParser, err
    18  }
    19  
    20  func TestSpecDiscovery(t *testing.T) {
    21  	tests := []struct {
    22  		name         string
    23  		inputFile    string
    24  		inputType    string
    25  		parseErr     bool
    26  		expectedType string
    27  	}{
    28  		{
    29  			name:      "Protobuf input type with OAS3 Spec",
    30  			inputFile: "./testdata/petstore-openapi3.json",
    31  			parseErr:  true,
    32  			inputType: Protobuf,
    33  		},
    34  		{
    35  			name:      "Protobuf input type with OAS2 Spec",
    36  			inputFile: "./testdata/petstore-openapi2.yaml",
    37  			parseErr:  true,
    38  			inputType: AsyncAPI,
    39  		},
    40  		{
    41  			name:      "OAS3 input type with WSDL Spec",
    42  			inputFile: "./testdata/weather.xml",
    43  			parseErr:  true,
    44  			inputType: Oas3,
    45  		},
    46  		{
    47  			name:      "AsyncAPI input type with Protobuf Spec",
    48  			inputFile: "./testdata/petstore.proto",
    49  			parseErr:  true,
    50  			inputType: Oas2,
    51  		},
    52  		{
    53  			name:      "Protobuf input type with AsyncAPI Spec",
    54  			inputFile: "./testdata/asyncapi-sample.yaml",
    55  			parseErr:  true,
    56  			inputType: Wsdl,
    57  		},
    58  		{
    59  			name:      "Raml input type with no valid raml version provided",
    60  			inputFile: "./testdata/raml_invalid.raml",
    61  			parseErr:  true,
    62  			inputType: Raml,
    63  		},
    64  		{
    65  			name:         "No input type bad OAS version creates Unstructured",
    66  			inputFile:    "./testdata/petstore-openapi-bad-version.json",
    67  			parseErr:     true,
    68  			expectedType: Unstructured,
    69  		},
    70  		{
    71  			name:         "No input type bad Swagger version creates Unstructured",
    72  			inputFile:    "./testdata/petstore-swagger-bad-version.json",
    73  			parseErr:     true,
    74  			expectedType: Unstructured,
    75  		},
    76  		{
    77  			name:         "No input type OAS3 Spec",
    78  			inputFile:    "./testdata/petstore-openapi3.json",
    79  			expectedType: Oas3,
    80  		},
    81  		{
    82  			name:         "No input type OAS2 Spec",
    83  			inputFile:    "./testdata/petstore-openapi2.yaml",
    84  			expectedType: Oas2,
    85  		},
    86  		{
    87  			name:         "No input type OAS2 swagger Spec",
    88  			inputFile:    "./testdata/petstore-swagger2.json",
    89  			expectedType: Oas2,
    90  		},
    91  		{
    92  			name:         "No input type OAS2 swagger Spec yaml",
    93  			inputFile:    "./testdata/petstore-swagger2.yaml",
    94  			expectedType: Oas2,
    95  		},
    96  		{
    97  			name:         "No input type WSDL Spec",
    98  			inputFile:    "./testdata/weather.xml",
    99  			parseErr:     false,
   100  			expectedType: Wsdl,
   101  		},
   102  		{
   103  			name:         "No input type Protobuf Spec",
   104  			inputFile:    "./testdata/petstore.proto",
   105  			parseErr:     false,
   106  			expectedType: Protobuf,
   107  		},
   108  		{
   109  			name:         "No input type AsyncAPI Spec YAML",
   110  			inputFile:    "./testdata/asyncapi-sample.yaml",
   111  			expectedType: AsyncAPI,
   112  		},
   113  		{
   114  			name:         "No input type Raml 1.0 spec",
   115  			inputFile:    "./testdata/raml_10.raml",
   116  			expectedType: Raml,
   117  		},
   118  		{
   119  			name:         "No input type Raml 0.8 spec",
   120  			inputFile:    "./testdata/raml_08.raml",
   121  			expectedType: Raml,
   122  		},
   123  		{
   124  			name:         "No input type Unstructured",
   125  			inputFile:    "./testdata/multiplication.thrift",
   126  			parseErr:     true,
   127  			expectedType: Unstructured,
   128  		},
   129  	}
   130  
   131  	for _, tc := range tests {
   132  		t.Run(tc.name, func(t *testing.T) {
   133  			specParser, err := createSpecParser(tc.inputFile, tc.inputType)
   134  			if tc.parseErr {
   135  				assert.NotNil(t, err)
   136  				return
   137  			}
   138  			assert.Nil(t, err)
   139  			specProcessor := specParser.GetSpecProcessor()
   140  			assert.NotNil(t, specProcessor)
   141  			assert.Equal(t, tc.expectedType, specProcessor.GetResourceType())
   142  			if tc.expectedType != specProcessor.GetResourceType() {
   143  				return
   144  			}
   145  			ok := false
   146  			switch tc.expectedType {
   147  			case Oas3:
   148  				_, ok = specProcessor.(*oas3SpecProcessor)
   149  				ValidateOAS3Processors(t, specParser)
   150  			case Oas2:
   151  				_, ok = specProcessor.(*oas2SpecProcessor)
   152  				ValidateOAS2Processors(t, specParser, tc.inputFile)
   153  			case Wsdl:
   154  				_, ok = specProcessor.(*wsdlProcessor)
   155  				ValidateWsdlProcessors(t, specParser)
   156  			case Protobuf:
   157  				_, ok = specProcessor.(*protobufProcessor)
   158  				ValidateProtobufProcessors(t, specParser)
   159  			case AsyncAPI:
   160  				_, ok = specProcessor.(*asyncAPIProcessor)
   161  				ValidateAsyncAPIProcessors(t, specParser)
   162  			case Raml:
   163  				_, ok = specProcessor.(*ramlProcessor)
   164  				ValidateRamlProcessors(t, specParser, tc.inputFile)
   165  			case Unstructured:
   166  				_, ok = specProcessor.(*unstructuredProcessor)
   167  			}
   168  			assert.True(t, ok)
   169  		})
   170  	}
   171  }
   172  
   173  func TestLoadRamlAsYaml(t *testing.T) {
   174  	var v map[string]interface{}
   175  	yamlFile, err := os.ReadFile("./testdata/raml_08.raml")
   176  	assert.Nil(t, err)
   177  
   178  	err = yaml.Unmarshal(yamlFile, &v)
   179  	assert.Nil(t, err)
   180  
   181  	yamlFile, err = os.ReadFile("./testdata/raml_10.raml")
   182  	assert.Nil(t, err)
   183  
   184  	err = yaml.Unmarshal(yamlFile, &v)
   185  	assert.Nil(t, err)
   186  }
   187  
   188  func ValidateOAS3Processors(t *testing.T, specParser SpecResourceParser) {
   189  	// JSON OAS3 specification
   190  	specProcessor := specParser.GetSpecProcessor()
   191  	endPoints, err := specProcessor.GetEndpoints()
   192  
   193  	assert.Nil(t, err, "An unexpected Error was returned from getEndpoints with oas3")
   194  	assert.Len(t, endPoints, 3, "The returned end points array did not have exactly 3 endpoints")
   195  	assert.Equal(t, "petstore.swagger.io", endPoints[0].Host, "The first returned end point had an unexpected value for it's host")
   196  	assert.Equal(t, int32(8080), endPoints[0].Port, "The first returned end point had an unexpected value for it's port")
   197  	assert.Equal(t, "http", endPoints[0].Protocol, "The first returned end point had an unexpected value for it's protocol")
   198  	assert.Equal(t, "petstore.swagger.io", endPoints[1].Host, "The second returned end point had an unexpected value for it's host")
   199  	assert.Equal(t, int32(80), endPoints[1].Port, "The second returned end point had an unexpected value for it's port")
   200  	assert.Equal(t, "http", endPoints[1].Protocol, "The second returned end point had an unexpected value for it's protocol")
   201  	assert.Equal(t, "petstore.swagger.io", endPoints[2].Host, "The third returned end point had an unexpected value for it's host")
   202  	assert.Equal(t, int32(443), endPoints[2].Port, "The third returned end point had an unexpected value for it's port")
   203  	assert.Equal(t, "https", endPoints[2].Protocol, "The third returned end point had an unexpected value for it's protocol")
   204  
   205  	specParser, err = createSpecParser("./testdata/petstore-openapi3-template-urls.json", Oas3)
   206  	assert.Nil(t, err)
   207  	specProcessor = specParser.GetSpecProcessor()
   208  	assert.NotNil(t, specProcessor)
   209  	endPoints, err = specProcessor.GetEndpoints()
   210  
   211  	type verification struct {
   212  		Host     string
   213  		Port     int32
   214  		Protocol string
   215  		Found    bool
   216  	}
   217  
   218  	possibleEndpoints := []verification{
   219  		{
   220  			Host:     "petstore.swagger.io",
   221  			Port:     443,
   222  			Protocol: "https",
   223  		},
   224  		{
   225  			Host:     "petstore.swagger.io",
   226  			Port:     80,
   227  			Protocol: "http",
   228  		},
   229  		{
   230  			Host:     "petstore-preprod.swagger.io",
   231  			Port:     443,
   232  			Protocol: "https",
   233  		},
   234  		{
   235  			Host:     "petstore-preprod.swagger.io",
   236  			Port:     80,
   237  			Protocol: "http",
   238  		},
   239  		{
   240  			Host:     "petstore-test.swagger.io",
   241  			Port:     443,
   242  			Protocol: "https",
   243  		},
   244  		{
   245  			Host:     "petstore-test.swagger.io",
   246  			Port:     80,
   247  			Protocol: "http",
   248  		},
   249  	}
   250  
   251  	assert.Nil(t, err, "An unexpected Error was returned from getEndpoints with oas3 and templated URLs")
   252  	assert.Len(t, endPoints, 6, "The returned end points array did not have exactly 6 endpoints")
   253  	endpointNotFound := false
   254  	for _, endpoint := range endPoints {
   255  		found := false
   256  		for i, possibleEndpoint := range possibleEndpoints {
   257  			if possibleEndpoint.Found {
   258  				continue // Can't find the same endpoint twice
   259  			}
   260  			if endpoint.Host == possibleEndpoint.Host && endpoint.Port == possibleEndpoint.Port && endpoint.Protocol == possibleEndpoint.Protocol {
   261  				found = true
   262  				possibleEndpoints[i].Found = true
   263  				continue // No need to keep looking once we find it
   264  			}
   265  		}
   266  		if !found {
   267  			endpointNotFound = true
   268  		}
   269  	}
   270  
   271  	// Check that all endpoints have been verified
   272  	assert.False(t, endpointNotFound, "At least one endpoint returned was not expected")
   273  	for _, possibleEndpoint := range possibleEndpoints {
   274  		assert.True(t, possibleEndpoint.Found, "Did not find an endpoint with Host(%s), Port(%d), and Protocol(%s) in the returned endpoint array", possibleEndpoint.Host, possibleEndpoint.Port, possibleEndpoint.Protocol)
   275  	}
   276  }
   277  
   278  func ValidateOAS2Processors(t *testing.T, specParser SpecResourceParser, inputFile string) {
   279  	specProcessor := specParser.GetSpecProcessor()
   280  	endPoints, err := specProcessor.GetEndpoints()
   281  
   282  	assert.Nil(t, err, "An unexpected Error was returned from getEndpoints with oas2")
   283  	assert.Len(t, endPoints, 1, "The returned end points array did not have exactly 1 endpoint")
   284  	assert.Equal(t, "petstore.swagger.io", endPoints[0].Host, "The returned end point had an unexpected value for it's host")
   285  	if inputFile == "./testdata/petstore-swagger2.json" {
   286  		assert.Equal(t, int32(443), endPoints[0].Port, "The returned end point had an unexpected value for it's port")
   287  		assert.Equal(t, "https", endPoints[0].Protocol, "The returned end point had an unexpected value for it's protocol")
   288  		assert.Equal(t, "/v2", endPoints[0].BasePath, "The base path was not parsed from the JSON as expected")
   289  	} else {
   290  		assert.Equal(t, int32(80), endPoints[0].Port, "The returned end point had an unexpected value for it's port")
   291  		assert.Equal(t, "http", endPoints[0].Protocol, "The returned end point had an unexpected value for it's protocol")
   292  		assert.Equal(t, "/v1", endPoints[0].BasePath, "The base path was not parsed from the JSON as expected")
   293  	}
   294  }
   295  
   296  func ValidateWsdlProcessors(t *testing.T, specParser SpecResourceParser) {
   297  	specProcessor := specParser.GetSpecProcessor()
   298  	endPoints, err := specProcessor.GetEndpoints()
   299  
   300  	assert.Nil(t, err, "An unexpected Error was returned from getEndpoints with wsdl")
   301  	assert.Len(t, endPoints, 2, "The returned end points array did not have exactly 2 endpoints")
   302  	assert.Equal(t, "beano.com", endPoints[0].Host, "The returned end point had an unexpected value for it's host")
   303  	assert.Equal(t, int32(8065), endPoints[0].Port, "The returned end point had an unexpected value for it's port")
   304  	assert.Equal(t, "https", endPoints[0].Protocol, "The returned end point had an unexpected value for it's protocol")
   305  }
   306  
   307  func ValidateProtobufProcessors(t *testing.T, specParser SpecResourceParser) {
   308  	specProcessor := specParser.GetSpecProcessor()
   309  	endPoints, err := specProcessor.GetEndpoints()
   310  
   311  	assert.Nil(t, err, "An unexpected Error was returned from getEndpoints with protobuf")
   312  	assert.Len(t, endPoints, 0, "The returned end points array is not empty")
   313  }
   314  
   315  func ValidateAsyncAPIProcessors(t *testing.T, specParser SpecResourceParser) {
   316  	specProcessor := specParser.GetSpecProcessor()
   317  	endPoints, err := specProcessor.GetEndpoints()
   318  
   319  	assert.Nil(t, err, "An unexpected Error was returned from getEndpoints with asyncapi")
   320  	assert.Equal(t, "api.company.com", endPoints[0].Host)
   321  	assert.Equal(t, int32(5676), endPoints[0].Port)
   322  	assert.Equal(t, "mqtt", endPoints[0].Protocol)
   323  	assert.Equal(t, "", endPoints[0].BasePath)
   324  	assert.Equal(t, map[string]interface{}{
   325  		"solace": map[string]interface{}{
   326  			"msgVpn":  "apim-test",
   327  			"version": "0.2.0",
   328  		},
   329  	}, endPoints[0].Details)
   330  }
   331  
   332  func ValidateRamlProcessors(t *testing.T, specParser SpecResourceParser, inputFile string) {
   333  	specProcessor := specParser.GetSpecProcessor()
   334  	endPoints, err := specProcessor.GetEndpoints()
   335  	description := specProcessor.GetDescription()
   336  	version := specProcessor.GetVersion()
   337  	assert.Nil(t, err, "An unexpected Error was returned from getEndpoints with raml")
   338  	if inputFile == "./testdata/raml_10.raml" {
   339  		for i := range endPoints {
   340  			assert.True(t, isInList(endPoints[i].Protocol, []string{"http", "https"}))
   341  			assert.True(t, isInList(endPoints[i].Port, []int32{80, 443}))
   342  		}
   343  		assert.Equal(t, "na1.salesforce.com", endPoints[0].Host)
   344  		assert.Equal(t, "/services/data/v3/chatter", endPoints[0].BasePath)
   345  		assert.Equal(t, "Grand Theft Auto:Vice City", description)
   346  		assert.Equal(t, "v3", version)
   347  	} else if inputFile == "./testdata/raml_08.raml" {
   348  		assert.Equal(t, "Sonny Forelli", description)
   349  		assert.Equal(t, "1.0", version)
   350  		assert.Equal(t, "example.local", endPoints[0].Host)
   351  		assert.Equal(t, endPoints[0].Protocol, "https")
   352  		assert.Equal(t, endPoints[0].Port, int32(8000))
   353  		assert.Equal(t, "/api", endPoints[0].BasePath)
   354  	}
   355  }
   356  
   357  func isInList[T comparable](actual T, validValues []T) bool {
   358  	for i := range validValues {
   359  		if validValues[i] == actual {
   360  			return true
   361  		}
   362  	}
   363  	return false
   364  }