Skip to content

Commit 6e9b765

Browse files
[typespec-go] Add typespec-go-add-spector-test skill (Azure#5057)
## Summary Adds a new Copilot skill, `typespec-go-add-spector-test`, that guides contributors through adding a [Spector](https://github.com/microsoft/typespec) mock API test for the `@azure-tools/typespec-go` emitter. The skill was migrated from the `autorest.go` repo and updated to reflect the current typespec-go development process, including the standardized opt-in spec selection config introduced in Azure#5023. ## What the skill covers Given a Spector case link (`http-specs` or `azure-http-specs`), it walks through: 1. **Identify the spec** — resolve the spec type and path. 2. **Opt into generation** — add a one-line entry to `spector.config.http.yaml` / `spector.config.azure.yaml` (with the required `options.module`), instead of editing `.scripts/tspcompile.js`. 3. **Generate the client** — regenerate with `pnpm tspcompile --filter=<module>`. 4. **Read the mock API and generated surface** — inspect `mockapi.ts` and the generated client methods. 5. **Write Go client tests** — one `*_client_test.go` per generated `zz_*_client.go`, using `require` against the `http://localhost:3000` endpoint. 6. **Validate against Spector** — `pnpm spector --start` / `go test` / `pnpm spector --stop`, plus `pnpm test:go:e2e` and `pnpm lint:go`. ## Notes - Scoped purely to adding Spector tests — no scenario/unit test guidance. - Aligned with `packages/typespec-go/docs/development.md` (uses `pnpm build:deps`, `pnpm lint:go`).
1 parent 843ae24 commit 6e9b765

2 files changed

Lines changed: 224 additions & 0 deletions

File tree

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
---
2+
name: typespec-go-add-spector-test
3+
description: >
4+
Adds a Spector mock API test for the typespec-go emitter. Use when given a Spector
5+
case link (http-specs or azure-http-specs) to opt the spec into generation, write
6+
Go client tests, and validate them against the Spector mock server.
7+
allowed-tools: shell
8+
---
9+
10+
# Add a Spector Test for typespec-go
11+
12+
## Inputs
13+
14+
You will receive one or more Spector cases. Each case can be expressed as any of:
15+
16+
- A link under one of these roots:
17+
- `https://github.com/microsoft/typespec/tree/main/packages/http-specs/specs/...`
18+
- `https://github.com/Azure/typespec-azure/tree/main/packages/azure-http-specs/specs/...`
19+
- A spec path relative to `specs/` (for example, `type/model/empty`), optionally with the
20+
spec type (`http-specs` or `azure-http-specs`) when it is ambiguous.
21+
- A pull request link (in `microsoft/typespec` or `Azure/typespec-azure`) that adds or
22+
changes specs. Inspect the PR's changed files under `packages/http-specs/specs/` or
23+
`packages/azure-http-specs/specs/` and treat each affected spec directory as a case.
24+
25+
When multiple cases are provided, repeat the workflow below for each one.
26+
27+
## Output
28+
29+
- An opt-in entry in `packages/typespec-go/spector.config.http.yaml` or
30+
`packages/typespec-go/spector.config.azure.yaml`.
31+
- Generated Go client code under `packages/typespec-go/test/http-specs/` or
32+
`packages/typespec-go/test/azure-http-specs/`.
33+
- Hand-written `*_client_test.go` files that exercise the generated client against the
34+
Spector mock API server. Create one test file per generated `zz_*_client.go` file.
35+
36+
## Workflow
37+
38+
1. Ensure dependencies are installed and `typespec-go` is built.
39+
2. Identify the Spector case, spec type, and spec path.
40+
3. Add the spec to the appropriate opt-in Spector config.
41+
4. Regenerate the selected Go client with `pnpm tspcompile --filter=<module>`.
42+
5. Read `mockapi.ts` and the generated client method signatures.
43+
6. Write one `*_client_test.go` file per generated client.
44+
7. Start Spector, run the generated module's Go tests, and stop Spector.
45+
46+
## Prerequisites
47+
48+
Run commands from the repository root unless a step specifies otherwise:
49+
50+
```bash
51+
pnpm install
52+
cd packages/typespec-go
53+
pnpm build:deps
54+
```
55+
56+
`pnpm build:deps` builds `typespec-go` and its workspace dependencies through Turbo. Do
57+
not substitute `pnpm build`, which assumes those dependencies are already built.
58+
59+
## 1. Identify the Spec
60+
61+
Determine the spec type from the link:
62+
63+
- `microsoft/typespec/.../packages/http-specs/specs/<path>` uses
64+
`spector.config.http.yaml` and generates to `test/http-specs/`.
65+
- `Azure/typespec-azure/.../packages/azure-http-specs/specs/<path>` uses
66+
`spector.config.azure.yaml` and generates to `test/azure-http-specs/`.
67+
68+
The spec path is the portion after `specs/`. For example,
69+
`type/model/empty` is the path for
70+
`.../packages/http-specs/specs/type/model/empty`.
71+
72+
Search the matching `spector.config.*.yaml` file before adding an entry. If it is
73+
already enabled, retain its existing configuration and proceed to the test work.
74+
75+
## 2. Opt Into Generation
76+
77+
Spector selection is opt-in. Do not add or modify hard-coded external Spector groups in
78+
`.scripts/tspcompile.js`; it loads and resolves the two YAML config files.
79+
80+
Add an enabled entry under `specs`, providing a unique Go module name in `options.module`.
81+
Use lowercase names without hyphens and retain the conventional `group` suffix:
82+
83+
```yaml
84+
specs:
85+
"type/model/empty": { options: { module: emptygroup, single-client: true } }
86+
```
87+
88+
For Azure specs that require a particular `.tsp` file, include it in the key:
89+
90+
```yaml
91+
specs:
92+
"azure/client-generator-core/api-version/header/client.tsp":
93+
{ options: { module: apiversionheadergroup } }
94+
```
95+
96+
Emitter options belong in the same `options` object and are passed as
97+
`@azure-tools/typespec-go` emitter options. `module` is required. A single spec may
98+
produce multiple test modules by supplying a list of option objects:
99+
100+
```yaml
101+
specs:
102+
"azure/versioning/previewVersion":
103+
- options: { module: previewversiongroup, api-version: "2024-12-01-preview" }
104+
- options: { module: previewversiongroupspecificversion, api-version: "2024-06-01" }
105+
```
106+
107+
Do not override the generation-owned `module`, `emitter-output-dir`, or `file-prefix`
108+
options; set only this config's required `module` value. Per-test emitter defaults such as
109+
`generate-fakes`, `inject-spans`, `head-as-boolean`, and `fix-const-stuttering` may be
110+
overridden when the test needs it.
111+
112+
When a known unsupported spec should be explicitly tracked but not generated, add it as
113+
`false` with a nearby comment linking the issue:
114+
115+
```yaml
116+
# requires union support: https://github.com/Azure/autorest.go/issues/1234
117+
"type/union": false
118+
```
119+
120+
## 3. Generate the Client
121+
122+
From `packages/typespec-go`, regenerate only the new module:
123+
124+
```bash
125+
pnpm tspcompile --filter=emptygroup
126+
```
127+
128+
`--filter` is a regular expression matched against module names. The generator derives
129+
the output path from the spec path and module name. Confirm the resulting module contains
130+
the expected `zz_*_client.go` files. Do not edit generated `zz_*` files.
131+
132+
If the generated module requires dependencies that are absent from its `go.sum`, run:
133+
134+
```bash
135+
cd test/<http-specs|azure-http-specs>/<spec-parent-path>/<module>
136+
go mod tidy
137+
```
138+
139+
Generated Go fixtures are ignored by git. Commit the opt-in config and hand-written test
140+
files, not generated output.
141+
142+
## 4. Read the Mock API and Generated Surface
143+
144+
Read the upstream `mockapi.ts` for the selected spec:
145+
146+
- HTTP specs: `packages/typespec-go/node_modules/@typespec/http-specs/specs/<spec-path>/mockapi.ts`
147+
- Azure HTTP specs: `packages/typespec-go/node_modules/@azure-tools/azure-http-specs/specs/<spec-path>/mockapi.ts`
148+
149+
For each scenario, match the expected URI, method, request body, headers, query and path
150+
parameters, plus response status, headers, and body. Then inspect the generated
151+
`zz_*_client.go` file for the exact client constructor, method names, and parameter types.
152+
153+
## 5. Write Go Client Tests
154+
155+
Create one hand-written `<name>_client_test.go` for every generated
156+
`zz_<name>_client.go`. The test package is `<module>_test`; use `require`, not `assert`.
157+
158+
```go
159+
package emptygroup_test
160+
161+
import (
162+
"context"
163+
"emptygroup"
164+
"testing"
165+
166+
"github.com/stretchr/testify/require"
167+
)
168+
169+
func TestEmptyClientGetEmpty(t *testing.T) {
170+
client, err := emptygroup.NewEmptyClientWithNoCredential("http://localhost:3000", nil)
171+
require.NoError(t, err)
172+
173+
resp, err := client.GetEmpty(context.Background(), nil)
174+
require.NoError(t, err)
175+
require.Zero(t, resp)
176+
}
177+
```
178+
179+
Use `http://localhost:3000` for every Spector client. For sub-clients, construct the
180+
root client and access the sub-client from it. Common assertion patterns:
181+
182+
- 204 responses: `require.Zero(t, resp)`.
183+
- Response bodies: `require.EqualValues(t, expected, resp.<Field>)`.
184+
- Pointer fields: `to.Ptr(value)` from `github.com/Azure/azure-sdk-for-go/sdk/azcore/to`.
185+
- Time values: `require.WithinDuration(t, expected, actual, 0)`.
186+
- Pagers: iterate with `pager.More()` and `pager.NextPage(context.Background())`.
187+
- LROs: call `poller.PollUntilDone(context.Background(), nil)`.
188+
189+
## 6. Validate Against Spector
190+
191+
From `packages/typespec-go`, start the mock server:
192+
193+
```bash
194+
pnpm spector --start
195+
```
196+
197+
Then run the selected module's tests:
198+
199+
```bash
200+
cd test/<http-specs|azure-http-specs>/<spec-parent-path>/<module>
201+
go test -v ./...
202+
```
203+
204+
Stop the server when validation completes:
205+
206+
```bash
207+
pnpm spector --stop
208+
```
209+
210+
For full generated Go test coverage, use `pnpm test:go:e2e`. If a focused test fails,
211+
verify the server is running, the endpoint is `http://localhost:3000`, the test matches
212+
`mockapi.ts`, and the generated method signature was used correctly.
213+
214+
Run `pnpm lint:go` after regeneration when `golangci-lint` and `shadow` are available on
215+
`PATH`. This lint command covers all generated Go modules, including the new Spector test.
216+
217+
## Notes
218+
219+
- Each generated test group is an independent Go module.
220+
- Hand-written Go tests are the source of truth; regeneration can replace generated files.
221+
- Keep config entries organized with the existing logical/alphabetical layout.
222+
- The config format is standardized across emitters. Keep selection and per-spec options
223+
together in the relevant `spector.config.*.yaml` file.

cspell.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ words:
110110
- seti
111111
- stac
112112
- strconv
113+
- stretchr
113114
- tcgc
114115
- tsmv
115116
- userrp

0 commit comments

Comments
 (0)