chromium/tools/variations/split_variations_cmd_unittest.py

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

import unittest

import os
import split_variations_cmd

_ENABLE_FEATURES_SWITCH_NAME = 'enable-features'
_DISABLE_FEATURES_SWITCH_NAME = 'disable-features'
_FORCE_FIELD_TRIALS_SWITCH_NAME = 'force-fieldtrials'
_FORCE_FIELD_TRIAL_PARAMS_SWITCH_NAME = 'force-fieldtrial-params'

class SplitVariationsCmdUnittest(unittest.TestCase):

  def _CompareCommandLineSwitches(self, filename, cmd_list):
    """Compares two sets of command line switches.

    Args:
        filename: Name to a file that contains a set of commandline switches.
        cmd_list: A list of strings in the form of '--switch_name=switch_value'.

    Return True if they contain the same switches and each switch's values
    are the same.
    """
    assert os.path.isfile(filename)
    data = None
    with open(filename, 'r') as f:
      data = f.read().replace('\n', ' ')
    switches = split_variations_cmd.ParseCommandLineSwitchesString(data)
    if len(switches) != len(cmd_list):
      return False
    for switch_name, switch_value in switches.items():
      switch_string = '--%s="%s"' % (switch_name, switch_value)
      if switch_string not in cmd_list:
        return False
    return True

  def _GetUnittestDataDir(self):
    return os.path.join(os.path.dirname(__file__), 'unittest_data')

  def _VerifySplits(self, switch_name, splits, ref_switch_data):
    """Verifies splitting commandline switches works correctly.

    Compare that when we combine switch data from all |splits| into one,
    it's exactly the same as the |ref_switch_data|. Also check the splits are
    almost evenly distributed, that is, their data size are almost the same.

    Args:
        switch_name: The name of the switch that is verified.
        splits: A list of {switch_name: [items]} dictionaries.
                Each list element represents one of the split switch sets.
                |items| is a list of items representing switch value.
        ref_switch_data: A {switch_name: [items]} dictionary.
                         This is the switch set before splitting.
                         |items| is a list of items representing switch value.
    """
    data_lists = [
        split[switch_name] for split in splits if switch_name in split]
    if len(data_lists) == 0:
      self.assertFalse(ref_switch_data)
      return
    max_size = max(len(data) for data in data_lists)
    min_size = min(len(data) for data in data_lists)
    if switch_name != _FORCE_FIELD_TRIAL_PARAMS_SWITCH_NAME:
      self.assertTrue(max_size - min_size <= 1)
    joined_switch_data = []
    for data in data_lists:
      joined_switch_data.extend(data)
    self.assertEqual(ref_switch_data, joined_switch_data)


  def testLoadFromFileAndSaveToStrings(self):
    # Verifies we load data from the file and save it to a list of strings,
    # the two data sets contain the same command line switches.
    data_file = os.path.join(self._GetUnittestDataDir(), 'variations_cmd.txt')
    assert os.path.isfile(data_file)
    data = split_variations_cmd.ParseVariationsCmdFromFile(data_file)
    cmd_list = split_variations_cmd.VariationsCmdToStrings(data)
    self.assertTrue(self._CompareCommandLineSwitches(data_file, cmd_list))


  def _testSplitVariationsCmdHelper(self, input_data):
    # Verifies we correctly and (almost) evenly split one set of command line
    # switches into two sets.
    splits = split_variations_cmd.SplitVariationsCmd(input_data)
    switches = [_ENABLE_FEATURES_SWITCH_NAME,
                _DISABLE_FEATURES_SWITCH_NAME,
                _FORCE_FIELD_TRIALS_SWITCH_NAME,
                _FORCE_FIELD_TRIAL_PARAMS_SWITCH_NAME]
    for switch in switches:
      self._VerifySplits(switch, splits, input_data.get(switch, []))
    # Verify both split variations are valid.
    for variations_cmd in splits:
      cmd_list = split_variations_cmd.VariationsCmdToStrings(variations_cmd)
      split_variations_cmd.ParseVariationsCmdFromString(' '.join(cmd_list))


  def testSplitVariationsCmd(self):
    input_file = os.path.join(self._GetUnittestDataDir(), 'variations_cmd.txt')
    assert os.path.isfile(input_file)
    data = split_variations_cmd.ParseVariationsCmdFromFile(input_file)
    self._testSplitVariationsCmdHelper(data)


  def testSplitVariationsCmdWithMissingEnableDisableFeatures(self):
    input_string = (
        '--force-fieldtrials="Tria1/Disabled/*Trial2/Enabled/" '
        '--force-fieldtrial-params="Trial2.Enabled:age/18/gender/male" '
        '--disable-features="FeatureA<FeatureA"')
    data = split_variations_cmd.ParseVariationsCmdFromString(input_string)
    self._testSplitVariationsCmdHelper(data)


  def testSplitVariationsCmdWithMissingForceFieldTrialParams(self):
    input_string = (
        '--force-fieldtrials="*Trial2/Enabled/" '
        '--enable-features="FeatureA<FeatureA,FeatureB<FeatureB" '
        '--disable-features="FeatureC<FeatureC,FeatureD<FeatureD"')
    data = split_variations_cmd.ParseVariationsCmdFromString(input_string)
    self._testSplitVariationsCmdHelper(data)

  def testSplitVariationsCmdNoFurtherSplit(self):
    input_string = (
        '--force-fieldtrials="*Trial2/Enabled/" '
        '--enable-features="FeatureA<FeatureA" '
        '--disable-features="FeatureC<FeatureC"')
    splits = split_variations_cmd.SplitVariationsCmdFromString(input_string)
    self.assertEqual(1, len(splits))


if __name__ == '__main__':
  unittest.main()