Restore behaviour for adding a new interval with same tag set

- Closes #351

Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
This commit is contained in:
Thomas Lauf 2020-08-13 21:25:23 +02:00
parent ea33b29986
commit 02491f8153
6 changed files with 90 additions and 17 deletions

View file

@ -114,10 +114,11 @@ int CmdContinue (
to_copy.end = end_time; to_copy.end = end_time;
journal.startTransaction (); journal.startTransaction ();
validate (cli, rules, database, to_copy); if (validate (cli, rules, database, to_copy))
database.addInterval (to_copy, verbose); {
journal.endTransaction (); database.addInterval (to_copy, verbose);
journal.endTransaction ();
}
if (verbose) if (verbose)
{ {
std::cout << intervalSummarize (database, rules, to_copy); std::cout << intervalSummarize (database, rules, to_copy);

View file

@ -51,10 +51,11 @@ int CmdStart (
} }
journal.startTransaction (); journal.startTransaction ();
validate (cli, rules, database, interval); if (validate (cli, rules, database, interval))
database.addInterval (interval, verbose); {
journal.endTransaction (); database.addInterval (interval, verbose);
journal.endTransaction ();
}
if (verbose) if (verbose)
{ {
std::cout << intervalSummarize (database, rules, interval); std::cout << intervalSummarize (database, rules, interval);

View file

@ -59,7 +59,7 @@ Range getFullDay (const Datetime&);
// validate.cpp // validate.cpp
void autoFill (const Rules&, Database&, Interval&); void autoFill (const Rules&, Database&, Interval&);
void validate (const CLI& cli, const Rules& rules, Database&, Interval&); bool validate (const CLI& cli, const Rules& rules, Database&, Interval&);
// init.cpp // init.cpp
bool lightweightVersionCheck (int, const char**); bool lightweightVersionCheck (int, const char**);

View file

@ -91,7 +91,7 @@ void autoFill (
// can involve rejection, adjustment of modified interval, or adjustment of // can involve rejection, adjustment of modified interval, or adjustment of
// recorded data. // recorded data.
// //
static void autoAdjust ( static bool autoAdjust (
bool adjust, bool adjust,
const Rules& rules, const Rules& rules,
Database& database, Database& database,
@ -108,7 +108,7 @@ static void autoAdjust (
{ {
// If the new interval tags match those of the currently open interval, // If the new interval tags match those of the currently open interval,
// then do nothing - the tags are already being tracked. // then do nothing - the tags are already being tracked.
return; return false;
} }
database.deleteInterval (latest); database.deleteInterval (latest);
@ -128,7 +128,7 @@ static void autoAdjust (
if (overlaps.empty ()) if (overlaps.empty ())
{ {
return; return true;
} }
debug ("Input " + interval.dump ()); debug ("Input " + interval.dump ());
@ -195,10 +195,11 @@ static void autoAdjust (
} }
} }
} }
return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void validate ( bool validate (
const CLI& cli, const CLI& cli,
const Rules& rules, const Rules& rules,
Database& database, Database& database,
@ -210,7 +211,7 @@ void validate (
autoFill (rules, database, interval); autoFill (rules, database, interval);
} }
autoAdjust (findHint (cli, ":adjust"), rules, database, interval); return autoAdjust (findHint (cli, ":adjust"), rules, database, interval);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -394,6 +394,70 @@ class TestContinue(TestCase):
expectedTags=["FOO"], expectedTags=["FOO"],
description="continued interval") description="continued interval")
def test_continue_with_id_is_idempotent(self):
"""Verify that continuing with id is idempotent"""
now_utc = datetime.now().utcnow()
two_hours_before_utc = now_utc - timedelta(hours=2)
three_hours_before_utc = now_utc - timedelta(hours=3)
four_hours_before_utc = now_utc - timedelta(hours=4)
five_hours_before_utc = now_utc - timedelta(hours=5)
self.t("track FOO {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(five_hours_before_utc, four_hours_before_utc))
self.t("track BAR {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(four_hours_before_utc, three_hours_before_utc))
self.t("start FOO {:%Y-%m-%dT%H}:00:00Z".format(three_hours_before_utc))
self.t("continue @3 {:%Y-%m-%dT%H}:00:00Z".format(now_utc))
j = self.t.export()
self.assertEqual(len(j), 3)
self.assertClosedInterval(j[0],
expectedStart="{:%Y%m%dT%H}0000Z".format(five_hours_before_utc),
expectedEnd="{:%Y%m%dT%H}0000Z".format(four_hours_before_utc),
expectedTags=["FOO"],
description="third interval")
self.assertClosedInterval(j[1],
expectedStart="{:%Y%m%dT%H}0000Z".format(four_hours_before_utc),
expectedEnd="{:%Y%m%dT%H}0000Z".format(three_hours_before_utc),
expectedTags=["BAR"],
description="second interval")
self.assertOpenInterval(j[2],
expectedStart="{:%Y%m%dT%H}0000Z".format(three_hours_before_utc),
expectedTags=["FOO"],
description="first interval")
def test_continue_with_tag_is_idempotent(self):
"""Verify that continuing with id is idempotent"""
now_utc = datetime.now().utcnow()
two_hours_before_utc = now_utc - timedelta(hours=2)
three_hours_before_utc = now_utc - timedelta(hours=3)
four_hours_before_utc = now_utc - timedelta(hours=4)
five_hours_before_utc = now_utc - timedelta(hours=5)
self.t("track FOO {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(five_hours_before_utc, four_hours_before_utc))
self.t("track BAR {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(four_hours_before_utc, three_hours_before_utc))
self.t("start FOO {:%Y-%m-%dT%H}:00:00Z".format(three_hours_before_utc))
self.t("continue FOO {:%Y-%m-%dT%H}:00:00Z".format(now_utc))
j = self.t.export()
self.assertEqual(len(j), 3)
self.assertClosedInterval(j[0],
expectedStart="{:%Y%m%dT%H}0000Z".format(five_hours_before_utc),
expectedEnd="{:%Y%m%dT%H}0000Z".format(four_hours_before_utc),
expectedTags=["FOO"],
description="third interval")
self.assertClosedInterval(j[1],
expectedStart="{:%Y%m%dT%H}0000Z".format(four_hours_before_utc),
expectedEnd="{:%Y%m%dT%H}0000Z".format(three_hours_before_utc),
expectedTags=["BAR"],
description="second interval")
self.assertOpenInterval(j[2],
expectedStart="{:%Y%m%dT%H}0000Z".format(three_hours_before_utc),
expectedTags=["FOO"],
description="first interval")
def test_continue_with_id_and_range(self): def test_continue_with_id_and_range(self):
"""Verify that continue with a range adds a copy with same tags""" """Verify that continue with a range adds a copy with same tags"""
now_utc = datetime.now().utcnow() now_utc = datetime.now().utcnow()

View file

@ -131,11 +131,17 @@ class TestStart(TestCase):
def test_start_with_same_tags_as_current_tracking(self): def test_start_with_same_tags_as_current_tracking(self):
"""Test 'start' with same tags as current tracking should not start new tracking""" """Test 'start' with same tags as current tracking should not start new tracking"""
self.t("start 1h ago bar foo") utc_now = datetime.now().utcnow()
one_hour_ago_utc = utc_now - timedelta(hours=1)
code, out, err = self.t("start foo bar") self.t("start {:%Y-%m-%dT%H:%M:%S}Z bar foo".format(one_hour_ago_utc))
self.assertNotIn("Recorded bar foo", out) self.t("start foo bar")
j = self.t.export()
self.assertEqual(len(j), 1)
self.assertOpenInterval(j[0], expectedStart=one_hour_ago_utc, expectedTags=["foo", "bar"])
def test_single_interval_enclosing_exclusion(self): def test_single_interval_enclosing_exclusion(self):
"""Add one interval that encloses an exclusion, and is therefore flattened""" """Add one interval that encloses an exclusion, and is therefore flattened"""