func TestReconciler_PausedOrFailedDeployment_Migrations(t *testing.T) {
	job := mock.Job()
	job.TaskGroups[0].Update = noCanaryUpdate

	cases := []struct {
		name              string
		deploymentStatus  string
		place             int
		stop              int
		ignoreAnnotation  uint64
		migrateAnnotation uint64
		stopAnnotation    uint64
	}{
		{
			name:             "paused deployment",
			deploymentStatus: structs.DeploymentStatusPaused,
			place:            0,
			stop:             3,
			ignoreAnnotation: 5,
			stopAnnotation:   3,
		},
		{
			name:              "failed deployment",
			deploymentStatus:  structs.DeploymentStatusFailed,
			place:             0,
			stop:              3,
			ignoreAnnotation:  5,
			migrateAnnotation: 0,
			stopAnnotation:    3,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			// Create a deployment that is paused and has placed some canaries
			d := structs.NewDeployment(job)
			d.Status = c.deploymentStatus
			d.TaskGroups[job.TaskGroups[0].Name] = &structs.DeploymentState{
				Promoted:     false,
				DesiredTotal: 10,
				PlacedAllocs: 8,
			}

			// Create 8 allocations in the deployment
			var allocs []*structs.Allocation
			for i := 0; i < 8; i++ {
				alloc := mock.Alloc()
				alloc.Job = job
				alloc.JobID = job.ID
				alloc.NodeID = structs.GenerateUUID()
				alloc.Name = structs.AllocName(job.ID, job.TaskGroups[0].Name, uint(i))
				alloc.TaskGroup = job.TaskGroups[0].Name
				alloc.DeploymentID = d.ID
				allocs = append(allocs, alloc)
			}

			// Build a map of tainted nodes
			tainted := make(map[string]*structs.Node, 3)
			for i := 0; i < 3; i++ {
				n := mock.Node()
				n.ID = allocs[i].NodeID
				n.Drain = true
				tainted[n.ID] = n
			}

			reconciler := NewAllocReconciler(testLogger(), allocUpdateFnIgnore, false, job.ID, job, d, allocs, tainted)
			r := reconciler.Compute()

			// Assert the correct results
			assertResults(t, r, &resultExpectation{
				createDeployment:  nil,
				deploymentUpdates: nil,
				place:             c.place,
				inplace:           0,
				stop:              c.stop,
				desiredTGUpdates: map[string]*structs.DesiredUpdates{
					job.TaskGroups[0].Name: {
						Migrate: c.migrateAnnotation,
						Ignore:  c.ignoreAnnotation,
						Stop:    c.stopAnnotation,
					},
				},
			})
		})
	}
}
// Tests the reconciler handles migrations correctly when a deployment is paused
// or failed
Tests the reconciler handles migrations correctly when a deployment is paused
or failed
// Tests the reconciler handles migrations correctly when a deployment is paused // or failed
func TestReconciler_PausedOrFailedDeployment_Migrations(t *testing.T) {
	job := mock.Job()
	job.TaskGroups[0].Update = noCanaryUpdate
	cases := []struct {
		name              string
		deploymentStatus  string
		place             int
		stop              int
		ignoreAnnotation  uint64
		migrateAnnotation uint64
		stopAnnotation    uint64
	}{
		{
			name:             "paused deployment",
			deploymentStatus: structs.DeploymentStatusPaused,
			place:            0,
			stop:             3,
			ignoreAnnotation: 5,
			stopAnnotation:   3,
		},
		{
			name:              "failed deployment",
			deploymentStatus:  structs.DeploymentStatusFailed,
			place:             0,
			stop:              3,
			ignoreAnnotation:  5,
			migrateAnnotation: 0,
			stopAnnotation:    3,
		},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			d := structs.NewDeployment(job)
			d.Status = c.deploymentStatus
			d.TaskGroups[job.TaskGroups[0].Name] = &structs.DeploymentState{
				Promoted:     false,
				DesiredTotal: 10,
				PlacedAllocs: 8,
			}
			var allocs []*structs.Allocation
			for i := 0; i < 8; i++ {
				alloc := mock.Alloc()
				alloc.Job = job
				alloc.JobID = job.ID
				alloc.NodeID = structs.GenerateUUID()
				alloc.Name = structs.AllocName(job.ID, job.TaskGroups[0].Name, uint(i))
				alloc.TaskGroup = job.TaskGroups[0].Name
				alloc.DeploymentID = d.ID
				allocs = append(allocs, alloc)
			}
			tainted := make(map[string]*structs.Node, 3)
			for i := 0; i < 3; i++ {
				n := mock.Node()
				n.ID = allocs[i].NodeID
				n.Drain = true
				tainted[n.ID] = n
			}
			reconciler := NewAllocReconciler(testLogger(), allocUpdateFnIgnore, false, job.ID, job, d, allocs, tainted)
			r := reconciler.Compute()
			assertResults(t, r, &resultExpectation{
				createDeployment:  nil,
				deploymentUpdates: nil,
				place:             c.place,
				inplace:           0,
				stop:              c.stop,
				desiredTGUpdates: map[string]*structs.DesiredUpdates{
					job.TaskGroups[0].Name: {
						Migrate: c.migrateAnnotation,
						Ignore:  c.ignoreAnnotation,
						Stop:    c.stopAnnotation,
					},
				},
			})
		})
	}
}
func TestReconciler_PausedOrFailedDeployment_Migrations ( t * testing . T ) { job := mock . Job ( ) job . TaskGroups [ 0 ] . Update = noCanaryUpdate cases := [ ] struct { name string deploymentStatus string place int stop int ignoreAnnotation uint64 migrateAnnotation uint64 stopAnnotation uint64 } { { name : " " , deploymentStatus : structs . DeploymentStatusPaused , place : 0 , stop : 3 , ignoreAnnotation : 5 , stopAnnotation : 3 , } , { name : " " , deploymentStatus : structs . DeploymentStatusFailed , place : 0 , stop : 3 , ignoreAnnotation : 5 , migrateAnnotation : 0 , stopAnnotation : 3 , } , } for _ , c := range cases { t . Run ( c . name , func ( t * testing . T ) { d := structs . NewDeployment ( job ) d . Status = c . deploymentStatus d . TaskGroups [ job . TaskGroups [ 0 ] . Name ] = & structs . DeploymentState { Promoted : false , DesiredTotal : 10 , PlacedAllocs : 8 , } var allocs [ ] * structs . Allocation for i := 0 ; i < 8 ; i ++ { alloc := mock . Alloc ( ) alloc . Job = job alloc . JobID = job . ID alloc . NodeID = structs . GenerateUUID ( ) alloc . Name = structs . AllocName ( job . ID , job . TaskGroups [ 0 ] . Name , uint ( i ) ) alloc . TaskGroup = job . TaskGroups [ 0 ] . Name alloc . DeploymentID = d . ID allocs = append ( allocs , alloc ) } tainted := make ( map [ string ] * structs . Node , 3 ) for i := 0 ; i < 3 ; i ++ { n := mock . Node ( ) n . ID = allocs [ i ] . NodeID n . Drain = true tainted [ n . ID ] = n } reconciler := NewAllocReconciler ( testLogger ( ) , allocUpdateFnIgnore , false , job . ID , job , d , allocs , tainted ) r := reconciler . Compute ( ) assertResults ( t , r , & resultExpectation { createDeployment : nil , deploymentUpdates : nil , place : c . place , inplace : 0 , stop : c . stop , desiredTGUpdates : map [ string ] * structs . DesiredUpdates { job . TaskGroups [ 0 ] . Name : { Migrate : c . migrateAnnotation , Ignore : c . ignoreAnnotation , Stop : c . stopAnnotation , } , } , } ) } ) } }
Tests the reconciler handles migrations correctly when a deployment is paused
or failed
Tests the reconciler handles migrations correctly when a deployment is paused or failed
// Create a deployment that is paused and has placed some canaries // Create 8 allocations in the deployment // Build a map of tainted nodes // Assert the correct results