Page MenuHomePhabricator

MediaWikiIntegrationTestCase::setTemporaryHook needs to support new style hooks
Closed, ResolvedPublic

Description

When using MediaWikiIntegrationTestCase::setTemporaryHook() in an integration test, it will stash any hooks defined in:

  1. $wgHooks
  2. Registered through HookContainer::register/Hooks::register()
  3. In extension.json (only if defined in the legacy way)

What it is currently lacking, is code to stash any new-style hook handlers defined in an extension.json. This causes problems because tests that were operating under the assumption that all existing hooks have been cleared for a clean slate, now risk having extension defined handlers interfere with tests and causes breakage.

Observations:

  • The hook container is reset after every test run anyway. We can just add hook handlers the usual way.
  • A mechanism for temporary/scoped hook handlers is still needed for some rare use cases, but generally not useful for tests.
  • Tests may want to suppress all other handlers for a hook, to ensure the testing handler is actually used.
  • Unit tests (and most integration tests) may want to suppress all other handlers for all hooks, to ensure they are testing vanilla behavior. Compliance tests and structure tests however will need all hooks handlers registered by extensions to be in place.

Ideas:

  • MediaWikiIntegrationTestCase::setTemporaryHook() just calls register() on the HookContainer. If the $replace flag is set, it calls clear() on the HookContainer first.
  • Create MediaWikiIntegrationTestCase::clearAllHooks(), which replaces the default HookContaienr with an empty one.
  • Ensure that HookContainer::scopedRegister() interacts correctly with hooks registered in different ways.
  • Remove the $replace flag from HookContainer::scopedRegister() unless we are sure we really need it. If we do need it, implement it by creating an array of override handlers.

Event Timeline

nnikkhoui renamed this task from MediaWikiIntegrationTestCase::setTemporaryHook not working for new style hooks to MediaWikiIntegrationTestCase::setTemporaryHook needs to support new style hooks .Jun 10 2020, 6:23 PM
WDoranWMF triaged this task as Unbreak Now! priority.Jun 10 2020, 6:35 PM
AMooney lowered the priority of this task from Unbreak Now! to High.Jun 10 2020, 10:06 PM

After talking with @tstarling, he suggested that instead of just modifying HookContainer::scopedRegister(), it might be a better idea to replace usages of setTemporaryHook() with the creation of an empty hook container. The empty hook container could be passed to MediaWikiServices::redefineService() to test code that doesn't have a HookContainer passed in in a constructor.

That would work, but it would have the side effect of disabling all hooks. That may be desirable for core tests (we could even consider doing it per default), but could potentially mess with extension tests. Also, calling it twice should result in two temporary hooks being set, so the second call should not again install an empty container. We may also provide an option to retain existing handlers for specific hooks (by copying them to the new container).

The "clean slate" logic that would make the temporary handler the *only* handler for the given hook was new in https://gerrit.wikimedia.org/r/c/mediawiki/core/+/589097, before that, the temporary hook handler was just added, existing handlers remain in place. What motivated this change?

In my mind, the following cases are relevant:

  • run a test with no hooks, so we can test vanilla core behavior
  • run a test with only hook handlers explicitly registered by the test itself
  • run a test with all hooks enabled, so we can do structure tests that assert that extensions do not break expectations
  • MAYBE run with all hooks enabled, plus additional temporary hooks

The current behavior is that we we leave all hooks intact, but temporarily disable all existing handlers for a specific hook when registring a temporary handler for this hook. That seems confusing.

I made an experimental patch that disabled all hooks per default in unit tests. It causes 139 failures and errors, mostly in extensions:

1hook-failures-1.txt:1) CirrusSearch\Test\RequestLoggerTest::testRequestLogging with data set "fulltext_basic_005" (array('fulltext', 'intitle:main', false), array(array(3, false, array(4, 4, 0), array(0, null, array())), array(array(array(72, false, array(8, 8, 0), array(0, null, array()))))), array(array('cirrussearch-request', array('/mediawiki/cirrussearch/request/0.0.1', false, array(array(false, 0, 0, 0, array('mw_cirrus_metastore'), 'intitle', 'namespace', 3, false), array(false, 0, 0, 0, array('wiki'), 21, 'intitle:main', 'full_text', 72, false, array('full_text', 'full_text_querystring', 'complex_query', 'intitle'))), array('127.0.0.1', false, 'GET'), 'cli'), 'debug', ''), array('CirrusSearchRequests', array(0, '123456789', 0, 0, 0, '2c33c9c64851a02e2ba8143c6550a3b8', 'mw_cirrus_metastore', 'intitle', 'intitle', 'namespace', 'cli', false, 0), 'debug', 'lookup namespace for {namespa...cutor}'), array('CirrusSearchRequests', array(0, '123456789', 0, 0, 0, '2c33c9c64851a02e2ba8143c6550a3b8', 'wiki', 21, 'intitle:main', 'full_text', 'cli', false, array('full_text', 'full_text_querystring', 'complex_query', 'intitle'), 0), 'debug', '{queryType} search for '{quer...cutor}')))
2hook-failures-1.txt-Undefined index: elasticsearch_requests
3--
4hook-failures-1.txt:2) Kartographer\Tests\KartographerTest::testTagData with data set #0 ('[]', '<mapframe width=700 height=40...e=37/>', '<mapframe> without JSON')
5hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
6--
7hook-failures-1.txt:3) Kartographer\Tests\KartographerTest::testTagData with data set #1 ('[]', '<mapframe width=700 height=40...frame>', '<mapframe> without JSON 2')
8hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
9--
10hook-failures-1.txt:4) Kartographer\Tests\KartographerTest::testTagData with data set #2 ('{"_07f50db5d8d017fd95ccd49d38...\n }]}', '<mapframe width=700 height=40...frame>', '<mapframe> with GeoJSON')
11hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
12--
13hook-failures-1.txt:5) Kartographer\Tests\KartographerTest::testTagData with data set #3 ('{"_07f50db5d8d017fd95ccd49d38...\n }]}', '<mapframe width=700 height=40...frame>', '<mapframe> with GeoJSON array')
14hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
15--
16hook-failures-1.txt:6) Kartographer\Tests\KartographerTest::testTagData with data set #4 (false, '<mapframe width=700 height=40...frame>', 'Invalid JSON')
17hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
18--
19hook-failures-1.txt:7) Kartographer\Tests\KartographerTest::testTagData with data set #5 (false, '<mapframe width=700 height=40...frame>', 'Invalid JSON 2')
20hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
21--
22hook-failures-1.txt:8) Kartographer\Tests\KartographerTest::testTagData with data set #6 (false, '<mapframe width=700 height=40...frame>', 'Invalid JSON 3')
23hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
24--
25hook-failures-1.txt:9) Kartographer\Tests\KartographerTest::testTagData with data set #7 (false, '<mapframe width=700 height=40...frame>', 'Invalid JSON 4')
26hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
27--
28hook-failures-1.txt:10) Kartographer\Tests\KartographerTest::testTagData with data set #8 (false, '<mapframe width=700 height=40...frame>', 'Invalid JSON 5')
29hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
30--
31hook-failures-1.txt:11) Kartographer\Tests\KartographerTest::testTagData with data set #9 (false, '<mapframe width=700 height=40...frame>', 'Invalid JSON 6')
32hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
33--
34hook-failures-1.txt:12) Kartographer\Tests\KartographerTest::testTagData with data set #10 ('{"_ee2aa7342f7aee686e9d155932...n ]}', '<mapframe width=700 height=40...frame>', '<mapframe> with parsable text...iption')
35hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
36--
37hook-failures-1.txt:13) Kartographer\Tests\KartographerTest::testTagData with data set #11 ('{"_ee2aa7342f7aee686e9d155932...n ]}', '<maplink zoom=13 longitude=-1...plink>', '<maplink> with parsable text ...iption')
38hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
39--
40hook-failures-1.txt:14) Kartographer\Tests\KartographerTest::testTagData with data set #12 ('[]', '<maplink zoom=13 longitude=-1...plink>', 'T127345: whitespace-only tag ...plink>')
41hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
42--
43hook-failures-1.txt:15) Kartographer\Tests\KartographerTest::testTagData with data set #13 ('{"_52fbfcdf508cc75f6e496a8988...\n ]}', '<maplink zoom=13 longitude=10...plink>', 'T134719: XSS via __proto__')
44hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
45--
46hook-failures-1.txt:16) Kartographer\Tests\KartographerTest::testTagData with data set #14 ('[]', '<mapframe show="foo, bar, baz...100 />', 'T148971 - weird LiveData', true)
47hook-failures-1.txt-Error: Call to a member function hasBrokenTags() on null
48--
49hook-failures-1.txt:17) ApiParseExtenderTest::testApi with data set #0 (array('', 'I exist\n\n<span class='nomob.../span>'), '<section class="mf-section-0"...ction>')
50hook-failures-1.txt-MWException: No namespace configured for MediaInfo entities!
51--
52hook-failures-1.txt:18) ApiParseExtenderTest::testApi with data set #1 (array('html', 'Lede<h2>Section1</h2>Text<h2>...2>Text'), '<section class="mf-section-0"...ction>')
53hook-failures-1.txt-MWException: No namespace configured for MediaInfo entities!
54--
55hook-failures-1.txt:19) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_de-ch-en" (array('Wien', 'de-ch', 'en', 'item', false), '/workspace/src/extensions/Wik...pected')
56hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
57--
58hook-failures-1.txt:20) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_de-ch" (array('Wien', 'de-ch', 'de-ch', 'item', 7, false), '/workspace/src/extensions/Wik...pected')
59hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
60--
61hook-failures-1.txt:21) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_de-ch_strict" (array('Wien', 'de-ch', 'de-ch', 'item', true), '/workspace/src/extensions/Wik...pected')
62hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
63--
64hook-failures-1.txt:22) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_en" (array('Duck', 'en', 'en', 'item', false), '/workspace/src/extensions/Wik...pected')
65hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
66--
67hook-failures-1.txt:23) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_en_strict" (array('Duck', 'en', 'en', 'item', 15, true), '/workspace/src/extensions/Wik...pected')
68hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
69--
70hook-failures-1.txt:24) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_id" (array('q42', 'en', 'en', 'item', false), '/workspace/src/extensions/Wik...pected')
71hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
72--
73hook-failures-1.txt:25) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_par" (array('(p128) ', 'en', 'en', 'item', false), '/workspace/src/extensions/Wik...pected')
74hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
75--
76hook-failures-1.txt:26) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_prop" (array(' p42', 'en', 'en', 'item', false), '/workspace/src/extensions/Wik...pected')
77hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
78--
79hook-failures-1.txt:27) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_space" (array('space age ', 'de-ch', 'de-ch', 'item', 7, false), '/workspace/src/extensions/Wik...pected')
80hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
81--
82hook-failures-1.txt:28) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_url" (array('https://www.wikidata.org/wiki/Q56', 'en', 'en', 'item', false), '/workspace/src/extensions/Wik...pected')
83hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
84--
85hook-failures-1.txt:29) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_zh-de-ch" (array('父類', 'zh', 'de-ch', 'property', false), '/workspace/src/extensions/Wik...pected')
86hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
87--
88hook-failures-1.txt:30) Wikibase\Search\Elastic\Tests\EntitySearchElasticTest::testSearchElastic with data set "search_zh" (array('父類', 'zh', 'zh', 'property', false), '/workspace/src/extensions/Wik...pected')
89hook-failures-1.txt-CirrusSearch\Profile\SearchProfileException: No default profile found for wikibase_prefix_querybuilder in context wikibase_prefix_search
90--
91hook-failures-1.txt:31) Wikibase\MediaInfo\Tests\MediaWiki\WikibaseMediaInfoHooksTest::testOnBeforePageDisplay
92hook-failures-1.txt-OutOfBoundsException: No EntityDocumentView is registered for entity type 'mediainfo'
93--
94hook-failures-1.txt:32) Wikibase\Lib\Tests\WikibaseContentLanguagesTest::testGetDefaultInstance_withHook
95hook-failures-1.txt-OutOfRangeException: No ContentLanguages registered for context: test
96--
97hook-failures-1.txt:1) Wikibase\Lib\Tests\Formatters\CachingKartographerEmbeddingHandlerTest::testGetHtml_cached
98hook-failures-1.txt-Proxying to original methods requires invoking the original constructor
99--
100hook-failures-1.txt:1) ResourcesTest::testValidDependencies
101hook-failures-1.txt-Dependencies that do not exist
102--
103hook-failures-1.txt:2) MediaWiki\Skins\Vector\Tests\Integration\VectorTemplateTest::testGetMenuProps
104hook-failures-1.txt-Failed asserting that two arrays are identical.
105--
106hook-failures-1.txt:3) AutoEnrollmentTest::testAutoEnroll with data set #1 ('betafeatures-auto-enroll', '1', 'unittest-ft1', '1', 'Hooks did not set the prefere...s set.')
107hook-failures-1.txt-Hooks did not set the preference though global auto-enroll was set.
108--
109hook-failures-1.txt:4) AutoEnrollmentTest::testAutoEnroll with data set #3 ('unittest-all', '1', 'unittest-ft1', '1', 'Hooks did not set the prefere...s set.')
110hook-failures-1.txt-Hooks did not set the preference though group auto-enroll was set.
111--
112hook-failures-1.txt:5) AutoEnrollmentTest::testAutoEnroll with data set #5 ('unittest-all', '1', 'unittest-ft2', '1', 'Hooks did not set the prefere...s set.')
113hook-failures-1.txt-Hooks did not set the preference though grandparent group auto-enroll was set.
114--
115hook-failures-1.txt:6) AutoEnrollmentTest::testAutoEnroll with data set #6 ('betafeatures-auto-enroll', '1', 'unittest-ft2', '1', 'Hooks did not set the prefere...s set.')
116hook-failures-1.txt-Hooks did not set the preference though global auto-enroll was set.
117--
118hook-failures-1.txt:7) DependentFeatureTest::testPassingDependency
119hook-failures-1.txt-Hook did not run with passing dependency.
120--
121hook-failures-1.txt:8) DependentFeatureTest::testNoDependency
122hook-failures-1.txt-Hook did not run without dependency.
123--
124hook-failures-1.txt:9) HooksRunTest::testHooksRun
125hook-failures-1.txt-Hook did not run
126--
127hook-failures-1.txt:10) PreferenceHandlingTest::testHandlingOfPreferences with data set #0 ('Invalid preference should cau... error', array('google it bro'), null)
128hook-failures-1.txt-Invalid preference should cause an error
129--
130hook-failures-1.txt:11) PreferenceHandlingTest::testHandlingOfPreferences with data set #1 ('Totally valid preference shou...rately', array('soup-label', 'something-something-desc-side', 'http://example.org/features', 'http://example.org/feedback'), array('soup-label', 'something-something-desc-side', 'http://example.org/features', 'http://example.org/feedback', 'HTMLFeatureField', 'betafeatures'))
131hook-failures-1.txt-Failed asserting that an array has the key 'unittest'.
132--
133hook-failures-1.txt:12) TimeUnitsTest::testTimeUnit with data set #0 ('en', '20111231170000', '20120101000000', '7 hours ago', '"Yesterday" across years')
134hook-failures-1.txt-"Yesterday" across years
135--
136hook-failures-1.txt:13) TimeUnitsTest::testTimeUnit with data set #1 ('en', '20120717190900', '20120717190929', '29 seconds ago', '"Just now"')
137hook-failures-1.txt-"Just now"
138--
139hook-failures-1.txt:14) TimeUnitsTest::testTimeUnit with data set #4 ('en', '20120617190900', '20120717190900', '1 month ago', 'Month difference')
140hook-failures-1.txt-Month difference
141--
142hook-failures-1.txt:15) TimeUnitsTest::testTimeUnit with data set #5 ('en', '19910130151500', '20120716193700', '21 years ago', 'Different year')
143hook-failures-1.txt-Different year
144--
145hook-failures-1.txt:16) TimeUnitsTest::testTimeUnit with data set #6 ('en', '20120714184300', '20120715040000', '9 hours ago', 'Today at another time')
146hook-failures-1.txt-Today at another time
147--
148hook-failures-1.txt:17) TimeUnitsTest::testTimeUnit with data set #7 ('en', '20120617190900', '20120717190900', '1 month ago', 'Another month')
149hook-failures-1.txt-Another month
150--
151hook-failures-1.txt:18) TimeUnitsTest::testTimeUnit with data set #8 ('en', '19910130151500', '20120716193700', '21 years ago', 'Different year')
152hook-failures-1.txt-Different year
153--
154hook-failures-1.txt:19) TimeUnitsTest::testTimeUnit with data set #9 ('ml', '20111231170000', '20120101000000', '7 മണിക്കൂർ മുമ്പ്', '"Yesterday" across years')
155hook-failures-1.txt-"Yesterday" across years
156--
157hook-failures-1.txt:20) TimeUnitsTest::testTimeUnit with data set #10 ('ml', '20120717190900', '20120717190929', '29 സെക്കൻഡ് മുമ്പ്', '"Just now"')
158hook-failures-1.txt-"Just now"
159--
160hook-failures-1.txt:21) TimeUnitsTest::testTimeUnit with data set #11 ('ml', '20120717190900', '20120717191530', '6 മിനിറ്റ് മുമ്പ്', 'X minutes ago')
161hook-failures-1.txt-X minutes ago
162--
163hook-failures-1.txt:22) TimeUnitsTest::testTimeUnit with data set #12 ('ml', '20121006173100', '20121006173200', '1 മിനിറ്റ് മുമ്പ്', '"1 minute ago"')
164hook-failures-1.txt-"1 minute ago"
165--
166hook-failures-1.txt:23) TimeUnitsTest::testTimeUnit with data set #13 ('ml', '20120617190900', '20120717190900', '1 മാസം മുമ്പ്', 'Month difference')
167hook-failures-1.txt-Month difference
168--
169hook-failures-1.txt:24) TimeUnitsTest::testTimeUnit with data set #14 ('ml', '19910130151500', '20120716193700', '21 വർഷം മുമ്പ്', 'Different year')
170hook-failures-1.txt-Different year
171--
172hook-failures-1.txt:25) TimeUnitsTest::testTimeUnit with data set #15 ('ml', '20120714184300', '20120715040000', '9 മണിക്കൂർ മുമ്പ്', 'Today at another time')
173hook-failures-1.txt-Today at another time
174--
175hook-failures-1.txt:26) TimeUnitsTest::testTimeUnit with data set #16 ('ml', '20120617190900', '20120717190900', '1 മാസം മുമ്പ്', 'Another month')
176hook-failures-1.txt-Another month
177--
178hook-failures-1.txt:27) TimeUnitsTest::testTimeUnit with data set #17 ('ml', '19910130151500', '20120716193700', '21 വർഷം മുമ്പ്', 'Different year')
179hook-failures-1.txt-Different year
180--
181hook-failures-1.txt:28) GeoData\Test\TagTest::testLooseTagParsing with data set #0 ('{{#coordinates: 10|20|primary}}', GeoData\Coord Object (...))
182hook-failures-1.txt-Failed asserting that null is not null.
183--
184hook-failures-1.txt:29) GeoData\Test\TagTest::testLooseTagParsing with data set #3 ('{{#coordinates: 10| primary | 20}}', GeoData\Coord Object (...))
185hook-failures-1.txt-Failed asserting that null is not null.
186--
187hook-failures-1.txt:30) GeoData\Test\TagTest::testLooseTagParsing with data set #4 ('{{#coordinates: 10 | | 20 }}', GeoData\Coord Object (...))
188hook-failures-1.txt-Failed asserting that null is not null.
189--
190hook-failures-1.txt:31) GeoData\Test\TagTest::testLooseTagParsing with data set #5 ('{{#coordinates: primary|10|20}}', GeoData\Coord Object (...))
191hook-failures-1.txt-Failed asserting that null is not null.
192--
193hook-failures-1.txt:32) GeoData\Test\TagTest::testLooseTagParsing with data set #6 ('{{#coordinates: 10|20|type:landmark}}', GeoData\Coord Object (...))
194hook-failures-1.txt-Failed asserting that null is not null.
195--
196hook-failures-1.txt:33) GeoData\Test\TagTest::testLooseTagParsing with data set #7 ('{{#coordinates: 10|20|type:city(666)}}', GeoData\Coord Object (...))
197hook-failures-1.txt-Failed asserting that null is not null.
198--
199hook-failures-1.txt:34) GeoData\Test\TagTest::testLooseTagParsing with data set #8 ('{{#coordinates: 10|20}}', GeoData\Coord Object (...))
200hook-failures-1.txt-Failed asserting that null is not null.
201--
202hook-failures-1.txt:35) GeoData\Test\TagTest::testLooseTagParsing with data set #9 ('{{#coordinates:10|20|globe:Mo...-mos}}', GeoData\Coord Object (...))
203hook-failures-1.txt-Failed asserting that null is not null.
204--
205hook-failures-1.txt:36) GeoData\Test\TagTest::testLooseTagParsing with data set #10 ('{{#coordinates:10|20|globe:Mo...n:RU}}', GeoData\Coord Object (...))
206hook-failures-1.txt-Failed asserting that null is not null.
207--
208hook-failures-1.txt:37) GeoData\Test\TagTest::testLooseTagParsing with data set #11 ('{{#coordinates: 10|20|_dim:3Km_}}', GeoData\Coord Object (...))
209hook-failures-1.txt-Failed asserting that null is not null.
210--
211hook-failures-1.txt:38) GeoData\Test\TagTest::testLooseTagParsing with data set #12 ('{{#coordinates: 10|20|foo:bar...100m}}', GeoData\Coord Object (...))
212hook-failures-1.txt-Failed asserting that null is not null.
213--
214hook-failures-1.txt:39) GeoData\Test\TagTest::testLooseTagParsing with data set #13 ('{{#coordinates: 10|20|dim:-300}}', GeoData\Coord Object (...))
215hook-failures-1.txt-Failed asserting that null is not null.
216--
217hook-failures-1.txt:40) GeoData\Test\TagTest::testLooseTagParsing with data set #14 ('{{#coordinates: 10|20|dim:-10km}}', GeoData\Coord Object (...))
218hook-failures-1.txt-Failed asserting that null is not null.
219--
220hook-failures-1.txt:41) GeoData\Test\TagTest::testLooseTagParsing with data set #15 ('{{#coordinates: 10|20|dim:1L}}', GeoData\Coord Object (...))
221hook-failures-1.txt-Failed asserting that null is not null.
222--
223hook-failures-1.txt:42) GeoData\Test\TagTest::testLooseTagParsing with data set #16 ('{{#coordinates: 10|20|type:city}}', GeoData\Coord Object (...))
224hook-failures-1.txt-Failed asserting that null is not null.
225--
226hook-failures-1.txt:43) GeoData\Test\TagTest::testLooseTagParsing with data set #17 ('{{#coordinates: 10|20|type:ci...000)}}', GeoData\Coord Object (...))
227hook-failures-1.txt-Failed asserting that null is not null.
228--
229hook-failures-1.txt:44) GeoData\Test\TagTest::testLooseTagParsing with data set #18 ('{{#coordinates: 10|20|type:lulz}}', GeoData\Coord Object (...))
230hook-failures-1.txt-Failed asserting that null is not null.
231--
232hook-failures-1.txt:45) GeoData\Test\TagTest::testLooseTagParsing with data set #19 ('{{#coordinates: 10|20|scale:50000}}', GeoData\Coord Object (...))
233hook-failures-1.txt-Failed asserting that null is not null.
234--
235hook-failures-1.txt:46) GeoData\Test\TagTest::testLooseTagParsing with data set #20 ('{{#coordinates: 2.5|3,5}}', GeoData\Coord Object (...), 'de')
236hook-failures-1.txt-Failed asserting that null is not null.
237--
238hook-failures-1.txt:47) GeoData\Test\TagTest::testLooseTagParsing with data set #21 ('{{#coordinates: -3.29237|-60....obe=}}', GeoData\Coord Object (...))
239hook-failures-1.txt-Failed asserting that null is not null.
240--
241hook-failures-1.txt:48) GeoData\Test\TagTest::testLooseTagParsing with data set #22 ('{{#coordinates: 10|20|type:sOmEtHiNg}}', GeoData\Coord Object (...))
242hook-failures-1.txt-Failed asserting that null is not null.
243--
244hook-failures-1.txt:49) GeoData\Test\TagTest::testLooseTagParsing with data set #23 ('{{#coordinates:10|20|scale=boom!}}', GeoData\Coord Object (...))
245hook-failures-1.txt-Failed asserting that null is not null.
246--
247hook-failures-1.txt:50) GeoData\Test\TagTest::testLooseTagParsing with data set #24 ('{{#coordinates:10|20|scale=-3}}', GeoData\Coord Object (...))
248hook-failures-1.txt-Failed asserting that null is not null.
249--
250hook-failures-1.txt:51) Kartographer\Tests\KartographerTest::testResourceModules with data set #1 ('<mapframe width=700 height=40...e=37/>', array(''), array(''))
251hook-failures-1.txt-Failed asserting that two arrays are equal.
252--
253hook-failures-1.txt:52) Kartographer\Tests\KartographerTest::testResourceModules with data set #2 ('<maplink width=700 height=400...e=37/>', array(''), array(''))
254hook-failures-1.txt-Failed asserting that two arrays are equal.
255--
256hook-failures-1.txt:53) Kartographer\Tests\KartographerTest::testResourceModules with data set #3 ('<mapframe width=700 height=40...e=37/>', array('', ''), array(''))
257hook-failures-1.txt-Failed asserting that two arrays are equal.
258--
259hook-failures-1.txt:54) Kartographer\Tests\KartographerTest::testLiveData with data set #0 (' <maplink latitude=10 longi...frame>', array('_5e4843908b3c3d3b11ac4321edad...882cc2'), false, false, false)
260hook-failures-1.txt-Failed asserting that an array has the key 'wgKartographerLiveData'.
261--
262hook-failures-1.txt:55) Kartographer\Tests\KartographerTest::testLiveData with data set #1 (' <maplink latitude=10 longi...frame>', array('_0616e83db3b0cc67d5f835eb765d...26f4ce', '_5e4843908b3c3d3b11ac4321edad...882cc2'), true, false, false)
263hook-failures-1.txt-Failed asserting that an array has the key 'wgKartographerLiveData'.
264--
265hook-failures-1.txt:56) Kartographer\Tests\KartographerTest::testLiveData with data set #2 (' <maplink latitude=10 longi...frame>', array('_0616e83db3b0cc67d5f835eb765d...26f4ce', '_5e4843908b3c3d3b11ac4321edad...882cc2'), false, true, false)
266hook-failures-1.txt-Failed asserting that an array has the key 'wgKartographerLiveData'.
267--
268hook-failures-1.txt:57) Kartographer\Tests\KartographerTest::testLiveData with data set #3 (' <maplink latitude=10 longi...frame>', array('_0616e83db3b0cc67d5f835eb765d...26f4ce', '_5e4843908b3c3d3b11ac4321edad...882cc2'), true, true, false)
269hook-failures-1.txt-Failed asserting that an array has the key 'wgKartographerLiveData'.
270--
271hook-failures-1.txt:58) Kartographer\Tests\KartographerTest::testLiveData with data set #4 ('<mapframe show="foo, bar, baz...100 />', array('foo', 'bar', 'baz'), false, false, true)
272hook-failures-1.txt-Failed asserting that an array has the key 'wgKartographerLiveData'.
273--
274hook-failures-1.txt:59) Kartographer\Tests\KartographerTest::testPageProps with data set #2 ('<mapframe>broken but still tr...e=0 />', 2, null)
275hook-failures-1.txt-Failed asserting that false matches expected 2.
276--
277hook-failures-1.txt:60) Kartographer\Tests\KartographerTest::testPageProps with data set #3 ('<mapframe/><maplink/><mapfram...plink>', 2, 2)
278hook-failures-1.txt-Failed asserting that false matches expected 2.
279--
280hook-failures-1.txt:61) MobileContextTest::testGetMobileUrl
281hook-failures-1.txt-Ensure that hook got the right context
282--
283hook-failures-1.txt:62) MobileFrontendHooksTest::testOnTitleSquidURLs
284hook-failures-1.txt-Failed asserting that two arrays are equal.
285--
286hook-failures-1.txt:63) TwoColConflict\Tests\TwoColConflictHooksTest::testGetOption with data set #0 (0, 0, false)
287hook-failures-1.txt-Failed asserting that 0 is null.
288--
289hook-failures-1.txt:64) TwoColConflict\Tests\TwoColConflictHooksTest::testGetOption with data set #1 (0, null, false)
290hook-failures-1.txt-Failed asserting that 0 is null.
291--
292hook-failures-1.txt:65) TwoColConflict\Tests\TwoColConflictHooksTest::testGetOption with data set #2 (0, 1, false)
293hook-failures-1.txt-Failed asserting that 0 is null.
294--
295hook-failures-1.txt:66) TwoColConflict\Tests\TwoColConflictHooksTest::testGetOption with data set #4 (null, null, true)
296hook-failures-1.txt-Failed asserting that false is identical to true.
297--
298hook-failures-1.txt:67) TwoColConflict\Tests\TwoColConflictHooksTest::testGetOption with data set #6 (1, 0, false)
299hook-failures-1.txt-Failed asserting that '1' is null.
300--
301hook-failures-1.txt:68) TwoColConflict\Tests\TwoColConflictHooksTest::testGetOption with data set #7 (1, null, true)
302hook-failures-1.txt-Failed asserting that '1' is null.
303--
304hook-failures-1.txt:69) TwoColConflict\Tests\TwoColConflictHooksTest::testGetOption with data set #8 (1, 1, true)
305hook-failures-1.txt-Failed asserting that '1' is null.
306--
307hook-failures-1.txt:70) TwoColConflict\Tests\TwoColConflictHooksTest::testSetOption with data set #2 (null, null, null, true)
308hook-failures-1.txt-Failed asserting that false is identical to true.
309--
310hook-failures-1.txt:71) Wikibase\Search\Elastic\Tests\EntitySearchElasticFulltextTest::testSearchElastic with data set "search_de-ch" (array('Wien', 'de-ch', array(0, 120)), '/workspace/src/extensions/Wik...pected')
311hook-failures-1.txt-Failed asserting that 'full_text search for 'Wien'' starts with "entity_full_text".
312--
313hook-failures-1.txt:72) Wikibase\Search\Elastic\Tests\EntitySearchElasticFulltextTest::testSearchElastic with data set "search_en" (array('Duck', 'en', array(0)), '/workspace/src/extensions/Wik...pected')
314hook-failures-1.txt-Failed asserting that 'full_text search for 'Duck'' starts with "entity_full_text".
315--
316hook-failures-1.txt:73) Wikibase\Search\Elastic\Tests\EntitySearchElasticFulltextTest::testSearchElastic with data set "search_id" (array('q42', 'en', array(0)), '/workspace/src/extensions/Wik...pected')
317hook-failures-1.txt-Failed asserting that 'full_text search for 'q42'' starts with "entity_full_text".
318--
319hook-failures-1.txt:74) Wikibase\Search\Elastic\Tests\EntitySearchElasticFulltextTest::testSearchElastic with data set "search_par" (array('(p128) ', 'en', array(120)), '/workspace/src/extensions/Wik...pected')
320hook-failures-1.txt-Failed asserting that 'full_text search for '(p128) '' starts with "entity_full_text".
321--
322hook-failures-1.txt:75) Wikibase\Search\Elastic\Tests\EntitySearchElasticFulltextTest::testSearchElastic with data set "search_prop" (array(' p42', 'en', array(120)), '/workspace/src/extensions/Wik...pected')
323hook-failures-1.txt-Failed asserting that 'full_text search for ' p42'' starts with "entity_full_text".
324--
325hook-failures-1.txt:76) Wikibase\Search\Elastic\Tests\EntitySearchElasticFulltextTest::testSearchElastic with data set "search_url" (array('https://www.wikidata.org/wiki/Q56', 'en', array(0)), '/workspace/src/extensions/Wik...pected')
326hook-failures-1.txt-Failed asserting that 'full_text search for 'https://www.wikidata.org/wiki/Q56'' starts with "entity_full_text".
327--
328hook-failures-1.txt:77) Wikibase\Search\Elastic\Tests\EntitySearchElasticFulltextTest::testSearchElastic with data set "search_zh" (array('父類', 'zh', array(0)), '/workspace/src/extensions/Wik...pected')
329hook-failures-1.txt-Failed asserting that 'full_text search for '父類'' starts with "entity_full_text".
330--
331hook-failures-1.txt:78) Wikibase\Search\Elastic\Tests\ShowSearchHitHandlerTest::testShowSearchHit with data set "desc hit other language" (array('en', 'Hit <escape me> item'), array('de', 'Hit <here> "some" description'), array('en', 'Hit <escape me> item'), array('de', HtmlArmor Object (...)), null, 1, 2, 'descHit')
332hook-failures-1.txt-Failed asserting that two strings are equal.
333--
334hook-failures-1.txt:79) Wikibase\Search\Elastic\Tests\ShowSearchHitHandlerTest::testShowSearchHit with data set "label hit in other language" (array('en', 'Hit item'), array('en', 'Hit description'), array('de', 'Der hit !HERE! item'), array('en', 'Hit description'), null, 1, 2, 'labelHitDe')
335hook-failures-1.txt-Failed asserting that two strings are equal.
336--
337hook-failures-1.txt:80) Wikibase\Search\Elastic\Tests\ShowSearchHitHandlerTest::testShowSearchHit with data set "description from fallback" (array('en', 'Hit item'), array('de', 'Beschreibung <"here">'), array('de', 'Der hit !HERE! item'), array('de', 'Beschreibung <"here">'), null, 3, 4, 'labelHitDescDe')
338hook-failures-1.txt-Failed asserting that two strings are equal.
339--
340hook-failures-1.txt:81) Wikibase\Search\Elastic\Tests\ShowSearchHitHandlerTest::testShowSearchHit with data set "extra data different language" (array('en', 'Hit item'), array('en', 'Hit description'), array('en', 'Hit item'), array('en', 'Hit description'), array('ru', HtmlArmor Object (...)), 1, 2, 'extraLang')
341hook-failures-1.txt-Failed asserting that two strings are equal.
342--
343hook-failures-1.txt:82) Wikibase\Search\Elastic\Tests\ShowSearchHitHandlerTest::testShowSearchHit with data set "all languages" (array('ar', 'Hit item'), array('he', 'Hit description'), array('es', 'Hit !HERE! item'), array('ru', 'Hit !HERE! description'), array('de', 'Look <what> I found!'), 100, 200, 'manyLang')
344hook-failures-1.txt-Failed asserting that two strings are equal.
345--
346hook-failures-1.txt:83) Wikibase\Search\Elastic\Tests\ShowSearchHitHandlerTest::testShowSearchHit with data set "all languages 2" (array('de', 'Hit item'), array('ru', 'Hit description'), array('fa', 'Hit !HERE! item'), array('he', 'Hit !HERE! description'), array('ar', 'Look <what> I found!'), 100, 200, 'manyLang2')
347hook-failures-1.txt-Failed asserting that two strings are equal.
348--
349hook-failures-1.txt:84) Wikibase\MediaInfo\Tests\MediaWiki\WikibaseMediaInfoHooksTest::testOnWikibaseEntityTypes with data set #0 ('WikibaseRepoEntityTypes')
350hook-failures-1.txt-Failed asserting that an array has the key 'mediainfo'.
351--
352hook-failures-1.txt:85) Wikibase\MediaInfo\Tests\MediaWiki\WikibaseMediaInfoHooksTest::testOnWikibaseEntityTypes with data set #1 ('WikibaseClientEntityTypes')
353hook-failures-1.txt-Failed asserting that an array has the key 'mediainfo'.
354--
355hook-failures-1.txt:86) Wikibase\Repo\Tests\Hooks\EditFilterHookRunnerTest::testRun_hooksAreCalled with data set "fatal existing item" (Status Object (...), Wikibase\DataModel\Entity\Item Object (...), array(Status Object (...), 'Q444', 0))
356hook-failures-1.txt-Failed asserting that two objects are equal.
357--
358hook-failures-1.txt:87) Wikibase\Repo\Tests\Hooks\EditFilterHookRunnerTest::testRun_hooksAreCalled with data set "fatal new item" (Status Object (...), Wikibase\DataModel\Entity\Item Object (...), array(Status Object (...), 'NewItem', 0))
359hook-failures-1.txt-Failed asserting that two objects are equal.
360--
361hook-failures-1.txt:88) Wikibase\Repo\Tests\Hooks\EditFilterHookRunnerTest::testRun_hooksAreCalled with data set "fatal existing entityredirect" (Status Object (...), Wikibase\DataModel\Entity\EntityRedirect Object (...), array(Status Object (...), 'Q12', 0))
362hook-failures-1.txt-Failed asserting that two objects are equal.
363--
364hook-failures-1.txt:89) Wikibase\Repo\Tests\Hooks\ShowSearchHitHandlerTest::testShowSearchHitPlain with data set "fallback" ('Q3', array('Test RU', 'Test 1'), 'de', array('de', 'ru', 'en'), 'de-ru')
365hook-failures-1.txt-Failed asserting that two strings are equal.
366--
367hook-failures-1.txt:90) Wikibase\Repo\Tests\Notifications\HookChangeTransmitterTest::testTransmitChange
368hook-failures-1.txt-The hook function was not called
369--
370hook-failures-1.txt:91) Wikibase\Lib\Tests\Formatters\CachingKartographerEmbeddingHandlerTest::testGetHtml
371hook-failures-1.txt-Failed asserting that '<div class="mw-parser-output"><p>&lt;mapframe width="310" height="180" zoom="13" latitude="50" longitude="0.000011" frameless align="left"&gt;\n
372--
373hook-failures-1.txt:92) Wikibase\Lib\Tests\Formatters\CachingKartographerEmbeddingHandlerTest::testGetParserOutput
374hook-failures-1.txt-Failed asserting that false is not false.
375--
376hook-failures-1.txt:93) Wikibase\Client\Tests\Integration\Hooks\LoginFormValidErrorMessagesHandlerTest::testIsRegistered
377hook-failures-1.txt-Failed asserting that an array contains 'wikibase-client-data-bridge-login-warning'.
378--
379hook-failures-1.txt:1) Wikibase\Repo\Tests\GlobalStateFactoryMethodsResourceTest::testOutputPageJsConfigHookHandler
380hook-failures-1.txt-This test did not perform any assertions
381--
382hook-failures-2.txt:1) MediaWiki\HookContainer\HookContainerIntegrationTest::testHookRunsWhenExtensionRegistered
383hook-failures-2.txt-Failed asserting that 1 matches expected 0.
384--
385hook-failures-2.txt:2) MediaWiki\HookContainer\HookContainerIntegrationTest::testPreviouslyRegisteredHooksAreReAppliedAfterScopedRegisterRemovesThem
386hook-failures-2.txt-Failed asserting that actual size 0 matches expected size 2.
387--
388hook-failures-2.txt:3) MediaWiki\HookContainer\HookContainerIntegrationTest::testHookRunsWithMultipleMixedHandlerTypes
389hook-failures-2.txt-Failed asserting that 3 matches expected 2.
390--
391hook-failures-2.txt:4) HooksTest::testGetHandlers
392hook-failures-2.txt-Hook registered by $wgHooks
393--
394hook-failures-2.txt:5) HooksTest::testNewStyleHookInteraction
395hook-failures-2.txt-Hook registered via $wgHooks should be noticed by Hooks::isRegistered
396--
397hook-failures-2.txt:6) WebRequestTest::testGetIP with data set #8 ('10.0.0.4', array('12.0.0.2', '10.0.0.4, 10.0.0.3, 12.0.0.2'), array('12.0.0.1', '12.0.0.2'), array('10.0.0.3'), true, 'With X-Forwaded-For and priva...lowed)')
398hook-failures-2.txt-With X-Forwaded-For and private IP (allowed)
399--
400hook-failures-2.txt:7) WebRequestTest::testGetIP with data set #10 ('12.0.0.3', array('12.0.0.1', '12.0.0.3, 12.0.0.2'), array(), array('12.0.0.1', '12.0.0.2'), false, 'With X-Forwaded-For')
401hook-failures-2.txt-With X-Forwaded-For
402--
403hook-failures-2.txt:8) WebRequestTest::testGetIP with data set #11 ('12.0.0.2', array('12.0.0.1', '12.0.0.3, 12.0.0.2'), array(), array('12.0.0.1'), false, 'With multiple X-Forwaded-For ...server')
404hook-failures-2.txt-With multiple X-Forwaded-For and only one allowed server
405--
406hook-failures-2.txt:9) MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProviderTest::testGetNewPasswordExpiry
407hook-failures-2.txt-Failed asserting that two strings are identical.
408--
409hook-failures-2.txt:10) MediaWiki\Auth\AbstractPrimaryAuthenticationProviderTest::testProviderNormalizeUsername with data set "Interwiki prefix" ('interwiki:Username', null)
410hook-failures-2.txt-Failed asserting that 'Interwiki:Username' is identical to null.
411--
412hook-failures-2.txt:11) ImportLogFormatterTest::testInterwikiLogDatabaseRows with data set #0 (array('import', 'interwiki', 'interwiki comment', 0, 'ImportPage', array('1', 'importiw:PageImport')), array('User imported ImportPage from...ision)', array(1, 0, 'importiw:PageImport')))
413hook-failures-2.txt-Action text is equal to expected text
414--
415hook-failures-2.txt:12) ResourceLoaderTest::testServiceWiring
416hook-failures-2.txt-Hook was called
417--
418hook-failures-2.txt:13) MediaWiki\Session\PHPSessionHandlerTest::testSessionHandling with data set #0 ('php')
419hook-failures-2.txt-sanity check
420Übereinstimmungen in Binärdatei hook-failures-2.txt

So it seems that most tests would work fine with hooks disabled, there are quite a few that would fail if this was to become the default behavior. Also, when writing tests for an extensions, developers would likely expect the hooks they define to be active, and there would be no obvious way to discover the reason for failure.

We could do the inverse and introduce a clearHooks() method, which would disable all hooks. That would work, but how would it interact with setTemporaryHook()? Would setTemporaryHook() require clearHooks() to be called first? That would be a breaking change as well, which would cause tests in several extensions to fail. Or should setTemporaryHook() imply clearHooks()? That would work, but it's a surprising side effect.

The best I can think of right now is to deprecate setTemporaryHook() in favor of overrideHooks(). Both would imply clearHooks(), and both would have an extra parameter that allows hooks to be listed that should be preserved.

The best I can think of right now is to deprecate setTemporaryHook() in favor of overrideHooks(). Both would imply clearHooks(), and both would have an extra parameter that allows hooks to be listed that should be preserved.

Actually, perhaps better: setTemporaryHook() should go back to simply adding the handler. clearHooks() can be added to create a clean slate, with an option to retain a set of hooks that may be needed.

Change 614880 had a related patch set uploaded (by Nikki Nikkhoui; owner: Nikki Nikkhoui):
[mediawiki/core@master] Fix scopedRegister() handler key

https://gerrit.wikimedia.org/r/614880

Change 614880 abandoned by Nikki Nikkhoui:
[mediawiki/core@master] Fix scopedRegister() handler key

Reason:

https://gerrit.wikimedia.org/r/614880

Change 614880 restored by Nikki Nikkhoui:
[mediawiki/core@master] Fix scopedRegister() handler key

https://gerrit.wikimedia.org/r/614880

Change 614880 merged by jenkins-bot:
[mediawiki/core@master] Fix scopedRegister() handler key

https://gerrit.wikimedia.org/r/614880

Status: this is still broken. I will update the description.

Change 622398 had a related patch set uploaded (by Daniel Kinzler; owner: Daniel Kinzler):
[mediawiki/core@master] HookContainer: fix clear() and scopedRegister().

https://gerrit.wikimedia.org/r/622398

Change 622400 had a related patch set uploaded (by Daniel Kinzler; owner: Daniel Kinzler):
[mediawiki/core@master] Unit tests: simplify setTemporaryHook()

https://gerrit.wikimedia.org/r/622400

Change 622398 merged by jenkins-bot:
[mediawiki/core@master] HookContainer: fix clear() and scopedRegister().

https://gerrit.wikimedia.org/r/622398

Change 622400 merged by jenkins-bot:
[mediawiki/core@master] Unit tests: simplify setTemporaryHook()

https://gerrit.wikimedia.org/r/622400

Can this task be closed?

I believe so.

Change 658619 had a related patch set uploaded (by Reedy; owner: Daniel Kinzler):
[mediawiki/core@REL1_35] HookContainer: fix clear() and scopedRegister().

https://gerrit.wikimedia.org/r/658619

Change 658619 abandoned by Reedy:
[mediawiki/core@REL1_35] HookContainer: fix clear() and scopedRegister().

Reason:

https://gerrit.wikimedia.org/r/658619