Updater: Create test updater binaries that have an offset version.

These build targets will generate an updater at a.b.c.(10 * d + 1).

Bug: 1206314
Change-Id: I7e5ea56c6d392f6f1b0047d7a00791e6e0b4acdb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2874250
Auto-Submit: Joshua Pawlicki <[email protected]>
Commit-Queue: Joshua Pawlicki <[email protected]>
Reviewed-by: Sorin Jianu <[email protected]>
Cr-Commit-Position: refs/heads/master@{#880513}
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 628757a..13793d6 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -250,11 +250,22 @@
     }
   }
 
-  process_version("version_header") {
+  source_set("version_header") {
+    sources = [ "updater_version.h" ]
+  }
+
+  process_version("updater_version_cc") {
     sources = [ "//chrome/VERSION" ]
 
-    template_file = "updater_version.h.in"
-    output = "$target_gen_dir/updater_version.h"
+    template_file = "updater_version.cc.in"
+    output = "$target_gen_dir/updater_version.cc"
+  }
+
+  process_version("updater_version_cc_offset") {
+    sources = [ "//chrome/VERSION" ]
+
+    template_file = "updater_version_offset.cc.in"
+    output = "$target_gen_dir/updater_version_offset.cc"
   }
 
   process_version("branding_header") {
@@ -367,6 +378,7 @@
       ":lib",
       ":updater",
       ":updater_tests_support",
+      ":updater_version_cc",
       ":version_header",
       "//base",
       "//base/test:test_support",
diff --git a/chrome/updater/app/app_install.cc b/chrome/updater/app/app_install.cc
index 3db7603..a397ca6 100644
--- a/chrome/updater/app/app_install.cc
+++ b/chrome/updater/app/app_install.cc
@@ -100,7 +100,7 @@
                                 const base::Version& version) {
   VLOG_IF(1, (version.IsValid()))
       << "Found active version: " << version.GetString();
-  if (version.IsValid() && version >= base::Version(UPDATER_VERSION_STRING)) {
+  if (version.IsValid() && version >= base::Version(kUpdaterVersion)) {
     splash_screen_->Dismiss(base::BindOnce(&AppInstall::MaybeInstallApp, this));
     return;
   }
diff --git a/chrome/updater/app/app_install_mac.mm b/chrome/updater/app/app_install_mac.mm
index 50e18d3..d7a83ff7 100644
--- a/chrome/updater/app/app_install_mac.mm
+++ b/chrome/updater/app/app_install_mac.mm
@@ -16,7 +16,8 @@
 
 void AppInstall::WakeCandidateDone() {
   PollLaunchctlList(
-      updater_scope(), kUpdateServiceLaunchdName, LaunchctlPresence::kPresent,
+      updater_scope(), GetUpdateServiceLaunchdName(),
+      LaunchctlPresence::kPresent,
       base::TimeDelta::FromSeconds(kWaitForLaunchctlUpdateSec),
       base::BindOnce([](scoped_refptr<AppInstall> installer,
                         bool unused) { installer->MaybeInstallApp(); },
diff --git a/chrome/updater/app/app_server.cc b/chrome/updater/app/app_server.cc
index a7f1534..3edd378 100644
--- a/chrome/updater/app/app_server.cc
+++ b/chrome/updater/app/app_server.cc
@@ -56,7 +56,7 @@
                           kErrorFailedToLockPrefsMutex);
   }
 
-  const base::Version this_version(UPDATER_VERSION_STRING);
+  const base::Version this_version(kUpdaterVersion);
   const base::Version active_version(global_prefs->GetActiveVersion());
 
   VLOG(2) << "This version: " << this_version.GetString()
@@ -99,7 +99,7 @@
   if (config_)
     PrefsCommitPendingWrites(config_->GetPrefService());
   if (uninstall_self_) {
-    VLOG(1) << "Uninstalling version " << UPDATER_VERSION_STRING;
+    VLOG(1) << "Uninstalling version " << kUpdaterVersion;
     UninstallSelf();
   } else {
     MaybeUninstall();
@@ -157,7 +157,7 @@
   bool result = SwapRPCInterfaces();
   if (!result)
     return false;
-  global_prefs->SetActiveVersion(UPDATER_VERSION_STRING);
+  global_prefs->SetActiveVersion(kUpdaterVersion);
   global_prefs->SetSwapping(false);
   PrefsCommitPendingWrites(global_prefs->GetPrefService());
   return true;
diff --git a/chrome/updater/app/app_server_unittest.cc b/chrome/updater/app/app_server_unittest.cc
index 89a21b9..a850d46 100644
--- a/chrome/updater/app/app_server_unittest.cc
+++ b/chrome/updater/app/app_server_unittest.cc
@@ -138,7 +138,7 @@
   }
   std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
   EXPECT_FALSE(global_prefs->GetSwapping());
-  EXPECT_EQ(global_prefs->GetActiveVersion(), UPDATER_VERSION_STRING);
+  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
 }
 
 TEST_F(AppServerTestCase, InstallAutoPromotes) {
@@ -155,7 +155,7 @@
   }
   std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
   EXPECT_FALSE(global_prefs->GetSwapping());
-  EXPECT_EQ(global_prefs->GetActiveVersion(), UPDATER_VERSION_STRING);
+  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
 }
 
 TEST_F(AppServerTestCase, SelfPromoteFails) {
@@ -181,7 +181,7 @@
 TEST_F(AppServerTestCase, ActiveDutyAlready) {
   {
     std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
-    global_prefs->SetActiveVersion(UPDATER_VERSION_STRING);
+    global_prefs->SetActiveVersion(kUpdaterVersion);
     PrefsCommitPendingWrites(global_prefs->GetPrefService());
     std::unique_ptr<LocalPrefs> local_prefs = CreateLocalPrefs();
     local_prefs->SetQualified(true);
@@ -198,13 +198,13 @@
   }
   std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
   EXPECT_FALSE(global_prefs->GetSwapping());
-  EXPECT_EQ(global_prefs->GetActiveVersion(), UPDATER_VERSION_STRING);
+  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
 }
 
 TEST_F(AppServerTestCase, StateDirty) {
   {
     std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
-    global_prefs->SetActiveVersion(UPDATER_VERSION_STRING);
+    global_prefs->SetActiveVersion(kUpdaterVersion);
     global_prefs->SetSwapping(true);
     PrefsCommitPendingWrites(global_prefs->GetPrefService());
     std::unique_ptr<LocalPrefs> local_prefs = CreateLocalPrefs();
@@ -223,13 +223,13 @@
   }
   std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
   EXPECT_FALSE(global_prefs->GetSwapping());
-  EXPECT_EQ(global_prefs->GetActiveVersion(), UPDATER_VERSION_STRING);
+  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
 }
 
 TEST_F(AppServerTestCase, StateDirtySwapFails) {
   {
     std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
-    global_prefs->SetActiveVersion(UPDATER_VERSION_STRING);
+    global_prefs->SetActiveVersion(kUpdaterVersion);
     global_prefs->SetSwapping(true);
     PrefsCommitPendingWrites(global_prefs->GetPrefService());
     std::unique_ptr<LocalPrefs> local_prefs = CreateLocalPrefs();
@@ -247,7 +247,7 @@
   }
   std::unique_ptr<GlobalPrefs> global_prefs = CreateGlobalPrefs();
   EXPECT_TRUE(global_prefs->GetSwapping());
-  EXPECT_EQ(global_prefs->GetActiveVersion(), UPDATER_VERSION_STRING);
+  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
 }
 
 }  // namespace updater
diff --git a/chrome/updater/app/server/win/com_classes.cc b/chrome/updater/app/server/win/com_classes.cc
index 4efc4f85..4618f31a 100644
--- a/chrome/updater/app/server/win/com_classes.cc
+++ b/chrome/updater/app/server/win/com_classes.cc
@@ -104,10 +104,7 @@
   // non-blocking function of `UpdateServiceImpl`. This results in some
   // code duplication but it avoids the complexities of making this function
   // non-blocking.
-  *version =
-      base::win::ScopedBstr(
-          base::UTF8ToWide(base::Version(UPDATER_VERSION_STRING).GetString()))
-          .Release();
+  *version = base::win::ScopedBstr(kUpdaterVersionUtf16).Release();
   return S_OK;
 }
 
diff --git a/chrome/updater/device_management/dm_client.cc b/chrome/updater/device_management/dm_client.cc
index 82b679b..a0d73415 100644
--- a/chrome/updater/device_management/dm_client.cc
+++ b/chrome/updater/device_management/dm_client.cc
@@ -16,6 +16,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/sequence_checker.h"
+#include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/threading/sequenced_task_runner_handle.h"
@@ -78,7 +79,7 @@
   }
 
   std::string GetAgentParameter() const override {
-    return "Updater-" UPDATER_VERSION_STRING;
+    return base::StrCat({"Updater-", kUpdaterVersion});
   }
 
   std::string GetPlatformParameter() const override;
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn
index 19868a6..b1d0aad 100644
--- a/chrome/updater/mac/BUILD.gn
+++ b/chrome/updater/mac/BUILD.gn
@@ -63,6 +63,22 @@
     ":network_fetcher_sources",
     ":updater_setup_sources",
     "//chrome/updater:lib",
+    "//chrome/updater:updater_version_cc",
+  ]
+}
+
+mac_app_bundle("updater_bundle_test_v2") {
+  info_plist_target = ":updater_plist"
+  output_name = updater_product_full_name + "_Test_V2"
+  extra_substitutions =
+      [ "MAC_BUNDLE_IDENTIFIER=$mac_updater_bundle_identifier" ]
+
+  sources = [ "main.cc" ]
+  deps = [
+    ":network_fetcher_sources",
+    ":updater_setup_sources",
+    "//chrome/updater:lib",
+    "//chrome/updater:updater_version_cc_offset",
   ]
 }
 
diff --git a/chrome/updater/mac/mac_util.h b/chrome/updater/mac/mac_util.h
index c548c46a..f17253d 100644
--- a/chrome/updater/mac/mac_util.h
+++ b/chrome/updater/mac/mac_util.h
@@ -42,7 +42,7 @@
     const base::Version& version);
 
 // The same as GetVersionedUpdaterFolderPathForVersion, where the version is
-// UPDATER_VERSION_STRING.
+// kUpdaterVersion.
 base::Optional<base::FilePath> GetVersionedUpdaterFolderPath(
     UpdaterScope scope);
 
diff --git a/chrome/updater/mac/mac_util.mm b/chrome/updater/mac/mac_util.mm
index 1e4b70e1..64bf886 100644
--- a/chrome/updater/mac/mac_util.mm
+++ b/chrome/updater/mac/mac_util.mm
@@ -96,7 +96,7 @@
   base::Optional<base::FilePath> path = GetUpdaterFolderPath(scope);
   if (!path)
     return base::nullopt;
-  return path->AppendASCII(UPDATER_VERSION_STRING);
+  return path->AppendASCII(kUpdaterVersion);
 }
 
 base::Optional<base::FilePath> GetExecutableFolderPathForVersion(
diff --git a/chrome/updater/mac/xpc_service_names.h b/chrome/updater/mac/xpc_service_names.h
index dc224b4..1fe356a 100644
--- a/chrome/updater/mac/xpc_service_names.h
+++ b/chrome/updater/mac/xpc_service_names.h
@@ -10,8 +10,8 @@
 
 namespace updater {
 
-extern const char kUpdateServiceInternalLaunchdName[];
-extern const char kUpdateServiceLaunchdName[];
+std::string GetUpdateServiceLaunchdName();
+std::string GetUpdateServiceInternalLaunchdName();
 
 base::ScopedCFTypeRef<CFStringRef> CopyUpdateServiceLaunchdName();
 base::ScopedCFTypeRef<CFStringRef> CopyWakeLaunchdName();
diff --git a/chrome/updater/mac/xpc_service_names.mm b/chrome/updater/mac/xpc_service_names.mm
index c3cda02..cf8510b 100644
--- a/chrome/updater/mac/xpc_service_names.mm
+++ b/chrome/updater/mac/xpc_service_names.mm
@@ -13,21 +13,33 @@
 
 namespace updater {
 
-const char kUpdateServiceInternalLaunchdName[] =
-    MAC_BUNDLE_IDENTIFIER_STRING ".update-internal." UPDATER_VERSION_STRING;
+namespace {
+
+const char kUpdateServiceInternalLaunchdPrefix[] =
+    MAC_BUNDLE_IDENTIFIER_STRING ".update-internal.";
 const char kUpdateServiceLaunchdName[] = MAC_BUNDLE_IDENTIFIER_STRING ".update";
 
+}  // namespace
+
+std::string GetUpdateServiceLaunchdName() {
+  return kUpdateServiceLaunchdName;
+}
+
+std::string GetUpdateServiceInternalLaunchdName() {
+  return base::StrCat({kUpdateServiceInternalLaunchdPrefix, kUpdaterVersion});
+}
+
 base::ScopedCFTypeRef<CFStringRef> CopyUpdateServiceLaunchdName() {
   return base::SysUTF8ToCFStringRef(kUpdateServiceLaunchdName);
 }
 
 base::ScopedCFTypeRef<CFStringRef> CopyWakeLaunchdName() {
-  return base::SysUTF8ToCFStringRef(MAC_BUNDLE_IDENTIFIER_STRING
-                                    ".wake." UPDATER_VERSION_STRING);
+  return base::SysUTF8ToCFStringRef(
+      base::StrCat({MAC_BUNDLE_IDENTIFIER_STRING ".wake.", kUpdaterVersion}));
 }
 
 base::ScopedCFTypeRef<CFStringRef> CopyUpdateServiceInternalLaunchdName() {
-  return base::SysUTF8ToCFStringRef(kUpdateServiceInternalLaunchdName);
+  return base::SysUTF8ToCFStringRef(GetUpdateServiceInternalLaunchdName());
 }
 
 base::scoped_nsobject<NSString> GetUpdateServiceLaunchdLabel() {
diff --git a/chrome/updater/setup_mac.mm b/chrome/updater/setup_mac.mm
index 4b6733d..66c1d590 100644
--- a/chrome/updater/setup_mac.mm
+++ b/chrome/updater/setup_mac.mm
@@ -27,7 +27,7 @@
     return;
   }
   PollLaunchctlList(
-      scope, kUpdateServiceInternalLaunchdName, LaunchctlPresence::kPresent,
+      scope, GetUpdateServiceInternalLaunchdName(), LaunchctlPresence::kPresent,
       base::TimeDelta::FromSeconds(kWaitForLaunchctlUpdateSec),
       base::BindOnce(
           [](base::OnceCallback<void(int)> callback, bool service_exists) {
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index e547738..b657eab 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -157,7 +157,7 @@
 TEST_F(IntegrationTest, InstallUninstall) {
   Install();
   ExpectInstalled();
-  ExpectVersionActive(UPDATER_VERSION_STRING);
+  ExpectVersionActive(kUpdaterVersion);
   ExpectActiveUpdater();
 #if defined(OS_WIN)
   // Tests the COM registration after the install. For now, tests that the
@@ -172,7 +172,7 @@
   Install();
   ExpectInstalled();
   SetupFakeUpdaterHigherVersion();
-  ExpectVersionNotActive(UPDATER_VERSION_STRING);
+  ExpectVersionNotActive(kUpdaterVersion);
   SleepFor(2);
 
   RunWake(0);
@@ -184,7 +184,7 @@
 
   ExpectCandidateUninstalled();
   // The candidate uninstall should not have altered global prefs.
-  ExpectVersionNotActive(UPDATER_VERSION_STRING);
+  ExpectVersionNotActive(kUpdaterVersion);
   ExpectVersionNotActive("0.0.0.0");
 
   Uninstall();
@@ -194,7 +194,7 @@
 TEST_F(IntegrationTest, RegisterTestApp) {
   RegisterTestApp();
   ExpectInstalled();
-  ExpectVersionActive(UPDATER_VERSION_STRING);
+  ExpectVersionActive(kUpdaterVersion);
   ExpectActiveUpdater();
   Uninstall();
 }
@@ -240,7 +240,7 @@
 TEST_F(IntegrationTest, UnregisterUninstalledApp) {
   RegisterTestApp();
   ExpectInstalled();
-  ExpectVersionActive(UPDATER_VERSION_STRING);
+  ExpectVersionActive(kUpdaterVersion);
   ExpectActiveUpdater();
 
   RegisterApp("test1");
@@ -262,7 +262,7 @@
 TEST_F(IntegrationTest, UninstallUpdaterWhenAllAppsUninstalled) {
   RegisterTestApp();
   ExpectInstalled();
-  ExpectVersionActive(UPDATER_VERSION_STRING);
+  ExpectVersionActive(kUpdaterVersion);
   ExpectActiveUpdater();
 
   SetExistenceCheckerPath(kTestAppId,
@@ -279,7 +279,7 @@
 TEST_F(IntegrationTest, UnregisterUnownedApp) {
   Install();
   ExpectInstalled();
-  ExpectVersionActive(UPDATER_VERSION_STRING);
+  ExpectVersionActive(kUpdaterVersion);
   ExpectActiveUpdater();
 
   RegisterApp("test1");
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc
index 5f887b0..9b3ebd1 100644
--- a/chrome/updater/test/integration_tests_impl.cc
+++ b/chrome/updater/test/integration_tests_impl.cc
@@ -145,7 +145,7 @@
 void SetupFakeUpdaterVersion(UpdaterScope scope, int offset) {
   ASSERT_NE(offset, 0);
   std::vector<uint32_t> components =
-      base::Version(UPDATER_VERSION_STRING).components();
+      base::Version(kUpdaterVersion).components();
   base::CheckedNumeric<uint32_t> new_version = components[0];
   new_version += offset;
   ASSERT_TRUE(new_version.AssignIfValid(&components[0]));
diff --git a/chrome/updater/test/integration_tests_mac.mm b/chrome/updater/test/integration_tests_mac.mm
index 529d5888..ff45540 100644
--- a/chrome/updater/test/integration_tests_mac.mm
+++ b/chrome/updater/test/integration_tests_mac.mm
@@ -193,8 +193,8 @@
   if (path)
     EXPECT_FALSE(base::PathExists(*path));
 
-  ExpectServiceAbsent(scope, kUpdateServiceLaunchdName);
-  ExpectServiceAbsent(scope, kUpdateServiceInternalLaunchdName);
+  ExpectServiceAbsent(scope, GetUpdateServiceLaunchdName());
+  ExpectServiceAbsent(scope, GetUpdateServiceInternalLaunchdName());
 }
 
 void ExpectInstalled(UpdaterScope scope) {
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index be67fce..62ff98b 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -63,7 +63,7 @@
     return base::nullopt;
   return app_data_dir.AppendASCII(COMPANY_SHORTNAME_STRING)
       .AppendASCII(PRODUCT_FULLNAME_STRING)
-      .AppendASCII(UPDATER_VERSION_STRING);
+      .AppendASCII(kUpdaterVersion);
 }
 
 std::wstring GetAppClientStateKey(const std::string& id) {
diff --git a/chrome/updater/test/test_app/BUILD.gn b/chrome/updater/test/test_app/BUILD.gn
index b192ed19..6f829ef 100644
--- a/chrome/updater/test/test_app/BUILD.gn
+++ b/chrome/updater/test/test_app/BUILD.gn
@@ -63,6 +63,7 @@
     "//base",
     "//chrome/updater:base",
     "//chrome/updater:lib",
+    "//chrome/updater:updater_version_cc",
     "//chrome/updater:version_header",
     "//components/update_client:update_client",
   ]
diff --git a/chrome/updater/update_service.h b/chrome/updater/update_service.h
index 8beba15..4481292 100644
--- a/chrome/updater/update_service.h
+++ b/chrome/updater/update_service.h
@@ -162,8 +162,8 @@
       base::OnceCallback<void(const RegistrationResponse&)>;
 
   // Returns the version of the active updater. In the current implementation,
-  // this value corresponds to UPDATER_VERSION. The version object is invalid
-  // ]if an error occurs.
+  // this value corresponds to kUpdaterVersion. The version object is invalid
+  // if an error occurs.
   virtual void GetVersion(
       base::OnceCallback<void(const base::Version&)>) const = 0;
 
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc
index 6af967d4..9543d9c 100644
--- a/chrome/updater/update_service_impl.cc
+++ b/chrome/updater/update_service_impl.cc
@@ -161,8 +161,8 @@
     base::OnceCallback<void(const base::Version&)> callback) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   main_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback),
-                                base::Version(UPDATER_VERSION_STRING)));
+      FROM_HERE,
+      base::BindOnce(std::move(callback), base::Version(kUpdaterVersion)));
 }
 
 void UpdateServiceImpl::RegisterApp(
@@ -174,7 +174,7 @@
   if (!base::Contains(persisted_data_->GetAppIds(), kUpdaterAppId)) {
     RegistrationRequest updater_request;
     updater_request.app_id = kUpdaterAppId;
-    updater_request.version = base::Version(UPDATER_VERSION_STRING);
+    updater_request.version = base::Version(kUpdaterVersion);
     persisted_data_->RegisterApp(updater_request);
     update_client_->SendRegistrationPing(
         updater_request.app_id, updater_request.version, base::DoNothing());
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc
index c3bfca8..2fbc7df 100644
--- a/chrome/updater/updater.cc
+++ b/chrome/updater/updater.cc
@@ -67,7 +67,7 @@
                        true,    // enable_thread_id
                        true,    // enable_timestamp
                        false);  // enable_tickcount
-  VLOG(1) << "Version " << UPDATER_VERSION_STRING << ", log file "
+  VLOG(1) << "Version " << kUpdaterVersion << ", log file "
           << settings.log_file_path;
 }
 
@@ -80,7 +80,7 @@
     VLOG(1) << "Crash reporting initialized.";
   else
     VLOG(1) << "Crash reporting is not available.";
-  StartCrashReporter(UPDATER_VERSION_STRING);
+  StartCrashReporter(kUpdaterVersion);
 }
 
 }  // namespace
diff --git a/chrome/updater/updater_version.cc.in b/chrome/updater/updater_version.cc.in
new file mode 100644
index 0000000..2948582
--- /dev/null
+++ b/chrome/updater/updater_version.cc.in
@@ -0,0 +1,8 @@
+// Copyright 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 "chrome/updater/updater_version.h"
+
+const char kUpdaterVersion[] = "@MAJOR@.@MINOR@.@BUILD@.@PATCH@";
+const wchar_t kUpdaterVersionUtf16[] = L"@MAJOR@.@MINOR@.@BUILD@.@PATCH@";
diff --git a/chrome/updater/updater_version.h b/chrome/updater/updater_version.h
new file mode 100644
index 0000000..f1c7238
--- /dev/null
+++ b/chrome/updater/updater_version.h
@@ -0,0 +1,11 @@
+// Copyright 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.
+
+#ifndef CHROME_UPDATER_UPDATER_VERSION_H_
+#define CHROME_UPDATER_UPDATER_VERSION_H_
+
+extern const char kUpdaterVersion[];
+extern const wchar_t kUpdaterVersionUtf16[];
+
+#endif  // CHROME_UPDATER_UPDATER_VERSION_H_
diff --git a/chrome/updater/updater_version.h.in b/chrome/updater/updater_version.h.in
deleted file mode 100644
index 9f105709..0000000
--- a/chrome/updater/updater_version.h.in
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2019 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.
-
-// Version Information
-
-#define UPDATER_VERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
-#define UPDATER_VERSION_STRING "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
diff --git a/chrome/updater/updater_version_offset.cc.in b/chrome/updater/updater_version_offset.cc.in
new file mode 100644
index 0000000..e5d0355
--- /dev/null
+++ b/chrome/updater/updater_version_offset.cc.in
@@ -0,0 +1,11 @@
+// Copyright 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 "chrome/updater/updater_version.h"
+
+// The offset version is major.minor.build.(patch * 10 + 1). This is used
+// to build a copy of the updater at a different version for the purposes of
+// testing.
+const char kUpdaterVersion[] = "@MAJOR@.@MINOR@.@BUILD@.@PATCH@1";
+const wchar_t kUpdaterVersionUtf16[] = L"@MAJOR@.@MINOR@.@BUILD@.@PATCH@1";
diff --git a/chrome/updater/util.cc b/chrome/updater/util.cc
index fbacbaf..e5c892d 100644
--- a/chrome/updater/util.cc
+++ b/chrome/updater/util.cc
@@ -122,7 +122,7 @@
     return base::nullopt;
   }
 
-  const auto versioned_dir = product_dir->AppendASCII(UPDATER_VERSION_STRING);
+  const auto versioned_dir = product_dir->AppendASCII(kUpdaterVersion);
   if (!base::CreateDirectory(versioned_dir)) {
     LOG(ERROR) << "Can't create versioned directory.";
     return base::nullopt;
diff --git a/chrome/updater/win/BUILD.gn b/chrome/updater/win/BUILD.gn
index 23da1a7..94849fa 100644
--- a/chrome/updater/win/BUILD.gn
+++ b/chrome/updater/win/BUILD.gn
@@ -38,6 +38,28 @@
     ":version_resources",
     "//build/win:default_exe_manifest",
     "//chrome/updater:lib",
+    "//chrome/updater:updater_version_cc",
+    "//chrome/updater/win/ui:ui_resources",
+  ]
+
+  data_deps = [ ":uninstall.cmd" ]
+}
+
+executable("updater_exe_test_v2") {
+  sources = [
+    "main.cc",
+    "updater.rc",
+  ]
+
+  configs -= [ "//build/config/compiler:cet_shadow_stack" ]
+  configs += [ "//build/config/win:windowed" ]
+
+  deps = [
+    ":app_install_controller",
+    ":version_resources",
+    "//build/win:default_exe_manifest",
+    "//chrome/updater:lib",
+    "//chrome/updater:updater_version_cc_offset",
     "//chrome/updater/win/ui:ui_resources",
   ]
 
diff --git a/chrome/updater/win/setup/setup.cc b/chrome/updater/win/setup/setup.cc
index 4d29710..3db7701 100644
--- a/chrome/updater/win/setup/setup.cc
+++ b/chrome/updater/win/setup/setup.cc
@@ -160,9 +160,9 @@
        {GetRegistryKeyClientsUpdater(), GetRegistryKeyClientStateUpdater()}) {
     install_list->AddCreateRegKeyWorkItem(key, key_path,
                                           WorkItem::kWow64Default);
-    install_list->AddSetRegValueWorkItem(
-        key, key_path, WorkItem::kWow64Default, kRegValuePV,
-        base::ASCIIToWide(UPDATER_VERSION_STRING), true);
+    install_list->AddSetRegValueWorkItem(key, key_path, WorkItem::kWow64Default,
+                                         kRegValuePV, kUpdaterVersionUtf16,
+                                         true);
     install_list->AddSetRegValueWorkItem(
         key, key_path, WorkItem::kWow64Default, kRegValueName,
         base::ASCIIToWide(PRODUCT_FULLNAME_STRING), true);
diff --git a/chrome/updater/win/test/BUILD.gn b/chrome/updater/win/test/BUILD.gn
index fd7f1dc..928038e7 100644
--- a/chrome/updater/win/test/BUILD.gn
+++ b/chrome/updater/win/test/BUILD.gn
@@ -61,5 +61,6 @@
     "//base/test:test_support",
     "//build/win:default_exe_manifest",
     "//chrome/updater:lib",
+    "//chrome/updater:updater_version_cc",
   ]
 }