OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/notifier/registration_manager.h" | 5 #include "chrome/browser/sync/notifier/registration_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <cstddef> | 9 #include <cstddef> |
10 #include <deque> | 10 #include <deque> |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 virtual void Unregister(const invalidation::ObjectId& oid) { | 88 virtual void Unregister(const invalidation::ObjectId& oid) { |
89 syncable::ModelType model_type = ObjectIdToModelType(oid); | 89 syncable::ModelType model_type = ObjectIdToModelType(oid); |
90 EXPECT_TRUE(registered_types_.Has(model_type)); | 90 EXPECT_TRUE(registered_types_.Has(model_type)); |
91 registered_types_.Remove(model_type); | 91 registered_types_.Remove(model_type); |
92 } | 92 } |
93 | 93 |
94 virtual void Unregister(const std::vector<invalidation::ObjectId>& oids) { | 94 virtual void Unregister(const std::vector<invalidation::ObjectId>& oids) { |
95 // Unused for now. | 95 // Unused for now. |
96 } | 96 } |
97 | 97 |
98 const syncable::ModelEnumSet GetRegisteredTypes() const { | 98 const syncable::ModelTypeSet GetRegisteredTypes() const { |
99 return registered_types_; | 99 return registered_types_; |
100 } | 100 } |
101 | 101 |
102 private: | 102 private: |
103 syncable::ModelEnumSet registered_types_; | 103 syncable::ModelTypeSet registered_types_; |
104 | 104 |
105 DISALLOW_COPY_AND_ASSIGN(FakeInvalidationClient); | 105 DISALLOW_COPY_AND_ASSIGN(FakeInvalidationClient); |
106 }; | 106 }; |
107 | 107 |
108 const syncable::ModelType kModelTypes[] = { | 108 const syncable::ModelType kModelTypes[] = { |
109 syncable::BOOKMARKS, | 109 syncable::BOOKMARKS, |
110 syncable::PREFERENCES, | 110 syncable::PREFERENCES, |
111 syncable::THEMES, | 111 syncable::THEMES, |
112 syncable::AUTOFILL, | 112 syncable::AUTOFILL, |
113 syncable::EXTENSIONS, | 113 syncable::EXTENSIONS, |
114 }; | 114 }; |
115 const size_t kModelTypeCount = arraysize(kModelTypes); | 115 const size_t kModelTypeCount = arraysize(kModelTypes); |
116 | 116 |
117 syncable::ModelEnumSet FromPtr( | 117 syncable::ModelTypeSet FromPtr( |
118 const syncable::ModelType* types, size_t count) { | 118 const syncable::ModelType* types, size_t count) { |
119 syncable::ModelEnumSet type_set; | 119 syncable::ModelTypeSet type_set; |
120 for (size_t i = 0; i < count; ++i) { | 120 for (size_t i = 0; i < count; ++i) { |
121 type_set.Put(types[i]); | 121 type_set.Put(types[i]); |
122 } | 122 } |
123 return type_set; | 123 return type_set; |
124 } | 124 } |
125 | 125 |
126 void ExpectPendingRegistrations( | 126 void ExpectPendingRegistrations( |
127 syncable::ModelEnumSet expected_pending_types, | 127 syncable::ModelTypeSet expected_pending_types, |
128 double expected_delay_seconds, | 128 double expected_delay_seconds, |
129 const RegistrationManager::PendingRegistrationMap& pending_registrations) { | 129 const RegistrationManager::PendingRegistrationMap& pending_registrations) { |
130 syncable::ModelEnumSet pending_types; | 130 syncable::ModelTypeSet pending_types; |
131 for (RegistrationManager::PendingRegistrationMap::const_iterator it = | 131 for (RegistrationManager::PendingRegistrationMap::const_iterator it = |
132 pending_registrations.begin(); it != pending_registrations.end(); | 132 pending_registrations.begin(); it != pending_registrations.end(); |
133 ++it) { | 133 ++it) { |
134 SCOPED_TRACE(syncable::ModelTypeToString(it->first)); | 134 SCOPED_TRACE(syncable::ModelTypeToString(it->first)); |
135 pending_types.Put(it->first); | 135 pending_types.Put(it->first); |
136 base::TimeDelta offset = | 136 base::TimeDelta offset = |
137 it->second.last_registration_request - | 137 it->second.last_registration_request - |
138 it->second.registration_attempt; | 138 it->second.registration_attempt; |
139 base::TimeDelta expected_delay = | 139 base::TimeDelta expected_delay = |
140 base::TimeDelta::FromSeconds( | 140 base::TimeDelta::FromSeconds( |
(...skipping 12 matching lines...) Expand all Loading... |
153 EXPECT_TRUE(pending_types.Equals(expected_pending_types)); | 153 EXPECT_TRUE(pending_types.Equals(expected_pending_types)); |
154 } | 154 } |
155 | 155 |
156 class RegistrationManagerTest : public testing::Test { | 156 class RegistrationManagerTest : public testing::Test { |
157 protected: | 157 protected: |
158 RegistrationManagerTest() | 158 RegistrationManagerTest() |
159 : fake_registration_manager_(&fake_invalidation_client_) {} | 159 : fake_registration_manager_(&fake_invalidation_client_) {} |
160 | 160 |
161 virtual ~RegistrationManagerTest() {} | 161 virtual ~RegistrationManagerTest() {} |
162 | 162 |
163 void LoseRegistrations(syncable::ModelEnumSet types) { | 163 void LoseRegistrations(syncable::ModelTypeSet types) { |
164 for (syncable::ModelEnumSet::Iterator it = types.First(); | 164 for (syncable::ModelTypeSet::Iterator it = types.First(); |
165 it.Good(); it.Inc()) { | 165 it.Good(); it.Inc()) { |
166 fake_invalidation_client_.LoseRegistration(it.Get()); | 166 fake_invalidation_client_.LoseRegistration(it.Get()); |
167 fake_registration_manager_.MarkRegistrationLost(it.Get()); | 167 fake_registration_manager_.MarkRegistrationLost(it.Get()); |
168 } | 168 } |
169 } | 169 } |
170 | 170 |
171 void DisableTypes(syncable::ModelEnumSet types) { | 171 void DisableTypes(syncable::ModelTypeSet types) { |
172 for (syncable::ModelEnumSet::Iterator it = types.First(); | 172 for (syncable::ModelTypeSet::Iterator it = types.First(); |
173 it.Good(); it.Inc()) { | 173 it.Good(); it.Inc()) { |
174 fake_invalidation_client_.LoseRegistration(it.Get()); | 174 fake_invalidation_client_.LoseRegistration(it.Get()); |
175 fake_registration_manager_.DisableType(it.Get()); | 175 fake_registration_manager_.DisableType(it.Get()); |
176 } | 176 } |
177 } | 177 } |
178 | 178 |
179 // Used by MarkRegistrationLostBackoff* tests. | 179 // Used by MarkRegistrationLostBackoff* tests. |
180 void RunBackoffTest(double jitter) { | 180 void RunBackoffTest(double jitter) { |
181 fake_registration_manager_.SetJitter(jitter); | 181 fake_registration_manager_.SetJitter(jitter); |
182 syncable::ModelEnumSet types = FromPtr(kModelTypes, kModelTypeCount); | 182 syncable::ModelTypeSet types = FromPtr(kModelTypes, kModelTypeCount); |
183 fake_registration_manager_.SetRegisteredTypes(types); | 183 fake_registration_manager_.SetRegisteredTypes(types); |
184 | 184 |
185 // Lose some types. | 185 // Lose some types. |
186 syncable::ModelEnumSet lost_types = FromPtr(kModelTypes, 2); | 186 syncable::ModelTypeSet lost_types = FromPtr(kModelTypes, 2); |
187 LoseRegistrations(lost_types); | 187 LoseRegistrations(lost_types); |
188 ExpectPendingRegistrations( | 188 ExpectPendingRegistrations( |
189 lost_types, 0.0, | 189 lost_types, 0.0, |
190 fake_registration_manager_.GetPendingRegistrations()); | 190 fake_registration_manager_.GetPendingRegistrations()); |
191 | 191 |
192 // Trigger another failure to start delaying. | 192 // Trigger another failure to start delaying. |
193 fake_registration_manager_.FirePendingRegistrationsForTest(); | 193 fake_registration_manager_.FirePendingRegistrationsForTest(); |
194 LoseRegistrations(lost_types); | 194 LoseRegistrations(lost_types); |
195 | 195 |
196 double scaled_jitter = | 196 double scaled_jitter = |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 FakeRegistrationManager fake_registration_manager_; | 232 FakeRegistrationManager fake_registration_manager_; |
233 | 233 |
234 private: | 234 private: |
235 // Needed by timers in RegistrationManager. | 235 // Needed by timers in RegistrationManager. |
236 MessageLoop message_loop_; | 236 MessageLoop message_loop_; |
237 | 237 |
238 DISALLOW_COPY_AND_ASSIGN(RegistrationManagerTest); | 238 DISALLOW_COPY_AND_ASSIGN(RegistrationManagerTest); |
239 }; | 239 }; |
240 | 240 |
241 TEST_F(RegistrationManagerTest, SetRegisteredTypes) { | 241 TEST_F(RegistrationManagerTest, SetRegisteredTypes) { |
242 syncable::ModelEnumSet types = FromPtr(kModelTypes, kModelTypeCount); | 242 syncable::ModelTypeSet types = FromPtr(kModelTypes, kModelTypeCount); |
243 | 243 |
244 EXPECT_TRUE(fake_registration_manager_.GetRegisteredTypes().Empty()); | 244 EXPECT_TRUE(fake_registration_manager_.GetRegisteredTypes().Empty()); |
245 EXPECT_TRUE(fake_invalidation_client_.GetRegisteredTypes().Empty()); | 245 EXPECT_TRUE(fake_invalidation_client_.GetRegisteredTypes().Empty()); |
246 | 246 |
247 fake_registration_manager_.SetRegisteredTypes(types); | 247 fake_registration_manager_.SetRegisteredTypes(types); |
248 EXPECT_TRUE(fake_registration_manager_.GetRegisteredTypes().Equals(types)); | 248 EXPECT_TRUE(fake_registration_manager_.GetRegisteredTypes().Equals(types)); |
249 EXPECT_TRUE(fake_invalidation_client_.GetRegisteredTypes().Equals(types)); | 249 EXPECT_TRUE(fake_invalidation_client_.GetRegisteredTypes().Equals(types)); |
250 | 250 |
251 types.Put(syncable::APPS); | 251 types.Put(syncable::APPS); |
252 types.Remove(syncable::BOOKMARKS); | 252 types.Remove(syncable::BOOKMARKS); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 EXPECT_EQ(10, GetRoundedBackoff(5.0, 0.0)); | 287 EXPECT_EQ(10, GetRoundedBackoff(5.0, 0.0)); |
288 EXPECT_EQ(12, GetRoundedBackoff(5.0, +1.0)); | 288 EXPECT_EQ(12, GetRoundedBackoff(5.0, +1.0)); |
289 | 289 |
290 // Test ceiling. | 290 // Test ceiling. |
291 EXPECT_EQ(19, GetRoundedBackoff(13.0, -1.0)); | 291 EXPECT_EQ(19, GetRoundedBackoff(13.0, -1.0)); |
292 EXPECT_EQ(20, GetRoundedBackoff(13.0, 0.0)); | 292 EXPECT_EQ(20, GetRoundedBackoff(13.0, 0.0)); |
293 EXPECT_EQ(20, GetRoundedBackoff(13.0, +1.0)); | 293 EXPECT_EQ(20, GetRoundedBackoff(13.0, +1.0)); |
294 } | 294 } |
295 | 295 |
296 TEST_F(RegistrationManagerTest, MarkRegistrationLost) { | 296 TEST_F(RegistrationManagerTest, MarkRegistrationLost) { |
297 syncable::ModelEnumSet types = FromPtr(kModelTypes, kModelTypeCount); | 297 syncable::ModelTypeSet types = FromPtr(kModelTypes, kModelTypeCount); |
298 | 298 |
299 fake_registration_manager_.SetRegisteredTypes(types); | 299 fake_registration_manager_.SetRegisteredTypes(types); |
300 EXPECT_TRUE(fake_registration_manager_.GetPendingRegistrations().empty()); | 300 EXPECT_TRUE(fake_registration_manager_.GetPendingRegistrations().empty()); |
301 | 301 |
302 // Lose some types. | 302 // Lose some types. |
303 syncable::ModelEnumSet lost_types = FromPtr( | 303 syncable::ModelTypeSet lost_types = FromPtr( |
304 kModelTypes, 3); | 304 kModelTypes, 3); |
305 syncable::ModelEnumSet non_lost_types = FromPtr( | 305 syncable::ModelTypeSet non_lost_types = FromPtr( |
306 kModelTypes + 3, kModelTypeCount - 3); | 306 kModelTypes + 3, kModelTypeCount - 3); |
307 LoseRegistrations(lost_types); | 307 LoseRegistrations(lost_types); |
308 ExpectPendingRegistrations( | 308 ExpectPendingRegistrations( |
309 lost_types, 0.0, | 309 lost_types, 0.0, |
310 fake_registration_manager_.GetPendingRegistrations()); | 310 fake_registration_manager_.GetPendingRegistrations()); |
311 EXPECT_TRUE( | 311 EXPECT_TRUE( |
312 fake_registration_manager_.GetRegisteredTypes().Equals(non_lost_types)); | 312 fake_registration_manager_.GetRegisteredTypes().Equals(non_lost_types)); |
313 EXPECT_TRUE( | 313 EXPECT_TRUE( |
314 fake_invalidation_client_.GetRegisteredTypes().Equals(non_lost_types)); | 314 fake_invalidation_client_.GetRegisteredTypes().Equals(non_lost_types)); |
315 | 315 |
(...skipping 11 matching lines...) Expand all Loading... |
327 | 327 |
328 TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoffMid) { | 328 TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoffMid) { |
329 RunBackoffTest(0.0); | 329 RunBackoffTest(0.0); |
330 } | 330 } |
331 | 331 |
332 TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoffHigh) { | 332 TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoffHigh) { |
333 RunBackoffTest(+1.0); | 333 RunBackoffTest(+1.0); |
334 } | 334 } |
335 | 335 |
336 TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoffReset) { | 336 TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoffReset) { |
337 syncable::ModelEnumSet types = FromPtr(kModelTypes, kModelTypeCount); | 337 syncable::ModelTypeSet types = FromPtr(kModelTypes, kModelTypeCount); |
338 | 338 |
339 fake_registration_manager_.SetRegisteredTypes(types); | 339 fake_registration_manager_.SetRegisteredTypes(types); |
340 | 340 |
341 // Lose some types. | 341 // Lose some types. |
342 syncable::ModelEnumSet lost_types = FromPtr(kModelTypes, 2); | 342 syncable::ModelTypeSet lost_types = FromPtr(kModelTypes, 2); |
343 LoseRegistrations(lost_types); | 343 LoseRegistrations(lost_types); |
344 ExpectPendingRegistrations( | 344 ExpectPendingRegistrations( |
345 lost_types, 0.0, | 345 lost_types, 0.0, |
346 fake_registration_manager_.GetPendingRegistrations()); | 346 fake_registration_manager_.GetPendingRegistrations()); |
347 | 347 |
348 // Trigger another failure to start delaying. | 348 // Trigger another failure to start delaying. |
349 fake_registration_manager_.FirePendingRegistrationsForTest(); | 349 fake_registration_manager_.FirePendingRegistrationsForTest(); |
350 LoseRegistrations(lost_types); | 350 LoseRegistrations(lost_types); |
351 double expected_delay = | 351 double expected_delay = |
352 RegistrationManager::kInitialRegistrationDelaySeconds; | 352 RegistrationManager::kInitialRegistrationDelaySeconds; |
353 ExpectPendingRegistrations( | 353 ExpectPendingRegistrations( |
354 lost_types, expected_delay, | 354 lost_types, expected_delay, |
355 fake_registration_manager_.GetPendingRegistrations()); | 355 fake_registration_manager_.GetPendingRegistrations()); |
356 | 356 |
357 // Set types again. | 357 // Set types again. |
358 fake_registration_manager_.SetRegisteredTypes(types); | 358 fake_registration_manager_.SetRegisteredTypes(types); |
359 ExpectPendingRegistrations( | 359 ExpectPendingRegistrations( |
360 syncable::ModelEnumSet(), 0.0, | 360 syncable::ModelTypeSet(), 0.0, |
361 fake_registration_manager_.GetPendingRegistrations()); | 361 fake_registration_manager_.GetPendingRegistrations()); |
362 } | 362 } |
363 | 363 |
364 TEST_F(RegistrationManagerTest, MarkAllRegistrationsLost) { | 364 TEST_F(RegistrationManagerTest, MarkAllRegistrationsLost) { |
365 syncable::ModelEnumSet types = FromPtr(kModelTypes, kModelTypeCount); | 365 syncable::ModelTypeSet types = FromPtr(kModelTypes, kModelTypeCount); |
366 | 366 |
367 fake_registration_manager_.SetRegisteredTypes(types); | 367 fake_registration_manager_.SetRegisteredTypes(types); |
368 | 368 |
369 fake_invalidation_client_.LoseAllRegistrations(); | 369 fake_invalidation_client_.LoseAllRegistrations(); |
370 fake_registration_manager_.MarkAllRegistrationsLost(); | 370 fake_registration_manager_.MarkAllRegistrationsLost(); |
371 | 371 |
372 syncable::ModelEnumSet expected_types; | 372 syncable::ModelTypeSet expected_types; |
373 EXPECT_TRUE( | 373 EXPECT_TRUE( |
374 fake_registration_manager_.GetRegisteredTypes().Equals(expected_types)); | 374 fake_registration_manager_.GetRegisteredTypes().Equals(expected_types)); |
375 EXPECT_TRUE( | 375 EXPECT_TRUE( |
376 fake_invalidation_client_.GetRegisteredTypes().Equals(expected_types)); | 376 fake_invalidation_client_.GetRegisteredTypes().Equals(expected_types)); |
377 | 377 |
378 ExpectPendingRegistrations( | 378 ExpectPendingRegistrations( |
379 types, 0.0, | 379 types, 0.0, |
380 fake_registration_manager_.GetPendingRegistrations()); | 380 fake_registration_manager_.GetPendingRegistrations()); |
381 | 381 |
382 // Trigger another failure to start delaying. | 382 // Trigger another failure to start delaying. |
383 fake_registration_manager_.FirePendingRegistrationsForTest(); | 383 fake_registration_manager_.FirePendingRegistrationsForTest(); |
384 fake_invalidation_client_.LoseAllRegistrations(); | 384 fake_invalidation_client_.LoseAllRegistrations(); |
385 fake_registration_manager_.MarkAllRegistrationsLost(); | 385 fake_registration_manager_.MarkAllRegistrationsLost(); |
386 double expected_delay = | 386 double expected_delay = |
387 RegistrationManager::kInitialRegistrationDelaySeconds; | 387 RegistrationManager::kInitialRegistrationDelaySeconds; |
388 ExpectPendingRegistrations( | 388 ExpectPendingRegistrations( |
389 types, expected_delay, | 389 types, expected_delay, |
390 fake_registration_manager_.GetPendingRegistrations()); | 390 fake_registration_manager_.GetPendingRegistrations()); |
391 | 391 |
392 // Pretend we waited long enough to re-register. | 392 // Pretend we waited long enough to re-register. |
393 fake_registration_manager_.FirePendingRegistrationsForTest(); | 393 fake_registration_manager_.FirePendingRegistrationsForTest(); |
394 EXPECT_TRUE( | 394 EXPECT_TRUE( |
395 fake_registration_manager_.GetRegisteredTypes().Equals(types)); | 395 fake_registration_manager_.GetRegisteredTypes().Equals(types)); |
396 EXPECT_TRUE( | 396 EXPECT_TRUE( |
397 fake_invalidation_client_.GetRegisteredTypes().Equals(types)); | 397 fake_invalidation_client_.GetRegisteredTypes().Equals(types)); |
398 } | 398 } |
399 | 399 |
400 TEST_F(RegistrationManagerTest, DisableType) { | 400 TEST_F(RegistrationManagerTest, DisableType) { |
401 syncable::ModelEnumSet types = FromPtr(kModelTypes, kModelTypeCount); | 401 syncable::ModelTypeSet types = FromPtr(kModelTypes, kModelTypeCount); |
402 | 402 |
403 fake_registration_manager_.SetRegisteredTypes(types); | 403 fake_registration_manager_.SetRegisteredTypes(types); |
404 EXPECT_TRUE(fake_registration_manager_.GetPendingRegistrations().empty()); | 404 EXPECT_TRUE(fake_registration_manager_.GetPendingRegistrations().empty()); |
405 | 405 |
406 // Disable some types. | 406 // Disable some types. |
407 syncable::ModelEnumSet disabled_types = FromPtr( | 407 syncable::ModelTypeSet disabled_types = FromPtr( |
408 kModelTypes, 3); | 408 kModelTypes, 3); |
409 syncable::ModelEnumSet enabled_types = FromPtr( | 409 syncable::ModelTypeSet enabled_types = FromPtr( |
410 kModelTypes + 3, kModelTypeCount - 3); | 410 kModelTypes + 3, kModelTypeCount - 3); |
411 DisableTypes(disabled_types); | 411 DisableTypes(disabled_types); |
412 ExpectPendingRegistrations( | 412 ExpectPendingRegistrations( |
413 syncable::ModelEnumSet(), 0.0, | 413 syncable::ModelTypeSet(), 0.0, |
414 fake_registration_manager_.GetPendingRegistrations()); | 414 fake_registration_manager_.GetPendingRegistrations()); |
415 EXPECT_TRUE( | 415 EXPECT_TRUE( |
416 fake_registration_manager_.GetRegisteredTypes().Equals(enabled_types)); | 416 fake_registration_manager_.GetRegisteredTypes().Equals(enabled_types)); |
417 EXPECT_TRUE( | 417 EXPECT_TRUE( |
418 fake_invalidation_client_.GetRegisteredTypes().Equals(enabled_types)); | 418 fake_invalidation_client_.GetRegisteredTypes().Equals(enabled_types)); |
419 | 419 |
420 fake_registration_manager_.SetRegisteredTypes(types); | 420 fake_registration_manager_.SetRegisteredTypes(types); |
421 EXPECT_TRUE( | 421 EXPECT_TRUE( |
422 fake_registration_manager_.GetRegisteredTypes().Equals(enabled_types)); | 422 fake_registration_manager_.GetRegisteredTypes().Equals(enabled_types)); |
423 | 423 |
424 fake_registration_manager_.MarkRegistrationLost( | 424 fake_registration_manager_.MarkRegistrationLost( |
425 disabled_types.First().Get()); | 425 disabled_types.First().Get()); |
426 ExpectPendingRegistrations( | 426 ExpectPendingRegistrations( |
427 syncable::ModelEnumSet(), 0.0, | 427 syncable::ModelTypeSet(), 0.0, |
428 fake_registration_manager_.GetPendingRegistrations()); | 428 fake_registration_manager_.GetPendingRegistrations()); |
429 | 429 |
430 fake_registration_manager_.MarkAllRegistrationsLost(); | 430 fake_registration_manager_.MarkAllRegistrationsLost(); |
431 ExpectPendingRegistrations( | 431 ExpectPendingRegistrations( |
432 enabled_types, 0.0, | 432 enabled_types, 0.0, |
433 fake_registration_manager_.GetPendingRegistrations()); | 433 fake_registration_manager_.GetPendingRegistrations()); |
434 } | 434 } |
435 | 435 |
436 } // namespace | 436 } // namespace |
437 } // namespace notifier | 437 } // namespace notifier |
OLD | NEW |