github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/servicecontext/task.go (about)

     1  package servicecontext
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  
     7  	"github.com/evergreen-ci/evergreen"
     8  	"github.com/evergreen-ci/evergreen/apiv3"
     9  	serviceModel "github.com/evergreen-ci/evergreen/model"
    10  	"github.com/evergreen-ci/evergreen/model/task"
    11  	"github.com/evergreen-ci/evergreen/util"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  // DBTaskConnector is a struct that implements the Task related methods
    16  // from the ServiceContext through interactions with he backing database.
    17  type DBTaskConnector struct{}
    18  
    19  // FindTaskById uses the service layer's task type to query the backing database for
    20  // the task with the given taskId.
    21  func (tc *DBTaskConnector) FindTaskById(taskId string) (*task.Task, error) {
    22  	t, err := task.FindOne(task.ById(taskId))
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  	if t == nil {
    27  		return nil, &apiv3.APIError{
    28  			StatusCode: http.StatusNotFound,
    29  			Message:    fmt.Sprintf("task with id %s not found", taskId),
    30  		}
    31  	}
    32  	return t, nil
    33  }
    34  
    35  // FindTasksByBuildId uses the service layer's task type to query the backing database for a
    36  // list of task that matches buildId. It accepts the startTaskId and a limit
    37  // to allow for pagination of the queries. It returns results sorted by taskId.
    38  func (tc *DBTaskConnector) FindTasksByBuildId(buildId, taskId, status string, limit int, sortDir int) ([]task.Task, error) {
    39  	pipeline := task.TasksByBuildIdPipeline(buildId, taskId, status, limit, sortDir)
    40  	res := []task.Task{}
    41  
    42  	err := task.Aggregate(pipeline, &res)
    43  	if err != nil {
    44  		return []task.Task{}, err
    45  	}
    46  	if len(res) == 0 {
    47  		var message string
    48  		if status != "" {
    49  			message = fmt.Sprintf("tasks from build '%s' with status '%s' "+
    50  				"not found", buildId, status)
    51  		} else {
    52  			message = fmt.Sprintf("tasks from build '%s' not found", buildId)
    53  		}
    54  		return []task.Task{}, &apiv3.APIError{
    55  			StatusCode: http.StatusNotFound,
    56  			Message:    message,
    57  		}
    58  	}
    59  
    60  	if taskId != "" {
    61  		found := false
    62  		for _, t := range res {
    63  			if t.Id == taskId {
    64  				found = true
    65  				break
    66  			}
    67  		}
    68  		if !found {
    69  			return []task.Task{}, &apiv3.APIError{
    70  				StatusCode: http.StatusNotFound,
    71  				Message:    fmt.Sprintf("task with id '%s' not found", taskId),
    72  			}
    73  		}
    74  	}
    75  	return res, nil
    76  }
    77  
    78  func (tc *DBTaskConnector) FindTasksByIds(ids []string) ([]task.Task, error) {
    79  	ts, err := task.Find(task.ByIds(ids))
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	if len(ts) == 0 {
    84  		return []task.Task{}, &apiv3.APIError{
    85  			StatusCode: http.StatusNotFound,
    86  			Message:    "no tasks found",
    87  		}
    88  	}
    89  	return ts, nil
    90  }
    91  
    92  func (tc *DBTestConnector) FindTasksByProjectAndCommit(projectId, commitHash, taskId,
    93  	status string, limit, sortDir int) ([]task.Task, error) {
    94  	pipeline := task.TasksByProjectAndCommitPipeline(projectId, commitHash, taskId,
    95  		status, limit, sortDir)
    96  	res := []task.Task{}
    97  
    98  	err := task.Aggregate(pipeline, &res)
    99  	if err != nil {
   100  		return []task.Task{}, err
   101  	}
   102  	if len(res) == 0 {
   103  		var message string
   104  		if status != "" {
   105  			message = fmt.Sprintf("task from project '%s' and commit '%s' with status '%s' "+
   106  				"not found", projectId, commitHash, status)
   107  		} else {
   108  			message = fmt.Sprintf("task from project '%s' and commit '%s' not found",
   109  				projectId, commitHash)
   110  		}
   111  		return []task.Task{}, &apiv3.APIError{
   112  			StatusCode: http.StatusNotFound,
   113  			Message:    message,
   114  		}
   115  	}
   116  
   117  	if taskId != "" {
   118  		found := false
   119  		for _, t := range res {
   120  			if t.Id == taskId {
   121  				found = true
   122  				break
   123  			}
   124  		}
   125  		if !found {
   126  			return []task.Task{}, &apiv3.APIError{
   127  				StatusCode: http.StatusNotFound,
   128  				Message:    fmt.Sprintf("task with id '%s' not found", taskId),
   129  			}
   130  		}
   131  	}
   132  	return res, nil
   133  }
   134  
   135  // SetTaskPriority changes the priority value of a task using a call to the
   136  // service layer function.
   137  func (tc *DBTaskConnector) SetTaskPriority(t *task.Task, priority int64) error {
   138  	err := t.SetPriority(priority)
   139  	return err
   140  }
   141  
   142  // SetTaskPriority changes the priority value of a task using a call to the
   143  // service layer function.
   144  func (tc *DBTaskConnector) SetTaskActivated(taskId, user string, activated bool) error {
   145  	return errors.Wrap(serviceModel.SetActiveState(taskId, user, activated),
   146  		"Erorr setting task active")
   147  }
   148  
   149  // ResetTask sets the task to be in an unexecuted state and prepares it to be
   150  // run again.
   151  func (tc *DBTaskConnector) ResetTask(taskId, username string, proj *serviceModel.Project) error {
   152  	return errors.Wrap(serviceModel.TryResetTask(taskId, username, evergreen.RESTV2Package, proj, nil),
   153  		"Reset task error")
   154  }
   155  
   156  // MockTaskConnector stores a cached set of tasks that are queried against by the
   157  // implementations of the ServiceContext interface's Task related functions.
   158  type MockTaskConnector struct {
   159  	CachedTasks []task.Task
   160  	StoredError error
   161  }
   162  
   163  // FindTaskById provides a mock implementation of the functions for the
   164  // ServiceContext interface without needing to use a database. It returns results
   165  // based on the cached tasks in the MockTaskConnector.
   166  func (mtc *MockTaskConnector) FindTaskById(taskId string) (*task.Task, error) {
   167  	for _, t := range mtc.CachedTasks {
   168  		if t.Id == taskId {
   169  			return &t, mtc.StoredError
   170  		}
   171  	}
   172  	return nil, mtc.StoredError
   173  }
   174  
   175  // FindTestsBytaskId
   176  func (mtc *MockTaskConnector) FindTasksByProjectAndCommit(projectId, commitHash, taskId,
   177  	status string, limit, sortDir int) ([]task.Task, error) {
   178  	if mtc.StoredError != nil {
   179  		return []task.Task{}, mtc.StoredError
   180  	}
   181  
   182  	ofProjectAndCommit := []task.Task{}
   183  	for _, t := range mtc.CachedTasks {
   184  		if t.Project == projectId && t.Revision == commitHash {
   185  			ofProjectAndCommit = append(ofProjectAndCommit, t)
   186  		}
   187  	}
   188  
   189  	// loop until the filename is found
   190  	for ix, t := range ofProjectAndCommit {
   191  		if t.Id == taskId {
   192  			// We've found the test
   193  			var testsToReturn []task.Task
   194  			if sortDir < 0 {
   195  				if ix-limit > 0 {
   196  					testsToReturn = ofProjectAndCommit[ix-(limit) : ix]
   197  				} else {
   198  					testsToReturn = ofProjectAndCommit[:ix]
   199  				}
   200  			} else {
   201  				if ix+limit > len(ofProjectAndCommit) {
   202  					testsToReturn = ofProjectAndCommit[ix:]
   203  				} else {
   204  					testsToReturn = ofProjectAndCommit[ix : ix+limit]
   205  				}
   206  			}
   207  			return testsToReturn, nil
   208  		}
   209  	}
   210  	return nil, nil
   211  }
   212  func (mdf *MockTaskConnector) FindTasksByIds(taskIds []string) ([]task.Task, error) {
   213  	return mdf.CachedTasks, mdf.StoredError
   214  }
   215  
   216  // FindTaskByBuildId provides a mock implementation of the function for the
   217  // ServiceContext interface without needing to use a database. It returns results
   218  // based on the cached tasks in the MockTaskConnector.
   219  func (mdf *MockTaskConnector) FindTasksByBuildId(buildId, startTaskId, status string, limit,
   220  	sortDir int) ([]task.Task, error) {
   221  	if mdf.StoredError != nil {
   222  		return []task.Task{}, mdf.StoredError
   223  	}
   224  	ofBuildIdAndStatus := []task.Task{}
   225  	for _, t := range mdf.CachedTasks {
   226  		if t.BuildId == buildId {
   227  			if status == "" || t.Status == status {
   228  				ofBuildIdAndStatus = append(ofBuildIdAndStatus, t)
   229  			}
   230  		}
   231  	}
   232  
   233  	// loop until the start task is found
   234  	for ix, t := range ofBuildIdAndStatus {
   235  		if t.Id == startTaskId {
   236  			// We've found the task
   237  			var tasksToReturn []task.Task
   238  			if sortDir < 0 {
   239  				if ix-limit > 0 {
   240  					tasksToReturn = mdf.CachedTasks[ix-(limit) : ix]
   241  				} else {
   242  					tasksToReturn = mdf.CachedTasks[:ix]
   243  				}
   244  			} else {
   245  				if ix+limit > len(mdf.CachedTasks) {
   246  					tasksToReturn = mdf.CachedTasks[ix:]
   247  				} else {
   248  					tasksToReturn = mdf.CachedTasks[ix : ix+limit]
   249  				}
   250  			}
   251  			return tasksToReturn, nil
   252  		}
   253  	}
   254  	return nil, nil
   255  }
   256  
   257  // SetTaskPriority changes the priority value of a task using a call to the
   258  // service layer function.
   259  func (mdf *MockTaskConnector) SetTaskPriority(it *task.Task, priority int64) error {
   260  	for ix, t := range mdf.CachedTasks {
   261  		if t.Id == it.Id {
   262  			mdf.CachedTasks[ix].Priority = priority
   263  			return mdf.StoredError
   264  		}
   265  	}
   266  	return mdf.StoredError
   267  }
   268  
   269  // SetTaskActivated changes the activation value of a task using a call to the
   270  // service layer function.
   271  func (mdf *MockTaskConnector) SetTaskActivated(taskId, user string, activated bool) error {
   272  	for ix, t := range mdf.CachedTasks {
   273  		if t.Id == taskId {
   274  			mdf.CachedTasks[ix].Activated = activated
   275  			mdf.CachedTasks[ix].ActivatedBy = user
   276  			return mdf.StoredError
   277  		}
   278  	}
   279  	return mdf.StoredError
   280  }
   281  
   282  func (mdf *MockTaskConnector) ResetTask(taskId, username string, proj *serviceModel.Project) error {
   283  	for ix, t := range mdf.CachedTasks {
   284  		if t.Id == taskId {
   285  			t.Activated = true
   286  			t.Secret = "new secret"
   287  			t.Status = evergreen.TaskUndispatched
   288  			t.DispatchTime = util.ZeroTime
   289  			t.StartTime = util.ZeroTime
   290  			t.ScheduledTime = util.ZeroTime
   291  			t.FinishTime = util.ZeroTime
   292  			t.TestResults = []task.TestResult{}
   293  			mdf.CachedTasks[ix] = t
   294  		}
   295  	}
   296  	return mdf.StoredError
   297  }