Skip to content
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

test: add a baseline test that covers possible naming conflicts #668

Merged
merged 6 commits into from
Aug 25, 2020

Conversation

alexander-fenster
Copy link
Contributor

This PR adds a baseline test for one Very Bad Proto. This proto is so bad that the generated library will never compile (I left some comments below to show the problems).

We have some naming problems in the generator that do not affect any existing API so far, but one of those problem (the *Stream one, see below) affects Ads APIs and will backfire when we start generating Ads TypeScript client library.

Currently, the client library class has some extra stuff that can have name conflicts with protobuf methods:

  1. For any paginated method method, we generate extra functions methodStream and methodAsync, both can conflict with an actual RPC with the same name. (this is what happens with Ads protos - they have a paginated rpc Something and also rpc SomethingStream)

  2. For any long running method method, we generate an extra function checkMethodProgress which can conflict with an actual RPC with the same name.

  3. We have some other methods in our class (e.g. initialize and getProjectId) which will conflict with RPCs with the same names.

  4. An RPC can be named in a way that won't work in TypeScript (e.g. rpc Constructor or rpc Function). This is discouraged by AIPs but possible.

As a result, the generator works perfectly in these cases, but the resulting code cannot compile.

This proto does not currently handle all bad use cases (e.g. the one in #609 is not covered) but I will update it with more naming conflict findings.

These problems are going to be solved by some naming refactor (I'm still thinking about the proper design), and when the code for the naming baseline finally compiles, I'll add its compilation to CircleCI to make we don't break things after this is fixed.

Cc: @noahdietz - as we discussed in the chat, it might be only TypeScript problem for now, but I guess we still can have problems with reserved words in other languages. Do you think making this kind of "bad bad proto" (covering all languages and not just TypeScript) would make sense as a team effort?

@alexander-fenster alexander-fenster requested a review from a team as a code owner August 20, 2020 23:47
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Aug 20, 2020
* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
initialize(
Copy link
Contributor Author

@alexander-fenster alexander-fenster Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops! we already have initialize above

* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
servicePath(
Copy link
Contributor Author

@alexander-fenster alexander-fenster Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops! we already have servicePath above

* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
apiEndpoint(
Copy link
Contributor Author

@alexander-fenster alexander-fenster Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops! we already have apiEndpoint above

* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
port(
Copy link
Contributor Author

@alexander-fenster alexander-fenster Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops! we already have port above

* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
scopes(
Copy link
Contributor Author

@alexander-fenster alexander-fenster Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops! we already have scopes above

* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
getProjectId(
Copy link
Contributor Author

@alexander-fenster alexander-fenster Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops! we already have getProjectId above

* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
function(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just oops

* The first element of the array is an object representing [Empty]{@link google.protobuf.Empty}.
* The promise has a method named "cancel" which cancels the ongoing API call.
*/
constructor(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big ooops

* console.log(decodedOperation.metadata);
*
*/
async checkLongRunningProgress(name: string): Promise<LROperation<protos.google.protobuf.Empty, protos.google.protobuf.Empty>>{
Copy link
Contributor Author

@alexander-fenster alexander-fenster Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops! We already has this one.

* @returns {Stream}
* An object stream which emits an object representing [Empty]{@link google.protobuf.Empty} on 'data' event.
*/
paginatedMethodStream(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name conflict again.

* @returns {Object}
* An iterable Object that conforms to @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols.
*/
paginatedMethodAsync(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name conflict as well.

@noahdietz
Copy link
Contributor

as we discussed in the chat, it might be only TypeScript problem for now, but I guess we still can have problems with reserved words in other languages. Do you think making this kind of "bad bad proto" (covering all languages and not just TypeScript) would make sense as a team effort?

  1. I think a general effort to improve fuzzing across plugins would be nice-to-have
  2. I think we should consider what we want to get out of such a "bad bad proto" - just testing? do we want to front it with an AIP of "forbidden names"?

What are we really trying to achieve with such a proto? I see in your description you're going to check this in once all of the naming issues are resolved. Do you plan on fixing all such collisions? What if some names should not be used ever? We can probably make some guidance for that (e.g. "never name an RPC 'Public'" for java or something like that).

Copy link
Contributor

@xiaozhenliu-gg5 xiaozhenliu-gg5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some thoughts:

  1. checkMethodProgress for LRO methods, is it doing the same thing as our added checkMethodProgress helper? If it is, we probably wanna replace it, if not, we can change to another name for avoiding conflict.
  2. when the rpc name hits the reserved words like function, should we throw error for them during generation? Otherwise, if we put this naming.proto to gapic-showcase, we probably wanna add more reserved words for other languanges like class, enum, etc. @noahdietz
    Thank you!

@alexander-fenster
Copy link
Contributor Author

@xiaozhenliu-gg5 re: checkMethodProgress - just imagine that this is some completely unrelated RPC in the proto, that happens to be in conflict with what we generate. Similar to how *Stream or *Async will be in conflict if a method with this name exists - this is what actually happened :)

@xiaozhenliu-gg5 @noahdietz re: "bad names", unfortunately, the corresponding AIP is not strict enough - AIP-140 only suggests that field names should not use words that might be reserved, and there is no guidance on method names. So all examples above are perfectly valid from AIP point of view.

What I'm planning to do with this is to introduce a simple method renaming logic in the generator - basically, the generator should know of the reserved names (all RPC names and language keywords) and it should not add conflicting names to the class. I expect to make the generator finally generate a working library based on this bad proto (which I consider to be AIP-compliant), but this is not the main goal here.

The main goal is to have a test coverage for this planned refactor. Before I can start working on this refactor, I must have a baseline test checked in, because it's the only way to cover the refactored code with tests (since all our existing tests do not have naming conflicts, the name resolution logic will never trigger in the regular test coverage). Hence this new baseline.

I started this because of an Ads method that triggered the naming conflict similar to #1 above, and with this baseline, the future change to *Stream method will be visible. I may or may not fix other problems listed, but at least we'll have a test that shows the current behavior.

@alexander-fenster alexander-fenster merged commit 97476f5 into master Aug 25, 2020
@alexander-fenster alexander-fenster deleted the name-conflict-test branch August 25, 2020 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants