[feedback] add build jiri snapshot to attachments

DX-957 #comment

Change-Id: I101b9ecb534ad5b29cb18c22440fc4b9ab496f4d
diff --git a/src/developer/feedback_agent/BUILD.gn b/src/developer/feedback_agent/BUILD.gn
index 857bc1d..705bb74 100644
--- a/src/developer/feedback_agent/BUILD.gn
+++ b/src/developer/feedback_agent/BUILD.gn
@@ -40,6 +40,8 @@
   sources = [
     "annotations.cc",
     "annotations.h",
+    "attachments.cc",
+    "attachments.h",
     "feedback_agent.cc",
     "feedback_agent.h",
     "image_conversion.cc",
diff --git a/src/developer/feedback_agent/attachments.cc b/src/developer/feedback_agent/attachments.cc
new file mode 100644
index 0000000..1f1f9aa
--- /dev/null
+++ b/src/developer/feedback_agent/attachments.cc
@@ -0,0 +1,53 @@
+// Copyright 2019 The Fuchsia 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 "src/developer/feedback_agent/attachments.h"
+
+#include <string>
+#include <vector>
+
+#include <fuchsia/mem/cpp/fidl.h>
+#include <lib/fsl/vmo/file.h>
+#include <lib/fsl/vmo/sized_vmo.h>
+
+namespace fuchsia {
+namespace feedback {
+namespace {
+
+Attachment BuildAttachment(const std::string& key, fuchsia::mem::Buffer value) {
+  Attachment attachment;
+  attachment.key = key;
+  attachment.value = std::move(value);
+  return attachment;
+}
+
+std::optional<fuchsia::mem::Buffer> VmoFromFilename(
+    const std::string& filename) {
+  fsl::SizedVmo vmo;
+  if (fsl::VmoFromFilename(filename, &vmo)) {
+    return std::move(vmo).ToTransport();
+  }
+  return std::nullopt;
+}
+
+void PushBackIfValuePresent(const std::string& key,
+                            std::optional<fuchsia::mem::Buffer> value,
+                            std::vector<Attachment>* attachments) {
+  if (value.has_value()) {
+    attachments->push_back(BuildAttachment(key, std::move(value.value())));
+  }
+}
+
+}  // namespace
+
+std::vector<Attachment> GetAttachments() {
+  std::vector<Attachment> attachments;
+  PushBackIfValuePresent("build.snapshot",
+                         VmoFromFilename("/config/build-info/snapshot"),
+                         &attachments);
+  return attachments;
+}
+
+}  // namespace feedback
+}  // namespace fuchsia
diff --git a/src/developer/feedback_agent/attachments.h b/src/developer/feedback_agent/attachments.h
new file mode 100644
index 0000000..4661cec
--- /dev/null
+++ b/src/developer/feedback_agent/attachments.h
@@ -0,0 +1,22 @@
+// Copyright 2019 The Fuchsia 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 SRC_DEVELOPER_FEEDBACK_AGENT_ATTACHMENTS_H_
+#define SRC_DEVELOPER_FEEDBACK_AGENT_ATTACHMENTS_H_
+
+#include <vector>
+
+#include <fuchsia/feedback/cpp/fidl.h>
+
+namespace fuchsia {
+namespace feedback {
+
+// Returns attachments useful to attach in feedback reports (crash or user
+// feedback).
+std::vector<Attachment> GetAttachments();
+
+}  // namespace feedback
+}  // namespace fuchsia
+
+#endif  // SRC_DEVELOPER_FEEDBACK_AGENT_ATTACHMENTS_H_
diff --git a/src/developer/feedback_agent/feedback_agent.cc b/src/developer/feedback_agent/feedback_agent.cc
index efab74d..51ee99d 100644
--- a/src/developer/feedback_agent/feedback_agent.cc
+++ b/src/developer/feedback_agent/feedback_agent.cc
@@ -11,6 +11,7 @@
 #include <zircon/status.h>
 
 #include "src/developer/feedback_agent/annotations.h"
+#include "src/developer/feedback_agent/attachments.h"
 #include "src/developer/feedback_agent/image_conversion.h"
 
 namespace fuchsia {
@@ -24,6 +25,7 @@
 void FeedbackAgent::GetData(GetDataCallback callback) {
   DataProvider_GetData_Response response;
   response.data.set_annotations(GetAnnotations());
+  response.data.set_attachments(GetAttachments());
   DataProvider_GetData_Result result;
   result.set_response(std::move(response));
   callback(std::move(result));
diff --git a/src/developer/feedback_agent/tests/feedback_agent_integration_test.cc b/src/developer/feedback_agent/tests/feedback_agent_integration_test.cc
index 83a1719..c7dfe2d 100644
--- a/src/developer/feedback_agent/tests/feedback_agent_integration_test.cc
+++ b/src/developer/feedback_agent/tests/feedback_agent_integration_test.cc
@@ -19,7 +19,7 @@
 namespace {
 
 // Returns true if gMock |arg|.key matches |expected_key|.
-MATCHER_P(MatchesAnnotationKey, expected_key,
+MATCHER_P(MatchesKey, expected_key,
           "matches an annotation with key \"" + std::string(expected_key) +
               "\"") {
   return arg.key == expected_key;
@@ -57,23 +57,28 @@
   // return a screenshot or not depending on which device the test runs.
 }
 
-TEST_F(FeedbackAgentIntegrationTest, GetData_CheckAnnotationKeys) {
+TEST_F(FeedbackAgentIntegrationTest, GetData_CheckKeys) {
   DataProvider_GetData_Result out_result;
   ASSERT_EQ(feedback_data_provider_->GetData(&out_result), ZX_OK);
   ASSERT_TRUE(out_result.is_response());
 
-  // We cannot expect a particular value for each annotation because values
-  // might depend on which device the test runs (e.g., board name) or what
-  // happened prior to running this test (e.g., logs).
-  // But we should expect the keys to be present.
+  // We cannot expect a particular value for each annotation or attachment
+  // because values might depend on which device the test runs (e.g., board
+  // name) or what happened prior to running this test (e.g., logs). But we
+  // should expect the keys to be present.
   ASSERT_TRUE(out_result.response().data.has_annotations());
   EXPECT_THAT(out_result.response().data.annotations(),
               testing::UnorderedElementsAreArray({
-                  MatchesAnnotationKey("device.board-name"),
-                  MatchesAnnotationKey("build.last-update"),
-                  MatchesAnnotationKey("build.version"),
-                  MatchesAnnotationKey("build.board"),
-                  MatchesAnnotationKey("build.product"),
+                  MatchesKey("device.board-name"),
+                  MatchesKey("build.last-update"),
+                  MatchesKey("build.version"),
+                  MatchesKey("build.board"),
+                  MatchesKey("build.product"),
+              }));
+  ASSERT_TRUE(out_result.response().data.has_attachments());
+  EXPECT_THAT(out_result.response().data.attachments(),
+              testing::UnorderedElementsAreArray({
+                  MatchesKey("build.snapshot"),
               }));
 }