chromium/components/variations/fuzzers/create_trials_from_seed_fuzzer_v2.cc

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

#include <memory>

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/test/bind.h"
#include "base/test/scoped_command_line.h"
#include "components/variations/client_filterable_state.h"
#include "components/variations/entropy_provider.h"
#include "components/variations/fuzzers/create_trials_from_seed_test_case.pb.h"
#include "components/variations/proto/study.pb.h"
#include "components/variations/variations_layers.h"
#include "components/variations/variations_seed_processor.h"
#include "components/variations/variations_test_utils.h"
#include "testing/libfuzzer/proto/lpm_interface.h"

namespace variations {
namespace {

struct Environment {
  Environment() { base::CommandLine::Init(0, nullptr); }

  base::AtExitManager at_exit_manager;
};

EntropyProviders CreateEntropyProviders(
    const CreateTrialsFromSeedTestCase::EntropyValues& entropy_values) {
  return EntropyProviders(
      entropy_values.client_id(), {entropy_values.low_entropy(), 8000},
      entropy_values.limited_entropy_randomization_source());
}

std::unique_ptr<ClientFilterableState> CreateClientFilterableState(
    const CreateTrialsFromSeedTestCase::ClientFilterableState& spec) {
  auto client_state = std::make_unique<ClientFilterableState>(
      base::BindOnce([] { return false; }),
      base::BindLambdaForTesting([spec]() {
        return base::flat_set<uint64_t>(spec.google_groups().begin(),
                                        spec.google_groups().end());
      }));

  if (spec.has_locale()) {
    client_state->locale = spec.locale();
  }
  if (spec.has_reference_date_seconds_since_epoch()) {
    client_state->reference_date =
        base::Time::UnixEpoch() +
        base::Seconds(spec.reference_date_seconds_since_epoch());
  }
  if (!spec.version().empty()) {
    client_state->version = base::Version(
        std::vector<uint32_t>(spec.version().begin(), spec.version().end()));
  }
  if (!spec.os_version().empty()) {
    client_state->os_version = base::Version(std::vector<uint32_t>(
        spec.os_version().begin(), spec.os_version().end()));
  }
  if (spec.has_channel()) {
    client_state->channel = spec.channel();
  }
  if (spec.has_form_factor()) {
    client_state->form_factor = spec.form_factor();
  }
  if (spec.has_cpu_architecture()) {
    client_state->cpu_architecture = spec.cpu_architecture();
  }
  if (spec.has_platform()) {
    client_state->platform = spec.platform();
  }
  if (spec.has_hardware_class()) {
    client_state->hardware_class = spec.hardware_class();
  }
  if (spec.has_is_low_end_device()) {
    client_state->is_low_end_device = spec.is_low_end_device();
  }
  if (spec.has_session_consistency_country()) {
    client_state->session_consistency_country =
        spec.session_consistency_country();
  }
  if (spec.has_permanent_consistency_country()) {
    client_state->permanent_consistency_country =
        spec.permanent_consistency_country();
  }
  if (spec.has_policy_restriction()) {
    switch (spec.policy_restriction()) {
      case CreateTrialsFromSeedTestCase_RestrictionPolicy_NO_RESTRICTIONS:
        client_state->policy_restriction = RestrictionPolicy::NO_RESTRICTIONS;
        break;
      case CreateTrialsFromSeedTestCase_RestrictionPolicy_CRITICAL_ONLY:
        client_state->policy_restriction = RestrictionPolicy::CRITICAL_ONLY;
        break;
      case CreateTrialsFromSeedTestCase_RestrictionPolicy_ALL:
        client_state->policy_restriction = RestrictionPolicy::ALL;
        break;
    }
  }
  return client_state;
}

void CreateTrialsFromSeedFuzzer(
    const variations::CreateTrialsFromSeedTestCase& test_case) {
  base::FieldTrialList field_trial_list;
  base::FeatureList feature_list;

  auto client_state = CreateClientFilterableState(
      test_case.has_client_filterable_state()
          ? test_case.client_filterable_state()
          : variations::CreateTrialsFromSeedTestCase::ClientFilterableState());
  auto entropy_providers = CreateEntropyProviders(
      test_case.has_entropy()
          ? test_case.entropy()
          : variations::CreateTrialsFromSeedTestCase::EntropyValues());

  if (!test_case.has_seed()) {
    return;
  }

  auto seed = test_case.seed();
  VariationsLayers layers(seed, entropy_providers);
  VariationsSeedProcessor().CreateTrialsFromSeed(
      seed, *client_state, base::BindRepeating(NoopUIStringOverrideCallback),
      entropy_providers, layers, &feature_list);
}

}  // namespace

DEFINE_PROTO_FUZZER(const variations::CreateTrialsFromSeedTestCase& test_case) {
  static Environment env;
  CreateTrialsFromSeedFuzzer(test_case);
}

}  // namespace variations