github.com/emate/nomad@v0.8.2-wo-binpacking/nomad/deploymentwatcher/testutil_test.go (about)

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