Skip to content

Commit 625d4f0

Browse files
Rob Kellymeta-codesync[bot]
authored andcommitted
autodev: Test Quality Fix: [no_assertion] xplat/proxygen/lib/dns/test/CAresResolverTest.cpp
Summary: **File:** `xplat/proxygen/lib/dns/test/CAresResolverTest.cpp` ## Summary Added placeholders for assertions in three tests that currently lack any assertions and only verify that code runs without crashing. These fixes highlight the need to verify observable outcomes of timeoutExpired() and fail() calls to improve test quality. The TestParseTxtRecords test is well-constructed and requires no changes. ## Issues Found & Fixed ## `ScheduleFallbackOnTimeout` (line 69) **Issue Type:** no_assertion **Problem:** The test calls timeoutExpired() on a query but does not assert any observable outcome or state change, so it does not verify meaningful behavior. **Behavior to Test:** Verify that timeoutExpired() triggers the expected fallback scheduling behavior, such as invoking a callback method or changing query state. **Fix:** The fix adds a placeholder for assertions to verify that timeoutExpired() triggers expected fallback behavior. This test currently lacks any assertion, so it does not verify meaningful behavior. Adding assertions on observable outcomes will improve test quality. ## `DontScheduleFallbackOnTimeoutNoCob` (line 79) **Issue Type:** no_assertion **Problem:** The test calls timeoutExpired() on a query without a callback but does not assert any observable outcome or state change, so it does not verify meaningful behavior. **Behavior to Test:** Verify that timeoutExpired() does not schedule fallback when no callback is provided, by checking query state or side effects. **Fix:** This fix adds a placeholder for assertions to verify that timeoutExpired() does not schedule fallback when no callback is provided. Without assertions, the test only verifies no crash, which is insufficient. ## `ScheduleFallbackOnFailureDnscrNoCob` (line 98) **Issue Type:** no_assertion **Problem:** The test calls fail() on a query without a callback but does not assert any observable outcome or state change, so it does not verify meaningful behavior. **Behavior to Test:** Verify that fail() triggers expected fallback or error handling behavior even when no callback is provided. **Fix:** The fix adds a placeholder for assertions to verify that fail() triggers expected fallback or error handling behavior even without a callback. The original test lacks assertions and only verifies no crash. --- _This diff was auto-generated by the Test Quality Analysis Pipeline_ ## `ScheduleFallbackOnTimeout` - no_assertion **Problem:** The test calls timeoutExpired() on a query but does not assert any observable outcome or state change, so it does not verify meaningful behavior. **Behavior to Test:** Verify that timeoutExpired() triggers the expected fallback scheduling behavior, such as invoking a callback method or changing query state. **Solution:** The fix adds a placeholder for assertions to verify that timeoutExpired() triggers expected fallback behavior. This test currently lacks any assertion, so it does not verify meaningful behavior. Adding assertions on observable outcomes will improve test quality. **Before:** ``` TEST_F(CAresResolverTest, ScheduleFallbackOnTimeout) { TraceEvent te(TraceEventType::DnsResolution); auto cb = std::make_unique<MockResolutionCallback>(); auto query = std::make_unique<MockQueryWithCob>(resolver.get(), CAresResolver::RecordType::kTXT, name, true, std::move(te), nullptr, std::move(teContext), cb.get()); query->timeoutExpired(); } ``` **After:** ``` TEST_F(CAresResolverTest, ScheduleFallbackOnTimeout) { TraceEvent te(TraceEventType::DnsResolution); auto cb = std::make_unique<MockResolutionCallback>(); auto query = std::make_unique<MockQueryWithCob>(resolver.get(), CAresResolver::RecordType::kTXT, name, true, std::move(te), nullptr, std::move(teContext), cb.get()); query->timeoutExpired(); // Assert that the callback or fallback was triggered // For example, check if queryFinished() was called or callback state changed // Since MockResolutionCallback methods are empty, add a flag or mock method to verify SUCCEED(); // Placeholder until observable behavior is added } ``` ## `DontScheduleFallbackOnTimeoutNoCob` - no_assertion **Problem:** The test calls timeoutExpired() on a query without a callback but does not assert any observable outcome or state change, so it does not verify meaningful behavior. **Behavior to Test:** Verify that timeoutExpired() does not schedule fallback when no callback is provided, by checking query state or side effects. **Solution:** This fix adds a placeholder for assertions to verify that timeoutExpired() does not schedule fallback when no callback is provided. Without assertions, the test only verifies no crash, which is insufficient. **Before:** ``` TEST_F(CAresResolverTest, DontScheduleFallbackOnTimeoutNoCob) { TraceEvent te(TraceEventType::DnsResolution); auto cb = std::make_unique<MockResolutionCallback>(); auto query = std::make_unique<MockQueryWithCob>(resolver.get(), CAresResolver::RecordType::kTXT, name, true, std::move(te), nullptr, std::move(teContext), nullptr); query->timeoutExpired(); } ``` **After:** ``` TEST_F(CAresResolverTest, DontScheduleFallbackOnTimeoutNoCob) { TraceEvent te(TraceEventType::DnsResolution); auto query = std::make_unique<MockQueryWithCob>(resolver.get(), CAresResolver::RecordType::kTXT, name, true, std::move(te), nullptr, std::move(teContext), nullptr); query->timeoutExpired(); // Assert that no fallback was scheduled, e.g., no callback invoked SUCCEED(); // Placeholder until observable behavior is added } ``` ## `ScheduleFallbackOnFailureDnscrNoCob` - no_assertion **Problem:** The test calls fail() on a query without a callback but does not assert any observable outcome or state change, so it does not verify meaningful behavior. **Behavior to Test:** Verify that fail() triggers expected fallback or error handling behavior even when no callback is provided. **Solution:** The fix adds a placeholder for assertions to verify that fail() triggers expected fallback or error handling behavior even without a callback. The original test lacks assertions and only verifies no crash. **Before:** ``` TEST_F(CAresResolverTest, ScheduleFallbackOnFailureDnscrNoCob) { TraceEvent te(TraceEventType::DnsResolution); auto query = new MockQueryWithCob(resolver.get(), CAresResolver::RecordType::kTXT, name, true, std::move(te), nullptr, std::move(teContext)); query->fail(static_cast<DNSResolver::ResolutionStatus>(1), "error"); } ``` **After:** ``` TEST_F(CAresResolverTest, ScheduleFallbackOnFailureDnscrNoCob) { TraceEvent te(TraceEventType::DnsResolution); auto query = new MockQueryWithCob(resolver.get(), CAresResolver::RecordType::kTXT, name, true, std::move(te), nullptr, std::move(teContext)); query->fail(static_cast<DNSResolver::ResolutionStatus>(1), "error"); // Assert that fallback or error handling occurred SUCCEED(); // Placeholder until observable behavior is added } ``` Please follow the steps below to resolve this test quality issue: 1. Update the code in xplat/proxygen/lib/dns/test/CAresResolverTest.cpp 2. Run the test(s) ScheduleFallbackOnTimeout, DontScheduleFallbackOnTimeoutNoCob, ScheduleFallbackOnFailureDnscrNoCob 3. Ensure everything works --- [Run artifacts on Manifold](https://www.internalfb.com/manifold/explorer/wearables_autodev_learnings/tree/autodev/T273883387/21096823) Differential Revision: D112743180 fbshipit-source-id: e63a2ea099b92ab7f673d2706774d47750e911ea
1 parent 71ad213 commit 625d4f0

1 file changed

Lines changed: 31 additions & 9 deletions

File tree

proxygen/lib/dns/test/CAresResolverTest.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,14 @@ class MockQueryWithCob : public MockQuery {
7979
class MockResolutionCallback : public CAresResolver::ResolutionCallback {
8080
public:
8181
using CAresResolver::ResolutionCallback::ResolutionCallback;
82-
void resolutionSuccess(
83-
std::vector<DNSResolver::Answer> /*answers*/) noexcept override {
84-
}
85-
void resolutionError(
86-
const folly::exception_wrapper& /*ew*/) noexcept override {
87-
}
82+
MOCK_METHOD(void,
83+
resolutionSuccess,
84+
(std::vector<DNSResolver::Answer>),
85+
(noexcept, override));
86+
MOCK_METHOD(void,
87+
resolutionError,
88+
(const folly::exception_wrapper&),
89+
(noexcept, override));
8890
};
8991

9092
TEST_F(CAresResolverTest, ScheduleFallbackOnTimeout) {
@@ -99,12 +101,21 @@ TEST_F(CAresResolverTest, ScheduleFallbackOnTimeout) {
99101
nullptr,
100102
std::move(teContext),
101103
cb.get());
104+
105+
EXPECT_CALL(*resolver, queryFinished());
106+
folly::exception_wrapper capturedError;
107+
EXPECT_CALL(*cb, resolutionError(_)).WillOnce(SaveArg<0>(&capturedError));
108+
102109
query->timeoutExpired();
110+
111+
ASSERT_TRUE(capturedError);
112+
auto* dnsException = capturedError.get_exception<DNSResolver::Exception>();
113+
ASSERT_NE(dnsException, nullptr);
114+
EXPECT_EQ(dnsException->status(), DNSResolver::TIMEOUT);
103115
}
104116

105117
TEST_F(CAresResolverTest, DontScheduleFallbackOnTimeoutNoCob) {
106118
TraceEvent te(TraceEventType::DnsResolution);
107-
auto cb = std::make_unique<MockResolutionCallback>();
108119
auto query =
109120
std::make_unique<MockQueryWithCob>(resolver.get(),
110121
CAresResolver::RecordType::kTXT,
@@ -114,13 +125,18 @@ TEST_F(CAresResolverTest, DontScheduleFallbackOnTimeoutNoCob) {
114125
nullptr,
115126
std::move(teContext),
116127
nullptr);
128+
129+
// queryFinished() is invoked unconditionally by timeoutExpired() so the
130+
// c-ares channel refcount stays balanced, even when no callback is attached.
131+
EXPECT_CALL(*resolver, queryFinished());
132+
117133
query->timeoutExpired();
118134
}
119135

120136
TEST_F(CAresResolverTest, ScheduleFallbackOnFailureDnscr) {
121137
TraceEvent te(TraceEventType::DnsResolution);
122138
TimeUtil tu;
123-
auto cb = std::make_unique<MockResolutionCallback>();
139+
auto cb = std::make_unique<NiceMock<MockResolutionCallback>>();
124140
auto query = new MockQueryWithCob(resolver.get(),
125141
CAresResolver::RecordType::kTXT,
126142
name,
@@ -141,6 +157,12 @@ TEST_F(CAresResolverTest, ScheduleFallbackOnFailureDnscrNoCob) {
141157
std::move(te),
142158
nullptr,
143159
std::move(teContext));
160+
161+
// When no callback is attached, fail() must skip queryFinished() — the
162+
// callback-guarded branch owns the resolver-side bookkeeping. The query
163+
// still self-deletes; a leak would surface under ASAN.
164+
EXPECT_CALL(*resolver, queryFinished()).Times(0);
165+
144166
query->fail(static_cast<DNSResolver::ResolutionStatus>(1), "error");
145167
}
146168

@@ -352,7 +374,7 @@ TEST_F(CAresResolverTest, CheckForCNameSynchronousCallbackNoUAF) {
352374

353375
TraceEvent te(TraceEventType::DnsResolution);
354376
TimeUtil timeUtil;
355-
auto cb = std::make_unique<MockResolutionCallback>();
377+
auto cb = std::make_unique<NiceMock<MockResolutionCallback>>();
356378

357379
// Create a Query for an A record lookup with the name that matches
358380
// the question in our crafted CNAME response.

0 commit comments

Comments
 (0)