| Index: content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
 | 
| diff --git a/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc b/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..cdfe5a90edf4f65f54f4bdb5018dc604b40487e1
 | 
| --- /dev/null
 | 
| +++ b/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
 | 
| @@ -0,0 +1,414 @@
 | 
| +// Copyright 2017 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "content/browser/service_worker/service_worker_data_pipe_reader.h"
 | 
| +
 | 
| +#include "base/run_loop.h"
 | 
| +#include "content/browser/service_worker/embedded_worker_test_helper.h"
 | 
| +#include "content/browser/service_worker/service_worker_context_core.h"
 | 
| +#include "content/browser/service_worker/service_worker_context_wrapper.h"
 | 
| +#include "content/browser/service_worker/service_worker_registration.h"
 | 
| +#include "content/browser/service_worker/service_worker_url_request_job.h"
 | 
| +#include "content/browser/service_worker/service_worker_version.h"
 | 
| +#include "content/public/test/test_browser_thread_bundle.h"
 | 
| +#include "net/base/io_buffer.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +
 | 
| +namespace content {
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +const char kTestData[] = "Here is sample text for the blob.";
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +class MockServiceWorkerURLRequestJob : public ServiceWorkerURLRequestJob {
 | 
| + public:
 | 
| +  explicit MockServiceWorkerURLRequestJob(
 | 
| +      ServiceWorkerURLRequestJob::Delegate* delegate)
 | 
| +      : ServiceWorkerURLRequestJob(nullptr,
 | 
| +                                   nullptr,
 | 
| +                                   "",
 | 
| +                                   nullptr,
 | 
| +                                   nullptr,
 | 
| +                                   FETCH_REQUEST_MODE_NO_CORS,
 | 
| +                                   FETCH_CREDENTIALS_MODE_OMIT,
 | 
| +                                   FetchRedirectMode::FOLLOW_MODE,
 | 
| +                                   RESOURCE_TYPE_MAIN_FRAME,
 | 
| +                                   REQUEST_CONTEXT_TYPE_HYPERLINK,
 | 
| +                                   REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
 | 
| +                                   scoped_refptr<ResourceRequestBodyImpl>(),
 | 
| +                                   ServiceWorkerFetchType::FETCH,
 | 
| +                                   base::Optional<base::TimeDelta>(),
 | 
| +                                   delegate),
 | 
| +        is_response_started_(false) {}
 | 
| +
 | 
| +  void OnResponseStarted() override { is_response_started_ = true; }
 | 
| +
 | 
| +  void OnReadRawDataComplete(int bytes_read) override {
 | 
| +    async_read_bytes_.push_back(bytes_read);
 | 
| +  }
 | 
| +
 | 
| +  void RecordResult(ServiceWorkerMetrics::URLRequestJobResult result) override {
 | 
| +    results_.push_back(result);
 | 
| +  }
 | 
| +
 | 
| +  bool is_response_started() { return is_response_started_; }
 | 
| +  const std::vector<int>& async_read_bytes() { return async_read_bytes_; }
 | 
| +  const std::vector<ServiceWorkerMetrics::URLRequestJobResult>& results() {
 | 
| +    return results_;
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  bool is_response_started_;
 | 
| +  std::vector<int> async_read_bytes_;
 | 
| +  std::vector<ServiceWorkerMetrics::URLRequestJobResult> results_;
 | 
| +};
 | 
| +
 | 
| +class ServiceWorkerDataPipeReaderTest
 | 
| +    : public testing::Test,
 | 
| +      public ServiceWorkerURLRequestJob::Delegate {
 | 
| + public:
 | 
| +  ServiceWorkerDataPipeReaderTest()
 | 
| +      : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
 | 
| +
 | 
| +  void SetUp() override {
 | 
| +    helper_ = base::MakeUnique<EmbeddedWorkerTestHelper>(base::FilePath());
 | 
| +    mock_url_request_job_ =
 | 
| +        base::MakeUnique<MockServiceWorkerURLRequestJob>(this);
 | 
| +    registration_ = new ServiceWorkerRegistration(
 | 
| +        GURL("https://example.com/"), 1L, helper_->context()->AsWeakPtr());
 | 
| +    version_ = new ServiceWorkerVersion(
 | 
| +        registration_.get(), GURL("https://example.com/service_worker.js"), 1L,
 | 
| +        helper_->context()->AsWeakPtr());
 | 
| +    std::vector<ServiceWorkerDatabase::ResourceRecord> records;
 | 
| +    records.push_back(
 | 
| +        ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100));
 | 
| +    version_->script_cache_map()->SetResources(records);
 | 
| +    version_->set_fetch_handler_existence(
 | 
| +        ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
 | 
| +  }
 | 
| +
 | 
| +  std::unique_ptr<ServiceWorkerDataPipeReader> CreateTargetDataPipeReader(
 | 
| +      blink::mojom::ServiceWorkerStreamCallbackPtr* stream_callback,
 | 
| +      mojo::DataPipe* data_pipe) {
 | 
| +    blink::mojom::ServiceWorkerStreamHandlePtr stream_handle =
 | 
| +        blink::mojom::ServiceWorkerStreamHandle::New();
 | 
| +    stream_handle->stream = std::move(data_pipe->consumer_handle);
 | 
| +    stream_handle->callback_request = mojo::MakeRequest(stream_callback);
 | 
| +    return base::MakeUnique<ServiceWorkerDataPipeReader>(
 | 
| +        mock_url_request_job_.get(), version_, std::move(stream_handle));
 | 
| +  }
 | 
| +
 | 
| +  // Implements ServiceWorkerURLRequestJob::Delegate.
 | 
| +  void OnPrepareToRestart() override { NOTREACHED(); }
 | 
| +
 | 
| +  ServiceWorkerVersion* GetServiceWorkerVersion(
 | 
| +      ServiceWorkerMetrics::URLRequestJobResult*) override {
 | 
| +    NOTREACHED();
 | 
| +    return nullptr;
 | 
| +  }
 | 
| +
 | 
| +  bool RequestStillValid(ServiceWorkerMetrics::URLRequestJobResult*) override {
 | 
| +    NOTREACHED();
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  void TearDown() override { helper_.reset(); }
 | 
| +
 | 
| +  MockServiceWorkerURLRequestJob* mock_url_request_job() {
 | 
| +    return mock_url_request_job_.get();
 | 
| +  }
 | 
| +
 | 
| + protected:
 | 
| +  TestBrowserThreadBundle thread_bundle_;
 | 
| +
 | 
| +  std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
 | 
| +  std::unique_ptr<MockServiceWorkerURLRequestJob> mock_url_request_job_;
 | 
| +  scoped_refptr<ServiceWorkerRegistration> registration_;
 | 
| +  scoped_refptr<ServiceWorkerVersion> version_;
 | 
| +};
 | 
| +
 | 
| +class ServiceWorkerDataPipeReaderTestP
 | 
| +    : public ServiceWorkerDataPipeReaderTest,
 | 
| +      public testing::WithParamInterface<
 | 
| +          std::tuple<bool /* should_close_connection_first */,
 | 
| +                     bool /* has_body */>> {
 | 
| + public:
 | 
| +  ServiceWorkerDataPipeReaderTestP() {}
 | 
| +  virtual ~ServiceWorkerDataPipeReaderTestP() {}
 | 
| +
 | 
| + protected:
 | 
| +  bool should_close_connection_first() const { return std::get<0>(GetParam()); }
 | 
| +  bool has_body() const { return std::get<1>(GetParam()); }
 | 
| +};
 | 
| +
 | 
| +TEST_P(ServiceWorkerDataPipeReaderTestP, SyncRead) {
 | 
| +  blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
 | 
| +  mojo::DataPipe data_pipe;
 | 
| +  std::unique_ptr<ServiceWorkerDataPipeReader> data_pipe_reader =
 | 
| +      CreateTargetDataPipeReader(&stream_callback, &data_pipe);
 | 
| +
 | 
| +  // Push enough data.
 | 
| +  if (has_body()) {
 | 
| +    std::string expected_response;
 | 
| +    expected_response.reserve((sizeof(kTestData) - 1) * 1024);
 | 
| +    for (int i = 0; i < 1024; ++i) {
 | 
| +      expected_response += kTestData;
 | 
| +      uint32_t written_bytes = sizeof(kTestData) - 1;
 | 
| +      MojoResult result =
 | 
| +          mojo::WriteDataRaw(data_pipe.producer_handle.get(), kTestData,
 | 
| +                             &written_bytes, MOJO_WRITE_DATA_FLAG_NONE);
 | 
| +      ASSERT_EQ(MOJO_RESULT_OK, result);
 | 
| +      EXPECT_EQ(sizeof(kTestData) - 1, written_bytes);
 | 
| +    }
 | 
| +  }
 | 
| +  data_pipe.producer_handle.reset();
 | 
| +  stream_callback->OnCompleted();
 | 
| +  base::RunLoop().RunUntilIdle();
 | 
| +
 | 
| +  // Nothing has started.
 | 
| +  EXPECT_FALSE(mock_url_request_job()->is_response_started());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->results().size());
 | 
| +
 | 
| +  // Start to read.
 | 
| +  data_pipe_reader->Start();
 | 
| +  EXPECT_TRUE(mock_url_request_job()->is_response_started());
 | 
| +  const int buffer_size = sizeof(kTestData);
 | 
| +  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(buffer_size);
 | 
| +  buffer->data()[buffer_size - 1] = '\0';
 | 
| +
 | 
| +  // Read successfully.
 | 
| +  if (has_body()) {
 | 
| +    std::string retrieved_response;
 | 
| +    retrieved_response.reserve(buffer_size * 1024);
 | 
| +    for (int i = 0; i < 1024; ++i) {
 | 
| +      EXPECT_EQ(buffer_size - 1,
 | 
| +                data_pipe_reader->ReadRawData(buffer.get(), buffer_size - 1));
 | 
| +      EXPECT_STREQ(kTestData, buffer->data());
 | 
| +      retrieved_response += buffer->data();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // Finish successfully.
 | 
| +  EXPECT_EQ(net::OK,
 | 
| +            data_pipe_reader->ReadRawData(buffer.get(), buffer_size - 1));
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->async_read_bytes().size());
 | 
| +  ASSERT_EQ(1UL, mock_url_request_job()->results().size());
 | 
| +  EXPECT_EQ(ServiceWorkerMetrics::REQUEST_JOB_STREAM_RESPONSE,
 | 
| +            mock_url_request_job()->results()[0]);
 | 
| +}
 | 
| +
 | 
| +TEST_P(ServiceWorkerDataPipeReaderTestP, SyncAbort) {
 | 
| +  blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
 | 
| +  mojo::DataPipe data_pipe;
 | 
| +  std::unique_ptr<ServiceWorkerDataPipeReader> data_pipe_reader =
 | 
| +      CreateTargetDataPipeReader(&stream_callback, &data_pipe);
 | 
| +
 | 
| +  // Push enough data.
 | 
| +  if (has_body()) {
 | 
| +    std::string expected_response;
 | 
| +    expected_response.reserve((sizeof(kTestData) - 1) * 1024);
 | 
| +    for (int i = 0; i < 1024; ++i) {
 | 
| +      expected_response += kTestData;
 | 
| +      uint32_t written_bytes = sizeof(kTestData) - 1;
 | 
| +      MojoResult result =
 | 
| +          mojo::WriteDataRaw(data_pipe.producer_handle.get(), kTestData,
 | 
| +                             &written_bytes, MOJO_WRITE_DATA_FLAG_NONE);
 | 
| +      ASSERT_EQ(MOJO_RESULT_OK, result);
 | 
| +      EXPECT_EQ(sizeof(kTestData) - 1, written_bytes);
 | 
| +    }
 | 
| +  }
 | 
| +  data_pipe.producer_handle.reset();
 | 
| +  stream_callback->OnAborted();
 | 
| +  base::RunLoop().RunUntilIdle();
 | 
| +
 | 
| +  // Nothing has started.
 | 
| +  EXPECT_FALSE(mock_url_request_job()->is_response_started());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->results().size());
 | 
| +
 | 
| +  // Start to read.
 | 
| +  data_pipe_reader->Start();
 | 
| +  EXPECT_TRUE(mock_url_request_job()->is_response_started());
 | 
| +  const int buffer_size = sizeof(kTestData);
 | 
| +  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(buffer_size);
 | 
| +  buffer->data()[buffer_size - 1] = '\0';
 | 
| +
 | 
| +  // Read successfully.
 | 
| +  if (has_body()) {
 | 
| +    std::string retrieved_response;
 | 
| +    retrieved_response.reserve(buffer_size * 1024);
 | 
| +    for (int i = 0; i < 1024; ++i) {
 | 
| +      EXPECT_EQ(buffer_size - 1,
 | 
| +                data_pipe_reader->ReadRawData(buffer.get(), buffer_size - 1));
 | 
| +      EXPECT_STREQ(kTestData, buffer->data());
 | 
| +      retrieved_response += buffer->data();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // Abort after all data has been read.
 | 
| +  EXPECT_EQ(net::ERR_CONNECTION_RESET,
 | 
| +            data_pipe_reader->ReadRawData(buffer.get(), buffer_size - 1));
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->async_read_bytes().size());
 | 
| +  ASSERT_EQ(1UL, mock_url_request_job()->results().size());
 | 
| +  EXPECT_EQ(ServiceWorkerMetrics::REQUEST_JOB_ERROR_STREAM_ABORTED,
 | 
| +            mock_url_request_job()->results()[0]);
 | 
| +}
 | 
| +
 | 
| +TEST_P(ServiceWorkerDataPipeReaderTestP, AsyncRead) {
 | 
| +  blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
 | 
| +  mojo::DataPipe data_pipe;
 | 
| +  std::unique_ptr<ServiceWorkerDataPipeReader> data_pipe_reader =
 | 
| +      CreateTargetDataPipeReader(&stream_callback, &data_pipe);
 | 
| +
 | 
| +  // Nothing has started.
 | 
| +  EXPECT_FALSE(mock_url_request_job()->is_response_started());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->results().size());
 | 
| +
 | 
| +  // Start to read.
 | 
| +  data_pipe_reader->Start();
 | 
| +  EXPECT_TRUE(mock_url_request_job()->is_response_started());
 | 
| +  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(sizeof(kTestData));
 | 
| +  buffer->data()[sizeof(kTestData) - 1] = '\0';
 | 
| +  std::string expected_response;
 | 
| +  std::string retrieved_response;
 | 
| +  expected_response.reserve((sizeof(kTestData) - 1) * 1024);
 | 
| +  retrieved_response.reserve((sizeof(kTestData) - 1) * 1024);
 | 
| +
 | 
| +  if (has_body()) {
 | 
| +    for (int i = 0; i < 1024; ++i) {
 | 
| +      // Data is not coming. It should be pending state.
 | 
| +      EXPECT_EQ(net::ERR_IO_PENDING, data_pipe_reader->ReadRawData(
 | 
| +                                         buffer.get(), sizeof(kTestData) - 1));
 | 
| +
 | 
| +      // Push a portion of data.
 | 
| +      uint32_t written_bytes = sizeof(kTestData) - 1;
 | 
| +      MojoResult result =
 | 
| +          mojo::WriteDataRaw(data_pipe.producer_handle.get(), kTestData,
 | 
| +                             &written_bytes, MOJO_WRITE_DATA_FLAG_NONE);
 | 
| +      ASSERT_EQ(MOJO_RESULT_OK, result);
 | 
| +      EXPECT_EQ(sizeof(kTestData) - 1, written_bytes);
 | 
| +      expected_response += kTestData;
 | 
| +      base::RunLoop().RunUntilIdle();
 | 
| +
 | 
| +      // Read the pushed data correctly.
 | 
| +      ASSERT_EQ(static_cast<size_t>(i + 1),
 | 
| +                mock_url_request_job()->async_read_bytes().size());
 | 
| +      EXPECT_EQ(static_cast<int>(sizeof(kTestData) - 1),
 | 
| +                mock_url_request_job()->async_read_bytes()[i]);
 | 
| +      EXPECT_STREQ(kTestData, buffer->data());
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // Data is not coming. It should be pending state.
 | 
| +  EXPECT_EQ(net::ERR_IO_PENDING,
 | 
| +            data_pipe_reader->ReadRawData(buffer.get(), sizeof(kTestData) - 1));
 | 
| +
 | 
| +  // Finish successfully when connection is closed AND OnCompleted is delivered.
 | 
| +  size_t num_read = mock_url_request_job()->async_read_bytes().size();
 | 
| +  if (should_close_connection_first()) {
 | 
| +    data_pipe.producer_handle.reset();
 | 
| +  } else {
 | 
| +    stream_callback->OnCompleted();
 | 
| +  }
 | 
| +  base::RunLoop().RunUntilIdle();
 | 
| +  EXPECT_EQ(num_read, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->results().size());
 | 
| +
 | 
| +  if (should_close_connection_first()) {
 | 
| +    stream_callback->OnCompleted();
 | 
| +  } else {
 | 
| +    data_pipe.producer_handle.reset();
 | 
| +  }
 | 
| +  base::RunLoop().RunUntilIdle();
 | 
| +  ASSERT_EQ(num_read + 1, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(net::OK, mock_url_request_job()->async_read_bytes().back());
 | 
| +  ASSERT_EQ(1UL, mock_url_request_job()->results().size());
 | 
| +  EXPECT_EQ(ServiceWorkerMetrics::REQUEST_JOB_STREAM_RESPONSE,
 | 
| +            mock_url_request_job()->results()[0]);
 | 
| +}
 | 
| +
 | 
| +TEST_P(ServiceWorkerDataPipeReaderTestP, AsyncAbort) {
 | 
| +  blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
 | 
| +  mojo::DataPipe data_pipe;
 | 
| +  std::unique_ptr<ServiceWorkerDataPipeReader> data_pipe_reader =
 | 
| +      CreateTargetDataPipeReader(&stream_callback, &data_pipe);
 | 
| +
 | 
| +  // Nothing has started.
 | 
| +  EXPECT_FALSE(mock_url_request_job()->is_response_started());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->results().size());
 | 
| +
 | 
| +  // Start to read.
 | 
| +  data_pipe_reader->Start();
 | 
| +  EXPECT_TRUE(mock_url_request_job()->is_response_started());
 | 
| +  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(sizeof(kTestData));
 | 
| +  buffer->data()[sizeof(kTestData) - 1] = '\0';
 | 
| +  std::string expected_response;
 | 
| +  std::string retrieved_response;
 | 
| +  expected_response.reserve((sizeof(kTestData) - 1) * 1024);
 | 
| +  retrieved_response.reserve((sizeof(kTestData) - 1) * 1024);
 | 
| +
 | 
| +  if (has_body()) {
 | 
| +    for (int i = 0; i < 1024; ++i) {
 | 
| +      // Data is not coming. It should be pending state.
 | 
| +      EXPECT_EQ(net::ERR_IO_PENDING, data_pipe_reader->ReadRawData(
 | 
| +                                         buffer.get(), sizeof(kTestData) - 1));
 | 
| +
 | 
| +      // Push a portion of data.
 | 
| +      uint32_t written_bytes = sizeof(kTestData) - 1;
 | 
| +      MojoResult result =
 | 
| +          mojo::WriteDataRaw(data_pipe.producer_handle.get(), kTestData,
 | 
| +                             &written_bytes, MOJO_WRITE_DATA_FLAG_NONE);
 | 
| +      ASSERT_EQ(MOJO_RESULT_OK, result);
 | 
| +      EXPECT_EQ(sizeof(kTestData) - 1, written_bytes);
 | 
| +      expected_response += kTestData;
 | 
| +      base::RunLoop().RunUntilIdle();
 | 
| +
 | 
| +      // Read the pushed data correctly.
 | 
| +      ASSERT_EQ(static_cast<size_t>(i + 1),
 | 
| +                mock_url_request_job()->async_read_bytes().size());
 | 
| +      EXPECT_EQ(static_cast<int>(sizeof(kTestData) - 1),
 | 
| +                mock_url_request_job()->async_read_bytes()[i]);
 | 
| +      EXPECT_STREQ(kTestData, buffer->data());
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // Data is not coming. It should be pending state.
 | 
| +  EXPECT_EQ(net::ERR_IO_PENDING,
 | 
| +            data_pipe_reader->ReadRawData(buffer.get(), sizeof(kTestData) - 1));
 | 
| +
 | 
| +  // Abort when connection is closed AND OnAborted is delivered.
 | 
| +  size_t num_read = mock_url_request_job()->async_read_bytes().size();
 | 
| +  if (should_close_connection_first()) {
 | 
| +    data_pipe.producer_handle.reset();
 | 
| +  } else {
 | 
| +    stream_callback->OnAborted();
 | 
| +  }
 | 
| +  base::RunLoop().RunUntilIdle();
 | 
| +  EXPECT_EQ(num_read, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(0UL, mock_url_request_job()->results().size());
 | 
| +
 | 
| +  if (should_close_connection_first()) {
 | 
| +    stream_callback->OnAborted();
 | 
| +  } else {
 | 
| +    data_pipe.producer_handle.reset();
 | 
| +  }
 | 
| +  base::RunLoop().RunUntilIdle();
 | 
| +  ASSERT_EQ(num_read + 1, mock_url_request_job()->async_read_bytes().size());
 | 
| +  EXPECT_EQ(net::ERR_CONNECTION_RESET,
 | 
| +            mock_url_request_job()->async_read_bytes().back());
 | 
| +  ASSERT_EQ(1UL, mock_url_request_job()->results().size());
 | 
| +  EXPECT_EQ(ServiceWorkerMetrics::REQUEST_JOB_ERROR_STREAM_ABORTED,
 | 
| +            mock_url_request_job()->results()[0]);
 | 
| +}
 | 
| +
 | 
| +INSTANTIATE_TEST_CASE_P(ServiceWorkerDataPipeReaderTest,
 | 
| +                        ServiceWorkerDataPipeReaderTestP,
 | 
| +                        testing::Combine(testing::Bool(), testing::Bool()));
 | 
| +
 | 
| +}  // namespace content
 | 
| 
 |