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

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"
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, DispatchMessageEventWithCustomEventType)
166 {
167 enqueue("event:foo\ndata:hello\n\n");
168
169 ASSERT_EQ(1u, events().size());
170 ASSERT_EQ(Type::Event, events()[0].type);
171 EXPECT_EQ("foo", events()[0].event);
172 EXPECT_EQ("hello", events()[0].data);
173 }
174
175 TEST_F(EventSourceParserTest, RetryTakesEffectEvenWhenNotDispatching)
176 {
177 enqueue("retry:999\n");
178 ASSERT_EQ(1u, events().size());
179 ASSERT_EQ(Type::ReconnectionTimeSetting, events()[0].type);
180 ASSERT_EQ(999u, events()[0].reconnectionTime);
181 }
182
183 TEST_F(EventSourceParserTest, EventTypeShouldBeReset)
184 {
185 enqueue("event:foo\ndata:hello\n\ndata:bye\n\n");
186
187 ASSERT_EQ(2u, events().size());
188 ASSERT_EQ(Type::Event, events()[0].type);
189 EXPECT_EQ("foo", events()[0].event);
190 EXPECT_EQ("hello", events()[0].data);
191
192 ASSERT_EQ(Type::Event, events()[1].type);
193 EXPECT_EQ("message", events()[1].event);
194 EXPECT_EQ("bye", events()[1].data);
195 }
196
197 TEST_F(EventSourceParserTest, DataShouldBeReset)
198 {
199 enqueue("data:hello\n\n\n");
200
201 ASSERT_EQ(1u, events().size());
202 ASSERT_EQ(Type::Event, events()[0].type);
203 EXPECT_EQ("message", events()[0].event);
204 EXPECT_EQ("hello", events()[0].data);
205 }
206
207 TEST_F(EventSourceParserTest, LastEventIdShouldNotBeReset)
208 {
209 enqueue("id:99\ndata:hello\n\ndata:bye\n\n");
210
211 EXPECT_EQ("99", parser()->lastEventId());
212 ASSERT_EQ(2u, 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 EXPECT_EQ("99", events()[0].id);
217
218 ASSERT_EQ(Type::Event, events()[1].type);
219 EXPECT_EQ("message", events()[1].event);
220 EXPECT_EQ("bye", events()[1].data);
221 EXPECT_EQ("99", events()[1].id);
222 }
223
224 TEST_F(EventSourceParserTest, VariousNewLinesShouldBeAllowed)
225 {
226 enqueueOneByOne("data:hello\r\n\rdata:bye\r\r");
227
228 ASSERT_EQ(2u, events().size());
229 ASSERT_EQ(Type::Event, events()[0].type);
230 EXPECT_EQ("message", events()[0].event);
231 EXPECT_EQ("hello", events()[0].data);
232
233 ASSERT_EQ(Type::Event, events()[1].type);
234 EXPECT_EQ("message", events()[1].event);
235 EXPECT_EQ("bye", events()[1].data);
236 }
237
238 TEST_F(EventSourceParserTest, RetryWithEmptyValueShouldRestoreDefaultValue)
239 {
240 // TODO(yhirano): This is unspecified in the spec. We need to update
241 // the implementation or the spec.
242 enqueue("retry\n");
243 ASSERT_EQ(1u, events().size());
244 ASSERT_EQ(Type::ReconnectionTimeSetting, events()[0].type);
245 EXPECT_EQ(EventSource::defaultReconnectDelay, events()[0].reconnectionTime);
246 }
247
248 TEST_F(EventSourceParserTest, NonDigitRetryShouldBeIgnored)
249 {
250 enqueue("retry:a0\n");
251 enqueue("retry:xi\n");
252 enqueue("retry:2a\n");
253 enqueue("retry:09a\n");
254 enqueue("retry:1\b\n");
255 enqueue("retry: 1234\n");
256 enqueue("retry:456 \n");
257
258 EXPECT_EQ(0u, events().size());
259 }
260
261 TEST_F(EventSourceParserTest, UnrecognizedFieldShouldBeIgnored)
262 {
263 enqueue("data:hello\nhoge:fuga\npiyo\n\n");
264
265 ASSERT_EQ(1u, events().size());
266 ASSERT_EQ(Type::Event, events()[0].type);
267 EXPECT_EQ("message", events()[0].event);
268 EXPECT_EQ("hello", events()[0].data);
269 }
270
271 TEST_F(EventSourceParserTest, CommentShouldBeIgnored)
272 {
273 enqueue("data:hello\n:event:a\n\n");
274
275 ASSERT_EQ(1u, events().size());
276 ASSERT_EQ(Type::Event, events()[0].type);
277 EXPECT_EQ("message", events()[0].event);
278 EXPECT_EQ("hello", events()[0].data);
279 }
280
281 TEST_F(EventSourceParserTest, BOMShouldBeIgnored)
282 {
283 // This line is recognized because "\xef\xbb\xbf" is a BOM.
284 enqueue("\xef\xbb\xbf" "data:hello\n");
285 // This line is ignored because "\xef\xbb\xbf" is part of the field name.
286 enqueue("\xef\xbb\xbf" "data:bye\n");
287 enqueue("\n");
288
289 ASSERT_EQ(1u, events().size());
290 ASSERT_EQ(Type::Event, events()[0].type);
291 EXPECT_EQ("message", events()[0].event);
292 EXPECT_EQ("hello", events()[0].data);
293 }
tyoshino (SeeGerritForStatus) 2016/01/28 07:31:44 Please add BOM test that uses enqueueOneByOne()
yhirano 2016/01/28 08:45:36 Done.
294
295 TEST_F(EventSourceParserTest, ColonlessLineShouldBeTreatedAsNameOnlyField)
296 {
297 enqueue("data:hello\nevent:a\nevent\n\n");
298
299 ASSERT_EQ(1u, events().size());
300 ASSERT_EQ(Type::Event, events()[0].type);
301 EXPECT_EQ("message", events()[0].event);
302 EXPECT_EQ("hello", events()[0].data);
303 }
304
305 TEST_F(EventSourceParserTest, AtMostOneLeadingSpaceCanBeSkipped)
306 {
307 enqueue("data: hello \nevent: type \n\n");
308
309 ASSERT_EQ(1u, events().size());
310 ASSERT_EQ(Type::Event, events()[0].type);
311 EXPECT_EQ(" type ", events()[0].event);
312 EXPECT_EQ(" hello ", events()[0].data);
313 }
314
315 TEST_F(EventSourceParserTest, DataShouldAccumulate)
316 {
317 enqueue("data\ndata:hello\ndata: world\ndata\n\n");
318
319 ASSERT_EQ(1u, events().size());
320 ASSERT_EQ(Type::Event, events()[0].type);
321 EXPECT_EQ("message", events()[0].event);
322 EXPECT_EQ("\nhello\nworld\n", events()[0].data);
323 }
324
325 TEST_F(EventSourceParserTest, EventShouldNotAccumulate)
326 {
327 enqueue("data:hello\nevent:a\nevent:b\n\n");
328
329 ASSERT_EQ(1u, events().size());
330 ASSERT_EQ(Type::Event, events()[0].type);
331 EXPECT_EQ("b", events()[0].event);
332 EXPECT_EQ("hello", events()[0].data);
333 }
334
335 TEST_F(EventSourceParserTest, FeedDataOneByOne)
336 {
337 enqueueOneByOne("data:hello\r\ndata:world\revent:a\revent:b\nid:4\n\nid:8\nd ata:bye\r\n\r");
338
339 ASSERT_EQ(2u, events().size());
340 ASSERT_EQ(Type::Event, events()[0].type);
341 EXPECT_EQ("b", events()[0].event);
342 EXPECT_EQ("hello\nworld", events()[0].data);
343 EXPECT_EQ("4", events()[0].id);
344
345 ASSERT_EQ(Type::Event, events()[1].type);
346 EXPECT_EQ("message", events()[1].event);
347 EXPECT_EQ("bye", events()[1].data);
348 EXPECT_EQ("8", events()[1].id);
349 }
350
351 TEST_F(EventSourceParserTest, InvalidUTF8Sequence)
352 {
353 enqueue("data:\xffhello\xc2\n\n");
354
355 ASSERT_EQ(1u, events().size());
356 ASSERT_EQ(Type::Event, events()[0].type);
357 EXPECT_EQ("message", events()[0].event);
358 String expected = String() + replacementCharacter + "hello" + replacementCha racter;
359 EXPECT_EQ(expected, events()[0].data);
360 }
361
362 TEST(EventSourceParserStoppingTest, Stop)
363 {
364 StoppingClient* client = new StoppingClient();
365 EventSourceParser* parser = new EventSourceParser(AtomicString(), client);
366 client->setParser(parser);
367
368 const char input[] = "data:hello\n\ndata:bye\n\n";
369 parser->addBytes(input, strlen(input));
370
371 const auto& events = client->events();
372
373 ASSERT_EQ(1u, events.size());
374 ASSERT_EQ(EventOrReconnectionTimeSetting::Type::Event, events[0].type);
375 EXPECT_EQ("message", events[0].event);
376 EXPECT_EQ("hello", events[0].data);
377 }
378
379 } // namespace
380
381 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698