TestImpactRuntimeConfigurationFactory.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include <TestImpactFramework/TestImpactConfigurationException.h>
  8. #include <TestImpactRuntimeConfigurationFactory.h>
  9. #include <AzCore/JSON/document.h>
  10. #include <AzCore/std/functional.h>
  11. #include <AzCore/std/optional.h>
  12. namespace TestImpact
  13. {
  14. namespace Config
  15. {
  16. // Keys for pertinent JSON elements
  17. constexpr const char* Keys[] =
  18. {
  19. "root",
  20. "platform",
  21. "relative_paths",
  22. "artifact_dir",
  23. "enumeration_cache_dir",
  24. "test_impact_data_files",
  25. "temp",
  26. "active",
  27. "target_sources",
  28. "static",
  29. "autogen",
  30. "static",
  31. "include_filters",
  32. "input_output_pairer",
  33. "input",
  34. "dir",
  35. "matchers",
  36. "target_dependency_file",
  37. "target_vertex",
  38. "file",
  39. "test_runner",
  40. "instrumentation",
  41. "bin",
  42. "exclude",
  43. "shard",
  44. "fixture_contiguous",
  45. "fixture_interleaved",
  46. "test_contiguous",
  47. "test_interleaved",
  48. "never",
  49. "target",
  50. "policy",
  51. "artifacts",
  52. "meta",
  53. "repo",
  54. "workspace",
  55. "build_target_descriptor",
  56. "dependency_graph_data",
  57. "test_target_meta",
  58. "test_engine",
  59. "target"
  60. };
  61. enum
  62. {
  63. Root = 0,
  64. PlatformName,
  65. RelativePaths,
  66. ArtifactDir,
  67. EnumerationCacheDir,
  68. TestImpactDataFiles,
  69. TempWorkspace,
  70. ActiveWorkspace,
  71. TargetSources,
  72. StaticSources,
  73. AutogenSources,
  74. StaticArtifacts,
  75. SourceIncludeFilters,
  76. AutogenInputOutputPairer,
  77. AutogenInputSources,
  78. Directory,
  79. DependencyGraphMatchers,
  80. TargetDependencyFileMatcher,
  81. TargetVertexMatcher,
  82. TestTargetMetaFile,
  83. TestRunner,
  84. TestInstrumentation,
  85. BinaryFile,
  86. TargetExcludeFilter,
  87. TestSharding,
  88. ContinuousFixtureSharding,
  89. InterleavedFixtureSharding,
  90. ContinuousTestSharding,
  91. InterleavedTestSharding,
  92. NeverShard,
  93. TargetName,
  94. TestShardingPolicy,
  95. Artifacts,
  96. Meta,
  97. Repository,
  98. Workspace,
  99. BuildTargetDescriptor,
  100. DependencyGraphData,
  101. TestTargetMeta,
  102. TestEngine,
  103. TargetConfig
  104. };
  105. }
  106. //! Returns an absolute path for a path relative to the specified root.
  107. RepoPath GetAbsPathFromRelPath(const RepoPath& root, const RepoPath& rel)
  108. {
  109. return root / rel;
  110. }
  111. ConfigMeta ParseConfigMeta(const rapidjson::Value& meta)
  112. {
  113. ConfigMeta configMeta;
  114. configMeta.m_platform = meta[Config::Keys[Config::PlatformName]].GetString();
  115. return configMeta;
  116. }
  117. RepoConfig ParseRepoConfig(const rapidjson::Value& repo)
  118. {
  119. RepoConfig repoConfig;
  120. repoConfig.m_root = repo[Config::Keys[Config::Root]].GetString();
  121. return repoConfig;
  122. }
  123. WorkspaceConfig::Temp ParseTempWorkspaceConfig(const rapidjson::Value& tempWorkspace)
  124. {
  125. WorkspaceConfig::Temp tempWorkspaceConfig;
  126. tempWorkspaceConfig.m_root = tempWorkspace[Config::Keys[Config::Root]].GetString();
  127. tempWorkspaceConfig.m_artifactDirectory =
  128. GetAbsPathFromRelPath(
  129. tempWorkspaceConfig.m_root, tempWorkspace[Config::Keys[Config::RelativePaths]][Config::Keys[Config::ArtifactDir]].GetString());
  130. return tempWorkspaceConfig;
  131. }
  132. AZStd::array<RepoPath, 3> ParseTestImpactAnalysisDataFiles(const RepoPath& root, const rapidjson::Value& sparTIAFile)
  133. {
  134. AZStd::array<RepoPath, 3> sparTIAFiles;
  135. sparTIAFiles[static_cast<size_t>(SuiteType::Main)] =
  136. GetAbsPathFromRelPath(root, sparTIAFile[GetSuiteTypeName(SuiteType::Main).c_str()].GetString());
  137. sparTIAFiles[static_cast<size_t>(SuiteType::Periodic)] =
  138. GetAbsPathFromRelPath(root, sparTIAFile[GetSuiteTypeName(SuiteType::Periodic).c_str()].GetString());
  139. sparTIAFiles[static_cast<size_t>(SuiteType::Sandbox)] =
  140. GetAbsPathFromRelPath(root, sparTIAFile[GetSuiteTypeName(SuiteType::Sandbox).c_str()].GetString());
  141. return sparTIAFiles;
  142. }
  143. WorkspaceConfig::Active ParseActiveWorkspaceConfig(const rapidjson::Value& activeWorkspace)
  144. {
  145. WorkspaceConfig::Active activeWorkspaceConfig;
  146. const auto& relativePaths = activeWorkspace[Config::Keys[Config::RelativePaths]];
  147. activeWorkspaceConfig.m_root = activeWorkspace[Config::Keys[Config::Root]].GetString();
  148. activeWorkspaceConfig.m_enumerationCacheDirectory
  149. = GetAbsPathFromRelPath(activeWorkspaceConfig.m_root, relativePaths[Config::Keys[Config::EnumerationCacheDir]].GetString());
  150. activeWorkspaceConfig.m_sparTIAFiles =
  151. ParseTestImpactAnalysisDataFiles(activeWorkspaceConfig.m_root, relativePaths[Config::Keys[Config::TestImpactDataFiles]]);
  152. return activeWorkspaceConfig;
  153. }
  154. WorkspaceConfig ParseWorkspaceConfig(const rapidjson::Value& workspace)
  155. {
  156. WorkspaceConfig workspaceConfig;
  157. workspaceConfig.m_temp = ParseTempWorkspaceConfig(workspace[Config::Keys[Config::TempWorkspace]]);
  158. workspaceConfig.m_active = ParseActiveWorkspaceConfig(workspace[Config::Keys[Config::ActiveWorkspace]]);
  159. return workspaceConfig;
  160. }
  161. BuildTargetDescriptorConfig ParseBuildTargetDescriptorConfig(const rapidjson::Value& buildTargetDescriptor)
  162. {
  163. BuildTargetDescriptorConfig buildTargetDescriptorConfig;
  164. const auto& targetSources = buildTargetDescriptor[Config::Keys[Config::TargetSources]];
  165. const auto& staticTargetSources = targetSources[Config::Keys[Config::StaticSources]];
  166. const auto& autogenTargetSources = targetSources[Config::Keys[Config::AutogenSources]];
  167. buildTargetDescriptorConfig.m_mappingDirectory = buildTargetDescriptor[Config::Keys[Config::Directory]].GetString();
  168. const auto& staticInclusionFilters = staticTargetSources[Config::Keys[Config::SourceIncludeFilters]].GetArray();
  169. buildTargetDescriptorConfig.m_staticInclusionFilters.reserve(staticInclusionFilters.Size());
  170. for (const auto& staticInclusionFilter : staticInclusionFilters)
  171. {
  172. buildTargetDescriptorConfig.m_staticInclusionFilters.push_back(staticInclusionFilter.GetString());
  173. }
  174. buildTargetDescriptorConfig.m_inputOutputPairer = autogenTargetSources[Config::Keys[Config::AutogenInputOutputPairer]].GetString();
  175. const auto& inputInclusionFilters =
  176. autogenTargetSources[Config::Keys[Config::AutogenInputSources]][Config::Keys[Config::SourceIncludeFilters]].GetArray();
  177. buildTargetDescriptorConfig.m_inputInclusionFilters.reserve(inputInclusionFilters.Size());
  178. for (const auto& inputInclusionFilter : inputInclusionFilters)
  179. {
  180. buildTargetDescriptorConfig.m_inputInclusionFilters.push_back(inputInclusionFilter.GetString());
  181. }
  182. return buildTargetDescriptorConfig;
  183. }
  184. DependencyGraphDataConfig ParseDependencyGraphDataConfig(const rapidjson::Value& dependencyGraphData)
  185. {
  186. DependencyGraphDataConfig dependencyGraphDataConfig;
  187. const auto& matchers = dependencyGraphData[Config::Keys[Config::DependencyGraphMatchers]];
  188. dependencyGraphDataConfig.m_graphDirectory = dependencyGraphData[Config::Keys[Config::Directory]].GetString();
  189. dependencyGraphDataConfig.m_targetDependencyFileMatcher = matchers[Config::Keys[Config::TargetDependencyFileMatcher]].GetString();
  190. dependencyGraphDataConfig.m_targetVertexMatcher = matchers[Config::Keys[Config::TargetVertexMatcher]].GetString();
  191. return dependencyGraphDataConfig;
  192. }
  193. TestTargetMetaConfig ParseTestTargetMetaConfig(const rapidjson::Value& testTargetMeta)
  194. {
  195. TestTargetMetaConfig testTargetMetaConfig;
  196. testTargetMetaConfig.m_metaFile = testTargetMeta[Config::Keys[Config::TestTargetMetaFile]].GetString();
  197. return testTargetMetaConfig;
  198. }
  199. TestEngineConfig ParseTestEngineConfig(const rapidjson::Value& testEngine)
  200. {
  201. TestEngineConfig testEngineConfig;
  202. testEngineConfig.m_testRunner.m_binary = testEngine[Config::Keys[Config::TestRunner]][Config::Keys[Config::BinaryFile]].GetString();
  203. testEngineConfig.m_instrumentation.m_binary = testEngine[Config::Keys[Config::TestInstrumentation]][Config::Keys[Config::BinaryFile]].GetString();
  204. return testEngineConfig;
  205. }
  206. TargetConfig ParseTargetConfig(const rapidjson::Value& target)
  207. {
  208. TargetConfig targetConfig;
  209. targetConfig.m_outputDirectory = target[Config::Keys[Config::Directory]].GetString();
  210. const auto& testExcludes = target[Config::Keys[Config::TargetExcludeFilter]].GetArray();
  211. targetConfig.m_excludedTestTargets.reserve(testExcludes.Size());
  212. for (const auto& testExclude : testExcludes)
  213. {
  214. targetConfig.m_excludedTestTargets.push_back(testExclude.GetString());
  215. }
  216. const auto& testShards = target[Config::Keys[Config::TestSharding]].GetArray();
  217. targetConfig.m_shardedTestTargets.reserve(testShards.Size());
  218. for (const auto& testShard : testShards)
  219. {
  220. const auto getShardingConfiguration = [](const AZStd::string& config)
  221. {
  222. if (config == Config::Keys[Config::ContinuousFixtureSharding])
  223. {
  224. return ShardConfiguration::FixtureContiguous;
  225. }
  226. else if (config == Config::Keys[Config::InterleavedFixtureSharding])
  227. {
  228. return ShardConfiguration::FixtureInterleaved;
  229. }
  230. else if (config == Config::Keys[Config::ContinuousTestSharding])
  231. {
  232. return ShardConfiguration::TestContiguous;
  233. }
  234. else if (config == Config::Keys[Config::InterleavedTestSharding])
  235. {
  236. return ShardConfiguration::TestInterleaved;
  237. }
  238. else if (config == Config::Keys[Config::NeverShard])
  239. {
  240. return ShardConfiguration::Never;
  241. }
  242. else
  243. {
  244. throw ConfigurationException(AZStd::string::format("Unexpected sharding configuration: %s", config.c_str()));
  245. }
  246. };
  247. TargetConfig::ShardedTarget shard;
  248. shard.m_name = testShard[Config::Keys[Config::TargetName]].GetString();
  249. shard.m_configuration = getShardingConfiguration(testShard[Config::Keys[Config::TestShardingPolicy]].GetString());
  250. targetConfig.m_shardedTestTargets.push_back(AZStd::move(shard));
  251. }
  252. return targetConfig;
  253. }
  254. RuntimeConfig RuntimeConfigurationFactory(const AZStd::string& configurationData)
  255. {
  256. rapidjson::Document configurationFile;
  257. if (configurationFile.Parse(configurationData.c_str()).HasParseError())
  258. {
  259. throw TestImpact::ConfigurationException("Could not parse runtimeConfig data, JSON has errors");
  260. }
  261. RuntimeConfig runtimeConfig;
  262. const auto& staticArtifacts = configurationFile[Config::Keys[Config::Artifacts]][Config::Keys[Config::StaticArtifacts]];
  263. runtimeConfig.m_meta = ParseConfigMeta(configurationFile[Config::Keys[Config::Meta]]);
  264. runtimeConfig.m_repo = ParseRepoConfig(configurationFile[Config::Keys[Config::Repository]]);
  265. runtimeConfig.m_workspace = ParseWorkspaceConfig(configurationFile[Config::Keys[Config::Workspace]]);
  266. runtimeConfig.m_buildTargetDescriptor = ParseBuildTargetDescriptorConfig(staticArtifacts[Config::Keys[Config::BuildTargetDescriptor]]);
  267. runtimeConfig.m_dependencyGraphData = ParseDependencyGraphDataConfig(staticArtifacts[Config::Keys[Config::DependencyGraphData]]);
  268. runtimeConfig.m_testTargetMeta = ParseTestTargetMetaConfig(staticArtifacts[Config::Keys[Config::TestTargetMeta]]);
  269. runtimeConfig.m_testEngine = ParseTestEngineConfig(configurationFile[Config::Keys[Config::TestEngine]]);
  270. runtimeConfig.m_target = ParseTargetConfig(configurationFile[Config::Keys[Config::TargetConfig]]);
  271. return runtimeConfig;
  272. }
  273. } // namespace TestImpact