Create project context from project_id instead of name.

This will be used in Fuchsia to implement the CreateLoggerFromProjectId
methods being added in fxr/340058.

Bug: 36823
Change-Id: I13ea1241137ac5587c24c7f492332cc99febe322
diff --git a/src/logger/project_context_factory.cc b/src/logger/project_context_factory.cc
index 25e4170..1d476fa 100644
--- a/src/logger/project_context_factory.cc
+++ b/src/logger/project_context_factory.cc
@@ -64,6 +64,23 @@
                                           project_config, release_stage);
 }
 
+std::unique_ptr<ProjectContext> ProjectContextFactory::NewProjectContext(
+    uint32_t customer_id, uint32_t project_id, ReleaseStage release_stage) {
+  if (project_configs_ == nullptr) {
+    return nullptr;
+  }
+  const auto* customer_config = project_configs_->GetCustomerConfig(customer_id);
+  if (!customer_config) {
+    return nullptr;
+  }
+  const auto* project_config = project_configs_->GetProjectConfig(customer_id, project_id);
+  if (!project_config) {
+    return nullptr;
+  }
+  return std::make_unique<ProjectContext>(customer_id, customer_config->customer_name(),
+                                          project_config, release_stage);
+}
+
 std::unique_ptr<ProjectContext> ProjectContextFactory::TakeSingleProjectContext(
     ReleaseStage release_stage) {
   if (!is_single_project()) {
diff --git a/src/logger/project_context_factory.h b/src/logger/project_context_factory.h
index c4052ea..03a7599 100644
--- a/src/logger/project_context_factory.h
+++ b/src/logger/project_context_factory.h
@@ -85,6 +85,17 @@
                                                     const std::string& project_name,
                                                     ReleaseStage release_stage = GA);
 
+  // Returns a ProjectContext for the project with the given
+  // (customer_id, project_id), if the factory's CobaltRegistry is valid and
+  // contains that project. The ProjectContext will be marked as being for a
+  // client at the given |release_stage|. Returns nullptr otherwise.
+  //
+  // Important: The returned ProjectContext contains a pointer into this
+  // factory's CobaltRegistry. This ProjectContextFactory must remain alive as
+  // long as the returned ProjectContext is being used.
+  std::unique_ptr<ProjectContext> NewProjectContext(uint32_t customer_id, uint32_t project_id,
+                                                    ReleaseStage release_stage = GA);
+
   // If is_single_project() is true, then this returns a
   // ProjectContext for the unique Cobalt 1.0 project contained in the factory's
   // CobaltRegistry and removes the corresponding data from the registry,
diff --git a/src/logger/project_context_factory_test.cc b/src/logger/project_context_factory_test.cc
index 6e842cc..146aaa4 100644
--- a/src/logger/project_context_factory_test.cc
+++ b/src/logger/project_context_factory_test.cc
@@ -54,7 +54,9 @@
   EXPECT_FALSE(factory.is_valid());
   EXPECT_FALSE(factory.is_single_project());
   EXPECT_EQ(nullptr, factory.NewProjectContext("Customer11", "Project11"));
+  EXPECT_EQ(nullptr, factory.NewProjectContext(11, 1));
   EXPECT_EQ(nullptr, factory.NewProjectContext("Customer22", "Project22"));
+  EXPECT_EQ(nullptr, factory.NewProjectContext(22, 1));
   EXPECT_EQ(nullptr, factory.TakeSingleProjectContext());
 }
 
@@ -71,7 +73,9 @@
 
   // Registry A contains Cobalt 1.0 project 11, but no project 22
   EXPECT_NE(nullptr, factory.NewProjectContext("Customer11", "Project11").get());
+  EXPECT_NE(nullptr, factory.NewProjectContext(11, 1).get());
   EXPECT_EQ(nullptr, factory.NewProjectContext("Customer22", "Project22").get());
+  EXPECT_EQ(nullptr, factory.NewProjectContext(22, 1).get());
 
   // Registry A does contain a single Cobalt 1.0 project.
   auto context = factory.TakeSingleProjectContext();
@@ -83,6 +87,7 @@
 
   // The data has been removed from the factory.
   EXPECT_EQ(nullptr, factory.NewProjectContext("Customer11", "Project11"));
+  EXPECT_EQ(nullptr, factory.NewProjectContext(11, 1));
   EXPECT_FALSE(factory.is_valid());
 }
 
@@ -97,7 +102,9 @@
 
   // Registry B contains Cobalt 1.0 project 22, but no project 11
   EXPECT_EQ(nullptr, factory.NewProjectContext("Customer11", "Project11").get());
+  EXPECT_EQ(nullptr, factory.NewProjectContext(11, 1).get());
   EXPECT_NE(nullptr, factory.NewProjectContext("Customer22", "Project22").get());
+  EXPECT_NE(nullptr, factory.NewProjectContext(22, 1).get());
 
   // Registry B does contain a single Cobalt 1.0 project.
   auto context = factory.TakeSingleProjectContext();
@@ -109,6 +116,7 @@
 
   // The data has been removed from the factory.
   EXPECT_EQ(nullptr, factory.NewProjectContext("Customer22", "Project22"));
+  EXPECT_EQ(nullptr, factory.NewProjectContext(22, 1));
   EXPECT_FALSE(factory.is_valid());
 }
 
@@ -131,6 +139,16 @@
   EXPECT_EQ(nullptr, context1->GetMetric("Metric22"));
   EXPECT_NE(nullptr, context2->GetMetric("Metric22"));
   EXPECT_EQ(nullptr, context2->GetMetric("Metric11"));
+
+  context1 = factory.NewProjectContext(11, 1);
+  context2 = factory.NewProjectContext(22, 1);
+  EXPECT_NE(nullptr, context1.get());
+  EXPECT_NE(nullptr, context2.get());
+
+  EXPECT_NE(nullptr, context1->GetMetric("Metric11"));
+  EXPECT_EQ(nullptr, context1->GetMetric("Metric22"));
+  EXPECT_NE(nullptr, context2->GetMetric("Metric22"));
+  EXPECT_EQ(nullptr, context2->GetMetric("Metric11"));
 }
 
 TEST(ProjectContextFactoryTest, ReleaseStage) {
@@ -139,8 +157,14 @@
   auto context = factory.NewProjectContext("Customer22", "Project22");
   EXPECT_EQ(GA, context->project().release_stage());
 
+  context = factory.NewProjectContext(22, 1);
+  EXPECT_EQ(GA, context->project().release_stage());
+
   context = factory.NewProjectContext("Customer22", "Project22", FISHFOOD);
   EXPECT_EQ(FISHFOOD, context->project().release_stage());
+
+  context = factory.NewProjectContext(22, 1, FISHFOOD);
+  EXPECT_EQ(FISHFOOD, context->project().release_stage());
 }
 
 }  // namespace cobalt::logger