OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 "core/page/EventSourceParser.h" | |
6 | |
7 #include "core/page/EventSource.h" | |
tyoshino (SeeGerritForStatus)
2016/01/29 07:00:15
unnecessary?
yhirano
2016/01/29 11:41:16
For EventSource::defaultReconnectDelay.
| |
8 #include "testing/gtest/include/gtest/gtest.h" | |
9 #include "wtf/text/CharacterNames.h" | |
10 | |
11 #include <string.h> | |
12 | |
13 namespace blink { | |
14 | |
15 namespace { | |
16 | |
17 struct EventOrReconnectionTimeSetting { | |
18 enum Type { | |
19 Event, | |
20 ReconnectionTimeSetting, | |
21 }; | |
22 | |
23 EventOrReconnectionTimeSetting(const AtomicString& event, const String& data , const AtomicString& id) | |
24 : type(Event) | |
25 , event(event) | |
26 , data(data) | |
27 , id(id) | |
28 , reconnectionTime(0) | |
29 { | |
30 } | |
31 explicit EventOrReconnectionTimeSetting(unsigned long long reconnectionTime) | |
32 : type(ReconnectionTimeSetting) | |
33 , reconnectionTime(reconnectionTime) | |
34 { | |
35 } | |
36 | |
37 const Type type; | |
38 const AtomicString event; | |
39 const String data; | |
40 const AtomicString id; | |
41 const unsigned long long reconnectionTime; | |
42 }; | |
43 | |
44 class Client : public GarbageCollectedFinalized<Client>, public EventSourceParse r::Client { | |
45 USING_GARBAGE_COLLECTED_MIXIN(Client); | |
46 public: | |
47 ~Client() override {} | |
48 const Vector<EventOrReconnectionTimeSetting>& events() const { return m_even ts; } | |
49 void onMessageEvent(const AtomicString& event, const String& data, const Ato micString& id) override | |
50 { | |
51 m_events.append(EventOrReconnectionTimeSetting(event, data, id)); | |
52 } | |
53 void onReconnectionTimeSet(unsigned long long reconnectionTime) override | |
54 { | |
55 m_events.append(EventOrReconnectionTimeSetting(reconnectionTime)); | |
56 } | |
57 | |
58 private: | |
59 Vector<EventOrReconnectionTimeSetting> m_events; | |
60 }; | |
61 | |
62 class StoppingClient : public GarbageCollectedFinalized<Client>, public EventSou rceParser::Client { | |
63 USING_GARBAGE_COLLECTED_MIXIN(StoppingClient); | |
64 public: | |
65 ~StoppingClient() override {} | |
66 const Vector<EventOrReconnectionTimeSetting>& events() const { return m_even ts; } | |
67 void setParser(EventSourceParser* parser) { m_parser = parser; } | |
68 void onMessageEvent(const AtomicString& event, const String& data, const Ato micString& id) override | |
69 { | |
70 m_parser->stop(); | |
71 m_events.append(EventOrReconnectionTimeSetting(event, data, id)); | |
72 } | |
73 void onReconnectionTimeSet(unsigned long long reconnectionTime) override | |
74 { | |
75 m_events.append(EventOrReconnectionTimeSetting(reconnectionTime)); | |
76 } | |
77 | |
78 DEFINE_INLINE_VIRTUAL_TRACE() | |
79 { | |
80 visitor->trace(m_parser); | |
81 EventSourceParser::Client::trace(visitor); | |
82 } | |
83 | |
84 private: | |
85 Member<EventSourceParser> m_parser; | |
86 Vector<EventOrReconnectionTimeSetting> m_events; | |
87 }; | |
88 | |
89 class EventSourceParserTest : public ::testing::Test { | |
90 protected: | |
91 using Type = EventOrReconnectionTimeSetting::Type; | |
92 EventSourceParserTest() | |
93 : m_client(new Client) | |
94 , m_parser(new EventSourceParser(AtomicString(), m_client)) | |
95 { | |
96 } | |
97 ~EventSourceParserTest() override {} | |
98 | |
99 void enqueue(const char* data) { m_parser->addBytes(data, strlen(data)); } | |
100 void enqueueOneByOne(const char* data) | |
101 { | |
102 const char*p = data; | |
103 while (*p != '\0') | |
104 m_parser->addBytes(p++, 1); | |
105 } | |
106 | |
107 const Vector<EventOrReconnectionTimeSetting>& events() { return m_client->ev ents(); } | |
108 | |
109 EventSourceParser* parser() { return m_parser; } | |
110 | |
111 Persistent<Client> m_client; | |
112 Persistent<EventSourceParser> m_parser; | |
113 }; | |
114 | |
115 TEST_F(EventSourceParserTest, EmptyMessageEventShouldNotBeDispatched) | |
116 { | |
117 enqueue("\n"); | |
118 | |
119 EXPECT_EQ(0u, events().size()); | |
120 EXPECT_EQ(String(), parser()->lastEventId()); | |
121 } | |
122 | |
123 TEST_F(EventSourceParserTest, DispatchSimpleMessageEvent) | |
124 { | |
125 enqueue("data:hello\n\n"); | |
126 | |
127 ASSERT_EQ(1u, events().size()); | |
128 ASSERT_EQ(Type::Event, events()[0].type); | |
129 EXPECT_EQ("message", events()[0].event); | |
130 EXPECT_EQ("hello", events()[0].data); | |
131 EXPECT_EQ(String(), events()[0].id); | |
132 EXPECT_EQ(AtomicString(), parser()->lastEventId()); | |
133 } | |
134 | |
135 TEST_F(EventSourceParserTest, ConstructWithLastEventId) | |
136 { | |
137 m_parser = new EventSourceParser("hoge", m_client); | |
138 EXPECT_EQ("hoge", parser()->lastEventId()); | |
139 | |
140 enqueue("data:hello\n\n"); | |
141 | |
142 ASSERT_EQ(1u, events().size()); | |
143 ASSERT_EQ(Type::Event, events()[0].type); | |
144 EXPECT_EQ("message", events()[0].event); | |
145 EXPECT_EQ("hello", events()[0].data); | |
146 EXPECT_EQ("hoge", events()[0].id); | |
147 EXPECT_EQ("hoge", parser()->lastEventId()); | |
148 } | |
149 | |
150 TEST_F(EventSourceParserTest, DispatchMessageEventWithLastEventId) | |
151 { | |
152 enqueue("id:99\ndata:hello\n"); | |
153 EXPECT_EQ(String(), parser()->lastEventId()); | |
154 | |
155 enqueue("\n"); | |
156 | |
157 ASSERT_EQ(1u, events().size()); | |
158 ASSERT_EQ(Type::Event, events()[0].type); | |
159 EXPECT_EQ("message", events()[0].event); | |
160 EXPECT_EQ("hello", events()[0].data); | |
161 EXPECT_EQ("99", events()[0].id); | |
162 EXPECT_EQ("99", parser()->lastEventId()); | |
163 } | |
164 | |
165 TEST_F(EventSourceParserTest, LastEventIdCanBeUpdatedEvenWhenDataIsEmpty) | |
166 { | |
167 enqueue("id:99\n"); | |
168 EXPECT_EQ(String(), parser()->lastEventId()); | |
169 | |
170 enqueue("\n"); | |
171 | |
172 ASSERT_EQ(0u, events().size()); | |
173 EXPECT_EQ("99", parser()->lastEventId()); | |
174 } | |
175 | |
176 TEST_F(EventSourceParserTest, DispatchMessageEventWithCustomEventType) | |
177 { | |
178 enqueue("event:foo\ndata:hello\n\n"); | |
179 | |
180 ASSERT_EQ(1u, events().size()); | |
181 ASSERT_EQ(Type::Event, events()[0].type); | |
182 EXPECT_EQ("foo", events()[0].event); | |
183 EXPECT_EQ("hello", events()[0].data); | |
184 } | |
185 | |
186 TEST_F(EventSourceParserTest, RetryTakesEffectEvenWhenNotDispatching) | |
187 { | |
188 enqueue("retry:999\n"); | |
189 ASSERT_EQ(1u, events().size()); | |
190 ASSERT_EQ(Type::ReconnectionTimeSetting, events()[0].type); | |
191 ASSERT_EQ(999u, events()[0].reconnectionTime); | |
192 } | |
193 | |
194 TEST_F(EventSourceParserTest, EventTypeShouldBeReset) | |
195 { | |
196 enqueue("event:foo\ndata:hello\n\ndata:bye\n\n"); | |
197 | |
198 ASSERT_EQ(2u, events().size()); | |
199 ASSERT_EQ(Type::Event, events()[0].type); | |
200 EXPECT_EQ("foo", events()[0].event); | |
201 EXPECT_EQ("hello", events()[0].data); | |
202 | |
203 ASSERT_EQ(Type::Event, events()[1].type); | |
204 EXPECT_EQ("message", events()[1].event); | |
205 EXPECT_EQ("bye", events()[1].data); | |
206 } | |
207 | |
208 TEST_F(EventSourceParserTest, DataShouldBeReset) | |
209 { | |
210 enqueue("data:hello\n\n\n"); | |
211 | |
212 ASSERT_EQ(1u, events().size()); | |
213 ASSERT_EQ(Type::Event, events()[0].type); | |
214 EXPECT_EQ("message", events()[0].event); | |
215 EXPECT_EQ("hello", events()[0].data); | |
216 } | |
217 | |
218 TEST_F(EventSourceParserTest, LastEventIdShouldNotBeReset) | |
219 { | |
220 enqueue("id:99\ndata:hello\n\ndata:bye\n\n"); | |
221 | |
222 EXPECT_EQ("99", parser()->lastEventId()); | |
223 ASSERT_EQ(2u, events().size()); | |
224 ASSERT_EQ(Type::Event, events()[0].type); | |
225 EXPECT_EQ("message", events()[0].event); | |
226 EXPECT_EQ("hello", events()[0].data); | |
227 EXPECT_EQ("99", events()[0].id); | |
228 | |
229 ASSERT_EQ(Type::Event, events()[1].type); | |
230 EXPECT_EQ("message", events()[1].event); | |
231 EXPECT_EQ("bye", events()[1].data); | |
232 EXPECT_EQ("99", events()[1].id); | |
233 } | |
234 | |
235 TEST_F(EventSourceParserTest, VariousNewLinesShouldBeAllowed) | |
236 { | |
237 enqueueOneByOne("data:hello\r\n\rdata:bye\r\r"); | |
238 | |
239 ASSERT_EQ(2u, events().size()); | |
240 ASSERT_EQ(Type::Event, events()[0].type); | |
241 EXPECT_EQ("message", events()[0].event); | |
242 EXPECT_EQ("hello", events()[0].data); | |
243 | |
244 ASSERT_EQ(Type::Event, events()[1].type); | |
245 EXPECT_EQ("message", events()[1].event); | |
246 EXPECT_EQ("bye", events()[1].data); | |
247 } | |
248 | |
249 TEST_F(EventSourceParserTest, RetryWithEmptyValueShouldRestoreDefaultValue) | |
250 { | |
251 // TODO(yhirano): This is unspecified in the spec. We need to update | |
252 // the implementation or the spec. | |
253 enqueue("retry\n"); | |
254 ASSERT_EQ(1u, events().size()); | |
255 ASSERT_EQ(Type::ReconnectionTimeSetting, events()[0].type); | |
256 EXPECT_EQ(EventSource::defaultReconnectDelay, events()[0].reconnectionTime); | |
257 } | |
258 | |
259 TEST_F(EventSourceParserTest, NonDigitRetryShouldBeIgnored) | |
260 { | |
261 enqueue("retry:a0\n"); | |
262 enqueue("retry:xi\n"); | |
263 enqueue("retry:2a\n"); | |
264 enqueue("retry:09a\n"); | |
265 enqueue("retry:1\b\n"); | |
266 enqueue("retry: 1234\n"); | |
267 enqueue("retry:456 \n"); | |
268 | |
269 EXPECT_EQ(0u, events().size()); | |
270 } | |
271 | |
272 TEST_F(EventSourceParserTest, UnrecognizedFieldShouldBeIgnored) | |
273 { | |
274 enqueue("data:hello\nhoge:fuga\npiyo\n\n"); | |
275 | |
276 ASSERT_EQ(1u, events().size()); | |
277 ASSERT_EQ(Type::Event, events()[0].type); | |
278 EXPECT_EQ("message", events()[0].event); | |
279 EXPECT_EQ("hello", events()[0].data); | |
280 } | |
281 | |
282 TEST_F(EventSourceParserTest, CommentShouldBeIgnored) | |
283 { | |
284 enqueue("data:hello\n:event:a\n\n"); | |
285 | |
286 ASSERT_EQ(1u, events().size()); | |
287 ASSERT_EQ(Type::Event, events()[0].type); | |
288 EXPECT_EQ("message", events()[0].event); | |
289 EXPECT_EQ("hello", events()[0].data); | |
290 } | |
291 | |
292 TEST_F(EventSourceParserTest, BOMShouldBeIgnored) | |
293 { | |
294 // This line is recognized because "\xef\xbb\xbf" is a BOM. | |
295 enqueue("\xef\xbb\xbf" "data:hello\n"); | |
296 // This line is ignored because "\xef\xbb\xbf" is part of the field name. | |
297 enqueue("\xef\xbb\xbf" "data:bye\n"); | |
298 enqueue("\n"); | |
299 | |
300 ASSERT_EQ(1u, events().size()); | |
301 ASSERT_EQ(Type::Event, events()[0].type); | |
302 EXPECT_EQ("message", events()[0].event); | |
303 EXPECT_EQ("hello", events()[0].data); | |
304 } | |
305 | |
306 TEST_F(EventSourceParserTest, BOMShouldBeIgnored_OneByOne) | |
307 { | |
308 // This line is recognized because "\xef\xbb\xbf" is a BOM. | |
309 enqueueOneByOne("\xef\xbb\xbf" "data:hello\n"); | |
310 // This line is ignored because "\xef\xbb\xbf" is part of the field name. | |
311 enqueueOneByOne("\xef\xbb\xbf" "data:bye\n"); | |
312 enqueueOneByOne("\n"); | |
313 | |
314 ASSERT_EQ(1u, events().size()); | |
315 ASSERT_EQ(Type::Event, events()[0].type); | |
316 EXPECT_EQ("message", events()[0].event); | |
317 EXPECT_EQ("hello", events()[0].data); | |
318 } | |
319 | |
320 TEST_F(EventSourceParserTest, ColonlessLineShouldBeTreatedAsNameOnlyField) | |
321 { | |
322 enqueue("data:hello\nevent:a\nevent\n\n"); | |
323 | |
324 ASSERT_EQ(1u, events().size()); | |
325 ASSERT_EQ(Type::Event, events()[0].type); | |
326 EXPECT_EQ("message", events()[0].event); | |
327 EXPECT_EQ("hello", events()[0].data); | |
328 } | |
329 | |
330 TEST_F(EventSourceParserTest, AtMostOneLeadingSpaceCanBeSkipped) | |
331 { | |
332 enqueue("data: hello \nevent: type \n\n"); | |
333 | |
334 ASSERT_EQ(1u, events().size()); | |
335 ASSERT_EQ(Type::Event, events()[0].type); | |
336 EXPECT_EQ(" type ", events()[0].event); | |
337 EXPECT_EQ(" hello ", events()[0].data); | |
338 } | |
339 | |
340 TEST_F(EventSourceParserTest, DataShouldAccumulate) | |
341 { | |
342 enqueue("data\ndata:hello\ndata: world\ndata\n\n"); | |
343 | |
344 ASSERT_EQ(1u, events().size()); | |
345 ASSERT_EQ(Type::Event, events()[0].type); | |
346 EXPECT_EQ("message", events()[0].event); | |
347 EXPECT_EQ("\nhello\nworld\n", events()[0].data); | |
348 } | |
349 | |
350 TEST_F(EventSourceParserTest, EventShouldNotAccumulate) | |
351 { | |
352 enqueue("data:hello\nevent:a\nevent:b\n\n"); | |
353 | |
354 ASSERT_EQ(1u, events().size()); | |
355 ASSERT_EQ(Type::Event, events()[0].type); | |
356 EXPECT_EQ("b", events()[0].event); | |
357 EXPECT_EQ("hello", events()[0].data); | |
358 } | |
359 | |
360 TEST_F(EventSourceParserTest, FeedDataOneByOne) | |
361 { | |
362 enqueueOneByOne("data:hello\r\ndata:world\revent:a\revent:b\nid:4\n\nid:8\nd ata:bye\r\n\r"); | |
363 | |
364 ASSERT_EQ(2u, events().size()); | |
365 ASSERT_EQ(Type::Event, events()[0].type); | |
366 EXPECT_EQ("b", events()[0].event); | |
367 EXPECT_EQ("hello\nworld", events()[0].data); | |
368 EXPECT_EQ("4", events()[0].id); | |
369 | |
370 ASSERT_EQ(Type::Event, events()[1].type); | |
371 EXPECT_EQ("message", events()[1].event); | |
372 EXPECT_EQ("bye", events()[1].data); | |
373 EXPECT_EQ("8", events()[1].id); | |
374 } | |
375 | |
376 TEST_F(EventSourceParserTest, InvalidUTF8Sequence) | |
377 { | |
378 enqueue("data:\xffhello\xc2\ndata:bye\n\n"); | |
379 | |
380 ASSERT_EQ(1u, events().size()); | |
381 ASSERT_EQ(Type::Event, events()[0].type); | |
382 EXPECT_EQ("message", events()[0].event); | |
383 String expected = String() + replacementCharacter + "hello" + replacementCha racter + "\nbye"; | |
384 EXPECT_EQ(expected, events()[0].data); | |
385 } | |
386 | |
387 TEST(EventSourceParserStoppingTest, StopWhileParsing) | |
388 { | |
389 StoppingClient* client = new StoppingClient(); | |
390 EventSourceParser* parser = new EventSourceParser(AtomicString(), client); | |
391 client->setParser(parser); | |
392 | |
393 const char input[] = "data:hello\nid:99\n\nid:44\ndata:bye\n\n"; | |
394 parser->addBytes(input, strlen(input)); | |
395 | |
396 const auto& events = client->events(); | |
397 | |
398 ASSERT_EQ(1u, events.size()); | |
399 ASSERT_EQ(EventOrReconnectionTimeSetting::Type::Event, events[0].type); | |
400 EXPECT_EQ("message", events[0].event); | |
401 EXPECT_EQ("hello", events[0].data); | |
402 EXPECT_EQ("99", parser->lastEventId()); | |
403 } | |
404 | |
405 } // namespace | |
406 | |
407 } // namespace blink | |
OLD | NEW |