-
Notifications
You must be signed in to change notification settings - Fork 944
Switch serializer tests to test round trips + remove deprecated grpc.load() #1699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Rather than separate tests for encoding/decoding. Similar to the other platforms.
); | ||
const proto: api.Value = { | ||
timestampValue: (expectedJson[i] as unknown) as string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why the proto's timestampValue is typed as a string? But I also have no idea how protobufjs works.
I also needed the same trick down below in the bytes section, though at least in that case, it sort of makes sense... since at least some of the time this is actually a base64 encoded string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the backend accepts either a timestamp proto or a UTC string and our proto .d.ts file is currently typed as a string (https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/src/protos/firestore_proto_api.d.ts#L356). Per the conversation in chat, I think we can probably go ahead and just fix the d.ts file (so it accepts either format I guess).
// clang-format on | ||
}); | ||
}); | ||
const proto: api.Value = expectedJson; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding this comment which I deleted: "Compare the raw object ... in the event of an inequality".
After my change (I didn't test it before my change), I found this to be incorrect. If I introduced an inequality and ran the tests a few times, the tests always completed with the error string properly generated. As a result, I eliminated the special casing here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use jasmine anymore, so this is very likely fine. :) Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't done a fully detailed review yet but at a high-level I think I'm mostly on board with this (thanks a ton for tackling all of this). I left a few comments and I do have a bit of reservation about no longer constructing actual proto objects. As-is if you make a mistake in serializer.ts with the JSON we generate such that the JSON is wrong, the serializer tests won't notice as long as you make the mistake in both the serialization and deserialization methods. In theory the JSON representation of the protos is strongly typed based on https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/src/protos/firestore_proto_api.d.ts#L1, but there are some nuances / hacks because grpc and webchannel speak slightly different dialects of JSON protos so it's still conceivable we could screw something up... though presumably integration tests would catch it.
If we wanted to round-trip through the actual proto object that gRPC uses (similar to the way the tests did before), I think we could just load the protos directly in our tests via protobufjs instead of going through @grpc/proto-loader
and then we'd get access to the constructors as before. Basically just copy the gprc/proto-loader loadSync() code: https://github.com/grpc/grpc-node/blob/073dc563858a2d74bd114e5cc50d02203123078f/packages/proto-loader/src/index.ts#L314
I'd be a fan of that change, but if you don't feel like taking it on, I can probably get behind this PR as-is or else I might take a stab at it myself...
|
||
// Beware that converting fields to camel case does not convert the tag fields | ||
// in oneof groups (!!!). This will likely be fixed when we upgrade to | ||
// protobufjs 6.x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment is probably stale since:
- gprc/proto-loader pulls in protobufjs 6.8.6.
- This comment used to be referring to our usage of 'convertFieldsToCamelCase' which no longer exists.
I think this comment is referring to the fact that the tag fields are named value_type
, response_type
, etc. instead of valueType
, responseType
, etc. And I guess this is not going to change (since you didn't have to change that code in serializer.ts), so I would just drop the comment.
defaults: true, | ||
oneofs: true, | ||
includeDirs: [root] | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's worth commenting these options a bit so somebody (future me) doesn't have to go look up the grpc docs to figure out what they mean...
@@ -0,0 +1,882 @@ | |||
// Protocol Buffers - Google's data interchange format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to verify (I'm too lazy to diff), did you copy this from https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto ?
Can you update https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/src/protos/update.sh to automatically copy it?
// as optional fields. To stay consistent, we'll still test for the given | ||
// tag's presence here, though we won't test for absence of all other | ||
// fields. | ||
expect(actual[tag]).to.not.be.undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hrm...
- Since the following expectation fully verifies the contents of
actual
, it seems like this must be redundant, no? Or is this meant to verify the test is written correctly? If so, consider using an assert() instead. - The old code verified that the serializer generated protos that contain value_type, which I think was important. If I'm understanding correctly from
* Checks for a specific oneof tag in a protocol buffer message. value_type
but require input messages to havevalue_type
. But I wonder if that asymmetry still exists (or if we can avoid it by tweaking the options we pass to loadSync()).
So I think we need to rework the test to verify the serializer generates (and accepts) value_type
or else rework the serializer so we don't need the hasTag()
mess (which would be amazing if it works).
); | ||
const proto: api.Value = { | ||
timestampValue: (expectedJson[i] as unknown) as string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the backend accepts either a timestamp proto or a UTC string and our proto .d.ts file is currently typed as a string (https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/src/protos/firestore_proto_api.d.ts#L356). Per the conversation in chat, I think we can probably go ahead and just fix the d.ts file (so it accepts either format I guess).
// clang-format on | ||
}); | ||
}); | ||
const proto: api.Value = expectedJson; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use jasmine anymore, so this is very likely fine. :) Thanks!
@@ -31,6 +31,7 @@ | |||
"@firebase/logger": "0.1.11", | |||
"@firebase/webchannel-wrapper": "0.2.17", | |||
"grpc": "1.19.0", | |||
"@grpc/proto-loader": "^0.4.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to run yarn
or yarn install
from the root and check in the resulting yarn.lock
file.
new fieldValue.BlobValue(blob) | ||
); | ||
expectRoundTrip(objValue, proto, 'mapValue'); | ||
// clang-format on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this?
Take a look at this: #1669. It's my first attempt; I don't like it as much, but I think it does what you're suggesting. I think it may be possible to meld these two together, so that we still get access to the underlying ctors, but also can eliminate all the fromFoo tests. If that's what you had in mind, then I'll tackle it. |
Oh! Yes, #1669 is very much what I had in mind, but yeah, I think combining that with all the cleanup you did here would be great. Basically make your "roundtrip" methods also construct the real proto instead of just the JSON representation (maybe even encode to bytes and back to JSON?). That would make these tests really nice. |
Could we meld these two approaches together by essentially running the round trip twice? Once directly and once through protos? This would have the same benefit of reducing the volume of tests, while giving us the same net coverage. Note that this is at least conceptually similar to what we're doing in the C++ serialization tests, where we're validating that our serialization generates bytes that libprotobuf can parse. There we modified the round trip validation to check both paths. Though the particulars are different here, could the same approach work? |
LOL. I wish I refreshed before posting. |
Closing in favour of #1669 (which contains the relevant bits from this pr) |
Separately (though related) this PR also removes the deprecated grpc.load() method. The old tests relied on grpc.load() exposing the proto constructors (which the new protoLoader does not do.)