Skip to content
Open
Changes from 1 commit
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
157 changes: 151 additions & 6 deletions documentation/development/testing.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Testing SDKs

* [Write Tests](#write-tests)
* [Test Mode Options](#test-mode-options)
* [Routing Request to the Proxy](#routing-requests-to-the-proxy)
* [Writing Tests](#writing-tests)
* [Scrubbing Secrets](#scrubbing-secrets)
* [Live Test Resource Management](#live-test-resource-management)
* [Committing/Updating Recordings](#committingupdating-recordings)
* [Test Mode Options](#test-mode-options)
* [Routing Request to the Proxy](#routing-requests-to-the-proxy)
* [Writing Tests](#writing-tests)
* [Scrubbing Secrets](#scrubbing-secrets)
* [Live Test Resource Management](#live-test-resource-management)
* [Committing/Updating Recordings](#committingupdating-recordings)
* [Write Examples](#write-examples)

## Write Tests
Expand Down Expand Up @@ -94,6 +94,8 @@ NOTE: the path to the recordings **must** be in or under a directory named `test

### Writing Tests

#### example about `data plane`

A simple test for `aztables` is shown below:

```go
Expand Down Expand Up @@ -138,6 +140,149 @@ Check out the docs for more information about the methods available in the [`req

If you set the environment variable `AZURE_RECORD_MODE` to "record" and run `go test` with this code and the proper environment variables this test would pass and you would be left with a new directory and file. Test recordings are saved to a `recording` directory in the same directory that your test code lives. Running the above test would also create a file `recording/TestCreateTable.json` with the HTTP interactions persisted on disk. Now you can set `AZURE_RECORD_MODE` to "playback" and run `go test` again, the test will have the same output but without reaching the service.

#### example about `management plane`

A simple test for `armchaos` is shown below:
##### The first step is to download prepared scripts to genrated asset.json in the path and create file utils_test.go

1. Run the following PowerShell commands to download necessary scripts:

```ps
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code fence should use 'powershell' as the language identifier instead of 'ps' for better syntax highlighting and clarity.

Suggested change
```ps
```powershell

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you adopt this comment?

Invoke-WebRequest -OutFile "generate-assets-json.ps1" https://raw.githubusercontent.com/Azure/azure-sdk-tools/main/eng/common/testproxy/onboarding/generate-assets-json.ps1
Invoke-WebRequest -OutFile "common-asset-functions.ps1" https://raw.githubusercontent.com/Azure/azure-sdk-tools/main/eng/common/testproxy/onboarding/common-asset-functions.ps1
```

2. Run the script in the service path:
`.\generate-assets-json.ps1 -InitialPush`
This will create a config file `asset.json` and push recordings to the Azure SDK Assets repo.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be assets.json?


```
asset.json
Comment on lines +159 to +160
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
asset.json
`assets.json`
```json

{
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "go",
"TagPrefix": "go/resourcemanager/chaos/armchaos",
"Tag": "go/resourcemanager/chaos/armchaos_fd50b88100"
}
```

3. Before testing, create a utils_test.go file as the entry point for live tests. Modify "package" and pathToPackage to match your service.

```go
utils_test.go
//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package armchaos_test

import (
"os"
"testing"

"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3/testutil"
)
Comment on lines +179 to +186
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make sure the indentation of code aligns with the data-plane example code


const (
pathToPackage = "sdk/resourcemanager/chaos/armchaos/testdata"
)

func TestMain(m *testing.M) {
code := run(m)
os.Exit(code)
}

func run(m *testing.M) int {
f := testutil.StartProxy(pathToPackage)
defer f()
return m.Run()
}

```

##### Then you can add the test file

operation_live_test.go

```go
//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package armchaos_test

import (
"context"
"fmt"
"testing"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/internal/recording"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/chaos/armchaos/v2"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3/testutil"
"github.com/stretchr/testify/suite"
)

type OperationsTestSuite struct {
suite.Suite

ctx context.Context
cred azcore.TokenCredential
options *arm.ClientOptions
armEndpoint string
location string
resourceGroupName string
subscriptionId string
}

func (testsuite *OperationsTestSuite) SetupSuite() {
testutil.StartRecording(testsuite.T(), pathToPackage)

testsuite.ctx = context.Background()
testsuite.cred, testsuite.options = testutil.GetCredAndClientOptions(testsuite.T())
testsuite.armEndpoint = "https://management.azure.com"
testsuite.location = recording.GetEnvVariable("LOCATION", "eastus")
testsuite.resourceGroupName = recording.GetEnvVariable("RESOURCE_GROUP_NAME", "scenarioTestTempGroup")
testsuite.subscriptionId = recording.GetEnvVariable("AZURE_SUBSCRIPTION_ID", "00000000-0000-0000-0000-000000000000")
resourceGroup, _, err := testutil.CreateResourceGroup(testsuite.ctx, testsuite.subscriptionId, testsuite.cred, testsuite.options, testsuite.location)
testsuite.Require().NoError(err)
testsuite.resourceGroupName = *resourceGroup.Name
}

func (testsuite *OperationsTestSuite) TearDownSuite() {
_, err := testutil.DeleteResourceGroup(testsuite.ctx, testsuite.subscriptionId, testsuite.cred, testsuite.options, testsuite.resourceGroupName)
testsuite.Require().NoError(err)
testutil.StopRecording(testsuite.T())
}

func TestOperationsTestSuite(t *testing.T) {
suite.Run(t, new(OperationsTestSuite))
}

// Microsoft.Chaos/operations
func (testsuite *OperationsTestSuite) TestOperation() {
var err error
// From step Operations_ListAll
operationsClient, err := armchaos.NewOperationStatusesClient(testsuite.subscriptionId, testsuite.cred, nil)
testsuite.Require().NoError(err)
_, err = operationsClient.Get(testsuite.ctx, testsuite.location, testsuite.subscriptionId, nil)
testsuite.Require().NoError(err)
}

```

##### At last, you can run test via command `go test -run TestOperationsTestSuite`

1. Set the test mode to "live" using:
`$ENV:AZURE_RECORD_MODE="live"`
2. Once tests pass, switch to "playback" mode and ensure all tests pass in both modes.
3. Push the final assets with `test-proxy push --assets-json-path assets.json`.

### Scrubbing Secrets

Recording files live in the assets repository (`github.com/Azure/azure-sdk-assets`) and must not contain secrets. We use sanitizers with regular expression replacements to prevent recording secrets. The test proxy has many built-in sanitizers enabled by default. However, you may need to add your own by calling functions from the `recording` package. These functions generally take three parameters: the test instance (`t *testing.T`), the value to be removed (ie. an account name or key), and the value to use in replacement.
Expand Down