diff --git a/actor/actionerror/task_failed_error.go b/actor/actionerror/task_failed_error.go new file mode 100644 index 00000000000..66134d2ef51 --- /dev/null +++ b/actor/actionerror/task_failed_error.go @@ -0,0 +1,7 @@ +package actionerror + +type TaskFailedError struct{} + +func (TaskFailedError) Error() string { + return "Task failed to complete successfully" +} diff --git a/actor/v7action/cloud_controller_client.go b/actor/v7action/cloud_controller_client.go index e855e9624f5..88849010c58 100644 --- a/actor/v7action/cloud_controller_client.go +++ b/actor/v7action/cloud_controller_client.go @@ -136,6 +136,7 @@ type CloudControllerClient interface { GetAppFeature(appGUID string, featureName string) (resources.ApplicationFeature, ccv3.Warnings, error) GetStacks(query ...ccv3.Query) ([]resources.Stack, ccv3.Warnings, error) GetStagingSecurityGroups(spaceGUID string, queries ...ccv3.Query) ([]resources.SecurityGroup, ccv3.Warnings, error) + GetTask(guid string) (resources.Task, ccv3.Warnings, error) GetUser(userGUID string) (resources.User, ccv3.Warnings, error) GetUsers(query ...ccv3.Query) ([]resources.User, ccv3.Warnings, error) MakeRequestSendReceiveRaw(Method string, URL string, headers http.Header, requestBody []byte) ([]byte, *http.Response, error) diff --git a/actor/v7action/task.go b/actor/v7action/task.go index abebb726ecf..58ef0da3339 100644 --- a/actor/v7action/task.go +++ b/actor/v7action/task.go @@ -2,13 +2,16 @@ package v7action import ( "strconv" + "time" "sort" "code.cloudfoundry.org/cli/actor/actionerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" "code.cloudfoundry.org/cli/resources" + log "github.com/sirupsen/logrus" ) // Run resources.Task runs the provided command in the application environment associated @@ -67,3 +70,32 @@ func (actor Actor) TerminateTask(taskGUID string) (resources.Task, Warnings, err task, warnings, err := actor.CloudControllerClient.UpdateTaskCancel(taskGUID) return resources.Task(task), Warnings(warnings), err } + +func (actor Actor) PollTask(task resources.Task) (resources.Task, Warnings, error) { + var allWarnings Warnings + + for task.State != constant.TaskSucceeded && task.State != constant.TaskFailed { + + time.Sleep(actor.Config.PollingInterval()) + + ccTask, warnings, err := actor.CloudControllerClient.GetTask(task.GUID) + log.WithFields(log.Fields{ + "task_guid": task.GUID, + "state": task.State, + }).Debug("polling task state") + + allWarnings = append(allWarnings, warnings...) + + if err != nil { + return resources.Task{}, allWarnings, err + } + + task = resources.Task(ccTask) + } + + if task.State == constant.TaskFailed { + return task, allWarnings, actionerror.TaskFailedError{} + } + + return task, allWarnings, nil +} diff --git a/actor/v7action/task_test.go b/actor/v7action/task_test.go index 612951c72de..49f5a3cfb05 100644 --- a/actor/v7action/task_test.go +++ b/actor/v7action/task_test.go @@ -18,11 +18,13 @@ var _ = Describe("Task Actions", func() { var ( actor *Actor fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient + fakeConfig *v7actionfakes.FakeConfig ) BeforeEach(func() { fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient) - actor = NewActor(fakeCloudControllerClient, nil, nil, nil, nil, nil) + fakeConfig = new(v7actionfakes.FakeConfig) + actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, nil, nil, nil) }) Describe("RunTask", func() { @@ -305,4 +307,63 @@ var _ = Describe("Task Actions", func() { }) }) }) + + Describe("PollTask", func() { + + It("polls for SUCCEDED state", func() { + firstTaskResponse := resources.Task{State: constant.TaskRunning} + secondTaskResponse := resources.Task{State: constant.TaskSucceeded} + + fakeCloudControllerClient.GetTaskReturnsOnCall(0, firstTaskResponse, nil, nil) + fakeCloudControllerClient.GetTaskReturnsOnCall(1, secondTaskResponse, nil, nil) + + task, _, _ := actor.PollTask(resources.Task{}) + + Expect(task.State).To(Equal(constant.TaskSucceeded)) + }) + + It("polls for FAILED state", func() { + firstTaskResponse := resources.Task{State: constant.TaskRunning} + secondTaskResponse := resources.Task{State: constant.TaskFailed} + + fakeCloudControllerClient.GetTaskReturnsOnCall(0, firstTaskResponse, nil, nil) + fakeCloudControllerClient.GetTaskReturnsOnCall(1, secondTaskResponse, nil, nil) + + task, _, _ := actor.PollTask(resources.Task{}) + + Expect(task.State).To(Equal(constant.TaskFailed)) + }) + + It("aggregates warnings from all requests made while polling", func() { + firstTaskResponse := resources.Task{State: constant.TaskRunning} + secondTaskResponse := resources.Task{State: constant.TaskSucceeded} + + fakeCloudControllerClient.GetTaskReturnsOnCall(0, firstTaskResponse, ccv3.Warnings{"warning-1"}, nil) + fakeCloudControllerClient.GetTaskReturnsOnCall(1, secondTaskResponse, ccv3.Warnings{"warning-2"}, nil) + + _, warnings, _ := actor.PollTask(resources.Task{}) + + Expect(warnings).To(ConsistOf("warning-1", "warning-2")) + }) + + It("handles errors from requests to cc", func() { + firstTaskResponse := resources.Task{State: constant.TaskSucceeded} + + fakeCloudControllerClient.GetTaskReturnsOnCall(0, firstTaskResponse, nil, errors.New("request-error")) + + _, _, err := actor.PollTask(resources.Task{}) + + Expect(err).To(MatchError("request-error")) + }) + + It("returns an error if the task failed", func() { + firstTaskResponse := resources.Task{State: constant.TaskFailed} + + fakeCloudControllerClient.GetTaskReturnsOnCall(0, firstTaskResponse, nil, nil) + + _, _, err := actor.PollTask(resources.Task{}) + + Expect(err).To(MatchError("Task failed to complete successfully")) + }) + }) }) diff --git a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go index e2ff9883854..b7ff686364e 100644 --- a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go +++ b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go @@ -1903,6 +1903,21 @@ type FakeCloudControllerClient struct { result2 ccv3.Warnings result3 error } + GetTaskStub func(string) (resources.Task, ccv3.Warnings, error) + getTaskMutex sync.RWMutex + getTaskArgsForCall []struct { + arg1 string + } + getTaskReturns struct { + result1 resources.Task + result2 ccv3.Warnings + result3 error + } + getTaskReturnsOnCall map[int]struct { + result1 resources.Task + result2 ccv3.Warnings + result3 error + } GetUserStub func(string) (resources.User, ccv3.Warnings, error) getUserMutex sync.RWMutex getUserArgsForCall []struct { @@ -10965,6 +10980,72 @@ func (fake *FakeCloudControllerClient) GetStagingSecurityGroupsReturnsOnCall(i i }{result1, result2, result3} } +func (fake *FakeCloudControllerClient) GetTask(arg1 string) (resources.Task, ccv3.Warnings, error) { + fake.getTaskMutex.Lock() + ret, specificReturn := fake.getTaskReturnsOnCall[len(fake.getTaskArgsForCall)] + fake.getTaskArgsForCall = append(fake.getTaskArgsForCall, struct { + arg1 string + }{arg1}) + fake.recordInvocation("GetTask", []interface{}{arg1}) + fake.getTaskMutex.Unlock() + if fake.GetTaskStub != nil { + return fake.GetTaskStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2, ret.result3 + } + fakeReturns := fake.getTaskReturns + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 +} + +func (fake *FakeCloudControllerClient) GetTaskCallCount() int { + fake.getTaskMutex.RLock() + defer fake.getTaskMutex.RUnlock() + return len(fake.getTaskArgsForCall) +} + +func (fake *FakeCloudControllerClient) GetTaskCalls(stub func(string) (resources.Task, ccv3.Warnings, error)) { + fake.getTaskMutex.Lock() + defer fake.getTaskMutex.Unlock() + fake.GetTaskStub = stub +} + +func (fake *FakeCloudControllerClient) GetTaskArgsForCall(i int) string { + fake.getTaskMutex.RLock() + defer fake.getTaskMutex.RUnlock() + argsForCall := fake.getTaskArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeCloudControllerClient) GetTaskReturns(result1 resources.Task, result2 ccv3.Warnings, result3 error) { + fake.getTaskMutex.Lock() + defer fake.getTaskMutex.Unlock() + fake.GetTaskStub = nil + fake.getTaskReturns = struct { + result1 resources.Task + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + +func (fake *FakeCloudControllerClient) GetTaskReturnsOnCall(i int, result1 resources.Task, result2 ccv3.Warnings, result3 error) { + fake.getTaskMutex.Lock() + defer fake.getTaskMutex.Unlock() + fake.GetTaskStub = nil + if fake.getTaskReturnsOnCall == nil { + fake.getTaskReturnsOnCall = make(map[int]struct { + result1 resources.Task + result2 ccv3.Warnings + result3 error + }) + } + fake.getTaskReturnsOnCall[i] = struct { + result1 resources.Task + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + func (fake *FakeCloudControllerClient) GetUser(arg1 string) (resources.User, ccv3.Warnings, error) { fake.getUserMutex.Lock() ret, specificReturn := fake.getUserReturnsOnCall[len(fake.getUserArgsForCall)] @@ -14952,6 +15033,8 @@ func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} defer fake.getStacksMutex.RUnlock() fake.getStagingSecurityGroupsMutex.RLock() defer fake.getStagingSecurityGroupsMutex.RUnlock() + fake.getTaskMutex.RLock() + defer fake.getTaskMutex.RUnlock() fake.getUserMutex.RLock() defer fake.getUserMutex.RUnlock() fake.getUsersMutex.RLock() diff --git a/api/cloudcontroller/ccv3/internal/api_routes.go b/api/cloudcontroller/ccv3/internal/api_routes.go index 1e747e21033..9f6b3fa1475 100644 --- a/api/cloudcontroller/ccv3/internal/api_routes.go +++ b/api/cloudcontroller/ccv3/internal/api_routes.go @@ -103,6 +103,7 @@ const ( GetSpaceStagingSecurityGroupsRequest = "GetSpaceStagingSecurityGroups" GetSSHEnabled = "GetSSHEnabled" GetStacksRequest = "GetStacks" + GetTaskRequest = "GetTask" GetUserRequest = "GetUser" GetUsersRequest = "GetUsers" MapRouteRequest = "MapRoute" @@ -343,6 +344,7 @@ var APIRoutes = map[string]Route{ DeleteSpaceQuotaFromSpaceRequest: {Path: "/v3/space_quotas/:quota_guid/relationships/spaces/:space_guid", Method: http.MethodDelete}, GetStacksRequest: {Path: "/v3/stacks", Method: http.MethodGet}, PatchStackRequest: {Path: "/v3/stacks/:stack_guid", Method: http.MethodPatch}, + GetTaskRequest: {Path: "/v3/tasks/:task_guid", Method: http.MethodGet}, PutTaskCancelRequest: {Path: "/v3/tasks/:task_guid/cancel", Method: http.MethodPut}, GetUsersRequest: {Path: "/v3/users", Method: http.MethodGet}, GetUserRequest: {Path: "/v3/users/:user_guid", Method: http.MethodGet}, diff --git a/api/cloudcontroller/ccv3/task.go b/api/cloudcontroller/ccv3/task.go index 2b67040596d..359ee9277a4 100644 --- a/api/cloudcontroller/ccv3/task.go +++ b/api/cloudcontroller/ccv3/task.go @@ -53,3 +53,17 @@ func (client *Client) UpdateTaskCancel(taskGUID string) (resources.Task, Warning return responseBody, warnings, err } + +func (client *Client) GetTask(guid string) (resources.Task, Warnings, error) { + var responseBody resources.Task + + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.GetTaskRequest, + URIParams: internal.Params{ + "task_guid": guid, + }, + ResponseBody: &responseBody, + }) + + return responseBody, warnings, err +} diff --git a/api/cloudcontroller/ccv3/task_test.go b/api/cloudcontroller/ccv3/task_test.go index 24d810d2193..e820eae19ed 100644 --- a/api/cloudcontroller/ccv3/task_test.go +++ b/api/cloudcontroller/ccv3/task_test.go @@ -443,4 +443,89 @@ var _ = Describe("Task", func() { }) }) }) + + Describe("GetTask", func() { + When("the task exists", func() { + BeforeEach(func() { + response := `{ + "guid": "the-task-guid", + "sequence_id": 1, + "name": "task-1", + "command": "some-command", + "state": "SUCCEEDED", + "created_at": "2016-11-07T05:59:01Z" + }` + + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodGet, "/v3/tasks/the-task-guid"), + RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning"}}), + ), + ) + }) + + It("returns the task and all warnings", func() { + task, warnings, err := client.GetTask("the-task-guid") + Expect(err).ToNot(HaveOccurred()) + + expectedTask := resources.Task{ + GUID: "the-task-guid", + SequenceID: 1, + Name: "task-1", + State: constant.TaskSucceeded, + CreatedAt: "2016-11-07T05:59:01Z", + Command: "some-command", + } + + Expect(task).To(Equal(expectedTask)) + Expect(warnings).To(ConsistOf("warning")) + }) + }) + + When("the cloud controller returns errors and warnings", func() { + BeforeEach(func() { + response := `{ + "errors": [ + { + "code": 10008, + "detail": "The request is semantically invalid: command presence", + "title": "CF-UnprocessableEntity" + }, + { + "code": 10010, + "detail": "Task not found", + "title": "CF-ResourceNotFound" + } + ] + }` + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodGet, "/v3/tasks/the-task-guid"), + RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning"}}), + ), + ) + }) + + It("returns the errors and all warnings", func() { + _, warnings, err := client.GetTask("the-task-guid") + + Expect(err).To(MatchError(ccerror.MultiError{ + ResponseCode: http.StatusTeapot, + Errors: []ccerror.V3Error{ + { + Code: 10008, + Detail: "The request is semantically invalid: command presence", + Title: "CF-UnprocessableEntity", + }, + { + Code: 10010, + Detail: "Task not found", + Title: "CF-ResourceNotFound", + }, + }, + })) + Expect(warnings).To(ConsistOf("warning")) + }) + }) + }) }) diff --git a/command/v7/actor.go b/command/v7/actor.go index 444a96ae3ba..aed36088a01 100644 --- a/command/v7/actor.go +++ b/command/v7/actor.go @@ -189,6 +189,7 @@ type Actor interface { PollPackage(pkg resources.Package) (resources.Package, v7action.Warnings, error) PollStart(app resources.Application, noWait bool, handleProcessStats func(string)) (v7action.Warnings, error) PollStartForRolling(app resources.Application, deploymentGUID string, noWait bool, handleProcessStats func(string)) (v7action.Warnings, error) + PollTask(task resources.Task) (resources.Task, v7action.Warnings, error) PollUploadBuildpackJob(jobURL ccv3.JobURL) (v7action.Warnings, error) PrepareBuildpackBits(inputPath string, tmpDirPath string, downloader v7action.Downloader) (string, error) PurgeServiceInstance(serviceInstanceName, spaceGUID string) (v7action.Warnings, error) diff --git a/command/v7/run_task_command.go b/command/v7/run_task_command.go index eb07aa4d3f2..61defab7818 100644 --- a/command/v7/run_task_command.go +++ b/command/v7/run_task_command.go @@ -17,6 +17,7 @@ type RunTaskCommand struct { Memory flag.Megabytes `short:"m" description:"Memory limit (e.g. 256M, 1024M, 1G)"` Name string `long:"name" description:"Name to give the task (generated if omitted)"` Process string `long:"process" description:"Process type to use as a template for command, memory, and disk for the created task."` + Wait bool `long:"wait" short:"w" description:"Wait for the task to complete before exiting"` usage interface{} `usage:"CF_NAME run-task APP_NAME [--command COMMAND] [-k DISK] [-m MEMORY] [-l LOG_RATE_LIMIT] [--name TASK_NAME] [--process PROCESS_TYPE]\n\nTIP:\n Use 'cf logs' to display the logs of the app and all its tasks. If your task name is unique, grep this command's output for the task name to view task-specific logs.\n\nEXAMPLES:\n CF_NAME run-task my-app --command \"bundle exec rake db:migrate\" --name migrate\n\n CF_NAME run-task my-app --process batch_job\n\n CF_NAME run-task my-app"` relatedCommands interface{} `related_commands:"logs, tasks, terminate-task"` } @@ -94,5 +95,21 @@ func (cmd RunTaskCommand) Execute(args []string) error { {cmd.UI.TranslateText("task id:"), fmt.Sprint(task.SequenceID)}, }, 3) + if cmd.Wait { + cmd.UI.DisplayNewline() + cmd.UI.DisplayText("Waiting for task to complete execution...") + + _, pollWarnings, err := cmd.Actor.PollTask(task) + cmd.UI.DisplayWarnings(pollWarnings) + if err != nil { + return err + } + + cmd.UI.DisplayNewline() + cmd.UI.DisplayText("Task has completed successfully.") + } + + cmd.UI.DisplayOK() + return nil } diff --git a/command/v7/run_task_command_test.go b/command/v7/run_task_command_test.go index 585515345a7..583aaf7ffec 100644 --- a/command/v7/run_task_command_test.go +++ b/command/v7/run_task_command_test.go @@ -145,6 +145,7 @@ var _ = Describe("run-task Command", func() { Expect(testUI.Out).To(Say(`task name:\s+31337ddd`)) Expect(testUI.Out).To(Say(`task id:\s+3`)) + Expect(testUI.Out).To(Say("OK")) Expect(testUI.Err).To(Say("get-application-warning-1")) Expect(testUI.Err).To(Say("get-application-warning-2")) @@ -190,6 +191,7 @@ var _ = Describe("run-task Command", func() { Expect(testUI.Out).To(Say(`task name:\s+some-task-name`)) Expect(testUI.Out).To(Say(`task id:\s+3`)) + Expect(testUI.Out).To(Say("OK")) Expect(testUI.Err).To(Say("get-application-warning-1")) Expect(testUI.Err).To(Say("get-application-warning-2")) @@ -280,6 +282,7 @@ var _ = Describe("run-task Command", func() { Expect(testUI.Out).To(Say(`task name:\s+some-task-name`)) Expect(testUI.Out).To(Say(`task id:\s+3`)) + Expect(testUI.Out).To(Say("OK")) Expect(testUI.Err).To(Say("get-application-warning-1")) Expect(testUI.Err).To(Say("get-application-warning-2")) @@ -331,6 +334,7 @@ var _ = Describe("run-task Command", func() { Expect(testUI.Out).To(Say(`task name:\s+some-task-name`)) Expect(testUI.Out).To(Say(`task id:\s+3`)) + Expect(testUI.Out).To(Say("OK")) Expect(testUI.Err).To(Say("get-application-warning-1")) Expect(testUI.Err).To(Say("get-application-warning-2")) @@ -338,6 +342,49 @@ var _ = Describe("run-task Command", func() { Expect(testUI.Err).To(Say("get-application-warning-3")) }) }) + + When("wait is provided", func() { + BeforeEach(func() { + cmd.Name = "some-task-name" + cmd.Command = "echo hello" + cmd.Wait = true + fakeActor.RunTaskReturns( + resources.Task{ + Name: "some-task-name", + SequenceID: 3, + }, + v7action.Warnings{"get-application-warning-3"}, + nil) + fakeActor.PollTaskReturns( + resources.Task{ + Name: "some-task-name", + SequenceID: 3, + }, + v7action.Warnings{"poll-warnings"}, + nil) + }) + + It("waits for the task to complete before exiting", func() { + Expect(executeErr).ToNot(HaveOccurred()) + + Expect(testUI.Out).To(Say("Creating task for app some-app-name in org some-org / space some-space as some-user...")) + + Expect(testUI.Out).To(Say("Task has been submitted successfully for execution.")) + Expect(testUI.Out).To(Say(`task name:\s+some-task-name`)) + Expect(testUI.Out).To(Say(`task id:\s+3`)) + + Expect(testUI.Out).To(Say(`Waiting for task to complete execution...`)) + + Expect(testUI.Out).To(Say(`Task has completed successfully.`)) + Expect(testUI.Out).To(Say("OK")) + + Expect(testUI.Err).To(Say("get-application-warning-1")) + Expect(testUI.Err).To(Say("get-application-warning-2")) + Expect(testUI.Err).To(Say("get-application-warning-3")) + Expect(testUI.Err).To(Say("poll-warnings")) + + }) + }) }) When("there are errors", func() { @@ -381,6 +428,31 @@ var _ = Describe("run-task Command", func() { Expect(executeErr).To(MatchError(returnedErr)) }) }) + + When("polling the task returns the error", func() { + var returnedErr error + + BeforeEach(func() { + cmd.Wait = true + returnedErr = ccerror.UnverifiedServerError{URL: "some-url"} + fakeActor.GetApplicationByNameAndSpaceReturns( + resources.Application{GUID: "some-app-guid"}, + nil, + nil) + fakeActor.RunTaskReturns( + resources.Task{}, + nil, + nil) + fakeActor.PollTaskReturns( + resources.Task{}, + nil, + returnedErr) + }) + + It("returns a translatable error", func() { + Expect(executeErr).To(MatchError(returnedErr)) + }) + }) }) When("the error is not translatable", func() { diff --git a/command/v7/v7fakes/fake_actor.go b/command/v7/v7fakes/fake_actor.go index 6f59ac2b2f1..f83b51a0f46 100644 --- a/command/v7/v7fakes/fake_actor.go +++ b/command/v7/v7fakes/fake_actor.go @@ -2578,6 +2578,21 @@ type FakeActor struct { result1 v7action.Warnings result2 error } + PollTaskStub func(resources.Task) (resources.Task, v7action.Warnings, error) + pollTaskMutex sync.RWMutex + pollTaskArgsForCall []struct { + arg1 resources.Task + } + pollTaskReturns struct { + result1 resources.Task + result2 v7action.Warnings + result3 error + } + pollTaskReturnsOnCall map[int]struct { + result1 resources.Task + result2 v7action.Warnings + result3 error + } PollUploadBuildpackJobStub func(ccv3.JobURL) (v7action.Warnings, error) pollUploadBuildpackJobMutex sync.RWMutex pollUploadBuildpackJobArgsForCall []struct { @@ -14601,6 +14616,72 @@ func (fake *FakeActor) PollStartForRollingReturnsOnCall(i int, result1 v7action. }{result1, result2} } +func (fake *FakeActor) PollTask(arg1 resources.Task) (resources.Task, v7action.Warnings, error) { + fake.pollTaskMutex.Lock() + ret, specificReturn := fake.pollTaskReturnsOnCall[len(fake.pollTaskArgsForCall)] + fake.pollTaskArgsForCall = append(fake.pollTaskArgsForCall, struct { + arg1 resources.Task + }{arg1}) + fake.recordInvocation("PollTask", []interface{}{arg1}) + fake.pollTaskMutex.Unlock() + if fake.PollTaskStub != nil { + return fake.PollTaskStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2, ret.result3 + } + fakeReturns := fake.pollTaskReturns + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 +} + +func (fake *FakeActor) PollTaskCallCount() int { + fake.pollTaskMutex.RLock() + defer fake.pollTaskMutex.RUnlock() + return len(fake.pollTaskArgsForCall) +} + +func (fake *FakeActor) PollTaskCalls(stub func(resources.Task) (resources.Task, v7action.Warnings, error)) { + fake.pollTaskMutex.Lock() + defer fake.pollTaskMutex.Unlock() + fake.PollTaskStub = stub +} + +func (fake *FakeActor) PollTaskArgsForCall(i int) resources.Task { + fake.pollTaskMutex.RLock() + defer fake.pollTaskMutex.RUnlock() + argsForCall := fake.pollTaskArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeActor) PollTaskReturns(result1 resources.Task, result2 v7action.Warnings, result3 error) { + fake.pollTaskMutex.Lock() + defer fake.pollTaskMutex.Unlock() + fake.PollTaskStub = nil + fake.pollTaskReturns = struct { + result1 resources.Task + result2 v7action.Warnings + result3 error + }{result1, result2, result3} +} + +func (fake *FakeActor) PollTaskReturnsOnCall(i int, result1 resources.Task, result2 v7action.Warnings, result3 error) { + fake.pollTaskMutex.Lock() + defer fake.pollTaskMutex.Unlock() + fake.PollTaskStub = nil + if fake.pollTaskReturnsOnCall == nil { + fake.pollTaskReturnsOnCall = make(map[int]struct { + result1 resources.Task + result2 v7action.Warnings + result3 error + }) + } + fake.pollTaskReturnsOnCall[i] = struct { + result1 resources.Task + result2 v7action.Warnings + result3 error + }{result1, result2, result3} +} + func (fake *FakeActor) PollUploadBuildpackJob(arg1 ccv3.JobURL) (v7action.Warnings, error) { fake.pollUploadBuildpackJobMutex.Lock() ret, specificReturn := fake.pollUploadBuildpackJobReturnsOnCall[len(fake.pollUploadBuildpackJobArgsForCall)] @@ -19499,6 +19580,8 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.pollStartMutex.RUnlock() fake.pollStartForRollingMutex.RLock() defer fake.pollStartForRollingMutex.RUnlock() + fake.pollTaskMutex.RLock() + defer fake.pollTaskMutex.RUnlock() fake.pollUploadBuildpackJobMutex.RLock() defer fake.pollUploadBuildpackJobMutex.RUnlock() fake.prepareBuildpackBitsMutex.RLock()