@@ -35,9 +35,13 @@ BOOST_AUTO_TEST_SUITE(CPersistenceManagerTest)
3535namespace {
3636
3737void reportPersistComplete (ml::api::CModelSnapshotJsonWriter::SModelSnapshotReport modelSnapshotReport,
38+ ml::core_t ::TTime& snapshotTimestamp,
39+ std::string& description,
3840 std::string& snapshotIdOut,
3941 std::size_t & numDocsOut) {
4042 LOG_DEBUG (<< " Persist complete with description: " << modelSnapshotReport.s_Description );
43+ snapshotTimestamp = modelSnapshotReport.s_SnapshotTimestamp ;
44+ description = modelSnapshotReport.s_Description ;
4145 snapshotIdOut = modelSnapshotReport.s_SnapshotId ;
4246 numDocsOut = modelSnapshotReport.s_NumDocs ;
4347}
@@ -71,10 +75,10 @@ class CTestFixture {
7175 ml::api::CSingleStreamDataAdder::TOStreamP backgroundStreamPtr{
7276 backgroundStream = new std::ostringstream ()};
7377 ml::api::CSingleStreamDataAdder backgroundDataAdder{backgroundStreamPtr};
78+
7479 std::ostringstream* foregroundStream{nullptr };
7580 ml::api::CSingleStreamDataAdder::TOStreamP foregroundStreamPtr{
7681 foregroundStream = new std::ostringstream ()};
77-
7882 ml::api::CSingleStreamDataAdder foregroundDataAdder{foregroundStreamPtr};
7983
8084 // The 30000 second persist interval is set large enough that the timer will
@@ -83,6 +87,8 @@ class CTestFixture {
8387 ml::api::CPersistenceManager persistenceManager{
8488 30000 , false , backgroundDataAdder, foregroundDataAdder};
8589
90+ ml::core_t ::TTime snapshotTimestamp;
91+ std::string description;
8692 std::string snapshotId;
8793 std::size_t numDocs{0 };
8894
@@ -102,6 +108,7 @@ class CTestFixture {
102108 modelConfig,
103109 wrappedOutputStream,
104110 std::bind (&reportPersistComplete, std::placeholders::_1,
111+ std::ref (snapshotTimestamp), std::ref (description),
105112 std::ref (snapshotId), std::ref (numDocs)),
106113 &persistenceManager,
107114 -1 ,
@@ -217,6 +224,8 @@ class CTestFixture {
217224 ml::api::CPersistenceManager persistenceManager{
218225 30000 , false , backgroundDataAdder, foregroundDataAdder};
219226
227+ ml::core_t ::TTime snapshotTimestamp;
228+ std::string description;
220229 std::string snapshotId;
221230 std::size_t numDocs{0 };
222231
@@ -232,6 +241,7 @@ class CTestFixture {
232241 modelConfig,
233242 wrappedOutputStream,
234243 std::bind (&reportPersistComplete, std::placeholders::_1,
244+ std::ref (snapshotTimestamp), std::ref (description),
235245 std::ref (snapshotId), std::ref (numDocs)),
236246 &persistenceManager,
237247 -1 ,
@@ -287,8 +297,106 @@ class CTestFixture {
287297
288298 BOOST_REQUIRE_EQUAL (backgroundState, foregroundState);
289299 }
300+
301+ void foregroundPersistWithGivenSnapshotDescriptors (const std::string& configFileName) {
302+ // Start by creating processors with non-trivial state
303+
304+ static const ml::core_t ::TTime BUCKET_SIZE{3600 };
305+ static const std::string JOB_ID{" job" };
306+
307+ std::string inputFilename{" testfiles/big_ascending.txt" };
308+
309+ // Open the input and output files
310+ std::ifstream inputStrm{inputFilename};
311+ BOOST_TEST_REQUIRE (inputStrm.is_open ());
312+
313+ std::ofstream outputStrm{ml::core::COsFileFuncs::NULL_FILENAME};
314+ BOOST_TEST_REQUIRE (outputStrm.is_open ());
315+
316+ ml::model::CLimits limits;
317+ ml::api::CFieldConfig fieldConfig;
318+ BOOST_TEST_REQUIRE (fieldConfig.initFromFile (configFileName));
319+
320+ ml::model::CAnomalyDetectorModelConfig modelConfig{
321+ ml::model::CAnomalyDetectorModelConfig::defaultConfig (BUCKET_SIZE)};
322+
323+ std::ostringstream* dataStream{nullptr };
324+ ml::api::CSingleStreamDataAdder::TOStreamP dataStreamPtr{
325+ dataStream = new std::ostringstream ()};
326+
327+ // Persist the processors' state
328+ ml::api::CSingleStreamDataAdder dataAdder{dataStreamPtr};
329+
330+ // The 30000 second persist interval is set large enough that the timer
331+ // will not trigger during the test - we bypass the timer in this test
332+ // and kick off the background persistence chain explicitly
333+ ml::api::CPersistenceManager persistenceManager{30000 , false , dataAdder};
334+
335+ ml::core_t ::TTime snapshotTimestamp_;
336+ std::string description_;
337+ std::string snapshotId_;
338+ std::size_t numDocs_{0 };
339+
340+ std::string backgroundSnapshotId;
341+ std::string foregroundSnapshotId;
342+
343+ {
344+ ml::core::CJsonOutputStreamWrapper wrappedOutputStream{outputStrm};
345+
346+ CTestAnomalyJob job{
347+ JOB_ID,
348+ limits,
349+ fieldConfig,
350+ modelConfig,
351+ wrappedOutputStream,
352+ std::bind (&reportPersistComplete, std::placeholders::_1,
353+ std::ref (snapshotTimestamp_), std::ref (description_),
354+ std::ref (snapshotId_), std::ref (numDocs_)),
355+ &persistenceManager,
356+ -1 ,
357+ " time" ,
358+ " %d/%b/%Y:%T %z" };
359+
360+ ml::api::CDataProcessor* firstProcessor{&job};
361+
362+ ml::api::CNdJsonInputParser parser{
363+ {CTestFieldDataCategorizer::MLCATEGORY_NAME}, inputStrm};
364+
365+ BOOST_TEST_REQUIRE (parser.readStreamIntoMaps (
366+ [firstProcessor](const ml::api::CDataProcessor::TStrStrUMap& dataRowFields) {
367+ return firstProcessor->handleRecord (
368+ dataRowFields, ml::api::CDataProcessor::TOptionalTime{});
369+ }));
370+
371+ // Ensure the model size stats are up to date
372+ job.finalise ();
373+
374+ ml::core_t ::TTime snapshotTimestamp{1283524206 };
375+ const std::string snapshotId{" my_special_snapshot" };
376+ const std::string description{" Supplied description for snapshot at " +
377+ ml::core::CTimeUtils::toIso8601 (snapshotTimestamp)};
378+ BOOST_TEST_REQUIRE (job.doPersistStateInForeground (
379+ dataAdder, description, snapshotId, snapshotTimestamp));
380+
381+ // Check that the snapshot description and Id reported by the "persist complete"
382+ // handler match those supplied to the persist function
383+ BOOST_REQUIRE_EQUAL (snapshotTimestamp, snapshotTimestamp_);
384+ BOOST_REQUIRE_EQUAL (description, description_);
385+ BOOST_REQUIRE_EQUAL (snapshotId, snapshotId_);
386+
387+ std::string state{dataStream->str ()};
388+
389+ // Compare snapshot ID embedded in the state string with the supplied value.
390+ const std::string expectedId{" job_model_state_" + snapshotId + " #1" };
391+ BOOST_TEST_REQUIRE (state.find (expectedId) != std::string::npos);
392+ }
393+ }
290394};
291395
396+ BOOST_FIXTURE_TEST_CASE (testDetectorPersistByWithGivenSnapshotDescriptors, CTestFixture) {
397+ this ->foregroundPersistWithGivenSnapshotDescriptors (" testfiles/new_mlfields.conf" );
398+ }
399+
292400BOOST_FIXTURE_TEST_CASE (testDetectorPersistBy, CTestFixture) {
293401 this ->foregroundBackgroundCompCategorizationAndAnomalyDetection (" testfiles/new_mlfields.conf" );
294402}
0 commit comments