Skip to content

Commit 22b8d8a

Browse files
committed
Add unit test for GetActiveUsers
Verify that the external users is correctly reported Change-Id: I1026ec13b0d4d043e16b954ac385234aeeed2413 Reviewed-on: http://review.couchbase.org/100259 Tested-by: Build Bot <[email protected]> Reviewed-by: Daniel Owen <[email protected]>
1 parent d2bbe39 commit 22b8d8a

File tree

3 files changed

+85
-25
lines changed

3 files changed

+85
-25
lines changed

protocol/connection/client_mcbp_commands.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ using BinprotIsaslRefreshCommand =
642642

643643
using BinprotIsaslRefreshResponse = BinprotResponse;
644644

645+
using BinprotGetActiveUsersCommand = BinprotCommandT<
646+
BinprotGenericCommand,
647+
uint8_t(cb::mcbp::ClientOpcode::GetActiveExternalUsers)>;
648+
645649
class BinprotMutationCommand : public BinprotCommandT<BinprotMutationCommand> {
646650
public:
647651
BinprotMutationCommand& setMutationType(MutationType);

tests/testapp/testapp_external_auth.cc

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,54 @@ class ExternalAuthTest : public TestappClientTest {
111111
provider->sendFrame(frame);
112112
}
113113

114+
std::unique_ptr<MemcachedConnection> loginOsbourne() {
115+
auto ret = getConnection().clone();
116+
117+
BinprotSaslAuthCommand saslAuthCommand;
118+
saslAuthCommand.setChallenge({"\0osbourne\0password", 18});
119+
saslAuthCommand.setMechanism("PLAIN");
120+
ret->sendCommand(saslAuthCommand);
121+
122+
stepAuthProvider();
123+
124+
// Now read out the response from the client
125+
BinprotResponse response;
126+
ret->recvResponse(response);
127+
if (!response.isSuccess()) {
128+
return {};
129+
}
130+
131+
return ret;
132+
}
133+
134+
/**
135+
* We've got multiple worker threads and if we try to disconnect a user
136+
* connected to one thread that thread may not be sheduled to run
137+
* immediately, so we may end up serving requests for another worker
138+
* thread.
139+
*
140+
* To work around this (and try to avoid spurious test failures) we'll
141+
* try to run the command a few times before we give up.
142+
*
143+
* @param content what we want the content of the users list to be
144+
*/
145+
void waitForUserList(const std::string& content) {
146+
const auto start = std::chrono::steady_clock::now();
147+
do {
148+
auto& conn = getAdminConnection();
149+
auto resp = conn.execute(BinprotGetActiveUsersCommand{});
150+
if (resp.isSuccess() && content == resp.getDataString()) {
151+
return;
152+
}
153+
} while ((std::chrono::steady_clock::now() - start) <
154+
std::chrono::seconds(2));
155+
156+
auto& conn = getAdminConnection();
157+
auto resp = conn.execute(BinprotGetActiveUsersCommand{});
158+
FAIL() << "Timed out trying to get expected content [" << content
159+
<< "] Current content is: " << resp.getDataString();
160+
}
161+
114162
std::unique_ptr<MemcachedConnection> provider;
115163
};
116164

@@ -255,3 +303,36 @@ TEST_P(ExternalAuthTest, TestReloadRbacDbDontNukeExternalUsers) {
255303
EXPECT_EQ("external", json["osbourne"]["domain"])
256304
<< response.getDataString();
257305
}
306+
307+
TEST_P(ExternalAuthTest, GetActiveUsers) {
308+
// Log in a few "local" users
309+
auto& conn = getConnection();
310+
auto clone1 = conn.clone();
311+
auto clone2 = conn.clone();
312+
auto clone3 = conn.clone();
313+
auto clone4 = conn.clone();
314+
315+
clone1->authenticate("smith", "smithpassword", "PLAIN");
316+
clone2->authenticate("smith", "smithpassword", "PLAIN");
317+
clone3->authenticate("jones", "jonespassword", "PLAIN");
318+
clone4->authenticate("@admin", "password", "PLAIN");
319+
320+
// Log in 2 external ones
321+
auto osbourne1 = loginOsbourne();
322+
EXPECT_TRUE(osbourne1);
323+
324+
auto osbourne2 = loginOsbourne();
325+
EXPECT_TRUE(osbourne2);
326+
327+
waitForUserList(R"(["osbourne"])");
328+
329+
// Log out one of the external users
330+
osbourne1.reset();
331+
332+
waitForUserList(R"(["osbourne"])");
333+
334+
// Log out the second external user
335+
osbourne2.reset();
336+
337+
waitForUserList(R"([])");
338+
}

tests/testapp/testapp_misc.cc

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,31 +62,6 @@ TEST_P(MiscTest, GetFailoverLog) {
6262
EXPECT_EQ(header.cas, 0);
6363
}
6464

65-
TEST_P(MiscTest, GetActiveUsers) {
66-
auto& conn = getConnection();
67-
auto clone1 = conn.clone();
68-
auto clone2 = conn.clone();
69-
auto clone3 = conn.clone();
70-
auto clone4 = conn.clone();
71-
72-
clone1->authenticate("smith", "smithpassword", "PLAIN");
73-
clone2->authenticate("smith", "smithpassword", "PLAIN");
74-
clone3->authenticate("jones", "jonespassword", "PLAIN");
75-
clone4->authenticate("@admin", "password", "PLAIN");
76-
77-
conn = getAdminConnection();
78-
BinprotCommand cmd;
79-
cmd.setOp(uint8_t(cb::mcbp::ClientOpcode::GetActiveExternalUsers));
80-
BinprotResponse resp;
81-
82-
conn.executeCommand(cmd, resp);
83-
EXPECT_TRUE(resp.isSuccess());
84-
// We don't have any external users to test with for now.. will add
85-
// them after we've added support for external auth through our mock
86-
// server
87-
EXPECT_EQ("[]", resp.getDataString());
88-
}
89-
9065
/**
9166
* Send the UpdateUserPermissions with a valid username and paylaod.
9267
*

0 commit comments

Comments
 (0)