Skip to content

Commit 969cfcd

Browse files
authored
Update developer_setup.md (Azure#23274)
1 parent e8defc7 commit 969cfcd

File tree

1 file changed

+38
-58
lines changed

1 file changed

+38
-58
lines changed

documentation/developer_setup.md

Lines changed: 38 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ use: "@autorest/[email protected]"
116116
For the `use` section, the value should always be the latest version of the `@autorest/go` package.
117117
The latest version can be found at the NPM [page][autorest_go] for `@autorest/go`.
118118

119-
For services that authenticate with Azure Active Directory, you **must** include the `security-scopes` parameter with the appropriate values (example below).
119+
For services that authenticate with Microsoft Entra ID, you **must** include the `security-scopes` parameter with the appropriate values (example below).
120120

121121
```yaml
122122
security-scopes: "https://vault.azure.net/.default"
@@ -160,30 +160,45 @@ import (
160160
161161
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
162162
"github.com/Azure/azure-sdk-for-go/sdk/internal/recording"
163+
"github.com/Azure/azure-sdk-for-go/sdk/internal/test/credential"
163164
)
164165
165-
func createClientForRecording(t *testing.T, tableName string, serviceURL string, cred SharedKeyCredential) (*Client, error) {
166+
func createClientForRecording(t *testing.T, tableName string, serviceURL string) (*Client, error) {
166167
transport, err := recording.NewRecordingHTTPClient(t)
167168
require.NoError(t, err)
168169
169170
options := &ClientOptions{
170171
ClientOptions: azcore.ClientOptions{
171-
Transport: client,
172+
Transport: transport,
172173
},
173174
}
174175
175-
return NewClientWithSharedKey(runtime.JoinPaths(serviceURL, tableName), &cred, options)
176+
// credential.New returns a credential for Entra ID authentication. It works in CI
177+
// and local development, in all recording modes. To authenticate live tests on
178+
// your machine, sign in to the Azure CLI or Azure Developer CLI.
179+
cred, err := credential.New(nil)
180+
require.NoError(t, err)
181+
182+
return NewClient(runtime.JoinPaths(serviceURL, tableName), &cred, options)
183+
}
184+
185+
func startRecording(t *testing.T) {
186+
err := recording.Start(t, recordingDirectory, nil)
187+
require.NoError(t, err)
188+
t.Cleanup(func() {
189+
err := recording.Stop(t, nil)
190+
require.NoError(t, err)
191+
})
176192
}
177193
```
178194

179195
Including this in a file for test helper methods will ensure that before each test the developer simply has to add
180196

181197
```go
182198
func TestExample(t *testing.T) {
183-
err := recording.Start(t, "path/to/package", nil)
184-
defer recording.Stop(t, nil)
199+
startRecording(t)
185200
186-
client, err := createClientForRecording(t, "myTableName", "myServiceUrl", myCredential)
201+
client, err := createClientForRecording(t, "myTableName", "myServiceUrl")
187202
require.NoError(t, err)
188203
...
189204
<test code>
@@ -204,14 +219,10 @@ import (
204219
"os"
205220
206221
"github.com/stretchr/testify/require"
207-
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
208222
"github.com/Azure/azure-sdk-for-go/sdk/internal/recording"
209223
)
210224
211-
const (
212-
accountName := os.GetEnv("TABLES_PRIMARY_ACCOUNT_NAME")
213-
accountKey := os.GetEnv("TABLES_PRIMARY_ACCOUNT_KEY")
214-
)
225+
const accountName = os.GetEnv("TABLES_PRIMARY_ACCOUNT_NAME")
215226
216227
// Test creating a single table
217228
func TestCreateTable(t *testing.T) {
@@ -222,11 +233,8 @@ func TestCreateTable(t *testing.T) {
222233
require.NoError(t, err)
223234
}()
224235
225-
serviceUrl := fmt.Sprintf("https://%v.table.core.windows.net", accountName)
226-
cred, err := azidentity.NewDefaultAzureCredential(nil)
227-
require.NoError(t, err)
228-
229-
client, err := createClientForRecording(t, "tableName", serviceUrl, cred)
236+
serviceURL := fmt.Sprintf("https://%v.table.core.windows.net", accountName)
237+
client, err := createClientForRecording(t, "tableName", serviceURL)
230238
require.NoError(t, err)
231239
232240
resp, err := client.Create()
@@ -239,7 +247,7 @@ func TestCreateTable(t *testing.T) {
239247
}
240248
```
241249

242-
The first part of the test above is for getting the secrets needed for authentication from your environment, best practice is to store your test secrets in environment variables.
250+
The first part of the test above is for getting resource configuration from your environment.
243251

244252
The rest of the snippet shows a test that creates a single table and requirements (similar to assertions in other languages) that the response from the service has the same table name as the supplied parameter. Every test in Go has to have exactly one parameter, the `t *testing.T` object, and it must begin with `Test`. After making a service call or creating an object you can make assertions on that object by using the external `testify/require` library. In the example above, we "require" that the error returned is `nil`, meaning the call was successful and then we require that the response object has the same table name as supplied.
245253

@@ -249,7 +257,7 @@ If you set the environment variable `AZURE_RECORD_MODE` to "record" and run `go
249257

250258
### Scrubbing Secrets
251259

252-
The recording files eventually live in the main repository (`github.com/Azure/azure-sdk-for-go`) and we need to make sure that all of these recordings are free from secrets. To do this we use Sanitizers with regular expressions for replacements. All of the available sanitizers are available as methods from the `recording` package. The recording methods 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.
260+
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.
253261

254262
| Sanitizer Type | Method |
255263
| -------------- | ------ |
@@ -263,7 +271,9 @@ The recording files eventually live in the main repository (`github.com/Azure/az
263271
| URI Sanitizer | `AddURISanitizer(value, regex string, options *RecordingOptions)` |
264272
| URI Subscription ID Sanitizer | `AddURISubscriptionIDSanitizer(value string, options *RecordingOptions)` |
265273

266-
To add a scrubber that replaces the URL of your account use the `TestMain()` function to set sanitizers before you begin running tests.
274+
You may also need to remove a built-in sanitizer overwriting a non-secret value needed by a test. To do this, call `RemoveRegisteredSanitizers` with a list of sanitizer IDs such as "AZSDK3430". See the [test proxy documentation](https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/SanitizerDictionary.cs) for a complete list of all the built-in sanitizers and their IDs.
275+
276+
Configure sanitizers before running tests:
267277

268278
```go
269279
const recordingDirectory = "<path to service directory with assets.json file>/testdata"
@@ -290,15 +300,18 @@ func run(m *testing.M) int {
290300
}()
291301
}
292302
293-
// Set sanitizers in record mode
294-
if recording.GetRecordMode() == "record" {
295-
vaultUrl := os.Getenv("AZURE_KEYVAULT_URL")
296-
err = recording.AddURISanitizer(fakeKvURL, vaultUrl, nil)
303+
// sanitizers run in playback and recording modes
304+
if recording.GetRecordMode() != recording.LiveMode {
305+
// configure sanitizers here. For example:
306+
err := recording.RemoveRegisteredSanitizers([]string{
307+
"AZSDK3430", // body key $..id
308+
}, nil)
297309
if err != nil {
298310
panic(err)
299311
}
300312
}
301313
314+
// run test cases
302315
return m.Run()
303316
}
304317
```
@@ -319,47 +332,14 @@ func TestClient(t *testing.T) {
319332
}
320333
```
321334

322-
### Using `azidentity` Credentials In Tests
323-
324-
The credentials in `azidentity` are not automatically configured to run in playback mode. To make sure your tests run in playback mode even with `azidentity` credentials the best practice is to use a simple `FakeCredential` type that inserts a fake Authorization header to mock a credential. An example for swapping the `DefaultAzureCredential` using a helper function is shown below in the context of `aztables`
325-
326-
```go
327-
type FakeCredential struct {}
328-
329-
func NewFakeCredential() *FakeCredential {
330-
return &FakeCredential{}
331-
}
332-
333-
func (f *FakeCredential) GetToken(ctx context.Context, options policy.TokenRequestOptions) (*azcore.AccessToken, error) {
334-
return &azcore.AccessToken{Token: "***", ExpiresOn: time.Now().Add(time.Hour)}, nil
335-
}
336-
337-
func getAADCredential() (azcore.TokenCredential, error) {
338-
if recording.GetRecordMode() == recording.PlaybackMode {
339-
return NewFakeCredential(), nil
340-
}
341-
return azidentity.NewDefaultCredential(nil)
342-
}
343-
344-
func TestClientWithAAD(t *testing.T) {
345-
accountName := recording.GetEnvVariable(t, "TABLES_PRIMARY_ACCOUNT_NAME", "fakeAccountName")
346-
cred, err := getAADCredential()
347-
require.NoError(t, err)
348-
...
349-
...run tests...
350-
}
351-
```
352-
353-
The `FakeCredential` show here implements the `azcore.TokenCredential` interface and can be used anywhere the `azcore.TokenCredential` is used.
354-
355335
### Live Test Resource Management
356336

357337
If you have live tests that require Azure resources, you'll need to create a test resources config file for deployment during CI.
358338
Please see the [test resource][test_resources] documentation for more info.
359339

360340
### Committing/Updating Recordings
361341

362-
The `assets.json` file located in your module directory is used by the Test Framework to figure out how to retrieve session records from the assets repo. In order to push new session records, you need to invoke:
342+
Always inspect recordings for secrets before pushing them. The `assets.json` file located in your module directory is used by the Test Framework to figure out how to retrieve session records from the assets repo. In order to push new session records, you need to invoke:
363343

364344
```PowerShell
365345
test-proxy push -a <path-to-assets.json>

0 commit comments

Comments
 (0)