Skip to content

Commit f749ab9

Browse files
committed
Fix bug where azkaban prop.contains(object) is checking value not key as intended
1 parent 401fb30 commit f749ab9

File tree

4 files changed

+43
-50
lines changed

4 files changed

+43
-50
lines changed

gobblin-data-management/src/main/java/org/apache/gobblin/data/management/trash/TimeBasedSnapshotCleanupPolicy.java

+3-8
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import org.apache.hadoop.fs.FileStatus;
2323
import org.joda.time.DateTime;
24-
import org.joda.time.DateTimeZone;
2524

2625

2726
/**
@@ -31,21 +30,17 @@ public class TimeBasedSnapshotCleanupPolicy implements SnapshotCleanupPolicy {
3130

3231
public static final String SNAPSHOT_RETENTION_POLICY_MINUTES_KEY = "gobblin.trash.snapshot.retention.minutes";
3332
public static final int SNAPSHOT_RETENTION_POLICY_MINUTES_DEFAULT = 1440; // one day
34-
public static final String RETENTION_SNAPSHOT_TIMEZONE = "gobblin.trash.snapshot.retention.timezone";
3533

36-
protected final int retentionMinutes;
37-
protected final DateTimeZone retentionSnapshotTimezone;
34+
private final int retentionMinutes;
3835

3936
public TimeBasedSnapshotCleanupPolicy(Properties props) {
4037
this.retentionMinutes = Integer.parseInt(props.getProperty(SNAPSHOT_RETENTION_POLICY_MINUTES_KEY,
4138
Integer.toString(SNAPSHOT_RETENTION_POLICY_MINUTES_DEFAULT)));
42-
this.retentionSnapshotTimezone = props.containsKey(RETENTION_SNAPSHOT_TIMEZONE) ? DateTimeZone.forID(props.getProperty(RETENTION_SNAPSHOT_TIMEZONE)) : DateTimeZone.getDefault();
4339
}
4440

4541
@Override
4642
public boolean shouldDeleteSnapshot(FileStatus snapshot, Trash trash) {
4743
DateTime snapshotTime = Trash.TRASH_SNAPSHOT_NAME_FORMATTER.parseDateTime(snapshot.getPath().getName());
48-
// Ensure that the comparison between snapshotTime and the current time can be done in the same time zone (UTC) with timezone specified in the propertie (Default to system time zone)
49-
return snapshotTime.plusMinutes(this.retentionMinutes).isBefore(DateTime.now(this.retentionSnapshotTimezone));
44+
return snapshotTime.plusMinutes(this.retentionMinutes).isBeforeNow();
5045
}
51-
}
46+
}

gobblin-data-management/src/main/java/org/apache/gobblin/data/management/trash/Trash.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ protected Trash(FileSystem fs, Properties props, String user) throws IOException
178178
}
179179

180180
public static Trash getTrash(FileSystem fs, Properties props, String user) throws IOException {
181-
if (props.contains(TRASH_CLASS_KEY)) {
181+
if (props.containsKey(TRASH_CLASS_KEY)) {
182182
return GobblinConstructorUtils.invokeConstructor(Trash.class, props.getProperty(TRASH_CLASS_KEY), fs, props, user);
183183
} else {
184184
return new Trash(fs, props, user);

gobblin-data-management/src/test/java/org/apache/gobblin/data/management/trash/TimeBasedSnapshotCleanupPolicyTest.java

+16-41
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,15 @@
3030

3131
public class TimeBasedSnapshotCleanupPolicyTest {
3232

33-
private MockTimeBasedSnapshotCleanupPolicy cleanupPolicy;
33+
private TimeBasedSnapshotCleanupPolicy cleanupPolicy;
3434

3535
@BeforeMethod
3636
public void setUp() {
37-
// Initialize the cleanup policy with a retention period (e.g., 1 day)
37+
// Initialize the cleanup policy with a retention period of 600 minutes (10 hours)
3838
Properties properties = new Properties();
39-
properties.setProperty(MockTimeBasedSnapshotCleanupPolicy.SNAPSHOT_RETENTION_POLICY_MINUTES_KEY, "1440"); // 1440 minutes = 1 day
40-
properties.setProperty(MockTimeBasedSnapshotCleanupPolicy.RETENTION_SNAPSHOT_TIMEZONE, "UTC");
41-
// Mock the cutoff time to be 2024-10-30 01:01:00 UTC
42-
cleanupPolicy = new MockTimeBasedSnapshotCleanupPolicy(properties, new DateTime(2024, 10, 30, 1, 1));
39+
properties.setProperty(TimeBasedSnapshotCleanupPolicy.SNAPSHOT_RETENTION_POLICY_MINUTES_KEY, "600"); // 600 minutes = 10 hours
40+
cleanupPolicy = new TimeBasedSnapshotCleanupPolicy(properties);
41+
4342
}
4443

4544
@Test
@@ -49,42 +48,18 @@ public void testShouldDeleteSnapshot() throws IOException {
4948
TrashTestBase trashTestBase = new TrashTestBase(new Properties());
5049
Trash trash = trashTestBase.trash;
5150

52-
// Create dummy paths
53-
FileStatus fs1 = new FileStatus(0, true, 0, 0, 0,
54-
new Path(trash.getTrashLocation(), new DateTime(2024, 10, 29, 1, 0, DateTimeZone.UTC).toString(Trash.TRASH_SNAPSHOT_NAME_FORMATTER)));
55-
FileStatus fs2 = new FileStatus(0, true, 0, 0, 0,
56-
new Path(trash.getTrashLocation(), new DateTime(2024, 10, 29, 2, 0, DateTimeZone.UTC).toString(Trash.TRASH_SNAPSHOT_NAME_FORMATTER)));
51+
// Get the current time
52+
DateTime now = DateTime.now(DateTimeZone.UTC);
5753

58-
// Test old snapshot (should be deleted)
59-
// 2024-10-29 01:00:00 UTC + 1440 minutes = 2024-10-30 01:00:00 UTC < Cutoff time a.k.a system current_time (2024-10-30 01:01:00 UTC)
60-
Assert.assertTrue(cleanupPolicy.shouldDeleteSnapshot(fs1, trash), "Old snapshot should be deleted");
54+
// Create dummy paths with timestamps between 11 and 9 hours ago in UTC
55+
FileStatus fs1 = new FileStatus(0, true, 0, 0, 0,
56+
new Path(trash.getTrashLocation(), now.minusHours(11).toString(Trash.TRASH_SNAPSHOT_NAME_FORMATTER)));
57+
FileStatus fs2 = new FileStatus(0, true, 0, 0, 0,
58+
new Path(trash.getTrashLocation(), now.minusHours(9).toString(Trash.TRASH_SNAPSHOT_NAME_FORMATTER)));
6159

62-
// Test snapshot (should not be deleted)
63-
// 2024-10-29 02:00:00 UTC + 1440 minutes = 2024-10-30 02:00:00 UTC > Cutoff time a.k.a system current_time (2024-10-30 01:01:00 UTC)
64-
Assert.assertFalse(cleanupPolicy.shouldDeleteSnapshot(fs2, trash), "snapshot should not be deleted");
60+
// Test snapshot (should be deleted)
61+
Assert.assertTrue(cleanupPolicy.shouldDeleteSnapshot(fs1, trash),"Snapshot should be deleted");
62+
// Test snapshot (should NOT be deleted)
63+
Assert.assertFalse(cleanupPolicy.shouldDeleteSnapshot(fs2, trash),"Snapshot should NOT be deleted");
6564
}
66-
67-
/**
68-
* Mock the TimeBasedSnapshotCleanupPolicy for testing purposes
69-
*
70-
* In this class, the current time used in the comparison method isBefore() can be mocked
71-
* Why? The current time is used to determine if a snapshot is older than the retention period,
72-
* and given that the current time is always changing, it is difficult to test the method shouldDeleteSnapshot()
73-
*/
74-
public class MockTimeBasedSnapshotCleanupPolicy extends TimeBasedSnapshotCleanupPolicy {
75-
76-
private final DateTime MOCK_CURRENT_TIME;
77-
78-
public MockTimeBasedSnapshotCleanupPolicy(Properties props, DateTime mockCurrentTime) {
79-
super(props);
80-
this.MOCK_CURRENT_TIME = mockCurrentTime;
81-
}
82-
83-
@Override
84-
public boolean shouldDeleteSnapshot(FileStatus snapshot, Trash trash) {
85-
DateTime snapshotTime = Trash.TRASH_SNAPSHOT_NAME_FORMATTER.parseDateTime(snapshot.getPath().getName());
86-
return snapshotTime.plusMinutes(this.retentionMinutes).isBefore(this.MOCK_CURRENT_TIME.withZoneRetainFields(this.retentionSnapshotTimezone));
87-
}
88-
}
89-
9065
}

gobblin-data-management/src/test/java/org/apache/gobblin/data/management/trash/TrashTest.java

+23
Original file line numberDiff line numberDiff line change
@@ -318,4 +318,27 @@ public Boolean answer(InvocationOnMock invocation)
318318
}
319319
}
320320

321+
/**
322+
* Test Trash.getTrash() method to ensure that the correct Trash implementation is returned based on the properties evaluation
323+
*/
324+
@Test
325+
public void testGetTrashEvanluateExpected() throws IOException {
326+
Properties properties = new Properties();
327+
properties.setProperty(Trash.TRASH_CLASS_KEY, MockTrash.class.getCanonicalName());
328+
properties.setProperty(TrashFactory.SIMULATE, "true");
329+
properties.setProperty(TrashFactory.SIMULATE_USING_ACTUAL_TRASH, "true");
330+
properties.setProperty(Trash.TRASH_LOCATION_KEY, "/trash/dir");
331+
FileSystem mockFs = mock(FileSystem.class);
332+
333+
Trash trash = Trash.getTrash(mockFs, properties, "testUser");
334+
335+
// Assert if condition is evaluated and the correct trash is returned
336+
Assert.assertTrue(trash instanceof MockTrash);
337+
338+
properties.remove(Trash.TRASH_CLASS_KEY);
339+
Trash trash2 = Trash.getTrash(mockFs, properties, "testUser");
340+
// Assert if the trash would default to Trash if the condition is not met
341+
Assert.assertTrue(trash2 instanceof Trash);
342+
}
343+
321344
}

0 commit comments

Comments
 (0)