Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .chronus/changes/add-arm-spector-issue-1-2026-06-01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@azure-tools/azure-http-specs"
---

Add ARM spector test scenario for ArmResourceDeploymentScope (armResourceIdentifier with scopes)
139 changes: 139 additions & 0 deletions packages/azure-http-specs/spec-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,71 @@ maxpagesize=3
}
```

### Azure_ResourceManager_CommonProperties_ArmResourceIdentifiers_createOrReplace

- Endpoint: `put https://management.azure.com`

Resource PUT operation.
Expected path: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId
Expected query parameter: api-version=2023-12-01-preview
Expected request body:

```json
{
"location": "eastus",
"properties": {
"simpleArmId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithType": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithTypeAndScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithAllScopes": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachines/myVm"
}
}
```

Expected response body:

```json
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId",
"location": "eastus",
"name": "armId",
"type": "Azure.ResourceManager.CommonProperties/armResourceIdentifierResources",
"properties": {
"provisioningState": "Succeeded",
"simpleArmId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithType": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithTypeAndScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithAllScopes": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachines/myVm"
}
}
```

### Azure_ResourceManager_CommonProperties_ArmResourceIdentifiers_get

- Endpoint: `get https://management.azure.com`

Resource GET operation.
Expected path: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId
Expected query parameter: api-version=2023-12-01-preview

Expected response body:

```json
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId",
"location": "eastus",
"name": "armId",
"type": "Azure.ResourceManager.CommonProperties/armResourceIdentifierResources",
"properties": {
"provisioningState": "Succeeded",
"simpleArmId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithType": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithTypeAndScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithAllScopes": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachines/myVm"
}
}
```

### Azure_ResourceManager_CommonProperties_Error_createForUserDefinedError

- Endpoint: `put https://management.azure.com`
Expand Down Expand Up @@ -2330,6 +2395,80 @@ Expected response body:
}
```

### Azure_ResourceManager_LargeHeader_LargeHeaders_two6k

- Endpoint: `post https://management.azure.com`

Resource POST operation with long LRO headers(> 6KB + 6KB = 12KB).
To pass the test, client should accept both:

1. Single header size that's more than 6KB. 7KB is sure to pass the test.
2. Total headers size that's more than 12KB. 13KB is sure to pass the test.

Service returns both Location and Azure-AsyncOperation header on initial request.
final-state-via: location

Expected verb: POST
Expected path: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.LargeHeader/largeHeaders/header1/two6k
Expected query parameter: api-version=2023-12-01-preview
Expected response status code: 202
Expected response headers:

- Azure-AsyncOperation={endpoint}/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/locations/eastus/operations/post?userContext=<6KB-string>
- Location={endpoint}/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/operations/post?userContext=<6KB-string>
Expected no response body

Whether you do polling through AAO, Location or combined, first one will respond with provisioning state "InProgress", second one with "Succeeded".

AAO first poll.
Expected verb: GET
Expected URL: {endpoint}/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/locations/eastus/operations/post_aao?userContext=<6KB-string>
Expected status code: 200
Expected response body:

```json
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/locations/eastus/operations/post_aao?userContext=<6KB-string>",
"name": "post_aao",
"status": "InProgress",
"startTime": "2024-11-08T01:41:53.5508583+00:00"
}
```

AAO second poll.
Expected verb: GET
Expected URL: {endpoint}/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/locations/eastus/operations/post_aao?userContext=<6KB-string>
Expected status code: 200
Expected response body:

```json
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/locations/eastus/operations/post_aao?userContext=<6KB-string>",
"name": "post_aao",
"status": "Succeeded",
"startTime": "2024-11-08T01:41:53.5508583+00:00",
"endTime": "2024-11-08T01:42:41.5354192+00:00"
}
```

Location first poll.
Expected verb: GET
Expected URL: {endpoint}/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/locations/eastus/operations/post_location?userContext=<6KB-string>
Expected status code: 202
Expected no response body

Location second poll.
Expected verb: GET
Expected URL: {endpoint}/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.LargeHeader/locations/eastus/operations/post_location?userContext=<6KB-string>
Expected status code: 200
Expected response body:

```json
{
"succeeded": true
}
```

### Azure_ResourceManager_MethodSubscriptionId_MixedSubscriptionPlacement_ResourceGroupResourceOperations_delete

- Endpoint: `delete https://management.azure.com`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import "@typespec/http";
import "@typespec/rest";
import "@typespec/versioning";
import "@azure-tools/typespec-azure-core";
import "@azure-tools/typespec-azure-resource-manager";
import "@typespec/spector";

using Http;
using Rest;
using Versioning;
using Azure.Core;
using Azure.ResourceManager;
using OpenAPI;
using Spector;

namespace Azure.ResourceManager.CommonProperties;

@resource("armResourceIdentifierResources")
model ArmResourceIdentifierResource is TrackedResource<ArmResourceIdentifierResourceProperties> {
@key("armResourceIdentifierResourceName")
@path
@segment("armResourceIdentifierResources")
@doc("arm resource name for path")
@pattern("^[A-Za-z0-9]([A-Za-z0-9-_.]{0,62}[A-Za-z0-9])?$")
name: string;
}

@doc("ArmResourceIdentifier Resource Properties.")
model ArmResourceIdentifierResourceProperties {
@visibility(Lifecycle.Read)
@doc("The status of the last operation.")
provisioningState: ResourceProvisioningState;

@doc("A basic ARM resource identifier without type or scopes.")
simpleArmId: armResourceIdentifier;

@doc("An ARM resource identifier with type only.")
armIdWithType: armResourceIdentifier<[
{
type: "Microsoft.Network/virtualNetworks";
}
]>;

@doc("An ARM resource identifier with type and scopes.")
armIdWithTypeAndScope: armResourceIdentifier<[
{
type: "Microsoft.Network/virtualNetworks";
scopes: ["Tenant", "ResourceGroup"];
}
]>;

@doc("An ARM resource identifier with all scopes.")
armIdWithAllScopes: armResourceIdentifier<[
{
type: "Microsoft.Compute/virtualMachines";
scopes: ["Tenant", "Subscription", "ResourceGroup", "ManagementGroup", "Extension"];
}
]>;
}

@armResourceOperations
interface ArmResourceIdentifiers {
@scenario
@scenarioDoc("""
Resource GET operation.
Expected path: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId
Expected query parameter: api-version=2023-12-01-preview

Expected response body:
```json
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId",
"location": "eastus",
"name": "armId",
"type": "Azure.ResourceManager.CommonProperties/armResourceIdentifierResources",
"properties": {
"provisioningState": "Succeeded",
"simpleArmId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithType": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithTypeAndScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithAllScopes": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachines/myVm"
}
}
```
""")
get is ArmResourceRead<ArmResourceIdentifierResource>;

@scenario
@scenarioDoc("""
Resource PUT operation.
Expected path: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId
Expected query parameter: api-version=2023-12-01-preview
Expected request body:
```json
{
"location": "eastus",
"properties": {
"simpleArmId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithType": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithTypeAndScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithAllScopes": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachines/myVm"
}
}
```
Expected response body:
```json
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId",
"location": "eastus",
"name": "armId",
"type": "Azure.ResourceManager.CommonProperties/armResourceIdentifierResources",
"properties": {
"provisioningState": "Succeeded",
"simpleArmId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithType": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithTypeAndScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/myVnet",
"armIdWithAllScopes": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachines/myVm"
}
}
```
""")
createOrReplace is ArmResourceCreateOrReplaceSync<ArmResourceIdentifierResource>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "@azure-tools/typespec-azure-core";
import "@azure-tools/typespec-azure-resource-manager";
import "./managed-identity.tsp";
import "./error.tsp";
import "./arm-resource-identifier.tsp";

using Http;
using Rest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,73 @@ Scenarios.Azure_ResourceManager_CommonProperties_Error_createForUserDefinedError
},
kind: "MockApiDefinition",
});

// armResourceIdentifier resources
const SIMPLE_ARM_ID = `/subscriptions/${SUBSCRIPTION_ID_EXPECTED}/resourceGroups/${RESOURCE_GROUP_EXPECTED}/providers/Microsoft.Network/virtualNetworks/myVnet`;
const ARM_ID_WITH_TYPE = `/subscriptions/${SUBSCRIPTION_ID_EXPECTED}/resourceGroups/${RESOURCE_GROUP_EXPECTED}/providers/Microsoft.Network/virtualNetworks/myVnet`;
const ARM_ID_WITH_TYPE_AND_SCOPE = `/subscriptions/${SUBSCRIPTION_ID_EXPECTED}/resourceGroups/${RESOURCE_GROUP_EXPECTED}/providers/Microsoft.Network/virtualNetworks/myVnet`;
const ARM_ID_WITH_ALL_SCOPES = `/subscriptions/${SUBSCRIPTION_ID_EXPECTED}/resourceGroups/${RESOURCE_GROUP_EXPECTED}/providers/Microsoft.Compute/virtualMachines/myVm`;

const validArmResourceIdentifierResource = {
id: `/subscriptions/${SUBSCRIPTION_ID_EXPECTED}/resourceGroups/${RESOURCE_GROUP_EXPECTED}/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/armId`,
location: `${LOCATION_REGION_EXPECTED}`,
name: "armId",
type: "Azure.ResourceManager.CommonProperties/armResourceIdentifierResources",
properties: {
provisioningState: "Succeeded",
simpleArmId: SIMPLE_ARM_ID,
armIdWithType: ARM_ID_WITH_TYPE,
armIdWithTypeAndScope: ARM_ID_WITH_TYPE_AND_SCOPE,
armIdWithAllScopes: ARM_ID_WITH_ALL_SCOPES,
},
};

Scenarios.Azure_ResourceManager_CommonProperties_ArmResourceIdentifiers_get = passOnSuccess({
uri: "/subscriptions/:subscriptionId/resourceGroups/:resourceGroup/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/:armResourceIdentifierResourceName",
method: "get",
request: {
pathParams: {
subscriptionId: SUBSCRIPTION_ID_EXPECTED,
resourceGroup: RESOURCE_GROUP_EXPECTED,
armResourceIdentifierResourceName: "armId",
},
query: {
"api-version": "2023-12-01-preview",
},
},
response: {
status: 200,
body: json(validArmResourceIdentifierResource),
},
kind: "MockApiDefinition",
});

Scenarios.Azure_ResourceManager_CommonProperties_ArmResourceIdentifiers_createOrReplace =
passOnSuccess({
uri: "/subscriptions/:subscriptionId/resourceGroups/:resourceGroup/providers/Azure.ResourceManager.CommonProperties/armResourceIdentifierResources/:armResourceIdentifierResourceName",
method: "put",
request: {
body: json({
location: "eastus",
properties: {
simpleArmId: SIMPLE_ARM_ID,
armIdWithType: ARM_ID_WITH_TYPE,
armIdWithTypeAndScope: ARM_ID_WITH_TYPE_AND_SCOPE,
armIdWithAllScopes: ARM_ID_WITH_ALL_SCOPES,
},
}),
pathParams: {
subscriptionId: SUBSCRIPTION_ID_EXPECTED,
resourceGroup: RESOURCE_GROUP_EXPECTED,
armResourceIdentifierResourceName: "armId",
},
query: {
"api-version": "2023-12-01-preview",
},
},
response: {
status: 200,
body: json(validArmResourceIdentifierResource),
},
kind: "MockApiDefinition",
});
Loading