From 4e1dd53a01cedaec593ef45e6e679fb568400c46 Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:24:02 +0000 Subject: [PATCH 1/9] fix coverage count and report --- commands/credential_scan.go | 4 +- coverage/coverage.go | 34 ++++++++ coverage/coverage_test.go | 150 ++++++++++++++++++++++-------------- coverage/expand.go | 3 + coverage/index.go | 12 +-- coverage/index_test.go | 14 +++- coverage/report.go | 143 +++++++++++++++++++++++----------- 7 files changed, 245 insertions(+), 115 deletions(-) diff --git a/commands/credential_scan.go b/commands/credential_scan.go index 8dee80d..de983a9 100644 --- a/commands/credential_scan.go +++ b/commands/credential_scan.go @@ -235,7 +235,7 @@ func (c CredentialScanCommand) Execute() int { var swaggerModel *coverage.SwaggerModel if c.swaggerRepoPath != "" { logrus.Infof("scan based on local swagger repo: %s", c.swaggerRepoPath) - swaggerModel, err = coverage.GetModelInfoFromLocalIndex(mockedResourceId, apiVersion, c.swaggerRepoPath, c.swaggerIndexFile) + swaggerModel, err = coverage.GetModelInfoFromLocalIndex(mockedResourceId, apiVersion, "PUT", c.swaggerRepoPath, c.swaggerIndexFile) if err != nil { credScanErr := makeCredScanError( azapiResource, @@ -248,7 +248,7 @@ func (c CredentialScanCommand) Execute() int { continue } } else { - swaggerModel, err = coverage.GetModelInfoFromIndex(mockedResourceId, apiVersion, c.swaggerIndexFile) + swaggerModel, err = coverage.GetModelInfoFromIndex(mockedResourceId, apiVersion, "PUT", c.swaggerIndexFile) if err != nil { credScanErr := makeCredScanError( azapiResource, diff --git a/coverage/coverage.go b/coverage/coverage.go index fb69081..d2b8299 100644 --- a/coverage/coverage.go +++ b/coverage/coverage.go @@ -22,10 +22,13 @@ type Model struct { IsFullyCovered bool `json:"IsFullyCovered,omitempty"` IsReadOnly bool `json:"IsReadOnly,omitempty"` IsRequired bool `json:"IsRequired,omitempty"` + IsRoot bool `json:"IsRoot,omitempty"` IsSecret bool `json:"IsSecret,omitempty"` // related to x-ms-secret Item *Model `json:"Item,omitempty"` ModelName string `json:"ModelName,omitempty"` Properties *map[string]*Model `json:"Properties,omitempty"` + RootCoveredCount int `json:"RootCoveredCount,omitempty"` // only for root model, covered count plus all variant count if any + RootTotalCount int `json:"RootTotalCount,omitempty"` // only for root model, total count plus all variant count if any SourceFile string `json:"SourceFile,omitempty"` TotalCount int `json:"TotalCount,omitempty"` Type *string `json:"Type,omitempty"` @@ -272,6 +275,20 @@ func (m *Model) CountCoverage() (int, int) { } } + if m.IsRoot { + if m.Variants != nil { + for _, v := range *m.Variants { + v.CountCoverage() + } + } + + if m.Item != nil && m.Item.Variants != nil { + for _, v := range *m.Item.Variants { + v.CountCoverage() + } + } + } + if m.TotalCount == 0 { m.TotalCount = 1 } @@ -281,6 +298,23 @@ func (m *Model) CountCoverage() (int, int) { m.IsFullyCovered = m.TotalCount > 0 && m.CoveredCount == m.TotalCount + if m.IsRoot { + m.RootCoveredCount = m.CoveredCount + m.RootTotalCount = m.TotalCount + if m.Variants != nil { + for _, v := range *m.Variants { + m.RootCoveredCount += v.CoveredCount + m.RootTotalCount += v.TotalCount + } + } + if m.Item != nil && m.Item.Variants != nil { + for _, v := range *m.Item.Variants { + m.RootCoveredCount += v.CoveredCount + m.RootTotalCount += v.TotalCount + } + } + } + return m.CoveredCount, m.TotalCount } diff --git a/coverage/coverage_test.go b/coverage/coverage_test.go index 03c1219..e26d06d 100644 --- a/coverage/coverage_test.go +++ b/coverage/coverage_test.go @@ -15,11 +15,13 @@ import ( ) type testCase struct { - name string - apiVersion string - apiPath string - rawRequest []string - resourceType string + name string + apiPath string + rawRequest []string + resourceType string + method string + expectedCoveredCount int + expectedTotalCount int } func normarlizePath(path string) string { @@ -28,10 +30,12 @@ func normarlizePath(path string) string { func TestCoverage_ResourceGroup(t *testing.T) { tc := testCase{ - name: "ResourceGroup", - resourceType: "Microsoft.Resources/resourceGroups@2022-09-01", - apiVersion: "2022-09-01", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rgName", + name: "ResourceGroup", + resourceType: "Microsoft.Resources/resourceGroups@2022-09-01", + method: "PUT", + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rgName", + expectedCoveredCount: 1, + expectedTotalCount: 3, rawRequest: []string{ `{ "location": "westeurope" @@ -44,14 +48,6 @@ func TestCoverage_ResourceGroup(t *testing.T) { t.Fatalf("process coverage: %+v", err) } - if model.CoveredCount != 1 { - t.Fatalf("expected CoveredCount 1, got %d", model.CoveredCount) - } - - if model.TotalCount != 3 { - t.Fatalf("expected TotalCount 3, got %d", model.TotalCount) - } - if model.Properties == nil { t.Fatalf("expected properties, got none") } @@ -65,12 +61,36 @@ func TestCoverage_ResourceGroup(t *testing.T) { } } +func TestCoverage_AzureTerraform(t *testing.T) { + tc := testCase{ + name: "AzureTerraform", + resourceType: "Microsoft.AzureTerraform@2023-07-01-preview", + method: "POST", + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.AzureTerraform/exportTerraform", + expectedCoveredCount: 2, + expectedTotalCount: 25, + rawRequest: []string{ + `{ + "resourceGroupName" : "rg1", + "type" : "ExportResourceGroup" + }`, + }, + } + + _, err := testCoverage(t, tc) + if err != nil { + t.Fatalf("process coverage: %+v", err) + } +} + func TestCoverage_HealthcareDicom(t *testing.T) { tc := testCase{ - name: "HealthcareApisDicom", - resourceType: "Microsoft.HealthcareApis/workspaces/dicomservices@2024-03-31", - apiVersion: "2024-03-31", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rgName/providers/Microsoft.HealthcareApis/workspaces/workspaceName/dicomservices/dicomServiceName", + name: "HealthcareApisDicom", + resourceType: "Microsoft.HealthcareApis/workspaces/dicomservices@2024-03-31", + method: "PUT", + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rgName/providers/Microsoft.HealthcareApis/workspaces/workspaceName/dicomservices/dicomServiceName", + expectedCoveredCount: 12, + expectedTotalCount: 14, // bulkImportConfiguration property not in swagger rawRequest: []string{ `{ @@ -131,8 +151,8 @@ func TestCoverage_HealthcareDicom(t *testing.T) { func TestCoverage_MachineLearningServicesWorkspacesJobs(t *testing.T) { tc := testCase{ name: "MachineLearningServicesWorkspacesJobs", - resourceType: "Microsoft.MachineLearningServices/workspaces/jobs", - apiVersion: "2023-06-01-preview", + resourceType: "Microsoft.MachineLearningServices/workspaces/jobs@2023-06-01-preview", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/jobs/job1", rawRequest: []string{ `{ @@ -193,8 +213,8 @@ func TestCoverage_MachineLearningServicesWorkspacesJobs(t *testing.T) { func TestCoverage_MachineLearningServicesWorkspacesDataVersions(t *testing.T) { tc := testCase{ name: "MachineLearningServicesWorkspacesDataVersions", - resourceType: "Microsoft.MachineLearningServices/workspaces/data/versions", - apiVersion: "2023-06-01-preview", + resourceType: "Microsoft.MachineLearningServices/workspaces/data/versions@2023-06-01-preview", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/data/data1/versions/version1", rawRequest: []string{ `{ @@ -233,7 +253,7 @@ func TestCoverage_DeviceSecurityGroup(t *testing.T) { tc := testCase{ name: "DeviceSecurityGroup", resourceType: "Microsoft.Security/deviceSecurityGroups@2019-08-01", - apiVersion: "2019-08-01", + method: "PUT", apiPath: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/SampleRG/providers/Microsoft.Devices/iotHubs/sampleiothub/providers/Microsoft.Security/deviceSecurityGroups/samplesecuritygroup", rawRequest: []string{ `{ @@ -269,7 +289,7 @@ func TestCoverage_DataMigrationServiceTasks(t *testing.T) { tc := testCase{ name: "DataMigrationServiceTasks", resourceType: "Microsoft.DataMigration/services/serviceTasks@2021-06-30", - apiVersion: "2021-06-30", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/serviceTasks/DmsSdkTask", rawRequest: []string{ `{ @@ -293,7 +313,7 @@ func TestCoverage_SCVMM(t *testing.T) { tc := testCase{ name: "SCVMM", resourceType: "Microsoft.ScVmm/virtualMachineInstances@2023-10-07", - apiVersion: "2023-10-07", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/cli-test-rg-vmm/providers/Microsoft.HybridCompute/machines/test-vm-tf/providers/Microsoft.ScVmm/virtualMachineInstances/default", rawRequest: []string{ `{ @@ -327,7 +347,7 @@ func TestCoverage_DataMigrationTasks(t *testing.T) { tc := testCase{ name: "DataMigrationTasks", resourceType: "Microsoft.DataMigration/services/projects/tasks@2021-06-30", - apiVersion: "2021-06-30", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/projects/DmsSdkProject/tasks/DmsSdkTask", rawRequest: []string{ `{ @@ -364,7 +384,7 @@ func TestCoverage_KeyVault(t *testing.T) { tc := testCase{ name: "KeyVault", resourceType: "Microsoft.KeyVault/vaults@2023-02-01", - apiVersion: "2023-02-01", + method: "PUT", apiPath: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sample-resource-group/providers/Microsoft.KeyVault/vaults/sample-vault", rawRequest: []string{ `{ @@ -451,7 +471,7 @@ func TestCoverage_StorageAccount(t *testing.T) { tc := testCase{ name: "StorageAccount", resourceType: "Microsoft.Storage/storageAccounts@2022-09-01", - apiVersion: "2022-09-01", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/res9101/providers/Microsoft.Storage/storageAccounts/sto4445", rawRequest: []string{ `{ @@ -520,7 +540,7 @@ func TestCoverage_VM(t *testing.T) { tc := testCase{ name: "VM", resourceType: "Microsoft.Compute/virtualMachines@2023-03-01", - apiVersion: "2023-03-01", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm", rawRequest: []string{ `{ @@ -591,7 +611,7 @@ func TestCoverage_VNet(t *testing.T) { tc := testCase{ name: "VNet", resourceType: "Microsoft.Network/virtualNetworks@2023-02-01", - apiVersion: "2023-02-01", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/virtualNetwork", rawRequest: []string{ `{ @@ -630,7 +650,7 @@ func TestCoverage_DataCollectionRule(t *testing.T) { tc := testCase{ name: "DataCollectionRule", resourceType: "Microsoft.Insights/dataCollectionRules@2022-06-01", - apiVersion: "2022-06-01", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", rawRequest: []string{ `{ @@ -957,7 +977,7 @@ func TestCoverage_WebSite(t *testing.T) { tc := testCase{ name: "WebSites", resourceType: "Microsoft.Web/sites@2022-09-01", - apiVersion: "2022-09-01", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/testrg123/providers/Microsoft.Web/sites/sitef6141", rawRequest: []string{ `{ @@ -983,10 +1003,12 @@ func TestCoverage_WebSite(t *testing.T) { func TestCoverage_AKS(t *testing.T) { tc := testCase{ - name: "AKS", - resourceType: "Microsoft.ContainerService/ManagedClusters@2023-05-02-preview", - apiVersion: "2023-05-02-preview", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourcegroups/rg1/providers/Microsoft.ContainerService/managedClusters/clustername1", + name: "AKS", + resourceType: "Microsoft.ContainerService/ManagedClusters@2024-05-01", + method: "PUT", + expectedCoveredCount: 33, + expectedTotalCount: 234, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourcegroups/rg1/providers/Microsoft.ContainerService/managedClusters/clustername1", rawRequest: []string{`{ "location": "location1", "tags": { @@ -1074,8 +1096,8 @@ func TestCoverage_AKS(t *testing.T) { func TestCoverage_CosmosDB(t *testing.T) { tc := testCase{ name: "CosmosDB", - resourceType: "Microsoft.DocumentDB/databaseAccounts@2023-04-15", - apiVersion: "2023-04-15", + resourceType: "Microsoft.DocumentDB/databaseAccounts@2024-05-15", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DocumentDB/databaseAccounts/testdb", rawRequest: []string{ `{ @@ -1302,8 +1324,8 @@ func TestCoverage_CosmosDB(t *testing.T) { func TestCoverage_DataFactoryPipelines(t *testing.T) { tc := testCase{ name: "DataFactoryPipelines", - apiVersion: "2018-06-01", resourceType: "Microsoft.DataFactory/factories/pipelines@2018-06-01", + method: "PUT", apiPath: "/subscriptions/12345678-1234-1234-1234-12345678abc/resourceGroups/exampleResourceGroup/providers/Microsoft.DataFactory/factories/exampleFactoryName/pipelines/examplePipeline", rawRequest: []string{ `{ @@ -1404,7 +1426,7 @@ func TestCoverage_DataFactoryLinkedServices(t *testing.T) { tc := testCase{ name: "DataFactoryLinkedServices", resourceType: "Microsoft.DataFactory/factories/linkedServices@2018-06-01", - apiVersion: "2018-06-01", + method: "PUT", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DataFactory/factories/factory1/linkedServices/linked", rawRequest: []string{ `{ @@ -1501,10 +1523,13 @@ func TestCoverage_DataFactoryLinkedServices(t *testing.T) { } func testCoverage(t *testing.T, tc testCase) (*coverage.Model, error) { - swaggerModel, err := coverage.GetModelInfoFromIndex( + apiVersion := strings.Split(tc.resourceType, "@")[1] + swaggerModel, err := coverage.GetModelInfoFromLocalIndex( tc.apiPath, - tc.apiVersion, - "", + apiVersion, + tc.method, + "/home/wangta/project/go/azure-rest-api-specs/specification/", + "index0910.json", ) t.Logf("swaggerModel: %+v", swaggerModel) @@ -1518,11 +1543,11 @@ func testCoverage(t *testing.T, tc testCase) (*coverage.Model, error) { return nil, fmt.Errorf("expand model: %+v", err) } - //out, err := json.MarshalIndent(model, "", "\t") - //if err != nil { - // t.Error(err) - //} - //t.Logf("expand model %s", string(out)) + // out, err := json.MarshalIndent(model, "", "\t") + // if err != nil { + // t.Error(err) + // } + // t.Logf("expand model %s", string(out)) for _, rq := range tc.rawRequest { request := map[string]interface{}{} @@ -1536,11 +1561,19 @@ func testCoverage(t *testing.T, tc testCase) (*coverage.Model, error) { model.CountCoverage() - //out, err = json.MarshalIndent(model, "", "\t") - //if err != nil { - // t.Error(err) - //} - //t.Logf("coverage model %s", string(out)) + if model.RootCoveredCount != tc.expectedCoveredCount { + t.Errorf("expected CoveredCount %d, got %d", tc.expectedCoveredCount, model.RootCoveredCount) + } + + if model.RootTotalCount != tc.expectedTotalCount { + t.Errorf("expected TotalCount %d, got %d", tc.expectedTotalCount, model.RootTotalCount) + } + + // out, err = json.MarshalIndent(model, "", "\t") + // if err != nil { + // t.Error(err) + // } + // t.Logf("coverage model %s", string(out)) coverageReport := coverage.CoverageReport{ Coverages: map[string]*coverage.CoverageItem{ @@ -1578,9 +1611,11 @@ func storeCoverageReport(passReport types.PassReport, coverageReport coverage.Co } func testCredScan(t *testing.T, tc testCase) (*map[string]string, error) { + apiVersion := strings.Split(tc.resourceType, "@")[1] swaggerModel, err := coverage.GetModelInfoFromIndex( tc.apiPath, - tc.apiVersion, + apiVersion, + "PUT", "", ) @@ -1623,7 +1658,6 @@ func TestCredScan(t *testing.T) { tc := testCase{ name: "VM", resourceType: "Microsoft.Compute/virtualMachines@2023-03-01", - apiVersion: "2023-03-01", apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm", rawRequest: []string{ `{ diff --git a/coverage/expand.go b/coverage/expand.go index 18b3d50..3fca964 100644 --- a/coverage/expand.go +++ b/coverage/expand.go @@ -89,6 +89,8 @@ func Expand(modelName, swaggerPath string) (*Model, error) { output := expandSchema(modelSchema, swaggerPath, modelName, "#", spec, map[string]interface{}{}, map[string]interface{}{}) + output.IsRoot = true + return output, nil } @@ -178,6 +180,7 @@ func expandSchema(input openapiSpec.Schema, swaggerPath, modelName, identifier s properties[k] = v } } + output.ModelName = referenceModel.ModelName if referenceModel.Enum != nil { output.Enum = referenceModel.Enum } diff --git a/coverage/index.go b/coverage/index.go index b27d5b6..7eb6697 100644 --- a/coverage/index.go +++ b/coverage/index.go @@ -165,7 +165,7 @@ type SwaggerModel struct { // GetModelInfoFromIndex will try to download online index from https://github.com/teowa/azure-rest-api-index-file, and get model info from it // if the index is already downloaded as in {indexFilePath}, it will use the cached index -func GetModelInfoFromIndex(resourceId, apiVersion, indexFilePath string) (*SwaggerModel, error) { +func GetModelInfoFromIndex(resourceId, apiVersion, method, indexFilePath string) (*SwaggerModel, error) { index, err := GetIndex(indexFilePath) if err != nil { return nil, err @@ -176,7 +176,7 @@ func GetModelInfoFromIndex(resourceId, apiVersion, indexFilePath string) (*Swagg if err != nil { return nil, fmt.Errorf("parsing URL %s: %+v", resourceURL, err) } - ref, err := index.Lookup("PUT", *uRL) + ref, err := index.Lookup(method, *uRL) if err != nil { return nil, fmt.Errorf("lookup PUT URL %s in index: %+v", resourceURL, err) } @@ -193,7 +193,7 @@ func GetModelInfoFromIndex(resourceId, apiVersion, indexFilePath string) (*Swagg } // GetModelInfoFromLocalIndex tries to build index from local swagger repo and get model info from it -func GetModelInfoFromLocalIndex(resourceId, apiVersion, swaggerRepo, indexCacheFile string) (*SwaggerModel, error) { +func GetModelInfoFromLocalIndex(resourceId, apiVersion, method, swaggerRepo, indexCacheFile string) (*SwaggerModel, error) { swaggerRepo, err := filepath.Abs(swaggerRepo) if err != nil { return nil, fmt.Errorf("swagger repo path %q is invalid: %+v", swaggerRepo, err) @@ -221,7 +221,7 @@ func GetModelInfoFromLocalIndex(resourceId, apiVersion, swaggerRepo, indexCacheF if err != nil { return nil, fmt.Errorf("parsing URL %s: %+v", resourceURL, err) } - ref, err := index.Lookup("PUT", *uRL) + ref, err := index.Lookup(method, *uRL) if err != nil { return nil, fmt.Errorf("lookup PUT URL %s in index: %+v", resourceURL, err) } @@ -309,7 +309,7 @@ func MockResourceIDFromType(azapiResourceType string) (string, string) { return fmt.Sprintf("%s/%s/providers/%s/%s", subscritionSeg, resourceGroupSeg, resourceProvider, typeIds), apiVersion } -func GetModelInfoFromIndexWithType(azapiResourceType, indexCacheFile string) (*SwaggerModel, error) { +func GetModelInfoFromIndexWithType(azapiResourceType, method, indexCacheFile string) (*SwaggerModel, error) { resourceId, apiVersion := MockResourceIDFromType(azapiResourceType) - return GetModelInfoFromIndex(resourceId, apiVersion, indexCacheFile) + return GetModelInfoFromIndex(resourceId, apiVersion, method, indexCacheFile) } diff --git a/coverage/index_test.go b/coverage/index_test.go index a70a1a0..88cd4e9 100644 --- a/coverage/index_test.go +++ b/coverage/index_test.go @@ -17,6 +17,7 @@ func TestGetModelInfoFromIndex_DataCollectionRule(t *testing.T) { swaggerModel, err := coverage.GetModelInfoFromIndex( "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", apiVersion, + "PUT", "", ) if err != nil { @@ -44,6 +45,7 @@ func TestGetModelInfoFromIndexWithCache_DataCollectionRule(t *testing.T) { swaggerModel, err := coverage.GetModelInfoFromIndex( "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", apiVersion, + "PUT", indexFilePath, ) if err != nil { @@ -71,6 +73,7 @@ func TestGetModelInfoFromIndex_DeviceSecurityGroups(t *testing.T) { swaggerModel, err := coverage.GetModelInfoFromIndex( "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/SampleRG/providers/Microsoft.Devices/iotHubs/sampleiothub/providers/Microsoft.Security/deviceSecurityGroups/samplesecuritygroup", apiVersion, + "PUT", "", ) if err != nil { @@ -95,7 +98,7 @@ func TestGetModelInfoFromIndex_DeviceSecurityGroups(t *testing.T) { func TestGetModelInfoFromIndexWithType_DataCollectionRule(t *testing.T) { azapiResourceType := "Microsoft.Insights/dataCollectionRules@2022-06-01" - swaggerModel, err := coverage.GetModelInfoFromIndexWithType(azapiResourceType, "") + swaggerModel, err := coverage.GetModelInfoFromIndexWithType(azapiResourceType, "PUT", "") if err != nil { t.Fatalf("get model info from index error: %+v", err) } @@ -108,7 +111,7 @@ func TestGetModelInfoFromIndexWithType_DataCollectionRule(t *testing.T) { func TestGetModelInfoFromIndexWithTypeWithCache_DataCollectionRule(t *testing.T) { azapiResourceType := "Microsoft.Insights/dataCollectionRules@2022-06-01" - swaggerModel, err := coverage.GetModelInfoFromIndexWithType(azapiResourceType, indexFilePath) + swaggerModel, err := coverage.GetModelInfoFromIndexWithType(azapiResourceType, "PUT", indexFilePath) if err != nil { t.Fatalf("get model info from index error: %+v", err) } @@ -118,7 +121,7 @@ func TestGetModelInfoFromIndexWithTypeWithCache_DataCollectionRule(t *testing.T) t.Fatalf("expected apiPath %s, got %s", expectedApiPath, swaggerModel.ApiPath) } - _, err = coverage.GetModelInfoFromIndexWithType(azapiResourceType, indexFilePath) + _, err = coverage.GetModelInfoFromIndexWithType(azapiResourceType, "PUT", indexFilePath) if err != nil { t.Fatalf("get model info from index error: %+v", err) } @@ -126,7 +129,7 @@ func TestGetModelInfoFromIndexWithTypeWithCache_DataCollectionRule(t *testing.T) func TestGetModelInfoFromIndexWithType_DeviceSecurityGroups(t *testing.T) { azapiResourceType := "Microsoft.Security/deviceSecurityGroups@2019-08-01" - swaggerModel, err := coverage.GetModelInfoFromIndexWithType(azapiResourceType, "") + swaggerModel, err := coverage.GetModelInfoFromIndexWithType(azapiResourceType, "PUT", "") if err != nil { t.Fatalf("get model info from index error: %+v", err) } @@ -147,6 +150,7 @@ func TestGetModelInfoFromLocalIndex_DataCollectionRule(t *testing.T) { swaggerModel, err := coverage.GetModelInfoFromLocalIndex( "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", apiVersion, + "PUT", azureRepoDir, "", ) @@ -180,6 +184,7 @@ func TestGetModelInfoFromLocalIndexWithCache_DataCollectionRule(t *testing.T) { swaggerModel, err := coverage.GetModelInfoFromLocalIndex( "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", apiVersion, + "PUT", azureRepoDir, indexFilePath, ) @@ -205,6 +210,7 @@ func TestGetModelInfoFromLocalIndexWithCache_DataCollectionRule(t *testing.T) { _, err = coverage.GetModelInfoFromLocalIndex( "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", apiVersion, + "PUT", azureRepoDir, indexFilePath, ) diff --git a/coverage/report.go b/coverage/report.go index 421ddd6..6f5f09c 100644 --- a/coverage/report.go +++ b/coverage/report.go @@ -33,7 +33,7 @@ func (c *CoverageReport) AddCoverageFromState(resourceId, resourceType string, j swaggerModel = swaggerModelFromLocal } if swaggerModel == nil { - swaggerModelFromIndex, err := GetModelInfoFromIndex(resourceId, apiVersion, "") + swaggerModelFromIndex, err := GetModelInfoFromIndex(resourceId, apiVersion, "PUT", "") if err != nil { return fmt.Errorf("error find the path for %s from index: %+v", resourceId, err) } @@ -98,7 +98,7 @@ ${coverage_details} for _, v := range c.Coverages { count++ - reportDetail := getReport(v.Model) + reportDetail := getReport(v.Model.ModelName, v.Model) sort.Strings(reportDetail) coverages = append(coverages, fmt.Sprintf(`##### @@ -107,20 +107,14 @@ ${coverage_details} [swagger](%[3]v)
-
-%[5]v(%[6]v/%[7]v) -
- -%[8]v -
-
+%[4]v
--- -`, v.DisplayName, v.ApiPath, v.Model.SourceFile, getStyle(v.Model.IsFullyCovered), v.Model.ModelName, v.Model.CoveredCount, v.Model.TotalCount, strings.Join(reportDetail, "\n\n"))) +`, v.DisplayName, v.ApiPath, v.Model.SourceFile, strings.Join(reportDetail, "\n\n"))) } sort.Strings(coverages) @@ -158,8 +152,21 @@ func (c *CoverageReport) MarkdownContentCompact() string { return template + content } -func getReport(model *Model) []string { +func getReport(displayName string, model *Model) []string { out := make([]string, 0) + style := getStyle(model.IsFullyCovered) + + if hasNoDetail(model) { + // leaf property + out = append(out, + fmt.Sprintf(` +
+%[3]v + +
`, model.Identifier, style, displayName), + ) + return out + } if isBoolEnumDisplayed { if model.Enum != nil { @@ -178,7 +185,7 @@ func getReport(model *Model) []string { } if model.Item != nil { - return getReport(model.Item) + return getReport(displayName, model.Item) } if model.Properties != nil { @@ -196,17 +203,16 @@ func getReport(model *Model) []string { if v.VariantType != nil { variantType = *v.VariantType } - variantKey := fmt.Sprintf("%s{%s}", k, variantType) - - out = append(out, getChildReport(variantKey, v)) + variantKey := getDiscriminatorKey(k, variantType) + out = append(out, getReport(variantKey, v)...) for variantType, variant := range *v.Variants { variantType := variantType if variant.VariantType != nil { variantType = *variant.VariantType } - variantKey := fmt.Sprintf("%s{%s}", k, variantType) - out = append(out, getChildReport(variantKey, variant)) + variantKey := getDiscriminatorKey(k, variantType) + out = append(out, getReport(variantKey, variant)...) } continue } @@ -216,25 +222,68 @@ func getReport(model *Model) []string { if v.Item.VariantType != nil { variantType = *v.Item.VariantType } - variantKey := fmt.Sprintf("%s{%s}", k, variantType) - out = append(out, getChildReport(variantKey, v)) + variantKey := getDiscriminatorKey(k, variantType) + out = append(out, getReport(variantKey, v)...) for variantType, variant := range *v.Item.Variants { variantType := variantType if variant.VariantType != nil { variantType = *variant.VariantType } - variantKey := fmt.Sprintf("%s{%s}", k, variantType) - out = append(out, getChildReport(variantKey, variant)) + variantKey := getDiscriminatorKey(k, variantType) + out = append(out, getReport(variantKey, variant)...) } continue } - out = append(out, getChildReport(k, v)) + out = append(out, getReport(k, v)...) + } + } + + sort.Strings(out) + + outWithoutVariant := []string{ + fmt.Sprintf(` +
+%[3]v %[4]v +
+ +%[5]v + +
+
`, model.Identifier, style, displayName, getCoverageCount(model), strings.Join(out, "\n\n")), + } + + if model.IsRoot { + var variants *map[string]*Model + if model.Variants != nil { + variants = model.Variants + } + if model.Item != nil && model.Item.Variants != nil { + variants = model.Item.Variants + } + + if variants != nil { + outWithVariant := make([]string, 0) + outWithVariant = append(outWithVariant, outWithoutVariant...) + + for variantType, variant := range *variants { + variantType := variantType + if variant.VariantType != nil { + variantType = *variant.VariantType + } + variantKey := getDiscriminatorKey(displayName, variantType) + outWithVariant = append(outWithVariant, getReport(variantKey, variant)...) + } + + sort.Strings(outWithVariant) + + return outWithVariant } } - return out + return outWithoutVariant + } func getEnumBoolReport(name string, isCovered bool) string { @@ -251,34 +300,34 @@ func getCoverageCount(model *Model) string { return fmt.Sprintf("(%v/%v)", model.CoveredCount, model.TotalCount) } -func getChildReport(name string, model *Model) string { - var style, report string +// func getChildReport(name string, model *Model) string { +// var style, report string - style = getStyle(model.IsFullyCovered) +// style = getStyle(model.IsFullyCovered) - if hasNoDetail(model) { - // leaf property - report = fmt.Sprintf(` -
-%[3]v +// if hasNoDetail(model) { +// // leaf property +// report = fmt.Sprintf(` +//
+// %[3]v -
`, model.Identifier, style, name) - } else { - childReport := getReport(model) - sort.Strings(childReport) - report = fmt.Sprintf(` -
-%[3]v %[4]v -
+//
`, model.Identifier, style, name) +// } else { +// childReport := getReport(model, model.ModelName) +// sort.Strings(childReport) +// report = fmt.Sprintf(` +//
+// %[3]v %[4]v +//
-%[5]v +// %[5]v -
-
`, model.Identifier, style, name, getCoverageCount(model), strings.Join(childReport, "\n\n")) - } +// +//
`, model.Identifier, style, name, getCoverageCount(model), strings.Join(childReport, "\n\n")) +// } - return report -} +// return report +// } func hasNoDetail(model *Model) bool { if model.Properties == nil && model.Variants == nil && model.Item == nil && (!isBoolEnumDisplayed || (model.Bool == nil && model.Enum == nil)) { @@ -299,3 +348,7 @@ func getStyle(isFullyCovered bool) string { } return " style=\"color:red\"" } + +func getDiscriminatorKey(modelName, variantType string) string { + return fmt.Sprintf("%s{%s}", modelName, variantType) +} From 3899268e053b0977358a634c06fc266257917345 Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 02:40:01 +0000 Subject: [PATCH 2/9] enhance test --- .gitignore | 2 +- coverage/coverage_test.go | 314 ++++++++++++++++++-------------------- coverage/expand.go | 10 ++ coverage/expand_test.go | 2 +- 4 files changed, 158 insertions(+), 170 deletions(-) diff --git a/.gitignore b/.gitignore index e87a764..1a1e5b5 100644 --- a/.gitignore +++ b/.gitignore @@ -16,5 +16,5 @@ armstrong armstrong.exe # test output -coverage/test_coverage_report*.md +coverage/testdata/test_coverage_report*.md coverage/testdata/index.json diff --git a/coverage/coverage_test.go b/coverage/coverage_test.go index e26d06d..5016a88 100644 --- a/coverage/coverage_test.go +++ b/coverage/coverage_test.go @@ -138,22 +138,20 @@ func TestCoverage_HealthcareDicom(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - if model.CoveredCount != 12 { - t.Fatalf("expected CoveredCount 12, got %d", model.CoveredCount) - } } func TestCoverage_MachineLearningServicesWorkspacesJobs(t *testing.T) { tc := testCase{ - name: "MachineLearningServicesWorkspacesJobs", - resourceType: "Microsoft.MachineLearningServices/workspaces/jobs@2023-06-01-preview", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/jobs/job1", + name: "MachineLearningServicesWorkspacesJobs", + resourceType: "Microsoft.MachineLearningServices/workspaces/jobs@2024-04-01", + method: "PUT", + expectedCoveredCount: 11, + expectedTotalCount: 895, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/jobs/job1", rawRequest: []string{ `{ "properties": { @@ -199,23 +197,20 @@ func TestCoverage_MachineLearningServicesWorkspacesJobs(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 11 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_MachineLearningServicesWorkspacesDataVersions(t *testing.T) { tc := testCase{ - name: "MachineLearningServicesWorkspacesDataVersions", - resourceType: "Microsoft.MachineLearningServices/workspaces/data/versions@2023-06-01-preview", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/data/data1/versions/version1", + name: "MachineLearningServicesWorkspacesDataVersions", + resourceType: "Microsoft.MachineLearningServices/workspaces/data/versions@2024-04-01", + method: "PUT", + expectedCoveredCount: 8, + expectedTotalCount: 29, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/data/data1/versions/version1", rawRequest: []string{ `{ "properties": { @@ -238,23 +233,20 @@ func TestCoverage_MachineLearningServicesWorkspacesDataVersions(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 8 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_DeviceSecurityGroup(t *testing.T) { tc := testCase{ - name: "DeviceSecurityGroup", - resourceType: "Microsoft.Security/deviceSecurityGroups@2019-08-01", - method: "PUT", - apiPath: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/SampleRG/providers/Microsoft.Devices/iotHubs/sampleiothub/providers/Microsoft.Security/deviceSecurityGroups/samplesecuritygroup", + name: "DeviceSecurityGroup", + resourceType: "Microsoft.Security/deviceSecurityGroups@2019-08-01", + method: "PUT", + expectedCoveredCount: 5, + expectedTotalCount: 192, + apiPath: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/SampleRG/providers/Microsoft.Devices/iotHubs/sampleiothub/providers/Microsoft.Security/deviceSecurityGroups/samplesecuritygroup", rawRequest: []string{ `{ "properties": { @@ -273,30 +265,32 @@ func TestCoverage_DeviceSecurityGroup(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - expected := 5 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } -func TestCoverage_DataMigrationServiceTasks(t *testing.T) { - // Do we need to support cross file discriminator reference? Now seems only DataMigration has this. e.g., https://github.com/Azure/azure-rest-api-specs/blob/0ab5469dc0d75594f5747493dcfe8774e22d728f/specification/datamigration/resource-manager/Microsoft.DataMigration/stable/2021-06-30/definitions/ServiceTasks.json#L39 +func TestCoverage_SCVMM(t *testing.T) { tc := testCase{ - name: "DataMigrationServiceTasks", - resourceType: "Microsoft.DataMigration/services/serviceTasks@2021-06-30", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/serviceTasks/DmsSdkTask", + name: "SCVMM", + resourceType: "Microsoft.ScVmm/virtualMachineInstances@2023-10-07", + method: "PUT", + expectedCoveredCount: 5, + expectedTotalCount: 39, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/cli-test-rg-vmm/providers/Microsoft.HybridCompute/machines/test-vm-tf/providers/Microsoft.ScVmm/virtualMachineInstances/default", rawRequest: []string{ `{ + "extendedLocation": { + "name": "/subscriptions/12345678-1234-9876-4563-123456789012/resourcegroups/syntheticsscvmmcan/providers/microsoft.extendedlocation/customlocations/terraform-test-cl", + "type": "customLocation" + }, "properties": { - "taskType": "Service.Check.OCI", - "input": { - "serverVersion": "NA" + "infrastructureProfile": { + "cloudId": "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/cli-test-rg-vmm/providers/Microsoft.SCVMM/Clouds/azcli-test-cloud", + "templateId": "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/cli-test-rg-vmm/providers/Microsoft.SCVMM/VirtualMachineTemplates/azcli-test-vm-template-win19", + "vmmServerId": "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/SyntheticsSCVMMCan/providers/microsoft.scvmm/vmmservers/tf-test-vmmserver" } } }`, @@ -309,46 +303,41 @@ func TestCoverage_DataMigrationServiceTasks(t *testing.T) { } } -func TestCoverage_SCVMM(t *testing.T) { +func TestCoverage_DataMigrationServiceTasks(t *testing.T) { + // Do we need to support cross file discriminator reference? Now seems only DataMigration has this. e.g., https://github.com/Azure/azure-rest-api-specs/blob/0ab5469dc0d75594f5747493dcfe8774e22d728f/specification/datamigration/resource-manager/Microsoft.DataMigration/stable/2021-06-30/definitions/ServiceTasks.json#L39 tc := testCase{ - name: "SCVMM", - resourceType: "Microsoft.ScVmm/virtualMachineInstances@2023-10-07", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/cli-test-rg-vmm/providers/Microsoft.HybridCompute/machines/test-vm-tf/providers/Microsoft.ScVmm/virtualMachineInstances/default", + name: "DataMigrationServiceTasks", + resourceType: "Microsoft.DataMigration/services/serviceTasks@2021-06-30", + method: "PUT", + expectedCoveredCount: 1, + expectedTotalCount: 615, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/serviceTasks/DmsSdkTask", rawRequest: []string{ `{ - "extendedLocation": { - "name": "/subscriptions/12345678-1234-9876-4563-123456789012/resourcegroups/syntheticsscvmmcan/providers/microsoft.extendedlocation/customlocations/terraform-test-cl", - "type": "customLocation" - }, "properties": { - "infrastructureProfile": { - "cloudId": "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/cli-test-rg-vmm/providers/Microsoft.SCVMM/Clouds/azcli-test-cloud", - "templateId": "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/cli-test-rg-vmm/providers/Microsoft.SCVMM/VirtualMachineTemplates/azcli-test-vm-template-win19", - "vmmServerId": "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/SyntheticsSCVMMCan/providers/microsoft.scvmm/vmmservers/tf-test-vmmserver" + "taskType": "Service.Check.OCI", + "input": { + "serverVersion": "NA" } } }`, }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 5 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_DataMigrationTasks(t *testing.T) { tc := testCase{ - name: "DataMigrationTasks", - resourceType: "Microsoft.DataMigration/services/projects/tasks@2021-06-30", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/projects/DmsSdkProject/tasks/DmsSdkTask", + name: "DataMigrationTasks", + resourceType: "Microsoft.DataMigration/services/projects/tasks@2021-06-30", + method: "PUT", + expectedCoveredCount: 8, + expectedTotalCount: 615, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/projects/DmsSdkProject/tasks/DmsSdkTask", rawRequest: []string{ `{ "properties": { @@ -369,23 +358,20 @@ func TestCoverage_DataMigrationTasks(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 8 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_KeyVault(t *testing.T) { tc := testCase{ - name: "KeyVault", - resourceType: "Microsoft.KeyVault/vaults@2023-02-01", - method: "PUT", - apiPath: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sample-resource-group/providers/Microsoft.KeyVault/vaults/sample-vault", + name: "KeyVault", + resourceType: "Microsoft.KeyVault/vaults@2023-02-01", + method: "PUT", + expectedCoveredCount: 13, + expectedTotalCount: 28, + apiPath: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sample-resource-group/providers/Microsoft.KeyVault/vaults/sample-vault", rawRequest: []string{ `{ "location": "westus", @@ -456,23 +442,20 @@ func TestCoverage_KeyVault(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 13 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_StorageAccount(t *testing.T) { tc := testCase{ - name: "StorageAccount", - resourceType: "Microsoft.Storage/storageAccounts@2022-09-01", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/res9101/providers/Microsoft.Storage/storageAccounts/sto4445", + name: "StorageAccount", + resourceType: "Microsoft.Storage/storageAccounts@2023-01-01", + method: "PUT", + expectedCoveredCount: 24, + expectedTotalCount: 69, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/res9101/providers/Microsoft.Storage/storageAccounts/sto4445", rawRequest: []string{ `{ "sku": { @@ -525,23 +508,20 @@ func TestCoverage_StorageAccount(t *testing.T) { }`, }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 24 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_VM(t *testing.T) { tc := testCase{ - name: "VM", - resourceType: "Microsoft.Compute/virtualMachines@2023-03-01", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm", + name: "VM", + resourceType: "Microsoft.Compute/virtualMachines@2024-03-01", + method: "PUT", + expectedCoveredCount: 20, + expectedTotalCount: 166, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm", rawRequest: []string{ `{ "location": "westus", @@ -596,23 +576,20 @@ func TestCoverage_VM(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 20 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_VNet(t *testing.T) { tc := testCase{ - name: "VNet", - resourceType: "Microsoft.Network/virtualNetworks@2023-02-01", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/virtualNetwork", + name: "VNet", + resourceType: "Microsoft.Network/virtualNetworks@2024-01-01", + method: "PUT", + expectedCoveredCount: 4, + expectedTotalCount: 104, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/virtualNetwork", rawRequest: []string{ `{ "properties": { @@ -635,23 +612,20 @@ func TestCoverage_VNet(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 4 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_DataCollectionRule(t *testing.T) { tc := testCase{ - name: "DataCollectionRule", - resourceType: "Microsoft.Insights/dataCollectionRules@2022-06-01", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", + name: "DataCollectionRule", + resourceType: "Microsoft.Insights/dataCollectionRules@2022-06-01", + method: "PUT", + expectedCoveredCount: 65, + expectedTotalCount: 65, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/test-resources/providers/Microsoft.Insights/dataCollectionRules/testDCR", rawRequest: []string{ `{ "location": "westeurope", @@ -975,10 +949,12 @@ func TestCoverage_DataCollectionRule(t *testing.T) { func TestCoverage_WebSite(t *testing.T) { tc := testCase{ - name: "WebSites", - resourceType: "Microsoft.Web/sites@2022-09-01", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/testrg123/providers/Microsoft.Web/sites/sitef6141", + name: "WebSites", + resourceType: "Microsoft.Web/sites@2023-01-01", + method: "PUT", + expectedCoveredCount: 3, + expectedTotalCount: 198, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/testrg123/providers/Microsoft.Web/sites/sitef6141", rawRequest: []string{ `{ "kind": "app", @@ -990,15 +966,10 @@ func TestCoverage_WebSite(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 3 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_AKS(t *testing.T) { @@ -1082,23 +1053,20 @@ func TestCoverage_AKS(t *testing.T) { }`}, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 33 - if model.CoveredCount != expected { - t.Fatalf("expected TotalCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_CosmosDB(t *testing.T) { tc := testCase{ - name: "CosmosDB", - resourceType: "Microsoft.DocumentDB/databaseAccounts@2024-05-15", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DocumentDB/databaseAccounts/testdb", + name: "CosmosDB", + resourceType: "Microsoft.DocumentDB/databaseAccounts@2024-05-15", + method: "PUT", + expectedCoveredCount: 33, + expectedTotalCount: 67, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DocumentDB/databaseAccounts/testdb", rawRequest: []string{ `{ "location": "westus", @@ -1187,11 +1155,6 @@ func TestCoverage_CosmosDB(t *testing.T) { t.Fatalf("process coverage: %v", err) } - expected := 33 - if model.CoveredCount != expected { - t.Fatalf("expected CoveredCount %d, got %d", expected, model.CoveredCount) - } - if model.Properties == nil { t.Fatalf("expected properties, got none") } @@ -1323,10 +1286,12 @@ func TestCoverage_CosmosDB(t *testing.T) { func TestCoverage_DataFactoryPipelines(t *testing.T) { tc := testCase{ - name: "DataFactoryPipelines", - resourceType: "Microsoft.DataFactory/factories/pipelines@2018-06-01", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-1234-1234-12345678abc/resourceGroups/exampleResourceGroup/providers/Microsoft.DataFactory/factories/exampleFactoryName/pipelines/examplePipeline", + name: "DataFactoryPipelines", + resourceType: "Microsoft.DataFactory/factories/pipelines@2018-06-01", + method: "PUT", + expectedCoveredCount: 11, + expectedTotalCount: 7239, + apiPath: "/subscriptions/12345678-1234-1234-1234-12345678abc/resourceGroups/exampleResourceGroup/providers/Microsoft.DataFactory/factories/exampleFactoryName/pipelines/examplePipeline", rawRequest: []string{ `{ "properties": { @@ -1411,23 +1376,20 @@ func TestCoverage_DataFactoryPipelines(t *testing.T) { }, } - model, err := testCoverage(t, tc) + _, err := testCoverage(t, tc) if err != nil { t.Fatalf("process coverage: %+v", err) } - - expected := 11 - if model.CoveredCount != expected { - t.Fatalf("expected TotalCount %d, got %d", expected, model.CoveredCount) - } } func TestCoverage_DataFactoryLinkedServices(t *testing.T) { tc := testCase{ - name: "DataFactoryLinkedServices", - resourceType: "Microsoft.DataFactory/factories/linkedServices@2018-06-01", - method: "PUT", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DataFactory/factories/factory1/linkedServices/linked", + name: "DataFactoryLinkedServices", + resourceType: "Microsoft.DataFactory/factories/linkedServices@2018-06-01", + method: "PUT", + expectedCoveredCount: 2, + expectedTotalCount: 3450, + apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DataFactory/factories/factory1/linkedServices/linked", rawRequest: []string{ `{ "properties": { @@ -1448,11 +1410,6 @@ func TestCoverage_DataFactoryLinkedServices(t *testing.T) { t.Fatalf("process coverage: %+v", err) } - expected := 2 - if model.CoveredCount != expected { - t.Fatalf("expected TotalCount %d, got %d", expected, model.CoveredCount) - } - if model.Properties == nil { t.Fatalf("expected properties, got none") } @@ -1524,14 +1481,35 @@ func TestCoverage_DataFactoryLinkedServices(t *testing.T) { func testCoverage(t *testing.T, tc testCase) (*coverage.Model, error) { apiVersion := strings.Split(tc.resourceType, "@")[1] - swaggerModel, err := coverage.GetModelInfoFromLocalIndex( - tc.apiPath, - apiVersion, - tc.method, - "/home/wangta/project/go/azure-rest-api-specs/specification/", - "index0910.json", - ) + var swaggerModel *coverage.SwaggerModel + var err error + azureRepoDir := os.Getenv("AZURE_REST_REPO_DIR") + if azureRepoDir != "" { + if strings.HasSuffix(azureRepoDir, "specification") { + azureRepoDir += "/" + } + if !strings.HasSuffix(normarlizePath(azureRepoDir), "specification/") { + t.Fatalf("AZURE_REST_REPO_DIR must specify the specification folder, e.g., AZURE_REST_REPO_DIR=\"/home/test/go/src/github.com/azure/azure-rest-api-specs/specification/\"") + } + + t.Logf("AZURE_REST_REPO_DIR: %s", azureRepoDir) + + swaggerModel, err = coverage.GetModelInfoFromLocalIndex( + tc.apiPath, + apiVersion, + tc.method, + azureRepoDir, + "./testdata/index.json", + ) + } else { + swaggerModel, err = coverage.GetModelInfoFromIndex( + tc.apiPath, + apiVersion, + tc.method, + "./testdata/index.json", + ) + } t.Logf("swaggerModel: %+v", swaggerModel) if err != nil { @@ -1594,7 +1572,7 @@ func testCoverage(t *testing.T, tc testCase) (*coverage.Model, error) { }, } - storeCoverageReport(passReport, coverageReport, ".", fmt.Sprintf("test_coverage_report_%s.md", tc.name)) + storeCoverageReport(passReport, coverageReport, "./testdata/", fmt.Sprintf("test_coverage_report_%s.md", tc.name)) return model, nil } diff --git a/coverage/expand.go b/coverage/expand.go index 3fca964..a0af0e7 100644 --- a/coverage/expand.go +++ b/coverage/expand.go @@ -70,11 +70,20 @@ func getAllOfTable(swaggerPath string) (map[string]map[string]interface{}, error return allOfTable, nil } +func trimPath(path string) string { + if strings.Contains(path, "\\") { + return strings.ReplaceAll(path, "\\.\\", "\\") + } + return strings.ReplaceAll(path, "/./", "/") +} + func Expand(modelName, swaggerPath string) (*Model, error) { if modelName == "" { return nil, fmt.Errorf("modelName is empty") } + swaggerPath = trimPath(swaggerPath) + doc, err := loadSwagger(swaggerPath) if err != nil { return nil, err @@ -330,6 +339,7 @@ func SchemaNamePathFromRef(swaggerPath string, ref openapiSpec.Ref) (schemaName } else { swaggerPath, _ := filepath.Split(swaggerPath) schemaPath = swaggerPath + schemaPath + schemaPath = trimPath(schemaPath) } fragments := strings.Split(refUrl.Fragment, "/") diff --git a/coverage/expand_test.go b/coverage/expand_test.go index e84f72b..58b3f56 100644 --- a/coverage/expand_test.go +++ b/coverage/expand_test.go @@ -123,7 +123,7 @@ func TestExpandAll(t *testing.T) { t.Fatalf("AZURE_REST_REPO_DIR must specify the specification folder, e.g., AZURE_REST_REPO_DIR=\"/home/test/go/src/github.com/azure/azure-rest-api-specs/specification/\"") } - t.Logf("azure repo dir: %s", azureRepoDir) + t.Logf("AZURE_REST_REPO_DIR: %s", azureRepoDir) testResultFilePath := os.Getenv("TEST_RESULT_PATH") From 3cd01850dbf1bcc24c018fa06fcad25093247b1a Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 02:43:11 +0000 Subject: [PATCH 3/9] remove unused --- coverage/report.go | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/coverage/report.go b/coverage/report.go index 6f5f09c..5a96020 100644 --- a/coverage/report.go +++ b/coverage/report.go @@ -300,35 +300,6 @@ func getCoverageCount(model *Model) string { return fmt.Sprintf("(%v/%v)", model.CoveredCount, model.TotalCount) } -// func getChildReport(name string, model *Model) string { -// var style, report string - -// style = getStyle(model.IsFullyCovered) - -// if hasNoDetail(model) { -// // leaf property -// report = fmt.Sprintf(` -//
-// %[3]v - -//
`, model.Identifier, style, name) -// } else { -// childReport := getReport(model, model.ModelName) -// sort.Strings(childReport) -// report = fmt.Sprintf(` -//
-// %[3]v %[4]v -//
- -// %[5]v - -//
-//
`, model.Identifier, style, name, getCoverageCount(model), strings.Join(childReport, "\n\n")) -// } - -// return report -// } - func hasNoDetail(model *Model) bool { if model.Properties == nil && model.Variants == nil && model.Item == nil && (!isBoolEnumDisplayed || (model.Bool == nil && model.Enum == nil)) { return true From 1effd4c4f5c7501719171951489d1bea5ec5d57e Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 02:47:15 +0000 Subject: [PATCH 4/9] update report coverage count --- coverage/report.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coverage/report.go b/coverage/report.go index 5a96020..e4acf8a 100644 --- a/coverage/report.go +++ b/coverage/report.go @@ -79,7 +79,7 @@ ${coverage_details} if v.Model.IsFullyCovered { fullyCoveredPath = append(fullyCoveredPath, v.DisplayName) } else { - partiallyCoveredPath = append(partiallyCoveredPath, fmt.Sprintf("%v (%v/%v)", v.DisplayName, v.Model.CoveredCount, v.Model.TotalCount)) + partiallyCoveredPath = append(partiallyCoveredPath, fmt.Sprintf("%v (%v/%v)", v.DisplayName, v.Model.RootCoveredCount, v.Model.RootTotalCount)) } } @@ -136,11 +136,11 @@ func (c *CoverageReport) MarkdownContentCompact() string { for _, v := range c.Coverages { coverage := 100.0 if v.Model.TotalCount > 0 { - coverage = float64(v.Model.CoveredCount * 100 / v.Model.TotalCount) + coverage = float64(v.Model.RootCoveredCount * 100 / v.Model.RootTotalCount) } - content += fmt.Sprintf("|%s|%d|%d|%.1f%%|\n", v.DisplayName, v.Model.CoveredCount, v.Model.TotalCount, coverage) - total += v.Model.TotalCount - covered += v.Model.CoveredCount + content += fmt.Sprintf("|%s|%d|%d|%.1f%%|\n", v.DisplayName, v.Model.RootCoveredCount, v.Model.RootTotalCount, coverage) + total += v.Model.RootTotalCount + covered += v.Model.RootCoveredCount } coverage := 100.0 From 8a2d91d5731e57fffca71119e6340f3e9eb3d4b5 Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 03:18:04 +0000 Subject: [PATCH 5/9] fix test --- coverage/coverage_test.go | 32 +++----------------------------- coverage/index.go | 4 ++-- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/coverage/coverage_test.go b/coverage/coverage_test.go index 5016a88..8eda804 100644 --- a/coverage/coverage_test.go +++ b/coverage/coverage_test.go @@ -61,28 +61,6 @@ func TestCoverage_ResourceGroup(t *testing.T) { } } -func TestCoverage_AzureTerraform(t *testing.T) { - tc := testCase{ - name: "AzureTerraform", - resourceType: "Microsoft.AzureTerraform@2023-07-01-preview", - method: "POST", - apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.AzureTerraform/exportTerraform", - expectedCoveredCount: 2, - expectedTotalCount: 25, - rawRequest: []string{ - `{ - "resourceGroupName" : "rg1", - "type" : "ExportResourceGroup" - }`, - }, - } - - _, err := testCoverage(t, tc) - if err != nil { - t.Fatalf("process coverage: %+v", err) - } -} - func TestCoverage_HealthcareDicom(t *testing.T) { tc := testCase{ name: "HealthcareApisDicom", @@ -91,7 +69,6 @@ func TestCoverage_HealthcareDicom(t *testing.T) { apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rgName/providers/Microsoft.HealthcareApis/workspaces/workspaceName/dicomservices/dicomServiceName", expectedCoveredCount: 12, expectedTotalCount: 14, - // bulkImportConfiguration property not in swagger rawRequest: []string{ `{ "identity": { @@ -120,9 +97,6 @@ func TestCoverage_HealthcareDicom(t *testing.T) { "*" ] }, - "bulkImportConfiguration": { - "enabled": false - }, "enableDataPartitions": false, "encryption": { "customerManagedKeyEncryption": { @@ -309,15 +283,15 @@ func TestCoverage_DataMigrationServiceTasks(t *testing.T) { name: "DataMigrationServiceTasks", resourceType: "Microsoft.DataMigration/services/serviceTasks@2021-06-30", method: "PUT", - expectedCoveredCount: 1, + expectedCoveredCount: 2, expectedTotalCount: 615, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/serviceTasks/DmsSdkTask", rawRequest: []string{ `{ "properties": { - "taskType": "Service.Check.OCI", + "taskType": "ConnectToSource.MySql", "input": { - "serverVersion": "NA" + "targetPlatform": "string" } } }`, diff --git a/coverage/index.go b/coverage/index.go index 7eb6697..97538d2 100644 --- a/coverage/index.go +++ b/coverage/index.go @@ -178,7 +178,7 @@ func GetModelInfoFromIndex(resourceId, apiVersion, method, indexFilePath string) } ref, err := index.Lookup(method, *uRL) if err != nil { - return nil, fmt.Errorf("lookup PUT URL %s in index: %+v", resourceURL, err) + return nil, fmt.Errorf("lookup %s URL %s in index: %+v", method, resourceURL, err) } model, err := GetModelInfoFromIndexRef(openapispec.Ref{Ref: *ref}, azureRepoURL) @@ -223,7 +223,7 @@ func GetModelInfoFromLocalIndex(resourceId, apiVersion, method, swaggerRepo, ind } ref, err := index.Lookup(method, *uRL) if err != nil { - return nil, fmt.Errorf("lookup PUT URL %s in index: %+v", resourceURL, err) + return nil, fmt.Errorf("lookup %s URL %s in index: %+v", method, resourceURL, err) } model, err := GetModelInfoFromIndexRef(openapispec.Ref{Ref: *ref}, swaggerRepo) From 2139807d586c9ab1ee8f579fdc52b4fbe0acc7cf Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 04:22:15 +0000 Subject: [PATCH 6/9] fix error message level --- coverage/coverage.go | 7 +++---- coverage/coverage_test.go | 11 ++++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/coverage/coverage.go b/coverage/coverage.go index d2b8299..270b3c0 100644 --- a/coverage/coverage.go +++ b/coverage/coverage.go @@ -131,7 +131,7 @@ func (m *Model) MarkCovered(root interface{}) { if m.Enum != nil { strValue := fmt.Sprintf("%v", value) if _, ok := (*m.Enum)[strValue]; !ok { - logrus.Errorf("unexpected enum %s in %s", value, m.Identifier) + logrus.Warningf("unexpected enum %s in %s", value, m.Identifier) } (*m.Enum)[strValue] = true @@ -192,9 +192,8 @@ func (m *Model) MarkCovered(root interface{}) { if isMatchProperty { for k, v := range value { if m.Properties == nil { - if !m.HasAdditionalProperties { - logrus.Errorf("unexpected key %s in %s", k, m.Identifier) - } + // some objects has no properties defined + // https://github.com/Azure/azure-rest-api-specs/blob/3519c80fe510a268f6e59a29ccac8a53fdec15b6/specification/monitor/resource-manager/Microsoft.Insights/stable/2023-03-11/dataCollectionRules_API.json#L724 continue } if _, ok := (*m.Properties)[k]; !ok { diff --git a/coverage/coverage_test.go b/coverage/coverage_test.go index 8eda804..c5cd972 100644 --- a/coverage/coverage_test.go +++ b/coverage/coverage_test.go @@ -291,7 +291,9 @@ func TestCoverage_DataMigrationServiceTasks(t *testing.T) { "properties": { "taskType": "ConnectToSource.MySql", "input": { - "targetPlatform": "string" + "sourceConnectionInfo": { + "serverName": "mySqlService" + } } } }`, @@ -873,8 +875,7 @@ func TestCoverage_DataCollectionRule(t *testing.T) { "extensions": [ { "streams": [ - "Microsoft-WindowsEvent", - "Microsoft-ServiceMap" + "Microsoft-WindowsEvent" ], "inputDataSources": [ "test-datasource-wineventlog" @@ -961,7 +962,7 @@ func TestCoverage_AKS(t *testing.T) { "archv2": "" }, "sku": { - "name": "Basic", + "name": "Base", "tier": "Free" }, "properties": { @@ -1505,7 +1506,7 @@ func testCoverage(t *testing.T, tc testCase) (*coverage.Model, error) { request := map[string]interface{}{} err = json.Unmarshal([]byte(rq), &request) if err != nil { - t.Error(err) + t.Errorf("error unmarshal request json: %v", err) } model.MarkCovered(request) From f49b539bfa72d344d524049c3cd82107127d1e03 Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 04:36:00 +0000 Subject: [PATCH 7/9] fix vnet test --- coverage/coverage_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coverage/coverage_test.go b/coverage/coverage_test.go index c5cd972..b3e4a17 100644 --- a/coverage/coverage_test.go +++ b/coverage/coverage_test.go @@ -564,7 +564,7 @@ func TestCoverage_VNet(t *testing.T) { resourceType: "Microsoft.Network/virtualNetworks@2024-01-01", method: "PUT", expectedCoveredCount: 4, - expectedTotalCount: 104, + expectedTotalCount: 103, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/virtualNetwork", rawRequest: []string{ `{ From bc1d049ae0026efab69837a0f93987a87188bde2 Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 05:25:20 +0000 Subject: [PATCH 8/9] always match base discriminator --- coverage/coverage.go | 6 +++--- coverage/coverage_test.go | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/coverage/coverage.go b/coverage/coverage.go index 270b3c0..577f223 100644 --- a/coverage/coverage.go +++ b/coverage/coverage.go @@ -32,7 +32,7 @@ type Model struct { SourceFile string `json:"SourceFile,omitempty"` TotalCount int `json:"TotalCount,omitempty"` Type *string `json:"Type,omitempty"` - Variants *map[string]*Model `json:"Variants,omitempty"` // variant model name is used as key, this may only contains + Variants *map[string]*Model `json:"Variants,omitempty"` // variant model name is used as key, in case x-ms-discriminator-value is not available VariantType *string `json:"VariantType,omitempty"` // the x-ms-discriminator-value of the variant model if exists, otherwise model name } @@ -171,14 +171,14 @@ func (m *Model) MarkCovered(root interface{}) { // either the discriminator value hit the variant model name or variant type, we match the variant if variant, ok := (*m.Variants)[v.(string)]; ok { - isMatchProperty = false + isMatchProperty = true variant.MarkCovered(value) break } for _, variant := range *m.Variants { if variant.VariantType != nil && *variant.VariantType == v.(string) { - isMatchProperty = false + isMatchProperty = true variant.MarkCovered(value) break Loop diff --git a/coverage/coverage_test.go b/coverage/coverage_test.go index b3e4a17..748626c 100644 --- a/coverage/coverage_test.go +++ b/coverage/coverage_test.go @@ -123,7 +123,7 @@ func TestCoverage_MachineLearningServicesWorkspacesJobs(t *testing.T) { name: "MachineLearningServicesWorkspacesJobs", resourceType: "Microsoft.MachineLearningServices/workspaces/jobs@2024-04-01", method: "PUT", - expectedCoveredCount: 11, + expectedCoveredCount: 19, expectedTotalCount: 895, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/jobs/job1", rawRequest: []string{ @@ -182,7 +182,7 @@ func TestCoverage_MachineLearningServicesWorkspacesDataVersions(t *testing.T) { name: "MachineLearningServicesWorkspacesDataVersions", resourceType: "Microsoft.MachineLearningServices/workspaces/data/versions@2024-04-01", method: "PUT", - expectedCoveredCount: 8, + expectedCoveredCount: 15, expectedTotalCount: 29, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.MachineLearningServices/workspaces/works1/data/data1/versions/version1", rawRequest: []string{ @@ -218,7 +218,7 @@ func TestCoverage_DeviceSecurityGroup(t *testing.T) { name: "DeviceSecurityGroup", resourceType: "Microsoft.Security/deviceSecurityGroups@2019-08-01", method: "PUT", - expectedCoveredCount: 5, + expectedCoveredCount: 10, expectedTotalCount: 192, apiPath: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/SampleRG/providers/Microsoft.Devices/iotHubs/sampleiothub/providers/Microsoft.Security/deviceSecurityGroups/samplesecuritygroup", rawRequest: []string{ @@ -243,7 +243,6 @@ func TestCoverage_DeviceSecurityGroup(t *testing.T) { if err != nil { t.Fatalf("process coverage: %+v", err) } - } func TestCoverage_SCVMM(t *testing.T) { @@ -283,7 +282,7 @@ func TestCoverage_DataMigrationServiceTasks(t *testing.T) { name: "DataMigrationServiceTasks", resourceType: "Microsoft.DataMigration/services/serviceTasks@2021-06-30", method: "PUT", - expectedCoveredCount: 2, + expectedCoveredCount: 3, expectedTotalCount: 615, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/serviceTasks/DmsSdkTask", rawRequest: []string{ @@ -311,7 +310,7 @@ func TestCoverage_DataMigrationTasks(t *testing.T) { name: "DataMigrationTasks", resourceType: "Microsoft.DataMigration/services/projects/tasks@2021-06-30", method: "PUT", - expectedCoveredCount: 8, + expectedCoveredCount: 9, expectedTotalCount: 615, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/DmsSdkRg/providers/Microsoft.DataMigration/services/DmsSdkService/projects/DmsSdkProject/tasks/DmsSdkTask", rawRequest: []string{ @@ -1039,7 +1038,7 @@ func TestCoverage_CosmosDB(t *testing.T) { name: "CosmosDB", resourceType: "Microsoft.DocumentDB/databaseAccounts@2024-05-15", method: "PUT", - expectedCoveredCount: 33, + expectedCoveredCount: 34, expectedTotalCount: 67, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DocumentDB/databaseAccounts/testdb", rawRequest: []string{ @@ -1264,7 +1263,7 @@ func TestCoverage_DataFactoryPipelines(t *testing.T) { name: "DataFactoryPipelines", resourceType: "Microsoft.DataFactory/factories/pipelines@2018-06-01", method: "PUT", - expectedCoveredCount: 11, + expectedCoveredCount: 13, expectedTotalCount: 7239, apiPath: "/subscriptions/12345678-1234-1234-1234-12345678abc/resourceGroups/exampleResourceGroup/providers/Microsoft.DataFactory/factories/exampleFactoryName/pipelines/examplePipeline", rawRequest: []string{ @@ -1362,7 +1361,7 @@ func TestCoverage_DataFactoryLinkedServices(t *testing.T) { name: "DataFactoryLinkedServices", resourceType: "Microsoft.DataFactory/factories/linkedServices@2018-06-01", method: "PUT", - expectedCoveredCount: 2, + expectedCoveredCount: 3, expectedTotalCount: 3450, apiPath: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/rg1/providers/Microsoft.DataFactory/factories/factory1/linkedServices/linked", rawRequest: []string{ @@ -1397,8 +1396,8 @@ func TestCoverage_DataFactoryLinkedServices(t *testing.T) { t.Fatalf("expected properties type property, got none") } - if (*(*model.Properties)["properties"].Properties)["type"].IsAnyCovered { - t.Fatalf("expected properties type IsAnyCovered false, got true") + if !(*(*model.Properties)["properties"].Properties)["type"].IsAnyCovered { + t.Fatalf("expected properties type IsAnyCovered true, got false") } if (*model.Properties)["properties"].Discriminator == nil { From a88e1511c37ae4c89830cdaf0f25542fe1b1f04c Mon Sep 17 00:00:00 2001 From: teowa <104055472+teowa@users.noreply.github.com> Date: Wed, 11 Sep 2024 05:43:33 +0000 Subject: [PATCH 9/9] suppress error message for base discriminator prop match --- coverage/coverage.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/coverage/coverage.go b/coverage/coverage.go index 577f223..d57918f 100644 --- a/coverage/coverage.go +++ b/coverage/coverage.go @@ -93,13 +93,14 @@ func (m *Model) CredScan(root interface{}, secrets map[string]string) { if isMatchProperty { for k, v := range value { if m.Properties == nil { - if !m.HasAdditionalProperties { - logrus.Errorf("unexpected key %s in %s", k, m.Identifier) - } + // some objects has no properties defined + // https://github.com/Azure/azure-rest-api-specs/blob/3519c80fe510a268f6e59a29ccac8a53fdec15b6/specification/monitor/resource-manager/Microsoft.Insights/stable/2023-03-11/dataCollectionRules_API.json#L724 + + logrus.Warnf("unexpected key %s in %s", k, m.Identifier) continue } if _, ok := (*m.Properties)[k]; !ok { - if !m.HasAdditionalProperties { + if !m.HasAdditionalProperties && m.Discriminator == nil { logrus.Errorf("unexpected key %s in %s", k, m.Identifier) continue } @@ -194,10 +195,12 @@ func (m *Model) MarkCovered(root interface{}) { if m.Properties == nil { // some objects has no properties defined // https://github.com/Azure/azure-rest-api-specs/blob/3519c80fe510a268f6e59a29ccac8a53fdec15b6/specification/monitor/resource-manager/Microsoft.Insights/stable/2023-03-11/dataCollectionRules_API.json#L724 + logrus.Warnf("unexpected key %s in %s", k, m.Identifier) + continue } if _, ok := (*m.Properties)[k]; !ok { - if !m.HasAdditionalProperties { + if !m.HasAdditionalProperties && m.Discriminator == nil { logrus.Errorf("unexpected key %s in %s", k, m.Identifier) continue }