Skip to content

test: Use test-listener rather than TestBase to assure quiescence after each method.#5833

Merged
jmarantz merged 23 commits intoenvoyproxy:masterfrom
jmarantz:all-tests-use-test-base
Feb 13, 2019
Merged

test: Use test-listener rather than TestBase to assure quiescence after each method.#5833
jmarantz merged 23 commits intoenvoyproxy:masterfrom
jmarantz:all-tests-use-test-base

Conversation

@jmarantz
Copy link
Contributor

@jmarantz jmarantz commented Feb 4, 2019

Description: Follow-up to #5811 -- use ::testing::TestEventListeners to add the singleton-quiescence hook. This is significantly cleaner than what I previously checked in which is to add a new TestBase class to every test-class, and covers TEST(fixture, name) tests too.

After this the TestBase class can be removed as it's now just an alias for ::testing:::Test.

Risk Level: low
Testing: //test/...
Docs Changes: n/a
Release Notes: n/a

Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
@alyssawilk
Copy link
Contributor

Can you open a tracking issue and document why we need this and why it's a good idea? I think I could use a bit more context

Unit tests are supposed to be standalone - by default I'm not a big fan of anything changing global state on them

@htuch
Copy link
Member

htuch commented Feb 4, 2019

Please merge master to pick up #5827.

@alyssawilk
Copy link
Contributor

Also have we looked into alternates? AFIK internal gtest has built in flagsavers - not sure if there's hooks for one off registration like you want or if they hard-coded in-house

Also on alternates, I'm a heavy user of gtest_filter/gunit_filter and losing TestSuite.Test is sad. would it be a pain to have our own macro function which called your function before test code rather than losing the standard gtest naming?

@jmarantz
Copy link
Contributor Author

jmarantz commented Feb 4, 2019

RE test-naming: let's call that a blocker for this PR; I was wondering how critical that was.

I have an alternate approach to interpose a new test-class. This transformation is more complicated (but tractable) to apply at scale. However, frequently in the codebase, we test class Foo with TEST(Foo, testname), and so we can't just add class Foo : public TestBase {}; and then add add the _F to the macro.

I'm also fine with defining a macro to replace TEST( but first we need to solve what transformation to make when the expected class-name is already a class. Maybe we can disambiguate without changing the testing UI by putting the test-class in a namespace? I'm open to suggestions.

In this implementation, we need to put the test-body as a third macro arg, so we
can wrap it in a scoped object. This is more syntactically invasive, but avoids
altering any names of tests or fixtures.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
@jmarantz
Copy link
Contributor Author

jmarantz commented Feb 5, 2019

@alyssawilk PTAL at the latest commits, in particular the new macro TEST_E (suggestions welcome on name) and the one file I reworked in that style, test/common/runtime/uuid_util_test.cc

This avoids changing any test or fixture names, but requires a broad syntactic change by putting the entire test-body in a macro arg.

Suggestions also welcome on how better to do this.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
@mattklein123
Copy link
Member

Suggestions also welcome on how better to do this.

Worth maybe talking to the googletest folks? I wonder if an upstream change might be the better way to do this? Some hook where we can use a custom base class for a TEST?

@alyssawilk
Copy link
Contributor

+1 to what Matt said. We've managed to make changes to gmock for Envoy-specific asks, and I think this is a generically useful feature (which we either do use inside with a one-off or could). If we're not in a desperate hurry and gtest is amenable I think we could do this cleanly in O(weeks) and it seems better than updating every test name and/or custom closure semantics.

@alyssawilk
Copy link
Contributor

Also on the other PR do we have checks in the fix_format script to not use the normal test-base? If not I strongly encourage adding them both for the last change and for whatever we do here.

@jmarantz
Copy link
Contributor Author

jmarantz commented Feb 5, 2019

RE "check_format" checks for avoiding "TEST(" -- yes, in this PR. For deriving test-classes from testing::Test? Yes, already in master.

RE "change gtest" -- that sounds reasonable. Just one other quick taste-test on something we could do with the current technology. WDYT of this transform:

old:

TEST(Foo, t1) { ... }
TEST(Foo, t2) { ... }

new:

class FooTest : public TestBase {};
TEST_F(FooTest, t1) { ... }
TEST_F(FooTest, t2) { ... }

This would work most of the time, and be achievable with automation. FooTest might collide here or there and would need to be resolved manually in the context of the PR. Would that be a decent outcome?

If not I'll contact the gtest team.

@alyssawilk
Copy link
Contributor

How would you automate? Or you mean you could script the one time change?

FWIW I think you can also get away with aliasing FooTest to TestBase rather than declaring a new class and still have gtest filter work. I think I'd take that over the current macro though, so good call.

@jmarantz
Copy link
Contributor Author

jmarantz commented Feb 5, 2019

by aliasing do you mean using FooTest = TestBase;? I can try, but I'd be worried about two different tests with the same name, which are currently disambiguated by the test-suite.

Automation would be via one-time script.

@alyssawilk
Copy link
Contributor

Yeah, I had concerns about that for the protocol integration test and turns out it works fine. I don't think creating a test class is bad though, so if you're more comfortable with that it's fine too.

I still think global test hooks would be better, but if it looks like it'll take more than a day or two I can buy the workaround described.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
@alyssawilk
Copy link
Contributor

Also since I'm a bit behind on reviews and annotations are nice :-)
/wait

Signed-off-by: Joshua Marantz <jmarantz@google.com>
@jmarantz jmarantz changed the title WiP test: Change all TEST(xxx, yyy) to TEST_F(TestBase, xxx_yyy) test: Change all TEST(xxx, yyy) to TEST_F(TestBase, xxx_yyy) Feb 7, 2019
…t run without ASAN need it too.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
@jmarantz
Copy link
Contributor Author

jmarantz commented Feb 8, 2019

Apologies for the size of the PR. You can see the pattern from the first visible file in it. This was all done semi-automatically, requiring manual-fixes where the test-fixture name matched an existing class name. My fix was to append 'Test' to the test fixture name, and I probably had to do this a few dozen times.

Also in this PR is a check_format addition to flag "TEST(" going forward. This check_format.py change is the last file in the PR so you can find the diff by going to the Files view and scrolling to the bottom.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
@jmarantz
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

🔨 rebuilding ci/circleci: asan (failed build)
🔨 rebuilding ci/circleci: mac (failed build)

🐱

Caused by: a #5833 (comment) was created by @jmarantz.

see: more, trace.

@jmarantz
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

🔨 rebuilding ci/circleci: mac (failed build)

🐱

Caused by: a #5833 (comment) was created by @jmarantz.

see: more, trace.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
@jmarantz
Copy link
Contributor Author

@alyssawilk any further comments or discussion? This PR has the property that it probably won't be prone to automatically detected merge conflicts, but the longer it sits, the more new unchecked 'TEST(' macros will be added to the codebase. So if you let me know when you start reviewing I will do another quick merge and fix newly added 'TEST(' instances.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
@alyssawilk
Copy link
Contributor

Sorry, I started reviewing, paused to do some digging, and got distracted.

So digging
https://github.com/google/googletest/blob/master/googletest/docs/advanced.md
Can we add an EnvoyTestListener which calls your custom code OnTestEnd and skip all of this work?

Signed-off-by: Joshua Marantz <jmarantz@google.com>
…t listener.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
@jmarantz jmarantz changed the title test: Change all TEST(xxx, yyy) to TEST_F(TestBase, xxx_yyy) test: Use test-listener rather than TestBase to assure quiescence after each method. Feb 13, 2019
@jmarantz
Copy link
Contributor Author

@alyssawilk yes done. Thank you very much for finding this...I had looked in some gtest header files for something like this and managed to miss it.

Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

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

Awesome - glad this worked out.

Both comments optional so I'll give you my LGTM now but I'm happy to do another pass if you fix either or both.

public:
~TestBaseWithParam() { TestBase::checkSingletonQuiescensce(); }
};
// TODO(jmarantz): Before Alyssa found this TestListener hook for me, we had
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional: think it's worth removing the check_format checks in this PR, just so folks can create new testing::Test classes while we get around to clean up?

public:
static void checkSingletonQuiescensce();
~TestBase() override;
class TestListener : public ::testing::EmptyTestEventListener {
Copy link
Contributor

Choose a reason for hiding this comment

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

bonus points if you can think of a more descriptive name - I currently can't :-P

@jmarantz
Copy link
Contributor Author

Thanks -- I think TestListener is the best I can do at the moment and I'll follow up this morning with the rollback of the existing check_format and other tests, so I'll go ahead and merge and get rid of that stuff :)

@jmarantz jmarantz merged commit b9ec5b6 into envoyproxy:master Feb 13, 2019
@jmarantz jmarantz deleted the all-tests-use-test-base branch February 13, 2019 14:22
fredlas pushed a commit to fredlas/envoy that referenced this pull request Mar 5, 2019
…er each method. (envoyproxy#5833)

* Back out the TEST( -> TEST_F( changes in favor of establishing a gtest listener.

Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Fred Douglas <fredlas@google.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.

4 participants