text:
namespace content {

namespace {
const char kTestData[] = "Hello World";

// Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
// the memory.
storage::BlobProtocolHandler* CreateMockBlobProtocolHandler(
    storage::BlobStorageContext* blob_storage_context) {
  // The FileSystemContext and MessageLoopProxy are not actually used but a
  // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor.
  return new storage::BlobProtocolHandler(
      blob_storage_context, NULL, base::MessageLoopProxy::current().get());
}

// A disk_cache::Backend wrapper that can delay operations.
class DelayableBackend : public disk_cache::Backend {
 public:
  DelayableBackend(scoped_ptr<disk_cache::Backend> backend)
      : backend_(backend.Pass()), delay_open_(false) {}

  // disk_cache::Backend overrides
  net::CacheType GetCacheType() const override {
    return backend_->GetCacheType();
  }
  int32 GetEntryCount() const override { return backend_->GetEntryCount(); }
  int OpenEntry(const std::string& key,
                disk_cache::Entry** entry,
                const CompletionCallback& callback) override {
    if (delay_open_) {
      open_entry_callback_ =
          base::Bind(&DelayableBackend::OpenEntryDelayedImpl,
                     base::Unretained(this), key, entry, callback);
      return net::ERR_IO_PENDING;
    }

    return backend_->OpenEntry(key, entry, callback);
  }
  int CreateEntry(const std::string& key,
                  disk_cache::Entry** entry,
                  const CompletionCallback& callback) override {
    return backend_->CreateEntry(key, entry, callback);
  }
  int DoomEntry(const std::string& key,
                const CompletionCallback& callback) override {
    return backend_->DoomEntry(key, callback);
  }
  int DoomAllEntries(const CompletionCallback& callback) override {
    return backend_->DoomAllEntries(callback);
  }
  int DoomEntriesBetween(base::Time initial_time,
                         base::Time end_time,
                         const CompletionCallback& callback) override {
    return backend_->DoomEntriesBetween(initial_time, end_time, callback);
  }
  int DoomEntriesSince(base::Time initial_time,
                       const CompletionCallback& callback) override {
    return backend_->DoomEntriesSince(initial_time, callback);
  }
  scoped_ptr<Iterator> CreateIterator() override {
    return backend_->CreateIterator();
  }
  void GetStats(
      std::vector<std::pair<std::string, std::string>>* stats) override {
    return backend_->GetStats(stats);
  }
  void OnExternalCacheHit(const std::string& key) override {
    return backend_->OnExternalCacheHit(key);
  }

  // Call to continue a delayed open.
  void OpenEntryContinue() {
    EXPECT_FALSE(open_entry_callback_.is_null());
    open_entry_callback_.Run();
  }

  void set_delay_open(bool value) { delay_open_ = value; }

 private:
  void OpenEntryDelayedImpl(const std::string& key,
                            disk_cache::Entry** entry,
                            const CompletionCallback& callback) {
    int rv = backend_->OpenEntry(key, entry, callback);
    if (rv != net::ERR_IO_PENDING)
      callback.Run(rv);
  }

  scoped_ptr<disk_cache::Backend> backend_;
  bool delay_open_;
  base::Closure open_entry_callback_;
};

}  // namespace

// A CacheStorageCache that can optionally delay during backend creation.
class TestCacheStorageCache : public CacheStorageCache {
 public:
  TestCacheStorageCache(
      const GURL& origin,
      const base::FilePath& path,
      net::URLRequestContext* request_context,
      const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
      base::WeakPtr<storage::BlobStorageContext> blob_context)
      : CacheStorageCache(origin,
                          path,
                          request_context,
                          quota_manager_proxy,
                          blob_context),
        delay_backend_creation_(false) {}

  void CreateBackend(const ErrorCallback& callback) override {
    backend_creation_callback_ = callback;
    if (delay_backend_creation_)
      return;
    ContinueCreateBackend();
  }

  void ContinueCreateBackend() {
    CacheStorageCache::CreateBackend(backend_creation_callback_);
  }

  void set_delay_backend_creation(bool delay) {
    delay_backend_creation_ = delay;
  }

  // Swap the existing backend with a delayable one. The backend must have been
  // created before calling this.
  DelayableBackend* UseDelayableBackend() {
    EXPECT_TRUE(backend_);
    DelayableBackend* delayable_backend = new DelayableBackend(backend_.Pass());
    backend_.reset(delayable_backend);
    return delayable_backend;
  }

 private:
  ~TestCacheStorageCache() override {}

  bool delay_backend_creation_;
  ErrorCallback backend_creation_callback_;

  DISALLOW_COPY_AND_ASSIGN(TestCacheStorageCache);
};

class CacheStorageCacheTest : public testing::Test {
 public:
  CacheStorageCacheTest()
      : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
        callback_error_(CacheStorageCache::ERROR_TYPE_OK),
        callback_closed_(false) {}

  void SetUp() override {
    ChromeBlobStorageContext* blob_storage_context =
        ChromeBlobStorageContext::GetFor(&browser_context_);
    // Wait for chrome_blob_storage_context to finish initializing.
    base::RunLoop().RunUntilIdle();
    blob_storage_context_ = blob_storage_context->context();

    quota_manager_proxy_ = new MockQuotaManagerProxy(
        nullptr, base::MessageLoopProxy::current().get());

    url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl);
    url_request_job_factory_->SetProtocolHandler(
        "blob", CreateMockBlobProtocolHandler(blob_storage_context->context()));

    net::URLRequestContext* url_request_context =
        browser_context_.GetRequestContext()->GetURLRequestContext();

    url_request_context->set_job_factory(url_request_job_factory_.get());

    CreateRequests(blob_storage_context);

    if (!MemoryOnly())
      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    base::FilePath path = MemoryOnly() ? base::FilePath() : temp_dir_.path();

    cache_ = make_scoped_refptr(new TestCacheStorageCache(
        GURL("http://example.com"), path, url_request_context,
        quota_manager_proxy_, blob_storage_context->context()->AsWeakPtr()));
  }

  void TearDown() override {
    quota_manager_proxy_->SimulateQuotaManagerDestroyed();
    base::RunLoop().RunUntilIdle();
  }

  void CreateRequests(ChromeBlobStorageContext* blob_storage_context) {
    ServiceWorkerHeaderMap headers;
    headers.insert(std::make_pair("a", "a"));
    headers.insert(std::make_pair("b", "b"));
    body_request_ =
        ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET",
                                  headers, Referrer(), false);
    no_body_request_ =
        ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
                                  "GET", headers, Referrer(), false);

    std::string expected_response;
    for (int i = 0; i < 100; ++i)
      expected_blob_data_ += kTestData;

    scoped_ptr<storage::BlobDataBuilder> blob_data(
        new storage::BlobDataBuilder("blob-id:myblob"));
    blob_data->AppendData(expected_blob_data_);

    blob_handle_ =
        blob_storage_context->context()->AddFinishedBlob(blob_data.get());

    body_response_ = ServiceWorkerResponse(
        GURL("http://example.com/body.html"), 200, "OK",
        blink::WebServiceWorkerResponseTypeDefault, headers,
        blob_handle_->uuid(), expected_blob_data_.size(), GURL());

    no_body_response_ = ServiceWorkerResponse(
        GURL("http://example.com/no_body.html"), 200, "OK",
        blink::WebServiceWorkerResponseTypeDefault, headers, "", 0, GURL());
  }

  scoped_ptr<ServiceWorkerFetchRequest> CopyFetchRequest(
      const ServiceWorkerFetchRequest& request) {
    return make_scoped_ptr(new ServiceWorkerFetchRequest(
        request.url, request.method, request.headers, request.referrer,
        request.is_reload));
  }

  scoped_ptr<ServiceWorkerResponse> CopyFetchResponse(
      const ServiceWorkerResponse& response) {
    scoped_ptr<ServiceWorkerResponse> sw_response(new ServiceWorkerResponse(
        response.url, response.status_code, response.status_text,
        response.response_type, response.headers, response.blob_uuid,
        response.blob_size, response.stream_url));
    return sw_response.Pass();
  }

  bool Put(const ServiceWorkerFetchRequest& request,
           const ServiceWorkerResponse& response) {
    scoped_ptr<base::RunLoop> loop(new base::RunLoop());

    cache_->Put(
        CopyFetchRequest(request), CopyFetchResponse(response),
        base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback,
                   base::Unretained(this), base::Unretained(loop.get())));
    // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
    // once the cache uses a passed in MessageLoopProxy instead of the CACHE
    // thread.
    loop->Run();

    return callback_error_ == CacheStorageCache::ERROR_TYPE_OK;
  }

  bool Match(const ServiceWorkerFetchRequest& request) {
    scoped_ptr<base::RunLoop> loop(new base::RunLoop());

    cache_->Match(
        CopyFetchRequest(request),
        base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback,
                   base::Unretained(this), base::Unretained(loop.get())));
    loop->Run();

    return callback_error_ == CacheStorageCache::ERROR_TYPE_OK;
  }

  bool Delete(const ServiceWorkerFetchRequest& request) {
    scoped_ptr<base::RunLoop> loop(new base::RunLoop());

    cache_->Delete(
        CopyFetchRequest(request),
        base::Bind(&CacheStorageCacheTest::ErrorTypeCallback,
                   base::Unretained(this), base::Unretained(loop.get())));
    loop->Run();

    return callback_error_ == CacheStorageCache::ERROR_TYPE_OK;
  }

  bool Keys() {
    scoped_ptr<base::RunLoop> loop(new base::RunLoop());

    cache_->Keys(base::Bind(&CacheStorageCacheTest::RequestsCallback,
                            base::Unretained(this),
                            base::Unretained(loop.get())));
    loop->Run();

    return callback_error_ == CacheStorageCache::ERROR_TYPE_OK;
  }

  bool Close() {
    scoped_ptr<base::RunLoop> loop(new base::RunLoop());

    cache_->Close(base::Bind(&CacheStorageCacheTest::CloseCallback,
                             base::Unretained(this),
                             base::Unretained(loop.get())));
    loop->Run();
    return callback_closed_;
  }

  void RequestsCallback(base::RunLoop* run_loop,
                        CacheStorageCache::ErrorType error,
                        scoped_ptr<CacheStorageCache::Requests> requests) {
    callback_error_ = error;
    callback_strings_.clear();
    if (requests) {
      for (size_t i = 0u; i < requests->size(); ++i)
        callback_strings_.push_back(requests->at(i).url.spec());
    }
    if (run_loop)
      run_loop->Quit();
  }

  void ErrorTypeCallback(base::RunLoop* run_loop,
                         CacheStorageCache::ErrorType error) {
    callback_error_ = error;
    if (run_loop)
      run_loop->Quit();
  }

  void ResponseAndErrorCallback(
      base::RunLoop* run_loop,
      CacheStorageCache::ErrorType error,
      scoped_ptr<ServiceWorkerResponse> response,
      scoped_ptr<storage::BlobDataHandle> body_handle) {
    callback_error_ = error;
    callback_response_ = response.Pass();
    callback_response_data_.reset();
    if (error == CacheStorageCache::ERROR_TYPE_OK &&
        !callback_response_->blob_uuid.empty()) {
      callback_response_data_ = body_handle.Pass();
    }

    if (run_loop)
      run_loop->Quit();
  }

  void CloseCallback(base::RunLoop* run_loop) {
    EXPECT_FALSE(callback_closed_);
    callback_closed_ = true;
    if (run_loop)
      run_loop->Quit();
  }

  void CopyBody(storage::BlobDataHandle* blob_handle, std::string* output) {
    scoped_ptr<storage::BlobDataSnapshot> data = blob_handle->CreateSnapshot();
    const auto& items = data->items();
    for (const auto& item : items) {
      output->append(item->bytes(), item->length());
    }
  }

  bool VerifyKeys(const std::vector<std::string>& expected_keys) {
    if (expected_keys.size() != callback_strings_.size())
      return false;

    std::set<std::string> found_set;
    for (int i = 0, max = callback_strings_.size(); i < max; ++i)
      found_set.insert(callback_strings_[i]);

    for (int i = 0, max = expected_keys.size(); i < max; ++i) {
      if (found_set.find(expected_keys[i]) == found_set.end())
        return false;
    }
    return true;
  }

  bool TestResponseType(blink::WebServiceWorkerResponseType response_type) {
    body_response_.response_type = response_type;
    EXPECT_TRUE(Put(body_request_, body_response_));
    EXPECT_TRUE(Match(body_request_));
    EXPECT_TRUE(Delete(body_request_));
    return response_type == callback_response_->response_type;
  }

  void VerifyAllOpsFail() {
    EXPECT_FALSE(Put(no_body_request_, no_body_response_));
    EXPECT_FALSE(Match(no_body_request_));
    EXPECT_FALSE(Delete(body_request_));
    EXPECT_FALSE(Keys());
  }

  virtual bool MemoryOnly() { return false; }

 protected:
  TestBrowserContext browser_context_;
  TestBrowserThreadBundle browser_thread_bundle_;
  scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_;
  scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
  storage::BlobStorageContext* blob_storage_context_;

  base::ScopedTempDir temp_dir_;
  scoped_refptr<TestCacheStorageCache> cache_;

  ServiceWorkerFetchRequest body_request_;
  ServiceWorkerResponse body_response_;
  ServiceWorkerFetchRequest no_body_request_;
  ServiceWorkerResponse no_body_response_;
  scoped_ptr<storage::BlobDataHandle> blob_handle_;
  std::string expected_blob_data_;

  CacheStorageCache::ErrorType callback_error_;
  scoped_ptr<ServiceWorkerResponse> callback_response_;
  scoped_ptr<storage::BlobDataHandle> callback_response_data_;
  std::vector<std::string> callback_strings_;
  bool callback_closed_;
};

class CacheStorageCacheTestP : public CacheStorageCacheTest,
                               public testing::WithParamInterface<bool> {
  bool MemoryOnly() override { return !GetParam(); }
};

class CacheStorageCacheMemoryOnlyTest
    : public CacheStorageCacheTest,
      public testing::WithParamInterface<bool> {
  bool MemoryOnly() override { return true; }
};

TEST_P(CacheStorageCacheTestP, PutNoBody) {
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(callback_response_);
  EXPECT_STREQ(no_body_response_.url.spec().c_str(),
               callback_response_->url.spec().c_str());
  EXPECT_FALSE(callback_response_data_);
  EXPECT_STREQ("", callback_response_->blob_uuid.c_str());
  EXPECT_EQ(0u, callback_response_->blob_size);
}

TEST_P(CacheStorageCacheTestP, PutBody) {
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(callback_response_);
  EXPECT_STREQ(body_response_.url.spec().c_str(),
               callback_response_->url.spec().c_str());
  EXPECT_TRUE(callback_response_data_);
  EXPECT_STRNE("", callback_response_->blob_uuid.c_str());
  EXPECT_EQ(expected_blob_data_.size(), callback_response_->blob_size);

  std::string response_body;
  CopyBody(callback_response_data_.get(), &response_body);
  EXPECT_STREQ(expected_blob_data_.c_str(), response_body.c_str());
}

TEST_P(CacheStorageCacheTestP, ResponseURLDiffersFromRequestURL) {
  no_body_response_.url = GURL("http://example.com/foobar");
  EXPECT_STRNE("http://example.com/foobar",
               no_body_request_.url.spec().c_str());
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(Match(no_body_request_));
  EXPECT_STREQ("http://example.com/foobar",
               callback_response_->url.spec().c_str());
}

TEST_P(CacheStorageCacheTestP, ResponseURLEmpty) {
  no_body_response_.url = GURL();
  EXPECT_STRNE("", no_body_request_.url.spec().c_str());
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(Match(no_body_request_));
  EXPECT_STREQ("", callback_response_->url.spec().c_str());
}

TEST_F(CacheStorageCacheTest, PutBodyDropBlobRef) {
  scoped_ptr<base::RunLoop> loop(new base::RunLoop());
  cache_->Put(CopyFetchRequest(body_request_),
              CopyFetchResponse(body_response_),
              base::Bind(&CacheStorageCacheTestP::ResponseAndErrorCallback,
                         base::Unretained(this), base::Unretained(loop.get())));
  // The handle should be held by the cache now so the deref here should be
  // okay.
  blob_handle_.reset();
  loop->Run();

  EXPECT_EQ(CacheStorageCache::ERROR_TYPE_OK, callback_error_);
}

TEST_P(CacheStorageCacheTestP, PutReplace) {
  EXPECT_TRUE(Put(body_request_, no_body_response_));
  EXPECT_TRUE(Match(body_request_));
  EXPECT_FALSE(callback_response_data_);

  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));
  EXPECT_TRUE(callback_response_data_);

  EXPECT_TRUE(Put(body_request_, no_body_response_));
  EXPECT_TRUE(Match(body_request_));
  EXPECT_FALSE(callback_response_data_);
}

TEST_P(CacheStorageCacheTestP, MatchNoBody) {
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(Match(no_body_request_));
  EXPECT_EQ(200, callback_response_->status_code);
  EXPECT_STREQ("OK", callback_response_->status_text.c_str());
  EXPECT_STREQ("http://example.com/no_body.html",
               callback_response_->url.spec().c_str());
  EXPECT_STREQ("", callback_response_->blob_uuid.c_str());
  EXPECT_EQ(0u, callback_response_->blob_size);
}

TEST_P(CacheStorageCacheTestP, MatchBody) {
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));
  EXPECT_EQ(200, callback_response_->status_code);
  EXPECT_STREQ("OK", callback_response_->status_text.c_str());
  EXPECT_STREQ("http://example.com/body.html",
               callback_response_->url.spec().c_str());
  EXPECT_STRNE("", callback_response_->blob_uuid.c_str());
  EXPECT_EQ(expected_blob_data_.size(), callback_response_->blob_size);

  std::string response_body;
  CopyBody(callback_response_data_.get(), &response_body);
  EXPECT_STREQ(expected_blob_data_.c_str(), response_body.c_str());
}

TEST_P(CacheStorageCacheTestP, Vary) {
  body_request_.headers["vary_foo"] = "foo";
  body_response_.headers["vary"] = "vary_foo";
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));

  body_request_.headers["vary_foo"] = "bar";
  EXPECT_FALSE(Match(body_request_));

  body_request_.headers.erase("vary_foo");
  EXPECT_FALSE(Match(body_request_));
}

TEST_P(CacheStorageCacheTestP, EmptyVary) {
  body_response_.headers["vary"] = "";
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));

  body_request_.headers["zoo"] = "zoo";
  EXPECT_TRUE(Match(body_request_));
}

TEST_P(CacheStorageCacheTestP, NoVaryButDiffHeaders) {
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));

  body_request_.headers["zoo"] = "zoo";
  EXPECT_TRUE(Match(body_request_));
}

TEST_P(CacheStorageCacheTestP, VaryMultiple) {
  body_request_.headers["vary_foo"] = "foo";
  body_request_.headers["vary_bar"] = "bar";
  body_response_.headers["vary"] = " vary_foo    , vary_bar";
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));

  body_request_.headers["vary_bar"] = "foo";
  EXPECT_FALSE(Match(body_request_));

  body_request_.headers.erase("vary_bar");
  EXPECT_FALSE(Match(body_request_));
}

TEST_P(CacheStorageCacheTestP, VaryNewHeader) {
  body_request_.headers["vary_foo"] = "foo";
  body_response_.headers["vary"] = " vary_foo, vary_bar";
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));

  body_request_.headers["vary_bar"] = "bar";
  EXPECT_FALSE(Match(body_request_));
}

TEST_P(CacheStorageCacheTestP, VaryStar) {
  body_response_.headers["vary"] = "*";
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_FALSE(Match(body_request_));
}

TEST_P(CacheStorageCacheTestP, EmptyKeys) {
  EXPECT_TRUE(Keys());
  EXPECT_EQ(0u, callback_strings_.size());
}

TEST_P(CacheStorageCacheTestP, TwoKeys) {
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Keys());
  EXPECT_EQ(2u, callback_strings_.size());
  std::vector<std::string> expected_keys;
  expected_keys.push_back(no_body_request_.url.spec());
  expected_keys.push_back(body_request_.url.spec());
  EXPECT_TRUE(VerifyKeys(expected_keys));
}

TEST_P(CacheStorageCacheTestP, TwoKeysThenOne) {
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Keys());
  EXPECT_EQ(2u, callback_strings_.size());
  std::vector<std::string> expected_keys;
  expected_keys.push_back(no_body_request_.url.spec());
  expected_keys.push_back(body_request_.url.spec());
  EXPECT_TRUE(VerifyKeys(expected_keys));

  EXPECT_TRUE(Delete(body_request_));
  EXPECT_TRUE(Keys());
  EXPECT_EQ(1u, callback_strings_.size());
  std::vector<std::string> expected_key;
  expected_key.push_back(no_body_request_.url.spec());
  EXPECT_TRUE(VerifyKeys(expected_key));
}

TEST_P(CacheStorageCacheTestP, DeleteNoBody) {
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(Match(no_body_request_));
  EXPECT_TRUE(Delete(no_body_request_));
  EXPECT_FALSE(Match(no_body_request_));
  EXPECT_FALSE(Delete(no_body_request_));
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_TRUE(Match(no_body_request_));
  EXPECT_TRUE(Delete(no_body_request_));
}

TEST_P(CacheStorageCacheTestP, DeleteBody) {
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));
  EXPECT_TRUE(Delete(body_request_));
  EXPECT_FALSE(Match(body_request_));
  EXPECT_FALSE(Delete(body_request_));
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Match(body_request_));
  EXPECT_TRUE(Delete(body_request_));
}

TEST_P(CacheStorageCacheTestP, QuickStressNoBody) {
  for (int i = 0; i < 100; ++i) {
    EXPECT_FALSE(Match(no_body_request_));
    EXPECT_TRUE(Put(no_body_request_, no_body_response_));
    EXPECT_TRUE(Match(no_body_request_));
    EXPECT_TRUE(Delete(no_body_request_));
  }
}

TEST_P(CacheStorageCacheTestP, QuickStressBody) {
  for (int i = 0; i < 100; ++i) {
    ASSERT_FALSE(Match(body_request_));
    ASSERT_TRUE(Put(body_request_, body_response_));
    ASSERT_TRUE(Match(body_request_));
    ASSERT_TRUE(Delete(body_request_));
  }
}

TEST_P(CacheStorageCacheTestP, PutResponseType) {
  EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeBasic));
  EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeCORS));
  EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeDefault));
  EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeError));
  EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeOpaque));
}

TEST_F(CacheStorageCacheTest, CaselessServiceWorkerResponseHeaders) {
  // CacheStorageCache depends on ServiceWorkerResponse having caseless
  // headers so that it can quickly lookup vary headers.
  ServiceWorkerResponse response(GURL("http://www.example.com"), 200, "OK",
                                 blink::WebServiceWorkerResponseTypeDefault,
                                 ServiceWorkerHeaderMap(), "", 0, GURL());
  response.headers["content-type"] = "foo";
  response.headers["Content-Type"] = "bar";
  EXPECT_EQ("bar", response.headers["content-type"]);
}

TEST_F(CacheStorageCacheTest, CaselessServiceWorkerFetchRequestHeaders) {
  // CacheStorageCache depends on ServiceWorkerFetchRequest having caseless
  // headers so that it can quickly lookup vary headers.
  ServiceWorkerFetchRequest request(GURL("http://www.example.com"), "GET",
                                    ServiceWorkerHeaderMap(), Referrer(),
                                    false);
  request.headers["content-type"] = "foo";
  request.headers["Content-Type"] = "bar";
  EXPECT_EQ("bar", request.headers["content-type"]);
}

TEST_P(CacheStorageCacheTestP, QuotaManagerModified) {
  EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count());

  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_EQ(1, quota_manager_proxy_->notify_storage_modified_count());
  EXPECT_LT(0, quota_manager_proxy_->last_notified_delta());
  int64 sum_delta = quota_manager_proxy_->last_notified_delta();

  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_EQ(2, quota_manager_proxy_->notify_storage_modified_count());
  EXPECT_LT(sum_delta, quota_manager_proxy_->last_notified_delta());
  sum_delta += quota_manager_proxy_->last_notified_delta();

  EXPECT_TRUE(Delete(body_request_));
  EXPECT_EQ(3, quota_manager_proxy_->notify_storage_modified_count());
  sum_delta += quota_manager_proxy_->last_notified_delta();

  EXPECT_TRUE(Delete(no_body_request_));
  EXPECT_EQ(4, quota_manager_proxy_->notify_storage_modified_count());
  sum_delta += quota_manager_proxy_->last_notified_delta();

  EXPECT_EQ(0, sum_delta);
}

TEST_F(CacheStorageCacheMemoryOnlyTest, MemoryBackedSize) {
  EXPECT_EQ(0, cache_->MemoryBackedSize());
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_LT(0, cache_->MemoryBackedSize());
  int64 no_body_size = cache_->MemoryBackedSize();

  EXPECT_TRUE(Delete(no_body_request_));
  EXPECT_EQ(0, cache_->MemoryBackedSize());

  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_LT(no_body_size, cache_->MemoryBackedSize());

  EXPECT_TRUE(Delete(body_request_));
  EXPECT_EQ(0, cache_->MemoryBackedSize());
}

TEST_F(CacheStorageCacheTest, MemoryBackedSizePersistent) {
  EXPECT_EQ(0, cache_->MemoryBackedSize());
  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
  EXPECT_EQ(0, cache_->MemoryBackedSize());
}

TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackendNeverCreated) {
  cache_->set_delay_backend_creation(
      true);  // Will hang the test if a backend is created.
  EXPECT_TRUE(Close());
  VerifyAllOpsFail();
}

TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackend) {
  // Create the backend and put something in it.
  EXPECT_TRUE(Put(body_request_, body_response_));
  EXPECT_TRUE(Close());
  VerifyAllOpsFail();
}

TEST_P(CacheStorageCacheTestP, VerifySerialScheduling) {
  // Start two operations, the first one is delayed but the second isn't. The
  // second should wait for the first.
  EXPECT_TRUE(Keys());  // Opens the backend.
  DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
  delayable_backend->set_delay_open(true);

  scoped_ptr<ServiceWorkerResponse> response1 =
      CopyFetchResponse(body_response_);
  response1->status_code = 1;

  scoped_ptr<base::RunLoop> close_loop1(new base::RunLoop());
  cache_->Put(CopyFetchRequest(body_request_), response1.Pass(),
              base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback,
                         base::Unretained(this), close_loop1.get()));

  // Blocks on opening the cache entry.
  base::RunLoop().RunUntilIdle();

  delayable_backend->set_delay_open(false);
  scoped_ptr<ServiceWorkerResponse> response2 =
      CopyFetchResponse(body_response_);
  response2->status_code = 2;
  scoped_ptr<base::RunLoop> close_loop2(new base::RunLoop());
  cache_->Put(CopyFetchRequest(body_request_), response2.Pass(),
              base::Bind(&CacheStorageCacheTest::ResponseAndErrorCallback,
                         base::Unretained(this), close_loop2.get()));

  // The second put operation should wait for the first to complete.
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(callback_response_);

  delayable_backend->OpenEntryContinue();
  close_loop1->Run();
  EXPECT_EQ(1, callback_response_->status_code);
  close_loop2->Run();
  EXPECT_EQ(2, callback_response_->status_code);
}

INSTANTIATE_TEST_CASE_P(CacheStorageCacheTest,
                        CacheStorageCacheTestP,
                        ::testing::Values(false, true));

}  // namespace content


text:
package jtrade;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import jtrade.util.DateTimeRange;

import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.Months;
import org.joda.time.MutableDateTime;
import org.joda.time.ReadableDateTime;

public class SymbolFactory {
	public static List<Symbol> forex = new ArrayList<Symbol>();
	public static List<Symbol> futures = new ArrayList<Symbol>();
	public static Map<String, Symbol> symbols = new TreeMap<String, Symbol>();
	static {
		symbols.put("OMXS30-OMS-SEK-INDEX", new Symbol("OMXS30", "OMS", "SEK", "INDEX", 100, 0.25));
		symbols.put("SPX-CBOE-USD-INDEX", new Symbol("SPX-CBOE-USD-INDEX"));
		symbols.put("INDU-NYSE-USD-INDEX", new Symbol("INDU-NYSE-USD-INDEX"));
		symbols.put("COMP-NASDAQ-USD-INDEX", new Symbol("COMP-NASDAQ-USD-INDEX"));
		symbols.put("Z-LIFFE-GBP-INDEX", new Symbol("Z-LIFFE-GBP-INDEX"));
		symbols.put("DAX-DTB-EUR-INDEX", new Symbol("DAX-DTB-EUR-INDEX"));
		symbols.put("ESTX50-DTB-EUR-INDEX", new Symbol("ESTX50-DTB-EUR-INDEX"));
		symbols.put("CAC40-MONEP-EUR-INDEX", new Symbol("CAC40-MONEP-EUR-INDEX"));
		symbols.put("N225-OSE.JPN-JPY-INDEX", new Symbol("N225-OSE.JPN-JPY-INDEX"));
		symbols.put("VIX-CBOE-USD-INDEX", new Symbol("VIX-CBOE-USD-INDEX"));
		symbols.put("HSI-HKFE-HKD-INDEX", new Symbol("HSI-HKFE-HKD-INDEX"));

		futures.add(new Symbol("OMXS30", "OMS", "SEK", "FUTURE", 100, 0.25));
		futures.add(new Symbol("ES", "GLOBEX", "USD", "FUTURE", 50, 0.25));
		futures.add(new Symbol("Z", "LIFFE", "GBP", "FUTURE", 10, 0.5));
		futures.add(new Symbol("DAX", "DTB", "EUR", "FUTURE", 25, 0.5));
		futures.add(new Symbol("ESTX50", "DTB", "EUR", "FUTURE", 10, 1.0));
		futures.add(new Symbol("CAC40", "MONEP", "EUR", "FUTURE", 10, 0.5));
		futures.add(new Symbol("WTI", "IPE", "USD", "FUTURE", 1000, 0.01));
		futures.add(new Symbol("COIL", "IPE", "USD", "FUTURE", 100, 0.25));
		futures.add(new Symbol("GC", "NYMEX", "USD", "FUTURE", 100, 0.1));
		futures.add(new Symbol("CL", "NYMEX", "USD", "FUTURE", 1000, 0.01));
		for (Symbol f : futures) {
			symbols.put(f.getFullCode(), f);
		}
		for (Iterator<DateTime> dates = new DateTimeRange(new DateTime().withDayOfYear(1).minusYears(2), new DateTime().withDayOfYear(1).plusYears(2))
				.iterator(Months.ONE); dates.hasNext();) {
			DateTime dt = dates.next();
			for (Symbol f : futures) {
				Symbol s = getMostLiquidFutureSymbol(f, dt);
				symbols.put(s.getFullCode(), s);
			}
		}

		forex.add(new Symbol("EUR", "IDEALPRO", "USD", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "SGD", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "RUB", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "CZK", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "HUF", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "ILS", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "PLN", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "MXN", "CASH", 1, 0.0001));
		forex.add(new Symbol("USD", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "USD", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "GBP", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "AUD", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "SGD", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "RUB", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "CZK", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "HUF", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "ILS", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "PLN", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "MXN", "CASH", 1, 0.0001));
		forex.add(new Symbol("EUR", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "USD", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "NZD", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "AUD", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "MXN", "CASH", 1, 0.0001));
		forex.add(new Symbol("GBP", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
		forex.add(new Symbol("CAD", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
		forex.add(new Symbol("CAD", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
		forex.add(new Symbol("CAD", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
		forex.add(new Symbol("CAD", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "USD", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "NZD", "CASH", 1, 0.0001));
		forex.add(new Symbol("AUD", "IDEALPRO", "SGD", "CASH", 1, 0.0001));
		forex.add(new Symbol("CHF", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
		forex.add(new Symbol("CHF", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
		forex.add(new Symbol("CHF", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
		forex.add(new Symbol("CHF", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
		forex.add(new Symbol("CHF", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
		for (Symbol f : forex) {
			symbols.put(f.getFullCode(), f);
		}
	}

	public static List<Symbol> getFutures() {
		return new ArrayList<Symbol>(futures);
	}

	public static List<Symbol> getSymbols(List<String> symbols) {
		return getSymbols(symbols.toArray(new String[symbols.size()]));
	}

	public static List<Symbol> getSymbols(String... symbol) {
		List<Symbol> result = new ArrayList<Symbol>(symbol.length);
		for (String s : symbol) {
			result.add(getSymbol(s));
		}
		return result;
	}

	public static List<Symbol> getExchangeSymbols(String exchange) {
		List<Symbol> result = new ArrayList<Symbol>();
		for (Symbol s : symbols.values()) {
			if (s.getExchange().equals(exchange)) {
				result.add(s);
			}
		}
		return result;
	}

	public static Symbol getSymbol(String fullCode) {
		Symbol s = symbols.get(fullCode);
		if (s == null) {
			s = new Symbol(fullCode);
			symbols.put(fullCode, s);
		}
		return s;
	}

	public static Symbol getCash(String currency, String baseCurrency) {
		return getSymbol(new StringBuilder().append(currency).append("-IDEALPRO-").append(baseCurrency).append("-CASH").toString());
	}

	public static Symbol getSP500Index() {
		return symbols.get("SPX-CBOE-USD-INDEX");
	}

	public static Symbol getDowIndex() {
		return symbols.get("INDU-NYSE-USD-INDEX");
	}

	public static Symbol getNasdaqIndex() {
		return symbols.get("COMP-NASDAQ-USD-INDEX");
	}

	public static Symbol getNikkeiIndex() {
		return symbols.get("N225-OSE.JPN-JPY-INDEX");
	}

	public static Symbol getHangSengIndex() {
		return symbols.get("HSI-HKFE-HKD-INDEX");
	}

	public static Symbol getVixIndex() {
		return symbols.get("VIX-CBOE-USD-INDEX");
	}

	public static Symbol getDAXIndex() {
		return symbols.get("DAX-DTB-EUR-INDEX");
	}

	public static Symbol getESTX50Index() {
		return symbols.get("ESTX50-DTB-EUR-INDEX");
	}

	public static Symbol getFTSEIndex() {
		return symbols.get("Z-LIFFE-GBP-INDEX");
	}

	public static Symbol getOMXS30Index() {
		return symbols.get("OMXS30-OMS-SEK-INDEX");
	}

	public static Symbol getCAC40Index() {
		return symbols.get("CAC40-MONEP-EUR-INDEX");
	}

	public static Symbol getMostLiquidFutureSymbol(Symbol s, DateTime date) {
		if (!s.isFuture()) {
			return s;
		}
		if (s.getCode().equals("ES")) {
			return getESFutureSymbol(s, date);
		}
		if (s.getCode().equals("OMXS30")) {
			return getOMXFutureSymbol(s, date);
		}
		if (s.getCode().equals("DAX")) {
			return getDAXFutureSymbol(s, date);
		}
		if (s.getCode().equals("ESTX50")) {
			return getESTX50FutureSymbol(s, date);
		}
		if (s.getCode().equals("Z")) {
			return getZFutureSymbol(s, date);
		}
		if (s.getCode().equals("CAC40")) {
			return getCAC40FutureSymbol(s, date);
		}
		if (s.getCode().equals("VIX")) {
			return getVIXFutureSymbol(s, date);
		}
		if (s.getCode().equals("COIL")) {
			return getCOILFutureSymbol(s, date);
		}
		if (s.getCode().equals("WTI")) {
			return getWTIFutureSymbol(s, date);
		}
		if (s.getCode().equals("GC")) {
			return getGCFutureSymbol(s, date);
		}
		if (s.getCode().equals("CL")) {
			return getCLFutureSymbol(s, date);
		}
		if (s.getExchange().equals("OMX")) {
			return getOMXFutureSymbol(s, date);
		}
		if (s.getExchange().equals("ONE")) {
			return getONEFutureSymbol(s, date);
		}
		throw new IllegalArgumentException("Unsupported future: " + s.toString());
	}

	public static Symbol getOMXS30FutureSymbol(DateTime date) {
		return getOMXFutureSymbol(null, date);
	}

	public static Symbol getOMXS30FutureSymbol(Symbol s, DateTime date) {
		return getOMXFutureSymbol(s, date);
	}

	public static Symbol getOMXFutureSymbol(DateTime date) {
		return getOMXFutureSymbol(null, date);
	}

	public static Symbol getOMXFutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = null;
		if (date.isBefore(1208383200000L)) { // 2008-04-17
			expiryDate = getMostLiquidMonthlyExpiry(date, 2, 4);
			if (expiryDate.equals(new DateTime(2007, 6, 22, 0, 0, 0, 0))) {
				expiryDate = expiryDate.minusDays(1);
			}
		} else if (date.isBefore(1293836400000L)) { // 2011-01-01
			expiryDate = getMostLiquidMonthlyExpiry(date, 2, 3);
			// Strange hack for these dates
			if (expiryDate.equals(new DateTime(2008, 6, 20, 0, 0, 0, 0))) {
				expiryDate = expiryDate.minusDays(1);
			} else if (expiryDate.equals(new DateTime(2009, 1, 16, 0, 0, 0, 0))) {
				expiryDate = expiryDate.plusDays(7);
			} else if (expiryDate.equals(new DateTime(2009, 6, 19, 0, 0, 0, 0))) {
				expiryDate = expiryDate.minusDays(1);
			} else if (expiryDate.equals(new DateTime(2010, 1, 15, 0, 0, 0, 0))) {
				expiryDate = expiryDate.plusDays(7);
			}
		} else if (date.isBefore(1371765600000L)) { // 2013-06-21
			expiryDate = getMostLiquidMonthlyExpiry(date, 2, 3);
			// Strange hack for these dates
			if (expiryDate.getMillis() == 1371765600000L) {
				expiryDate = expiryDate.minusDays(1);
			}
		} else {
			expiryDate = getMostLiquidMonthlyExpiry(date, 2, 3);
		}
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		// String code = "OMXS30" + (expiryDate.getYearOfCentury() % 10) +
		// (char)
		// (64 + expiryDate.getMonthOfYear());
		// return new Symbol(code, "OMS", "SEK", expiryDate);
		return new Symbol(s != null ? s.getCode() : "OMXS30", "OMS", "SEK", expiryDate, 100, 0.25);
	}

	public static Symbol getESFutureSymbol(DateTime date) {
		return getESFutureSymbol(null, date);
	}

	public static Symbol getESFutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("ES", "GLOBEX", "USD", expiryDate, 50, 0.25);
	}

	public static Symbol getDAXFutureSymbol(DateTime date) {
		return getDAXFutureSymbol(null, date);
	}

	public static Symbol getDAXFutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("DAX", "DTB", "EUR", getMostLiquidQuarterlyExpiry(date, 8), 25, 0.5);
	}

	public static Symbol getESTX50FutureSymbol(DateTime date) {
		return getESTX50FutureSymbol(null, date);
	}

	public static Symbol getESTX50FutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("ESTX50", "DTB", "EUR", getMostLiquidQuarterlyExpiry(date, 8), 10, 1.0);
	}

	public static Symbol getZFutureSymbol(DateTime date) {
		return getZFutureSymbol(null, date);
	}

	public static Symbol getZFutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("Z", "LIFFE", "GBP", expiryDate, 10, 0.5);
	}

	public static Symbol getCAC40FutureSymbol(DateTime date) {
		return getCAC40FutureSymbol(null, date);
	}

	public static Symbol getCAC40FutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidMonthlyExpiry(date, 7, 3);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("CAC40", "MONEP", "EUR", expiryDate, 10, 0.5);
	}

	public static Symbol getVIXFutureSymbol(DateTime date) {
		return getVIXFutureSymbol(null, date);
	}

	public static Symbol getVIXFutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidVIXMonthlyExpiry(date);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("VIX", "CFE", "USD", expiryDate, 1000, 0.05);
	}

	public static Symbol getCOILFutureSymbol(DateTime date) {
		return getCOILFutureSymbol(null, date);
	}

	public static Symbol getCOILFutureSymbol(Symbol s, DateTime date) {
		// Get 15th day preceding the first of the contract month
		MutableDateTime expiryDate = new MutableDateTime(date);
		expiryDate.setMillisOfDay(0);
		expiryDate.setMonthOfYear(expiryDate.getMonthOfYear() + (expiryDate.getMonthOfYear() < 12 ? 1 : 0));
		expiryDate.setDayOfMonth(1);
		expiryDate.addDays(-15);
		if (expiryDate.getDayOfWeek() == DateTimeConstants.SATURDAY) {
			expiryDate.addDays(-2);
		} else if (expiryDate.getDayOfWeek() == DateTimeConstants.SUNDAY) {
			expiryDate.addDays(-3);
		} else if (expiryDate.getDayOfWeek() == DateTimeConstants.MONDAY) {
			expiryDate.addDays(-3);
		} else {
			expiryDate.addDays(-1);
		}

		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("COIL", "IPE", "USD", expiryDate.toDateTime(), 1000, 0.01);
	}

	public static Symbol getWTIFutureSymbol(DateTime date) {
		return getWTIFutureSymbol(null, date);
	}

	public static Symbol getWTIFutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidMonthlyExpiry(date, 7, 3);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		s = symbols.get(s.getFullCode());
		return new Symbol("WTI", "IPE", "USD", expiryDate, 1000, 0.01);
	}

	public static Symbol getGCFutureSymbol(DateTime date) {
		return getGCFutureSymbol(null, date);
	}

	public static Symbol getGCFutureSymbol(Symbol s, DateTime date) {
		// Get the third last business day of the delivery month.
		MutableDateTime expiryDate = new MutableDateTime(date.dayOfMonth().withMaximumValue());
		expiryDate.setMillisOfDay(0);
		int d = 3;
		while (d > 1) {
			if (isBusinessDay(expiryDate)) {
				d--;
			}
			expiryDate.addDays(-1);
		}
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("GC", "NYMEX", "USD", expiryDate.toDateTime(), 100, 0.1);
	}

	public static Symbol getCLFutureSymbol(DateTime date) {
		return getCLFutureSymbol(null, date);
	}

	public static Symbol getCLFutureSymbol(Symbol s, DateTime date) {
		// Trading in the current delivery month shall cease on the third
		// business
		// day prior to the twenty-fifth calendar day of the
		// month preceding the delivery month.
		// If the twenty-fifth calendar day of the month is a non-business day,
		// trading shall cease on the third business day prior
		// to the last business day preceding the twenty-fifth calendar day.
		// In the event that the official Exchange holiday schedule changes
		// subsequent to the listing of a Crude Oil futures,
		// the originally listed expiration date shall remain in effect. In the
		// event that the originally listed expiration day is declared a
		// holiday,
		// expiration will move to the business day immediately prior.
		MutableDateTime expiryDate = new MutableDateTime(date);
		expiryDate.setMillisOfDay(0);
		if (expiryDate.getDayOfMonth() > 25) {
			expiryDate.addMonths(1);
		}
		expiryDate.setDayOfMonth(25);
		while (!isBusinessDay(expiryDate)) {
			expiryDate.addDays(-1);
		}
		int d = 3;
		while (d > 0) {
			if (isBusinessDay(expiryDate)) {
				d--;
			}
			expiryDate.addDays(-1);
		}
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol("CL", "NYMEX", "USD", expiryDate.toDateTime(), 1000, 0.01);
	}

	public static Symbol getONEFutureSymbol(DateTime date) {
		return getONEFutureSymbol(null, date);
	}

	public static Symbol getONEFutureSymbol(Symbol s, DateTime date) {
		DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
		if (s != null && expiryDate.equals(s.getExpiry())) {
			return s;
		}
		return new Symbol(s.getCode(), "ONE", "USD", expiryDate, 100, 0.01);
	}

	public static DateTime getMostLiquidQuarterlyExpiry() {
		return getMostLiquidQuarterlyExpiry(new DateTime(), 8);
	}

	public static DateTime getMostLiquidQuarterlyExpiry(DateTime date, int daysBeforeExpiry) {
		DateTime expiryDate = getQuarterlyExpiryDate(date);
		// Volume shifts to next month about x days before expiry
		DateTime volumeShiftDate = expiryDate.minusDays(daysBeforeExpiry);

		if (date.isBefore(volumeShiftDate)) {
			return expiryDate;
		}
		return getQuarterlyExpiryDate(new DateTime(date.getMonthOfYear() == DateTimeConstants.DECEMBER ? date.getYear() + 1 : date.getYear(),
				(date.getMonthOfYear() + 1) % 12, 1, 0, 0, 0, 0));
	}

	public static DateTime getMostLiquidOMXMonthlyExpiry(DateTime date) {
		if (date == null) {
			date = new DateTime();
		} else if (date.isBefore(new DateTime(2008, 4, 17, 0, 0, 0, 0))) {
			return getMostLiquidMonthlyExpiry(date, 8, 4);
		}
		return getMostLiquidMonthlyExpiry(date, 8, 3);
	}

	public static DateTime getMostLiquidVIXMonthlyExpiry(DateTime date) {
		if (date == null) {
			date = new DateTime();
		}
		DateTime expiryDate = getNthFriday(date.plusMonths(1), 3).minusDays(31);
		DateTime volumeShiftDate = expiryDate.minusDays(2);

		if (date.isBefore(volumeShiftDate)) {
			return expiryDate;
		}
		return getNthFriday(date.plusMonths(2), 3).minusDays(31);
	}

	public static DateTime getMostLiquidMonthlyExpiry() {
		return getMostLiquidMonthlyExpiry(new DateTime(), 7, 3);
	}

	public static DateTime getMostLiquidMonthlyExpiry(DateTime date, int daysBeforeExpiry, int nthFriday) {
		DateTime expiryDate = getNthFriday(date, nthFriday);
		// Volume shifts to next month about x days before expiry
		DateTime volumeShiftDate = expiryDate.minusDays(daysBeforeExpiry);

		if (date.isBefore(volumeShiftDate)) {
			return expiryDate;
		}
		return getNthFriday(date.plusMonths(1), nthFriday);
	}

	public static DateTime getQuarterlyExpiryDate(DateTime date) {
		// Get third Friday
		MutableDateTime expiryDate = new MutableDateTime(date);
		expiryDate.setMillisOfDay(0);
		switch (expiryDate.getMonthOfYear()) {
		case DateTimeConstants.JANUARY:
		case DateTimeConstants.FEBRUARY:
		case DateTimeConstants.MARCH:
			expiryDate.setMonthOfYear(DateTimeConstants.MARCH);
			break;
		case DateTimeConstants.APRIL:
		case DateTimeConstants.MAY:
		case DateTimeConstants.JUNE:
			expiryDate.setMonthOfYear(DateTimeConstants.JUNE);
			break;
		case DateTimeConstants.JULY:
		case DateTimeConstants.AUGUST:
		case DateTimeConstants.SEPTEMBER:
			expiryDate.setMonthOfYear(DateTimeConstants.SEPTEMBER);
			break;
		case DateTimeConstants.OCTOBER:
		case DateTimeConstants.NOVEMBER:
		case DateTimeConstants.DECEMBER:
			expiryDate.setMonthOfYear(DateTimeConstants.DECEMBER);
			break;
		}
		expiryDate.setDayOfMonth(1);
		if (expiryDate.getDayOfWeek() > DateTimeConstants.FRIDAY) {
			expiryDate.addWeeks(3);
			expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
		} else {
			expiryDate.addWeeks(2);
			expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
		}
		return expiryDate.toDateTime();
	}

	private static DateTime getNthFriday(DateTime date, int nthFriday) {
		MutableDateTime expiryDate = new MutableDateTime(date);
		expiryDate.setMillisOfDay(0);
		expiryDate.setDayOfMonth(1);
		if (expiryDate.getDayOfWeek() > DateTimeConstants.FRIDAY) {
			expiryDate.addWeeks(nthFriday);
			expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
		} else {
			expiryDate.addWeeks(nthFriday - 1);
			expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
		}
		return expiryDate.toDateTime();
	}

	private static boolean isBusinessDay(ReadableDateTime date) {
		int dayOfWeek = date.getDayOfWeek();
		if (dayOfWeek == DateTimeConstants.SATURDAY || dayOfWeek == DateTimeConstants.SUNDAY) {
			return false;
		}
		return true;
	}
}

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Joselfonseca\LaravelAdmin\Contracts;

use Prettus\Repository\Contracts\RepositoryInterface;

/**
 * Class RoleRepositoryContract
 * @package Joselfonseca\LaravelAdmin\Contracts
 */
interface RoleRepositoryContract extends RepositoryInterface
{
}


text:
package main

import (
	configconvert "./../../source/configconvert"
	hostsetup "./../../source/hostsetup"
	specs "./../../source/specs"
	"fmt"
	"log"
	"os/exec"
)

func testVersion() {
	programmeString := "process_guest"
	outputFile := ""
	err := hostsetup.SetupEnv(programmeString, outputFile)
	if err != nil {
		log.Fatalf("Specstest version test: hostsetup.SetupEnv error, %v", err)
	}

	fmt.Println("Build test programme...................")
	cmd := exec.Command("/bin/sh", "-c", "go build test_process.go")
	_, err = cmd.Output()
	if err != nil {
		log.Fatalf("[Specstest] platform linux amd64 test: build test programme error, %v", err)
	}

	cmd = exec.Command("/bin/sh", "-c", "mv test_process ./../../source/")
	_, err = cmd.Output()
	if err != nil {
		log.Fatalf("[Specstest] platform linux amd64 test:: mv test programme error, %v", err)
	}

	fmt.Println("Host enviroment setting up for runc is already!")
	var filePath string
	filePath = "./../../source/config.json"

	oriSpecVersion := specs.Version
	var linuxspec *specs.LinuxSpec
	linuxspec, err = configconvert.ConfigToLinuxSpec(filePath)
	if err != nil {
		log.Fatalf("Specstest version test: readconfig error, %v", err)
	}

	linuxspec.Spec.Root.Path = "./rootfs_rootconfig"
	linuxspec.Spec.Version = oriSpecVersion
	linuxspec.Spec.Process.Terminal = true
	linuxspec.Spec.Process.User.UID = 1
	linuxspec.Spec.Process.User.GID = 1
	linuxspec.Spec.Process.User.AdditionalGids = nil
	linuxspec.Spec.Process.Env[0] = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
	linuxspec.Spec.Process.Env[1] = "TERM=xterm"
	linuxspec.Spec.Process.Cwd = "/testtool"
	linuxspec.Spec.Process.Args[0] = "./process_guest"

	err = configconvert.LinuxSpecToConfig(filePath, linuxspec)

	if err != nil {
		log.Fatalf("Specstest version test: writeconfig error, %v", err)
	}
	fmt.Println("Host enviroment for runc is already!")

}

func main() {
	testVersion()
}