<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.0.0">Jekyll</generator><link href="http://davehunt.co.uk/feed.xml" rel="self" type="application/atom+xml" /><link href="http://davehunt.co.uk/" rel="alternate" type="text/html" /><updated>2020-01-10T15:50:57+00:00</updated><id>http://davehunt.co.uk/feed.xml</id><title type="html">Dave Hunt, Automationeer</title><author><name>Dave Hunt</name></author><entry><title type="html">State of Performance Test Engineering (H2/2019)</title><link href="http://davehunt.co.uk/2020/01/06/fxperftest-h2-2019.html" rel="alternate" type="text/html" title="State of Performance Test Engineering (H2/2019)" /><published>2020-01-06T15:50:42+00:00</published><updated>2020-01-06T15:50:42+00:00</updated><id>http://davehunt.co.uk/2020/01/06/fxperftest-h2-2019</id><content type="html" xml:base="http://davehunt.co.uk/2020/01/06/fxperftest-h2-2019.html">&lt;p&gt;It’s a new year, and time for me to post an update on the state of Firefox performance test engineering. The last update was in July 2019 and covered the first half of the year. This update covers the second half of 2019.
&lt;!--more--&gt;&lt;/p&gt;

&lt;h2 id=&quot;team&quot;&gt;Team&lt;/h2&gt;

&lt;p&gt;The team consists of &lt;strong&gt;9&lt;/strong&gt; engineers based in California, Toronto, Montreal, and Romania.&lt;/p&gt;

&lt;h2 id=&quot;tests&quot;&gt;Tests&lt;/h2&gt;

&lt;p&gt;We currently support &lt;strong&gt;4&lt;/strong&gt; frameworks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/AWSY/Tests&quot;&gt;Are We Slim Yet (AWSY)&lt;/a&gt; - memory consumption by the browser&lt;/li&gt;
  &lt;li&gt;build_metrics - build times, installer size, and other compiler-specific insights&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Raptor&quot;&gt;Raptor&lt;/a&gt; - page load and browser benchmarks&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos&quot;&gt;Talos&lt;/a&gt; - various time-based performance KPIs on the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the time of writing, there are &lt;strong&gt;511&lt;/strong&gt; test suites (&lt;a href=&quot;https://activedata.allizom.org/tools/query.html#query_id=JoYO3bKr&quot;&gt;query&lt;/a&gt;) for the above frameworks. This is up from &lt;strong&gt;263&lt;/strong&gt; in the H1/2019 report.&lt;/p&gt;

&lt;p&gt;The following are some highlights of tests introduced in H2/2019:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1548814&quot;&gt;Migrated ARES6 benchmark from Talos to Raptor&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1542046&quot;&gt;Jetstream 2 benchmark&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1552738&quot;&gt;YouTube playback tests&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1575575&quot;&gt;YouTube playback power tests for macOS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1581829&quot;&gt;Enabled cold page load for all sites&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1563708&quot;&gt;Started running tests against Chrome (desktop)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=browsertime&quot;&gt;Prototyped Browsertime as an alternative engine for page load tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;dashboards&quot;&gt;Dashboards&lt;/h2&gt;

&lt;p&gt;In addition to updating &lt;a href=&quot;https://health.graphics&quot;&gt;health.graphics&lt;/a&gt; and related dashboards based on test changes, we have also contributed summary dashboards for &lt;a href=&quot;https://health.graphics/playback&quot;&gt;media playback performance&lt;/a&gt; and &lt;a href=&quot;https://health.graphics/power&quot;&gt;power usage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We have also contributed several improvements to the &lt;a href=&quot;https://wiki.mozilla.org/EngineeringProductivity/Projects/Perfherder&quot;&gt;Perfherder&lt;/a&gt; tool used by the performance sheriffs for monitoring and investigating regression and improvement alerts. Some example are listed below:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ability for sheriffs to assign alerts&lt;/li&gt;
  &lt;li&gt;Allow users to retrigger from the compare view&lt;/li&gt;
  &lt;li&gt;New view showing active performance tests&lt;/li&gt;
  &lt;li&gt;Highlight prioritised alerts for investigation&lt;/li&gt;
  &lt;li&gt;Show measurement unit in graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;hardware&quot;&gt;Hardware&lt;/h2&gt;

&lt;p&gt;Our tests are running on the following hardware in continuous integration:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;38&lt;/strong&gt; Moto G5 devices (with two of these dedicated to power testing)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;23&lt;/strong&gt; Pixel 2 devices (with two of these dedicated to power testing)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;16&lt;/strong&gt; Acer Aspire 15 laptops (2017 reference hardware)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;35&lt;/strong&gt; Lenovo Yoga C630 laptops (Windows ARM64)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2&lt;/strong&gt; Apple MacBook Pro laptops (used for power testing)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See &lt;a href=&quot;https://wiki.mozilla.org/TestEngineering/Performance/Platforms&quot;&gt;this wiki page&lt;/a&gt; for more details on the hardware used.&lt;/p&gt;

&lt;h2 id=&quot;sheriffs&quot;&gt;Sheriffs&lt;/h2&gt;

&lt;p&gt;We have &lt;strong&gt;3&lt;/strong&gt; performance sheriffs 🤠 dedicating up to &lt;strong&gt;50%&lt;/strong&gt; of their time to this role. Outside of this, they assist with improving our tools and test harnesses.&lt;/p&gt;

&lt;h2 id=&quot;q32019&quot;&gt;Q3/2019&lt;/h2&gt;

&lt;p&gt;During the third quarter of 2019 our perfomance tools generated &lt;strong&gt;1110&lt;/strong&gt; alert summaries. This is an average of &lt;strong&gt;12&lt;/strong&gt; alert summaries every day.&lt;/p&gt;

&lt;p&gt;Of the four test frameworks, &lt;strong&gt;build_metrics&lt;/strong&gt; caused the most alert summaries, accounting for &lt;strong&gt;42%&lt;/strong&gt; of the total. The &lt;strong&gt;raptor&lt;/strong&gt; framework was the second biggest contributor, with &lt;strong&gt;30%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q3_asbf.png&quot; alt=&quot;Alert Summaries by Framework (Q3/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of the alert summaries generated, &lt;strong&gt;13%&lt;/strong&gt; were improvements. Of the alert summaries showing regressions, &lt;strong&gt;51%&lt;/strong&gt; were determined to be invalid, &lt;strong&gt;5%&lt;/strong&gt; were backed out, &lt;strong&gt;23%&lt;/strong&gt; were accepted, and &lt;strong&gt;18%&lt;/strong&gt; were fixed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q3_rbs.png&quot; alt=&quot;Regressions by Status (Q3/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Our performance sheriffs triaged &lt;strong&gt;63%&lt;/strong&gt; of alerts within a day, and an additional &lt;strong&gt;22%&lt;/strong&gt; within 3 days.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q3_tr.png&quot; alt=&quot;Triage Response (Q3/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Bugs were filed within 3 days for &lt;strong&gt;53%&lt;/strong&gt; of confirmed regressions, with a further &lt;strong&gt;16%&lt;/strong&gt; within 5 days.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q3_rbr.png&quot; alt=&quot;Regression Bug Response (Q3/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here are some highlights for some of our sheriffed frameworks:&lt;/p&gt;

&lt;h3 id=&quot;are-we-slim-yet-awsy&quot;&gt;Are We Slim Yet (AWSY)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=22205&quot;&gt;July 22nd&lt;/a&gt; we detected up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;18.9%&lt;/strong&gt; &lt;/span&gt;improvement in AWSY for macOS. This was caused by Paul Bone’s patch on &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1567366&quot;&gt;bug 1567366&lt;/a&gt;, which switched to using MADV_FREE_REUSABLE.&lt;/li&gt;
  &lt;li&gt;The largest fixed regression detected from AWSY was noticed on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=22270&quot;&gt;August 2nd&lt;/a&gt;, and had an impact of up to &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;21.57%&lt;/strong&gt;&lt;/span&gt; regression to images. This was attributed to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1570745&quot;&gt;bug 1570745&lt;/a&gt; and was fixed by switching AWSY to the common scenario for new tab page rather than the new user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;raptor&quot;&gt;Raptor&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The improvement alert with the highest magnitude for Raptor was created on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21951&quot;&gt;July 16th&lt;/a&gt;, which saw up to a massive &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;46.06%&lt;/strong&gt;&lt;/span&gt; improvement to page load time on desktop. The gains were attributed to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1541229&quot;&gt;bug 1541229&lt;/a&gt;, which tweaked idle detection during page load.&lt;/li&gt;
  &lt;li&gt;The largest regression alert that was ultimately fixed for Raptor was generated on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=22746&quot;&gt;August 13th&lt;/a&gt;. This showed up to &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;21.86%&lt;/strong&gt;&lt;/span&gt; regression to the &lt;a href=&quot;https://wiki.mozilla.org/TestEngineering/Performance/Raptor#Cold_Page-Load&quot;&gt;cold page load&lt;/a&gt; tests on Android, and was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1570905&quot;&gt;bug 1557282&lt;/a&gt;. This was also noticed in Telemetry and was fixed via &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1575794&quot;&gt;bug 1575794&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;talos&quot;&gt;Talos&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;For Talos, the alert showing the largest improvement was created on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=22496&quot;&gt;August 13th&lt;/a&gt;, which showed up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;13.09%&lt;/strong&gt;&lt;/span&gt; improvement to &lt;a href=&quot;https://wiki.mozilla.org/TestEngineering/Performance/Talos/Tests#ts_paint&quot;&gt;ts_paint&lt;/a&gt;. It was attributed to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1572646&quot;&gt;bug 1572646&lt;/a&gt;, which optimised picture cache tiles that are solid colours.&lt;/li&gt;
  &lt;li&gt;The largest fixed regression alert for Talos was spotted on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=22414&quot;&gt;August 8th&lt;/a&gt;, and includes a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;4.24%&lt;/strong&gt;&lt;/span&gt; hit to &lt;a href=&quot;https://wiki.mozilla.org/TestEngineering/Performance/Talos/Tests#ts_paint&quot;&gt;ts_paint&lt;/a&gt; on Windows. It was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1539651&quot;&gt;bug 1539651&lt;/a&gt;, and was fixed by Brian Grinstead in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1573158&quot;&gt;bug 1573158&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;q42019&quot;&gt;Q4/2019&lt;/h2&gt;

&lt;p&gt;In the final quarter, our perfomance tools generated &lt;strong&gt;996&lt;/strong&gt; alert summaries. This is an average of &lt;strong&gt;11&lt;/strong&gt; alert summaries every day.&lt;/p&gt;

&lt;p&gt;Of the four test frameworks, &lt;strong&gt;build_metrics&lt;/strong&gt; caused the most alert summaries, accounting for &lt;strong&gt;49%&lt;/strong&gt; of the total. The &lt;strong&gt;raptor&lt;/strong&gt; framework was the second biggest contributor, with &lt;strong&gt;25%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q4_asbf.png&quot; alt=&quot;Alert Summaries by Framework (Q4/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of the alert summaries generated, &lt;strong&gt;14%&lt;/strong&gt; were improvements. Of the alert summaries showing regressions, &lt;strong&gt;50%&lt;/strong&gt; were determined to be invalid, &lt;strong&gt;8%&lt;/strong&gt; were backed out, &lt;strong&gt;17%&lt;/strong&gt; were accepted, and &lt;strong&gt;10%&lt;/strong&gt; were fixed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q4_rbs.png&quot; alt=&quot;Regressions by Status (Q4/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Our performance sheriffs triaged &lt;strong&gt;61%&lt;/strong&gt; of alerts within a day, and an additional &lt;strong&gt;26%&lt;/strong&gt; within 3 days.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q4_tr.png&quot; alt=&quot;Triage Response (Q4/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Bugs were filed within 3 days for &lt;strong&gt;67%&lt;/strong&gt; of confirmed regressions, with a further &lt;strong&gt;11%&lt;/strong&gt; within 5 days.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019_q4_rbr.png&quot; alt=&quot;Regression Bug Response (Q4/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here are some highlights for some of our sheriffed frameworks:&lt;/p&gt;

&lt;h3 id=&quot;are-we-slim-yet-awsy-1&quot;&gt;Are We Slim Yet (AWSY)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The largest improvement noticed for AWSY was on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=23456&quot;&gt;October 11th&lt;/a&gt;, where we saw up to a &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;3.88%&lt;/strong&gt;&lt;/span&gt; decrease in &lt;a href=&quot;https://wiki.mozilla.org/AWSY/Tests#Base_Content_JS&quot;&gt;Base Content JS&lt;/a&gt;. This was attributed to the work by André Bargull &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1570370&quot;&gt;bug 1570370&lt;/a&gt; to move language tag parsing and Intl.Locale to C++.&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=23346&quot;&gt;September 30th&lt;/a&gt;, a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;6.15%&lt;/strong&gt;&lt;/span&gt; regression was noticed in &lt;a href=&quot;https://wiki.mozilla.org/AWSY/Tests#JS_summary&quot;&gt;JS&lt;/a&gt;, caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1345830&quot;&gt;bug 1345830&lt;/a&gt;. This was fixed by Gijs in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1586220&quot;&gt;bug 1586220&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;The open regression with the highest impact for AWSY was detected on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21576&quot;&gt;June 12th&lt;/a&gt;. Whilst there were a large number of improvements in this alert, the &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;12.67%&lt;/strong&gt;&lt;/span&gt; regression to &lt;a href=&quot;https://wiki.mozilla.org/AWSY/Tests#Images_summary&quot;&gt;images&lt;/a&gt; was also significant. The regression was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1558763&quot;&gt;bug 1558763&lt;/a&gt;, which changed the value of a preference within Marionette. It looks like this &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21687&quot;&gt;may have been fixed&lt;/a&gt;, but our performance sheriffs have yet to verify this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;raptor-1&quot;&gt;Raptor&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The most significant improvement detected by Raptor was on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=24271&quot;&gt;December 2nd&lt;/a&gt;. Up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;35.59%&lt;/strong&gt;&lt;/span&gt; boost to many page load and benchmark tests on macOS. This was due to Nathan Froyd’s patch in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1599133&quot;&gt;bug 1599133&lt;/a&gt; to enable constructing Sequence from moved nsTArrays.&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=23717&quot;&gt;November 4th&lt;/a&gt;, a regression alert of &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;9.53%&lt;/strong&gt;&lt;/span&gt; was reported against the Wikipedia page load test for bing.com on desktop. It turned out that &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1591717&quot;&gt;bug 1591717&lt;/a&gt; caused the unexpected regression. It was fixed by a patch by Emilio Cobos Álvarez to turn layout.css.notify-of-unvisited off for now.&lt;/li&gt;
  &lt;li&gt;Due to many page recordings being recreated, there are a lot of &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?status=5&amp;amp;framework=10&amp;amp;hideDwnToInv=1&quot;&gt;open alerts&lt;/a&gt; that require closer examination.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;talos-1&quot;&gt;Talos&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=24535&quot;&gt;December 18th&lt;/a&gt; we detected an improvement of up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;32.21%&lt;/strong&gt;&lt;/span&gt; to several tests on macOS. This was thanks to Chris Manchester’s work on enabling PGO (Profile-Guided Optimisations) for the platform in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1604578&quot;&gt;bug 1604578&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Talos detected a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;35.21%&lt;/strong&gt;&lt;/span&gt; regression to &lt;a href=&quot;https://wiki.mozilla.org/TestEngineering/Performance/Talos/Tests#perf-reftest-singletons&quot;&gt;perf_reftest_singletons&lt;/a&gt; on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=23951&quot;&gt;November 14th&lt;/a&gt;, which was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1588431&quot;&gt;bug 1588431&lt;/a&gt; and fixed by Emilio Cobos Álvarez in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1596712&quot;&gt;bug 1596712&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;The open regression alert with the highest magnitude was opened on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=24166&quot;&gt;November 26th&lt;/a&gt;, and reports up to &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;196.47%&lt;/strong&gt;&lt;/span&gt; regression to tp5o. It was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1512011&quot;&gt;bug 1512011&lt;/a&gt;, which replaced mozhttpd with wptserve in Talos.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Dave Hunt</name></author><summary type="html">It’s a new year, and time for me to post an update on the state of Firefox performance test engineering. The last update was in July 2019 and covered the first half of the year. This update covers the second half of 2019.</summary></entry><entry><title type="html">State of Performance Test Engineering (H1/2019)</title><link href="http://davehunt.co.uk/2019/07/02/fxperftest-h1-2019.html" rel="alternate" type="text/html" title="State of Performance Test Engineering (H1/2019)" /><published>2019-07-02T12:04:42+01:00</published><updated>2019-07-02T12:04:42+01:00</updated><id>http://davehunt.co.uk/2019/07/02/fxperftest-h1-2019</id><content type="html" xml:base="http://davehunt.co.uk/2019/07/02/fxperftest-h1-2019.html">&lt;p&gt;Late in 2018 I stepped out of the familiar position of automation engineer, and into the unknown as an engineering manager. A new team was formed for me to manage, focusing on performance test engineering. Now here we are, just over six months in, and I’m excited to share some updates!&lt;!--more--&gt;&lt;/p&gt;

&lt;h2 id=&quot;team&quot;&gt;Team&lt;/h2&gt;

&lt;p&gt;The team consists of &lt;strong&gt;10&lt;/strong&gt; engineers based in California, Toronto, Montreal, and Romania.&lt;/p&gt;

&lt;p&gt;The following team members joined us in H1/2019:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Alexandru Ionescu 🇷🇴&lt;/li&gt;
  &lt;li&gt;Marian Raicof 🇷🇴&lt;/li&gt;
  &lt;li&gt;Alexandru Irimovici 🇷🇴&lt;/li&gt;
  &lt;li&gt;Arnold Iakab 🇷🇴&lt;/li&gt;
  &lt;li&gt;Ken Rubin 🇺🇸&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also welcomed &lt;strong&gt;Greg Mierzwinski&lt;/strong&gt;, who was converted from a contractor to full time employee.&lt;/p&gt;

&lt;p&gt;Despite some early signs of interest, there were no community contributions in this period.&lt;/p&gt;

&lt;h2 id=&quot;tests&quot;&gt;Tests&lt;/h2&gt;

&lt;p&gt;We currently support &lt;strong&gt;4&lt;/strong&gt; frameworks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/AWSY/Tests&quot;&gt;Are We Slim Yet (AWSY)&lt;/a&gt; - memory consumption by the browser&lt;/li&gt;
  &lt;li&gt;build_metrics - build times, installer size, and other compiler-specific insights&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Raptor&quot;&gt;Raptor&lt;/a&gt; - page load and browser benchmarks&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos&quot;&gt;Talos&lt;/a&gt; - various time-based performance KPIs on the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the time of writing, there are &lt;strong&gt;263&lt;/strong&gt; test suites (&lt;a href=&quot;https://activedata.allizom.org/tools/query.html#query_id=L58DqO9p&quot;&gt;query&lt;/a&gt;) for the above frameworks.&lt;/p&gt;

&lt;p&gt;The following are some highlights of tests introduced in H1/2019:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Raptor power tests for Android:
    &lt;ul&gt;
      &lt;li&gt;Idle foreground&lt;/li&gt;
      &lt;li&gt;Idle background&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Raptor page load tests for Android:
    &lt;ul&gt;
      &lt;li&gt;Expanded from &lt;strong&gt;4&lt;/strong&gt; sites to &lt;strong&gt;26&lt;/strong&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Raptor &lt;strong&gt;cold&lt;/strong&gt; page load tests for Android and desktop&lt;/li&gt;
  &lt;li&gt;Raptor page load tests for &lt;strong&gt;Reference Browser&lt;/strong&gt; and &lt;strong&gt;Firefox Preview&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;hardware&quot;&gt;Hardware&lt;/h2&gt;

&lt;p&gt;Our tests are running on the following hardware in continuous integration:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;35&lt;/strong&gt; Moto G5 devices (with two of these dedicated to power testing) 📱&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;38&lt;/strong&gt; Pixel 2 devices (with two of these dedicated to power testing) 📱&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;16&lt;/strong&gt; Windows UX laptops (2017 reference hardware) 💻&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;35&lt;/strong&gt; Windows ARM64 laptops (Lenovo Yoga C630) 💻&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sheriffs&quot;&gt;Sheriffs&lt;/h2&gt;

&lt;p&gt;We have &lt;strong&gt;2&lt;/strong&gt; performance sheriffs 🤠 dedicating up to &lt;strong&gt;50%&lt;/strong&gt; of their time to this role. Outside of this, they assist with improving our tools and test harnesses. We also have &lt;strong&gt;2&lt;/strong&gt; sheriffs in training to meet the needs of the additional tests we’re adding, and to provide support when needed.&lt;/p&gt;

&lt;h2 id=&quot;q12019&quot;&gt;Q1/2019&lt;/h2&gt;

&lt;p&gt;During the first quarter of 2019 our perfomance tools generated &lt;strong&gt;863&lt;/strong&gt; alert summaries. This is an average of &lt;strong&gt;9.7&lt;/strong&gt; alert summaries every day. Of the four test frameworks, &lt;strong&gt;build_metrics&lt;/strong&gt; caused the most alert summaries, accounting for &lt;strong&gt;35.1%&lt;/strong&gt; of the total. The &lt;strong&gt;raptor&lt;/strong&gt; framework was the second biggest contributor, with &lt;strong&gt;29.9%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Alert Summaries by Framework (Q1_2019).png&quot; alt=&quot;Alert Summaries by Framework (Q1/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of the alert summaries generated, &lt;strong&gt;106&lt;/strong&gt; (12.3%) were improvements. &lt;strong&gt;13&lt;/strong&gt; alerts associated with regressions were fixed, and &lt;strong&gt;9&lt;/strong&gt; were backed out. The remaining alerts were either reassigned, marked as downstream, marked as invalid, are still under investigation, or were accepted.&lt;/p&gt;

&lt;p&gt;Here are some highlights for some of our sheriffed frameworks:&lt;/p&gt;

&lt;h3 id=&quot;are-we-slim-yet-awsy&quot;&gt;Are We Slim Yet (AWSY)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=19393&quot;&gt;February 15th&lt;/a&gt; we detected up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;20.66%&lt;/strong&gt; &lt;/span&gt;improvement in AWSY. This was caused by Paul Bone’s patch on &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1433007&quot;&gt;bug 1433007&lt;/a&gt;, which allowed the nursery to use less than a single chunk.&lt;/li&gt;
  &lt;li&gt;The largest fixed regression detected from AWSY was noticed on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=20020&quot;&gt;March 20th&lt;/a&gt;, and had an impact of up to &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;9.53%&lt;/strong&gt;&lt;/span&gt; regression to the heap unclassified. This was attributed to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1429796&quot;&gt;bug 1429796&lt;/a&gt; and was fixed a week later by Myk Melez.&lt;/li&gt;
  &lt;li&gt;There are no open regressions for AWSY for this period!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;raptor&quot;&gt;Raptor&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The improvement alert with the highest magnitude for Raptor was created on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=20105&quot;&gt;March 25th&lt;/a&gt;, which saw up to a massive &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;41.04%&lt;/strong&gt;&lt;/span&gt; improvement to page load time on Android. The gains were attributed to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1537964&quot;&gt;bug 1537964&lt;/a&gt;, which raised the importance of services launched from the main process.&lt;/li&gt;
  &lt;li&gt;The largest regression alert that was ultimately fixed for Raptor was generated early on in the quarter on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=18575&quot;&gt;January 3rd&lt;/a&gt;. This showed up to &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;120.65%&lt;/strong&gt;&lt;/span&gt; regression to the &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Raptor#raptor-assorted-dom&quot;&gt;assorted-dom&lt;/a&gt; benchmark, caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1467124&quot;&gt;bug 1467124&lt;/a&gt;. A fix was quickly identified by the author, Jan de Mooij and pushed within 24 hours of the notification from our sheriff.&lt;/li&gt;
  &lt;li&gt;Our biggest regression that remains unresolved was created on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=18849&quot;&gt;January 23rd&lt;/a&gt;, and includes &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;20.38%&lt;/strong&gt;&lt;/span&gt; page load regression for Reddit on desktop, and appears to have been caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1485216&quot;&gt;bug 1485216&lt;/a&gt;. Due to excessive noise, we have since disabled the Time to First Interactive (TTFI) measurement, which is the metric that caused this regression. This will make confirming any fix here more difficult.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;talos&quot;&gt;Talos&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;For Talos, the alert showing the largest improvement was created on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=18657&quot;&gt;January 9th&lt;/a&gt;, which showed up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;38.14%&lt;/strong&gt;&lt;/span&gt; improvement to &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#tsvg_static&quot;&gt;tsvg_static&lt;/a&gt;, &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#tsvgr_opacity&quot;&gt;tsvgr_opacity&lt;/a&gt;, and &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#tsvgx&quot;&gt;tsvgx&lt;/a&gt;. It was attributed to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1518773&quot;&gt;bug 1518773&lt;/a&gt;, which was a WebRender update.&lt;/li&gt;
  &lt;li&gt;The largest fixed regression alert for Talos was spotted on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=18846&quot;&gt;January 23rd&lt;/a&gt;, and includes a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;26.73%&lt;/strong&gt;&lt;/span&gt; hit to &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#tscrollx&quot;&gt;tscrollx&lt;/a&gt; and &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#tp5o_scroll&quot;&gt;tp5o_scroll&lt;/a&gt;. It was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1522028&quot;&gt;bug 1522028&lt;/a&gt;, and was fixed by Glenn Watson via &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1523210&quot;&gt;1523210&lt;/a&gt; within a couple of days of being notified by our sheriffs.&lt;/li&gt;
  &lt;li&gt;The worst open regression alert for Talos was created on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=19159&quot;&gt;February 5th&lt;/a&gt;, and contains a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;28.66%&lt;/strong&gt;&lt;/span&gt; slow down to the &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#about-preferences&quot;&gt;about-preferences&lt;/a&gt; test. It looks like this has stalled with a patch to enable ASAP mode for the test, which caused failures and was subsequently backed out. According to Mike Conley in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1504139#c16&quot;&gt;this comment&lt;/a&gt;, “ASAP mode causes us to paint ASAP after the DOM has been dirtied, without waiting for vsync”.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;q22019&quot;&gt;Q2/2019&lt;/h2&gt;

&lt;p&gt;In the second quarter, our perfomance tools generated &lt;strong&gt;831&lt;/strong&gt; alert summaries. This is an average of &lt;strong&gt;9.23&lt;/strong&gt; alert summaries every day. Of the four test frameworks, &lt;strong&gt;raptor&lt;/strong&gt; caused the most alert summaries, accounting for &lt;strong&gt;42.2%&lt;/strong&gt; of the total. The &lt;strong&gt;build_metrics&lt;/strong&gt; framework was the second biggest contributor, with &lt;strong&gt;32.7%&lt;/strong&gt;. There have been additional tests landed for Raptor, new page recordings, and a focus on improving page load performance, which are all likely to be reasons for the increase in Raptor alerts in this period.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Alert Summaries by Framework (Q2_2019).png&quot; alt=&quot;Alert Summaries by Framework (Q2/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of the alert summaries generated, &lt;strong&gt;98&lt;/strong&gt; (11.79%) were improvements. &lt;strong&gt;19&lt;/strong&gt; alerts associated with regressions were fixed, and &lt;strong&gt;6&lt;/strong&gt; were backed out. The remaining alerts were either reassigned, marked as downstream, marked as invalid, are still under investigation, or were accepted.&lt;/p&gt;

&lt;p&gt;In Q1 we introduced a &lt;strong&gt;first_triaged&lt;/strong&gt; timestamp in Perfherder (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1521025&quot;&gt;bug 1521025&lt;/a&gt;), which allows us to track how much time passes between the alert generation and the initial triage from a performance sheriff. Using this, we can see that our perf sheriffs triaged &lt;strong&gt;56.1%&lt;/strong&gt; of alerts within a day, and an additional &lt;strong&gt;24.7%&lt;/strong&gt; within three days.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Days to Triage (Q2_2019).png&quot; alt=&quot;Days to Triage (Q2/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In Q2 we introduced a &lt;strong&gt;bug_updated&lt;/strong&gt; timestamp in Perfherder (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1536040&quot;&gt;bug 1536040&lt;/a&gt;) to more closely track the time between the alert and the correct bug being identified, which is where we handover to the regression author and test owners. The data doesn’t cover all of Q2, but so far we see that &lt;strong&gt;63.3%&lt;/strong&gt; of alerts complete this period within 3 days, and &lt;strong&gt;87.4%&lt;/strong&gt; complete within 1 week.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Days to Bug (Q2_2019).png&quot; alt=&quot;Days to Bug (Q2/2019)&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here are some highlights for some of our sheriffed frameworks:&lt;/p&gt;

&lt;h3 id=&quot;are-we-slim-yet-awsy-1&quot;&gt;Are We Slim Yet (AWSY)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The largest improvement noticed for AWSY was on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21394&quot;&gt;June 9th&lt;/a&gt;, where we saw up to a &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;5.98%&lt;/strong&gt;&lt;/span&gt; decrease in &lt;a href=&quot;https://wiki.mozilla.org/AWSY/Tests#Heap_Unclassified_summary&quot;&gt;heap unclassified&lt;/a&gt; and &lt;a href=&quot;hhttps://wiki.mozilla.org/AWSY/Tests#Base_Content_JS&quot;&gt;base content js&lt;/a&gt;. This was attributed to a patch from Emilio Cobos Álvarez in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1487216&quot;&gt;bug &lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21194&quot;&gt;May 30th&lt;/a&gt;, a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;9.54%&lt;/strong&gt;&lt;/span&gt; regression was noticed across several tests, caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1493420&quot;&gt;bug 1493420&lt;/a&gt;. Fortunately, this was promptly followed by a fix from Emilio Cobos Álvarez.&lt;/li&gt;
  &lt;li&gt;The open regression with the highest impact for AWSY was detected on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21576&quot;&gt;June 12th&lt;/a&gt;. Whilst there were a large number of improvements in this alert, the &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;12.67%&lt;/strong&gt;&lt;/span&gt; regression to &lt;a href=&quot;https://wiki.mozilla.org/AWSY/Tests#Images_summary&quot;&gt;images&lt;/a&gt; was also significant. The regression was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1558763&quot;&gt;bug 1558763&lt;/a&gt;, which changed the value of a preference within Marionette. It looks like this &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21687&quot;&gt;may have been fixed&lt;/a&gt;, but our performance sheriffs have yet to verify this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;raptor-1&quot;&gt;Raptor&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The most significant improvement detected by Raptor was on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=21124&quot;&gt;May 22nd&lt;/a&gt;. Up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;20.42%&lt;/strong&gt;&lt;/span&gt; boost to page load of several sites was seen, which was thanks to Andrew Creskey’s investigation and Michal Novotny’s patch in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1553166&quot;&gt;bug 1553166&lt;/a&gt; to make disk cache sizing less restrictive on mobile.&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=20739&quot;&gt;April 30th&lt;/a&gt;, a regression alert of &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;52.62%&lt;/strong&gt;&lt;/span&gt; was reported against the Raptor page load test for bing.com on desktop. It turned out that &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1514655&quot;&gt;bug 1514655&lt;/a&gt; caused the unexpected regression, and Emilio Cobos Álvarez was able to post a fix within a day of the regression report!&lt;/li&gt;
  &lt;li&gt;Due to many page recordings being recreated, there are a lot of &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?status=5&amp;amp;framework=10&amp;amp;hideDwnToInv=1&quot;&gt;open alerts&lt;/a&gt; that require closer examination.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;talos-1&quot;&gt;Talos&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;On &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=20459&quot;&gt;April 13th&lt;/a&gt; we detected an improvement of up to &lt;span class=&quot;improvement&quot;&gt;&lt;strong&gt;99.24%&lt;/strong&gt;&lt;/span&gt; to the tp5n nonmain_startup_fileio test. This was thanks to Doug Thayer’s work on optimising prefetching of Windows DLLs in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1538279&quot;&gt;bug 1538279&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Talos detected a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;3.78%&lt;/strong&gt;&lt;/span&gt; regression to &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#tsvgr_opacity&quot;&gt;tsvgr_opacity&lt;/a&gt; on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=20235&quot;&gt;March 31st&lt;/a&gt;, which was caused by &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1539026&quot;&gt;bug 1539026&lt;/a&gt;. After an initial fix was backed out, Lee Salzman was able to fix the regression.&lt;/li&gt;
  &lt;li&gt;The open regression alert with the highest magnitude was opened on &lt;a href=&quot;https://treeherder.mozilla.org/perf.html#/alerts?id=20725&quot;&gt;April 29th&lt;/a&gt;, and reports a &lt;span class=&quot;regression&quot;&gt;&lt;strong&gt;38.25%&lt;/strong&gt;&lt;/span&gt; decrease in the average frame interval while animating a simple WebGL scene. It was discovered by the &lt;a href=&quot;https://wiki.mozilla.org/Performance_sheriffing/Talos/Tests#glterrain&quot;&gt;glterrain&lt;/a&gt; test, and attributed to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1547775&quot;&gt;1547775&lt;/a&gt;. It does look like this test returned to the pre-regression values, but we have yet to confirm if this was expected or if the regression remains.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;survey&quot;&gt;Survey&lt;/h2&gt;

&lt;p&gt;I’d really like to find out how our team is doing, and hear if you have any feedback or suggestions for any way we can improve. Please take a couple of minutes to complete the very simple &lt;a href=&quot;https://www.surveymonkey.co.uk/r/6ZP2ZX8&quot;&gt;satisfaction survey&lt;/a&gt; I have created. Thanks!&lt;/p&gt;</content><author><name>Dave Hunt</name></author><summary type="html">Late in 2018 I stepped out of the familiar position of automation engineer, and into the unknown as an engineering manager. A new team was formed for me to manage, focusing on performance test engineering. Now here we are, just over six months in, and I’m excited to share some updates!</summary></entry><entry><title type="html">EuroPython 2018</title><link href="http://davehunt.co.uk/2018/09/14/europython-2018.html" rel="alternate" type="text/html" title="EuroPython 2018" /><published>2018-09-14T11:52:42+01:00</published><updated>2018-09-14T11:52:42+01:00</updated><id>http://davehunt.co.uk/2018/09/14/europython-2018</id><content type="html" xml:base="http://davehunt.co.uk/2018/09/14/europython-2018.html">&lt;p&gt;In July I took the train up to beautiful Edinburgh to attend the
&lt;a href=&quot;https://ep2018.europython.eu/en/&quot;&gt;EuroPython 2018&lt;/a&gt; conference. Despite using Python
professionally for almost 8 years, this was my first experience of a Python conference.
The schedule was &lt;strong&gt;packed&lt;/strong&gt;, and it was challenging deciding what talks to attend, but
I had a great time and enjoyed the strong community feeling of the event. We even went
for a &lt;a href=&quot;https://www.strava.com/activities/1729797362&quot;&gt;group run&lt;/a&gt; around Holyrood Park
and Arthur’s Seat, which I hope is included in the schedule for future years.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;Now that the videos of the talks have all been published, I wanted to share my personal
highlights, and list the talks I saw during and since the conference. I still haven’t
caught up on everything I wanted to see, so I’ve also included my watch list. First,
here’s the &lt;a href=&quot;https://www.youtube.com/playlist?list=PL8uoeex94UhFrNUV2m5MigREebUms39U5&quot;&gt;full playlist of talks from the conference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are my top picks from the talks I either attended or have watched since:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/uSp0-TkGx3c&quot;&gt;Stephane Wirtel - What’s new in Python 3.7&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/8r4wNvbAYUQ&quot;&gt;Hynek Schlawack - How to Write Deployment friendly Applications&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/scum5a_mqBc&quot;&gt;Nicole Harris - PyPI: Past, Present and Future&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/3pokUifUyWM&quot;&gt;Raphael Pierzina - The Challenges of Maintaining a Popular Open Source Project&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/3zWHdyrGlDc&quot;&gt;Sarah Bird - The Web is Terrifying! Using the PyData stack to spy on the spies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/tEOGJ_h0Lx0&quot;&gt;Doug Hellmann - reno - A New Way to Manage Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also wanted to highlight the following lightning talks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/iRPPHg7sGrs?t=21m55s&quot;&gt;Leszek Jakubwski - The Ops Mindset&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/iRPPHg7sGrs?t=6s&quot;&gt;Hynek Schlawack - Imagine a Better World&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a list of the other talks I either attended at the conference or have watched
since:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/xOyJiN3yGfU&quot;&gt;David Beazley - Die Threads&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/ReXxO_azV-w&quot;&gt;Yury Selivanov - asyncio in Python 3.7 and 3.8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/1AqW9-E6VCM&quot;&gt;Łukasz Kąkol - Pythonic code vs performance&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/FCKrfWXBPE4&quot;&gt;Romain Dorgueil - Using Bonobo, Airflow and Grafana to visualize your business&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/u2kKxmb9BWs&quot;&gt;Almar Klein - Let’s embrace WebAssembly!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/JN6RAaufFzU&quot;&gt;Pascal van Kooten - When to use Machine Learning: Tips, Tricks and Warnings&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/SFqna5ilqig&quot;&gt;Bernat Gabor - Standardize Testing in Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/qx7cumg6EEE&quot;&gt;James Saryerwinnie - Debugging Your Code with Data Visualization&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/vIkpCOY-yGs&quot;&gt;Mark Smith - More Than You Ever Wanted To Know About Python Functions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/IZmlkoOO8Mg&quot;&gt;Neil Gall - System testing with Pytest, Docker, and Flask&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/dZ4ETY9Mzws&quot;&gt;Sven Hendrik Haase - Rust and Python - Oxidize Your Snake&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/h5tmNkyNAKs&quot;&gt;Becky Smith - Python 2 is dead! Drag your old code into the modern age&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/QB59ZibEOZ0&quot;&gt;Anastasiia Tymoshchuk - How to develop your project from an idea to architecture design&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/9s0AUlyIbUU&quot;&gt;Marco Buttu - White Mars living far away from any form of life&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/9QXACKrJ-1k&quot;&gt;Mika Boström, Alexander Schmolck - Marge: A bot for better Git’ing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/glvXlcpmVQo&quot;&gt;Dougal Matthews - 10 years of EuroPython and the Python community&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/74AsJ7RET20&quot;&gt;Ines Montani - How to Ignore Most Startup Advice and Build a Decent Software Business&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/UXSr1OL5JKo&quot;&gt;Ian Ozsvald - Citizen Science with Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/LxoKPGvMXf0&quot;&gt;Alec MacQueen - Python and GraphQL&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/apcNyycpidw&quot;&gt;Alexandre Figura - Integration Tests with Super Powers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/hgPH19nBlrk&quot;&gt;Lightning talks on Wednesday, July 25&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/z8rYW1UiHNc&quot;&gt;Lightning talks on Thursday, July 26&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/iRPPHg7sGrs&quot;&gt;Lightning talks on Friday, July 27&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s my list of talks I have yet to watch:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/OHaxQZPKURg&quot;&gt;Victor Stinner - Python 3: ten years later&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/6L3ZVLtSeo8&quot;&gt;Nina Zakharenko - Code Review Skills for Pythonistas&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/eJsu-7hFXyA&quot;&gt;Guillaume Gelin - PEP 557* versus the world&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/oo0Nq44d1yQ&quot;&gt;Ed Singleton - Autism in development&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/zM3cMTcmmk0&quot;&gt;Hrafn Eiriksson - Asyncio in production&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/DK4SwlyWm-k&quot;&gt;Emmanuel Leblond - Trio: A pythonic way to do async programming&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/ih2reTLOzWI&quot;&gt;Elisabetta Bergamini - Bad hotel again? Find your perfect match!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/7qLNrcYkQiY&quot;&gt;Steve Barnes - Why develop a CLI Command Line Interface first?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/1lJDZx6f6tY&quot;&gt;Lynn Root - asyncio in Practice: We Did It Wrong&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/btqFjNDdTlE&quot;&gt;Alex Grönholm - Automating testing and deployment with Github and Travis&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Were you at EuroPython 2018? Let me know if you have any favourite talks that aren’t
already on my list! I’m keen to attend again next year, if my travel schedule allows
for it.&lt;/p&gt;</content><author><name>Dave Hunt</name></author><summary type="html">In July I took the train up to beautiful Edinburgh to attend the EuroPython 2018 conference. Despite using Python professionally for almost 8 years, this was my first experience of a Python conference. The schedule was packed, and it was challenging deciding what talks to attend, but I had a great time and enjoyed the strong community feeling of the event. We even went for a group run around Holyrood Park and Arthur’s Seat, which I hope is included in the schedule for future years.</summary></entry><entry><title type="html">Python unit tests now running with Python 3 at Mozilla</title><link href="http://davehunt.co.uk/2018/06/29/python-unit-tests-now-running-with-python-3-at-mozilla.html" rel="alternate" type="text/html" title="Python unit tests now running with Python 3 at Mozilla" /><published>2018-06-29T15:48:42+01:00</published><updated>2018-06-29T15:48:42+01:00</updated><id>http://davehunt.co.uk/2018/06/29/python-unit-tests-now-running-with-python-3-at-mozilla</id><content type="html" xml:base="http://davehunt.co.uk/2018/06/29/python-unit-tests-now-running-with-python-3-at-mozilla.html">&lt;p&gt;I’m excited to announce that you can now run the Python unit tests for packages in the Firefox source code against Python 3! This will allow us to gradually build support for Python 3, whilst ensuring that we don’t later regress. Any tests not currently passing in Python 3 are skipped with the condition &lt;code class=&quot;highlighter-rouge&quot;&gt;skip-if = python == 3&lt;/code&gt; in the manifest files, so if you’d like to see how they fail (and maybe provide a patch to fix some!) then you will need to remove that condition locally. Once you’ve done this, use the &lt;code class=&quot;highlighter-rouge&quot;&gt;mach python-test&lt;/code&gt; command with the new optional argument &lt;code class=&quot;highlighter-rouge&quot;&gt;--python&lt;/code&gt;. This will accept a version number of Python or a path to the binary. You will need to make sure you have the appropriate version of Python installed.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;Once you’re ready to enable tests to run in &lt;a href=&quot;https://docs.taskcluster.net/docs&quot;&gt;TaskCluster&lt;/a&gt;, you can simply update the &lt;code class=&quot;highlighter-rouge&quot;&gt;python-version&lt;/code&gt; value in &lt;code class=&quot;highlighter-rouge&quot;&gt;taskcluster/ci/source-test/python.yml&lt;/code&gt; to include the major version numbers of Python to execute the tests against. At the current time our build machines have Python 2.7 and Python 3.5 available.&lt;/p&gt;

&lt;p&gt;To summarise:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Remove &lt;code class=&quot;highlighter-rouge&quot;&gt;skip-if = python == 3&lt;/code&gt; from manifest files. These are typically named &lt;code class=&quot;highlighter-rouge&quot;&gt;manifest.ini&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;python.ini&lt;/code&gt;, and are usually found in the &lt;code class=&quot;highlighter-rouge&quot;&gt;tests&lt;/code&gt; directory for the package.&lt;/li&gt;
  &lt;li&gt;Run &lt;code class=&quot;highlighter-rouge&quot;&gt;mach python-test --python=3&lt;/code&gt; with your target path or subsuite.&lt;/li&gt;
  &lt;li&gt;Fix the package(s) to support Python 3 and ensure the tests are passing&lt;/li&gt;
  &lt;li&gt;Add Python 3 to the &lt;code class=&quot;highlighter-rouge&quot;&gt;python-version&lt;/code&gt; for the appropriate job in &lt;code class=&quot;highlighter-rouge&quot;&gt;taskcluster/ci/source-test/python.yml&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the time of writing, the &lt;a href=&quot;https://pythonclock.org/&quot;&gt;pythonclock.org&lt;/a&gt; tells me that we have just over 18 months before Python 2.7 will be retired. What this actually means is still somewhat unknown, but it would be a good idea to check if your code is compatible with Python 3, and if it’s not, to do something about it. The Firefox build system at Mozilla uses Python, and it’s still some way from supporting Python 3. We have a lot of code, it’s going to be a long journey, and we could do with a bit of help!&lt;/p&gt;

&lt;p&gt;Whilst we do plan to support Python 3 in the Firefox build system (see &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1388447&quot;&gt;bug 1388447&lt;/a&gt;), my initial concern and focus has been the Python packages we distribute on the &lt;a href=&quot;https://pypi.org/&quot;&gt;Python Package Index (PyPI)&lt;/a&gt;. These are available to use outside of Mozilla’s build system, and therefore a lack of Python 3 support will prevent any users from adopting Python 3 in their projects. One such example is &lt;a href=&quot;https://github.com/mozilla/treeherder&quot;&gt;Treeherder&lt;/a&gt;, which uses &lt;a href=&quot;https://pypi.org/project/mozlog/&quot;&gt;mozlog&lt;/a&gt; for parsing log files. Treeherder is a &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;django&lt;/a&gt; project, which recently dropped support for Python 2 (unless you’re using their long term support release, which will support Python 2 until 2020).&lt;/p&gt;

&lt;p&gt;Updating these packages to support Python 3 isn’t necessary that hard to do, especially with tools such as &lt;a href=&quot;https://pythonhosted.org/six/&quot;&gt;six&lt;/a&gt;, which provides utilities for handling the differences between Python 2 and Python 3. The problem has been that we had no way to run the tests against Python 3 in TaskCluster. This is no longer the case, and Python unit tests can now be run against Python 3!&lt;/p&gt;

&lt;p&gt;So far I have enabled Python 3 jobs for our &lt;a href=&quot;https://firefox-source-docs.mozilla.org/mozbase/index.html&quot;&gt;mozbase&lt;/a&gt; unit tests (this includes the aforementioned mozlog), and our &lt;a href=&quot;https://pypi.org/project/mozterm/&quot;&gt;mozterm&lt;/a&gt; unit tests. There are still many tests in mozbase that are not passing in Python 3, so as mentioned above, these have been conditionally skipped in the manifest files. This will allow us to enable these tests as support is added, and this condition could even be used in the future if we have a package that doesn’t have full compatibility with Python 2.&lt;/p&gt;

&lt;p&gt;Now that running the tests against multiple versions of Python is relatively easy, it’s a great time for me to encourage our community to help us with supporting Python 3. If you’d like to help, we have a &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1093212&quot;&gt;tracking bug&lt;/a&gt; for all of our mozbase packages. Find a package you’d like to work on, read the comments to understand what you need and how to get set up, and let me know if you get stuck!&lt;/p&gt;</content><author><name>Dave Hunt</name></author><summary type="html">I’m excited to announce that you can now run the Python unit tests for packages in the Firefox source code against Python 3! This will allow us to gradually build support for Python 3, whilst ensuring that we don’t later regress. Any tests not currently passing in Python 3 are skipped with the condition skip-if = python == 3 in the manifest files, so if you’d like to see how they fail (and maybe provide a patch to fix some!) then you will need to remove that condition locally. Once you’ve done this, use the mach python-test command with the new optional argument --python. This will accept a version number of Python or a path to the binary. You will need to make sure you have the appropriate version of Python installed.</summary></entry><entry><title type="html">Prototype multi-device Firefox tests</title><link href="http://davehunt.co.uk/2018/03/20/prototype-multi-device-firefox-tests.html" rel="alternate" type="text/html" title="Prototype multi-device Firefox tests" /><published>2018-03-20T14:26:25+00:00</published><updated>2018-03-20T14:26:25+00:00</updated><id>http://davehunt.co.uk/2018/03/20/prototype-multi-device-firefox-tests</id><content type="html" xml:base="http://davehunt.co.uk/2018/03/20/prototype-multi-device-firefox-tests.html">&lt;p&gt;With &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Firefox_Accounts&quot;&gt;Firefox Accounts&lt;/a&gt;, you can access your tabs, history, and bookmarks from any device. You can even send tabs from one device to another, which is great when I find myself on a page that’s not optimised for mobile, or if I get distracted at the weekend and find something I want to pick up when I get to work on Monday morning. While these features are awesome, I’ve had issues when the sync isn’t triggered, or things don’t go as expected. Some of these issues are known (and are being addressed), but currently it’s too easy for regressions to be introduced.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;Let’s take the simple use case of saving a bookmark using Firefox on your phone, and later opening the bookmark on Firefox on desktop. In this scenario we have the mobile client, the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Firefox_Accounts&quot;&gt;Firefox Accounts&lt;/a&gt; service, the &lt;a href=&quot;https://wiki.mozilla.org/CloudServices/Sync&quot;&gt;Sync&lt;/a&gt; service, and the desktop client. We could be using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox_for_Android&quot;&gt;Firefox on Android&lt;/a&gt; or &lt;a href=&quot;https://github.com/mozilla-mobile/firefox-ios&quot;&gt;iOS&lt;/a&gt; as our mobile client, and we could be using Firefox on macOS, Linux, or Windows. Other scenarios could involve multiple different mobile clients, such as syncing between a tablet and phone. There’s a lot of configuration necessary, and many variations. Whilst each of the components have their own automated tests, there’s currently no automation to take care of the basic end-to-end scenarios.&lt;/p&gt;

&lt;p&gt;Part of the issue is that there are many individual components, and many ways they can be combined. Integration testing is currently carried out manually, which is time-consuming, and doesn’t allow us to cover as many scenarios and device combinations as we’d like. Introducing automation to cover the basic scenarios will allow the testers more time to focus on exploration and more edge cases.&lt;/p&gt;

&lt;p&gt;Over the last few weeks I’ve built a proof-of-concept test harness to automate end-to-end testing of multiple clients and server components. Initially I have focused on the previously mentioned scenario of syncing a bookmark from mobile to desktop, and limited to Firefox on iOS and macOS for now. Rather than create something entirely from scratch, I’ve brought together existing solutions for this initial prototype. This allowed me to pull something together relatively quickly, but does also bring some limitations and questions along.&lt;/p&gt;

&lt;h3 id=&quot;the-scenario&quot;&gt;The Scenario&lt;/h3&gt;

&lt;p&gt;Let’s remind ourselves of our initial scenario:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Firefox on iOS:
    &lt;ul&gt;
      &lt;li&gt;Open a website&lt;/li&gt;
      &lt;li&gt;Save a bookmark&lt;/li&gt;
      &lt;li&gt;Sign into Firefox Accounts&lt;/li&gt;
      &lt;li&gt;Perform initial sync&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Firefox on macOS:
    &lt;ul&gt;
      &lt;li&gt;Sign into Firefox Accounts&lt;/li&gt;
      &lt;li&gt;Perform initial sync&lt;/li&gt;
      &lt;li&gt;Verify new bookmark exists&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, we’ll need to present these results in a way the user can interpret, and can investigate in the event of a failure. For this we’ll need a framework that can pull everything together, which is where I started.&lt;/p&gt;

&lt;h3 id=&quot;the-test-framework&quot;&gt;The Test Framework&lt;/h3&gt;

&lt;p&gt;My language of choice is Python, and my preferred test framework is &lt;a href=&quot;https://docs.pytest.org/&quot;&gt;pytest&lt;/a&gt;. Being able to use something that I’m already familiar with for the framework allowed me to focus on the more challenging areas. By using pytest I’m also able to take advantage of several plugins I have built and maintain for other projects. Finally, if we decide in the future to land any part of this into mozilla-central, it shouldn’t require too many changes as Python and pytest are already in use there.&lt;/p&gt;

&lt;h3 id=&quot;generating-firefox-accounts&quot;&gt;Generating Firefox Accounts&lt;/h3&gt;

&lt;p&gt;As a prerequisite, we need credentials for Firefox Accounts. Fortunately, we already have the &lt;a href=&quot;https://github.com/mozilla/PyFxA&quot;&gt;PyFxA&lt;/a&gt; package. This allowed me to create a pytest fixture to create accounts as needed and destroy them when they’re done with. The following is a slightly simplified version of the fixture, which creates an account, verifies it, and ultimately destroys it once it’s no longer needed:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fx_account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestEmailAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'https://api-accounts.stage.mozaws.net/v1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ascii_letters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wait_for_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'x-verify-code'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'headers'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;verify_email_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'headers'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'x-verify-code'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'email'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'password'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroy_account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Whilst building out the prototype it was useful to have a Firefox Account that wasn’t immediately destroyed, which is why I &lt;a href=&quot;/2018/03/15/command-line-tool-for-firefox-accounts.html&quot;&gt;built a command line tool for creating and destroying accounts&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;automating-firefox-on-ios&quot;&gt;Automating Firefox on iOS&lt;/h3&gt;

&lt;p&gt;Fortunately there is already a suite of &lt;a href=&quot;https://github.com/mozilla-mobile/firefox-ios/tree/master/XCUITests&quot;&gt;automated UI tests for Firefox on iOS&lt;/a&gt;, so I was able to build on the existing code. For our scenario I was able to get away with only making a few changes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Created an &lt;code class=&quot;highlighter-rouge&quot;&gt;IntegrationTests.swift&lt;/code&gt; file for the new script. Note that although this is technically a test itself, I’m referring to it as a script. This is because it only forms part of the overall integration test, and is essentially executed as a script. Of course, any failure encountered while running it will result in a test failure.&lt;/li&gt;
  &lt;li&gt;Added &lt;code class=&quot;highlighter-rouge&quot;&gt;LaunchArguments.StageServer&lt;/code&gt; as a launch argument in  &lt;code class=&quot;highlighter-rouge&quot;&gt;BaseTestCase.swift&lt;/code&gt; so the staging environment would be used for Firefox Accounts and Sync.&lt;/li&gt;
  &lt;li&gt;Switched from using &lt;code class=&quot;highlighter-rouge&quot;&gt;type&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;typeText&lt;/code&gt; in &lt;code class=&quot;highlighter-rouge&quot;&gt;FxScreenGraph.swift&lt;/code&gt; for the Firefox Accounts login screen. This allowed entry of characters not displayed on the initial keyboard layout. If we want to use the on screen keyboard, then we’ll need to enhance the screen graph to support switching layouts. Alternatively, we could avoid using such characters.&lt;/li&gt;
  &lt;li&gt;Added the ability to set the timeout for &lt;code class=&quot;highlighter-rouge&quot;&gt;waitforExistence&lt;/code&gt; as loading the Firefox Accounts login screen and performing the initial sync were occasionally taking longer than the default of 5 seconds.&lt;/li&gt;
  &lt;li&gt;Modified the existing &lt;code class=&quot;highlighter-rouge&quot;&gt;Fennec_Enterprise_XCUITests&lt;/code&gt; scheme to include environment variables for the Firefox Account email and password so they can be used from the script.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these changes, I was able to create the script to open a website and save it as a bookmark:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;testFxASyncBookmark&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Go to a webpage, and add to bookmarks&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createNewTab&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;loadWebPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;www.example.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nowAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BrowserTab&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;bookmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Sign into Firefox Accounts&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FxASigninScreen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;waitforExistence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;webViews&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;staticTexts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Sign in&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;userState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fxaUsername&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ProcessInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;processInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;FXA_EMAIL&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;userState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fxaPassword&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ProcessInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;processInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;FXA_PASSWORD&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;performAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FxATypeEmail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;performAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FxATypePassword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;performAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FxATapOnSignInButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;allowNotifications&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Wait for initial sync to complete&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;waitforExistence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tables&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;staticTexts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Sync Now&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To run XCUITests from outside of Xcode, you need to use the &lt;code class=&quot;highlighter-rouge&quot;&gt;xcodebuild&lt;/code&gt; command line tool. So, using FxACLI to create a test account, I can run my new script using the following commands:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ fxacli create
Account created!
 - 🌐  https://api-accounts.stage.mozaws.net/v1
 - 📧  test-a478e06856@restmail.net
 - 🔑  CokFkuRA
Account verified! 🎉
$ export FXA_EMAIL=test-a478e06856@restmail.net FXA_PASSWORD=CokFkuRA
$ xcodebuild test -scheme Fennec_Enterprise_XCUITests -destination &quot;platform=iOS Simulator,name=iPhone X&quot; -only-testing:XCUITests/IntegrationTests/testFxASyncBookmark
--- snip ---
** TEST SUCCEEDED **
$ fxcli destroy
Account destroyed! 💥
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to run the script from my pytest framework, I created a fixture named &lt;code class=&quot;highlighter-rouge&quot;&gt;xcodebuild&lt;/code&gt;. This fixture patches the environment with the Firefox Account variables, and yields an &lt;code class=&quot;highlighter-rouge&quot;&gt;XCodeBuild&lt;/code&gt; object:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;xcodebuild_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytestconfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;xcodebuild_log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'xcodebuild.log'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pytestconfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_xcodebuild_log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xcodebuild_log&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xcodebuild_log&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;xcodebuild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fx_account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xcodebuild_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'FXA_EMAIL'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fx_account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'FXA_PASSWORD'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fx_account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;XCodeBuild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xcodebuild_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;XCodeBuild&lt;/code&gt; object has a &lt;code class=&quot;highlighter-rouge&quot;&gt;test&lt;/code&gt; method, which requires the identifier of the test to run. When the &lt;code class=&quot;highlighter-rouge&quot;&gt;test&lt;/code&gt; method is called, the &lt;code class=&quot;highlighter-rouge&quot;&gt;xcodebuild&lt;/code&gt; binary is started in a new process, and the output is redirected to a log file to later attach to the HTML report. The following test, although incomplete at this point, demonstrates running the XCUITest from pytest:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_sync_bookmark_from_device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xcodebuild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;xcodebuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'XCUITests/IntegrationTests/testFxASyncBookmark'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I noticed early on that once a test has signed into Firefox Accounts, the next test to run will remember the email address used and only ask for a password when attempting to sign in. There’s likely a less expensive solution, but for now I’ve resolved this by running &lt;code class=&quot;highlighter-rouge&quot;&gt;xcrun simctl shutdown all&lt;/code&gt; to shutdown all simulators, followed by &lt;code class=&quot;highlighter-rouge&quot;&gt;xcrun simctl erase all&lt;/code&gt; to wipe them.&lt;/p&gt;

&lt;h3 id=&quot;automating-firefox-on-desktop&quot;&gt;Automating Firefox on Desktop&lt;/h3&gt;

&lt;p&gt;So far we’ve added a bookmark in Firefox on iOS and performed an initial sync. We now need to sign into Firefox Accounts on desktop Firefox, perform a sync, and verify the new bookmark is added. Like our UI tests for Firefox on iOS, we already have a solution for performing integration tests for Sync. It’s called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Projects/TPS_Tests&quot;&gt;TPS&lt;/a&gt;, and I with the following tweaks I was able to get it to work for my prototype:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Added “mobile” bookmark folder to &lt;code class=&quot;highlighter-rouge&quot;&gt;bookmarks.jsm&lt;/code&gt;, which is necessary to verify bookmarks in this location.&lt;/li&gt;
  &lt;li&gt;Removed attempt to load and validate the ping schema. The &lt;code class=&quot;highlighter-rouge&quot;&gt;_tryLoadPingSchema&lt;/code&gt; method attempts to read a schema file from disk, which isn’t present for my prototype so I’ve removed that, and another related code path.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The source code for TPS is stored in mozilla-central, and I don’t want the entire repository to be a requirement for running my prototype. If we decide that TPS is the best approach for these tests, then we’d probably need to find a better way to share the code than my current approach of simply copying the extension source code and making local changes.&lt;/p&gt;

&lt;p&gt;TPS works by launching Firefox with the extension installed and passing an argument to the test to run. This means it’s necessary for us to write a TPS test in JavaScript for our scenario:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;EnableEngines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;bookmarks&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phases&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;phase1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;profile1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// expected bookmark state&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bookmarksExpected&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mobile&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;http://www.example.com/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Example Domain&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// sync and verify bookmarks&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;phase1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Bookmarks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bookmarksExpected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The phases allow Firefox to be restarted and for syncing to be performed across multiple profiles. Whilst this could be useful, I’ve currently enforced a single phase/profile for my prototype.&lt;/p&gt;

&lt;p&gt;There’s already a TPS test runner written in Python, so I was able to selectively pick what I needed for my prototype. I created several pytest fixtures that work together to package the TPS extension, configure a Firefox profile, and in a similar to our &lt;code class=&quot;highlighter-rouge&quot;&gt;xcodebuild&lt;/code&gt; fixture, provide an interface for executing a test:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'session'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tps_addon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpdir_factory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpdir_factory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mktemp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'addon'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'tps'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;shutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_archive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'zip'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;here&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'tps'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'{}.zip'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'{}.xpi'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'{}.xpi'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tps_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fx_account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'fx_account'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'username'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fx_account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'password'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fx_account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tps_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytestconfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tps_log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'tps.log'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pytestconfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_tps_log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_log&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_log&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tps_profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tps_addon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;preferences&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'extensions.autoDisableScopes'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'extensions.legacy.enabled'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'identity.fxaccounts.autoconfig.uri'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'content'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'tps.config'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tps_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'tps.logfile'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'tps.seconds_since_epoch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'xpinstall.signatures.required'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addons&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tps_addon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;preferences&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixture&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytestconfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pytestconfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getoption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'firefox'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tps_profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I also added a required command line option for the path to Firefox. The TPS test runner actually downloads the latest Firefox nightly, which could be an option in the future.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;TPS&lt;/code&gt; object provided by the &lt;code class=&quot;highlighter-rouge&quot;&gt;tps&lt;/code&gt; fixture provides a &lt;code class=&quot;highlighter-rouge&quot;&gt;run&lt;/code&gt; method, which takes a test file as an argument. After adding this to our Python test we have something that looks like this:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_sync_bookmark_from_device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xcodebuild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;xcodebuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'XCUITests/IntegrationTests/testFxASyncBookmark'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'test_bookmark.js'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we have a working prototype that satisfies our scenario. Note that there’s not much to see while the TPS test is running, however if you open the settings menu in Firefox you can watch the state transition from not signed in, to signed in, and the initial sync being performed. If you’re really quick you can also see the mobile bookmark appearing in the menu.&lt;/p&gt;

&lt;h3 id=&quot;running-the-tests&quot;&gt;Running the Tests&lt;/h3&gt;

&lt;p&gt;To run the tests you will need to first follow the instructions for &lt;a href=&quot;https://github.com/mozilla-mobile/firefox-ios#building-the-code&quot;&gt;building Firefox on iOS&lt;/a&gt;. You will also need to ensure you have &lt;a href=&quot;http://docs.python-guide.org/en/latest/starting/installation/#legacy-python-2-installation-guides&quot;&gt;legacy Python&lt;/a&gt; (2.7) installed (there are dependencies that have not yet been updated to support modern Python). Finally, install &lt;a href=&quot;https://docs.pipenv.org/&quot;&gt;pipenv&lt;/a&gt;, which will take care of the remaining Python dependencies.&lt;/p&gt;

&lt;p&gt;You can then run the tests as follows, making sure you set the correct path to your Firefox binary:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd python
$ pipenv install
$ pipenv run pytest --firefox=/path/to/Firefox.app/Contents/MacOS/firefox-bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The tests will build and install the application to the simulator, which can cause a delay where there will be no feedback to the user. Also, note that each XCUITest that is executed will shutdown and &lt;strong&gt;erase data from all available iOS simulators&lt;/strong&gt;. This assures that each execution starts from a known clean state.&lt;/p&gt;

&lt;h3 id=&quot;reviewing-results&quot;&gt;Reviewing Results&lt;/h3&gt;

&lt;p&gt;Hopefully you’ll see something like the following in your console:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ pipenv run pytest --firefox=/path/to/Firefox.app/Contents/MacOS/firefox-bin
============================= test session starts =============================
platform darwin -- Python 2.7.13, pytest-3.4.2, py-1.5.2, pluggy-0.6.0 -- /path/to/python2.7
cachedir: .pytest_cache
rootdir: /path/to/firefox-ios/python, inifile: pytest.ini
plugins: metadata-1.6.0, html-1.16.1, mozlog-3.7
collected 1 item

test_integration.py::test_sync_bookmark_from_device PASSED               [100%]

-------------- generated html file: /path/to/results/index.html ---------------
========================= 1 passed in 273.26 seconds ==========================
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even if the test fails, you should see the ‘generated html file’ somewhere in your console. Open this file in Firefox to review the results. If there was a failure, the report will include the details as shown in the console. You’ll also find environment details including the version of desktop Firefox being used.&lt;/p&gt;

&lt;p&gt;For each test there’s a link to logs for TPS and xcodebuild. At the moment these are included regardless of the outcome, however they’re mostly valuable for investigating failures. In the future we may decide to exclude them when tests pass.&lt;/p&gt;

&lt;h3 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h3&gt;

&lt;p&gt;Well, the next thing is to gather feedback on this prototype. Does it make sense to use XCUITests, TPS, and pytest, or have I missed something that would improve the integration testing between multiple devices? If you’ve read this far, I suspect you have some opinions. Please get in touch by leaving a comment or finding me on IRC, Slack, Twitter, email, etc!&lt;/p&gt;

&lt;p&gt;After I’ve given some time for feedback to reach me, we’ll need to device how to rollout the prototype so that it can start to provide value. Initially we might start with a dedicated Mac Mini available via remote access to trigger the tests.&lt;/p&gt;

&lt;p&gt;Then we’ll need to review the test cases that we’d want to write. Ideally we’d keep the suite relatively small, as the tests will take some time to run. The idea is to cover the basic functionality where risk is high, and the more obscure scenarios will be covered by manual testing.&lt;/p&gt;

&lt;p&gt;Other ideas for future plans include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pre-populate Firefox with history instead of creating them through the user interface. Our prototype test loads a website and adds it to the bookmarks as a user would. Doing it this way is slow and prone to failure, so if we can pre-populate Firefox with this it would be an improvement.&lt;/li&gt;
  &lt;li&gt;Experiment with going back-and-forth between devices. This could be achieved by saving and restoring state between sessions, or by using an alternative tools that would allow for switching between multiple concurrent sessions.&lt;/li&gt;
  &lt;li&gt;Create a prototype for Firefox on Android. Perhaps we can reuse parts of this prototype, although we’d probably look into using some combination of UIAutomator, Espresso, and Appium for the Android automation parts.&lt;/li&gt;
  &lt;li&gt;Experiment with Appium as an alternative to XCUITest. I went with XCUITest because we already had something in place, but perhaps there’s some value in switching these tests to using Appium. It’s at least worth investigating.&lt;/li&gt;
  &lt;li&gt;Experiment with introducing WebDriver to the prototype. If we have a scenario that requires us to interact with either Firefox or web content (such as Firefox Accounts) then we may need to introduce WebDriver (Selenium).&lt;/li&gt;
  &lt;li&gt;Look into setting up Continuous Integration for these tests. If the tests prove to be valuable and stable, then it would be ideal to run them whenever a new version of Firefox is avaiable. This could be a simple cron schedule, or something like a Jenkins agent running the tests when triggered.&lt;/li&gt;
  &lt;li&gt;Create a prototype for Firefox on other devices. In the future we may have Firefox Accounts integration in Firefox for FireTV, so it would be great if we could include coverage here, too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve been pushing my code to a branch on my fork of Firefox on iOS. You can see a comparison between my branch and the upstream master &lt;a href=&quot;https://github.com/mozilla-mobile/firefox-ios/compare/master...davehunt:integration&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;demo&quot;&gt;Demo&lt;/h3&gt;

&lt;p&gt;If you’re unable to run the tests locally, here’s a recording of the test running along with reviewing the HTML report and logs:&lt;/p&gt;

&lt;style&gt;.embed-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; } .embed-container iframe, .embed-container object, .embed-container embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }&lt;/style&gt;
&lt;div class=&quot;embed-container&quot;&gt;    &lt;iframe title=&quot;YouTube video player&quot; width=&quot;640&quot; height=&quot;390&quot; src=&quot;//www.youtube.com/embed/44DOpj4c07U&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;</content><author><name>Dave Hunt</name></author><summary type="html">With Firefox Accounts, you can access your tabs, history, and bookmarks from any device. You can even send tabs from one device to another, which is great when I find myself on a page that’s not optimised for mobile, or if I get distracted at the weekend and find something I want to pick up when I get to work on Monday morning. While these features are awesome, I’ve had issues when the sync isn’t triggered, or things don’t go as expected. Some of these issues are known (and are being addressed), but currently it’s too easy for regressions to be introduced.</summary></entry><entry><title type="html">Command line tool for Firefox Accounts</title><link href="http://davehunt.co.uk/2018/03/15/command-line-tool-for-firefox-accounts.html" rel="alternate" type="text/html" title="Command line tool for Firefox Accounts" /><published>2018-03-15T10:27:39+00:00</published><updated>2018-03-15T10:27:39+00:00</updated><id>http://davehunt.co.uk/2018/03/15/command-line-tool-for-firefox-accounts</id><content type="html" xml:base="http://davehunt.co.uk/2018/03/15/command-line-tool-for-firefox-accounts.html">&lt;p&gt;When testing services that depend on &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Firefox_Accounts&quot;&gt;Firefox Accounts&lt;/a&gt;, it’s useful to be able to create disposable test accounts. Fortunately we’ve had this ability from the very early days of the service, and our automated tests make heavy use of &lt;a href=&quot;https://github.com/mozilla/PyFxA&quot;&gt;PyFxA&lt;/a&gt; to create, verify, and ultimately destroying accounts. As useful as this is, it hasn’t been particularly easy to create accounts for the purposes of manual testing. For the rare occasion that I’ve needed an account, I’ve either created them manually via main user interface with a disposable email account, or I’ve created a simple one-off script to create a batch of accounts. As I had this need again recently, I decided to write a simple command line tool for creating verified accounts and subsequently destroying them.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;To use the tool, you’ll need Python (despite a dependency not claiming to have support for Python 3, it’s working fine for me using 3.6) and pip. It can then be installed by simply running &lt;code class=&quot;highlighter-rouge&quot;&gt;pip install fxacli&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Any account created by the tool will be stored in a JSON file named &lt;code class=&quot;highlighter-rouge&quot;&gt;.accounts&lt;/code&gt; in the working directory. This allows for one or more accounts to be created, and then destroyed without the need to specify the target account.&lt;/p&gt;

&lt;p&gt;To create an account:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ fxacli create
Account created!
 - 🌐  https://api-accounts.stage.mozaws.net/v1
 - 📧  test-72a888a3f6@restmail.net
 - 🔑  IvOhSLzI
Account verified! 🎉
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To destroy the most recently created account:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ fxacli destroy
Account destroyed! 💥
 - 🌐  https://api-accounts.stage.mozaws.net/v1
 - 📧  test-72a888a3f6@restmail.net
 - 🔑  IvOhSLzI
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To destroy all accounts created using the tool, pass the &lt;code class=&quot;highlighter-rouge&quot;&gt;--all&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;If you want to destroy an account not created by the tool, or if your &lt;code class=&quot;highlighter-rouge&quot;&gt;.accounts&lt;/code&gt; file is for any reason unreadable, you can pass &lt;code class=&quot;highlighter-rouge&quot;&gt;--email&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;--password&lt;/code&gt; options.&lt;/p&gt;

&lt;p&gt;By default all accounts will be created/destroyed from the staging instance of Firefox Accounts. This is highly recommended, but if you know what you’re doing, the target environment can be specified using the &lt;code class=&quot;highlighter-rouge&quot;&gt;--env&lt;/code&gt; command line option.&lt;/p&gt;

&lt;p&gt;Visit the &lt;a href=&quot;https://pypi.python.org/pypi/fxacli&quot;&gt;FxACLI package on PyPI&lt;/a&gt; for links to the source code, issue tracker, and more.&lt;/p&gt;</content><author><name>Dave Hunt</name></author><summary type="html">When testing services that depend on Firefox Accounts, it’s useful to be able to create disposable test accounts. Fortunately we’ve had this ability from the very early days of the service, and our automated tests make heavy use of PyFxA to create, verify, and ultimately destroying accounts. As useful as this is, it hasn’t been particularly easy to create accounts for the purposes of manual testing. For the rare occasion that I’ve needed an account, I’ve either created them manually via main user interface with a disposable email account, or I’ve created a simple one-off script to create a batch of accounts. As I had this need again recently, I decided to write a simple command line tool for creating verified accounts and subsequently destroying them.</summary></entry><entry><title type="html">Effective CI for Firefox projects developed in GitHub</title><link href="http://davehunt.co.uk/2017/06/28/effective-ci-for-firefox-projects-developed-in-github.html" rel="alternate" type="text/html" title="Effective CI for Firefox projects developed in GitHub" /><published>2017-06-28T00:00:00+01:00</published><updated>2017-06-28T00:00:00+01:00</updated><id>http://davehunt.co.uk/2017/06/28/effective-ci-for-firefox-projects-developed-in-github</id><content type="html" xml:base="http://davehunt.co.uk/2017/06/28/effective-ci-for-firefox-projects-developed-in-github.html">&lt;p&gt;Whilst the &lt;a href=&quot;https://hg.mozilla.org/&quot;&gt;canonical repository&lt;/a&gt; for the Firefox
source code uses &lt;a href=&quot;https://www.mercurial-scm.org/&quot;&gt;Mercurial&lt;/a&gt;, it’s becoming
increasingly popular for Firefox projects to use &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;
for development. When it’s time to ship, many of these projects will land their
code inside the canonical repository for inclusion in the upcoming Firefox
release. There are a few challenges that come with this approach.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;Primarily, we won’t know when a change in the project introduces a regression in
Firefox until we attempt to land the project alongside the Firefox source code.
Similarly, we won’t know when a change to Firefox might cause a regression in
the project.&lt;/p&gt;

&lt;p&gt;This quarter I spent some time discussing these issues, learning how different
teams are addressing the problems, and helping to define a more generic approach
for the future.&lt;/p&gt;

&lt;h2 id=&quot;current-solutions&quot;&gt;Current solutions&lt;/h2&gt;
&lt;p&gt;Here’s a summary of some the solutions I discovered teams are using:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mozilla/activity-stream&quot;&gt;ActivityStream&lt;/a&gt; are adding
their project to a local copy of the Firefox source code and pushing to an
alternate branch. This then runs all the tests and reports results to
&lt;a href=&quot;https://treeherder.mozilla.org/#/jobs?repo=pine&quot;&gt;Treeherder&lt;/a&gt;. This relies on
access to the alternate branch, and is currently a manual process.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mozilla/normandy&quot;&gt;Normandy&lt;/a&gt; download an archive from
&lt;a href=&quot;https://github.com/mozilla/gecko-dev&quot;&gt;gecko-dev&lt;/a&gt; (a read-only Git mirror of
the Firefox repository), combine this with the project repository, build
Firefox, and run project specific tests. Every two weeks or so, they bundle
the changes up and push to the Firefox repository.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/devtools-html/debugger.html&quot;&gt;debugger.html&lt;/a&gt; use a Docker
image with the Firefox source code, and run project specific tests in
&lt;a href=&quot;https://circleci.com/&quot;&gt;Circle CI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;proposed-solution&quot;&gt;Proposed solution&lt;/h2&gt;
&lt;p&gt;Whilst I wasn’t able to pull together a prototype this quarter, I did draft a
proposal based on my investigations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Each project would create an entry script &lt;code class=&quot;highlighter-rouge&quot;&gt;mcmerge.sh&lt;/code&gt;, which would be
responsible for integrating the project source code with the Firefox source
code. In some instances this might simply copy files, but it could also apply
patches as needed.&lt;/li&gt;
  &lt;li&gt;Whenever a pull request is opened against the GitHub project, or a change is
pushed:
    &lt;ul&gt;
      &lt;li&gt;Check if the author of the pull/push is authorised to trigger continuous
 integration. This might be that they’re a repository collaborator, or have
 authority to push to the main Firefox repository. If they are not
 authorised, we stop here.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Prepare a new patch using the
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1357597&quot;&gt;vcssync&lt;/a&gt; tool
currently in development, which will take the entire GitHub project repository
at the current revision and apply it in the patch to a vacant subdirectory in
the Firefox repository.&lt;/li&gt;
  &lt;li&gt;Push the prepared patch to our &lt;a href=&quot;https://wiki.mozilla.org/Try&quot;&gt;Try Server&lt;/a&gt;,
which will trigger tests according to the commit message. This syntax should
be configurable in the project repository, but would likely default to all
platforms/tests.&lt;/li&gt;
  &lt;li&gt;If triggered by a pull request, publish a comment indicating that the tests
have been triggered and linking to the results in Treeherder.&lt;/li&gt;
  &lt;li&gt;During the regular Firefox build, we’d scan for these projects and execute
any &lt;code class=&quot;highlighter-rouge&quot;&gt;mcmerge.sh&lt;/code&gt; scripts we encountered. This would integrate the project with
the Firefox source code.&lt;/li&gt;
  &lt;li&gt;Build Firefox and execute the tests as usual.&lt;/li&gt;
  &lt;li&gt;Reviewers of the pull request would be expected to check the results of the
Try push as part of their review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also identified a few possible directions this may evolve in the future:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We could use the same mechanism to automatically land changes that are pushed
to the GitHub repository into the Firefox repository. This would mean that the
Firefox repository would effectively hold a read-only mirror of the GitHub
project. This would remove the need for manually pushing the project to the
Firefox repository, and would allow us to determine when changes to the Firefox
source code causes regressions in the GitHub projects. This may not be
desirable for all projects, and would have implications for the sheriffs, who
may need to back out changes that cause bustage.&lt;/li&gt;
  &lt;li&gt;Rather than perform full builds of Firefox, we may be able to optimise these
in a similar fashion to the artefact builds. This isn’t something we can do
now, but it is a desirable build optimisation for other reasons.&lt;/li&gt;
  &lt;li&gt;Due to the intermittent nature of our tests, it’s not currently possible to
give a pass/fail indication in the GitHub pull request. If the scope of the
tests is narrow enough and they’re stable, it’s possible we could enhance this
to poll for the result and indicate the outcome in the pull.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;As mentioned, I was unfortunately not able to bring together a prototype based
on my proposal. I discovered early on that I wasn’t the only one looking into
this, and I even feel that the other work in this area is already in better
hands. The work in
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1364561&quot;&gt;bug 1364561&lt;/a&gt; and
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1357597&quot;&gt;bug 1357597&lt;/a&gt; are
particularly relevant to this project. It’s possible that I’ll return to this
project in the future, but for now I’ll be following the progress and
contributing to the discussions without actively working on the implementation.&lt;/p&gt;</content><author><name>Dave Hunt</name></author><category term="firefox" /><category term="continuous integration" /><category term="github" /><summary type="html">Whilst the canonical repository for the Firefox source code uses Mercurial, it’s becoming increasingly popular for Firefox projects to use GitHub for development. When it’s time to ship, many of these projects will land their code inside the canonical repository for inclusion in the upcoming Firefox release. There are a few challenges that come with this approach.</summary></entry><entry><title type="html">Reporting test results to Treeherder</title><link href="http://davehunt.co.uk/2017/04/10/reporting-test-results-to-treeherder.html" rel="alternate" type="text/html" title="Reporting test results to Treeherder" /><published>2017-04-10T00:00:00+01:00</published><updated>2017-04-10T00:00:00+01:00</updated><id>http://davehunt.co.uk/2017/04/10/reporting-test-results-to-treeherder</id><content type="html" xml:base="http://davehunt.co.uk/2017/04/10/reporting-test-results-to-treeherder.html">&lt;p&gt;Many of the web and services automated tests at Mozilla run in Jenkins, and until recently our instance was public. This meant it was easy for both paid and volunteer contributors to discover test failures, file issues, and provide fixes either for the tests or the projects they serve. Unfortunately, just like any software, Jenkins has had some security vulnerabilities. Last year, one of these prompted us to remove public access to our instance.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;As Jenkins is much more than just a dashboard of results, a compromised instance could cause loss of data, or worse, remote execution of code. Since removing access to Jenkins, we’ve been looking into alternative ways to share our test results publicly.&lt;/p&gt;

&lt;p&gt;Last month &lt;a href=&quot;/2017/03/21/analysing-pytest-results-using-activedata.html&quot;&gt;I wrote about&lt;/a&gt; how we’re making the test results accessible via &lt;a href=&quot;https://wiki.mozilla.org/EngineeringProductivity/Projects/ActiveData&quot;&gt;ActiveData&lt;/a&gt;. This allows anyone to query our results and perform data analysis and visualisation on them. Whilst this is going to prove to be a valuable tool, it doesn’t provide a convenient dashboard for the results and is unlikely to attract much interest from the community.&lt;/p&gt;

&lt;p&gt;The next step is submitting our results to &lt;a href=&quot;https://wiki.mozilla.org/EngineeringProductivity/Projects/Treeherder&quot;&gt;Treeherder&lt;/a&gt; - a public dashboard for commits to Mozilla projects, which displays results of tasks such as builds, linting, and automated tests. Treeherder can be used to monitor the health of projects, and as a tool for investigating failures and raising defects, making it the perfect home for our test results.&lt;/p&gt;

&lt;p&gt;The remainder of this post details the steps necessary to submit our test results to Treeherder. Note that whilst working on this I had local instances of most of the services and applications involved. This is a good practice as it reduces latency, and means you’re not filling up an live instances with experimental test data.&lt;/p&gt;

&lt;h2 id=&quot;creating-a-pulse-user&quot;&gt;Creating a Pulse user&lt;/h2&gt;
&lt;p&gt;Treeherder ingests information about jobs from &lt;a href=&quot;https://wiki.mozilla.org/Auto-tools/Projects/Pulse&quot;&gt;Pulse&lt;/a&gt; exchanges. Pulse is a RabbitMQ cluster, and if you’re unfamiliar (as I was), I can highly recommend the &lt;a href=&quot;http://www.rabbitmq.com/getstarted.html&quot;&gt;tutorials&lt;/a&gt; to learn more. The first step was to sign into &lt;a href=&quot;https://pulseguardian.mozilla.org/&quot;&gt;PulseGuardian&lt;/a&gt; and create a user for publishing our messages.&lt;/p&gt;

&lt;h2 id=&quot;adding-project-repositories&quot;&gt;Adding project repositories&lt;/h2&gt;
&lt;p&gt;To have our project repositories shown in Treeherder, it’s necessary to &lt;a href=&quot;http://treeherder.readthedocs.io/submitting_data.html#adding-a-github-repository&quot;&gt;tell Treeherder about them&lt;/a&gt;. Then, to get result sets showing up you’ll need to add &lt;a href=&quot;https://github.com/integration/taskcluster&quot;&gt;TaskCluster integration&lt;/a&gt; for the repositories. For each revision, TaskCluster will send a message to Pulse, which Treeherder uses to build a collection of result sets for each repository. Note that you will need a GitHub organisation owner or repository administrator to enable TaskCluster integration. It’s also worth noting that historic revisions will not be available in Treeherder, so only new commits will show up.&lt;/p&gt;

&lt;h2 id=&quot;generating-a-message&quot;&gt;Generating a message&lt;/h2&gt;
&lt;p&gt;Treeherder provides a &lt;a href=&quot;https://github.com/mozilla/treeherder/blob/master/schemas/pulse-job.yml&quot;&gt;schema&lt;/a&gt; that messages are expected to validate against. As we’re using Jenkins, and have recently &lt;a href=&quot;/2017/03/23/migrating-to-declarative-jenkins-pipelines.html&quot;&gt;migrated to declarative pipelines&lt;/a&gt; with a &lt;a href=&quot;https://github.com/mozilla/fxtest-jenkins-pipeline&quot;&gt;shared library&lt;/a&gt;, I wrote a &lt;code class=&quot;highlighter-rouge&quot;&gt;submitToTreeherder&lt;/code&gt; step to generate the payload using &lt;a href=&quot;https://github.com/daveclayton/json-schema-validator&quot;&gt;json-schema-validator&lt;/a&gt; to ensure we’re conforming to the schema. Whilst developing locally I used a simple Python script based on the &lt;a href=&quot;http://www.rabbitmq.com/getstarted.html&quot;&gt;RabbitMQ tutorials&lt;/a&gt;, as this made it much easier to iterate on the payload. Interestingly, this validation actually highlighted a couple of issues with the schema (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1352402&quot;&gt;1352402&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1352403&quot;&gt;1352403&lt;/a&gt;). I also encountered issues with the Jenkins pipelines (&lt;a href=&quot;https://issues.jenkins-ci.org/browse/JENKINS-43195&quot;&gt;JENKINS-43195&lt;/a&gt;, &lt;a href=&quot;https://issues.jenkins-ci.org/browse/JENKINS-43246&quot;&gt;JENKINS-43246&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;submitting-the-message&quot;&gt;Submitting the message&lt;/h2&gt;
&lt;p&gt;Once the message has been generated and validated against the schema, we send it as our Pulse user to an exchange including the username with a routing key that contains the username and project. Our Pulse username is &lt;code class=&quot;highlighter-rouge&quot;&gt;fxtesteng&lt;/code&gt;, so our exchange would be &lt;code class=&quot;highlighter-rouge&quot;&gt;exchange/fxtesteng/jobs&lt;/code&gt;, and for the &lt;a href=&quot;https://github.com/mozilla/fxapom&quot;&gt;FxAPOM&lt;/a&gt; project our routing key would be &lt;code class=&quot;highlighter-rouge&quot;&gt;fxtesteng.fxapom&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;using-pulse-inspector&quot;&gt;Using Pulse Inspector&lt;/h2&gt;
&lt;p&gt;At this point Treeherder isn’t aware of the new exchange, but you can use &lt;a href=&quot;https://tools.taskcluster.net/pulse-inspector/&quot;&gt;Pulse Inspector&lt;/a&gt; to listen on a specified exchange and routing key pattern to see the messages as they’re received by Pulse. If you want to listen to all messages published to the Firefox Test Engineering exchange for Treeherder jobs, enter the exchange &lt;code class=&quot;highlighter-rouge&quot;&gt;exchange/fxtesteng/jobs&lt;/code&gt; and click ‘Start Listening’. Note that traffic on this exchange is currently very low, but it’s useful if you’ve triggered a job and want to see what’s being sent.&lt;/p&gt;

&lt;h2 id=&quot;registering-with-treeherder&quot;&gt;Registering with Treeherder&lt;/h2&gt;
&lt;p&gt;Now that we’re sending messages for each job, all that’s left is to &lt;a href=&quot;file:///Users/dhunt/workspace/treeherder/docs/_build/html/submitting_data.html#register-with-treeherder&quot;&gt;tell Treeherder about your exchange&lt;/a&gt;. Once that’s done, the next job published to Pulse should be picked up by Treeherder and displayed under the appropriate repository. The following screenshot shows FxAPOM results in Treeherder.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/treeherder-fxapom.png&quot; alt=&quot;FxAPOM results in Treeherder&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href=&quot;https://treeherder.allizom.org/#/jobs?repo=fxapom&amp;amp;revision=cd87f7f8bb06ff035ac716081e01a6f55046911d&quot;&gt;see these for yourself&lt;/a&gt;, and take a look at the log files, HTML reports and other details for the results.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;
&lt;p&gt;At the time of writing, only FxAPOM is configured to submit results to Treeherder. This repository has a low volume of commits, and the tests are run once a day. Next, we’d like to submit results for more of our repositories. As we’re using our shared library, this is a relatively small change for most of our projects. There are also &lt;a href=&quot;https://github.com/mozilla/fxtest-jenkins-pipeline/labels/treeherder&quot;&gt;a number of enhancements&lt;/a&gt; filed for the shared library, which will improve the display of the results in Treeherder. If you’re interested in working on any of these, please add a comment and I’d be happy to mentor you.&lt;/p&gt;

&lt;p&gt;I’d like to think that this model could be repeated for other continuous integration services. It’s already provided by TaskCluster, but there’s certainly some value in submitting results from &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt; or &lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt;. That said, there are no current plans to implement this (that I’m aware of). If this is something you’d like to work on, let me know!&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;I would like to say thanks to the Treeherder team for their assistance and considerable patience whilst I worked on this.
I’d also like to thank &lt;a href=&quot;https://github.com/abayer&quot;&gt;Andrew Bayer&lt;/a&gt; from the Jenkins team for his encouragement and assistance while I battled through a few Groovy and Jenkins pipeline issues. Whenever we’re in the same city, I definitely owe that guy a drink!&lt;/p&gt;</content><author><name>Dave Hunt</name></author><category term="treeherder" /><category term="mozilla" /><category term="pulse" /><category term="jenkins" /><summary type="html">Many of the web and services automated tests at Mozilla run in Jenkins, and until recently our instance was public. This meant it was easy for both paid and volunteer contributors to discover test failures, file issues, and provide fixes either for the tests or the projects they serve. Unfortunately, just like any software, Jenkins has had some security vulnerabilities. Last year, one of these prompted us to remove public access to our instance.</summary></entry><entry><title type="html">Migrated content from seleniumexamples.com</title><link href="http://davehunt.co.uk/2017/03/24/migrated-content-from-seleniumexamples-com.html" rel="alternate" type="text/html" title="Migrated content from seleniumexamples.com" /><published>2017-03-24T00:00:00+00:00</published><updated>2017-03-24T00:00:00+00:00</updated><id>http://davehunt.co.uk/2017/03/24/migrated-content-from-seleniumexamples-com</id><content type="html" xml:base="http://davehunt.co.uk/2017/03/24/migrated-content-from-seleniumexamples-com.html">&lt;p&gt;I ran a blog at seleniumexamples.com from 2009-2011, where I posted examples
for using Selenium. This content has been unavailable for some time, so I
decided to migrate it here. Many of the examples are unlikely to work, and I
didn’t bother to migrate comments, but it might at least prove interesting to
some. Personal highlights include &lt;a href=&quot;/2010/05/25/play-pacman-with-selenium-2.html&quot;&gt;playing Pacman&lt;/a&gt;,
&lt;a href=&quot;/2009/11/25/a-successful-first-london-selenium-meetup.html&quot;&gt;the first London meetup&lt;/a&gt;, and &lt;a href=&quot;/2010/11/07/cheesecake.html&quot;&gt;cheesecake&lt;/a&gt;. You can find the entire
archive &lt;a href=&quot;/tag/seleniumexamples.com.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content><author><name>Dave Hunt</name></author><category term="migration" /><category term="seleniumexamples.com" /><summary type="html">I ran a blog at seleniumexamples.com from 2009-2011, where I posted examples for using Selenium. This content has been unavailable for some time, so I decided to migrate it here. Many of the examples are unlikely to work, and I didn’t bother to migrate comments, but it might at least prove interesting to some. Personal highlights include playing Pacman, the first London meetup, and cheesecake. You can find the entire archive here.</summary></entry><entry><title type="html">Migrating to declarative Jenkins pipelines</title><link href="http://davehunt.co.uk/2017/03/23/migrating-to-declarative-jenkins-pipelines.html" rel="alternate" type="text/html" title="Migrating to declarative Jenkins pipelines" /><published>2017-03-23T00:00:00+00:00</published><updated>2017-03-23T00:00:00+00:00</updated><id>http://davehunt.co.uk/2017/03/23/migrating-to-declarative-jenkins-pipelines</id><content type="html" xml:base="http://davehunt.co.uk/2017/03/23/migrating-to-declarative-jenkins-pipelines.html">&lt;p&gt;Last year I shared &lt;a href=&quot;/2016/12/08/my-thoughts-on-jenkins-pipelines.html&quot;&gt;my thoughts on Jenkins pipelines&lt;/a&gt;
and provided a &lt;a href=&quot;/2016/12/19/jenkins-pipeline-walkthrough.html&quot;&gt;walkthrough&lt;/a&gt; of how we’re using
pipelines at Mozilla. Since then, the &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Pipeline+Model+Definition+Plugin&quot;&gt;Pipeline Model Definition plugin&lt;/a&gt; has
came out of beta, and we’ve been migrating our pipelines to the new declarative
syntax with a &lt;a href=&quot;https://jenkins.io/doc/book/pipeline/shared-libraries/&quot;&gt;shared library&lt;/a&gt;.&lt;!--more--&gt;&lt;/p&gt;

&lt;h2 id=&quot;shared-libraries&quot;&gt;Shared libraries&lt;/h2&gt;
&lt;p&gt;As soon as you’re implementing similar steps in multiple Jenkins pipelines, it
makes sense to consider writing a shared library. Our &lt;a href=&quot;https://github.com/mozilla/fxtest-jenkins-pipeline&quot;&gt;fxtest-jenkins-pipeline&lt;/a&gt;
library allows us to centrally maintain custom steps such as IRC notifications,
or creating variables files with desired capabilities for Selenium, rather
than implementing these in every pipeline.&lt;/p&gt;

&lt;h2 id=&quot;pipeline-options&quot;&gt;Pipeline options&lt;/h2&gt;
&lt;p&gt;In our original pipelines it was necessary to wrap steps in order to configure
timeouts, ANSI colours, and timestamps. With declarative this is made so much
better by allowing &lt;a href=&quot;https://jenkins.io/doc/book/pipeline/syntax/#options&quot;&gt;pipeline-specific options&lt;/a&gt; to be
configured. The following snippet demonstrates enabling all three of these:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ansiColor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'xterm'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;timestamps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;time:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;unit:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'HOURS'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Everything defined in one place, and with less nesting/indentation vastly
improves the readability and maintainability of the pipelines.&lt;/p&gt;

&lt;h2 id=&quot;environment-variables&quot;&gt;Environment variables&lt;/h2&gt;
&lt;p&gt;Another huge improvement is the handling of
&lt;a href=&quot;https://jenkins.io/doc/book/pipeline/syntax/#environment&quot;&gt;environment variables&lt;/a&gt; variables and accessing
credentials. Previously it was necessary to wrap steps in &lt;code class=&quot;highlighter-rouge&quot;&gt;withEnv&lt;/code&gt; for
environment variables, and &lt;code class=&quot;highlighter-rouge&quot;&gt;withCredentials&lt;/code&gt; for credentials. This is what we
previously would have needed:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;withCredentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;([[&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;$class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'StringBinding'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;credentialsId:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'SAUCELABS_API_KEY'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;variable:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'SAUCELABS_API_KEY'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;withEnv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;PYTEST_ADDOPTS=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;-n=${processes} &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;--driver=SauceLabs &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;--variables=capabilities.json &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;--color=yes&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With declarative, this can be replaced with the following:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;PYTEST_ADDOPTS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;-n=10 &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;--tb=short &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;--color=yes &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;--driver=SauceLabs &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;--variables=capabilities.json&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SAUCELABS_API_KEY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'SAUCELABS_API_KEY'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that there’s a &lt;a href=&quot;https://issues.jenkins-ci.org/browse/JENKINS-42857&quot;&gt;regression&lt;/a&gt; in version 1.1.1 of the plugin
that prevents strings from being split over multiple lines, but this is already
fixed and will be included in the next release.&lt;/p&gt;

&lt;h2 id=&quot;post-build-steps&quot;&gt;Post build steps&lt;/h2&gt;
&lt;p&gt;Possibly the most valuable addition to declarative piplines are the post build
steps. It’s now possible to define steps to execute after each stage or
pipeline depending on the current status of the build. Previously we were using
try/catch/finally for our tests step ensure we reported our results, and a
broader try/catch to send failure notifications.&lt;/p&gt;

&lt;p&gt;We now have a &lt;code class=&quot;highlighter-rouge&quot;&gt;post&lt;/code&gt; section immediately after our test stage that publishes
artifacts, similar to the following snippet:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Test'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;archiveArtifacts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'results/*'&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;junit&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'results/*.xml'&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also have a &lt;code class=&quot;highlighter-rouge&quot;&gt;post&lt;/code&gt; section for the entire pipeline for notifications. This
means that we send notifications when any stage fails, which is another
improvement over our previous pipelines.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In my opinion declarative pipelines are a huge improvement over the original
scripted pipelines. The new syntax is succinct and easier to read and maintain.
As a result of migrating to declarative and our shared library, one of our
pipelines had a 60% reduction in the lines of code but with more functionality!&lt;/p&gt;

&lt;p&gt;Here’s a &lt;a href=&quot;https://github.com/mozilla/fxapom/blob/0f3b3cdb161940614ef50f2203a4633df1464c74/Jenkinsfile&quot;&gt;full example&lt;/a&gt; of one of our declarative Jenkins pipelines.&lt;/p&gt;</content><author><name>Dave Hunt</name></author><category term="continuous integration" /><category term="jenkins" /><category term="pipelines" /><category term="declarative" /><summary type="html">Last year I shared my thoughts on Jenkins pipelines and provided a walkthrough of how we’re using pipelines at Mozilla. Since then, the Pipeline Model Definition plugin has came out of beta, and we’ve been migrating our pipelines to the new declarative syntax with a shared library.</summary></entry></feed>