JobModelTest.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <native/tests/utilities/JobModelTest.h>
  9. #include <AzCore/std/string/string.h>
  10. TEST_F(JobModelUnitTests, Test_RemoveMiddleJob)
  11. {
  12. VerifyModel(); // verify up front for sanity.
  13. AzToolsFramework::AssetSystem::JobInfo jobInfo;
  14. jobInfo.m_watchFolder = "c:/test";
  15. jobInfo.m_sourceFile = "source2.txt";
  16. jobInfo.m_platform = "platform";
  17. jobInfo.m_jobKey = "jobKey";
  18. AssetProcessor::QueueElementID elementId(AssetProcessor::SourceAssetReference("c:/test/source2.txt"), "platform", "jobKey");
  19. auto iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  20. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  21. unsigned int jobIndex = iter.value();
  22. ASSERT_EQ(jobIndex, 1); // second job
  23. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 6);
  24. m_unitTestJobModel->OnJobRemoved(jobInfo);
  25. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 5);
  26. iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  27. ASSERT_EQ(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  28. AssetProcessor::CachedJobInfo* cachedJobInfo = m_unitTestJobModel->m_cachedJobs[jobIndex];
  29. ASSERT_EQ(cachedJobInfo->m_elementId.GetSourceAssetReference().AbsolutePath().Native(), "c:/test/source3.txt");
  30. // Checking index of last job
  31. elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source6.txt"));
  32. iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  33. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  34. jobIndex = iter.value();
  35. ASSERT_EQ(jobIndex, 4);
  36. VerifyModel();
  37. }
  38. TEST_F(JobModelUnitTests, Test_RemoveFirstJob)
  39. {
  40. VerifyModel(); // verify up front for sanity.
  41. AzToolsFramework::AssetSystem::JobInfo jobInfo;
  42. jobInfo.m_watchFolder = "c:/test";
  43. jobInfo.m_sourceFile = "source1.txt";
  44. jobInfo.m_platform = "platform";
  45. jobInfo.m_jobKey = "jobKey";
  46. AssetProcessor::QueueElementID elementId(AssetProcessor::SourceAssetReference ("c:/test/source1.txt"), "platform", "jobKey");
  47. auto iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  48. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  49. unsigned int jobIndex = iter.value();
  50. ASSERT_EQ(jobIndex, 0); //first job
  51. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 6);
  52. m_unitTestJobModel->OnJobRemoved(jobInfo);
  53. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 5);
  54. iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  55. ASSERT_EQ(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  56. AssetProcessor::CachedJobInfo* cachedJobInfo = m_unitTestJobModel->m_cachedJobs[jobIndex];
  57. ASSERT_EQ(cachedJobInfo->m_elementId.GetSourceAssetReference().AbsolutePath().Native(), "c:/test/source2.txt");
  58. // Checking index of last job
  59. elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source6.txt"));
  60. iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  61. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  62. jobIndex = iter.value();
  63. ASSERT_EQ(jobIndex, 4);
  64. VerifyModel();
  65. }
  66. TEST_F(JobModelUnitTests, Test_RemoveLastJob)
  67. {
  68. VerifyModel(); // verify up front for sanity.
  69. AzToolsFramework::AssetSystem::JobInfo jobInfo;
  70. jobInfo.m_watchFolder = "c:/test";
  71. jobInfo.m_sourceFile = "source6.txt";
  72. jobInfo.m_platform = "platform";
  73. jobInfo.m_jobKey = "jobKey";
  74. AssetProcessor::QueueElementID elementId(AssetProcessor::SourceAssetReference("c:/test/source6.txt"), "platform", "jobKey");
  75. auto iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  76. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  77. unsigned int jobIndex = iter.value();
  78. ASSERT_EQ(jobIndex, 5); //last job
  79. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 6);
  80. m_unitTestJobModel->OnJobRemoved(jobInfo);
  81. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 5);
  82. iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  83. ASSERT_EQ(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  84. AssetProcessor::CachedJobInfo* cachedJobInfo = m_unitTestJobModel->m_cachedJobs[jobIndex - 1];
  85. ASSERT_EQ(cachedJobInfo->m_elementId.GetSourceAssetReference().AbsolutePath().Native(), "c:/test/source5.txt");
  86. // Checking index of first job
  87. elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source1.txt"));
  88. iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  89. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  90. jobIndex = iter.value();
  91. ASSERT_EQ(jobIndex, 0);
  92. VerifyModel();
  93. }
  94. TEST_F(JobModelUnitTests, Test_RemoveAllJobsBySource)
  95. {
  96. VerifyModel(); // verify up front for sanity.
  97. AssetProcessor::CachedJobInfo* jobInfo1 = new AssetProcessor::CachedJobInfo();
  98. jobInfo1->m_elementId.SetSourceAssetReference(
  99. AssetProcessor::SourceAssetReference("c:/test/source3.txt")); // this is the second job for this source - the fixture creates one
  100. jobInfo1->m_elementId.SetPlatform("platform_2"); // differing job keys
  101. jobInfo1->m_elementId.SetJobDescriptor("jobKey_3"); // differing descriptor
  102. jobInfo1->m_jobState = AzToolsFramework::AssetSystem::JobStatus::Completed;
  103. m_unitTestJobModel->m_cachedJobs.push_back(jobInfo1);
  104. m_unitTestJobModel->m_cachedJobsLookup.insert(jobInfo1->m_elementId, aznumeric_caster(m_unitTestJobModel->m_cachedJobs.size() - 1));
  105. AssetProcessor::QueueElementID elementId(AssetProcessor::SourceAssetReference("c:/test/source3.txt"), "platform_2", "jobKey_3");
  106. auto iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  107. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  108. unsigned int jobIndex = iter.value();
  109. ASSERT_EQ(jobIndex, 6); //last job
  110. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 7);
  111. m_unitTestJobModel->OnSourceRemoved(AssetProcessor::SourceAssetReference("c:/test/source3.txt"));
  112. // both sources should be removed!
  113. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), 5);
  114. VerifyModel();
  115. // make sure source3 is completely gone.
  116. for (int idx = 0; idx < m_unitTestJobModel->m_cachedJobs.size(); idx++)
  117. {
  118. AssetProcessor::CachedJobInfo* jobInfo = m_unitTestJobModel->m_cachedJobs[idx];
  119. ASSERT_NE(jobInfo->m_elementId.GetSourceAssetReference().AbsolutePath().Native(), "c:/test/source3.txt");
  120. }
  121. }
  122. TEST_F(JobModelUnitTests, Test_PopulateJobsFromDatabase)
  123. {
  124. VerifyModel(); // verify up front for sanity.
  125. CreateDatabaseTestData();
  126. m_unitTestJobModel->PopulateJobsFromDatabase();
  127. for (const auto& jobEntry : m_data->m_jobEntries)
  128. {
  129. AssetProcessor::QueueElementID elementId(AssetProcessor::SourceAssetReference("c:/test", m_data->m_sourceName.c_str()), jobEntry.m_platform.c_str(), jobEntry.m_jobKey.c_str());
  130. auto iter = m_unitTestJobModel->m_cachedJobsLookup.find(elementId);
  131. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  132. //! expect the three jobs from database are populated into m_unitTestJobModel
  133. EXPECT_EQ(m_unitTestJobModel->m_cachedJobs.at(iter.value())->m_elementId, elementId);
  134. //! and that they have a valid m_processDuration, which is set to be equivalent to jobEntry.m_fingerprint
  135. EXPECT_EQ(
  136. m_unitTestJobModel->m_cachedJobs.at(iter.value())->m_processDuration.msecsSinceStartOfDay(),
  137. aznumeric_cast<int>(jobEntry.m_fingerprint));
  138. }
  139. // expect one AZ_Warning emitted, because we have one stat entry in the database that has 5 tokens.
  140. m_errorAbsorber->ExpectWarnings(1);
  141. VerifyModel();
  142. }
  143. void JobModelUnitTests::SetUp()
  144. {
  145. AssetProcessorTest::SetUp();
  146. {
  147. using namespace testing;
  148. m_data.reset(new StaticData());
  149. m_data->m_connection.ClearData();
  150. }
  151. m_unitTestJobModel = new UnitTestJobModel();
  152. AssetProcessor::CachedJobInfo* jobInfo1 = new AssetProcessor::CachedJobInfo();
  153. jobInfo1->m_elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source1.txt"));
  154. jobInfo1->m_elementId.SetPlatform("platform");
  155. jobInfo1->m_elementId.SetJobDescriptor("jobKey");
  156. jobInfo1->m_jobState = AzToolsFramework::AssetSystem::JobStatus::Completed;
  157. m_unitTestJobModel->m_cachedJobs.push_back(jobInfo1);
  158. m_unitTestJobModel->m_cachedJobsLookup.insert(jobInfo1->m_elementId, aznumeric_caster(m_unitTestJobModel->m_cachedJobs.size() - 1));
  159. AssetProcessor::CachedJobInfo* jobInfo2 = new AssetProcessor::CachedJobInfo();
  160. jobInfo2->m_elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source2.txt"));
  161. jobInfo2->m_elementId.SetPlatform("platform");
  162. jobInfo2->m_elementId.SetJobDescriptor("jobKey");
  163. m_unitTestJobModel->m_cachedJobs.push_back(jobInfo2);
  164. m_unitTestJobModel->m_cachedJobsLookup.insert(jobInfo2->m_elementId, aznumeric_caster(m_unitTestJobModel->m_cachedJobs.size() - 1));
  165. AssetProcessor::CachedJobInfo* jobInfo3 = new AssetProcessor::CachedJobInfo();
  166. jobInfo3->m_elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source3.txt"));
  167. jobInfo3->m_elementId.SetPlatform("platform");
  168. jobInfo3->m_elementId.SetJobDescriptor("jobKey");
  169. m_unitTestJobModel->m_cachedJobs.push_back(jobInfo3);
  170. m_unitTestJobModel->m_cachedJobsLookup.insert(jobInfo3->m_elementId, aznumeric_caster(m_unitTestJobModel->m_cachedJobs.size() - 1));
  171. AssetProcessor::CachedJobInfo* jobInfo4 = new AssetProcessor::CachedJobInfo();
  172. jobInfo4->m_elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source4.txt"));
  173. jobInfo4->m_elementId.SetPlatform("platform");
  174. jobInfo4->m_elementId.SetJobDescriptor("jobKey");
  175. m_unitTestJobModel->m_cachedJobs.push_back(jobInfo4);
  176. m_unitTestJobModel->m_cachedJobsLookup.insert(jobInfo4->m_elementId, aznumeric_caster(m_unitTestJobModel->m_cachedJobs.size() - 1));
  177. AssetProcessor::CachedJobInfo* jobInfo5 = new AssetProcessor::CachedJobInfo();
  178. jobInfo5->m_elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source5.txt"));
  179. jobInfo5->m_elementId.SetPlatform("platform");
  180. jobInfo5->m_elementId.SetJobDescriptor("jobKey");
  181. m_unitTestJobModel->m_cachedJobs.push_back(jobInfo5);
  182. m_unitTestJobModel->m_cachedJobsLookup.insert(jobInfo5->m_elementId, aznumeric_caster(m_unitTestJobModel->m_cachedJobs.size() - 1));
  183. AssetProcessor::CachedJobInfo* jobInfo6 = new AssetProcessor::CachedJobInfo();
  184. jobInfo6->m_elementId.SetSourceAssetReference(AssetProcessor::SourceAssetReference("c:/test/source6.txt"));
  185. jobInfo6->m_elementId.SetPlatform("platform");
  186. jobInfo6->m_elementId.SetJobDescriptor("jobKey");
  187. m_unitTestJobModel->m_cachedJobs.push_back(jobInfo6);
  188. m_unitTestJobModel->m_cachedJobsLookup.insert(jobInfo6->m_elementId, aznumeric_caster(m_unitTestJobModel->m_cachedJobs.size() - 1));
  189. }
  190. void JobModelUnitTests::TearDown()
  191. {
  192. delete m_unitTestJobModel;
  193. m_data->m_databaseLocationListener.BusDisconnect();
  194. m_data.reset();
  195. AssetProcessorTest::TearDown();
  196. }
  197. void JobModelUnitTests::VerifyModel()
  198. {
  199. // Every job should exist in the lookup map as well.
  200. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs.size(), m_unitTestJobModel->m_cachedJobsLookup.size());
  201. // every job in the vector should have a corresponding element in the lookup table.
  202. for (int idx = 0; idx < m_unitTestJobModel->m_cachedJobs.size(); idx++)
  203. {
  204. AssetProcessor::CachedJobInfo* jobInfo = m_unitTestJobModel->m_cachedJobs[idx];
  205. auto iter = m_unitTestJobModel->m_cachedJobsLookup.find(jobInfo->m_elementId);
  206. ASSERT_NE(iter, m_unitTestJobModel->m_cachedJobsLookup.end());
  207. }
  208. // this tests the other direction - every job in the lookup table should map to a job in the vector
  209. // we also verify that its the appropriate job and not an off-by-one type of problem.
  210. for (const auto& key : m_unitTestJobModel->m_cachedJobsLookup.keys())
  211. {
  212. int expectedIndex = m_unitTestJobModel->m_cachedJobsLookup[key];
  213. ASSERT_LT(expectedIndex, m_unitTestJobModel->m_cachedJobs.size());
  214. ASSERT_EQ(m_unitTestJobModel->m_cachedJobs[expectedIndex]->m_elementId, key);
  215. }
  216. }
  217. void JobModelUnitTests::CreateDatabaseTestData()
  218. {
  219. //! This method puts jobs and ProcessJob metrics into the database.
  220. using namespace AzToolsFramework::AssetDatabase;
  221. ScanFolderDatabaseEntry scanFolderEntry;
  222. SourceDatabaseEntry sourceEntry;
  223. StatDatabaseEntry statEntry;
  224. scanFolderEntry = { "c:/test", "dev", "rootportkey" };
  225. ASSERT_TRUE(m_data->m_connection.SetScanFolder(scanFolderEntry));
  226. sourceEntry = { scanFolderEntry.m_scanFolderID, m_data->m_sourceName.c_str(), AZ::Uuid::CreateRandom(), "AFPAFPAFP1" };
  227. ASSERT_TRUE(m_data->m_connection.SetSource(sourceEntry));
  228. //! Insert job entries
  229. m_data->m_jobEntries.clear();
  230. m_data->m_jobEntries.emplace_back(
  231. sourceEntry.m_sourceID, "jobKey1", 123, "pc", AZ::Uuid::CreateRandom(), AzToolsFramework::AssetSystem::JobStatus::Completed, 1);
  232. m_data->m_jobEntries.emplace_back(
  233. sourceEntry.m_sourceID, "jobKey2", 456, "linux", AZ::Uuid::CreateRandom(), AzToolsFramework::AssetSystem::JobStatus::Failed, 2);
  234. m_data->m_jobEntries.emplace_back(
  235. sourceEntry.m_sourceID, "jobKey3", 789, "mac", AZ::Uuid::CreateRandom(), AzToolsFramework::AssetSystem::JobStatus::Completed, 3);
  236. for (auto& jobEntry : m_data->m_jobEntries)
  237. {
  238. ASSERT_TRUE(m_data->m_connection.SetJob(jobEntry));
  239. }
  240. //! Insert valid stat entries, one per job
  241. for (const auto& jobEntry : m_data->m_jobEntries)
  242. {
  243. AZStd::string statName = AZStd::string::format(
  244. "ProcessJob,%s,%s,%s,%s,%s",
  245. scanFolderEntry.m_scanFolder.c_str(),
  246. m_data->m_sourceName.c_str(),
  247. jobEntry.m_jobKey.c_str(),
  248. jobEntry.m_platform.c_str(),
  249. jobEntry.m_builderGuid.ToString<AZStd::string>().c_str());
  250. statEntry = { statName /* StatName */,
  251. aznumeric_cast<AZ::s64>(jobEntry.m_fingerprint) /* StatValue */,
  252. aznumeric_cast<AZ::s64>(jobEntry.m_jobRunKey) /* LastLogTime */ };
  253. ASSERT_TRUE(m_data->m_connection.ReplaceStat(statEntry));
  254. }
  255. //! Insert an invalid stat entry (7 tokens)
  256. statEntry = { "ProcessJob,apple,peach,banana,carrot,dog,{FDAF4363-C530-476C-B382-579A43B3E2FC}", 123, 456 };
  257. ASSERT_TRUE(m_data->m_connection.ReplaceStat(statEntry));
  258. }