chromium/native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_pepper_interface_googledrivefs.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "fake_ppapi/fake_pepper_interface_googledrivefs.h"

#include <ppapi/c/pp_completion_callback.h>
#include <ppapi/c/pp_errors.h>

#include "gtest/gtest.h"

#include "fake_ppapi/fake_core_interface.h"
#include "fake_ppapi/fake_file_ref_interface.h"
#include "fake_ppapi/fake_pepper_interface_url_loader.h"
#include "fake_ppapi/fake_util.h"
#include "fake_ppapi/fake_var_interface.h"

class FakeDriveInstanceResource : public FakeResource {
 public:
  FakeDriveInstanceResource() : server_template(NULL) {}
  static const char* classname() { return "FakeDriveInstanceResource"; }

  FakeGoogleDriveServer* server_template;
};

class FakeDriveURLLoaderResource : public FakeResource {
 public:
  FakeDriveURLLoaderResource() : manager(NULL), server(NULL), response(0) {}

  virtual void Destroy() {
    EXPECT_TRUE(manager != NULL);
    if (response != 0)
      manager->Release(response);
  }

  static const char* classname() { return "FakeDriveURLLoaderResource"; }

  FakeResourceManager* manager;
  FakeGoogleDriveServer* server;
  PP_Resource response;
  std::string response_body;
};

class FakeDriveResponseResource : public FakeURLResponseInfoResource {
 public:
  FakeDriveResponseResource()
      : manager(NULL),
        loader_resource(NULL),
        file_ref(0),
        stream_to_file(false) {}

  virtual void Destroy() {
    EXPECT_TRUE(manager != NULL);
    if (file_ref != 0)
      manager->Release(file_ref);
  }

  static const char* classname() { return "FakeDriveResponseResource"; }

  FakeResourceManager* manager;
  FakeDriveURLLoaderResource* loader_resource;
  PP_Resource file_ref;
  bool stream_to_file;
  std::string body;
};

FakeGoogleDriveServer::FakeGoogleDriveServer() {}

void FakeGoogleDriveServer::Respond(
    const std::string& url,
    const std::string& headers,
    const std::string& method,
    const std::string& body,
    FakeGoogleDriveServerResponse* out_response) {
  out_response->status_code = STATUSCODE_NOT_IMPLEMENTED;
}

FakeDriveURLLoaderInterface::FakeDriveURLLoaderInterface(
    FakeCoreInterface* core_interface)
    : FakeURLLoaderInterface(core_interface) {}

PP_Resource FakeDriveURLLoaderInterface::Create(PP_Instance instance) {
  FakeDriveInstanceResource* drive_instance_resource =
      core_interface_->resource_manager()->Get<FakeDriveInstanceResource>(
          instance);
  if (drive_instance_resource == NULL)
    return 0;

  FakeDriveURLLoaderResource* drive_loader_resource =
      new FakeDriveURLLoaderResource;
  drive_loader_resource->manager = core_interface_->resource_manager();
  drive_loader_resource->server = drive_instance_resource->server_template;

  return CREATE_RESOURCE(core_interface_->resource_manager(),
                         FakeDriveURLLoaderResource, drive_loader_resource);
}

int32_t FakeDriveURLLoaderInterface::Open(PP_Resource loader,
                                          PP_Resource request,
                                          PP_CompletionCallback callback) {
  FakeDriveURLLoaderResource* drive_loader_resource =
      core_interface_->resource_manager()->Get<FakeDriveURLLoaderResource>(
          loader);
  if (drive_loader_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  // Close() has been called. Invalid to call Open() again.
  if (drive_loader_resource->server == NULL)
    return PP_ERROR_FAILED;

  FakeURLRequestInfoResource* request_resource =
      core_interface_->resource_manager()->Get<FakeURLRequestInfoResource>(
          request);
  if (request_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  // Create a response resource.
  FakeDriveResponseResource* drive_response_resource =
      new FakeDriveResponseResource;
  drive_response_resource->manager = drive_loader_resource->manager;
  drive_loader_resource->response =
      CREATE_RESOURCE(core_interface_->resource_manager(),
                      FakeDriveResponseResource, drive_response_resource);

  drive_response_resource->loader_resource = drive_loader_resource;
  drive_response_resource->stream_to_file = request_resource->stream_to_file;

  FakeGoogleDriveServerResponse server_response;
  drive_loader_resource->server->Respond(
      request_resource->url, request_resource->headers,
      request_resource->method, request_resource->body, &server_response);

  drive_response_resource->status_code = server_response.status_code;
  drive_loader_resource->response_body = server_response.body;

  // Call the callback.
  return RunCompletionCallback(&callback, PP_OK);
}

PP_Resource FakeDriveURLLoaderInterface::GetResponseInfo(PP_Resource loader) {
  FakeDriveURLLoaderResource* drive_loader_resource =
      core_interface_->resource_manager()->Get<FakeDriveURLLoaderResource>(
          loader);
  if (drive_loader_resource == NULL)
    return 0;

  if (drive_loader_resource->response == 0)
    return 0;

  // Returned resources have an implicit AddRef.
  core_interface_->resource_manager()->AddRef(drive_loader_resource->response);
  return drive_loader_resource->response;
}

int32_t FakeDriveURLLoaderInterface::FinishStreamingToFile(
    PP_Resource loader,
    PP_CompletionCallback callback) {
  FakeDriveURLLoaderResource* drive_loader_resource =
      core_interface_->resource_manager()->Get<FakeDriveURLLoaderResource>(
          loader);
  if (drive_loader_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  FakeDriveResponseResource* drive_response_resource =
      core_interface_->resource_manager()->Get<FakeDriveResponseResource>(
          drive_loader_resource->response);
  if (drive_response_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  if (!drive_response_resource->stream_to_file)
    return PP_ERROR_FAILED;

  drive_response_resource->body = drive_loader_resource->response_body;

  // PPB_URLLoader::FinishStreamingToFile(..) returns 0 even when
  // the response body size is > 0.
  return 0;
}

void FakeDriveURLLoaderInterface::Close(PP_Resource loader) {
  FakeDriveURLLoaderResource* drive_loader_resource =
      core_interface_->resource_manager()->Get<FakeDriveURLLoaderResource>(
          loader);
  if (drive_loader_resource == NULL)
    return;

  core_interface_->resource_manager()->Release(drive_loader_resource->response);

  drive_loader_resource->server = NULL;
  drive_loader_resource->response = 0;
  drive_loader_resource->response_body.clear();
}

FakeDriveURLRequestInfoInterface::FakeDriveURLRequestInfoInterface(
    FakeCoreInterface* core_interface,
    FakeVarInterface* var_interface)
    : FakeURLRequestInfoInterface(core_interface, var_interface) {}

PP_Resource FakeDriveURLRequestInfoInterface::Create(PP_Instance instance) {
  FakeDriveInstanceResource* drive_instance_resource =
      core_interface_->resource_manager()->Get<FakeDriveInstanceResource>(
          instance);
  if (drive_instance_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  return CREATE_RESOURCE(core_interface_->resource_manager(),
                         FakeURLRequestInfoResource,
                         new FakeURLRequestInfoResource);
}

FakeDriveURLResponseInfoInterface::FakeDriveURLResponseInfoInterface(
    FakeCoreInterface* core_interface,
    FakeVarInterface* var_interface,
    FakeFileRefInterface* file_ref_interface)
    : FakeURLResponseInfoInterface(core_interface, var_interface),
      file_ref_interface_(file_ref_interface) {
  FakeFileSystemResource* file_system_resource = new FakeFileSystemResource;
  file_system_resource->filesystem = new FakeFilesystem();
  file_system_resource->opened = true;

  filesystem_resource_ =
      CREATE_RESOURCE(core_interface_->resource_manager(),
                      FakeFileSystemResource, file_system_resource);
}

FakeDriveURLResponseInfoInterface::~FakeDriveURLResponseInfoInterface() {
  core_interface_->ReleaseResource(filesystem_resource_);
}

PP_Var FakeDriveURLResponseInfoInterface::GetProperty(
    PP_Resource response,
    PP_URLResponseProperty property) {
  FakeDriveResponseResource* drive_response_resource =
      core_interface_->resource_manager()->Get<FakeDriveResponseResource>(
          response);
  if (drive_response_resource == NULL)
    return PP_Var();

  switch (property) {
    case PP_URLRESPONSEPROPERTY_URL:
      return var_interface_->VarFromUtf8(drive_response_resource->url.data(),
                                         drive_response_resource->url.size());

    case PP_URLRESPONSEPROPERTY_STATUSCODE:
      return PP_MakeInt32(drive_response_resource->status_code);

    case PP_URLRESPONSEPROPERTY_HEADERS:
      return var_interface_->VarFromUtf8(
          drive_response_resource->headers.data(),
          drive_response_resource->headers.size());
    default:
      EXPECT_TRUE(false) << "Unimplemented property " << property
                         << " in "
                            "FakeDriveURLResponseInfoInterface::GetProperty";
      return PP_Var();
  }
}

PP_Resource FakeDriveURLResponseInfoInterface::GetBodyAsFileRef(
    PP_Resource response) {
  FakeDriveResponseResource* drive_response_resource =
      core_interface_->resource_manager()->Get<FakeDriveResponseResource>(
          response);
  if (drive_response_resource == NULL)
    return 0;

  if (!drive_response_resource->stream_to_file)
    return 0;

  if (drive_response_resource->loader_resource == NULL)
    return 0;

  if (drive_response_resource->loader_resource->server == NULL)
    return 0;

  if (drive_response_resource->file_ref == 0) {
    FakeFileSystemResource* file_system_resource =
        core_interface_->resource_manager()->Get<FakeFileSystemResource>(
            filesystem_resource_);
    if (file_system_resource == NULL)
      return 0;

    char path_buffer[32];
    snprintf(path_buffer, sizeof(path_buffer), "%u", response);

    FakeNode* fake_node;
    if (!file_system_resource->filesystem->AddFile(
            path_buffer, drive_response_resource->body, &fake_node))
      return 0;

    drive_response_resource->file_ref =
        file_ref_interface_->Create(filesystem_resource_, path_buffer);
  }

  // Returned resources have an implicit AddRef.
  core_interface_->resource_manager()->AddRef(
      drive_response_resource->file_ref);
  return drive_response_resource->file_ref;
}

FakePepperInterfaceGoogleDriveFs::FakePepperInterfaceGoogleDriveFs()
    : core_interface_(&resource_manager_),
      var_interface_(&var_manager_),
      file_io_interface_(&core_interface_),
      file_ref_interface_(&core_interface_, &var_interface_),
      drive_url_loader_interface_(&core_interface_),
      drive_url_request_info_interface_(&core_interface_, &var_interface_),
      drive_url_response_info_interface_(&core_interface_,
                                         &var_interface_,
                                         &file_ref_interface_) {
  Init();
}

void FakePepperInterfaceGoogleDriveFs::Init() {
  FakeDriveInstanceResource* drive_instance_resource =
      new FakeDriveInstanceResource;
  drive_instance_resource->server_template = &google_drive_server_template_;

  instance_ =
      CREATE_RESOURCE(core_interface_.resource_manager(),
                      FakeDriveInstanceResource, drive_instance_resource);
}

FakePepperInterfaceGoogleDriveFs::~FakePepperInterfaceGoogleDriveFs() {
  core_interface_.ReleaseResource(instance_);
}

nacl_io::CoreInterface* FakePepperInterfaceGoogleDriveFs::GetCoreInterface() {
  return &core_interface_;
}

nacl_io::FileIoInterface*
FakePepperInterfaceGoogleDriveFs::GetFileIoInterface() {
  return &file_io_interface_;
}

nacl_io::FileRefInterface*
FakePepperInterfaceGoogleDriveFs::GetFileRefInterface() {
  return &file_ref_interface_;
}

nacl_io::URLLoaderInterface*
FakePepperInterfaceGoogleDriveFs::GetURLLoaderInterface() {
  return &drive_url_loader_interface_;
}

nacl_io::URLRequestInfoInterface*
FakePepperInterfaceGoogleDriveFs::GetURLRequestInfoInterface() {
  return &drive_url_request_info_interface_;
}

nacl_io::URLResponseInfoInterface*
FakePepperInterfaceGoogleDriveFs::GetURLResponseInfoInterface() {
  return &drive_url_response_info_interface_;
}

nacl_io::VarInterface* FakePepperInterfaceGoogleDriveFs::GetVarInterface() {
  return &var_interface_;
}