-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadvanced_tutorial.html
323 lines (295 loc) · 25.1 KB
/
advanced_tutorial.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<ol class="breadcrumb">
<li><a href="index.html">Gatling documentation</a></li>
<li><a href="">
Advanced Tutorial
</a></li>
</ol>
<div class="content-left-wrap col-md-9">
<div id="primary" class="content-area">
<main itemscope="" itemtype="http://schema.org/WebPageElement" itemprop="mainContentOfPage" id="main"
class="site-main">
<article id="documentation" class="type-post status-publish format-standard hentry category-non-classe">
<header class="entry-header">
<h1 class="entry-title" itemprop="headline">Advanced Tutorial</h1>
</header>
<div class="entry-content" itemprop="text">
<div class="section" id="advanced-tutorial">
<span id="id1"></span>
<p>In this section, we assume that you have already gone through the <a class="reference internal" href="quickstart.html#quickstart"><span class="std std-ref">Quickstart</span></a> section and that you have a basic simulation to work with.
We will apply a series of refactorings to introduce more advanced concepts and DSL constructs.</p>
<div class="section" id="step-01-isolate-processes">
<h2>Step 01: Isolate processes<a class="headerlink" href="#step-01-isolate-processes" title="Permalink to this headline">¶</a></h2>
<p>Presently our Simulation is one big monolithic scenario.</p>
<p>So first let us split it into composable business processes, akin to the PageObject pattern with Selenium.
This way, you’ll be able to easily reuse some parts and build complex behaviors without sacrificing maintenance.</p>
<dl class="docutils">
<dt>In our scenario we have three separated processes:</dt>
<dd><ul class="first last simple">
<li>Search: search models by name</li>
<li>Browse: browse the list of models</li>
<li>Edit: edit a given model</li>
</ul>
</dd>
</dl>
<p>We are going to extract those chains and store them into <em>objects</em>.
Objects are native Scala singletons.
You can create those in dedicated files, or directly in the same file as the Simulation.</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">object</span> <span class="nc">Search</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">search</span> <span class="k">=</span> <span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Home"</span><span class="o">)</span> <span class="c1">// let's give proper names, as they are displayed in the reports</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/"</span><span class="o">))</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">7</span><span class="o">)</span>
<span class="o">.</span><span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Search"</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/computers?f=macbook"</span><span class="o">))</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span>
<span class="o">.</span><span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Select"</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/computers/6"</span><span class="o">))</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">3</span><span class="o">)</span>
<span class="o">}</span>
<span class="k">object</span> <span class="nc">Browse</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">browse</span> <span class="k">=</span> <span class="o">???</span>
<span class="o">}</span>
<span class="k">object</span> <span class="nc">Edit</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">edit</span> <span class="k">=</span> <span class="o">???</span>
<span class="o">}</span>
</pre></div>
</div>
<p>We can now rewrite our scenario using these reusable business processes:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">val</span> <span class="n">scn</span> <span class="k">=</span> <span class="n">scenario</span><span class="o">(</span><span class="s">"Scenario Name"</span><span class="o">).</span><span class="n">exec</span><span class="o">(</span><span class="nc">Search</span><span class="o">.</span><span class="n">search</span><span class="o">,</span> <span class="nc">Browse</span><span class="o">.</span><span class="n">browse</span><span class="o">,</span> <span class="nc">Edit</span><span class="o">.</span><span class="n">edit</span><span class="o">)</span>
</pre></div>
</div>
</div>
<div class="section" id="step-02-configure-virtual-users">
<h2>Step 02: Configure virtual users<a class="headerlink" href="#step-02-configure-virtual-users" title="Permalink to this headline">¶</a></h2>
<p>So, this is great, we can load test our server with… one user!
Let’s increase the number of users.</p>
<dl class="docutils">
<dt>Let’s define two populations of users:</dt>
<dd><ul class="first last simple">
<li><em>regular</em> users: they can search and browse computer models.</li>
<li><em>admin</em> users: they can search, browse and also edit computer models.</li>
</ul>
</dd>
</dl>
<p>Translating into a scenario this gives:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">val</span> <span class="n">users</span> <span class="k">=</span> <span class="n">scenario</span><span class="o">(</span><span class="s">"Users"</span><span class="o">).</span><span class="n">exec</span><span class="o">(</span><span class="nc">Search</span><span class="o">.</span><span class="n">search</span><span class="o">,</span> <span class="nc">Browse</span><span class="o">.</span><span class="n">browse</span><span class="o">)</span>
<span class="k">val</span> <span class="n">admins</span> <span class="k">=</span> <span class="n">scenario</span><span class="o">(</span><span class="s">"Admins"</span><span class="o">).</span><span class="n">exec</span><span class="o">(</span><span class="nc">Search</span><span class="o">.</span><span class="n">search</span><span class="o">,</span> <span class="nc">Browse</span><span class="o">.</span><span class="n">browse</span><span class="o">,</span> <span class="nc">Edit</span><span class="o">.</span><span class="n">edit</span><span class="o">)</span>
</pre></div>
</div>
<p>To increase the number of simulated users, all you have to do is to change the configuration of the simulation as follows:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="n">setUp</span><span class="o">(</span><span class="n">users</span><span class="o">.</span><span class="n">inject</span><span class="o">(</span><span class="n">atOnceUsers</span><span class="o">(</span><span class="mi">10</span><span class="o">)).</span><span class="n">protocols</span><span class="o">(</span><span class="n">httpConf</span><span class="o">))</span>
</pre></div>
</div>
<p>Here we set only 10 users, because we don’t want to flood our test web application. <em>Please</em>, be kind and don’t crash our server ;-)</p>
<p>If you want to simulate 3000 users, you might not want them to start at the same time.
Indeed, real users are more likely to connect to your web application gradually.</p>
<p>Gatling provides <code class="docutils literal"><span class="pre">rampUsers</span></code> to implement this behavior.
The value of the ramp indicates the duration over which the users will be linearly started.</p>
<p>In our scenario let’s have 10 regular users and 2 admins, and ramp them over 10 seconds so we don’t hammer the server:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="n">setUp</span><span class="o">(</span>
<span class="n">users</span><span class="o">.</span><span class="n">inject</span><span class="o">(</span><span class="n">rampUsers</span><span class="o">(</span><span class="mi">10</span><span class="o">)</span> <span class="n">over</span> <span class="o">(</span><span class="mi">10</span> <span class="n">seconds</span><span class="o">)),</span>
<span class="n">admins</span><span class="o">.</span><span class="n">inject</span><span class="o">(</span><span class="n">rampUsers</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span> <span class="n">over</span> <span class="o">(</span><span class="mi">10</span> <span class="n">seconds</span><span class="o">))</span>
<span class="o">).</span><span class="n">protocols</span><span class="o">(</span><span class="n">httpConf</span><span class="o">)</span>
</pre></div>
</div>
</div>
<div class="section" id="step-03-use-dynamic-data-with-feeders-and-checks">
<h2>Step 03: Use dynamic data with Feeders and Checks<a class="headerlink" href="#step-03-use-dynamic-data-with-feeders-and-checks" title="Permalink to this headline">¶</a></h2>
<p>We have set our simulation to run a bunch of users, but they all search for the same model.
Wouldn’t it be nice if every user could search a different model name?</p>
<p>We need dynamic data so that all users don’t play exactly the same scenario and we end up with a behavior completely different from the live system (due to caching, JIT etc.).
This is where Feeders will be useful.</p>
<p>Feeders are data sources containing all the values you want to use in your scenarios.
There are several types of Feeders, the most simple being the CSV Feeder: this is the one we will use in our test.</p>
<p>First let’s create a file named <em>search.csv</em> and place it in the <code class="docutils literal"><span class="pre">user-files/data</span></code> folder.</p>
<p>This file contains the following lines:</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>searchCriterion,searchComputerName
Macbook,MacBook Pro
eee,ASUS Eee PC 1005PE
</pre></div>
</div>
<p>Let’s then declare a feeder and use it to feed our users with the above data:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">object</span> <span class="nc">Search</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">feeder</span> <span class="k">=</span> <span class="n">csv</span><span class="o">(</span><span class="s">"search.csv"</span><span class="o">).</span><span class="n">random</span> <span class="c1">// 1, 2</span>
<span class="k">val</span> <span class="n">search</span> <span class="k">=</span> <span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Home"</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/"</span><span class="o">))</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="n">feed</span><span class="o">(</span><span class="n">feeder</span><span class="o">)</span> <span class="c1">// 3</span>
<span class="o">.</span><span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Search"</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/computers?f=${searchCriterion}"</span><span class="o">)</span> <span class="c1">// 4</span>
<span class="o">.</span><span class="n">check</span><span class="o">(</span><span class="n">css</span><span class="o">(</span><span class="s">"a:contains('${searchComputerName}')"</span><span class="o">,</span> <span class="s">"href"</span><span class="o">).</span><span class="n">saveAs</span><span class="o">(</span><span class="s">"computerURL"</span><span class="o">)))</span> <span class="c1">// 5</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Select"</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"${computerURL}"</span><span class="o">))</span> <span class="c1">// 6</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">}</span>
</pre></div>
</div>
<dl class="docutils">
<dt>Explanations:</dt>
<dd><ol class="first last arabic simple">
<li>First we create a feeder from a csv file with the following columns: <em>searchCriterion</em>, <em>searchComputerName</em>.</li>
<li>As the default feeder strategy is <em>queue</em>, we will use the <em>random</em> strategy for this test to avoid feeder starvation.</li>
<li>Every time a user reaches the feed step, it picks a random record from the feeder.
This user has two new session attributes named <em>searchCriterion</em>, <em>searchComputerName</em>.</li>
<li>We use session data through Gatling’s EL to parametrize the search.</li>
<li>We use a CSS selector with an EL to capture a part of the HTML response, here a hyperlink, and save it in the user session with the name <em>computerURL</em>.</li>
<li>We use the previously saved hyperlink to get a specific page.</li>
</ol>
</dd>
</dl>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p>For more details regarding <em>Feeders</em>, please check out <a class="reference internal" href="session/feeder.html#feeder"><span class="std std-ref">Feeder reference page</span></a>.</p>
<p class="last">For more details regarding <em>HTTP Checks</em>, please check out <a class="reference internal" href="http/http_check.html#http-check"><span class="std std-ref">Checks reference page</span></a>.</p>
</div>
</div>
<div class="section" id="step-04-looping">
<h2>Step 04: Looping<a class="headerlink" href="#step-04-looping" title="Permalink to this headline">¶</a></h2>
<p>In the <em>browse</em> process we have a lot of repetition when iterating through the pages.
We have four times the same request with a different query param value. Can we change this to not violate the DRY principle?</p>
<p>First we will extract the repeated <code class="docutils literal"><span class="pre">exec</span></code> block to a function.
Indeed, <code class="docutils literal"><span class="pre">Simulation</span></code>’s are plain Scala classes so we can use all the power of the language if needed:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">object</span> <span class="nc">Browse</span> <span class="o">{</span>
<span class="k">def</span> <span class="n">gotoPage</span><span class="o">(</span><span class="n">page</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span> <span class="k">=</span> <span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Page "</span> <span class="o">+</span> <span class="n">page</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/computers?p="</span> <span class="o">+</span> <span class="n">page</span><span class="o">))</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="k">val</span> <span class="n">browse</span> <span class="k">=</span> <span class="n">exec</span><span class="o">(</span><span class="n">gotoPage</span><span class="o">(</span><span class="mi">0</span><span class="o">),</span> <span class="n">gotoPage</span><span class="o">(</span><span class="mi">1</span><span class="o">),</span> <span class="n">gotoPage</span><span class="o">(</span><span class="mi">2</span><span class="o">),</span> <span class="n">gotoPage</span><span class="o">(</span><span class="mi">3</span><span class="o">),</span> <span class="n">gotoPage</span><span class="o">(</span><span class="mi">4</span><span class="o">))</span>
<span class="o">}</span>
</pre></div>
</div>
<p>We can now call this function and pass the desired page number.
But we still have repetition, it’s time to introduce another builtin structure:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">object</span> <span class="nc">Browse</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">browse</span> <span class="k">=</span> <span class="n">repeat</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span> <span class="s">"n"</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// 1</span>
<span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Page ${n}"</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/computers?p=${n}"</span><span class="o">))</span> <span class="c1">// 2</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
</div>
<dl class="docutils">
<dt>Explanations:</dt>
<dd><ol class="first last arabic simple">
<li>The <code class="docutils literal"><span class="pre">repeat</span></code> builtin is a loop resolved at <strong>runtime</strong>.
It takes the number of repetitions and, optionally, the name of the counter that’s stored in the user’s Session.</li>
<li>As we force the counter name we can use it in Gatling EL and access the nth page.</li>
</ol>
</dd>
</dl>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">For more details regarding loops, please check out <a class="reference internal" href="general/scenario.html#scenario-loops"><span class="std std-ref">Loops reference page</span></a>.</p>
</div>
</div>
<div class="section" id="step-05-check-and-failure-management">
<h2>Step 05: Check and failure management<a class="headerlink" href="#step-05-check-and-failure-management" title="Permalink to this headline">¶</a></h2>
<p>Up until now we have only used <code class="docutils literal"><span class="pre">check</span></code> to extract some data from the html response and store it in the session.
But <code class="docutils literal"><span class="pre">check</span></code> is also handy to check properties of the response.
By default Gatling checks if the http response status is <em>20x</em> or <em>304</em>.</p>
<p>To demonstrate failure management we will introduce a <code class="docutils literal"><span class="pre">check</span></code> on a condition that fails randomly:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">import</span> <span class="nn">java.util.concurrent.ThreadLocalRandom</span> <span class="c1">// 1</span>
<span class="k">val</span> <span class="n">edit</span> <span class="k">=</span> <span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Form"</span><span class="o">)</span>
<span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="s">"/computers/new"</span><span class="o">))</span>
<span class="o">.</span><span class="n">pause</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="n">exec</span><span class="o">(</span><span class="n">http</span><span class="o">(</span><span class="s">"Post"</span><span class="o">)</span>
<span class="o">.</span><span class="n">post</span><span class="o">(</span><span class="s">"/computers"</span><span class="o">)</span>
<span class="o">.</span><span class="n">check</span><span class="o">(</span><span class="n">status</span><span class="o">.</span><span class="n">is</span><span class="o">(</span><span class="n">session</span> <span class="k">=></span> <span class="mi">200</span> <span class="o">+</span> <span class="nc">ThreadLocalRandom</span><span class="o">.</span><span class="n">current</span><span class="o">.</span><span class="n">nextInt</span><span class="o">(</span><span class="mi">2</span><span class="o">))))</span> <span class="c1">// 2</span>
</pre></div>
</div>
<dl class="docutils">
<dt>Explanations:</dt>
<dd><ol class="first last arabic simple">
<li>First we import <code class="docutils literal"><span class="pre">ThreadLocalRandom</span></code>, to generate random values.</li>
<li>We do a check on a condition that’s been customized with a lambda.
It will be evaluated every time a user executes the request and randomly return <em>200</em> or <em>201</em>.
As response status is 200, the check will fail randomly.</li>
</ol>
</dd>
</dl>
<p>To handle this random failure we use the <code class="docutils literal"><span class="pre">tryMax</span></code> and <code class="docutils literal"><span class="pre">exitHereIfFailed</span></code> constructs as follow:</p>
<div class="highlight-scala"><div class="highlight"><pre><span></span><span class="k">val</span> <span class="n">tryMaxEdit</span> <span class="k">=</span> <span class="n">tryMax</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// 1</span>
<span class="n">exec</span><span class="o">(</span><span class="n">edit</span><span class="o">)</span>
<span class="o">}.</span><span class="n">exitHereIfFailed</span> <span class="c1">// 2</span>
</pre></div>
</div>
<dl class="docutils">
<dt>Explanations:</dt>
<dd><ol class="first last arabic simple">
<li><code class="docutils literal"><span class="pre">tryMax</span></code> tries a given block up to n times.
Here we try a maximum of two times.</li>
<li>If all tries failed, the user exits the whole scenario due to <code class="docutils literal"><span class="pre">exitHereIfFailed</span></code>.</li>
</ol>
</dd>
</dl>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">For more details regarding conditional blocks, please check out <a class="reference internal" href="general/scenario.html#scenario-conditions"><span class="std std-ref">Conditional Statements reference page</span></a>.</p>
</div>
<p>That’s all Folks!</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The files for this tutorial can be found in the distribution in the <code class="docutils literal"><span class="pre">user-files/simulations</span></code> directory, and on Github <a class="reference external" href="https://github.com/gatling/gatling/tree/master/gatling-bundle/src/main/scala/computerdatabase">here</a>.</p>
</div>
</div>
</div>
</div>
</article>
</main>
</div>
</div>
<div class="sidebar-wrap col-md-3 content-left-wrap">
<div id="secondary" class="widget-area" role="complementary" itemscope="itemscope"
itemtype="http://schema.org/WPSideBar">
<aside id="search-2" class="widget widget_search">
<form role="form" method="get" class="search-form" action="search.html">
<label>
<span class="screen-reader-text">Search through the documentation :</span>
<input type="search" class="search-field" placeholder="Search the documentation" name="q">
</label>
<input type="submit" class="search-submit" value="Search">
</form>
</aside>
<aside class="widget">
<h1 class="widget-title">Table of Content</h1>
<ul>
<li><a class="reference internal" href="#">Advanced Tutorial</a><ul>
<li><a class="reference internal" href="#step-01-isolate-processes">Step 01: Isolate processes</a></li>
<li><a class="reference internal" href="#step-02-configure-virtual-users">Step 02: Configure virtual users</a></li>
<li><a class="reference internal" href="#step-03-use-dynamic-data-with-feeders-and-checks">Step 03: Use dynamic data with Feeders and Checks</a></li>
<li><a class="reference internal" href="#step-04-looping">Step 04: Looping</a></li>
<li><a class="reference internal" href="#step-05-check-and-failure-management">Step 05: Check and failure management</a></li>
</ul>
</li>
</ul>
</aside>
<aside class="widget">
<h1 class="widget-title">Previous topic</h1>
<ul>
<li>
<a href="quickstart.html" title="Previous Chapter: Quickstart">
Quickstart
</a>
</li>
</ul>
</aside>
<aside class="widget">
<h1 class="widget-title">Next topic</h1>
<ul>
<li>
<a href="general/index.html" title="Next Chapter: General">
General
</a>
</li>
</ul>
</aside>
<aside class="widget">
<h1 class="widget-title">Contribute</h1>
<ul>
<li>
<a href="https://github.com/gatling/gatling/edit/master/src/sphinx/advanced_tutorial.rst">Edit this page on Github</a>
</li>
</ul>
</aside>
</div>
</div>