Skip to content

test: remove port dependency from integration tests (#574).#650

Merged
mattklein123 merged 6 commits intoenvoyproxy:masterfrom
htuch:integration-port-free
Mar 30, 2017
Merged

test: remove port dependency from integration tests (#574).#650
mattklein123 merged 6 commits intoenvoyproxy:masterfrom
htuch:integration-port-free

Conversation

@htuch
Copy link
Copy Markdown
Member

@htuch htuch commented Mar 29, 2017

No description provided.

@htuch
Copy link
Copy Markdown
Member Author

htuch commented Mar 29, 2017

@jamessynge @mattklein123

Comment thread source/server/server.cc
}

Network::ListenSocket* InstanceImpl::getListenSocketByIndex(uint32_t index) {
if (index < config_->listeners().size()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: this is kind of an odd impl for this function (requiring advancing from beginning by N each time). I know this is only used in test code, but can we potentially implement with a for loop over list elements which also increments an index?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Why's it faster to iterate over the list rather than advance an iterator? AFAIK, you can't randomly access an element in std::list, so you have to do something O(n).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry, nevermind, I misread. This is fine.

Comment thread test/integration/fake_upstream.h Outdated
// Network::FilterChainFactory
bool createFilterChain(Network::Connection& connection) override;

uint32_t port() const { return socket_->localAddress()->ip()->port(); }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: can we move this above 161 (makes it clear which functions are part of interface overrides). I'm not totally crazy that we have a port() function here either since FakeUpstream also does UDS. Can we just return localAddress maybe and then have the caller deal with the right thing to do depending on case?

Comment thread test/integration/integration.cc Outdated
if (it != port_map().end()) {
return it->second;
}
return 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should we crash/fail/print here?

}

ServerContextPtr SslIntegrationTest::createUpstreamSslContext() {
static Stats::TestIsolatedStoreImpl upstream_stats_store;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why was this change made? I think this is fragile since I think we have tests that look at stats which might then not reset.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The problem is that if you share a stats store between the Envoy server instance and upstream instance, you get into a dependency cycle. Previously the call to createUpstreamSslContext happened after the test_server_ was initialized. Now we need the test server to be created after the upstream, to allow the upstream to find its bound port and substitute the port into the JSON config prior to initializing the test server.

The test code doesn't check the stats for the upstream instances, only for the test server AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

OK sounds good, as long as nothing is being checked right now should be fine.

Comment thread include/envoy/server/admin.h Outdated
* Obtain socket the admin endpoint is bound to.
* @return Network::ListenSocket& socket reference.
*/
virtual Network::ListenSocket& socket() PURE;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we return a const Network::ListenSocket& here since callers just need to get local address?

Comment thread test/server/server_test.cc Outdated
server_(options_, hooks_, restart_, stats_store_, fakelock_, component_factory_,
local_info_) {}
ServerInstanceImplTest() {
options_.reset(new testing::NiceMock<MockOptions>(TestEnvironment::temporaryFileSubstitutePorts(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why did this need to get changed to pointers here? It seems like we could have just passed result of temporaryFileSubstitutePorts to constructor?

Copy link
Copy Markdown
Member Author

@htuch htuch Mar 30, 2017

Choose a reason for hiding this comment

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

Yeah, no need to change to pointers, I had at first thought the port map construction would be more involved, but it's not.

Comment thread test/run_envoy_tests.sh

# TODO(htuch): Clean this up when Bazelifying the hot restart test below.
HOT_RESTART_JSON="$TEST_SRCDIR"/test/config/integration/hot_restart.json
cat "$TEST_TMPDIR"/test/config/integration/server.json |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This used to test socket passing, but I don't think it actually does anymore since each listener now binds to a random port? Is there any way to restore the old behavior that is sane? At least can we put in TODO to restore the old test behavior?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

TODO added. One idea is we could add a flag to allow us to write back to the filesystem (or print to stdout) the JSON corresponding to what's actually used when zero port binding - basically the same JSON object we parsed but with addresses replaced based on the discovered ports. This would generalize to be useful in other cross-process integration tests where we can't access the ListenSocket objects directly. Another alternative is to do log scraping and JSON templating outside of Envoy. What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah I kind of like the idea of just spitting the JSON back out, or just generally having some way to have an admin endpoint that maybe spits out the listener list in JSON with the real ports. I think this is complex enough to fix and the risk of regression is low enough that I'm fine deferring this for now. We should open a GH issue though that specifically tracks various tech debt cleanups (or just track specifically in the making build better issue) from the migration just to make sure that we don't lose them in "TODO noise".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added #654. I like the idea of making this an admin endpoint feature, but if we bind the admin http address to 0 as well as we'd like to in tests, we need to find the admin endpoint. Maybe we could just have a flag that provides this address and return the rest from the admin endpoint?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't see how the flag would work unless it somehow talked to the existing process over RPC.

Actually, think the shared memory stuff might also be broken for bazel? How does that work? It definitely won't allow concurrently running the main server.

Let's just discuss in #654.

Http::CodecClient::Type type);
IntegrationTcpClientPtr makeTcpConnection(uint32_t port);

// Test-wide port map.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When you say that bazel runs tests in parallel, I assume you mean in parallel in different processes, right? Otherwise it seems like this static port map is not going to work.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's correct. Each individual _test.cc becomes an independent test target that is run in a separate process, and these may run in parallel. Within a _test.cc, gtest will run all tests sequentially in the same process.

@mattklein123 mattklein123 merged commit fdddfab into envoyproxy:master Mar 30, 2017
@htuch htuch deleted the integration-port-free branch March 31, 2017 16:30
PiotrSikora pushed a commit to jplevyak/envoy that referenced this pull request Oct 9, 2020
Add subset of struct Node protobuf for use by Wasm.
jpsim pushed a commit that referenced this pull request Nov 28, 2022
Signed-off-by: Jose Nino <jnino@lyft.com>
Signed-off-by: JP Simard <jp@jpsim.com>
jpsim pushed a commit that referenced this pull request Nov 29, 2022
Signed-off-by: Jose Nino <jnino@lyft.com>
Signed-off-by: JP Simard <jp@jpsim.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants