diff --git a/pkg/apis/camel/v1alpha1/integration_types.go b/pkg/apis/camel/v1alpha1/integration_types.go index 209196ad90..8cad47bc82 100644 --- a/pkg/apis/camel/v1alpha1/integration_types.go +++ b/pkg/apis/camel/v1alpha1/integration_types.go @@ -131,8 +131,10 @@ const ( IntegrationPhaseWaitingForPlatform IntegrationPhase = "Waiting For Platform" // IntegrationPhaseBuildingContext -- IntegrationPhaseBuildingContext IntegrationPhase = "Building Context" - // IntegrationPhaseBuildingImage -- - IntegrationPhaseBuildingImage IntegrationPhase = "Building Image" + // IntegrationPhaseBuildImageSubmitted -- + IntegrationPhaseBuildImageSubmitted IntegrationPhase = "Build Image Submitted" + // IntegrationPhaseBuildImageRunning -- + IntegrationPhaseBuildImageRunning IntegrationPhase = "Build Image Running" // IntegrationPhaseDeploying -- IntegrationPhaseDeploying IntegrationPhase = "Deploying" // IntegrationPhaseRunning -- diff --git a/pkg/apis/camel/v1alpha1/integrationcontext_types.go b/pkg/apis/camel/v1alpha1/integrationcontext_types.go index db034330e0..72c0d6548a 100644 --- a/pkg/apis/camel/v1alpha1/integrationcontext_types.go +++ b/pkg/apis/camel/v1alpha1/integrationcontext_types.go @@ -64,8 +64,10 @@ const ( // IntegrationContextTypeExternal -- IntegrationContextTypeExternal = "external" - // IntegrationContextPhaseBuilding -- - IntegrationContextPhaseBuilding IntegrationContextPhase = "Building" + // IntegrationContextPhaseBuildSubmitted -- + IntegrationContextPhaseBuildSubmitted IntegrationContextPhase = "Build Submitted" + // IntegrationContextPhaseBuildRunning -- + IntegrationContextPhaseBuildRunning IntegrationContextPhase = "Build Running" // IntegrationContextPhaseReady -- IntegrationContextPhaseReady IntegrationContextPhase = "Ready" // IntegrationContextPhaseError -- diff --git a/pkg/builder/builder.go b/pkg/builder/builder.go index 6321fc82a1..d9ec9e319c 100644 --- a/pkg/builder/builder.go +++ b/pkg/builder/builder.go @@ -41,7 +41,7 @@ import ( // ******************************** type buildTask struct { - handler func(Result) + handler func(*Result) request Request } @@ -78,14 +78,14 @@ func (b *defaultBuilder) IsBuilding(object v1.ObjectMeta) bool { } // Submit -- -func (b *defaultBuilder) Submit(request Request, handler func(Result)) { +func (b *defaultBuilder) Submit(request Request, handler func(*Result)) { if atomic.CompareAndSwapInt32(&b.running, 0, 1) { go b.loop() } result, present := b.request.Load(request.Meta.Name) if !present || result == nil { - result = Result{ + r := Result{ Builder: b, Request: request, Status: StatusSubmitted, @@ -93,7 +93,11 @@ func (b *defaultBuilder) Submit(request Request, handler func(Result)) { b.log.Infof("submitting request: %+v", request) - b.request.Store(request.Meta.Name, result) + if handler != nil { + handler(&r) + } + + b.request.Store(request.Meta.Name, r) b.tasks <- buildTask{handler: handler, request: request} } } @@ -127,7 +131,7 @@ func (b *defaultBuilder) loop() { } } -func (b *defaultBuilder) process(request Request, handler func(Result)) { +func (b *defaultBuilder) process(request Request, handler func(*Result)) { result, present := b.request.Load(request.Meta.Name) if !present || result == nil { b.log.Panicf("no info found for: %+v", request.Meta.Name) @@ -139,7 +143,7 @@ func (b *defaultBuilder) process(request Request, handler func(Result)) { r.Task.StartedAt = time.Now() if handler != nil { - handler(r) + handler(&r) } // create tmp path @@ -189,7 +193,7 @@ func (b *defaultBuilder) process(request Request, handler func(Result)) { if r.Status == StatusError { if handler != nil { - handler(r) + handler(&r) } return @@ -202,13 +206,15 @@ func (b *defaultBuilder) process(request Request, handler func(Result)) { b.log.Infof("steps: %v", request.Steps) for _, step := range request.Steps { - if c.Error != nil { + if c.Error != nil || r.Status == StatusInterrupted { break } select { case <-b.interrupt: c.Error = errors.New("build canceled") + case <-request.C.Done(): + r.Status = StatusInterrupted default: l := b.log.WithFields(logrus.Fields{ "step": step.ID(), @@ -229,33 +235,38 @@ func (b *defaultBuilder) process(request Request, handler func(Result)) { } } - r.Status = StatusCompleted - r.BaseImage = c.BaseImage - r.Image = c.Image - r.PublicImage = c.PublicImage - r.Error = c.Error r.Task.CompletedAt = time.Now() - if r.Error != nil { - r.Status = StatusError - } + if r.Status != StatusInterrupted { + r.Status = StatusCompleted + r.BaseImage = c.BaseImage + r.Image = c.Image + r.PublicImage = c.PublicImage + r.Error = c.Error - r.Artifacts = make([]v1alpha1.Artifact, 0, len(c.Artifacts)) - r.Artifacts = append(r.Artifacts, c.Artifacts...) + if r.Error != nil { + r.Status = StatusError + } + + r.Artifacts = make([]v1alpha1.Artifact, 0, len(c.Artifacts)) + r.Artifacts = append(r.Artifacts, c.Artifacts...) + + b.log.Infof("build request %s executed in %f seconds", request.Meta.Name, r.Task.Elapsed().Seconds()) + b.log.Infof("dependencies: %s", request.Dependencies) + b.log.Infof("artifacts: %s", ArtifactIDs(c.Artifacts)) + b.log.Infof("artifacts selected: %s", ArtifactIDs(c.SelectedArtifacts)) + b.log.Infof("requested image: %s", request.Image) + b.log.Infof("base image: %s", c.BaseImage) + b.log.Infof("resolved image: %s", c.Image) + b.log.Infof("resolved public image: %s", c.PublicImage) + } else { + b.log.Infof("build request %s interrupted after %f seconds", request.Meta.Name, r.Task.Elapsed().Seconds()) + } // update the cache b.request.Store(request.Meta.Name, r) - b.log.Infof("build request %s executed in %f seconds", request.Meta.Name, r.Task.Elapsed().Seconds()) - b.log.Infof("dependencies: %s", request.Dependencies) - b.log.Infof("artifacts: %s", ArtifactIDs(c.Artifacts)) - b.log.Infof("artifacts selected: %s", ArtifactIDs(c.SelectedArtifacts)) - b.log.Infof("requested image: %s", request.Image) - b.log.Infof("base image: %s", c.BaseImage) - b.log.Infof("resolved image: %s", c.Image) - b.log.Infof("resolved public image: %s", c.PublicImage) - if handler != nil { - handler(r) + handler(&r) } } diff --git a/pkg/builder/builder_types.go b/pkg/builder/builder_types.go index ff2c12880a..27cca9c001 100644 --- a/pkg/builder/builder_types.go +++ b/pkg/builder/builder_types.go @@ -47,7 +47,7 @@ const ( // Builder -- type Builder interface { IsBuilding(object v1.ObjectMeta) bool - Submit(request Request, handler func(Result)) + Submit(request Request, handler func(*Result)) Close() } @@ -102,6 +102,7 @@ type Resource struct { // Request -- type Request struct { + C context.Context Meta v1.ObjectMeta Platform v1alpha1.IntegrationPlatformSpec Dependencies []string @@ -190,4 +191,7 @@ const ( // StatusError -- StatusError + + // StatusInterrupted -- + StatusInterrupted ) diff --git a/pkg/controller/integration/build_image.go b/pkg/controller/integration/build_image.go index 5a0778e174..6145259083 100644 --- a/pkg/controller/integration/build_image.go +++ b/pkg/controller/integration/build_image.go @@ -52,11 +52,41 @@ func (action *buildImageAction) Name() string { } func (action *buildImageAction) CanHandle(integration *v1alpha1.Integration) bool { - return integration.Status.Phase == v1alpha1.IntegrationPhaseBuildingImage + if integration.Status.Phase == v1alpha1.IntegrationPhaseBuildImageSubmitted { + return true + } + if integration.Status.Phase == v1alpha1.IntegrationPhaseBuildImageRunning { + return true + } + + return false } func (action *buildImageAction) Handle(ctx context.Context, integration *v1alpha1.Integration) error { + if integration.Status.Phase == v1alpha1.IntegrationPhaseBuildImageSubmitted { + return action.handleBuildImageSubmitted(ctx, integration) + } + if integration.Status.Phase == v1alpha1.IntegrationPhaseBuildImageRunning { + return action.handleBuildImageRunning(ctx, integration) + } + + return nil +} + +func (action *buildImageAction) handleBuildImageRunning(ctx context.Context, integration *v1alpha1.Integration) error { + b, err := platform.GetPlatformBuilder(action.client, integration.Namespace) + if err != nil { + return err + } + + if b.IsBuilding(integration.ObjectMeta) { + logrus.Infof("Build for integration %s is running", integration.Name) + } + return nil +} + +func (action *buildImageAction) handleBuildImageSubmitted(ctx context.Context, integration *v1alpha1.Integration) error { // in this phase the integration need to be associated to a context whose image // will be used as base image for the integration images if integration.Status.Context == "" { @@ -81,9 +111,14 @@ func (action *buildImageAction) Handle(ctx context.Context, integration *v1alpha return err } - // This build do not require to determine dependencies nor a project, the builder - // step do remove them + // This build do not require to determine dependencies nor a project, the + // builder step do remove them + // + // the context given to the handler is per reconcile loop and as the build + // happens asynchronously, a new context has to be created. the new context + // can be used also to stop the build. r := builder.Request{ + C: context.TODO(), Meta: integration.ObjectMeta, Steps: env.Steps, BuildDir: env.BuildDir, @@ -99,15 +134,11 @@ func (action *buildImageAction) Handle(ctx context.Context, integration *v1alpha return err } - b.Submit(r, func(result builder.Result) { - // we can't use the handler ctx as this happen asynchronously so we - // need a new context - ctx := context.TODO() - + b.Submit(r, func(result *builder.Result) { // // this function is invoked synchronously for every state change // - if err := action.handleBuildStateChange(ctx, result); err != nil { + if err := action.handleBuildStateChange(result.Request.C, result); err != nil { logrus.Warnf("Error while building integration image %s, reason: %s", ictx.Name, err.Error()) } }) @@ -116,7 +147,7 @@ func (action *buildImageAction) Handle(ctx context.Context, integration *v1alpha return nil } -func (action *buildImageAction) handleBuildStateChange(ctx context.Context, res builder.Result) error { +func (action *buildImageAction) handleBuildStateChange(ctx context.Context, res *builder.Result) error { // // Get the latest status of the integration // @@ -129,7 +160,11 @@ func (action *buildImageAction) handleBuildStateChange(ctx context.Context, res case builder.StatusSubmitted: logrus.Info("Build submitted") case builder.StatusStarted: - logrus.Info("Build started") + target.Status.Phase = v1alpha1.IntegrationPhaseBuildImageRunning + + logrus.Infof("Integration %s transitioning to state %s", target.Name, target.Status.Phase) + + return action.client.Status().Update(ctx, target) case builder.StatusError: target.Status.Phase = v1alpha1.IntegrationPhaseBuildFailureRecovery diff --git a/pkg/controller/integrationcontext/build.go b/pkg/controller/integrationcontext/build.go index 9d07d60f71..bbc6d29700 100644 --- a/pkg/controller/integrationcontext/build.go +++ b/pkg/controller/integrationcontext/build.go @@ -19,6 +19,7 @@ package integrationcontext import ( "context" + "fmt" "time" "github.com/apache/camel-k/pkg/util/kubernetes" @@ -34,8 +35,8 @@ import ( k8sclient "sigs.k8s.io/controller-runtime/pkg/client" ) -// NewBuildAction creates a new build handling action for the context -func NewBuildAction(ctx context.Context) Action { +// NewBuildAction creates a new build request handling action for the context +func NewBuildAction() Action { return &buildAction{} } @@ -44,14 +45,45 @@ type buildAction struct { } func (action *buildAction) Name() string { - return "build" + return "build-submitted" } func (action *buildAction) CanHandle(ictx *v1alpha1.IntegrationContext) bool { - return ictx.Status.Phase == v1alpha1.IntegrationContextPhaseBuilding + if ictx.Status.Phase == v1alpha1.IntegrationContextPhaseBuildSubmitted { + return true + } + if ictx.Status.Phase == v1alpha1.IntegrationContextPhaseBuildRunning { + return true + } + + return false } func (action *buildAction) Handle(ctx context.Context, ictx *v1alpha1.IntegrationContext) error { + if ictx.Status.Phase == v1alpha1.IntegrationContextPhaseBuildSubmitted { + return action.handleBuildSubmitted(ctx, ictx) + } + if ictx.Status.Phase == v1alpha1.IntegrationContextPhaseBuildRunning { + return action.handleBuildRunning(ctx, ictx) + } + + return nil +} + +func (action *buildAction) handleBuildRunning(ctx context.Context, ictx *v1alpha1.IntegrationContext) error { + b, err := platform.GetPlatformBuilder(action.client, ictx.Namespace) + if err != nil { + return err + } + + if b.IsBuilding(ictx.ObjectMeta) { + logrus.Infof("Build for context %s is running", ictx.Name) + } + + return nil +} + +func (action *buildAction) handleBuildSubmitted(ctx context.Context, ictx *v1alpha1.IntegrationContext) error { b, err := platform.GetPlatformBuilder(action.client, ictx.Namespace) if err != nil { return err @@ -72,7 +104,11 @@ func (action *buildAction) Handle(ctx context.Context, ictx *v1alpha1.Integratio repositories = append(repositories, ictx.Spec.Repositories...) repositories = append(repositories, p.Spec.Build.Repositories...) + // the context given to the handler is per reconcile loop and as the build + // happens asynchronously, a new context has to be created. the new context + // can be used also to stop the build. r := builder.Request{ + C: context.TODO(), Meta: ictx.ObjectMeta, Dependencies: ictx.Spec.Dependencies, Repositories: repositories, @@ -81,17 +117,13 @@ func (action *buildAction) Handle(ctx context.Context, ictx *v1alpha1.Integratio Platform: env.Platform.Spec, } - b.Submit(r, func(result builder.Result) { - // we can't use the handler ctx as this happen asynchronously so we - // need a new context - ctx := context.TODO() - + b.Submit(r, func(result *builder.Result) { // // this function is invoked synchronously for every state change to avoid // leaving one context not fully updated when the incremental builder search // for a compatible/base image // - if err := action.handleBuildStateChange(ctx, result); err != nil { + if err := action.handleBuildStateChange(result.Request.C, result); err != nil { logrus.Warnf("Error while building context %s, reason: %s", ictx.Name, err.Error()) } }) @@ -100,7 +132,7 @@ func (action *buildAction) Handle(ctx context.Context, ictx *v1alpha1.Integratio return nil } -func (action *buildAction) handleBuildStateChange(ctx context.Context, res builder.Result) error { +func (action *buildAction) handleBuildStateChange(ctx context.Context, res *builder.Result) error { // // Get the latest status of the context // @@ -113,8 +145,27 @@ func (action *buildAction) handleBuildStateChange(ctx context.Context, res build case builder.StatusSubmitted: logrus.Infof("Build submitted for IntegrationContext %s", target.Name) case builder.StatusStarted: - logrus.Infof("Build started for IntegrationContext %s", target.Name) + target.Status.Phase = v1alpha1.IntegrationContextPhaseBuildRunning + + logrus.Infof("Context %s transitioning to state %s", target.Name, target.Status.Phase) + + return action.client.Update(ctx, target) case builder.StatusError: + // we should ensure that the integration context is still in the right + // phase, if not there is a chance that the context has been modified + // by the user + if target.Status.Phase != v1alpha1.IntegrationContextPhaseBuildRunning { + + // terminate the build + res.Request.C.Done() + + return fmt.Errorf("found context %s not the an expected phase (expectd=%s, found=%s)", + res.Request.Meta.Name, + string(v1alpha1.IntegrationContextPhaseBuildRunning), + string(target.Status.Phase), + ) + } + target.Status.Phase = v1alpha1.IntegrationContextPhaseBuildFailureRecovery if target.Status.Failure == nil { @@ -132,6 +183,20 @@ func (action *buildAction) handleBuildStateChange(ctx context.Context, res build return action.client.Update(ctx, target) case builder.StatusCompleted: + // we should ensure that the integration context is still in the right + // phase, if not there is a chance that the context has been modified + // by the user + if target.Status.Phase != v1alpha1.IntegrationContextPhaseBuildRunning { + // terminate the build + res.Request.C.Done() + + return fmt.Errorf("found context %s not in the expected phase (expectd=%s, found=%s)", + res.Request.Meta.Name, + string(v1alpha1.IntegrationContextPhaseBuildRunning), + string(target.Status.Phase), + ) + } + target.Status.BaseImage = res.BaseImage target.Status.Image = res.Image target.Status.PublicImage = res.PublicImage diff --git a/pkg/controller/integrationcontext/initialize.go b/pkg/controller/integrationcontext/initialize.go index f84ee4428d..5a75986115 100644 --- a/pkg/controller/integrationcontext/initialize.go +++ b/pkg/controller/integrationcontext/initialize.go @@ -60,7 +60,7 @@ func (action *initializeAction) Handle(ctx context.Context, ictx *v1alpha1.Integ if target.Spec.Image == "" { // by default the context should be build - target.Status.Phase = v1alpha1.IntegrationContextPhaseBuilding + target.Status.Phase = v1alpha1.IntegrationContextPhaseBuildSubmitted } else { // but in case it has been created from an image, mark the // context as ready diff --git a/pkg/controller/integrationcontext/integrationcontext_controller.go b/pkg/controller/integrationcontext/integrationcontext_controller.go index 0547dc6c1b..27fa3e1d96 100644 --- a/pkg/controller/integrationcontext/integrationcontext_controller.go +++ b/pkg/controller/integrationcontext/integrationcontext_controller.go @@ -88,7 +88,7 @@ func (r *ReconcileIntegrationContext) Reconcile(request reconcile.Request) (reco integrationContextActionPool := []Action{ NewInitializeAction(), - NewBuildAction(ctx), + NewBuildAction(), NewErrorRecoveryAction(), NewMonitorAction(), } diff --git a/pkg/controller/integrationcontext/monitor.go b/pkg/controller/integrationcontext/monitor.go index df108f7574..7d56f7001f 100644 --- a/pkg/controller/integrationcontext/monitor.go +++ b/pkg/controller/integrationcontext/monitor.go @@ -52,7 +52,7 @@ func (action *monitorAction) Handle(ctx context.Context, ictx *v1alpha1.Integrat target := ictx.DeepCopy() target.Status.Digest = hash - target.Status.Phase = v1alpha1.IntegrationContextPhaseBuilding + target.Status.Phase = v1alpha1.IntegrationContextPhaseBuildSubmitted logrus.Info("Context ", target.Name, " transitioning to state ", target.Status.Phase) diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go index 89443c39e6..e0f7fc01ab 100644 --- a/pkg/trait/builder.go +++ b/pkg/trait/builder.go @@ -49,11 +49,11 @@ func (t *builderTrait) Configure(e *Environment) (bool, error) { return false, nil } - if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuilding) { + if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuildSubmitted) { return true, nil } - if e.InPhase(v1alpha1.IntegrationContextPhaseReady, v1alpha1.IntegrationPhaseBuildingImage) { + if e.InPhase(v1alpha1.IntegrationContextPhaseReady, v1alpha1.IntegrationPhaseBuildImageSubmitted) { return true, nil } @@ -61,7 +61,7 @@ func (t *builderTrait) Configure(e *Environment) (bool, error) { } func (t *builderTrait) Apply(e *Environment) error { - if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuilding) { + if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuildSubmitted) { if platform.SupportsS2iPublishStrategy(e.Platform) { e.Steps = s2i.DefaultSteps if e.DetermineProfile() == v1alpha1.TraitProfileKnative { @@ -73,7 +73,7 @@ func (t *builderTrait) Apply(e *Environment) error { } } - if e.InPhase(v1alpha1.IntegrationContextPhaseReady, v1alpha1.IntegrationPhaseBuildingImage) { + if e.InPhase(v1alpha1.IntegrationContextPhaseReady, v1alpha1.IntegrationPhaseBuildImageSubmitted) { if platform.SupportsS2iPublishStrategy(e.Platform) { e.Steps = []builder.Step{ builder.NewStep("packager", builder.ApplicationPackagePhase, builder.StandardPackager), diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go index 95b6b5c4fa..704dac7055 100644 --- a/pkg/trait/builder_test.go +++ b/pkg/trait/builder_test.go @@ -127,7 +127,7 @@ func createBuilderTestEnv(cluster v1alpha1.IntegrationPlatformCluster, strategy }, Context: &v1alpha1.IntegrationContext{ Status: v1alpha1.IntegrationContextStatus{ - Phase: v1alpha1.IntegrationContextPhaseBuilding, + Phase: v1alpha1.IntegrationContextPhaseBuildSubmitted, }, }, Platform: &v1alpha1.IntegrationPlatform{ diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go index 4f01bcd176..eee4295cb6 100644 --- a/pkg/trait/deployment.go +++ b/pkg/trait/deployment.go @@ -76,7 +76,7 @@ func (t *deploymentTrait) Configure(e *Environment) (bool, error) { func (t *deploymentTrait) Apply(e *Environment) error { if t.ContainerImage && e.InPhase(v1alpha1.IntegrationContextPhaseReady, v1alpha1.IntegrationPhaseBuildingContext) { // trigger container image build - e.Integration.Status.Phase = v1alpha1.IntegrationPhaseBuildingImage + e.Integration.Status.Phase = v1alpha1.IntegrationPhaseBuildImageSubmitted } if !t.ContainerImage && e.InPhase(v1alpha1.IntegrationContextPhaseReady, v1alpha1.IntegrationPhaseBuildingContext) { diff --git a/pkg/trait/springboot.go b/pkg/trait/springboot.go index 325a867344..92befb335a 100644 --- a/pkg/trait/springboot.go +++ b/pkg/trait/springboot.go @@ -46,7 +46,7 @@ func (t *springBootTrait) Configure(e *Environment) (bool, error) { return false, nil } - if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuilding) { + if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuildSubmitted) { return true, nil } if e.InPhase(v1alpha1.IntegrationContextPhaseReady, v1alpha1.IntegrationPhaseDeploying) { @@ -113,7 +113,7 @@ func (t *springBootTrait) Apply(e *Environment) error { // Integration Context // - if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuilding) { + if e.IntegrationContextInPhase(v1alpha1.IntegrationContextPhaseBuildSubmitted) { // add custom initialization logic e.Steps = append(e.Steps, builder.NewStep("initialize/spring-boot", builder.InitPhase, springboot.Initialize)) e.Steps = append(e.Steps, builder.NewStep("build/compute-boot-dependencies", builder.ProjectBuildPhase+1, springboot.ComputeDependencies)) diff --git a/test/build_manager_integration_test.go b/test/build_manager_integration_test.go index 44ed8501d9..d4a7c06bf5 100644 --- a/test/build_manager_integration_test.go +++ b/test/build_manager_integration_test.go @@ -22,6 +22,7 @@ limitations under the License. package test import ( + "context" "fmt" "testing" "time" @@ -34,11 +35,28 @@ import ( "github.com/stretchr/testify/assert" ) +func handler(in chan builder.Result, out chan builder.Result) { + for { + select { + case res := <-in: + if res.Status == builder.StatusCompleted || res.Status == builder.StatusError { + out <- res + return + } + case <-time.After(5 * time.Minute): + fmt.Println("timeout 1") + close(out) + return + } + } +} + func TestBuildManagerBuild(t *testing.T) { namespace := getTargetNamespace() b := builder.New(testContext, testClient, namespace) r := builder.Request{ + C: context.TODO(), Meta: v1.ObjectMeta{ Name: "man-test", ResourceVersion: "1", @@ -56,28 +74,20 @@ func TestBuildManagerBuild(t *testing.T) { Steps: s2i.DefaultSteps, } - c := make(chan builder.Result) + hc := make(chan builder.Result) + rc := make(chan builder.Result) - b.Submit(r, func(res builder.Result) { - c <- res - }) - - var result builder.Result - -loop: - for { - select { - case res := <-c: - if res.Status == builder.StatusCompleted || res.Status == builder.StatusError { - result = res - break loop - } - case <-time.After(5 * time.Minute): - fmt.Println("timeout 1") - break loop - } - } + go func() { + handler(hc, rc) + }() + go func() { + b.Submit(r, func(res *builder.Result) { + hc <- *res + }) + }() + result, ok := <-rc + assert.True(t, ok) assert.NotEqual(t, builder.StatusError, result.Status) assert.Equal(t, builder.StatusCompleted, result.Status) assert.Regexp(t, ".*/.*/.*:.*", result.Image) @@ -88,6 +98,7 @@ func TestBuildManagerFailedBuild(t *testing.T) { b := builder.New(testContext, testClient, namespace) r := builder.Request{ + C: context.TODO(), Meta: v1.ObjectMeta{ Name: "man-test", ResourceVersion: "1", @@ -104,27 +115,20 @@ func TestBuildManagerFailedBuild(t *testing.T) { Steps: s2i.DefaultSteps, } - c := make(chan builder.Result) - - b.Submit(r, func(res builder.Result) { - c <- res - }) + hc := make(chan builder.Result) + rc := make(chan builder.Result) - var result builder.Result -loop: - for { - select { - case res := <-c: - if res.Status == builder.StatusCompleted || res.Status == builder.StatusError { - result = res - break loop - } - case <-time.After(5 * time.Minute): - fmt.Println("timeout 1") - break loop - } - } + go func() { + handler(hc, rc) + }() + go func() { + b.Submit(r, func(res *builder.Result) { + hc <- *res + }) + }() + result, ok := <-rc + assert.True(t, ok) assert.Equal(t, builder.StatusError, result.Status) assert.NotEqual(t, builder.StatusCompleted, result.Status) }