Skip to content

Commit c80d484

Browse files
committed
tests: Add a debug mode for acc tests.
1 parent 6664868 commit c80d484

13 files changed

+147
-9
lines changed

CONTRIBUTING.md

+111-3
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,24 @@ make unit NAME=TruncateLabel
153153
You can view the code coverage report with either:
154154
155155
```bash
156-
make view-cov-cli # on the CLI
156+
make view-cov-cli # on the CLI
157157
make view-cov-html # in the browser
158158
```
159159
160+
#### How to write a unit test
161+
162+
In the `testfixtures/` directory, there is a file for each function. This leverages a pattern known as [Table-Driven Testing](https://github.com/golang/go/wiki/TableDrivenTests), and composes all of the test cases in one place.
163+
164+
The `corefunc/` directory contains the code and tests for the Go library. The `corefuncprovider/` directory contains the code and tests for the Terraform provider. The relevant `_test.go` files in each directory leverage the same test fixture. This ensures that the Go library code and the Terraform provider which implements the Go library function both pass the test cases.
165+
166+
If we leverage a third-party package for functionality, there will not be a test in the `corefunc/` directory, but the Terraform provider implementation will have a test in the `corefuncprovider/` directory.
167+
168+
* A unit test function lives in the `corefunc/` directory, and begins with the word `Test`.
169+
* [Tutorial: Add a test](https://go.dev/doc/tutorial/add-a-test)
170+
* [Documentation: Coverage profiling](https://go.dev/testing/coverage/)
171+
* [Documentation: Testing flags](https://pkg.go.dev/cmd/go#hdr-Testing_flags)
172+
* [Tutorial: Code coverage for Go integration tests](https://go.dev/blog/integration-test-coverage)
173+
160174
### Terraform provider acceptance tests (and code coverage)
161175
162176
This will run Acceptance tests. Acceptance tests run the code through Terraform and test the Terraform communication pathway.
@@ -167,15 +181,39 @@ make acc
167181
168182
# Run one acceptance test
169183
make acc NAME=TruncateLabel
184+
185+
# Run all acceptance tests with debug-level output
186+
make acc DEBUG=true
187+
188+
# Run one acceptance test with debug-level output
189+
make acc NAME=TruncateLabel DEBUG=true
170190
```
171191
172192
You can view the code coverage report with either:
173193
174194
```bash
175-
make view-cov-cli # on the CLI
195+
make view-cov-cli # on the CLI
176196
make view-cov-html # in the browser
177197
```
178198
199+
#### How to write an acceptance test
200+
201+
In the `testfixtures/` directory, there is a file for each function. This leverages a pattern known as [Table-Driven Testing](https://github.com/golang/go/wiki/TableDrivenTests), and composes all of the test cases in one place.
202+
203+
The `corefunc/` directory contains the code and tests for the Go library. The `corefuncprovider/` directory contains the code and tests for the Terraform provider. The relevant `_test.go` files in each directory leverage the same test fixture. This ensures that the Go library code and the Terraform provider which implements the Go library function both pass the test cases.
204+
205+
If we leverage a third-party package for functionality, there will not be a test in the `corefunc/` directory, but the Terraform provider implementation will have a test in the `corefuncprovider/` directory.
206+
207+
To help keep things easy to understand, the acceptance tests use Go's [`text/template`](https://pkg.go.dev/text/template) package to generate the Terraform code that is used for the acceptance test. The documentation for the [`templatefile()`](https://developer.hashicorp.com/terraform/language/functions/templatefile) function says that templates for use with Terraform should use the `*.tftpl` extension:
208+
209+
> `*.tftpl` is the recommended naming pattern to use for your template files. Terraform will not prevent you from using other names, but following this convention will help your editor understand the content and likely provide better editing experience as a result.
210+
211+
* An acceptance test function lives in the `corefuncprovider/` directory, and begins with the word `TestAcc`.
212+
* [Tutorial: Add a test](https://go.dev/doc/tutorial/add-a-test)
213+
* [Documentation: Coverage profiling](https://go.dev/testing/coverage/)
214+
* [Documentation: Testing flags](https://pkg.go.dev/cmd/go#hdr-Testing_flags)
215+
* [Tutorial: Code coverage for Go integration tests](https://go.dev/blog/integration-test-coverage)
216+
179217
### Documentation Examples as tests (and code coverage)
180218

181219
This will run the Documentation Examples as tests. This ensures that the examples we put in front of users actually work.
@@ -192,15 +230,43 @@ make view-cov-cli # on the CLI
192230
make view-cov-html # in the browser
193231
```
194232

233+
#### How to write a documentation example
234+
235+
The `corefunc/` directory contains the code and tests for the Go library. If we leverage a third-party package for functionality, there will not be a test in the `corefunc/` directory.
236+
237+
* An example test function lives in the `corefunc/` directory, and begins with the word `Example`.
238+
* [Tutorial: Documentation examples](https://go.dev/blog/examples)
239+
240+
### Test the provider schema as tests
241+
242+
This will use `tfschema` (reads the provider schema) and `bats` (CLI testing framework) to verify that the provider exposes the correct schema. This test requires compiling and installing the provoider (which `go test` doesn't require.)
243+
244+
```bash
245+
# Run all BATS tests
246+
make bats
247+
```
248+
249+
#### How to write a BATS test
250+
195251
### Fuzzer
196252
253+
Fuzzing is a type of automated testing which continuously manipulates inputs to a program to find bugs. Go fuzzing uses coverage guidance to intelligently walk through the code being fuzzed to find and report failures to the user. Since it can reach edge cases which humans often miss, fuzz testing can be particularly valuable for finding security exploits and vulnerabilities.
254+
197255
This will run the fuzzer for 10 minutes. [Learn more about fuzzing](https://go.dev/doc/tutorial/fuzz).
198256
199257
```bash
200258
# May only run one fuzz test at a time
201259
make fuzz NAME=TruncateLabel
202260
```
203261
262+
#### How to write a fuzz test
263+
264+
The `corefunc/` directory contains the code and tests for the Go library. If we leverage a third-party package for functionality, there will not be a test in the `corefunc/` directory.
265+
266+
* A fuzzer test function lives in the `corefunc/` directory, and begins with the word `Fuzz`.
267+
* [Documentation: Go fuzzing](https://go.dev/security/fuzz/)
268+
* [Tutorial: Getting started with fuzzing](https://go.dev/doc/tutorial/fuzz)
269+
204270
## Benchmarks
205271
206272
Benchmarks test the performance of a package.
@@ -270,7 +336,16 @@ The way that these are written, `TruncateLabel` is the test. `balanced{number}`
270336

271337
For the middle part (`balanced{number}`), the number represents the number of characters I truncated the label to. I know from the implementation that different truncation lengths can trigger different code paths, and that anything under `6` results in a near-immediate return with no calculation necessary. We also know that the longer lengths similarly have less truncation logic to perform.
272338

273-
But the middle tests from ~10–80 are most likely to execute _all_ of the code in the function, which makes it the most intersting.
339+
But the middle tests from ~10–80 are most likely to execute _all_ of the code in the function, which makes it the most interesting.
340+
341+
#### How to write a benchmark suite
342+
343+
The `corefunc/` directory contains the code and tests for the Go library. If we leverage a third-party package for functionality, there will not be a test in the `corefunc/` directory.
344+
345+
* A fuzzer test function lives in the `corefunc/` directory, and begins with the word `Benchmark`.
346+
* There is one `Benchmark` test which runs the tests serially. There is a second `Benchmark` test which runs the tests in parallel. This latter function has `Parallel` as the suffix of its name.
347+
* [API Reference: Benchmarks](https://pkg.go.dev/testing@go1.21.1#hdr-Benchmarks)
348+
* [API Reference: Benchstat](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat)
274349

275350
### Exploring profiler data
276351

@@ -298,6 +373,19 @@ When you're done, clean-up.
298373
make clean-bench
299374
```
300375
376+
#### How to understand profiling and tracing data
377+
378+
* [Tutorial: Profiling Go Programs](https://go.dev/blog/pprof)
379+
* [Documentation: Diagnostics](https://go.dev/doc/diagnostics)
380+
* [Go: The Complete Guide to Profiling Your Code](https://hackernoon.com/go-the-complete-guide-to-profiling-your-code-h51r3waz)
381+
382+
## Profile-guided optimization
383+
384+
Profile-guided optimization (PGO), also known as feedback-directed optimization (FDO), is a compiler optimization technique that feeds information (a profile) from representative runs of the application back into to the compiler for the next build of the application, which uses that information to make more informed optimization decisions. For example, the compiler may decide to more aggressively inline functions which the profile indicates are called frequently.
385+
386+
* [Documentation: Profile-guided optimization](https://go.dev/doc/pgo)
387+
* [Tutorial: Profile-guided optimization in Go 1.21](https://go.dev/blog/pgo)
388+
301389
## Scanning for vulnerabilities
302390
303391
```bash
@@ -314,6 +402,16 @@ Generate the Terraform Registry-facing documentation.
314402
make docs-provider
315403
```
316404
405+
#### Terraform Provider Documentation
406+
407+
These are the patterns we follow for generating Terraform documentation. _Every_ resource/data source in the provider has at least one example. With a resource-specific template, we can implement multiple examples.
408+
409+
See `examples/data-sources/corefunc_env_ensure/` as an example of a custom template with multiple examples.
410+
411+
* [tfplugindocs: Conventional Paths](https://github.com/hashicorp/terraform-plugin-docs?tab=readme-ov-file#conventional-paths)
412+
* [Terraform: Provider Documentation](https://developer.hashicorp.com/terraform/registry/providers/docs)
413+
* [Terraform: Implement documentation generation](https://developer.hashicorp.com/terraform/tutorials/providers-plugin-framework/providers-plugin-framework-documentation-generation)
414+
317415
### Go CLI Documentation
318416
319417
You can get the package documentation on the CLI using the `go doc` command.
@@ -322,12 +420,22 @@ You can get the package documentation on the CLI using the `go doc` command.
322420
make docs-cli
323421
```
324422
423+
#### How to write Go documentation comments and examples
424+
425+
* [Documentation: Go Doc Comments](https://tip.golang.org/doc/comment)
426+
* [Tutorial: Testable Examples in Go](https://go.dev/blog/examples)
427+
325428
### Go Documentation Server
326429
327430
```bash
328431
make docs-serve
329432
```
330433
434+
#### How to write Go documentation comments and examples
435+
436+
* [Documentation: Go Doc Comments](https://tip.golang.org/doc/comment)
437+
* [Tutorial: Testable Examples in Go](https://go.dev/blog/examples)
438+
331439
## Running the debugger
332440
333441
> [!IMPORTANT]

Makefile

+11-1
Original file line numberDiff line numberDiff line change
@@ -269,11 +269,16 @@ bats: build
269269
bats bats/*
270270

271271
.PHONY: acc
272-
## acc: [test] Runs Terraform provider acceptance tests. Set NAME= (without 'Test') to run a specific test by name
272+
## acc: [test] Runs Terraform provider acceptance tests. Set NAME= (without 'TestAcc') to run a specific test by name
273273
acc:
274274
@ $(ECHO) " "
275275
@ $(ECHO) "\033[1;33m=====> Running acceptance tests...\033[0m"
276+
277+
ifeq ($(DEBUG), true)
278+
PROVIDER_DEBUG=1 TF_ACC=1 go test -run=TestAcc$(NAME) -count=1 -parallel=$(shell nproc) -timeout 30m -coverpkg=./corefuncprovider/... -coverprofile=__coverage.out -v ./corefuncprovider/...
279+
else
276280
TF_ACC=1 gotestsum --format testname -- -run=TestAcc$(NAME) -count=1 -parallel=$(shell nproc) -timeout 30m -coverpkg=./corefuncprovider/... -coverprofile=__coverage.out -v ./corefuncprovider/...
281+
endif
277282

278283
.PHONY: unit
279284
## unit: [test] Runs unit tests. Set NAME= (without 'Test') to run a specific test by name
@@ -306,6 +311,11 @@ quickbench:
306311
bench:
307312
$(GO) test -bench=. -count=6 -timeout 60m -benchmem -cpuprofile=__cpu.out -memprofile=__mem.out -trace=__trace.out ./corefunc | tee __bench-$(shell date --utc "+%Y%m%dT%H%M%SZ").out
308313

314+
.PHONY: pgo
315+
## pgo: [test] Runs the benchmarks with enough data for use with Profile-Guided Optimization.
316+
pgo:
317+
TF_ACC=1 go test -run=^TestAcc -count=6 -cpuprofile=default.pgo -parallel=$(shell nproc) -timeout 60m ./corefuncprovider/...
318+
309319
.PHONY: view-cov-cli
310320
## view-cov-cli: [test] After running test or unittest, this will view the coverage report on the CLI.
311321
view-cov-cli:

corefuncprovider/env_ensure_data_source_fixture.tftpl

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ data "corefunc_env_ensure" "env" {
44
pattern = "{{ . }}"
55
{{- end }}
66
}
7+
#=> {{ .ExpectedErr }}

corefuncprovider/env_ensure_data_source_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ func TestAccEnvEnsureDataSource(t *testing.T) {
5151
log.Fatalln(err)
5252
}
5353

54-
// fmt.Fprintln(os.Stderr, buf.String())
54+
if os.Getenv("PROVIDER_DEBUG") != "" {
55+
fmt.Fprintln(os.Stderr, buf.String())
56+
}
5557

5658
// We expect the error to be nil.
5759
if tc.ExpectedErr == nil {
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
data "corefunc_str_camel" "camel" {
22
string = "{{ .Input }}"
33
}
4+
#=> {{ .Expected }}

corefuncprovider/str_camel_data_source_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bytes"
1919
"fmt"
2020
"log"
21+
"os"
2122
"strings"
2223
"testing"
2324
"text/template"
@@ -47,7 +48,9 @@ func TestAccStrCamelDataSource(t *testing.T) {
4748
log.Fatalln(err)
4849
}
4950

50-
// fmt.Fprintln(os.Stderr, buf.String())
51+
if os.Getenv("PROVIDER_DEBUG") != "" {
52+
fmt.Fprintln(os.Stderr, buf.String())
53+
}
5154

5255
resource.Test(t, resource.TestCase{
5356
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,

corefuncprovider/str_pascal_data_source_fixture.tftpl

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ data "corefunc_str_pascal" "pascal" {
44
acronym_caps = {{ printf "%v" . }}
55
{{- end }}
66
}
7+
#=> {{ .Expected }}

corefuncprovider/str_pascal_data_source_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bytes"
1919
"fmt"
2020
"log"
21+
"os"
2122
"strings"
2223
"testing"
2324
"text/template"
@@ -47,7 +48,9 @@ func TestAccStrPascalDataSource(t *testing.T) {
4748
log.Fatalln(err)
4849
}
4950

50-
// fmt.Fprintln(os.Stderr, buf.String())
51+
if os.Getenv("PROVIDER_DEBUG") != "" {
52+
fmt.Fprintln(os.Stderr, buf.String())
53+
}
5154

5255
resource.Test(t, resource.TestCase{
5356
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
data "corefunc_str_snake" "snake" {
22
string = "{{ .Input }}"
33
}
4+
#=> {{ .Expected }}

corefuncprovider/str_snake_data_source_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bytes"
1919
"fmt"
2020
"log"
21+
"os"
2122
"strings"
2223
"testing"
2324
"text/template"
@@ -47,7 +48,9 @@ func TestAccStrSnakeDataSource(t *testing.T) {
4748
log.Fatalln(err)
4849
}
4950

50-
// fmt.Fprintln(os.Stderr, buf.String())
51+
if os.Getenv("PROVIDER_DEBUG") != "" {
52+
fmt.Fprintln(os.Stderr, buf.String())
53+
}
5154

5255
resource.Test(t, resource.TestCase{
5356
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,

corefuncprovider/truncate_label_data_source_fixture_default64.tftpl

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ data "corefunc_str_truncate_label" "truncated" {
22
prefix = "NW-ZZZ-CLOUD-TEST-APP-CLOUD-PROD-CRIT"
33
label = "K8S Pods Not Running Deployment Check"
44
}
5+
#=> NW-ZZZ-CLOUD-TEST-APP-CLOUD-PR…: K8S Pods Not Running Deploymen…

corefuncprovider/truncate_label_data_source_fixture_maxlength.tftpl

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ data "corefunc_str_truncate_label" "label" {
33
label = "{{ .Label }}"
44
max_length = {{ .MaxLength }}
55
}
6+
#=> {{ .Expected }}

corefuncprovider/truncate_label_data_source_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bytes"
1919
"fmt"
2020
"log"
21+
"os"
2122
"strings"
2223
"testing"
2324
"text/template"
@@ -80,7 +81,9 @@ func TestAccTruncateLabelDataSource(t *testing.T) {
8081
log.Fatalln(err)
8182
}
8283

83-
// fmt.Fprintln(os.Stderr, buf.String())
84+
if os.Getenv("PROVIDER_DEBUG") != "" {
85+
fmt.Fprintln(os.Stderr, buf.String())
86+
}
8487

8588
resource.Test(t, resource.TestCase{
8689
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,

0 commit comments

Comments
 (0)