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 }