update_engine: Support DLC Cohorts

UE at the moment doesn't send the correct cohorts to Omaha for DLCs. In
fact, the platform cohorts that are persisted are used for all DLCs.
This is incorrect and this CL fixes it.

```
Example DLC Response:
... cohort="1:7:" cohortname="eve_dlc_pita_canary"...

localhost ~ # ls /var/lib/update_engine/prefs/dlc/pita/omaha-cohort*
/var/lib/update_engine/prefs/dlc/pita/omaha-cohort
/var/lib/update_engine/prefs/dlc/pita/omaha-cohort-name
localhost ~ # cat /var/lib/update_engine/prefs/dlc/pita/omaha-cohort
1:7:
localhost ~ # cat
/var/lib/update_engine/prefs/dlc/pita/omaha-cohort-name
eve_dlc_pita_canary
```

BUG=b:162463872
TEST=FEATURES=test emerge-$B update_engine
TEST=# cros deploy + comment above

Change-Id: Ie503f0a63d3b19a51abb88379cb2e8f85919858b
Reviewed-on: https://chromium-review.googlesource.com/c/aosp/platform/system/update_engine/+/2515072
Tested-by: Jae Hoon Kim <kimjae@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
Commit-Queue: Jae Hoon Kim <kimjae@chromium.org>
diff --git a/cros/omaha_request_action_unittest.cc b/cros/omaha_request_action_unittest.cc
index c3842b8..8d94195 100644
--- a/cros/omaha_request_action_unittest.cc
+++ b/cros/omaha_request_action_unittest.cc
@@ -204,7 +204,13 @@
                 : "") +
            (dlc_app_update
                 ? "<app appid=\"" + request_params.GetDlcAppId(kDlcId1) +
-                      "\" status=\"ok\">"
+                      "\" " +
+                      (include_dlc_cohorts
+                           ? "cohort=\"" + dlc_cohort + "\" cohorthint=\"" +
+                                 dlc_cohorthint + "\" cohortname=\"" +
+                                 dlc_cohortname + "\" "
+                           : "") +
+                      "status=\"ok\">"
                       "<updatecheck status=\"ok\"><urls><url codebase=\"" +
                       codebase + "\"/><url codebase=\"" + codebase2 +
                       "\"/></urls><manifest version=\"" + version +
@@ -216,7 +222,13 @@
                 : "") +
            (dlc_app_no_update
                 ? "<app appid=\"" + request_params.GetDlcAppId(kDlcId2) +
-                      "\"><updatecheck status=\"noupdate\"/></app>"
+                      +"\" " +
+                      (include_dlc_cohorts
+                           ? "cohort=\"" + dlc_cohort + "\" cohorthint=\"" +
+                                 dlc_cohorthint + "\" cohortname=\"" +
+                                 dlc_cohortname + "\" "
+                           : "") +
+                      "><updatecheck status=\"noupdate\"/></app>"
                 : "") +
            "</response>";
   }
@@ -252,6 +264,11 @@
   string cohort = "";
   string cohorthint = "";
   string cohortname = "";
+  // Whether to include Omaha cohorts for DLC apps.
+  bool include_dlc_cohorts = false;
+  string dlc_cohort = "";
+  string dlc_cohorthint = "";
+  string dlc_cohortname = "";
 
   // Whether to include the CrOS <!ENTITY> in the XML response.
   bool include_entity = false;
@@ -1240,8 +1257,16 @@
   fake_update_response_.cohort = "s/154454/8479665";
   fake_update_response_.cohorthint = "please-put-me-on-beta";
   fake_update_response_.cohortname = "stable";
+  request_params_.set_dlc_apps_params(
+      {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
+  fake_update_response_.dlc_app_update = true;
+  fake_update_response_.include_dlc_cohorts = true;
+  fake_update_response_.dlc_cohort = "s/154454/8479665/dlc";
+  fake_update_response_.dlc_cohorthint = "please-put-me-on-beta-dlc";
+  fake_update_response_.dlc_cohortname = "stable-dlc";
   tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
 
+  EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
   ASSERT_TRUE(TestUpdateCheck());
 
   string value;
@@ -1253,18 +1278,52 @@
 
   EXPECT_TRUE(fake_prefs_.GetString(kPrefsOmahaCohortName, &value));
   EXPECT_EQ(fake_update_response_.cohortname, value);
+
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohort, value);
+
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
+
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohortname, value);
 }
 
 TEST_F(OmahaRequestActionTest, CohortsAreUpdated) {
   EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohort, "old_value"));
   EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohortHint, "old_hint"));
   EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohortName, "old_name"));
+  const string dlc_cohort_key =
+      fake_prefs_.CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort});
+  const string dlc_cohort_hint_key = fake_prefs_.CreateSubKey(
+      {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint});
+  const string dlc_cohort_name_key = fake_prefs_.CreateSubKey(
+      {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName});
+  request_params_.set_dlc_apps_params(
+      {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
+  EXPECT_TRUE(fake_prefs_.SetString(dlc_cohort_key, "old_value_dlc"));
+  EXPECT_TRUE(fake_prefs_.SetString(dlc_cohort_hint_key, "old_hint_dlc"));
+  EXPECT_TRUE(fake_prefs_.SetString(dlc_cohort_name_key, "old_name_dlc"));
   fake_update_response_.include_cohorts = true;
   fake_update_response_.cohort = "s/154454/8479665";
   fake_update_response_.cohorthint = "please-put-me-on-beta";
   fake_update_response_.cohortname = "";
+  fake_update_response_.dlc_app_update = true;
+  fake_update_response_.include_dlc_cohorts = true;
+  fake_update_response_.dlc_cohort = "s/154454/8479665/dlc";
+  fake_update_response_.dlc_cohorthint = "please-put-me-on-beta-dlc";
+  fake_update_response_.dlc_cohortname = "";
   tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
 
+  EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
   ASSERT_TRUE(TestUpdateCheck());
 
   string value;
@@ -1275,12 +1334,23 @@
   EXPECT_EQ(fake_update_response_.cohorthint, value);
 
   EXPECT_FALSE(fake_prefs_.GetString(kPrefsOmahaCohortName, &value));
+
+  EXPECT_TRUE(fake_prefs_.GetString(dlc_cohort_key, &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohort, value);
+
+  EXPECT_TRUE(fake_prefs_.GetString(dlc_cohort_hint_key, &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
+
+  EXPECT_FALSE(fake_prefs_.GetString(dlc_cohort_name_key, &value));
 }
 
 TEST_F(OmahaRequestActionTest, CohortsAreNotModifiedWhenMissing) {
   tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
 
   EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohort, "old_value"));
+  const string dlc_cohort_key =
+      fake_prefs_.CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort});
+  EXPECT_TRUE(fake_prefs_.SetString(dlc_cohort_key, "old_value_dlc"));
   ASSERT_TRUE(TestUpdateCheck());
 
   string value;
@@ -1289,6 +1359,18 @@
 
   EXPECT_FALSE(fake_prefs_.GetString(kPrefsOmahaCohortHint, &value));
   EXPECT_FALSE(fake_prefs_.GetString(kPrefsOmahaCohortName, &value));
+
+  EXPECT_TRUE(fake_prefs_.GetString(dlc_cohort_key, &value));
+  EXPECT_EQ("old_value_dlc", value);
+
+  EXPECT_FALSE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint}),
+      &value));
+  EXPECT_FALSE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName}),
+      &value));
 }
 
 TEST_F(OmahaRequestActionTest, CohortsArePersistedWhenNoUpdate) {
@@ -1319,8 +1401,18 @@
   fake_update_response_.cohort = "s/154454/8479665";
   fake_update_response_.cohorthint = "please-put-me-on-beta";
   fake_update_response_.cohortname = "stable";
+  request_params_.set_dlc_apps_params(
+      {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}},
+       {request_params_.GetDlcAppId(kDlcId2), {.name = kDlcId2}}});
+  fake_update_response_.dlc_app_update = true;
+  fake_update_response_.dlc_app_no_update = true;
+  fake_update_response_.include_dlc_cohorts = true;
+  fake_update_response_.dlc_cohort = "s/154454/8479665/dlc";
+  fake_update_response_.dlc_cohorthint = "please-put-me-on-beta-dlc";
+  fake_update_response_.dlc_cohortname = "stable-dlc";
   tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
 
+  EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
   ASSERT_TRUE(TestUpdateCheck());
 
   string value;
@@ -1332,6 +1424,37 @@
 
   EXPECT_TRUE(fake_prefs_.GetString(kPrefsOmahaCohortName, &value));
   EXPECT_EQ(fake_update_response_.cohortname, value);
+
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohort, value);
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey({kDlcPrefsSubDir, kDlcId2, kPrefsOmahaCohort}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohort, value);
+
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId2, kPrefsOmahaCohortHint}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
+
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohortname, value);
+  EXPECT_TRUE(fake_prefs_.GetString(
+      fake_prefs_.CreateSubKey(
+          {kDlcPrefsSubDir, kDlcId2, kPrefsOmahaCohortName}),
+      &value));
+  EXPECT_EQ(fake_update_response_.dlc_cohortname, value);
 }
 
 TEST_F(OmahaRequestActionTest, NoOutputPipeTest) {