TEST_P(DedicatedWorkerTest, PendingActivity_SetIntervalOnMessageEvent) { // Start a repeated timer on a message event, and stop it when another // message is received. The timer needs a non-zero delay or else worker // activities would not run. const String sourceCode = "var count = 0;" "var id;" "addEventListener('message', function(event) {" " if (count++ == 0) {" " id = setInterval(function() {}, 50);" " } else {" " clearInterval(id);" " }" "});"; startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); EXPECT_FALSE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // The first message event sets the active timer that is counted as a // pending activity. dispatchMessageEvent(); EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed); EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // Run the message loop for a while to make sure the timer is counted as a // pending activity until it's stopped. The delay is equal to the max // interval so that the pending activity timer may be able to have a chance // to run before the next expectation check. const double kDelayInMs = kMaxIntervalInSec * 1000; testing::runDelayedTasks(kDelayInMs); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // Stop the timer. dispatchMessageEvent(); EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed); EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // There should be no pending activities after the timer is stopped. workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); EXPECT_FALSE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); }
TEST_P(DedicatedWorkerTest, PendingActivity_SetInterval) { // Start a repeated timer on initial script evaluation, and stop it when a // message is received. The timer needs a non-zero delay or else worker // activities would not run. const String sourceCode = "var id = setInterval(function() {}, 50);" "addEventListener('message', function(event) { clearInterval(id); });"; startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // Stop the timer. dispatchMessageEvent(); EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed); EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // There should be no pending activities after the timer is stopped. workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); EXPECT_FALSE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); }
TEST_P(DedicatedWorkerTest, PendingActivity_SetTimeoutOnMessageEvent) { // Start an oneshot timer on a message event. const String sourceCode = "addEventListener('message', function(event) {" " setTimeout(function() {}, 0);" "});"; startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); EXPECT_FALSE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // A message starts the oneshot timer that is counted as a pending activity. dispatchMessageEvent(); EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed); EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount()); EXPECT_TRUE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); // The timer is fired soon and there should be no pending activities after // that. workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); EXPECT_FALSE( workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity()); }
void EventSource::parseEventStreamLine(unsigned position, Optional<unsigned> fieldLength, unsigned lineLength) { if (!lineLength) { if (!m_data.isEmpty()) dispatchMessageEvent(); m_eventName = { }; return; } if (fieldLength && !fieldLength.value()) return; StringView field { &m_receiveBuffer[position], fieldLength ? fieldLength.value() : lineLength }; unsigned step; if (!fieldLength) step = lineLength; else if (m_receiveBuffer[position + fieldLength.value() + 1] != ' ') step = fieldLength.value() + 1; else step = fieldLength.value() + 2; position += step; unsigned valueLength = lineLength - step; if (field == "data") { m_data.append(&m_receiveBuffer[position], valueLength); m_data.append('\n'); } else if (field == "event") m_eventName = { &m_receiveBuffer[position], valueLength }; else if (field == "id") m_currentlyParsedEventId = { &m_receiveBuffer[position], valueLength }; else if (field == "retry") { if (!valueLength) m_reconnectDelay = defaultReconnectDelay; else { // FIXME: Do we really want to ignore trailing garbage here? Should we be using the strict version instead? // FIXME: If we can't parse the value, should we leave m_reconnectDelay alone or set it to defaultReconnectDelay? bool ok; auto reconnectDelay = charactersToUInt64(&m_receiveBuffer[position], valueLength, &ok); if (ok) m_reconnectDelay = reconnectDelay; } } }