Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: third_party/WebKit/Source/core/page/EventSourceParserTest.cpp

Issue 1642563002: Introduce EventSourceParser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@event-source-retry-fix
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698