Wire up --force_fieldtrials for vie_auto_test and for test targets linking with test/test.gyp:{test_main|test_support_main}

This allows use of webrtc field trials  and opens up the possibility to try the different code paths when running the unit tests by wiring them up to a --force_fieldtrials.

Tested: running a test target that links with the above with a flag --force_fieldtrials=invalid leads the test to crash.

BUG=crbug/367114
R=mflodman@webrtc.org, phoglund@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/19439004

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6181 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/system_wrappers/interface/field_trial.h b/system_wrappers/interface/field_trial.h
index d38df26..f2cf880 100644
--- a/system_wrappers/interface/field_trial.h
+++ b/system_wrappers/interface/field_trial.h
@@ -53,7 +53,6 @@
 //     needs to push a config with start_active:true or run a local finch
 //     server.
 //
-// TODO(andresp): support --force_fieldtirals from webrtc tests.
 // TODO(andresp): find out how to get bots to run tests with trials enabled.
 
 namespace webrtc {
diff --git a/test/field_trial.cc b/test/field_trial.cc
new file mode 100644
index 0000000..6b3d83c
--- /dev/null
+++ b/test/field_trial.cc
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/test/field_trial.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <string>
+
+#include "webrtc/system_wrappers/interface/field_trial.h"
+
+namespace webrtc {
+namespace {
+// Clients of this library have show a clear intent to setup field trials by
+// linking with it. As so try to crash if they forget to call
+// InitFieldTrialsFromString before webrtc tries to access a field trial.
+bool field_trials_initiated_ = false;
+std::map<std::string, std::string> field_trials_;
+}  // namespace
+
+namespace field_trial {
+std::string FindFullName(const std::string& trial_name) {
+  assert(field_trials_initiated_);
+  std::map<std::string, std::string>::const_iterator it =
+      field_trials_.find(trial_name);
+  if (it == field_trials_.end())
+    return std::string();
+  return it->second;
+}
+}  // namespace field_trial
+
+namespace test {
+// Note: this code is copied from src/base/metrics/field_trial.cc since the aim
+// is to mimic chromium --force-fieldtrials.
+void InitFieldTrialsFromString(const std::string& trials_string) {
+  static const char kPersistentStringSeparator = '/';
+
+  // Catch an error if this is called more than once.
+  assert(field_trials_initiated_ == false);
+  field_trials_initiated_ = true;
+
+  if (trials_string.empty()) return;
+
+  size_t next_item = 0;
+  while (next_item < trials_string.length()) {
+    size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
+    if (name_end == trials_string.npos || next_item == name_end)
+      break;
+    size_t group_name_end = trials_string.find(kPersistentStringSeparator,
+                                               name_end + 1);
+    if (group_name_end == trials_string.npos || name_end + 1 == group_name_end)
+      break;
+    std::string name(trials_string, next_item, name_end - next_item);
+    std::string group_name(trials_string, name_end + 1,
+                           group_name_end - name_end - 1);
+    next_item = group_name_end + 1;
+
+    // Fail if duplicate with different group name.
+    if (field_trials_.find(name) != field_trials_.end() &&
+        field_trials_.find(name)->second != group_name)
+      break;
+
+    field_trials_[name] = group_name;
+
+    // Successfully parsed all field trials from the string.
+    if (next_item == trials_string.length())
+      return;
+  }
+  // LOG does not prints when this is called early on main.
+  fprintf(stderr, "Invalid field trials string.\n");
+
+  // Using abort so it crashs both in debug and release mode.
+  abort();
+}
+}  // namespace test
+}  // namespace webrtc
diff --git a/test/field_trial.h b/test/field_trial.h
new file mode 100644
index 0000000..6503254
--- /dev/null
+++ b/test/field_trial.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_TEST_FIELD_TRIAL_H_
+#define WEBRTC_TEST_FIELD_TRIAL_H_
+
+#include <string>
+
+namespace webrtc {
+namespace test {
+
+// Parses enabled field trials from a string config, such as the one passed
+// to chrome's argument --force-fieldtrials and initializes webrtc::field_trial
+// with such a config.
+//  E.g.:
+//    "WebRTC-experimentFoo/Enabled/WebRTC-experimentBar/Enabled100kbps/"
+//    Assigns the process to group "Enabled" on WebRTCExperimentFoo trial
+//    and to group "Enabled100kbps" on WebRTCExperimentBar.
+//
+//  E.g. invalid config:
+//    "WebRTC-experiment1/Enabled"  (note missing / separator at the end).
+//
+// Note: This method crashes with an error message if an invalid config is
+// passed to it. That can be used to find out if a binary is parsing the flags.
+void InitFieldTrialsFromString(const std::string& config);
+
+}  // namespace test
+}  // namespace webrtc
+
+#endif  // WEBRTC_TEST_FIELD_TRIAL_H_
diff --git a/test/test.gyp b/test/test.gyp
index 5be3c10..feca0b2 100644
--- a/test/test.gyp
+++ b/test/test.gyp
@@ -64,14 +64,26 @@
       ],
     },
     {
+      'target_name': 'field_trial',
+      'type': 'static_library',
+      'sources': [
+        'field_trial.cc',
+        'field_trial.h',
+      ],
+      'dependencies': [
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
+      ],
+    },
+    {
       'target_name': 'test_main',
       'type': 'static_library',
       'sources': [
         'test_main.cc',
       ],
       'dependencies': [
-	'<(DEPTH)/testing/gtest.gyp:gtest',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        'field_trial',
+        '<(DEPTH)/testing/gtest.gyp:gtest',
+        '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
       ],
     },
     {
@@ -80,12 +92,9 @@
       'dependencies': [
         '<(DEPTH)/testing/gtest.gyp:gtest',
         '<(DEPTH)/testing/gmock.gyp:gmock',
-        '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
       ],
       'sources': [
-        'test_suite.cc',
-        'test_suite.h',
         'testsupport/android/root_path_android.cc',
         'testsupport/android/root_path_android_chromium.cc',
         'testsupport/fileutils.cc',
@@ -128,11 +137,16 @@
       'target_name': 'test_support_main',
       'type': 'static_library',
       'dependencies': [
+        'field_trial',
         'test_support',
-	'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(DEPTH)/testing/gmock.gyp:gmock',
+        '<(DEPTH)/testing/gtest.gyp:gtest',
+        '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
       ],
       'sources': [
         'run_all_unittests.cc',
+        'test_suite.cc',
+        'test_suite.h',
       ],
     },
     {
diff --git a/test/test_main.cc b/test/test_main.cc
index 64109d4..acce96f 100644
--- a/test/test_main.cc
+++ b/test/test_main.cc
@@ -8,14 +8,26 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "gflags/gflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
-
+#include "webrtc/test/field_trial.h"
 #include "webrtc/test/run_tests.h"
 #include "webrtc/test/testsupport/fileutils.h"
 
+DEFINE_string(force_fieldtrials, "",
+    "Field trials control experimental feature code which can be forced. "
+    "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
+    " will assign the group Enable to field trial WebRTC-FooFeature.");
+
 int main(int argc, char* argv[]) {
   ::testing::InitGoogleTest(&argc, argv);
-  webrtc::test::SetExecutablePath(argv[0]);
 
+  // AllowCommandLineParsing allows us to ignore flags passed on to us by
+  // Chromium build bots without having to explicitly disable them.
+  google::AllowCommandLineReparsing();
+  google::ParseCommandLineFlags(&argc, &argv, false);
+
+  webrtc::test::SetExecutablePath(argv[0]);
+  webrtc::test::InitFieldTrialsFromString(FLAGS_force_fieldtrials);
   return webrtc::test::RunAllTests();
 }
diff --git a/test/test_suite.cc b/test/test_suite.cc
index 7cfb856..e88b030 100644
--- a/test/test_suite.cc
+++ b/test/test_suite.cc
@@ -15,9 +15,15 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/test/testsupport/fileutils.h"
 #include "webrtc/test/testsupport/trace_to_stderr.h"
+#include "webrtc/test/field_trial.h"
 
 DEFINE_bool(logs, false, "print logs to stderr");
 
+DEFINE_string(force_fieldtrials, "",
+    "Field trials control experimental feature code which can be forced. "
+    "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
+    " will assign the group Enable to field trial WebRTC-FooFeature.");
+
 namespace webrtc {
 namespace test {
 
@@ -28,6 +34,8 @@
   // Chromium build bots without having to explicitly disable them.
   google::AllowCommandLineReparsing();
   google::ParseCommandLineFlags(&argc, &argv, true);
+
+  webrtc::test::InitFieldTrialsFromString(FLAGS_force_fieldtrials);
 }
 
 TestSuite::~TestSuite() {
diff --git a/video_engine/test/auto_test/source/vie_autotest_main.cc b/video_engine/test/auto_test/source/vie_autotest_main.cc
index a1e45c1..c688e2e 100644
--- a/video_engine/test/auto_test/source/vie_autotest_main.cc
+++ b/video_engine/test/auto_test/source/vie_autotest_main.cc
@@ -13,6 +13,7 @@
 #include "gflags/gflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#include "webrtc/test/field_trial.h"
 #include "webrtc/test/testsupport/fileutils.h"
 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h"
 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest_window_manager_interface.h"
@@ -20,6 +21,10 @@
 
 DEFINE_bool(automated, false, "Run Video engine tests in noninteractive mode.");
 DEFINE_bool(auto_custom_call, false, "Run custom call directly.");
+DEFINE_string(force_fieldtrials, "",
+    "Field trials control experimental feature code which can be forced. "
+    "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
+    " will assign the group Enable to field trial WebRTC-FooFeature.");
 
 static const std::string kStandardTest = "ViEStandardIntegrationTest";
 static const std::string kExtendedTest = "ViEExtendedIntegrationTest";
@@ -48,6 +53,8 @@
   google::AllowCommandLineReparsing();
   // Parse remaining flags:
   google::ParseCommandLineFlags(&argc, &argv, true);
+  // Initialize field trial
+  webrtc::test::InitFieldTrialsFromString(FLAGS_force_fieldtrials);
 
   int result;
   if (FLAGS_automated) {
diff --git a/video_engine/test/auto_test/vie_auto_test.gypi b/video_engine/test/auto_test/vie_auto_test.gypi
index fb611b0..9629166 100644
--- a/video_engine/test/auto_test/vie_auto_test.gypi
+++ b/video_engine/test/auto_test/vie_auto_test.gypi
@@ -22,6 +22,7 @@
         '<(webrtc_root)/test/metrics.gyp:metrics',
         '<(webrtc_root)/test/test.gyp:channel_transport',
         '<(webrtc_root)/test/test.gyp:test_support',
+        '<(webrtc_root)/test/test.gyp:field_trial',
         'video_engine_core',
         'libvietest',
       ],