github.com/uchennaokeke444/nomad@v0.11.8/nomad/deploymentwatcher/testutil_test.go (about)

     1  package deploymentwatcher
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"sync"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/nomad/nomad/state"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  	mocker "github.com/stretchr/testify/mock"
    12  )
    13  
    14  type mockBackend struct {
    15  	mocker.Mock
    16  	index uint64
    17  	state *state.StateStore
    18  	l     sync.Mutex
    19  }
    20  
    21  func newMockBackend(t *testing.T) *mockBackend {
    22  	m := &mockBackend{
    23  		index: 10000,
    24  		state: state.TestStateStore(t),
    25  	}
    26  	m.Test(t)
    27  	return m
    28  }
    29  
    30  func (m *mockBackend) nextIndex() uint64 {
    31  	m.l.Lock()
    32  	defer m.l.Unlock()
    33  	i := m.index
    34  	m.index++
    35  	return i
    36  }
    37  
    38  func (m *mockBackend) UpdateAllocDesiredTransition(u *structs.AllocUpdateDesiredTransitionRequest) (uint64, error) {
    39  	m.Called(u)
    40  	i := m.nextIndex()
    41  	return i, m.state.UpdateAllocsDesiredTransitions(i, u.Allocs, u.Evals)
    42  }
    43  
    44  // matchUpdateAllocDesiredTransitions is used to match an upsert request
    45  func matchUpdateAllocDesiredTransitions(deploymentIDs []string) func(update *structs.AllocUpdateDesiredTransitionRequest) bool {
    46  	return func(update *structs.AllocUpdateDesiredTransitionRequest) bool {
    47  		if len(update.Evals) != len(deploymentIDs) {
    48  			return false
    49  		}
    50  
    51  		dmap := make(map[string]struct{}, len(deploymentIDs))
    52  		for _, d := range deploymentIDs {
    53  			dmap[d] = struct{}{}
    54  		}
    55  
    56  		for _, e := range update.Evals {
    57  			if _, ok := dmap[e.DeploymentID]; !ok {
    58  				return false
    59  			}
    60  
    61  			delete(dmap, e.DeploymentID)
    62  		}
    63  
    64  		return true
    65  	}
    66  }
    67  
    68  // matchUpdateAllocDesiredTransitionReschedule is used to match allocs that have their DesiredTransition set to Reschedule
    69  func matchUpdateAllocDesiredTransitionReschedule(allocIDs []string) func(update *structs.AllocUpdateDesiredTransitionRequest) bool {
    70  	return func(update *structs.AllocUpdateDesiredTransitionRequest) bool {
    71  		amap := make(map[string]struct{}, len(allocIDs))
    72  		for _, d := range allocIDs {
    73  			amap[d] = struct{}{}
    74  		}
    75  
    76  		for allocID, dt := range update.Allocs {
    77  			if _, ok := amap[allocID]; !ok {
    78  				return false
    79  			}
    80  			if !*dt.Reschedule {
    81  				return false
    82  			}
    83  		}
    84  
    85  		return true
    86  	}
    87  }
    88  
    89  func (m *mockBackend) UpsertJob(job *structs.Job) (uint64, error) {
    90  	m.Called(job)
    91  	i := m.nextIndex()
    92  	return i, m.state.UpsertJob(i, job)
    93  }
    94  
    95  func (m *mockBackend) UpdateDeploymentStatus(u *structs.DeploymentStatusUpdateRequest) (uint64, error) {
    96  	m.Called(u)
    97  	i := m.nextIndex()
    98  	return i, m.state.UpdateDeploymentStatus(i, u)
    99  }
   100  
   101  // matchDeploymentStatusUpdateConfig is used to configure the matching
   102  // function
   103  type matchDeploymentStatusUpdateConfig struct {
   104  	// DeploymentID is the expected ID
   105  	DeploymentID string
   106  
   107  	// Status is the desired status
   108  	Status string
   109  
   110  	// StatusDescription is the desired status description
   111  	StatusDescription string
   112  
   113  	// JobVersion marks whether we expect a roll back job at the given version
   114  	JobVersion *uint64
   115  
   116  	// Eval marks whether we expect an evaluation.
   117  	Eval bool
   118  }
   119  
   120  // matchDeploymentStatusUpdateRequest is used to match an update request
   121  func matchDeploymentStatusUpdateRequest(c *matchDeploymentStatusUpdateConfig) func(args *structs.DeploymentStatusUpdateRequest) bool {
   122  	return func(args *structs.DeploymentStatusUpdateRequest) bool {
   123  		if args.DeploymentUpdate.DeploymentID != c.DeploymentID {
   124  			return false
   125  		}
   126  
   127  		if args.DeploymentUpdate.Status != c.Status && args.DeploymentUpdate.StatusDescription != c.StatusDescription {
   128  			return false
   129  		}
   130  
   131  		if c.Eval && args.Eval == nil || !c.Eval && args.Eval != nil {
   132  			return false
   133  		}
   134  
   135  		if c.JobVersion != nil {
   136  			if args.Job == nil {
   137  				return false
   138  			} else if args.Job.Version != *c.JobVersion {
   139  				return false
   140  			}
   141  		} else if c.JobVersion == nil && args.Job != nil {
   142  			return false
   143  		}
   144  
   145  		return true
   146  	}
   147  }
   148  
   149  func (m *mockBackend) UpdateDeploymentPromotion(req *structs.ApplyDeploymentPromoteRequest) (uint64, error) {
   150  	m.Called(req)
   151  	i := m.nextIndex()
   152  	return i, m.state.UpdateDeploymentPromotion(i, req)
   153  }
   154  
   155  // matchDeploymentPromoteRequestConfig is used to configure the matching
   156  // function
   157  type matchDeploymentPromoteRequestConfig struct {
   158  	// Promotion holds the expected promote request
   159  	Promotion *structs.DeploymentPromoteRequest
   160  
   161  	// Eval marks whether we expect an evaluation.
   162  	Eval bool
   163  }
   164  
   165  // matchDeploymentPromoteRequest is used to match a promote request
   166  func matchDeploymentPromoteRequest(c *matchDeploymentPromoteRequestConfig) func(args *structs.ApplyDeploymentPromoteRequest) bool {
   167  	return func(args *structs.ApplyDeploymentPromoteRequest) bool {
   168  		if !reflect.DeepEqual(*c.Promotion, args.DeploymentPromoteRequest) {
   169  			return false
   170  		}
   171  
   172  		if c.Eval && args.Eval == nil || !c.Eval && args.Eval != nil {
   173  			return false
   174  		}
   175  
   176  		return true
   177  	}
   178  }
   179  func (m *mockBackend) UpdateDeploymentAllocHealth(req *structs.ApplyDeploymentAllocHealthRequest) (uint64, error) {
   180  	m.Called(req)
   181  	i := m.nextIndex()
   182  	return i, m.state.UpdateDeploymentAllocHealth(i, req)
   183  }
   184  
   185  // matchDeploymentAllocHealthRequestConfig is used to configure the matching
   186  // function
   187  type matchDeploymentAllocHealthRequestConfig struct {
   188  	// DeploymentID is the expected ID
   189  	DeploymentID string
   190  
   191  	// Healthy and Unhealthy contain the expected allocation IDs that are having
   192  	// their health set
   193  	Healthy, Unhealthy []string
   194  
   195  	// DeploymentUpdate holds the expected values of status and description. We
   196  	// don't check for exact match but string contains
   197  	DeploymentUpdate *structs.DeploymentStatusUpdate
   198  
   199  	// JobVersion marks whether we expect a roll back job at the given version
   200  	JobVersion *uint64
   201  
   202  	// Eval marks whether we expect an evaluation.
   203  	Eval bool
   204  }
   205  
   206  // matchDeploymentAllocHealthRequest is used to match an update request
   207  func matchDeploymentAllocHealthRequest(c *matchDeploymentAllocHealthRequestConfig) func(args *structs.ApplyDeploymentAllocHealthRequest) bool {
   208  	return func(args *structs.ApplyDeploymentAllocHealthRequest) bool {
   209  		if args.DeploymentID != c.DeploymentID {
   210  			return false
   211  		}
   212  
   213  		// Require a timestamp
   214  		if args.Timestamp.IsZero() {
   215  			return false
   216  		}
   217  
   218  		if len(c.Healthy) != len(args.HealthyAllocationIDs) {
   219  			return false
   220  		}
   221  		if len(c.Unhealthy) != len(args.UnhealthyAllocationIDs) {
   222  			return false
   223  		}
   224  
   225  		hmap, umap := make(map[string]struct{}, len(c.Healthy)), make(map[string]struct{}, len(c.Unhealthy))
   226  		for _, h := range c.Healthy {
   227  			hmap[h] = struct{}{}
   228  		}
   229  		for _, u := range c.Unhealthy {
   230  			umap[u] = struct{}{}
   231  		}
   232  
   233  		for _, h := range args.HealthyAllocationIDs {
   234  			if _, ok := hmap[h]; !ok {
   235  				return false
   236  			}
   237  		}
   238  		for _, u := range args.UnhealthyAllocationIDs {
   239  			if _, ok := umap[u]; !ok {
   240  				return false
   241  			}
   242  		}
   243  
   244  		if c.DeploymentUpdate != nil {
   245  			if args.DeploymentUpdate == nil {
   246  				return false
   247  			}
   248  
   249  			if !strings.Contains(args.DeploymentUpdate.Status, c.DeploymentUpdate.Status) {
   250  				return false
   251  			}
   252  			if !strings.Contains(args.DeploymentUpdate.StatusDescription, c.DeploymentUpdate.StatusDescription) {
   253  				return false
   254  			}
   255  		} else if args.DeploymentUpdate != nil {
   256  			return false
   257  		}
   258  
   259  		if c.Eval && args.Eval == nil || !c.Eval && args.Eval != nil {
   260  			return false
   261  		}
   262  
   263  		if (c.JobVersion != nil && (args.Job == nil || args.Job.Version != *c.JobVersion)) || c.JobVersion == nil && args.Job != nil {
   264  			return false
   265  		}
   266  
   267  		return true
   268  	}
   269  }