Repository: influxdata/influxdb
File: tsdb/engine/tsm1/compact_test.go (Go)

Code before:
						Path: "08-01.tsm",
						Size: 256 * 1024 * 1024,
					},
					FirstBlockCount: 50,
				},
				{
					FileStat: tsm1.FileStat{
						Path: "09-01.tsm",
						Size: 256 * 1024 * 1024,
					},
					FirstBlockCount: 50,
				},
				{
					FileStat: tsm1.FileStat{
						Path: "10-01.tsm",
						Size: 256 * 1024 * 1024,
					},
					FirstBlockCount: 50,
				},
				{
					FileStat: tsm1.FileStat{
						Path: "11-01.tsm",
						Size: 256 * 1024 * 1024,
					},
					FirstBlockCount: 50,
				},

				{
					FileStat: tsm1.FileStat{
						Path: "12-01.tsm",
						Size: 256 * 1024 * 1024,
					},
					FirstBlockCount: 50,
				},
				{
					FileStat: tsm1.FileStat{
						Path: "13-01.tsm",
						Size: 256 * 1024 * 1024,
					},
					FirstBlockCount: 50,
				},
				{
					FileStat: tsm1.FileStat{
						Path: "14-01.tsm",
						Size: 256 * 1024 * 1024,
					},
					FirstBlockCount: 50,
				},
				{
					FileStat: tsm1.FileStat{
						Path: "01-05.tsm",

Review comment (bug):
I like that the test code mirrors the production code... but the addition here mostly verifies that Release releases. It doesn't cause this test to verify that the production code releases when it should (I tried to get the original bug to fail tests in this PR and failed). 

Testing the action that occurs in `Engine.compact()` when the timer fires would help cover that the compact driver loop is sound. Pulling the timer action into a separate method would expose the innard's to tests. Nothing is saved between compact driver loop runs. 

Not something i recommend for this pr but perhaps for future work and tests in this part of the code. 

Code after:

			// Arbitrary group length to use in Scheduler.SetDepth
			mockGroupLen := 5
			// Set the scheduler depth for our lower level groups.
			e.Scheduler.SetDepth(1, mockGroupLen)
			e.Scheduler.SetDepth(2, mockGroupLen)

			// Normally this is called within PlanCompactions but because we want to simulate already running
			// some compactions we will set them manually here.
			atomic.StoreInt64(&e.Stats.TSMCompactionsActive[0], int64(mockGroupLen))
			atomic.StoreInt64(&e.Stats.TSMCompactionsActive[1], int64(mockGroupLen))

			// Plan and check results.
			level1Groups, level2Groups, Level3Groups, Level4Groups, Level5Groups := e.PlanCompactions()
			results := test.expectedResult()
			compareLevelGroups(t, results.level1Groups, level1Groups, "unexpected level 1 Group")
			compareLevelGroups(t, results.level2Groups, level2Groups, "unexpected level 2 Group")
			compareLevelGroups(t, results.level3Groups, Level3Groups, "unexpected level 3 Group")
			compareLevelGroups(t, results.level4Groups, Level4Groups, "unexpected level 4 Group")
			compareLevelGroups(t, results.level5Groups, Level5Groups, "unexpected level 5 Group")

			// Remove all the returned compaction levels and verify that no TSM files are marked as in-use.
			// Calling e.PlanCompactions followed by e.ReleaseCompactionPlans replicates the code structure
			// of the e.compact loop.
			e.ReleaseCompactionPlans(level1Groups, level2Groups, Level3Groups, Level4Groups, Level5Groups)
			require.Zero(t, cp.InUseCount(), "some TSM files were not released properly")
		})
	}
}

func compareLevelGroups(t *testing.T, exp, got []tsm1.PlannedCompactionGroup, message string) {
	require.Lenf(t, got, len(exp), "%s %s", message, " collection length mismatch")
	for i, group := range exp {
		require.Equal(t, group.Group, got[i].Group, message)
		require.Equal(t, group.PointsPerBlock, got[i].PointsPerBlock, message)
	}
}

func assertValueEqual(t *testing.T, a, b tsm1.Value) {
	if got, exp := a.UnixNano(), b.UnixNano(); got != exp {
		t.Fatalf("time mismatch: got %v, exp %v", got, exp)
	}
	if got, exp := a.Value(), b.Value(); got != exp {
		t.Fatalf("value mismatch: got %v, exp %v", got, exp)
	}
}

func MustTSMWriter(dir string, gen int) (tsm1.TSMWriter, string) {
	f := MustTempFile(dir)
	oldName := f.Name()