github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/docs/DeveloperGenerateTest.md (about) 1 # Generating Tests 2 3 ## Context 4 5 We rely on Ginkgo and Gomega as the core of our E2E functional test framework. Ginkgo allows you to write expressive BDD style tests that act as specifications by example. The intent is to allow a team to write specifications, which we call a spec outline, that look like this: 6 7 ``` 8 BookSuiteDescribe: Book service E2E tests 9 Describe: Categorizing book length @book 10 When: the book has more than 300 pages @slow 11 It: should be a novel 12 When: the book has fewer than 300 pages @fast 13 It: should be a short story 14 15 Describe: Creating bookmarks in a book @book, @bookmark, @parallel 16 It: has no bookmarks by default 17 It: can add bookmarks 18 19 ``` 20 21 and be able to generate skeleton Ginkgo Test Files that look like this: 22 23 ```golang 24 package books 25 26 /* This was generated from a template file. Please feel free to update as necessary! 27 a couple things to note: 28 - Remember to implement specific logic of the service/domain you are trying to test if it not already there in the pkg/ 29 30 - To include the tests as part of the E2E Test suite: 31 - Update the pkg/framework/describe.go to include the `Describe func` of this new test suite, If you haven't already done so. 32 - Import this new package into the cmd/e2e_test.go 33 */ 34 35 import ( 36 . "github.com/onsi/ginkgo/v2" 37 . "github.com/onsi/gomega" 38 39 "context" 40 "encoding/json" 41 "fmt" 42 "strings" 43 "time" 44 45 "github.com/redhat-appstudio/e2e-tests/pkg/framework" 46 //framework imports edit as required 47 "github.com/redhat-appstudio/e2e-tests/pkg/constants" 48 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 49 ) 50 51 var _ = framework.BookSuiteDescribe("Book service E2E tests", func() { 52 53 defer GinkgoRecover() 54 var err error 55 var f *framework.Framework 56 // use 'f' to access common controllers or the specific service controllers within the framework 57 BeforeAll(func() { 58 // Initialize the tests controllers 59 f, err = framework.NewFramework() 60 Expect(err).NotTo(HaveOccurred()) 61 }) 62 63 Describe("Categorizing book length ", Label("book"), func() { 64 // Declare variables here. 65 66 When("the book has more than 300 pages ", Label("slow"), func() { 67 68 It("should be a novel", func() { 69 70 // Implement test and assertions here 71 72 }) 73 74 }) 75 76 When("the book has fewer than 300 pages ", Label("fast"), func() { 77 78 It("should be a short story", func() { 79 80 // Implement test and assertions here 81 82 }) 83 84 }) 85 86 }) 87 88 Describe("Creating bookmarks in a book ", Label("book"), Label("bookmark"), Label("parallel"), func() { 89 // Declare variables here. 90 91 It("has no bookmarks by default", func() { 92 93 // Implement test and assertions here 94 95 }) 96 97 It("can add bookmarks", func() { 98 99 // Implement test and assertions here 100 101 }) 102 103 }) 104 105 }) 106 107 ``` 108 109 or parse Ginkgo Test Files that have large amounts of code, like [build.go](../tests/build/build.go), and generate spec outlines that looks like this. 110 111 ``` 112 BuildSuiteDescribe: Build service E2E tests @build, @HACBS 113 Describe: test PaC component build @github-webhook, @pac-build, @pipeline 114 When: a new component without specified branch is created @pac-custom-default-branch 115 It: correctly targets the default branch (that is not named 'main') with PaC 116 It: triggers a PipelineRun 117 It: a related PipelineRun and Github webhook should be deleted after deleting the component 118 It: PR branch should not exists in the repo 119 When: a new component with specified custom branch branch is created 120 It: triggers a PipelineRun 121 It: should lead to a PaC init PR creation 122 It: the PipelineRun should eventually finish successfully 123 It: eventually leads to a creation of a PR comment with the PipelineRun status report 124 When: the PaC init branch is updated 125 It: eventually leads to triggering another PipelineRun 126 It: PipelineRun should eventually finish 127 It: eventually leads to another update of a PR with a comment about the PipelineRun status report 128 When: the PaC init branch is merged 129 It: eventually leads to triggering another PipelineRun 130 It: pipelineRun should eventually finish 131 When: the component is removed and recreated (with the same name in the same namespace) 132 It: should no longer lead to a creation of a PaC PR 133 134 Describe: Creating component with container image source 135 It: should not trigger a PipelineRun 136 137 Describe: PLNSRVCE-799 - test pipeline selector @pipeline-selector 138 It: a specific Pipeline bundle should be used and additional pipeline params should be added to the PipelineRun if all WhenConditions match 139 It: default Pipeline bundle should be used and no additional Pipeline params should be added to the PipelineRun if one of the WhenConditions does not match 140 141 Describe: A secret with dummy quay.io credentials is created in the testing namespace 142 It: should override the shared secret 143 It: should not be possible to push to quay.io repo (PipelineRun should fail) 144 145 ``` 146 147 ## How it works 148 149 We leverage existing Ginkgo's tool set to be able to do this translation back and forth. 150 * `ginkgo outline` we use to be able to generate the initial spec outline for our internal model based on what is in the file Ginkgo Test File. This command depends on the GoLang AST to generates the output. 151 * `ginkgo generate` we use to pass a customize template and data so that it can render a spec file using Ginkgo's extensive use of closures to allow us to build a descriptive spec hierarchy. 152 153 ## Schema 154 155 The text outline file must be in the following format: 156 157 * Each line MUST be in key/value format using `:` as delimiter 158 * Each key MUST be a Ginkgo DSL word for Container and Subject nodes, `Describe/When/Context/It/By/DescribeTable/Entry` 159 * The value is essentially the description text of the container 160 * All lines MUST be nested, by using spaces, to represent the logical tree hierarchy of the specification 161 * The first line MUST be a framework decorator function type `Describe` node that will get implemented in `/pkg/framework/describe.go` 162 * To assign Labels: 163 * each string intended to be a label MUST be prefixed with `@` 164 * the set of labels MUST be a comma separated list 165 * they MUST be assigned AFTER the description text 166 * When using the `DescribeTable` key, the proceeding nested lines MUST have the `Entry` or `By` key or Ginkgo will not render the template properly 167 168 For the time being we don't support any of Ginkgo's Setup/Teardown nodes. We could technically graph it together from the text outline but it won't render with our base template. The important thing is to expressively model the behavior to test. Test developers will be able to insert Setup/Teardown nodes where they see fit when the spec has been rendered. 169 170 171 ## Prerequisite 172 173 Before generating anything make sure you have Ginkgo in place. To install Ginkgo: 174 175 `go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo` 176 177 ## Team specific template 178 Teams can create their own templates according to their needs. 179 These should utilize the provided `specs.tmpl` by including the following line wherever they want their specs to be. (do not forget the dot!) 180 181 `{{ template "specs" . }}` 182 183 Everything needed to get started is in the [templates/default](../templates/default) directory. 184 185 Please see the provided [recommended](../templates/default/recommended.tmpl) and [barebones](../templates/default/barebones.tmpl) templates. 186 Copy them and make your own. 187 188 ## Usage 189 190 ### Printing a text outline of an existing ginkgo spec file 191 This will generate the outline and output to your terminal. If you would like to save the outline to a file refer to the next section. 192 193 `./mage PrintOutlineOfGinkgoSpec tests/<subdirectory>/<test-file>.go` 194 195 ```bash 196 $ ./mage PrintOutlineOfGinkgoSpec tests/books/books.go 197 tests/books/books.goI0622 22:11:30.391491 19273 testcasemapper.go:26] Mapping outline from a Ginkgo test file, tests/books/books.go 198 I0622 22:11:30.395240 19273 testcasemapper.go:40] Printing outline: 199 200 BookSuiteDescribe: Book service E2E tests 201 Describe: Categorizing book length @book 202 When: the book has more than 300 pages @slow 203 It: Should be a novel 204 When: the book has fewer than 300 pages @fast 205 It: should be a short story 206 207 Describe: Creating bookmarks in a book @book, @bookmark, @parallel 208 It: Has no bookmarks by default 209 It: Can add bookmarks 210 211 DescribeTable: Reading invalid books always errors is table 212 Entry: Empty book 213 Entry: Only title 214 Entry: Only author 215 Entry: Missing pages 216 217 ``` 218 ### Generating the text outline file from an existing ginkgo spec file 219 This will generate the outline and output to a text file to the desired file location 220 221 `./mage GenerateTextOutlineFromGinkgoSpec tests/<subdirectory>/<test-file>.go <dest>/<sub-path>/<file>` 222 223 ```bash 224 $ ./mage GenerateTextOutlineFromGinkgoSpec tests/books/books.go /tmp/outlines/books.outline 225 I0622 22:19:41.857966 20923 testcasemapper.go:26] Mapping outline from a Ginkgo test file, tests/books/books.go 226 I0622 22:19:41.865725 20923 testcasemapper.go:70] Mapping outline to a text file, /tmp/outlines/books.outline 227 I0622 22:19:41.865837 20923 textspec.go:67] successfully written to /tmp/outlines/books.outline 228 229 ``` 230 231 ### Generating a generic Ginkgo spec file from an existing text outline file 232 This will generate a generic Ginkgo spec in a subdirectory within our tests directory 233 234 `./mage GenerateGinkgoSpecFromTextOutline <path>/<to>/<outline> <subpath-under-tests>/<filename>.go` 235 236 ```bash 237 $ ./mage GenerateGinkoSpecFromTextOutline dummy_test.outline books/books.go 238 I0622 22:14:22.140583 20356 testcasemapper.go:58] Mapping outline from a text file, dummy_test.outline 239 I0622 22:14:22.140673 20356 testcasemapper.go:47] Mapping outline to a Ginkgo test file, books/books.go 240 I0622 22:14:22.140841 20356 ginkgosspec.go:242] Creating new test package directory and spec file tests/books/books.go. 241 ``` 242 As noted above, this command will create a new package under the `tests/` directory and a test spec file `<filename>.go` for you. It will contain some basic imports but more importantly it will generate a basic structured Ginkgo spec skeleton that you can code against. 243 244 ### Generating a team specific Ginkgo spec file from an existing text outline file 245 This will generate the Ginkgo spec in a subdirectory within our tests directory using a team specific template provided by user. Please see the [Team specific template](#team-specific-template) section. 246 247 Feel free to use the provided [testOutline](../templates/default/testOutline) file for testing. 248 249 `./mage GenerateTeamSpecificGinkgoSpecFromTextOutline <path>/<to>/<outline> <path>/<to>/<team-specific-template> <subpath-under-tests>/<filename>.go` 250 251 ```bash 252 ➜ ./mage GenerateTeamSpecificGinkgoSpecFromTextOutline templates/default/testOutline templates/default/recommended.tmpl tests/template_poc/template_poc.go 253 I0219 15:42:17.808595 351210 magefile.go:755] Mapping outline from a text file, templates/default/testOutline 254 I0219 15:42:17.808685 351210 magefile.go:762] Mapping outline to a Ginkgo spec file, tests/template_poc/template_poc.go 255 I0219 15:42:17.809210 351210 ginkgosspec.go:144] Creating new test package directory and spec file /home/tnevrlka/Work/e2e-tests/tests/template_poc/template_poc.go. 256 ``` 257 258 ### Printing a text outline in JSON format of an existing ginkgo spec file 259 This will generate the outline and output to your terminal in JSON format. This is the format we use when rendering the template. You can pipe this output to tools like `jq` for formatting and filtering. This would only be useful for troubleshooting purposes 260 261 `./mage PrintJsonOutlineOfGinkgoSpec tests/<subdirectory>/<test-file>.go` 262 263 ```bash 264 $ ./mage PrintJsonOutlineOfGinkgoSpec tests/books/books.go 265 I0622 22:28:15.661455 23214 testcasemapper.go:26] Mapping outline from a Ginkgo test file, tests/books/books.go 266 [{"Name":"BookSuiteDescribe","Text":"Book service E2E tests","Labels":[],"Nodes":[{"Name":"Describe","Text":"Categorizing book length ","Labels":["book"],"Nodes":[{"Name":"When","Text":"the book has more than 300 pages ","Labels":["slow"],"Nodes":[{"Name":"It","Text":"Should be a novel","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0}],"InnerParentContainer":false,"LineSpaceLevel":0},{"Name":"When","Text":"the book has fewer than 300 pages ","Labels":["fast"],"Nodes":[{"Name":"It","Text":"should be a short story","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0}],"InnerParentContainer":false,"LineSpaceLevel":0}],"InnerParentContainer":true,"LineSpaceLevel":0},{"Name":"Describe","Text":"Creating bookmarks in a book ","Labels":["book","bookmark","parallel"],"Nodes":[{"Name":"It","Text":"Has no bookmarks by default","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0},{"Name":"It","Text":"Can add bookmarks","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0}],"InnerParentContainer":true,"LineSpaceLevel":0},{"Name":"DescribeTable","Text":"Reading invalid books always errors is table","Labels":[],"Nodes":[{"Name":"Entry","Text":"Empty book","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0},{"Name":"Entry","Text":"Only title","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0},{"Name":"Entry","Text":"Only author","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0},{"Name":"Entry","Text":"Missing pages","Labels":[],"Nodes":[],"InnerParentContainer":false,"LineSpaceLevel":0}],"InnerParentContainer":true,"LineSpaceLevel":0}],"InnerParentContainer":false,"LineSpaceLevel":0}] 267 268 ``` 269 270 ### Printing a text outline of an existing text outline file 271 This will generate the outline and output to your terminal. This would only be useful for troubleshooting purposes. i.e. To make sure complex text outlines are graphed properly in the tree. 272 273 `./mage PrintOutlineOfTextSpec <path>/<to>/<outline-file>` 274 275 ```bash 276 $ ./mage PrintOutlineOfTextSpec /tmp/outlines/books.outline 277 I0622 22:32:34.429681 23787 testcasemapper.go:58] Mapping outline from a text file, /tmp/outlines/books.outline 278 I0622 22:32:34.429771 23787 testcasemapper.go:40] Printing outline: 279 280 BookSuiteDescribe: Book service E2E tests 281 Describe: Categorizing book length @book 282 When: the book has more than 300 pages @slow 283 It: Should be a novel 284 When: the book has fewer than 300 pages @fast 285 It: should be a short story 286 Describe: Creating bookmarks in a book @book, @bookmark, @parallel 287 It: Has no bookmarks by default 288 It: Can add bookmarks 289 DescribeTable: Reading invalid books always errors is table 290 Entry: Empty book 291 Entry: Only title 292 Entry: Only author 293 Entry: Missing pages 294 295 ``` 296 297 ### Updating the pkg framework describe file 298 299 Once you are comfortable with your test you can update the framework/describe.go in our package directory. 300 301 `./mage AppendFrameworkDescribeGoFile tests/<test-package>/<specfile>.go` 302 303 ```bash 304 $ ./mage AppendFrameworkDescribeGoFile tests/books/books.go 305 I0623 11:56:42.997793 20862 magefile.go:670] Inspecting Ginkgo spec file, tests/books/books.go 306 pkg/framework/describe.go 307 308 ``` 309 310 ### Generating Ginkgo Test Suite File 311 312 This command will help setup a test suite file within the `cmd/` directory. It will do the test package import based on the name of the package you passed in. So using the example below it will assume there is a `tests/chaos` package to import as well. It uses a simplified version of the `cmd/e2e_test.go` as a template to allow you to leverage the existing functionality built into the framework like webhooks eventing. Edit this file as you feel necessary. 313 314 NOTE: You may not need to generate this file. This is useful when you want to move a type of testing into a separate suite that wouldn't go into the existing e2e test suite package. i.e. chaos testing. We have a current example with the existing `cmd/loadsTest.go` which are used to run the AppStudio Load tests. 315 316 `./mage GenerateTestSuiteFile <name of test package under tests directory>` 317 318 ```bash 319 $ ./mage GenerateTestSuiteFile chaos 320 I0623 12:48:13.761038 31196 magefile.go:467] Creating new test suite file cmd/chaos_test.go. 321 cmd/chaos_test.go 322 323 ```