@@ -2,19 +2,28 @@ package acctest_test
22
33import (
44 "encoding/json"
5+ "errors"
56 "fmt"
7+ "go/ast"
8+ "go/parser"
9+ "go/token"
610 "io/fs"
711 "net/http"
12+ "os"
813 "path/filepath"
14+ "sort"
915 "strings"
1016 "testing"
1117
18+ "github.com/scaleway/terraform-provider-scaleway/v2/internal/acctest"
1219 "github.com/scaleway/terraform-provider-scaleway/v2/internal/services/mnq"
1320 "github.com/stretchr/testify/assert"
1421 "github.com/stretchr/testify/require"
1522 "gopkg.in/dnaeon/go-vcr.v3/cassette"
1623)
1724
25+ const servicesDir = "../services"
26+
1827func exceptionsCassettesCases () map [string ]struct {} {
1928 return map [string ]struct {}{
2029 "../services/mnq/testdata/sns-topic-basic.cassette.yaml" : {},
@@ -35,16 +44,17 @@ func exceptionsCassettesCases() map[string]struct{} {
3544}
3645
3746// getTestFiles returns a map of cassettes files
38- func getTestFiles () (map [string ]struct {}, error ) {
47+ func getTestFiles (includeExceptions bool ) (map [string ]struct {}, error ) {
3948 filesMap := make (map [string ]struct {})
4049 exceptions := exceptionsCassettesCases ()
4150
42- err := filepath .WalkDir ("../services" , func (path string , _ fs.DirEntry , _ error ) error {
51+ err := filepath .WalkDir (servicesDir , func (path string , _ fs.DirEntry , _ error ) error {
4352 isCassette := strings .Contains (path , "cassette" )
44- _ , isException := exceptions [path ]
45-
46- if isCassette && ! isException {
47- filesMap [fileNameWithoutExtSuffix (path )] = struct {}{}
53+ if isCassette {
54+ _ , isException := exceptions [path ]
55+ if ! isException || includeExceptions {
56+ filesMap [fileNameWithoutExtSuffix (path )] = struct {}{}
57+ }
4858 }
4959
5060 return nil
@@ -57,7 +67,7 @@ func getTestFiles() (map[string]struct{}, error) {
5767}
5868
5969func TestAccCassettes_Validator (t * testing.T ) {
60- paths , err := getTestFiles ()
70+ paths , err := getTestFiles (false )
6171 require .NoError (t , err )
6272
6373 for path := range paths {
@@ -129,3 +139,71 @@ func isTransientStateError(i *cassette.Interaction) bool {
129139
130140 return scwError .Type == "transient_state"
131141}
142+
143+ func listAccTestFunctions () (map [string ]string , error ) {
144+ fset := token .NewFileSet ()
145+ testFuncs := map [string ]string {}
146+
147+ filepath .Walk (servicesDir , func (path string , info os.FileInfo , err error ) error {
148+ if err != nil || info .IsDir () || ! strings .HasSuffix (info .Name (), "_test.go" ) {
149+ return nil
150+ }
151+
152+ pkgFolder := filepath .Base (filepath .Dir (path ))
153+
154+ node , err := parser .ParseFile (fset , path , nil , 0 )
155+ if err != nil {
156+ return err
157+ }
158+
159+ for _ , decl := range node .Decls {
160+ if fn , ok := decl .(* ast.FuncDecl ); ok {
161+ if strings .HasPrefix (fn .Name .Name , "Test" ) && fn .Name .Name != "TestMain" && fn .Recv == nil {
162+ expectedCassettePath := fmt .Sprintf ("%s/%s" , servicesDir , acctest .BuildCassetteName (fn .Name .Name , pkgFolder , ".cassette" ))
163+ testFuncs [expectedCassettePath ] = fmt .Sprintf ("%s/%s" , pkgFolder , fn .Name .Name )
164+ }
165+ }
166+ }
167+
168+ return nil
169+ })
170+
171+ return testFuncs , nil
172+ }
173+
174+ func TestAccCassettes_CheckOrphans (t * testing.T ) {
175+ // List actual cassettes
176+ actualCassettesPaths , err := getTestFiles (true )
177+ require .NoError (t , err )
178+
179+ // List actual acceptance tests functions and their expected cassettes' paths
180+ expectedCassettesPaths , err := listAccTestFunctions ()
181+ if err != nil {
182+ t .Fatalf ("Failed to list acceptance tests: %v" , err )
183+ }
184+
185+ // Look for tests with no matching cassette
186+ testWithNoCassetteErrs := []string (nil )
187+ for expectedCassettePath , testName := range expectedCassettesPaths {
188+ if _ , ok := actualCassettesPaths [expectedCassettePath ]; ! ok {
189+ testWithNoCassetteErrs = append (testWithNoCassetteErrs , fmt .Sprintf ("- %s has no matching cassette" , testName ))
190+ }
191+ }
192+ sort .Strings (testWithNoCassetteErrs )
193+ t .Log ("WARNING:\n " , strings .Join (testWithNoCassetteErrs , "\n " ))
194+
195+ // Look for cassettes with no matching test
196+ cassetteWithNoTestErrs := []error (nil )
197+ for actualCassettePath := range actualCassettesPaths {
198+ if _ , ok := expectedCassettesPaths [actualCassettePath ]; ! ok {
199+ cassetteWithNoTestErrs = append (cassetteWithNoTestErrs , fmt .Errorf ("+ cassette [%s] has no matching test" , actualCassettePath ))
200+ }
201+ }
202+
203+ if len (cassetteWithNoTestErrs ) > 0 {
204+ sort .Slice (cassetteWithNoTestErrs , func (i , j int ) bool {
205+ return cassetteWithNoTestErrs [i ].Error () < cassetteWithNoTestErrs [j ].Error ()
206+ })
207+ t .Error (errors .Join (cassetteWithNoTestErrs ... ))
208+ }
209+ }
0 commit comments