Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
See #2735005: Convert all Simpletest web tests to BrowserTestBase (or UnitTestBase/KernelTestBase)
Scope:
Drupal\page_cache\Tests\PageCacheTagsIntegrationTest
Drupal\page_cache\Tests\PageCacheTest
Extra changes:
We introduce a helper function getHeaders()
to request headers from various urls. We not use drupalGet()
for this, because it works via Guzzle clients, which always normalizes URLs, eg:
That prevents testing all possible edge cases. See thorough review in #34.
Comment | File | Size | Author |
---|---|---|---|
#51 | interdiff-2870457-45-51.txt | 764 bytes | ApacheEx |
#51 | 2870457-51.patch | 11.02 KB | ApacheEx |
Comments
Comment #2
michielnugter CreditAttribution: michielnugter as a volunteer and at Synetic commentedComment #3
andypostInitial conversion
Comment #5
dawehnerFor me it would be totally fine to inline these 3 lines of code needed for
\Drupal\simpletest\WebTestBase::setHttpResponseDebugCacheabilityHeaders
It is used twice in the entirety of core.
Comment #6
michielnugter CreditAttribution: michielnugter as a volunteer and at Synetic commentedComment #7
andypostInlined cacheability disabling
Comment #8
dawehnerThank you @andypost
I strongly hope this passes it now :) Maybe still open up an issue to add such a method to something, it can't hurt.
Comment #9
andypost@dawehner do you mean to extend
AssertLegacyTrait
or separate trait cos usage after patch isComment #11
naveenvalechaHere's the patch which added the drupalHead function to the BTB base class to get it's passed. However, the tests are failing on local due to the headers response code in testConditionalRequests. The request is expecting not modified(304) but the drupalGet function in BTB is returning 200 which I'm not sure why it's happening
//Naveen
Comment #13
naveenvalechaPageCacheTest module requires the couple of assertions which needs to be added before converting them.
BTB drupalGetHeader function is calling getResponseHeader of Mink Session class which internally changing the string to lowercase which making couple of tests fail.
How about overriding this method in BTB? Let's continue this discussion in follow-up issue and let keep this issue for minimal disruption.
//Naveen
Comment #14
Lendude@naveenvalecha hmmm not sure if it's worth splitting this off, since that just leaves 1 test in this patch. I would opt for trying to get PageCacheTest to pass here. If it really needs new methods to be added, lets make an issue for that, then we just postpone on that issue.
Comment #15
nlisgo CreditAttribution: nlisgo commentedComment #17
andypostreplace curl with guzzle + fix docblock
btw it makes sense to split this out of the test to separate unit
Comment #19
dawehnerThis fixes one of the failures.
Comment #21
dawehnerI couldn't figure out
testNoUrlNormalization
yet.Comment #24
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedHere is a patch. There are some things which I want to highlight:
I removed it because guzzle client (which is default for BrowserTestBase) uses parse_url for building the URL and in this case
parse_url('http://drupal.org/?') will be exactly the same as parse_url('http://drupal.org/'). Hope, it's clear.
Comment #26
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedHopefully, this fixes one of the failures.
Comment #27
Wim Leers👏
These changes are out of scope.
Also out of scope.
Same.
Again.
Same and same.
Basically, the patch seems to be doing lots of great improvements, but they're out of scope here. The point of these "convert to
BrowserTestBase
issues" is to keep the set of changes as small as possible: the bare minimum to switch fromWebTestBase
toBrowserTestBase
.I see that in #21, the patch was 10.67 KB. And in #24, it was 39.42 KB. So it seems that @ApacheEx added all of these. Which is great! But those changes should be made in another issue, after this issue lands. We call that a "followup issue".
@ApacheEx, thanks for your great work :) But could you split off the non-essential changes to a separate patch that you post in a new followup issue? Once you've done that, I'll be able to RTBC this issue (and then once this is committed, I'll be able to RTBC the followup issue — because all of your changes in #24 look wonderful! 👌).
Comment #28
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedThank you for your great feedback. Yeah, I was a bit carried away :)
Here is a patch with minimal changes (WebTestBase => BrowserTestBase) to pass all tests.
p.s. I'll create a follow-up issue and put #24 there.
p.s.s I've also attached two interdiffs (from #21 and #24) to see differences.
Comment #29
andypostChanges looks great except nitpick
why that removed?
Comment #30
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commented@andypost,
I can explain:
- in WebTestBase we have curl as default client.
- in BrowserTestBase we have guzzle as default client.
Let's imagine that:
So, curl makes a request to that URL as is without any transformations.
The requests will look like:
- http://drupal.org/? - MISS
- http://drupal.org/? - HIT
- http://drupal.org/ - MISS
it means all tests passed.
But guzzle uses \GuzzleHttp\Psr7\Uri which composes a URI string from its various components.
The requests will look like:
- http://drupal.org/? - MISS (will be transformed to http://drupal.org/ by \GuzzleHttp\Psr7\Uri::__toString)
- http://drupal.org/? - HIT (will be transformed to http://drupal.org/ by \GuzzleHttp\Psr7\Uri::__toString)
- http://drupal.org/ - HIT (Failed, the expected result is MISS).
it means, one of the tests failed
I've tried to solve this, but it looks like impossible with Guzzle.
Hope, it's clear now.
Comment #31
Wim LeersThis can be removed too, it also belongs in the followup. :)
I agree with andypost about this. This is removing test coverage. It was added in #2761639: PageCache should not use $request->getUri(). We should be careful when removing test coverage.
Are you sure that Guzzle is getting in the way for
\Drupal\page_cache\Tests\PageCacheTest::testNoUrlNormalization()
? That test method is not explicitly using Guzzle, it's not constructing a URL explicitly.Comment #32
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commented1.
It's used, here is a proof after re-testing:
2. Guys, I agree with you that removing of test coverage is not a good idea. I'll try to figure out if this can be solved in another way.
Comment #33
Wim LeersComment #34
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedok, there is my investigation:
How BrowserWebBase::drupalGet does a request for testNoUrlNormalization
Sequence of calls:
- here is how GuzzleHttp\Psr7\Request handles an URL ($uri is http://d8.docksal/?):
- here is how GuzzleHttp\Psr7\Uri constructs an URL ($uri is http://d8.docksal/?):
- here is how GuzzleHttp\Psr7\Uri outputs an URL (and now we have http://d8.docksal/ instead of http://d8.docksal/?):
- Here is how parse_url works with this test case (see #29):
- Here is how tests work without test case (see #29). BTW, I've modified (a bit) tests to show how some things work.
code: https://gist.github.com/ApacheEx/65ad1d016062a106bad6778e01dbaaed
logs:
- Here is how test case works (see #29). BTW, I've modified (a bit) tests to show how some things work.
code: https://gist.github.com/ApacheEx/b140c4fec21e2af8327adebad1d16c79
logs:
You can notice that URL before drupalGet and after drupalGet was modified from http://d8.docksal/? to http://d8.docksal/
That's why we get HIT instead of MISS in this assert:
Why all test cases from testNoUrlNormalization have passed (WebTestBase)
Heh, drupalGet uses curlExec which builds an URL in Drupal way with WebTestBase::buildUrl
for example http://d8.docksal/? will be the same as WebTestBase::buildUrl('http://d8.docksal/?'), what I can't say about GuzzleHttp\Psr7\Uri ;(
How to fix it?
To be honest, I have no idea, all requests should be done by Client which implements GuzzleHttp\ClientInterface. It's not a solution to rewrite something there. What should we do then? Any ideas? Does it mean we should remove #29 from test coverage and use a patch from #28?
Comment #35
Anonymous (not verified) CreditAttribution: Anonymous commentedNice investigation @ApacheEx! It very useful for re-check what was happening here. Thanks!
Only one correction:
Because we lost
/?
after this operation.This is not true. The main goal of this test is to check the caching system with different url combinations. Therefore, if the current Client is not work, we are need to look for another one. I think this is exactly what the reviewers alluded to ;)
Yes, it will not be minimal changes (one of main rule for convert to BTB), but this rule ceases to be important when regression occurs.
So, let's just use the curl request.
Comment #36
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedyeah, that's true. But anyway, after this operation it goes to GuzzleHttp\Psr7\Request::__construct where again we have new Uri()
and here is a patch with some minimal corrections of your changes if you don't mind:
- I have added the test case which was removed by me in #28 :)
- Some CS fixes.
thank you for your feedback.
Comment #38
Anonymous (not verified) CreditAttribution: Anonymous commented@ApacheEx++, indeed, thanks!
Comment #39
Wim LeersThis is lacking an explanation for why this helper method exists.
Once that's done, this is RTBC. Great work, @vaplas and especially @ApacheEx! 👏
Comment #40
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedThanks,
what about this?
Comment #41
Wim Leersis still not entirely clear.
What about:
Comment #42
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedYeah, I agree.
Here is updated patch (hopefully the final version).
Comment #43
Wim LeersComment #44
alexpottI don't think we should mention drupalHead() here because eventually that code will disappear and this comment will be obsolete. The bit in brackets is the important thing - that we can't use Guzzle because it is going to normalise the request. (So it probably shouldn't be in brackets). I.e. maybe:
Also, I'm wondering if we should think about adding a general trait as drupalHead() is used in DownloadTest and contrib's redirect module tests. Not sure about that as the code added here is not general. Probably not worth it.
$expected comes first and I think I would actually bother with this. I'd just do (for example)
in the loop.
There's less indirection and less to think about.
Comment #45
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Drupal Ukraine Community commentedthank you for your review :)
1. I don't think that we need the drupalHead. It can be replaced by drupalGet in most cases I guess or even $client->request('HEAD'). Btw, I'm a bit modified text if you don't mind.
2. Fixed.
Comment #46
Anonymous (not verified) CreditAttribution: Anonymous commentedNice catches and fixes from #38 to #45! +1 to RTBC!
Comment #47
dawehnerI'm not convinced that testing
foo/?
vsfoo/
is actually worth testing, maybe its just me, but at least for me this is something a functional test coverage should not care about. If you care about that level of testing, better write a integration/kernel test.Comment #48
Wim Leers#47: That test was explicitly added in #2761639: PageCache should not use $request->getUri(), at @Berdir's request in #2761639-29: PageCache should not use $request->getUri(). I think it kinda makes sense to have in a functional test.
Comment #49
Anonymous (not verified) CreditAttribution: Anonymous commentedYep, @Berdir wrote:
By analogy, we can say that this example also shows the problem of phpunit, since the URL processing in Guzzle and Drupal is not equivalent.
By the way, phpunit has one more helper, which sometimes has a disservice - Behat/Mink. It is used in drupalPostForm, and as result we cann't send form with next set:
As a result, we have not simple tools for test various exploits that a user can do with a session and form tokens. See also #5.1 and #5.2 from #2809503: Convert AJAX part of \Drupal\file\Tests\FileFieldWidgetTest to JavascriptTestBase.
Comment #50
LendudeAbout #47, I think it's worth discussing if this is the right way to test this (because my initial reaction is that I agree that this is the wrong type of test for this), and I think core tests should serve as examples of how to test certain scenarios, but I'd opt to do so in a follow up.
The test exists currently, this issue is about converting existing test coverage with minimal changes. The changes here look as minimal as possible given all the previous findings. So I'd go with just leaving it as is for now.
On the patch:
Great work on this, and great research! Bit of nitpicking:
'the Guzzle'? Just 'Guzzle' would do here.
We are not using the internal browser, we are using cURL, that's the whole point of this method right?
More importantly: can we get some of the research from #34/#35 into the IS? It's a little minimal at the moment.
Comment #51
ApacheEx CreditAttribution: ApacheEx as a volunteer and at Internetdevels, Drupal Ukraine Community commentedmany thanks for reviewing, here is the patch.
Will try to update IS later or somebody else will do it.
Comment #52
dawehnerThank you @Lendude for providing an answer. I agree now, as long we clearly document why we are doing things a certain way.
It is great that we document why we need this.
Comment #53
Anonymous (not verified) CreditAttribution: Anonymous commentedShort note about extra changes was added to IS.
Comment #54
alexpottGiving credit to @Wim Leers, @Lendude and myself for reviews that influenced the direction of the patch and detailed why the approach taken is correct.
I've removed the "needs followup" tag because it was added #27 because the changes that were out-of-scope were all about removing deprecated usages or usages of the legacy layer in browser test base. These tasks should not be limited to fixing just one test but should be automated and done on a per method level.
Comment #55
alexpottCommitted and pushed 40698c6c8b to 8.5.x and dc14cf8150 to 8.4.x. Thanks!
Backported to 8.4.x as this is a test-only change.