• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &quota_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