github.com/terraform-modules-krish/terratest@v0.29.0/modules/terraform/count.go (about) 1 package terraform 2 3 import ( 4 "errors" 5 "regexp" 6 "strconv" 7 8 "github.com/terraform-modules-krish/terratest/modules/testing" 9 "github.com/stretchr/testify/require" 10 ) 11 12 // ResourceCount represents counts of resources affected by terraform apply/plan/destroy command. 13 type ResourceCount struct { 14 Add int 15 Change int 16 Destroy int 17 } 18 19 // Regular expressions for terraform commands stdout pattern matching. 20 const ( 21 applyRegexp = `Apply complete! Resources: (\d+) added, (\d+) changed, (\d+) destroyed\.` 22 destroyRegexp = `Destroy complete! Resources: (\d+) destroyed\.` 23 planWithChangesRegexp = `(\033\[1m)?Plan:(\033\[0m)? (\d+) to add, (\d+) to change, (\d+) to destroy\.` 24 planWithNoChangesRegexp = `No changes\. Infrastructure is up-to-date\.` 25 ) 26 27 const getResourceCountErrMessage = "Can't parse Terraform output" 28 29 // GetResourceCount parses stdout/stderr of apply/plan/destroy commands and returns number of affected resources. 30 // This will fail the test if given stdout/stderr isn't a valid output of apply/plan/destroy. 31 func GetResourceCount(t testing.TestingT, cmdout string) *ResourceCount { 32 cnt, err := GetResourceCountE(t, cmdout) 33 require.NoError(t, err) 34 return cnt 35 } 36 37 // GetResourceCountE parses stdout/stderr of apply/plan/destroy commands and returns number of affected resources. 38 func GetResourceCountE(t testing.TestingT, cmdout string) (*ResourceCount, error) { 39 cnt := ResourceCount{} 40 41 terraformCommandPatterns := []struct { 42 regexpStr string 43 addPosition int 44 changePosition int 45 destroyPosition int 46 }{ 47 {applyRegexp, 1, 2, 3}, 48 {destroyRegexp, -1, -1, 1}, 49 {planWithChangesRegexp, 3, 4, 5}, 50 {planWithNoChangesRegexp, -1, -1, -1}, 51 } 52 53 for _, tc := range terraformCommandPatterns { 54 pattern, err := regexp.Compile(tc.regexpStr) 55 if err != nil { 56 return nil, err 57 } 58 59 matches := pattern.FindStringSubmatch(cmdout) 60 if matches != nil { 61 if tc.addPosition != -1 { 62 cnt.Add, err = strconv.Atoi(matches[tc.addPosition]) 63 if err != nil { 64 return nil, err 65 } 66 } 67 68 if tc.changePosition != -1 { 69 cnt.Change, err = strconv.Atoi(matches[tc.changePosition]) 70 if err != nil { 71 return nil, err 72 } 73 } 74 75 if tc.destroyPosition != -1 { 76 cnt.Destroy, err = strconv.Atoi(matches[tc.destroyPosition]) 77 if err != nil { 78 return nil, err 79 } 80 } 81 82 return &cnt, nil 83 } 84 } 85 86 return nil, errors.New(getResourceCountErrMessage) 87 }