// Copyright (c) 2021 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 "quic/core/quic_chaos_protector.h"

#include <cstddef>
#include <memory>

#include "absl/strings/string_view.h"
#include "quic/core/frames/quic_crypto_frame.h"
#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_framer.h"
#include "quic/core/quic_packet_number.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_stream_frame_data_producer.h"
#include "quic/core/quic_time.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/mock_random.h"
#include "quic/test_tools/quic_test_utils.h"
#include "quic/test_tools/simple_quic_framer.h"

namespace quic {
namespace test {

class QuicChaosProtectorTest : public QuicTestWithParam<ParsedQuicVersion>,
                               public QuicStreamFrameDataProducer {
 public:
  QuicChaosProtectorTest()
      : version_(GetParam()),
        framer_({version_},
                QuicTime::Zero(),
                Perspective::IS_CLIENT,
                kQuicDefaultConnectionIdLength),
        validation_framer_({version_}),
        random_(/*base=*/3),
        level_(ENCRYPTION_INITIAL),
        crypto_offset_(0),
        crypto_data_length_(100),
        crypto_frame_(level_, crypto_offset_, crypto_data_length_),
        num_padding_bytes_(50),
        packet_size_(1000),
        packet_buffer_(std::make_unique<char[]>(packet_size_)),
        chaos_protector_(crypto_frame_,
                         num_padding_bytes_,
                         packet_size_,
                         SetupHeaderAndFramers(),
                         &random_) {}

  // From QuicStreamFrameDataProducer.
  WriteStreamDataResult WriteStreamData(QuicStreamId /*id*/,
                                        QuicStreamOffset /*offset*/,
                                        QuicByteCount /*data_length*/,
                                        QuicDataWriter* /*writer*/) override {
    ADD_FAILURE() << "This should never be called";
    return STREAM_MISSING;
  }

  // From QuicStreamFrameDataProducer.
  bool WriteCryptoData(EncryptionLevel level,
                       QuicStreamOffset offset,
                       QuicByteCount data_length,
                       QuicDataWriter* writer) override {
    EXPECT_EQ(level, level);
    EXPECT_EQ(offset, crypto_offset_);
    EXPECT_EQ(data_length, crypto_data_length_);
    for (QuicByteCount i = 0; i < data_length; i++) {
      EXPECT_TRUE(writer->WriteUInt8(static_cast<uint8_t>(i & 0xFF)));
    }
    return true;
  }

 protected:
  QuicFramer* SetupHeaderAndFramers() {
    // Setup header.
    header_.destination_connection_id = TestConnectionId();
    header_.destination_connection_id_included = CONNECTION_ID_PRESENT;
    header_.source_connection_id = EmptyQuicConnectionId();
    header_.source_connection_id_included = CONNECTION_ID_PRESENT;
    header_.reset_flag = false;
    header_.version_flag = true;
    header_.has_possible_stateless_reset_token = false;
    header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
    header_.version = version_;
    header_.packet_number = QuicPacketNumber(1);
    header_.form = IETF_QUIC_LONG_HEADER_PACKET;
    header_.long_packet_type = INITIAL;
    header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
    header_.length_length = kQuicDefaultLongHeaderLengthLength;
    // Setup validation framer.
    validation_framer_.framer()->SetInitialObfuscators(
        header_.destination_connection_id);
    // Setup framer.
    framer_.SetInitialObfuscators(header_.destination_connection_id);
    framer_.set_data_producer(this);
    return &framer_;
  }

  void BuildEncryptAndParse() {
    absl::optional<size_t> length =
        chaos_protector_.BuildDataPacket(header_, packet_buffer_.get());
    ASSERT_TRUE(length.has_value());
    ASSERT_GT(length.value(), 0u);
    size_t encrypted_length = framer_.EncryptInPlace(
        level_, header_.packet_number,
        GetStartOfEncryptedData(framer_.transport_version(), header_),
        length.value(), packet_size_, packet_buffer_.get());
    ASSERT_GT(encrypted_length, 0u);
    ASSERT_TRUE(validation_framer_.ProcessPacket(QuicEncryptedPacket(
        absl::string_view(packet_buffer_.get(), encrypted_length))));
  }

  void ResetOffset(QuicStreamOffset offset) {
    crypto_offset_ = offset;
    crypto_frame_.offset = offset;
    chaos_protector_.crypto_buffer_offset_ = offset;
  }

  ParsedQuicVersion version_;
  QuicPacketHeader header_;
  QuicFramer framer_;
  SimpleQuicFramer validation_framer_;
  MockRandom random_;
  EncryptionLevel level_;
  QuicStreamOffset crypto_offset_;
  QuicByteCount crypto_data_length_;
  QuicCryptoFrame crypto_frame_;
  int num_padding_bytes_;
  size_t packet_size_;
  std::unique_ptr<char[]> packet_buffer_;
  QuicChaosProtector chaos_protector_;
};

namespace {

ParsedQuicVersionVector TestVersions() {
  ParsedQuicVersionVector versions;
  for (const ParsedQuicVersion& version : AllSupportedVersions()) {
    if (version.UsesCryptoFrames()) {
      versions.push_back(version);
    }
  }
  return versions;
}

INSTANTIATE_TEST_SUITE_P(QuicChaosProtectorTests,
                         QuicChaosProtectorTest,
                         ::testing::ValuesIn(TestVersions()),
                         ::testing::PrintToStringParamName());

TEST_P(QuicChaosProtectorTest, Main) {
  BuildEncryptAndParse();
  ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, 0u);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, 1u);
  ASSERT_EQ(validation_framer_.ping_frames().size(), 3u);
  ASSERT_EQ(validation_framer_.padding_frames().size(), 7u);
  EXPECT_EQ(validation_framer_.padding_frames()[0].num_padding_bytes, 3);
}

TEST_P(QuicChaosProtectorTest, DifferentRandom) {
  random_.ResetBase(4);
  BuildEncryptAndParse();
  ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u);
  ASSERT_EQ(validation_framer_.ping_frames().size(), 4u);
  ASSERT_EQ(validation_framer_.padding_frames().size(), 8u);
}

TEST_P(QuicChaosProtectorTest, RandomnessZero) {
  random_.ResetBase(0);
  BuildEncryptAndParse();
  ASSERT_EQ(validation_framer_.crypto_frames().size(), 1u);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length,
            crypto_data_length_);
  ASSERT_EQ(validation_framer_.ping_frames().size(), 0u);
  ASSERT_EQ(validation_framer_.padding_frames().size(), 1u);
}

TEST_P(QuicChaosProtectorTest, Offset) {
  ResetOffset(123);
  BuildEncryptAndParse();
  ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, 1u);
  ASSERT_EQ(validation_framer_.ping_frames().size(), 3u);
  ASSERT_EQ(validation_framer_.padding_frames().size(), 7u);
  EXPECT_EQ(validation_framer_.padding_frames()[0].num_padding_bytes, 3);
}

TEST_P(QuicChaosProtectorTest, OffsetAndRandomnessZero) {
  ResetOffset(123);
  random_.ResetBase(0);
  BuildEncryptAndParse();
  ASSERT_EQ(validation_framer_.crypto_frames().size(), 1u);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_);
  EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length,
            crypto_data_length_);
  ASSERT_EQ(validation_framer_.ping_frames().size(), 0u);
  ASSERT_EQ(validation_framer_.padding_frames().size(), 1u);
}

}  // namespace
}  // namespace test
}  // namespace quic
