1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <string>
6
7 #include "mojo/core/test/mojo_test_base.h"
8 #include "mojo/public/c/system/quota.h"
9
10 namespace mojo {
11 namespace core {
12 namespace {
13
14 using QuotaTest = test::MojoTestBase;
15
QuotaExceededEventHandler(const MojoTrapEvent * event)16 void QuotaExceededEventHandler(const MojoTrapEvent* event) {
17 // Always treat trigger context as the address of a bool to set to |true|.
18 if (event->result == MOJO_RESULT_OK)
19 *reinterpret_cast<bool*>(event->trigger_context) = true;
20 }
21
TEST_F(QuotaTest,InvalidArguments)22 TEST_F(QuotaTest, InvalidArguments) {
23 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
24 MojoSetQuota(MOJO_HANDLE_INVALID,
25 MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, 2, nullptr));
26
27 const MojoQuotaType kInvalidQuotaType = 0xfffffffful;
28 MojoHandle message_pipe0, message_pipe1;
29 CreateMessagePipe(&message_pipe0, &message_pipe1);
30 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
31 MojoSetQuota(message_pipe0, kInvalidQuotaType, 0, nullptr));
32
33 const MojoSetQuotaOptions kInvalidSetQuotaOptions = {0};
34 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
35 MojoSetQuota(message_pipe0, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, 0,
36 &kInvalidSetQuotaOptions));
37
38 uint64_t limit = 0;
39 uint64_t usage = 0;
40 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
41 MojoQueryQuota(message_pipe0, kInvalidQuotaType, nullptr, &limit,
42 &usage));
43
44 const MojoQueryQuotaOptions kInvalidQueryQuotaOptions = {0};
45 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
46 MojoQueryQuota(message_pipe0, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH,
47 &kInvalidQueryQuotaOptions, &limit, &usage));
48
49 MojoClose(message_pipe0);
50 MojoClose(message_pipe1);
51
52 MojoHandle producer, consumer;
53 CreateDataPipe(&producer, &consumer, 1);
54 EXPECT_EQ(
55 MOJO_RESULT_INVALID_ARGUMENT,
56 MojoSetQuota(producer, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, 0, nullptr));
57 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
58 MojoSetQuota(producer, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE, 0,
59 nullptr));
60 EXPECT_EQ(
61 MOJO_RESULT_INVALID_ARGUMENT,
62 MojoSetQuota(consumer, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, 0, nullptr));
63 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
64 MojoSetQuota(consumer, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE, 0,
65 nullptr));
66 MojoClose(producer);
67 MojoClose(consumer);
68 }
69
TEST_F(QuotaTest,BasicReceiveQueueLength)70 TEST_F(QuotaTest, BasicReceiveQueueLength) {
71 MojoHandle a, b;
72 CreateMessagePipe(&a, &b);
73
74 uint64_t limit = 0;
75 uint64_t usage = 0;
76 EXPECT_EQ(MOJO_RESULT_OK,
77 MojoQueryQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, nullptr,
78 &limit, &usage));
79 EXPECT_EQ(MOJO_QUOTA_LIMIT_NONE, limit);
80 EXPECT_EQ(0u, usage);
81
82 const uint64_t kTestLimit = 42;
83 EXPECT_EQ(MOJO_RESULT_OK,
84 MojoSetQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, kTestLimit,
85 nullptr));
86
87 EXPECT_EQ(MOJO_RESULT_OK,
88 MojoQueryQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, nullptr,
89 &limit, &usage));
90 EXPECT_EQ(kTestLimit, limit);
91 EXPECT_EQ(0u, usage);
92
93 const std::string kTestMessage = "doot";
94 WriteMessage(b, kTestMessage);
95 WaitForSignals(a, MOJO_HANDLE_SIGNAL_READABLE);
96
97 EXPECT_EQ(MOJO_RESULT_OK,
98 MojoQueryQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, nullptr,
99 &limit, &usage));
100 EXPECT_EQ(kTestLimit, limit);
101 EXPECT_EQ(1u, usage);
102 }
103
TEST_F(QuotaTest,BasicReceiveQueueMemorySize)104 TEST_F(QuotaTest, BasicReceiveQueueMemorySize) {
105 MojoHandle a, b;
106 CreateMessagePipe(&a, &b);
107
108 uint64_t limit = 0;
109 uint64_t usage = 0;
110 EXPECT_EQ(MOJO_RESULT_OK,
111 MojoQueryQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
112 nullptr, &limit, &usage));
113 EXPECT_EQ(MOJO_QUOTA_LIMIT_NONE, limit);
114 EXPECT_EQ(0u, usage);
115
116 const uint64_t kTestLimit = 42;
117 EXPECT_EQ(MOJO_RESULT_OK,
118 MojoSetQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
119 kTestLimit, nullptr));
120
121 EXPECT_EQ(MOJO_RESULT_OK,
122 MojoQueryQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
123 nullptr, &limit, &usage));
124 EXPECT_EQ(kTestLimit, limit);
125 EXPECT_EQ(0u, usage);
126
127 const std::string kTestMessage = "doot";
128 WriteMessage(b, kTestMessage);
129 WaitForSignals(a, MOJO_HANDLE_SIGNAL_READABLE);
130
131 EXPECT_EQ(MOJO_RESULT_OK,
132 MojoQueryQuota(a, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
133 nullptr, &limit, &usage));
134 EXPECT_EQ(kTestLimit, limit);
135 EXPECT_EQ(usage, kTestMessage.size());
136
137 MojoClose(a);
138 MojoClose(b);
139 }
140
TEST_F(QuotaTest,ReceiveQueueLengthLimitExceeded)141 TEST_F(QuotaTest, ReceiveQueueLengthLimitExceeded) {
142 MojoHandle a, b;
143 CreateMessagePipe(&a, &b);
144
145 const uint64_t kMaxMessages = 1;
146 EXPECT_EQ(MOJO_RESULT_OK,
147 MojoSetQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, kMaxMessages,
148 nullptr));
149
150 MojoHandleSignalsState signals;
151 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
152 EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
153
154 const std::string kTestMessage = "this message is lit, fam";
155 WriteMessage(a, kTestMessage);
156 WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE);
157
158 uint64_t limit = 0;
159 uint64_t usage = 0;
160 EXPECT_EQ(MOJO_RESULT_OK,
161 MojoQueryQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, nullptr,
162 &limit, &usage));
163 EXPECT_EQ(kMaxMessages, limit);
164 EXPECT_EQ(1u, usage);
165
166 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
167 EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
168
169 // Push the endpoint over quota and ensure that it signals accordingly.
170 WriteMessage(a, kTestMessage);
171 WaitForSignals(b, MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
172
173 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
174 EXPECT_TRUE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
175
176 EXPECT_EQ(MOJO_RESULT_OK,
177 MojoQueryQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, nullptr,
178 &limit, &usage));
179 EXPECT_EQ(kMaxMessages, limit);
180 EXPECT_EQ(2u, usage);
181
182 // Read a message and wait for QUOTA_EXCEEDED to go back low.
183 EXPECT_EQ(kTestMessage, ReadMessage(b));
184 WaitForSignals(b, MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED,
185 MOJO_TRIGGER_CONDITION_SIGNALS_UNSATISFIED);
186
187 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
188 EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
189
190 EXPECT_EQ(MOJO_RESULT_OK,
191 MojoQueryQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, nullptr,
192 &limit, &usage));
193 EXPECT_EQ(kMaxMessages, limit);
194 EXPECT_EQ(1u, usage);
195
196 MojoClose(a);
197 MojoClose(b);
198 }
199
TEST_F(QuotaTest,ReceiveQueueMemorySizeLimitExceeded)200 TEST_F(QuotaTest, ReceiveQueueMemorySizeLimitExceeded) {
201 MojoHandle a, b;
202 CreateMessagePipe(&a, &b);
203
204 const uint64_t kMaxMessageBytes = 6;
205 EXPECT_EQ(MOJO_RESULT_OK,
206 MojoSetQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
207 kMaxMessageBytes, nullptr));
208
209 MojoHandleSignalsState signals;
210 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
211 EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
212
213 const std::string kTestMessage = "four";
214 WriteMessage(a, kTestMessage);
215 WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE);
216
217 uint64_t limit = 0;
218 uint64_t usage = 0;
219 EXPECT_EQ(MOJO_RESULT_OK,
220 MojoQueryQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
221 nullptr, &limit, &usage));
222 EXPECT_EQ(kMaxMessageBytes, limit);
223 EXPECT_EQ(kTestMessage.size(), usage);
224
225 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
226 EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
227
228 // Push the endpoint over quota and ensure that it signals accordingly.
229 WriteMessage(a, kTestMessage);
230 WaitForSignals(b, MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
231
232 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
233 EXPECT_TRUE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
234
235 EXPECT_EQ(MOJO_RESULT_OK,
236 MojoQueryQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
237 nullptr, &limit, &usage));
238 EXPECT_EQ(kMaxMessageBytes, limit);
239 EXPECT_EQ(kTestMessage.size() * 2, usage);
240
241 // Read a message and wait for QUOTA_EXCEEDED to go back low.
242 EXPECT_EQ(kTestMessage, ReadMessage(b));
243 WaitForSignals(b, MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED,
244 MOJO_TRIGGER_CONDITION_SIGNALS_UNSATISFIED);
245
246 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
247 EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
248
249 EXPECT_EQ(MOJO_RESULT_OK,
250 MojoQueryQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE,
251 nullptr, &limit, &usage));
252 EXPECT_EQ(kMaxMessageBytes, limit);
253 EXPECT_EQ(kTestMessage.size(), usage);
254
255 MojoClose(a);
256 MojoClose(b);
257 }
258
TEST_F(QuotaTest,TrapQuotaExceeded)259 TEST_F(QuotaTest, TrapQuotaExceeded) {
260 // Simple sanity check to verify that QUOTA_EXCEEDED signals can be trapped
261 // like any other signals.
262
263 MojoHandle a, b;
264 CreateMessagePipe(&a, &b);
265
266 const uint64_t kMaxMessages = 42;
267 EXPECT_EQ(MOJO_RESULT_OK,
268 MojoSetQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, kMaxMessages,
269 nullptr));
270
271 bool signal_event_fired = false;
272 MojoHandle quota_trap;
273 EXPECT_EQ(MOJO_RESULT_OK,
274 MojoCreateTrap(&QuotaExceededEventHandler, nullptr, "a_trap));
275 EXPECT_EQ(MOJO_RESULT_OK,
276 MojoAddTrigger(quota_trap, b, MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED,
277 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
278 reinterpret_cast<uintptr_t>(&signal_event_fired),
279 nullptr));
280 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(quota_trap, nullptr, nullptr, nullptr));
281
282 const std::string kTestMessage("sup");
283 for (uint64_t i = 0; i < kMaxMessages; ++i)
284 WriteMessage(a, kTestMessage);
285
286 // We're at quota but not yet over.
287 MojoHandleSignalsState signals;
288 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
289 EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
290 EXPECT_FALSE(signal_event_fired);
291
292 // Push over quota. The event handler should be invoked before this returns.
293 WriteMessage(a, kTestMessage);
294 EXPECT_TRUE(signal_event_fired);
295
296 EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &signals));
297 EXPECT_TRUE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
298
299 uint64_t limit = 0;
300 uint64_t usage = 0;
301 EXPECT_EQ(MOJO_RESULT_OK,
302 MojoQueryQuota(b, MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH, nullptr,
303 &limit, &usage));
304 EXPECT_EQ(kMaxMessages, limit);
305 EXPECT_EQ(kMaxMessages + 1, usage);
306
307 MojoClose(quota_trap);
308 MojoClose(a);
309 MojoClose(b);
310 }
311
312 } // namespace
313 } // namespace core
314 } // namespace mojo
315