Problem/Motivation
We're getting bug reports like this:
We have added a date field to a node type called EVENT. When we use the default admin edit form for the node we have noticed that the values for the date are saved in the database -2hours from what is entered.
There never seems to be any problem when viewing nodes or editing nodes. BUT we are using a REST service to access and write nodes... when we do this to doesn't add or remove the 2 hours either way...
Changing Time Zone of Default Country doesn't change anything either way...
We're a bit confused by this and are wondering what we may be doing wrong. Has anybody else encountered this problem?
IOW: it's not clear that TimestampItem
(and its subclasses CreatedItem
+ ChangedItem
) are storing a UNIX timestamp in the UTC timezone.
Proposed resolution
- New sites should normalize timestamps to
['value' => '2016-11-06T09:02:00+00:00', 'format' => 'Y-m-d\TH:i:sP']
— this makes it crystal clear what the expected format is! - Existing sites continue to normalize timestamps to UNIX timestamps:
['value' => 1478422920]
. They can opt in to the new behavior though. - All sites should denormalize timestamps from UNIX, ISO8601 and RFC3339 formats.
We can't embed additional information in a timestamp. A timestamp is just a number.
IOW: Be conservative in what you send, be liberal in what you accept
.
Why default to RFC3339? Because it's the date & time representation standard on the internet. It is the more precise/strict successor to ISO8601 (technically, it's a profile of ISO8601). Quoting RFC 3339's introduction:
Date and time formats cause a lot of confusion and interoperability problems on the Internet. This document addresses many of the problems encountered and makes recommendations to improve consistency and interoperability when representing and using date and time in Internet protocols.
This document includes an Internet profile of the ISO8601 standard for representation of dates and times using the Gregorian calendar.
Note that you can send ISO8601 or RFC3339 timestamps using any timezone; we'll convert them to UTC before saving. That's why this prevents the annoying/unpleasant surprise described in the problem report!
Remaining tasks
None.
User interface changes
None.
API changes
None.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#125 | interdiff-2768651-125.txt | 1.31 KB | damiankloip |
#125 | 2768651-125.patch | 48.02 KB | damiankloip |
#116 | 2768651-116.patch | 47.97 KB | Wim Leers |
#102 | 2768651-102.patch | 42.35 KB | damiankloip |
#99 | interdiff98_99.txt | 856 bytes | Munavijayalakshmi |
Comments
Comment #2
mpdonadioThe title of this issue is a little confusing here.
Storage is UTC. In the UI, when a user enters a value, DateTimeWidgetBase::massageFormValues() handles the conversion to UTC. On output, the DateTimeFormatterBase::setTimeZone() handles the conversion based on system/user settings.
TBH, I have never thought about this from the REST perspective. Pinging that team now.
Comment #3
apprentia CreditAttribution: apprentia commentedThanks for getting back to us on this issue. We're also going to try to find a solution but if you do get any info we would be grateful.
What do you think the title should be to make it clearer? should I change it now?
Comment #4
mpdonadioI tweaked the title.
Initial thoughts from some other committers where that the server (ie, Drupal) needs to stay UTC, and that the client (ie, you) needs to handle TZ conversion based on your rules.
However, I am trying to get a definitive answer on this from @Crell or @klausi on this.
Comment #5
mpdonadioOK, this is a really good question.
Short answer: client should handle conversion to/from UTC when using the REST w/ entities with datetime fields.
Long answer: REST isn't really timezone aware. The biggest problem is that according to Wim, cacheable metadata isn't woven into the REST system, which is needed for it to be TZ aware.
Comment #6
Wim LeersComment #7
Grayside CreditAttribution: Grayside at Phase2 for Norwegian Cruise Line commentedThis is a good write-up on best practices: http://apiux.com/2013/03/20/5-laws-api-dates-and-times/
Comment #8
Wim LeersEven though this is centered on the
datetime
field, I think this is a generic problem thatrest.module
should have a documented answer for. We also still have thecreated
andchanged
timestamps, which are stored as UNIX timestamps (i.e. integers), and which AFAICT just use the server's timezone.Comment #9
dawehnerIMHO we should just always return UTC and convert, if needed.
Comment #10
Wim Leers#9: sounds sensible to me. But then we should document it as such, and have tests to prove it actually works. So +1.
Note that if it turns out that the
created
andchanged
basefields are actually stored in UTC (which AFAICT is not the case), then maybe this issue can be moved to8.2.x
: if only docs + tests are needed, then this doesn't need to wait for 8.3.Comment #11
Wim LeersComment #12
Wim LeersMarked #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX as a duplicate of this. It contains useful information, especially for the tests that we'll need here.
Comment #13
mpdonadio#8 + #10, Unix timestamps by definition are offsets from 1970-01-01T00:00:00+00:00, so always reference UTC.
Fixed the dup issue.
Comment #14
Wim Leers#13: oh wow, I didn't know that! Feeling like such a noob now :D Is it possible that at some point it was common to have timezone-specific timestamps? Because I definitely remember dealing with timezone-specific timestamps some years ago!
Comment #15
tedbowI created #2824717: Add a format constraint to DateTimeItem to provide REST error message
This should give a more useful message when a datetime value is provided in the wrong format.
Comment #16
Wim LeersYay, thanks for that! Reviewing that patch now.
That new issue addresses the
DateTimeItem
case. But there's also theTimestampItem
case.CreatedItem</code + <code>ChangedItem
extendTimestampItem
, so it affects all "created" and "changed" fields, which almost every content entity type has.So this issue is then solely about
TimestampItem
. A number is a number, so I don't see how we could possibly add a validation constraint. Hence the only thing I think we can do is document this more clearly. For example:The description should become:
The description should become:
I don't think tests are needed.
Alternatively, we could do something very different: we could transform those UNIX timestamps to
2016-11-01T18:46:41
when normalizing. Then we could do proper validation.Because, in the end … why does a REST API consumer have to deal with UNIX timestamps? They're much more familiar with
2016-11-01T18:46:41
. UNIX timestamps actually can be considered an implementation detail.Thoughts?
Comment #17
Wim LeersComment #18
mpdonadio#16, the "alternatively" idea has been bouncing through my head lately because of some of the related issues. Ideally, I think we need to normalize this both inbound and outbound. Right now we are exposing the implementation and not an interface; the API expects people to know about the storage details for different time-related fields. In addition, our storage implementation is a little weird right now (no timezone w/ date+time).
From a REST perspective, we should always give data back in ISO 8601 format (well, the PHP 'c' flavor for date+time and YYYY-MM-DD for date-only) regardless of how we store it. Inbound, we should accept ISO 8601 (a few different variants) and normalize to storage for the item. This gets a bit hairy about how many of the variants we want to accept.
Comment #19
Wim LeersExactly!
+1
I'm not concerned about this. We can become more liberal in what we accept in the future.
Comment #20
Wim LeersNote that using ISO 8601 instead of UNIX timestamps would break BC. So we would need to think about BC:
rest.settings.yml
:In this case, we'd have
bc_timestamp_normalizer: false
(which is set to TRUE automatically in an update hook that will only run for existing sites).Comment #21
jhedstromBig +1 for this.
Comment #22
Wim LeersThanks for chiming in, @jhedstrom!
Comment #23
Wim LeersSo since we seem to be getting consensus… updating issue title.
Comment #24
mpdonadioLet's see how much breaks. Should be BC?
Comment #26
Wim LeersThat code needs to live in a new
TimestampItemNormalizer
class.Comment #27
mpdonadioOK, not 100% sure I am on right track here. Work-in-progress in case I can't wrap this up; if someone wants to pick this up feel free. As soon as I made the patch, I realized the changes to the rest module should really be in the hal module since there is where the config is needed? Also, not sure this class is really being picked up; I never saw my debug when testing and didn't get fails. No interdiff since this is a fresh-start.
Comment #28
Wim LeersThis patch looks like an excellent start! :)
Do you mean the BC layer stuff?
We also need this in
serialization.module
: that module is responsible for JSON, and provides the default normalization. The HAL module extends (decorates if you will) the default normalization, to change those things it needs to change.s/interchance/interchange/ :)
Looking at this again, I think
bc_timestamp_normalizer_unix
would be a more descriptive name.denormalize()
method is missing.Comment #29
mpdonadioYeah, the BC stuff. Since the config is in the new normalizer class in HAL, the setting should probably be moved there.
Comment #30
Wim LeersWell, actually the normalizer belongs in the
serialization
module (see #28.1). So the BC flag would need to be there.But agreed that
rest.settings.yml
is not the right place.Comment #31
jhedstromCan you add a code comment here describing why the first successful format is used? And why one or more might fail?
Should be 'interchange' I think :)
Comment #32
mpdonadioStill a work in progress, but think the feedback is addressed.
Not sure if the denormalize() is right. Does it need to use the $context to name itself and attach to the parent entity?
Kind of torn about whether using the date.formatter is overkill. On one hand, we have the service, so we should use it. On the other, we aren't using the language or timezone support that it provides. Leaning towards using it.
And can't get it to hit debug to see what is really going on when I run various tests.
Will do a Unit test once someone says this looks essentially correct.
Comment #33
Wim LeersI think this looks excellent! I only have nits. What's needed most, is test coverage :)
Nit: Perhaps it's me not being a native speaker, but the "Instead" is fairly confusing to me. I think "Now" would make it clearer.
Nit: s/Unix timestamps/Unix timestamps instead of RFC3339 timestamps for TimestampItem fields/
Nit: s/return/continue to return/
So we allow three formats? That doesn't match the documentation elsewhere.
This ALWAYS returns a UTC timestamp. In >=8.3, it will return a RFC3339-formatted timestamp. In Drupal <8.3, it will return a UNIX timestamp.
IOW: be conservative in what you send: we always send in a single format.
This looks great!
We try all three formats: UNIX, ISO8601 and RFC3339, IOW: be liberal in what you accept.
This should list accepted formats (and possibly provide the request time as an example).
Comment #34
Wim LeersComment #35
Wim LeersComment #36
damiankloip CreditAttribution: damiankloip commentedI didn't see this before, but just noticed it only just got moved to serialization module :) A few comments here:
This will need a priority, otherwise the regular field item normalizer could normalize first. See the EntityRererenceItemNormalizer as an example.
Related to my comment https://www.drupal.org/node/2751325#comment-11794602 I think we should consider not having config knowledge in a normalizer iteself, I don't think this is the right place for that implementation detail to live. Maybe based on the BC option we add the normalizer (or configure it differently) or not.
We shouldn't need to care about the parent here.
Related to the other comment, this is not correct. We just want to return an array with the values here, so ['value' => ...]. This will lead to a normalized structure like
['created' => ['created' => ['value' => 1234567890]]]
etc...This seems kind of inefficient. Maybe we should also consider adding the format to the normalized data too. I think that would be useful either way.
Comment #37
Wim LeersComment #38
Wim LeersDoes that help? :)
Comment #39
damiankloip CreditAttribution: damiankloip commentedAlso, the denormalize() implementation, are you expecting that to get called when denormalizing an entity? It would only get called if you denormalized that particular timestamp item afaict.
Comment #40
Wim LeersYes.
And yes, that's a huge bug in the existing system. For that, we have #2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods.
Comment #41
mpdonadio#33 should be take care of, and I started to stub out a test. Test will fail. I am doing something silly in the setUp, but it is escaping me right now.
#36 should be taken care of, but not sure if using config here and this way is appropriate, and not sure what to do about 36-5. If we don't choose the formats we want to accept, then we need to accept anything and use strtotime(), which can be problematic. Having both \DateTime::ISO8601 and \DateTime::RFC3339 may be overkill, but doing it this way would allow someone to extend the class and just change the list of formats to allow additional ones.
Comment #42
mpdonadioComment #44
damiankloip CreditAttribution: damiankloip commentedWe should probably wait on #2751325: All serialized values are strings, should be integers/booleans when appropriate and #2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods for this now. The first so we can reuse the BC helpers in the compiler pass and the latter so we can have denormalization that works.
Comment #45
damiankloip CreditAttribution: damiankloip at Acquia commentedHere is a rerolled patch that assumes #2751325: All serialized values are strings, should be integers/booleans when appropriate is in. So still needs to wait until then. I made quite a few changes, I have included a kind-of-interdiff file, which is changes I made past porting the patch to use the new changes in #2751325: All serialized values are strings, should be integers/booleans when appropriate. Also note, it moved the single normalization class test to a unit test. I think we should still maybe add some coverage to the rest tests maybe? Similar to the dependent issue.
Comment #46
damiankloip CreditAttribution: damiankloip at Acquia commentedOK, so I realised we need to do some more work if we want this to work everywhere as expected, like for hal. As it's a field level normalizer, we need a separate normalizer for hal that behaves the same as the hal FieldNormalizer (i.e. returns the field structure keyed by field name so it's mergeable by the content entity normalizer). Also added this BC case to the EntityResourceTestBase coverage in the form of a new helper method for timestamp values, as well as introduce a new bc attribute for normalizer service tags. This can then be used more generically by hal and serialization modules.
Comment #47
Wim LeersI like it :)
I'd prefer it if these were tested separately. By having a separate "section" for each BC thing, it's easier to understand.
I know that the code is testing each BC thing in isolation, but I'd just like separate code sections rather than everything in a big "if".
So:
Let's move this outside of
EntityResourceTestBase
, intoBcTimestampNormalizerUnixTestTrait
.Then
NodeResourceTestBase
and others can justuse
that trait.Comment #48
damiankloip CreditAttribution: damiankloip at Acquia commentedSeems fair, this should address those points. Thanks! (Still leaving as needs work for now).
Comment #49
Wim LeersPer #45.
Comment #51
Wim Leers#2751325: All serialized values are strings, should be integers/booleans when appropriate is in! Unblocked.
Comment #55
Wim LeersThis stuff already landed in #2751325: All serialized values are strings, should be integers/booleans when appropriate.
We need to reroll this.
Comment #56
mpdonadioIgnore this patch.
Comment #57
mpdonadioRerolled from wrong point. Having trouble finding a place where #48 actually applies to start from. I think this may be more of a re-do than a straight re-roll.
Comment #58
Wim LeersHere's a careful rebase of #48. Many patches have landed in the mean time that indeed conflicted with it. Fortunately, I reviewed all of them, so I was in a good position to rebase this.
Comment #59
Wim LeersComment #60
Wim LeersMissing
bc_config_name
.I did think to add it to the other one, but I forgot it for the first when rebasing.
Fixed that in this reroll.
Should be updated to match the existing message.
This will be
8401
instead now.s/rest/serialization/
Triple blank line. Should be single.
Comment #61
Wim LeersSo we need to still address:
Comment #62
mpdonadio#60 should be done, and visually verified #60-1 was in.
#47-2 doesn't seem to totally apply any more, but I reordered the code so to match the update hook numbers / version numbers.
#47-3 was already done.
Are we missing anything?
Comment #64
Wim LeersAt first I thought I had introduced an error in a YAML file. But then I saw that
ResolvedLibraryDefinitionsFilesMatchTest
also failed during YAML parsing. We definitely didn't touch that. So something's wrong with either testbot or the PECL YAML extension.Retesting.
Comment #65
Wim LeersI don't like the code that was moved around here. I think it was clearer previously.
So, reverting the move. Keeping the comment changes.
The closing comment for this still has "8.2.x to 8.3.x". Fixed.
Addressed both of those nits myself.
Comment #66
Wim LeersIn #48:
In my #58:
of that same patch inNot quite the same as you can tell. My bad!
That's the biggest problem. But there's more:
This has an indentation of one space, but should be indented by two spaces.
I copy/pasted this from #48, but that key has since changed from
bc_primitive_data_normalizer
tobc_primitives_as_strings
. So this fails of course.All of those are mistakes I introduced, so fixing them myself.
Comment #68
Wim LeersNow: an actual code review!
s/$values/$normalization/
This is repeating itself.
Nest the normalization in another array keyed by field name so that multiple items can be merged cleanly.
Nit: s/array()/[]/
These comments arecopy/pasted from the comment for
bc_primitives_as_strings
and then updated only partially. This does not yet make sense.In fact… this is currently not yet testing anything!
The tests here definitely need work. I also doubt we can test this in the same way that we tested
bc_primitives_as_strings
, because not every entity type even hasTimestampItem
fields. Forbc_primitives_as_strings
, we addedEntityResourceTestBase::castToString()
and called that on an expected normalization. That allows us to test this in a generic way.But the same is not true for timestamp items.
I think the same applies here as what I wrote at #2824717-30: Add a format constraint to DateTimeItem to provide REST error message:
Replace "datetime" with "timestamp" and the exact same strategy can work here too :)
s/$data/$normalization/
Should we also document that
format
is not a property onTimestampItem
? That it is solely there to inform the client that consumes the normalized data?Let's also validate the exception message.
Comment #69
Wim LeersFinally: a look at the BC impact:
#2751325: All serialized values are strings, should be integers/booleans when appropriate defaulted to
FALSE
: i.e. BC layer turned off.I think that in this case, we do want to have the BC layer turned on by default, because the disruption is far greater.
Comment #70
damiankloip CreditAttribution: damiankloip at Acquia commentedAddressed most of the feedback, However, the tests needing work I'm not sure I fully understand yet. To me the concept is the same as the strings. This is what the \Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait::formatExpectedTimestampItemValues method is for, no? This gets the expected result dependent on whether the config setting is set or not. This seems good to me. What am I missing?
EDIT: I also missed points 7 and 8 from your review. Will just wait on the test bot.
Comment #72
Wim LeersSupernit:
$normalized
works, I personally prefer$normalization
.#70 says points 7 and 8 were not yet addressed. Points 4 and 6 were also not yet addressed.
Point 5 is being questioned in #70. And… he's of course entirely right. I forgot about
formatExpectedTimestampItemVAlues()
for a moment! My bad.However, for full test coverage, it'd be nice to supplement the unit test
TimestampItemNormalizerTest
with a functional test as described in point 5, where I point to #2824717-30: Add a format constraint to DateTimeItem to provide REST error message. A function test that tests the various formats of sending a timestamp for denormalization would be valuable.Comment #73
damiankloip CreditAttribution: damiankloip at Acquia commentedThis addresses the other test fails, plus points 4, 7, 8 from #68. RE the $normalization variable name. I am not too keen on that name, as it is more a verb 'normalization', what you actually get is $normalized data. However, this is currently very inconsistent. we use $attributes, $values, and $data in other places.
So this leaves, the variable naming, and the additional test coverage now :) Let's make sure this passes.
Comment #75
Wim Leers"Normalized data" or "a normalization" can both work.
It's "a serialization of an object" and "a normalization of an object".
But I can live with this. I agree that it's "attributes", "values" and "data" that are bad names.
Comment #76
damiankloip CreditAttribution: damiankloip at Acquia commentedI just spent a while debugging this. We had a couple of issues:
- The denormalization for hal was broken, turns out we do really need to use a trait to share the functionality here. So both normalizers (default and hal) can extend their respective base normalizers. This was causing issues with hals handling of translated field values.
- Add a new normalizedFieldValues() for hal normalizers so extended classes can easily override the normalized data
- More test fixes (using the BC trait to construct the values)
And outstanding, there are still a couple of fails, to do with the \Drupal\Tests\rest\Functional\EntityResource\User\UserResourceTestBase::testPatchDxForSecuritySensitiveBaseFields() method I think. It seems that the 422 responses validated contain issues with the normalized data not containing numeric values (timestamp). Denormalization seems to be working ok, so does some validation happen before that or something? on the data? Wim - can you shed any light on this?
Comment #78
Wim LeersI read the #76 interdiff without reading the comment, to check whether I understood it. I think I understood it :)
This is pure refactoring. Logic is unchanged.
Rather than extending
serialization
's timestamp normalizer and adding HAL-specific stuff, we're now extending the HAL field item normalizer and adding timestamp-specific stuff.And so this is why: to reduce the amount of duplication. No more
normalize()
method. Instead override this new protected helper method. And then call a method that lives on a trait, so we can share it among thehal
normalization and the default normalization.The 422 responses wrt not containg numeric values: AFAICT it's due to changes in the normalization.
\Drupal\Tests\rest\Functional\EntityResource\User\UserResourceTestBase::testPatchDxForSecuritySensitiveBaseFields()
is what fails, on its first 422 assertion. With this patch applied, we're getting a different error response: a different validation error.So we must look at the request body we send. The request body that is sent is generated through this code:
Therefore, the content of
$request_options[RequestOptions::BODY]
MUST have changed. Comparing the before vs after should bring us an explanation.Comment #79
damiankloip CreditAttribution: damiankloip at Acquia commentedYes, the request body changed. It now has the formatted timestamp values instead of unix timestamps only. The reason I am confused is that I would have thought the validation runs after denormalization, in which case the values should be replaced with their UNIX timestamp equivalents again?
Comment #80
damiankloip CreditAttribution: damiankloip at Acquia commentedThis should address the sorting mis-match issue. I created a new recursiveKSort helper function on EntityResourceTestBase. This could be moved to a move generic place though?
Comment #82
damiankloip CreditAttribution: damiankloip at Acquia commentedLooks like some menu link REST tests have been added very recently which are now failing (that didn't exist before) because they need to use the new trait.
Comment #83
Wim LeersYes, #2832859: Write EntityResourceTestBase subclasses for: MenuLinkContent landed yesterday.
Comment #85
damiankloip CreditAttribution: damiankloip at Acquia commentedOK, me and Wim did a team effort on this bit of debugging. The short version is that our code in \Drupal\serialization\Normalizer\EntityNormalizer::denormalize() was assuming a fieldable entity type would also be using bundles, which users DO NOT :) So it was falling back to the 'basic' behaviour - which is just calling create with all the data passed in, and hence, no field level denormalization called.
Here is a tests only patch. I added some additional coverage and changed existing expectations to match what they should be. We only really need the bundle specific params to create the entity if it uses bundles. Otherwise, it doesn't really matter (like the case of users).
Comment #87
Wim LeersYAY!
The edge case described in #85 is one we overlooked in #2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods.
This is getting very close. Shall I go ahead and create a change record?
Docs needed.
s/$values/$normalized/
\Drupal\serialization\EventSubscriber\BcConfigSubscriber
should remove the need for rebuilding the container?I know that #2751325: All serialized values are strings, should be integers/booleans when appropriate also added this where it is activating this BC layer, but that can simply be removed.
This is copy/pasted from the comment for
bc_primitives_as_strings
. "values to strings" does not make sense here..
Nit: s/Timestamp Item/TimestampItem/
Nit: Append
|\Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem
.Comment #88
damiankloip CreditAttribution: damiankloip at Acquia commentedThanks Wim, all good points. Hopefully we don't have a need for the rebuildAll() calls anymore and the subscriber can work as expected for tests too!
Comment #90
Wim LeersTitle updated, IS updated & CR created: https://www.drupal.org/node/2859657.
Once the fails in #88 are addressed, this is RTBC.
Comment #91
damiankloip CreditAttribution: damiankloip at Acquia commentedI think these are new fails from the rebuidlAll() removal in the tests.
Comment #92
Wim LeersMehhhh :( Clearly you're right. I wonder why this passed locally without those calls then :( Anyway, that's really a nit in this issue. We shouldn't block this issue on test cleanup.
Per #87, this is now RTBC :)
Awesome work, @mpdonadio & @damiankloip! :)
Comment #93
Wim LeersAs of #2456257-64: [PP-1] Normalizers must set $entity->_restSubmittedFields for entity POSTing/PATCHing to work, this is blocking #2456257. So, tagging and marking since #2456257 is major too.
Comment #94
Wim LeersComment #96
mpdonadioLooks like this needs a reroll.
Comment #97
jofitz CreditAttribution: jofitz at ComputerMinds commentedRe-rolled.
Comment #98
mpdonadioWe need to remove the grouping, #2860096: Remove api doc groups for updates eg. updates-8.2.x-to-8.3.x. Here is my crosspost.
Comment #99
Munavijayalakshmi CreditAttribution: Munavijayalakshmi at Valuebound commentedThe word 'whic' should be changed to the word 'which'.
Fixed typo error and attached new patch.
Comment #100
damiankloip CreditAttribution: damiankloip at Acquia commentedAnother commit credit mining attempt from 'Value Bound' - thanks!
Comment #102
damiankloip CreditAttribution: damiankloip at Acquia commentedThis should fix the test failures, new tests added since the last patch.
Comment #103
Wim LeersYep, #99 started showing failures after #2853211: EntityResource::post() incorrectly assumes that every entity type has a canonical URL was committed yesterday, which added new test coverage, that this patch then also needed to update.
Comment #105
Wim Leers#2843752: EntityResource: Provide comprehensive test coverage for Item entity added new test coverage that now also needs to be updated. Done.
Comment #106
damiankloip CreditAttribution: damiankloip at Acquia commentedLooks good to me!
Comment #107
Wim LeersUpon replying to #2824717-61: Add a format constraint to DateTimeItem to provide REST error message, I wanted to make the comparison to this issue, and recommend it does the same as this issue: support converting from any timezone to UTC, so that the client does not have to deal with that.
The IS says:
But the test coverage only has this:
We should also have test cases with timezones other than UTC.
I added that to the IS in #90. To prove that I have not misunderstood the code, and to prove that that claim is correct, we should expand the test coverage.
So in this reroll, I'm adding four test cases: a positive and a negative offset for both the ISO8601 and RFC3339 test cases cited above. Also updated the CR to provide an example of this.
Comment #108
damiankloip CreditAttribution: damiankloip at Acquia commentedThat seems totally reasonable to me! The test coverage looks good.
Comment #110
Wim LeersRebased. Straight reroll.
Comment #111
Wim Leers#2866083: EntityNormalizer::denormalize() shouldn't require bundle key reported one of the problems fixed by this issue. Closed as a duplicate.
Comment #113
Wim Leers#2843754: EntityResource: Provide comprehensive test coverage for Feed entity landed yesterday, we'll need to update
FeedResourceTestBase
etc in this patch now too. Easy enough.However, the majority of the failures are due to the changes made by #2825973: Introduce a EditorialContentEntityBase class for revisionable and publishable entity types, which causes failures for every entity type that has
PATCH
-protected (i.e. read-only) fields. This should not cause a problem, because logically, we should first check whether a field is read-only or not, and then validate the input value. But, alas the entity validation system that uses Symfony's constraints works in a very illogical order. So, this now fails because we're sending a random string as the value for certain read-only timestamp fields (e.g.changed
), which then results in a 422 with this error message:We encountered this problem before in #2820364: Entity + Field + Property validation constraints are processed in the incorrect order.
Once again the Entity/Field API is blocking progress for REST :(
This should fix the 6
Feed
-related failures.Comment #115
Wim LeersComment #116
Wim LeersWe have only two options here:
EntityResourceTestBase
in #2825973: Introduce a EditorialContentEntityBase class for revisionable and publishable entity types, and instead keep testing the order in which PATCH-protected fields are validated.I vote we go for #2. That means progress now, rather than being held hostage by a chain of issues in another subsystem. Let's be pragmatic.
This effectively reverts all changes to
EntityResourceTestBase
made in #2825973, and instead updates those tests'static $patchProtectedFieldNames
properties that are affected by this.Comment #117
Wim Leersd.o--
Comment #119
damiankloip CreditAttribution: damiankloip at Acquia commentedThis makes sense to me, we could be waiting a long time for this to get resolved via the entity validation system... This is pretty minimal changes to the coverage too. So we have to systematically iterate and remove the patch protected fields as it usually fails on the first one? If so, just wondering if it would be better to go the other way, just add the one specific patch protected field to each request? or do you want to make sure you test multiple in one go?
Other than that clarification, agree this looks great.
Comment #121
damiankloip CreditAttribution: damiankloip at Acquia commentedComment #123
mpdonadioLooks like #2859704: Intermittent segfaults on DrupalCI (some "did not complete due to a fatal error" with no additional info) struck.
Comment #124
alexpottLet's document the array structure. This method is overridden so it'd be useful.
Why are these changes in scope? Test appears to pass without them.
This is kinda sad that we're back to this construction. I tried to run without this change but
Drupal\Tests\rest\Functional\EntityResource\Comment\CommentJsonCookieTest
fails. I guess this is because the order of the normalisers has changed.Comment #125
damiankloip CreditAttribution: damiankloip at Acquia commented1. Documented!
2. Yeah, I think it was more for consistency, but not needed so reverted.
Comment #126
Wim Leers#124.3: See #113 + #116.
Comment #127
alexpottCommitted da74f22 and pushed to 8.4.x. Thanks!
Fixed coding standards on commit.
Comment #129
Wim LeersI can't quite believe this is finally in… :)
Updated #2852860: REST: top priorities for Drupal 8.4.x with the happy news :)
Comment #130
damiankloip CreditAttribution: damiankloip at Acquia commentedWOW!
Comment #131
alexpott