[ProtoApiScrubber] Add Integration Tests#42121
Conversation
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: sumitkmr2 <sumitkmr@google.com>
|
/retest |
adisuissa
left a comment
There was a problem hiding this comment.
Thanks, overall LGTM.
Left a few minor comments.
| 1: 0 | ||
| )EOF"; | ||
|
|
||
| class ProtoApiScrubberIntegrationTest : public HttpProtocolIntegrationTest { |
There was a problem hiding this comment.
What's the reason for extending HttpProtocolIntegrationTest and not HttpIntegrationTest? Does it require AsyncLB?
There was a problem hiding this comment.
Actually, I'm not sure about the exact reason. I followed proto_message_extraction and grpc_field_extraction filters and both use HttpProtocolIntegrationTest. In my view, I think it's better for extensibility when we add support for non-grpc requests carrying protobuf payloads as well. In that case, tests can easily be extended with a one-line change. Let me know if you think this is too-much future proofing and needs to be removed.
| typed_config: | ||
| "@type": type.googleapis.com/xds.type.matcher.v3.CelMatcher | ||
| expr_match: | ||
| {2} |
There was a problem hiding this comment.
Can the expr_match be added in a non copy-paste method?
The reason is that it now depends on the spaces in the config, which makes it brittle to maintain.
There was a problem hiding this comment.
Done. Added in a json format so that indentation is not a problem. Tried doing in a builder fashion but that wasn't much readable (i.e., one can't figure out easily the config while looking at the builder). Hope that json format is ok.
| descriptor_set: | ||
| data_source: | ||
| filename: {0} | ||
| {1} |
There was a problem hiding this comment.
Same as expr_match above.
| restrictions_yaml = fmt::format( | ||
| R"EOF( | ||
| restrictions: | ||
| method_restrictions: |
There was a problem hiding this comment.
Does message_restrictions also need integrations tests?
Also does the method_restriction need to be validated?
There was a problem hiding this comment.
Does message_restrictions also need integrations tests?
Yes, it does. @pranavrautgoogle is working on it and the PR will be out once this PR gets merged.
Also does the method_restriction need to be validated?
Yes, it is already getting validated in the filter_config.cc as of today.
| // TEST GROUP 1: PASS THROUGH | ||
| // ============================================================================ | ||
|
|
||
| TEST_P(ProtoApiScrubberIntegrationTest, UnaryRequestPassesThrough) { |
There was a problem hiding this comment.
Please add a one-liner comment describing what the goal of each test.
| ASSERT_TRUE(response->waitForEndStream()); | ||
| } | ||
|
|
||
| TEST_P(ProtoApiScrubberIntegrationTest, ScrubNestedField) { |
There was a problem hiding this comment.
Please add a test that attempts to scrub a field that is not found in the data.
There was a problem hiding this comment.
By not found in the data., do you mean not found in the descriptors? eg, a newer client library passing a field to an old envoy build? If yes, that case is not handled yet in the code. Planning to add that in next few days. The expectation in that case is that it passes through without scrubbing. I'll add the tests along with it in the UTs itself.
If you mean that it's not found in the filter config (ie, no restrictions configured for the field), then that case is already covered in the UTs and it passes through without scrubbing.
| getFilterConfig(apikeysDescriptorPath(), kCreateApiKeyMethod, "key.display_name")); | ||
| initialize(); | ||
|
|
||
| auto original_proto = makeCreateApiKeyRequest(R"pb( |
There was a problem hiding this comment.
Will it be also useful to test the following cases:
- more than 1 key exists (say
another_namein addition todisplay_name) and only one (display_name) is scrubbed? - not sure if it's valid but a case where there's a double-nested field with the same name
key { key: { display_name: "sensitive" } }.
These may already be addressed by the unit tests, and in that case, that should be sufficient.
There was a problem hiding this comment.
The first one is already covered in the field checker UT.
The second one is interesting and is not covered anywhere, thanks for pointing out! It's a valid case - the field path for respective fields would be key, key.key and key.key.display_name. It's not possible to repro with the ApiKeys service that we are using currently for testing here in IT. I'll that case in the field checker UT where it is much simpler to repro that case. SG?
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
sumitkmr2
left a comment
There was a problem hiding this comment.
Addressed comments, thanks! Will add the requested tests in the field checker UT in a separate PR to avoid conflicts as there are a lot of pending changes going on by myself and Pranav so trying to keep the scope of each PR limited to as less number of files as possible.
| restrictions_yaml = fmt::format( | ||
| R"EOF( | ||
| restrictions: | ||
| method_restrictions: |
There was a problem hiding this comment.
Does message_restrictions also need integrations tests?
Yes, it does. @pranavrautgoogle is working on it and the PR will be out once this PR gets merged.
Also does the method_restriction need to be validated?
Yes, it is already getting validated in the filter_config.cc as of today.
| typed_config: | ||
| "@type": type.googleapis.com/xds.type.matcher.v3.CelMatcher | ||
| expr_match: | ||
| {2} |
There was a problem hiding this comment.
Done. Added in a json format so that indentation is not a problem. Tried doing in a builder fashion but that wasn't much readable (i.e., one can't figure out easily the config while looking at the builder). Hope that json format is ok.
| descriptor_set: | ||
| data_source: | ||
| filename: {0} | ||
| {1} |
| // TEST GROUP 1: PASS THROUGH | ||
| // ============================================================================ | ||
|
|
||
| TEST_P(ProtoApiScrubberIntegrationTest, UnaryRequestPassesThrough) { |
| ASSERT_TRUE(response->waitForEndStream()); | ||
| } | ||
|
|
||
| TEST_P(ProtoApiScrubberIntegrationTest, ScrubNestedField) { |
There was a problem hiding this comment.
By not found in the data., do you mean not found in the descriptors? eg, a newer client library passing a field to an old envoy build? If yes, that case is not handled yet in the code. Planning to add that in next few days. The expectation in that case is that it passes through without scrubbing. I'll add the tests along with it in the UTs itself.
If you mean that it's not found in the filter config (ie, no restrictions configured for the field), then that case is already covered in the UTs and it passes through without scrubbing.
| getFilterConfig(apikeysDescriptorPath(), kCreateApiKeyMethod, "key.display_name")); | ||
| initialize(); | ||
|
|
||
| auto original_proto = makeCreateApiKeyRequest(R"pb( |
There was a problem hiding this comment.
The first one is already covered in the field checker UT.
The second one is interesting and is not covered anywhere, thanks for pointing out! It's a valid case - the field path for respective fields would be key, key.key and key.key.display_name. It's not possible to repro with the ApiKeys service that we are using currently for testing here in IT. I'll that case in the field checker UT where it is much simpler to repro that case. SG?
| 1: 0 | ||
| )EOF"; | ||
|
|
||
| class ProtoApiScrubberIntegrationTest : public HttpProtocolIntegrationTest { |
There was a problem hiding this comment.
Actually, I'm not sure about the exact reason. I followed proto_message_extraction and grpc_field_extraction filters and both use HttpProtocolIntegrationTest. In my view, I think it's better for extensibility when we add support for non-grpc requests carrying protobuf payloads as well. In that case, tests can easily be extended with a one-line change. Let me know if you think this is too-much future proofing and needs to be removed.
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
adisuissa
left a comment
There was a problem hiding this comment.
Thanks, overall LGTM.
Can you please run this under tsan with runs_per_test=1000 to reduce the chances of introducing flaky tests?
| const std::string kCreateApiKeyMethod = "/apikeys.ApiKeys/CreateApiKey"; | ||
|
|
||
| // CEL Matcher Config (Protobuf Text Format) which evaluates to TRUE. | ||
| const std::string kCelAlwaysTrue = R"pb( |
There was a problem hiding this comment.
nit: preffer constexpr absl::string_view
|
|
||
| // Format the full config. | ||
| full_config_text = fmt::format(R"pb( | ||
| filtering_mode: OVERRIDE |
There was a problem hiding this comment.
nit: use yaml instead of this (no need for double curly brackets everywhere, and makes the code a bit more concise - example).
There was a problem hiding this comment.
Yeah, it was in yaml before but changed it to json due to spacing constraints while doing replacement of parameters {0}, {1}, etc. as discussed here.
In json, spacing doesn't matter so it's not brittle now.
There was a problem hiding this comment.
Another approach is using a different approach than format replace.
What about using a format replacement for simple elements (strings, numbers), and using the protobuf methods (e.g., PackFrom()) for non-simple elements?
There was a problem hiding this comment.
I've refactored the code to make it more configurable and readable at the same time. Let me know if this looks better now. Also, I'll be adding more Integration tests with different input types and different CEL expressions, etc. in follow-up CLs.
There was a problem hiding this comment.
I think we are back to square 1 with this, but as you will be the codeowner on this and it is only test code, then I can live with that.
| EXPECT_EQ("3", grpc_status->value().getStringView()); // 3 = Invalid Argument | ||
| } | ||
|
|
||
| INSTANTIATE_TEST_SUITE_P(Protocols, ProtoApiScrubberIntegrationTest, |
There was a problem hiding this comment.
style-nit: please move right after the class declaration.
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
sumitkmr2
left a comment
There was a problem hiding this comment.
Addressed comments, thanks!
Also, ran the following command to test flakiness:
envoy$ bazel test --config=tsan --runs_per_test=1000 --cache_test_results=no --test_output=errors //test/extensions/filters/http/proto_api_scrubber:integration_test
INFO: Invocation ID: d9aed359-0255-4f37-964a-ce8f86721e2f
INFO: Analyzed target //test/extensions/filters/http/proto_api_scrubber:integration_test (0 packages loaded, 20 targets configured).
INFO: Found 1 test target...
Target //test/extensions/filters/http/proto_api_scrubber:integration_test up-to-date:
*****/execroot/envoy/bazel-out/k8-fastbuild/bin/test/extensions/filters/http/proto_api_scrubber/integration_test
INFO: Elapsed time: 786.311s, Critical Path: 114.53s
INFO: 1001 processes: 1 internal, 1000 linux-sandbox.
INFO: Build completed successfully, 1001 total actions
Executed 1 out of 1 test: 1 test passes.
|
|
||
| // Format the full config. | ||
| full_config_text = fmt::format(R"pb( | ||
| filtering_mode: OVERRIDE |
There was a problem hiding this comment.
Yeah, it was in yaml before but changed it to json due to spacing constraints while doing replacement of parameters {0}, {1}, etc. as discussed here.
In json, spacing doesn't matter so it's not brittle now.
| EXPECT_EQ("3", grpc_status->value().getStringView()); // 3 = Invalid Argument | ||
| } | ||
|
|
||
| INSTANTIATE_TEST_SUITE_P(Protocols, ProtoApiScrubberIntegrationTest, |
| const std::string kCreateApiKeyMethod = "/apikeys.ApiKeys/CreateApiKey"; | ||
|
|
||
| // CEL Matcher Config (Protobuf Text Format) which evaluates to TRUE. | ||
| const std::string kCelAlwaysTrue = R"pb( |
Signed-off-by: Sumit Kumar <sumitkmr@google.com>
sumitkmr2
left a comment
There was a problem hiding this comment.
Addressed pending comment.
|
|
||
| // Format the full config. | ||
| full_config_text = fmt::format(R"pb( | ||
| filtering_mode: OVERRIDE |
There was a problem hiding this comment.
I've refactored the code to make it more configurable and readable at the same time. Let me know if this looks better now. Also, I'll be adding more Integration tests with different input types and different CEL expressions, etc. in follow-up CLs.
|
|
||
| // Format the full config. | ||
| full_config_text = fmt::format(R"pb( | ||
| filtering_mode: OVERRIDE |
There was a problem hiding this comment.
I think we are back to square 1 with this, but as you will be the codeowner on this and it is only test code, then I can live with that.
| getFilterConfig(apikeysDescriptorPath(), kCreateApiKeyMethod, "key.display_name")); | ||
| initialize(); | ||
|
|
||
| auto original_proto = makeCreateApiKeyRequest(R"pb( |
Signed-off-by: Sumit Kumar <sumitkmr@google.com> Signed-off-by: sumitkmr2 <sumitkmr@google.com> Signed-off-by: Gustavo <grnmeira@gmail.com>
Commit Message: Add Integration tests.
Additional Description: Currently, the tests are added using envoy_cc_extension as envoy_extension_cc_test fails to recognize the extension as it's not registered. Once the filter's core functionality is complete, we'll do the registration and update the build rule. Currently, only request integration tests are added as response flow is not ready. Response ITs will be added once response flow code is checked-in.
Risk Level: None.
Testing: ITs added.
Docs Changes: None.
Release Notes: None.
Platform Specific Features: None.
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Fixes commit #PR or SHA]
[Optional Deprecated:]
[Optional API Considerations:]