github.com/hernad/nomad@v1.6.112/nomad/plan_normalization_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package nomad
     5  
     6  import (
     7  	"bytes"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/hashicorp/go-msgpack/codec"
    12  	"github.com/hernad/nomad/ci"
    13  	"github.com/hernad/nomad/nomad/mock"
    14  	"github.com/hernad/nomad/nomad/structs"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  // This test compares the size of the normalized + OmitEmpty raft plan log entry
    19  // with the earlier denormalized log.
    20  //
    21  // Whenever this test is changed, care should be taken to ensure the older msgpack size
    22  // is recalculated when new fields are introduced in ApplyPlanResultsRequest
    23  func TestPlanNormalize(t *testing.T) {
    24  	ci.Parallel(t)
    25  
    26  	// This size was calculated using the older ApplyPlanResultsRequest format, in which allocations
    27  	// didn't use OmitEmpty and only the job was normalized in the stopped and preempted allocs.
    28  	// The newer format uses OmitEmpty and uses a minimal set of fields for the diff of the
    29  	// stopped and preempted allocs. The file for the older format hasn't been checked in, because
    30  	// it's not a good idea to check-in a 20mb file to the git repo.
    31  	unoptimizedLogSize := 19460168
    32  
    33  	numUpdatedAllocs := 10000
    34  	numStoppedAllocs := 8000
    35  	numPreemptedAllocs := 2000
    36  	mockAlloc := mock.Alloc()
    37  	mockAlloc.Job = nil
    38  
    39  	mockUpdatedAllocSlice := make([]*structs.Allocation, numUpdatedAllocs)
    40  	for i := 0; i < numUpdatedAllocs; i++ {
    41  		mockUpdatedAllocSlice = append(mockUpdatedAllocSlice, mockAlloc)
    42  	}
    43  
    44  	now := time.Now().UTC().UnixNano()
    45  	mockStoppedAllocSlice := make([]*structs.AllocationDiff, numStoppedAllocs)
    46  	for i := 0; i < numStoppedAllocs; i++ {
    47  		mockStoppedAllocSlice = append(mockStoppedAllocSlice, normalizeStoppedAlloc(mockAlloc, now))
    48  	}
    49  
    50  	mockPreemptionAllocSlice := make([]*structs.AllocationDiff, numPreemptedAllocs)
    51  	for i := 0; i < numPreemptedAllocs; i++ {
    52  		mockPreemptionAllocSlice = append(mockPreemptionAllocSlice, normalizePreemptedAlloc(mockAlloc, now))
    53  	}
    54  
    55  	// Create a plan result
    56  	applyPlanLogEntry := structs.ApplyPlanResultsRequest{
    57  		AllocUpdateRequest: structs.AllocUpdateRequest{
    58  			AllocsUpdated: mockUpdatedAllocSlice,
    59  			AllocsStopped: mockStoppedAllocSlice,
    60  		},
    61  		AllocsPreempted: mockPreemptionAllocSlice,
    62  	}
    63  
    64  	handle := structs.MsgpackHandle
    65  	var buf bytes.Buffer
    66  	if err := codec.NewEncoder(&buf, handle).Encode(applyPlanLogEntry); err != nil {
    67  		t.Fatalf("Encoding failed: %v", err)
    68  	}
    69  
    70  	optimizedLogSize := buf.Len()
    71  	assert.Less(t, float64(optimizedLogSize)/float64(unoptimizedLogSize), 0.67)
    72  }