Create ArtifactPath function to abstract test paths

When AOS is included as an external repo and renamed, paths have to be
updated.  Make a function to handle all this.

Change-Id: If1dfbfb3191809d86da1dca92981b7a0b851c51f
diff --git a/aos/BUILD b/aos/BUILD
index 04293df..0c94f35 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -355,6 +355,7 @@
         ":json_to_flatbuffer",
         ":json_to_flatbuffer_fbs",
         "//aos/testing:googletest",
+        "//aos/testing:path",
     ],
 )
 
@@ -371,6 +372,7 @@
         ":json_to_flatbuffer",
         ":json_to_flatbuffer_fbs",
         "//aos/testing:googletest",
+        "//aos/testing:path",
         "//aos/util:file",
         "@com_github_google_flatbuffers//:flatbuffers",
     ],
@@ -439,6 +441,7 @@
         ":configuration",
         "//aos/testing:flatbuffer_eq",
         "//aos/testing:googletest",
+        "//aos/testing:path",
         "//aos/testing:test_logging",
     ],
 )
diff --git a/aos/actions/BUILD b/aos/actions/BUILD
index 25c439d..5cc7e58 100644
--- a/aos/actions/BUILD
+++ b/aos/actions/BUILD
@@ -73,6 +73,7 @@
         "//aos/events:simulated_event_loop",
         "//aos/logging",
         "//aos/testing:googletest",
+        "//aos/testing:path",
         "//aos/time",
     ],
 )
diff --git a/aos/actions/action_test.cc b/aos/actions/action_test.cc
index 565bf11..1c8e506 100644
--- a/aos/actions/action_test.cc
+++ b/aos/actions/action_test.cc
@@ -11,6 +11,7 @@
 #include "aos/actions/actor.h"
 #include "aos/actions/test_action_generated.h"
 #include "aos/events/simulated_event_loop.h"
+#include "aos/testing/path.h"
 
 namespace aos {
 namespace common {
@@ -97,8 +98,8 @@
 class ActionTest : public ::testing::Test {
  protected:
   ActionTest()
-      : configuration_(
-            configuration::ReadConfig("aos/actions/action_test_config.json")),
+      : configuration_(configuration::ReadConfig(
+            aos::testing::ArtifactPath("aos/actions/action_test_config.json"))),
         event_loop_factory_(&configuration_.message()),
         actor1_event_loop_(event_loop_factory_.MakeEventLoop("actor1")),
         actor2_event_loop_(event_loop_factory_.MakeEventLoop("actor2")),
diff --git a/aos/configuration_test.cc b/aos/configuration_test.cc
index e0c4dc3..891dedb 100644
--- a/aos/configuration_test.cc
+++ b/aos/configuration_test.cc
@@ -3,6 +3,7 @@
 #include "absl/strings/strip.h"
 #include "aos/json_to_flatbuffer.h"
 #include "aos/testing/flatbuffer_eq.h"
+#include "aos/testing/path.h"
 #include "aos/testing/test_logging.h"
 #include "aos/util/file.h"
 #include "flatbuffers/reflection.h"
@@ -14,7 +15,7 @@
 namespace configuration {
 namespace testing {
 
-const std::string kConfigPrefix = "aos/testdata/";
+using aos::testing::ArtifactPath;
 
 class ConfigurationTest : public ::testing::Test {
  public:
@@ -39,19 +40,19 @@
 // Tests that we can read and merge a configuration.
 TEST_F(ConfigurationTest, ConfigMerge) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "config1.json");
+      ReadConfig(ArtifactPath("aos/testdata/config1.json"));
   LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
 
-  EXPECT_EQ(
-      absl::StripSuffix(
-          util::ReadFileToStringOrDie(kConfigPrefix + "expected.json"), "\n"),
-      FlatbufferToJson(config, {.multi_line = true}));
+  EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
+                                  ArtifactPath("aos/testdata/expected.json")),
+                              "\n"),
+            FlatbufferToJson(config, {.multi_line = true}));
 }
 
 // Tests that we can get back a ChannelIndex.
 TEST_F(ConfigurationTest, ChannelIndex) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "config1.json");
+      ReadConfig(ArtifactPath("aos/testdata/config1.json"));
 
   EXPECT_EQ(
       ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
@@ -61,12 +62,12 @@
 // Tests that we can read and merge a multinode configuration.
 TEST_F(ConfigurationTest, ConfigMergeMultinode) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "config1_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
   LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
 
   EXPECT_EQ(std::string(absl::StripSuffix(
-                util::ReadFileToStringOrDie(kConfigPrefix +
-                                            "expected_multinode.json"),
+                util::ReadFileToStringOrDie(
+                    ArtifactPath("aos/testdata/expected_multinode.json")),
                 "\n")),
             FlatbufferToJson(config, {.multi_line = true}));
 }
@@ -74,7 +75,7 @@
 // Tests that we sort the entries in a config so we can look entries up.
 TEST_F(ConfigurationTest, UnsortedConfig) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "backwards.json");
+      ReadConfig(ArtifactPath("aos/testdata/backwards.json"));
 
   LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
 
@@ -89,9 +90,9 @@
   EXPECT_DEATH(
       {
         FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "config1_bad.json");
+            ReadConfig(ArtifactPath("aos/testdata/config1_bad.json"));
       },
-      kConfigPrefix + "config1_bad.json");
+      "aos/testdata/config1_bad.json");
 }
 
 // Tests that we reject invalid channel names.  This means any channels with //
@@ -100,19 +101,19 @@
   EXPECT_DEATH(
       {
         FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "invalid_channel_name1.json");
+            ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name1.json"));
       },
       "Channel names can't end with '/'");
   EXPECT_DEATH(
       {
         FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "invalid_channel_name2.json");
+            ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name2.json"));
       },
       "Invalid channel name");
   EXPECT_DEATH(
       {
         FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "invalid_channel_name3.json");
+            ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name3.json"));
         LOG(FATAL) << "Foo";
       },
       "Invalid channel name");
@@ -121,7 +122,7 @@
 // Tests that we can modify a config with a json snippet.
 TEST_F(ConfigurationTest, MergeWithConfig) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "config1.json");
+      ReadConfig(ArtifactPath("aos/testdata/config1.json"));
   LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
 
   FlatbufferDetachedBuffer<Configuration> updated_config =
@@ -136,8 +137,8 @@
   ]
 })channel");
 
-  EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
-                                  kConfigPrefix + "expected_merge_with.json"),
+  EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(ArtifactPath(
+                                  "aos/testdata/expected_merge_with.json")),
                               "\n"),
             FlatbufferToJson(updated_config, {.multi_line = true}));
 }
@@ -146,7 +147,7 @@
 // config.
 TEST_F(ConfigurationTest, GetChannel) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "config1.json");
+      ReadConfig(ArtifactPath("aos/testdata/config1.json"));
 
   // Test a basic lookup first.
   EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
@@ -175,7 +176,7 @@
 // Tests that we can lookup a location with node specific maps.
 TEST_F(ConfigurationTest, GetChannelMultinode) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   const Node *pi1 = GetNode(&config.message(), "pi1");
   const Node *pi2 = GetNode(&config.message(), "pi2");
 
@@ -206,7 +207,7 @@
 // Tests that we can lookup a location with type specific maps.
 TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   const Node *pi1 = GetNode(&config.message(), "pi1");
 
   // Test a basic lookup first.
@@ -225,7 +226,7 @@
 // Tests that we can lookup a location with a glob
 TEST_F(ConfigurationTest, GetChannelGlob) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   const Node *pi1 = GetNode(&config.message(), "pi1");
 
   // Confirm that a glob with nothing after it matches.
@@ -248,28 +249,28 @@
   EXPECT_DEATH(
       {
         FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "invalid_nodes.json");
+            ReadConfig(ArtifactPath("aos/testdata/invalid_nodes.json"));
       },
       "source_node");
 
   EXPECT_DEATH(
       {
         FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "invalid_source_node.json");
+            ReadConfig(ArtifactPath("aos/testdata/invalid_source_node.json"));
       },
       "source_node");
 
   EXPECT_DEATH(
       {
-        FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "invalid_destination_node.json");
+        FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
+            ArtifactPath("aos/testdata/invalid_destination_node.json"));
       },
       "destination_nodes");
 
   EXPECT_DEATH(
       {
         FlatbufferDetachedBuffer<Configuration> config =
-            ReadConfig(kConfigPrefix + "self_forward.json");
+            ReadConfig(ArtifactPath("aos/testdata/self_forward.json"));
       },
       "forwarding data to itself");
 }
@@ -646,7 +647,7 @@
 // Tests that we can deduce source nodes from a multinode config.
 TEST_F(ConfigurationTest, SourceNodeNames) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "config1_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
 
   // This is a bit simplistic in that it doesn't test deduplication, but it does
   // exercise a lot of the logic.
@@ -661,7 +662,7 @@
 // Tests that we can deduce destination nodes from a multinode config.
 TEST_F(ConfigurationTest, DestinationNodeNames) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "config1_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
 
   // This is a bit simplistic in that it doesn't test deduplication, but it does
   // exercise a lot of the logic.
@@ -677,7 +678,7 @@
 TEST_F(ConfigurationTest, GetNodes) {
   {
     FlatbufferDetachedBuffer<Configuration> config =
-        ReadConfig(kConfigPrefix + "good_multinode.json");
+        ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
     const Node *pi1 = GetNode(&config.message(), "pi1");
     const Node *pi2 = GetNode(&config.message(), "pi2");
 
@@ -686,7 +687,7 @@
 
   {
     FlatbufferDetachedBuffer<Configuration> config =
-        ReadConfig(kConfigPrefix + "config1.json");
+        ReadConfig(ArtifactPath("aos/testdata/config1.json"));
     EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
   }
 }
@@ -695,7 +696,7 @@
 TEST_F(ConfigurationTest, GetNodesWithTag) {
   {
     FlatbufferDetachedBuffer<Configuration> config =
-        ReadConfig(kConfigPrefix + "good_multinode.json");
+        ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
     const Node *pi1 = GetNode(&config.message(), "pi1");
     const Node *pi2 = GetNode(&config.message(), "pi2");
 
@@ -709,7 +710,7 @@
 
   {
     FlatbufferDetachedBuffer<Configuration> config =
-        ReadConfig(kConfigPrefix + "config1.json");
+        ReadConfig(ArtifactPath("aos/testdata/config1.json"));
     EXPECT_THAT(GetNodesWithTag(&config.message(), "arglfish"),
                 ::testing::ElementsAre(nullptr));
   }
@@ -718,9 +719,9 @@
 // Tests that we can extract a node index from a config.
 TEST_F(ConfigurationTest, GetNodeIndex) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   FlatbufferDetachedBuffer<Configuration> config2 =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   const Node *pi1 = GetNode(&config.message(), "pi1");
   const Node *pi2 = GetNode(&config.message(), "pi2");
 
@@ -741,13 +742,13 @@
 // valid nodes.
 TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   FlatbufferDetachedBuffer<Configuration> config2 =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   {
     // Simple case, nullptr -> nullptr
     FlatbufferDetachedBuffer<Configuration> single_node_config =
-        ReadConfig(kConfigPrefix + "config1.json");
+        ReadConfig(ArtifactPath("aos/testdata/config1.json"));
     EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
 
     // Confirm that we die when a node is passed in.
@@ -767,7 +768,7 @@
 
 TEST_F(ConfigurationTest, GetNodeFromHostname) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "good_multinode.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
   EXPECT_EQ("pi1",
             CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
                 ->name()
@@ -783,7 +784,7 @@
 
 TEST_F(ConfigurationTest, GetNodeFromHostnames) {
   FlatbufferDetachedBuffer<Configuration> config =
-      ReadConfig(kConfigPrefix + "good_multinode_hostnames.json");
+      ReadConfig(ArtifactPath("aos/testdata/good_multinode_hostnames.json"));
   EXPECT_EQ("pi1",
             CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
                 ->name()
diff --git a/aos/events/BUILD b/aos/events/BUILD
index 1a72db9..aab764b 100644
--- a/aos/events/BUILD
+++ b/aos/events/BUILD
@@ -221,6 +221,7 @@
         "//aos:configuration",
         "//aos:flatbuffers",
         "//aos/testing:googletest",
+        "//aos/testing:path",
     ],
 )
 
@@ -315,6 +316,7 @@
         "//aos/network:remote_message_fbs",
         "//aos/network:testing_time_converter",
         "//aos/testing:googletest",
+        "//aos/testing:path",
     ],
 )
 
diff --git a/aos/events/logging/BUILD b/aos/events/logging/BUILD
index 0b6adeb..0123270 100644
--- a/aos/events/logging/BUILD
+++ b/aos/events/logging/BUILD
@@ -373,6 +373,7 @@
         "//aos/events:simulated_event_loop",
         "//aos/network:testing_time_converter",
         "//aos/testing:googletest",
+        "//aos/testing:path",
         "//aos/testing:tmpdir",
     ],
 )
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index 4b0f375..a342c12 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -12,6 +12,7 @@
 #include "aos/network/remote_message_generated.h"
 #include "aos/network/testing_time_converter.h"
 #include "aos/network/timestamp_generated.h"
+#include "aos/testing/path.h"
 #include "aos/testing/tmpdir.h"
 #include "aos/util/file.h"
 #include "glog/logging.h"
@@ -26,6 +27,8 @@
 namespace logger {
 namespace testing {
 
+using aos::testing::ArtifactPath;
+
 namespace chrono = std::chrono;
 using aos::message_bridge::RemoteMessage;
 using aos::testing::MessageCounter;
@@ -51,8 +54,8 @@
 class LoggerTest : public ::testing::Test {
  public:
   LoggerTest()
-      : config_(
-            aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
+      : config_(aos::configuration::ReadConfig(
+            ArtifactPath("aos/events/pingpong_config.json"))),
         event_loop_factory_(&config_.message()),
         ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
         ping_(ping_event_loop_.get()),
@@ -427,8 +430,8 @@
 class MultinodeLoggerTest : public ::testing::TestWithParam<struct Param> {
  public:
   MultinodeLoggerTest()
-      : config_(aos::configuration::ReadConfig(
-            absl::StrCat("aos/events/logging/", GetParam().config))),
+      : config_(aos::configuration::ReadConfig(ArtifactPath(
+            absl::StrCat("aos/events/logging/", GetParam().config)))),
         time_converter_(configuration::NodesCount(&config_.message())),
         event_loop_factory_(&config_.message()),
         pi1_(
diff --git a/aos/events/pingpong_test.cc b/aos/events/pingpong_test.cc
index 07e6d31..07340f7 100644
--- a/aos/events/pingpong_test.cc
+++ b/aos/events/pingpong_test.cc
@@ -2,19 +2,22 @@
 #include "aos/events/pong_lib.h"
 #include "aos/events/simulated_event_loop.h"
 #include "aos/json_to_flatbuffer.h"
+#include "aos/testing/path.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
 namespace aos {
 namespace testing {
 
+using aos::testing::ArtifactPath;
+
 namespace chrono = std::chrono;
 
 class PingPongTest : public ::testing::Test {
  public:
   PingPongTest()
-      : config_(
-            aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
+      : config_(aos::configuration::ReadConfig(
+            ArtifactPath("aos/events/pingpong_config.json"))),
         event_loop_factory_(&config_.message()),
         ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
         ping_(ping_event_loop_.get()),
diff --git a/aos/events/simulated_event_loop_test.cc b/aos/events/simulated_event_loop_test.cc
index ca0060c..7191365 100644
--- a/aos/events/simulated_event_loop_test.cc
+++ b/aos/events/simulated_event_loop_test.cc
@@ -13,13 +13,14 @@
 #include "aos/network/remote_message_generated.h"
 #include "aos/network/testing_time_converter.h"
 #include "aos/network/timestamp_generated.h"
+#include "aos/testing/path.h"
 #include "gtest/gtest.h"
 
 namespace aos {
 namespace testing {
 namespace {
 
-std::string ConfigPrefix() { return "aos/"; }
+using aos::testing::ArtifactPath;
 
 using message_bridge::RemoteMessage;
 namespace chrono = ::std::chrono;
@@ -92,7 +93,7 @@
  public:
   RemoteMessageSimulatedEventLoopTest()
       : config(aos::configuration::ReadConfig(
-            absl::StrCat(ConfigPrefix(), "events/", GetParam().config))) {
+            ArtifactPath(absl::StrCat("aos/events/", GetParam().config)))) {
     LOG(INFO) << "Config " << GetParam().config;
   }
 
@@ -762,9 +763,8 @@
 // ServerStatistics correctly.
 TEST(SimulatedEventLoopTest, MultinodePingPongWithOffset) {
   aos::FlatbufferDetachedBuffer<aos::Configuration> config =
-      aos::configuration::ReadConfig(
-          ConfigPrefix() +
-          "events/multinode_pingpong_test_combined_config.json");
+      aos::configuration::ReadConfig(ArtifactPath(
+          "aos/events/multinode_pingpong_test_combined_config.json"));
   const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
   const size_t pi1_index = configuration::GetNodeIndex(&config.message(), pi1);
   ASSERT_EQ(pi1_index, 0u);
@@ -1271,9 +1271,8 @@
 // it gets delivered as expected.
 TEST(SimulatedEventLoopTest, MultinodePingPongWithOffsetAndSlope) {
   aos::FlatbufferDetachedBuffer<aos::Configuration> config =
-      aos::configuration::ReadConfig(
-          ConfigPrefix() +
-          "events/multinode_pingpong_test_combined_config.json");
+      aos::configuration::ReadConfig(ArtifactPath(
+          "aos/events/multinode_pingpong_test_combined_config.json"));
   const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
   const size_t pi1_index = configuration::GetNodeIndex(&config.message(), pi1);
   ASSERT_EQ(pi1_index, 0u);
diff --git a/aos/flatbuffer_introspection_test.cc b/aos/flatbuffer_introspection_test.cc
index 1119b3b..fe8460f 100644
--- a/aos/flatbuffer_introspection_test.cc
+++ b/aos/flatbuffer_introspection_test.cc
@@ -1,5 +1,6 @@
 #include "aos/json_to_flatbuffer.h"
 #include "aos/json_to_flatbuffer_generated.h"
+#include "aos/testing/path.h"
 #include "aos/util/file.h"
 #include "flatbuffers/reflection.h"
 #include "gtest/gtest.h"
@@ -7,11 +8,13 @@
 namespace aos {
 namespace testing {
 
+using aos::testing::ArtifactPath;
+
 class FlatbufferIntrospectionTest : public ::testing::Test {
  public:
   FlatbufferIntrospectionTest()
       : schema_data_(FileToFlatbuffer<reflection::Schema>(
-            "aos/json_to_flatbuffer.bfbs")) {
+            ArtifactPath("aos/json_to_flatbuffer.bfbs"))) {
     schema_ = reflection::GetSchema(schema_data_.span().data());
   }
 
diff --git a/aos/json_to_flatbuffer_test.cc b/aos/json_to_flatbuffer_test.cc
index aa259df..e353b99 100644
--- a/aos/json_to_flatbuffer_test.cc
+++ b/aos/json_to_flatbuffer_test.cc
@@ -1,6 +1,7 @@
 #include "aos/json_to_flatbuffer.h"
 
 #include "aos/json_to_flatbuffer_generated.h"
+#include "aos/testing/path.h"
 #include "flatbuffers/minireflect.h"
 #include "gtest/gtest.h"
 
@@ -12,7 +13,8 @@
   JsonToFlatbufferTest() {}
 
   FlatbufferVector<reflection::Schema> Schema() {
-    return FileToFlatbuffer<reflection::Schema>("aos/json_to_flatbuffer.bfbs");
+    return FileToFlatbuffer<reflection::Schema>(
+        ArtifactPath("aos/json_to_flatbuffer.bfbs"));
   }
 
   bool JsonAndBack(const ::std::string str) { return JsonAndBack(str, str); }
diff --git a/aos/network/BUILD b/aos/network/BUILD
index 92897a1..4980748 100644
--- a/aos/network/BUILD
+++ b/aos/network/BUILD
@@ -372,6 +372,7 @@
         "//aos/events:shm_event_loop",
         "//aos/ipc_lib:event",
         "//aos/testing:googletest",
+        "//aos/testing:path",
     ],
 )
 
diff --git a/aos/network/message_bridge_test.cc b/aos/network/message_bridge_test.cc
index 3798943..1953dc2 100644
--- a/aos/network/message_bridge_test.cc
+++ b/aos/network/message_bridge_test.cc
@@ -8,6 +8,7 @@
 #include "aos/network/message_bridge_client_lib.h"
 #include "aos/network/message_bridge_server_lib.h"
 #include "aos/network/team_number.h"
+#include "aos/testing/path.h"
 #include "aos/util/file.h"
 #include "gtest/gtest.h"
 
@@ -19,6 +20,8 @@
 namespace message_bridge {
 namespace testing {
 
+using aos::testing::ArtifactPath;
+
 namespace chrono = std::chrono;
 
 std::string ShmBase(const std::string_view node) {
@@ -49,7 +52,7 @@
  public:
   MessageBridgeParameterizedTest()
       : config(aos::configuration::ReadConfig(
-            absl::StrCat("aos/network/", GetParam().config))),
+            ArtifactPath(absl::StrCat("aos/network/", GetParam().config)))),
         pi1_boot_uuid_(UUID::Random()),
         pi2_boot_uuid_(UUID::Random()) {
     util::UnlinkRecursive(ShmBase("pi1"));
diff --git a/aos/starter/BUILD b/aos/starter/BUILD
index fa62a87..9759713 100644
--- a/aos/starter/BUILD
+++ b/aos/starter/BUILD
@@ -41,6 +41,7 @@
         "//aos/events:ping_fbs",
         "//aos/events:pong_fbs",
         "//aos/testing:googletest",
+        "//aos/testing:path",
         "//aos/testing:tmpdir",
     ],
 )
diff --git a/aos/starter/starter_test.cc b/aos/starter/starter_test.cc
index 935c591..fafeb77 100644
--- a/aos/starter/starter_test.cc
+++ b/aos/starter/starter_test.cc
@@ -5,13 +5,17 @@
 
 #include "aos/events/ping_generated.h"
 #include "aos/events/pong_generated.h"
+#include "aos/testing/path.h"
 #include "aos/testing/tmpdir.h"
 #include "gtest/gtest.h"
 #include "starter_rpc_lib.h"
 #include "starterd_lib.h"
 
+using aos::testing::ArtifactPath;
+
 TEST(StarterdTest, StartStopTest) {
-  const std::string config_file = "aos/events/pingpong_config.json";
+  const std::string config_file =
+      ArtifactPath("aos/events/pingpong_config.json");
 
   aos::FlatbufferDetachedBuffer<aos::Configuration> config =
       aos::configuration::ReadConfig(config_file);
@@ -23,16 +27,17 @@
                              R"({"applications": [
                                   {
                                     "name": "ping",
-                                    "executable_name": "aos/events/ping",
+                                    "executable_name": "%s",
                                     "args": ["--shm_base", "%s/aos"]
                                   },
                                   {
                                     "name": "pong",
-                                    "executable_name": "aos/events/pong",
+                                    "executable_name": "%s",
                                     "args": ["--shm_base", "%s/aos"]
                                   }
                                 ]})",
-                             test_dir, test_dir));
+                             ArtifactPath("aos/events/ping"), test_dir,
+                             ArtifactPath("aos/events/pong"), test_dir));
 
   const aos::Configuration *config_msg = &new_config.message();
 
@@ -108,7 +113,8 @@
 }
 
 TEST(StarterdTest, DeathTest) {
-  const std::string config_file = "aos/events/pingpong_config.json";
+  const std::string config_file =
+      ArtifactPath("aos/events/pingpong_config.json");
 
   aos::FlatbufferDetachedBuffer<aos::Configuration> config =
       aos::configuration::ReadConfig(config_file);
@@ -120,16 +126,17 @@
                              R"({"applications": [
                                   {
                                     "name": "ping",
-                                    "executable_name": "aos/events/ping",
+                                    "executable_name": "%s",
                                     "args": ["--shm_base", "%s/aos"]
                                   },
                                   {
                                     "name": "pong",
-                                    "executable_name": "aos/events/pong",
+                                    "executable_name": "%s",
                                     "args": ["--shm_base", "%s/aos"]
                                   }
                                 ]})",
-                             test_dir, test_dir));
+                             ArtifactPath("aos/events/ping"), test_dir,
+                             ArtifactPath("aos/events/pong"), test_dir));
 
   const aos::Configuration *config_msg = &new_config.message();
 
diff --git a/aos/testing/BUILD b/aos/testing/BUILD
index d3287e3..1cff37e 100644
--- a/aos/testing/BUILD
+++ b/aos/testing/BUILD
@@ -117,3 +117,14 @@
         "@com_google_googletest//:gtest",
     ],
 )
+
+cc_library(
+    name = "path",
+    srcs = ["path.cc"],
+    hdrs = ["path.h"],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@com_google_absl//absl/strings",
+    ],
+)
diff --git a/aos/testing/path.cc b/aos/testing/path.cc
new file mode 100644
index 0000000..f999e58
--- /dev/null
+++ b/aos/testing/path.cc
@@ -0,0 +1,16 @@
+#include "aos/testing/path.h"
+#include "absl/strings/str_cat.h"
+
+namespace aos {
+namespace testing {
+
+// Returns the path to the provided artifact which works when built both as an
+// external target and in the repo.
+std::string ArtifactPath(std::string_view path) {
+  // TODO(austin): Don't hard-code the repo name here since it likely will
+  // change.
+  return absl::StrCat("../org_frc971/", path);
+}
+
+}  // namespace testing
+}  // namespace aos
diff --git a/aos/testing/path.h b/aos/testing/path.h
new file mode 100644
index 0000000..1abad74
--- /dev/null
+++ b/aos/testing/path.h
@@ -0,0 +1,16 @@
+#ifndef AOS_TESTING_PATH_H_
+#define AOS_TESTING_PATH_H_
+
+#include <string>
+#include <string_view>
+
+namespace aos {
+namespace testing {
+
+// Returns the path to the provided artifact which works 
+std::string ArtifactPath(std::string_view path);
+
+}  // namespace testing
+}  // namespace aos
+
+#endif  // AOS_TESTING_PATH_H_