Skip to content

Commit 92ed049

Browse files
BenHuddlestondaverigby
authored andcommitted
MB-41719: Make test_producer_stream_end_on_client_close_stream ST
Change-Id: Ia997c31b34a6a7d3090eb71e94bee0e3c26a9f8d Reviewed-on: http://review.couchbase.org/c/kv_engine/+/137423 Tested-by: Build Bot <[email protected]> Reviewed-by: Dave Rigby <[email protected]>
1 parent f133e71 commit 92ed049

File tree

4 files changed

+106
-66
lines changed

4 files changed

+106
-66
lines changed

engines/ep/tests/mock/mock_dcp_conn_map.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,9 @@ bool MockDcpConnMap::removeConn(const void* cookie) {
4343
bool MockDcpConnMap::doesVbConnExist(Vbid vbid, const std::string& name) {
4444
return connStore->doesVbConnExist(vbid, name);
4545
}
46+
47+
bool MockDcpConnMap::doesConnHandlerExist(const std::string& name) {
48+
return connStore->getCookieToConnectionMapHandle()
49+
->findConnHandlerByName(name)
50+
.get();
51+
}

engines/ep/tests/mock/mock_dcp_conn_map.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class MockDcpConnMap : public DcpConnMap {
5353
/// structure
5454
bool doesVbConnExist(Vbid vbid, const std::string& name);
5555

56+
bool doesConnHandlerExist(const std::string& name);
57+
5658
protected:
5759
/**
5860
* @param engine The engine

engines/ep/tests/module_tests/dcp_single_threaded_test.cc

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,47 @@
3131

3232
class STDcpTest : public STParameterizedBucketTest {
3333
protected:
34+
struct StreamRequestResult {
35+
ENGINE_ERROR_CODE status;
36+
uint64_t rollbackSeqno;
37+
};
38+
39+
// callbackCount needs to be static as its used inside of the static
40+
// function fakeDcpAddFailoverLog.
41+
// static int callbackCount;
42+
43+
/*
44+
* Fake callback emulating dcp_add_failover_log
45+
*/
46+
static ENGINE_ERROR_CODE fakeDcpAddFailoverLog(
47+
vbucket_failover_t* entry,
48+
size_t nentries,
49+
gsl::not_null<const void*> cookie) {
50+
// callbackCount++;
51+
return ENGINE_SUCCESS;
52+
}
53+
54+
StreamRequestResult doStreamRequest(DcpProducer& producer,
55+
uint64_t startSeqno = 0,
56+
uint64_t endSeqno = ~0,
57+
uint64_t snapStart = 0,
58+
uint64_t snapEnd = ~0,
59+
uint64_t vbUUID = 0) {
60+
StreamRequestResult result;
61+
result.status = producer.streamRequest(/*flags*/ 0,
62+
/*opaque*/ 0,
63+
vbid,
64+
startSeqno,
65+
endSeqno,
66+
vbUUID,
67+
snapStart,
68+
snapEnd,
69+
&result.rollbackSeqno,
70+
fakeDcpAddFailoverLog,
71+
{});
72+
return result;
73+
}
74+
3475
/**
3576
* @param producerState Are we simulating a negotiation against a Producer
3677
* that enables IncludeDeletedUserXattrs?
@@ -565,6 +606,63 @@ TEST_P(STDcpTest,
565606
processConsumerMutationsNearThreshold(false);
566607
}
567608

609+
/* Checks that the DCP producer does an async stream close when the DCP client
610+
expects "DCP_STREAM_END" msg. */
611+
TEST_P(STDcpTest, test_producer_stream_end_on_client_close_stream) {
612+
setVBucketStateAndRunPersistTask(vbid, vbucket_state_active);
613+
614+
const void* cookie = create_mock_cookie(engine.get());
615+
auto& mockConnMap = static_cast<MockDcpConnMap&>(engine->getDcpConnMap());
616+
617+
/* Create a new Dcp producer */
618+
auto producer = std::make_shared<MockDcpProducer>(*engine,
619+
cookie,
620+
"test_producer",
621+
/*flags*/ 0);
622+
mockConnMap.addConn(cookie, producer);
623+
EXPECT_TRUE(mockConnMap.doesConnHandlerExist("test_producer"));
624+
625+
/* Send a control message to the producer indicating that the DCP client
626+
expects a "DCP_STREAM_END" upon stream close */
627+
const std::string sendStreamEndOnClientStreamCloseCtrlMsg(
628+
"send_stream_end_on_client_close_stream");
629+
const std::string sendStreamEndOnClientStreamCloseCtrlValue("true");
630+
EXPECT_EQ(ENGINE_SUCCESS,
631+
producer->control(0,
632+
sendStreamEndOnClientStreamCloseCtrlMsg,
633+
sendStreamEndOnClientStreamCloseCtrlValue));
634+
635+
/* Open stream */
636+
EXPECT_EQ(ENGINE_SUCCESS, doStreamRequest(*producer).status);
637+
EXPECT_TRUE(mockConnMap.doesVbConnExist(vbid, "test_producer"));
638+
639+
/* Close stream */
640+
EXPECT_EQ(ENGINE_SUCCESS, producer->closeStream(0, vbid));
641+
642+
/* Expect a stream end message */
643+
MockDcpMessageProducers producers(engine.get());
644+
EXPECT_EQ(ENGINE_SUCCESS, producer->step(&producers));
645+
EXPECT_EQ(cb::mcbp::ClientOpcode::DcpStreamEnd, producers.last_op);
646+
EXPECT_EQ(cb::mcbp::DcpStreamEndStatus::Closed, producers.last_end_status);
647+
648+
/* Re-open stream for the same vbucket on the conn */
649+
EXPECT_EQ(ENGINE_SUCCESS, doStreamRequest(*producer).status);
650+
651+
/* Check that the new stream is opened properly */
652+
auto stream = producer->findStream(vbid);
653+
auto* as = static_cast<ActiveStream*>(stream.get());
654+
EXPECT_TRUE(as->isInMemory());
655+
656+
// MB-27769: Prior to the fix, this would fail here because we would skip
657+
// adding the connhandler into the connmap vbConns vector, causing the
658+
// stream to never get notified.
659+
EXPECT_TRUE(mockConnMap.doesVbConnExist(vbid, "test_producer"));
660+
661+
mockConnMap.disconnect(cookie);
662+
EXPECT_FALSE(mockConnMap.doesVbConnExist(vbid, "test_producer"));
663+
mockConnMap.manageConnections();
664+
}
665+
568666
INSTANTIATE_TEST_SUITE_P(PersistentAndEphemeral,
569667
STDcpTest,
570668
STParameterizedBucketTest::allConfigValues());

engines/ep/tests/module_tests/dcp_test.cc

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,72 +1161,6 @@ TEST_P(ConnectionTest, test_mb17042_duplicate_cookie_producer_connections) {
11611161
<< "Dead connections still remain";
11621162
}
11631163

1164-
/* Checks that the DCP producer does an async stream close when the DCP client
1165-
expects "DCP_STREAM_END" msg. */
1166-
TEST_P(ConnectionTest, test_producer_stream_end_on_client_close_stream) {
1167-
#ifdef UNDEFINED_SANITIZER
1168-
// See below MB-28739 comment for why this is skipped.
1169-
std::cerr << "MB-28739[UBsan] skipping test\n";
1170-
return;
1171-
#endif
1172-
const void* cookie = create_mock_cookie(engine);
1173-
/* Create a new Dcp producer */
1174-
producer = std::make_shared<MockDcpProducer>(*engine,
1175-
cookie,
1176-
"test_producer",
1177-
/*flags*/ 0);
1178-
1179-
/* Send a control message to the producer indicating that the DCP client
1180-
expects a "DCP_STREAM_END" upon stream close */
1181-
const std::string sendStreamEndOnClientStreamCloseCtrlMsg(
1182-
"send_stream_end_on_client_close_stream");
1183-
const std::string sendStreamEndOnClientStreamCloseCtrlValue("true");
1184-
EXPECT_EQ(ENGINE_SUCCESS,
1185-
producer->control(0,
1186-
sendStreamEndOnClientStreamCloseCtrlMsg,
1187-
sendStreamEndOnClientStreamCloseCtrlValue));
1188-
1189-
/* Open stream */
1190-
EXPECT_EQ(ENGINE_SUCCESS, doStreamRequest(*producer).status);
1191-
1192-
// MB-28739[UBSan]: The following cast is undefined behaviour - the DCP
1193-
// connection map object is of type DcpConnMap; so it's undefined to cast
1194-
// to MockDcpConnMap.
1195-
// However, in this instance MockDcpConnMap has identical member variables
1196-
// to DcpConnMap - the mock just exposes normally private data - and so
1197-
// this /seems/ ok.
1198-
// As such allow it in general, but skip this test under UBSan.
1199-
auto& mockConnMap =
1200-
static_cast<MockDcpConnMap&>(engine->getDcpConnMap());
1201-
mockConnMap.addConn(cookie, producer);
1202-
EXPECT_TRUE(mockConnMap.doesVbConnExist(vbid, "test_producer"));
1203-
1204-
/* Close stream */
1205-
EXPECT_EQ(ENGINE_SUCCESS, producer->closeStream(0, vbid));
1206-
1207-
/* Expect a stream end message */
1208-
MockDcpMessageProducers producers(handle);
1209-
EXPECT_EQ(ENGINE_SUCCESS, producer->step(&producers));
1210-
EXPECT_EQ(cb::mcbp::ClientOpcode::DcpStreamEnd, producers.last_op);
1211-
EXPECT_EQ(cb::mcbp::DcpStreamEndStatus::Closed, producers.last_end_status);
1212-
1213-
/* Re-open stream for the same vbucket on the conn */
1214-
EXPECT_EQ(ENGINE_SUCCESS, doStreamRequest(*producer).status);
1215-
1216-
/* Check that the new stream is opened properly */
1217-
auto stream = producer->findStream(vbid);
1218-
auto* as = static_cast<ActiveStream*>(stream.get());
1219-
EXPECT_TRUE(as->isInMemory());
1220-
1221-
// MB-27769: Prior to the fix, this would fail here because we would skip
1222-
// adding the connhandler into the connmap vbConns vector, causing the
1223-
// stream to never get notified.
1224-
EXPECT_TRUE(mockConnMap.doesVbConnExist(vbid, "test_producer"));
1225-
1226-
mockConnMap.disconnect(cookie);
1227-
EXPECT_FALSE(mockConnMap.doesVbConnExist(vbid, "test_producer"));
1228-
mockConnMap.manageConnections();
1229-
}
12301164

12311165
/* Checks that the DCP producer does a synchronous stream close when the DCP
12321166
client does not expect "DCP_STREAM_END" msg. */

0 commit comments

Comments
 (0)