910e62b5创建于 1月15日历史提交
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cronet_c.h"

#include "base/check.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "components/cronet/native/test/test_util.h"
#include "net/cert/mock_cert_verifier.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const char* kUserAgent = "EngineTest/1";

class EngineTest : public ::testing::Test {
 public:
  EngineTest(const EngineTest&) = delete;
  EngineTest& operator=(const EngineTest&) = delete;

 protected:
  EngineTest() = default;
  ~EngineTest() override {}
};

TEST_F(EngineTest, StartCronetEngine) {
  Cronet_EnginePtr engine = Cronet_Engine_Create();
  Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
  Cronet_EngineParams_user_agent_set(engine_params, kUserAgent);
  EXPECT_EQ(Cronet_RESULT_SUCCESS,
            Cronet_Engine_StartWithParams(engine, engine_params));
  Cronet_Engine_Destroy(engine);
  Cronet_EngineParams_Destroy(engine_params);
}

TEST_F(EngineTest, CronetEngineDefaultUserAgent) {
  Cronet_EnginePtr engine = Cronet_Engine_Create();
  // Version and DefaultUserAgent don't require engine start.
  std::string version = Cronet_Engine_GetVersionString(engine);
  std::string default_agent = Cronet_Engine_GetDefaultUserAgent(engine);
  EXPECT_NE(default_agent.find(version), std::string::npos);
  Cronet_Engine_Destroy(engine);
}

TEST_F(EngineTest, InitDifferentEngines) {
  Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
  Cronet_EnginePtr first_engine = Cronet_Engine_Create();
  Cronet_Engine_StartWithParams(first_engine, engine_params);
  Cronet_EnginePtr second_engine = Cronet_Engine_Create();
  Cronet_Engine_StartWithParams(second_engine, engine_params);
  Cronet_EnginePtr third_engine = Cronet_Engine_Create();
  Cronet_Engine_StartWithParams(third_engine, engine_params);
  Cronet_EngineParams_Destroy(engine_params);
  Cronet_Engine_Destroy(first_engine);
  Cronet_Engine_Destroy(second_engine);
  Cronet_Engine_Destroy(third_engine);
}

TEST_F(EngineTest, StartResults) {
  Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
  Cronet_EnginePtr engine = Cronet_Engine_Create();
  // Disable runtime CHECK of the result, so it could be verified.
  Cronet_EngineParams_enable_check_result_set(engine_params, false);
  Cronet_EngineParams_http_cache_mode_set(
      engine_params, Cronet_EngineParams_HTTP_CACHE_MODE_DISK);
  EXPECT_EQ(Cronet_RESULT_ILLEGAL_ARGUMENT_STORAGE_PATH_MUST_EXIST,
            Cronet_Engine_StartWithParams(engine, engine_params));
  Cronet_EngineParams_storage_path_set(engine_params, "InvalidPath");
  EXPECT_EQ(Cronet_RESULT_ILLEGAL_ARGUMENT_STORAGE_PATH_MUST_EXIST,
            Cronet_Engine_StartWithParams(engine, engine_params));
  base::ScopedTempDir temp_dir;
  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
  base::FilePath temp_path = base::MakeAbsoluteFilePath(temp_dir.GetPath());
  Cronet_EngineParams_storage_path_set(engine_params,
                                       temp_path.AsUTF8Unsafe().c_str());
  // Now the engine should start successfully.
  EXPECT_EQ(Cronet_RESULT_SUCCESS,
            Cronet_Engine_StartWithParams(engine, engine_params));
  // The second start should fail.
  EXPECT_EQ(Cronet_RESULT_ILLEGAL_STATE_ENGINE_ALREADY_STARTED,
            Cronet_Engine_StartWithParams(engine, engine_params));
  // The second engine should fail because storage path is already used.
  Cronet_EnginePtr second_engine = Cronet_Engine_Create();
  EXPECT_EQ(Cronet_RESULT_ILLEGAL_STATE_STORAGE_PATH_IN_USE,
            Cronet_Engine_StartWithParams(second_engine, engine_params));
  // Shutdown first engine to free storage path.
  EXPECT_EQ(Cronet_RESULT_SUCCESS, Cronet_Engine_Shutdown(engine));
  // Now the second engine should start.
  EXPECT_EQ(Cronet_RESULT_SUCCESS,
            Cronet_Engine_StartWithParams(second_engine, engine_params));
  Cronet_Engine_Destroy(second_engine);
  Cronet_Engine_Destroy(engine);
  Cronet_EngineParams_Destroy(engine_params);
}

TEST_F(EngineTest, InvalidPkpParams) {
  Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
  Cronet_EnginePtr engine = Cronet_Engine_Create();
  // Disable runtime CHECK of the result, so it could be verified.
  Cronet_EngineParams_enable_check_result_set(engine_params, false);
  // Try adding invalid public key pins.
  Cronet_PublicKeyPinsPtr public_key_pins = Cronet_PublicKeyPins_Create();
  Cronet_EngineParams_public_key_pins_add(engine_params, public_key_pins);
  EXPECT_EQ(Cronet_RESULT_NULL_POINTER_HOSTNAME,
            Cronet_Engine_StartWithParams(engine, engine_params));
  Cronet_EngineParams_public_key_pins_clear(engine_params);
  // Detect long host name.
  Cronet_PublicKeyPins_host_set(public_key_pins, std::string(256, 'a').c_str());
  Cronet_EngineParams_public_key_pins_add(engine_params, public_key_pins);
  EXPECT_EQ(Cronet_RESULT_ILLEGAL_ARGUMENT_INVALID_HOSTNAME,
            Cronet_Engine_StartWithParams(engine, engine_params));
  Cronet_EngineParams_public_key_pins_clear(engine_params);
  // Detect invalid host name.
  Cronet_PublicKeyPins_host_set(public_key_pins, "invalid:host/name");
  Cronet_EngineParams_public_key_pins_add(engine_params, public_key_pins);
  EXPECT_EQ(Cronet_RESULT_ILLEGAL_ARGUMENT_INVALID_HOSTNAME,
            Cronet_Engine_StartWithParams(engine, engine_params));
  Cronet_EngineParams_public_key_pins_clear(engine_params);
  // Set valid host name.
  Cronet_PublicKeyPins_host_set(public_key_pins, "valid.host.name");
  Cronet_EngineParams_public_key_pins_add(engine_params, public_key_pins);
  // Detect missing pins.
  EXPECT_EQ(Cronet_RESULT_NULL_POINTER_SHA256_PINS,
            Cronet_Engine_StartWithParams(engine, engine_params));
  // Detect invalid pin.
  Cronet_EngineParams_public_key_pins_clear(engine_params);
  Cronet_PublicKeyPins_pins_sha256_add(public_key_pins, "invalid_sha256");
  Cronet_EngineParams_public_key_pins_add(engine_params, public_key_pins);
  EXPECT_EQ(Cronet_RESULT_ILLEGAL_ARGUMENT_INVALID_PIN,
            Cronet_Engine_StartWithParams(engine, engine_params));
  // THe engine cannot start with these params, and have to be destroyed.
  Cronet_Engine_Destroy(engine);
  Cronet_EngineParams_Destroy(engine_params);
  Cronet_PublicKeyPins_Destroy(public_key_pins);
}

TEST_F(EngineTest, ValidPkpParams) {
  Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
  Cronet_EnginePtr engine = Cronet_Engine_Create();
  // Disable runtime CHECK of the result, so it could be verified.
  Cronet_EngineParams_enable_check_result_set(engine_params, false);
  // Add valid public key pins.
  Cronet_PublicKeyPinsPtr public_key_pins = Cronet_PublicKeyPins_Create();
  Cronet_PublicKeyPins_host_set(public_key_pins, "valid.host.name");
  Cronet_PublicKeyPins_pins_sha256_add(
      public_key_pins, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
  Cronet_EngineParams_public_key_pins_add(engine_params, public_key_pins);
  // The engine should start successfully.
  EXPECT_EQ(Cronet_RESULT_SUCCESS,
            Cronet_Engine_StartWithParams(engine, engine_params));
  Cronet_Engine_Destroy(engine);
  Cronet_EngineParams_Destroy(engine_params);
  Cronet_PublicKeyPins_Destroy(public_key_pins);
}

// Verify that Cronet_Engine_SetMockCertVerifierForTesting() doesn't crash or
// leak anything.
TEST_F(EngineTest, SetMockCertVerifierForTesting) {
  auto cert_verifier(std::make_unique<net::MockCertVerifier>());
  Cronet_EnginePtr engine = Cronet_Engine_Create();
  Cronet_Engine_SetMockCertVerifierForTesting(engine, cert_verifier.release());
  Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
  Cronet_Engine_StartWithParams(engine, engine_params);
  Cronet_Engine_Destroy(engine);
  Cronet_EngineParams_Destroy(engine_params);
}

TEST_F(EngineTest, StartNetLogToFile) {
  base::ScopedTempDir temp_dir;
  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
  base::FilePath temp_path = base::MakeAbsoluteFilePath(temp_dir.GetPath());
  base::FilePath net_log_file =
      temp_path.Append(FILE_PATH_LITERAL("netlog.json"));

  Cronet_EnginePtr engine = Cronet_Engine_Create();
  Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
  Cronet_EngineParams_experimental_options_set(
      engine_params,
      "{ \"QUIC\" : {\"max_server_configs_stored_in_properties\" : 8} }");
  // Test that net log cannot start/stop before engine start.
  EXPECT_FALSE(Cronet_Engine_StartNetLogToFile(
      engine, net_log_file.AsUTF8Unsafe().c_str(), true));
  Cronet_Engine_StopNetLog(engine);

  // Start the engine.
  Cronet_Engine_StartWithParams(engine, engine_params);
  Cronet_EngineParams_Destroy(engine_params);

  // Test that normal start/stop net log works.
  EXPECT_TRUE(Cronet_Engine_StartNetLogToFile(
      engine, net_log_file.AsUTF8Unsafe().c_str(), true));
  Cronet_Engine_StopNetLog(engine);

  // Test that double start/stop net log works.
  EXPECT_TRUE(Cronet_Engine_StartNetLogToFile(
      engine, net_log_file.AsUTF8Unsafe().c_str(), true));
  // Test that second start fails.
  EXPECT_FALSE(Cronet_Engine_StartNetLogToFile(
      engine, net_log_file.AsUTF8Unsafe().c_str(), true));
  // Test that multiple stops work.
  Cronet_Engine_StopNetLog(engine);
  Cronet_Engine_StopNetLog(engine);
  Cronet_Engine_StopNetLog(engine);

  // Test that net log contains effective experimental options.
  std::string net_log;
  EXPECT_TRUE(base::ReadFileToString(net_log_file, &net_log));
  EXPECT_TRUE(
      net_log.find(
          "{\"QUIC\":{\"max_server_configs_stored_in_properties\":8}") !=
      std::string::npos);

  // Test that bad file name fails.
  EXPECT_FALSE(Cronet_Engine_StartNetLogToFile(engine, "bad/file/name", true));

  Cronet_Engine_Shutdown(engine);
  // Test that net log cannot start/stop after engine shutdown.
  EXPECT_FALSE(Cronet_Engine_StartNetLogToFile(
      engine, net_log_file.AsUTF8Unsafe().c_str(), true));
  Cronet_Engine_StopNetLog(engine);
  Cronet_Engine_Destroy(engine);
}

}  // namespace