Skip to content

Commit

Permalink
bugfix: HEAD method and other methods combination couldn't be handl…
Browse files Browse the repository at this point in the history
…ed correctly
  • Loading branch information
ms-henglu committed Nov 17, 2023
1 parent 247f5ed commit 54cf9fd
Show file tree
Hide file tree
Showing 4 changed files with 422 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ BUG FIXES:
- Fix the bug that coverage reports are generated even if there are no valid test cases.
- Fix the bug that other dependency resolvers are not called when error occurs in the previous dependency resolver.
- Fix the bug that the generated resources are not in the correct order.
- Fix the bug that `HEAD` method and other methods combination couldn't be handled correctly.

## v0.12.0
FEATURES:
Expand Down
273 changes: 220 additions & 53 deletions resource/from_swagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,113 @@ func NewAzapiDefinitionsFromSwagger(apiPath swagger.ApiPath) []types.AzapiDefini

label := defaultLabel(apiPath.ResourceType)
caser := cases.Title(language.Und, cases.NoLower)
res := make([]types.AzapiDefinition, 0)
coveredMethodMap := make(map[string]bool)
switch {
case methodMap[http.MethodGet] && methodMap[http.MethodPut] && methodMap[http.MethodDelete]:
coveredMethodMap[http.MethodGet] = true
coveredMethodMap[http.MethodPut] = true
coveredMethodMap[http.MethodDelete] = true
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s, %s, %s", apiPath.OperationIdMap[http.MethodPut], apiPath.OperationIdMap[http.MethodGet], apiPath.OperationIdMap[http.MethodDelete]),
fmt.Sprintf("PUT GET DELETE %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource"
def.AdditionalFields["parent_id"] = types.NewStringLiteralValue(utils.ParentIdOfResourceId(apiPath.Path))
def.AdditionalFields["name"] = types.NewStringLiteralValue(utils.LastSegment(apiPath.Path))
def.AdditionalFields["schema_validation_enabled"] = types.NewRawValue("false")
def.Label = label
examplePath := apiPath.ExampleMap[http.MethodPut]
if requestBody, err := RequestBodyFromExample(examplePath); err == nil {
def.Body = requestBody
if requestBody != nil {
if requestBodyMap, ok := def.Body.(map[string]interface{}); ok && requestBody != nil {
if location := requestBodyMap["location"]; location != nil {
def.AdditionalFields["location"] = types.NewStringLiteralValue(location.(string))
delete(requestBodyMap, "location")
}
if name := requestBodyMap["name"]; name != nil {
delete(requestBodyMap, "name")
}
delete(requestBodyMap, "id")
def.Body = requestBodyMap
}
}
} else {
logrus.Warnf("failed to get request body from example, "+
"this usually means that the `x-ms-examples` extension is not set correctly for %s in the swagger spec. %v", apiPath.Path, err)
}
if def.Label != "" {
res = append(res, def)
}
case methodMap[http.MethodPut] && methodMap[http.MethodGet]:
coveredMethodMap[http.MethodGet] = true
coveredMethodMap[http.MethodPut] = true
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodPut]),
fmt.Sprintf("PUT %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(apiPath.Path)
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodPut)
examplePath := apiPath.ExampleMap[http.MethodPut]
if requestBody, err := RequestBodyFromExample(examplePath); err == nil {
def.Body = requestBody
} else {
logrus.Warnf("failed to get request body from example, "+
"this usually means that the `x-ms-examples` extension is not set correctly for %s in the swagger spec. %v", apiPath.Path, err)
}
def.Label = fmt.Sprintf("put_%s", label)
res = append(res, def)

def = types.AzapiDefinition{
Id: apiPath.Path,
AzureResourceType: apiPath.ResourceType,
ApiVersion: apiPath.ApiVersion,
BodyFormat: types.BodyFormatHcl,
AdditionalFields: make(map[string]types.Value),
}
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodGet]),
fmt.Sprintf("GET %s", apiPath.Path),
}
def.Kind = types.KindDataSource
def.ResourceName = "azapi_resource"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(apiPath.Path)
def.AdditionalFields["depends_on"] = types.NewRawValue(fmt.Sprintf("[ azapi_resource_action.put_%s ]", label))
def.Label = label
res = append(res, def)
case methodMap[http.MethodPut]:
coveredMethodMap[http.MethodPut] = true
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodPut]),
fmt.Sprintf("PUT %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(ResourceIdFromActionPath(apiPath.Path))
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodPut)
action := utils.ActionName(apiPath.Path)
def.AdditionalFields["action"] = types.NewStringLiteralValue(action)
if action != "" {
def.Label = action
} else {
def.Label = fmt.Sprintf("put_%s", label)
}
examplePath := apiPath.ExampleMap[http.MethodPut]
if requestBody, err := RequestBodyFromExample(examplePath); err == nil {
def.Body = requestBody
} else {
logrus.Warnf("failed to get request body from example, "+
"this usually means that the `x-ms-examples` extension is not set correctly for %s in the swagger spec. %v", apiPath.Path, err)
}
if def.Label != "" {
res = append(res, def)
}
case len(methodMap) == 1 && methodMap[http.MethodGet]:
coveredMethodMap[http.MethodGet] = true
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodGet]),
fmt.Sprintf("%s %s", http.MethodGet, apiPath.Path),
Expand Down Expand Up @@ -66,7 +171,11 @@ func NewAzapiDefinitionsFromSwagger(apiPath swagger.ApiPath) []types.AzapiDefini
def.Label = utils.LastSegment(apiPath.Path)
}
}
if def.Label != "" {
res = append(res, def)
}
case len(methodMap) == 1 && methodMap[http.MethodPost]:
coveredMethodMap[http.MethodPost] = true
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodPost]),
fmt.Sprintf("%s %s", http.MethodPost, apiPath.Path),
Expand All @@ -90,25 +199,59 @@ func NewAzapiDefinitionsFromSwagger(apiPath swagger.ApiPath) []types.AzapiDefini
logrus.Warnf("failed to get request body from example, "+
"this usually means that the `x-ms-examples` extension is not set correctly for %s in the swagger spec. %v", apiPath.Path, err)
}
if def.Label != "" {
res = append(res, def)
}
case methodMap[http.MethodGet] && methodMap[http.MethodDelete]:
coveredMethodMap[http.MethodGet] = true
coveredMethodMap[http.MethodDelete] = true
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodGet]),
fmt.Sprintf("GET %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(apiPath.Path)
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodGet)
def.Label = fmt.Sprintf("get_%s", label)
res = append(res, def)

case methodMap[http.MethodGet] && methodMap[http.MethodPut] && methodMap[http.MethodDelete]:
def = types.AzapiDefinition{
Id: apiPath.Path,
AzureResourceType: apiPath.ResourceType,
ApiVersion: apiPath.ApiVersion,
BodyFormat: types.BodyFormatHcl,
AdditionalFields: make(map[string]types.Value),
}
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s, %s, %s", apiPath.OperationIdMap[http.MethodPut], apiPath.OperationIdMap[http.MethodGet], apiPath.OperationIdMap[http.MethodDelete]),
fmt.Sprintf("PUT GET DELETE %s", apiPath.Path),
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodDelete]),
fmt.Sprintf("DELETE %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource"
def.AdditionalFields["parent_id"] = types.NewStringLiteralValue(utils.ParentIdOfResourceId(apiPath.Path))
def.AdditionalFields["name"] = types.NewStringLiteralValue(utils.LastSegment(apiPath.Path))
def.AdditionalFields["schema_validation_enabled"] = types.NewRawValue("false")
def.Label = label
examplePath := apiPath.ExampleMap[http.MethodPut]
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(apiPath.Path)
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodDelete)
def.AdditionalFields["depends_on"] = types.NewRawValue(fmt.Sprintf("[ azapi_resource_action.get_%s ]", label))
def.Label = fmt.Sprintf("delete_%s", label)
res = append(res, def)
case methodMap[http.MethodGet] && methodMap[http.MethodPatch]:
coveredMethodMap[http.MethodGet] = true
coveredMethodMap[http.MethodPatch] = true

def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodPatch]),
fmt.Sprintf("PATCH %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(apiPath.Path)
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodPatch)
examplePath := apiPath.ExampleMap[http.MethodPatch]
if requestBody, err := RequestBodyFromExample(examplePath); err == nil {
def.Body = requestBody
if requestBody != nil {
if requestBodyMap, ok := def.Body.(map[string]interface{}); ok && requestBody != nil {
if location := requestBodyMap["location"]; location != nil {
def.AdditionalFields["location"] = types.NewStringLiteralValue(location.(string))
delete(requestBodyMap, "location")
}
if name := requestBodyMap["name"]; name != nil {
Expand All @@ -122,56 +265,30 @@ func NewAzapiDefinitionsFromSwagger(apiPath swagger.ApiPath) []types.AzapiDefini
logrus.Warnf("failed to get request body from example, "+
"this usually means that the `x-ms-examples` extension is not set correctly for %s in the swagger spec. %v", apiPath.Path, err)
}
def.Label = fmt.Sprintf("patch_%s", label)
res = append(res, def)

case methodMap[http.MethodPut] && methodMap[http.MethodGet]:
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s, %s", apiPath.OperationIdMap[http.MethodPut], apiPath.OperationIdMap[http.MethodGet]),
fmt.Sprintf("PUT GET %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_update_resource"
def.AdditionalFields["parent_id"] = types.NewStringLiteralValue(utils.ParentIdOfResourceId(apiPath.Path))
def.AdditionalFields["name"] = types.NewStringLiteralValue(utils.LastSegment(apiPath.Path))
def.Label = label
examplePath := apiPath.ExampleMap[http.MethodPut]
if requestBody, err := RequestBodyFromExample(examplePath); err == nil {
def.Body = requestBody
} else {
logrus.Warnf("failed to get request body from example, "+
"this usually means that the `x-ms-examples` extension is not set correctly for %s in the swagger spec. %v", apiPath.Path, err)
def = types.AzapiDefinition{
Id: apiPath.Path,
AzureResourceType: apiPath.ResourceType,
ApiVersion: apiPath.ApiVersion,
BodyFormat: types.BodyFormatHcl,
AdditionalFields: make(map[string]types.Value),
}

case methodMap[http.MethodPut]:
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodPut]),
fmt.Sprintf("PUT %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(ResourceIdFromActionPath(apiPath.Path))
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodPut)
action := utils.ActionName(apiPath.Path)
def.AdditionalFields["action"] = types.NewStringLiteralValue(action)
if action != "" {
def.Label = action
} else {
def.Label = fmt.Sprintf("put_%s", label)
}
examplePath := apiPath.ExampleMap[http.MethodPut]
if requestBody, err := RequestBodyFromExample(examplePath); err == nil {
def.Body = requestBody
} else {
logrus.Warnf("failed to get request body from example, "+
"this usually means that the `x-ms-examples` extension is not set correctly for %s in the swagger spec. %v", apiPath.Path, err)
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodGet]),
fmt.Sprintf("GET %s", apiPath.Path),
}
}

res := make([]types.AzapiDefinition, 0)
if def.Label != "" {
def.Kind = types.KindDataSource
def.ResourceName = "azapi_resource"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(apiPath.Path)
def.AdditionalFields["depends_on"] = types.NewRawValue(fmt.Sprintf("[ azapi_resource_action.patch_%s ]", label))
def.Label = label
res = append(res, def)
}

if methodMap[http.MethodPatch] {
if methodMap[http.MethodPatch] && !coveredMethodMap[http.MethodPatch] {
coveredMethodMap[http.MethodPatch] = true
def := types.AzapiDefinition{
AzureResourceType: apiPath.ResourceType,
ApiVersion: apiPath.ApiVersion,
Expand Down Expand Up @@ -215,6 +332,56 @@ func NewAzapiDefinitionsFromSwagger(apiPath swagger.ApiPath) []types.AzapiDefini
res = append(res, def)
}

if methodMap[http.MethodHead] {
coveredMethodMap[http.MethodHead] = true
def := types.AzapiDefinition{
AzureResourceType: apiPath.ResourceType,
ApiVersion: apiPath.ApiVersion,
BodyFormat: types.BodyFormatHcl,
AdditionalFields: make(map[string]types.Value),
}
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodHead]),
fmt.Sprintf("HEAD %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodHead)
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(ResourceIdFromActionPath(apiPath.Path))
action := utils.ActionName(apiPath.Path)
def.AdditionalFields["action"] = types.NewStringLiteralValue(action)
if action != "" {
def.Label = action
} else {
def.Label = fmt.Sprintf("head_%s", label)
}
res = append(res, def)
}

if methodMap[http.MethodDelete] && !coveredMethodMap[http.MethodDelete] {
coveredMethodMap[http.MethodDelete] = true
def.LeadingComments = []string{
fmt.Sprintf("OperationId: %s", apiPath.OperationIdMap[http.MethodDelete]),
fmt.Sprintf("DELETE %s", apiPath.Path),
}
def.Kind = types.KindResource
def.ResourceName = "azapi_resource_action"
def.AdditionalFields["resource_id"] = types.NewStringLiteralValue(apiPath.Path)
def.AdditionalFields["method"] = types.NewStringLiteralValue(http.MethodDelete)
def.Label = fmt.Sprintf("delete_%s", label)
res = append(res, def)
}

notCoveredMethods := make([]string, 0)
for method := range methodMap {
if !coveredMethodMap[method] {
notCoveredMethods = append(notCoveredMethods, method)
}
}
if len(notCoveredMethods) != 0 {
// TODO: GET and POST on a collection URL are not supported
logrus.Errorf("there are methods not covered: %v for API path %s", notCoveredMethods, apiPath.Path)
}
return res
}

Expand Down
Loading

0 comments on commit 54cf9fd

Please sign in to comment.