package nomad import ( "bytes" "testing" "time" "github.com/hashicorp/go-msgpack/codec" "github.com/hashicorp/nomad/ci" "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" "github.com/stretchr/testify/assert" ) // This test compares the size of the normalized + OmitEmpty raft plan log entry // with the earlier denormalized log. // // Whenever this test is changed, care should be taken to ensure the older msgpack size // is recalculated when new fields are introduced in ApplyPlanResultsRequest func TestPlanNormalize(t *testing.T) { ci.Parallel(t) // This size was calculated using the older ApplyPlanResultsRequest format, in which allocations // didn't use OmitEmpty and only the job was normalized in the stopped and preempted allocs. // The newer format uses OmitEmpty and uses a minimal set of fields for the diff of the // stopped and preempted allocs. The file for the older format hasn't been checked in, because // it's not a good idea to check-in a 20mb file to the git repo. unoptimizedLogSize := 19460168 numUpdatedAllocs := 10000 numStoppedAllocs := 8000 numPreemptedAllocs := 2000 mockAlloc := mock.Alloc() mockAlloc.Job = nil mockUpdatedAllocSlice := make([]*structs.Allocation, numUpdatedAllocs) for i := 0; i < numUpdatedAllocs; i++ { mockUpdatedAllocSlice = append(mockUpdatedAllocSlice, mockAlloc) } now := time.Now().UTC().UnixNano() mockStoppedAllocSlice := make([]*structs.AllocationDiff, numStoppedAllocs) for i := 0; i < numStoppedAllocs; i++ { mockStoppedAllocSlice = append(mockStoppedAllocSlice, normalizeStoppedAlloc(mockAlloc, now)) } mockPreemptionAllocSlice := make([]*structs.AllocationDiff, numPreemptedAllocs) for i := 0; i < numPreemptedAllocs; i++ { mockPreemptionAllocSlice = append(mockPreemptionAllocSlice, normalizePreemptedAlloc(mockAlloc, now)) } // Create a plan result applyPlanLogEntry := structs.ApplyPlanResultsRequest{ AllocUpdateRequest: structs.AllocUpdateRequest{ AllocsUpdated: mockUpdatedAllocSlice, AllocsStopped: mockStoppedAllocSlice, }, AllocsPreempted: mockPreemptionAllocSlice, } handle := structs.MsgpackHandle var buf bytes.Buffer if err := codec.NewEncoder(&buf, handle).Encode(applyPlanLogEntry); err != nil { t.Fatalf("Encoding failed: %v", err) } optimizedLogSize := buf.Len() assert.Less(t, float64(optimizedLogSize)/float64(unoptimizedLogSize), 0.67) }