func describeBuilder() { var mockCtrl *gomock.Controller BeforeEach(func() { mockCtrl = gomock.NewController(GinkgoT()) }) AfterEach(func() { mockCtrl.Finish() }) var ( logger boshlog.Logger mockReleaseJobResolver *mock_deployment_release.MockJobResolver mockDependencyCompiler *mock_state_job.MockDependencyCompiler mockJobListRenderer *mock_template.MockJobListRenderer mockCompressor *mock_template.MockRenderedJobListCompressor mockBlobstore *mock_blobstore.MockBlobstore stateBuilder Builder ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) mockReleaseJobResolver = mock_deployment_release.NewMockJobResolver(mockCtrl) mockDependencyCompiler = mock_state_job.NewMockDependencyCompiler(mockCtrl) mockJobListRenderer = mock_template.NewMockJobListRenderer(mockCtrl) mockCompressor = mock_template.NewMockRenderedJobListCompressor(mockCtrl) mockBlobstore = mock_blobstore.NewMockBlobstore(mockCtrl) }) Describe("Build", func() { var ( mockRenderedJobList *mock_template.MockRenderedJobList mockRenderedJobListArchive *mock_template.MockRenderedJobListArchive jobName string instanceID int deploymentManifest bideplmanifest.Manifest fakeStage *fakebiui.FakeStage releasePackageLibyaml *birelpkg.Package releasePackageRuby *birelpkg.Package releasePackageCPI *birelpkg.Package expectCompile *gomock.Call ) BeforeEach(func() { mockRenderedJobList = mock_template.NewMockRenderedJobList(mockCtrl) mockRenderedJobListArchive = mock_template.NewMockRenderedJobListArchive(mockCtrl) jobName = "fake-deployment-job-name" instanceID = 0 deploymentManifest = bideplmanifest.Manifest{ Name: "fake-deployment-name", Jobs: []bideplmanifest.Job{ { Name: "fake-deployment-job-name", Networks: []bideplmanifest.JobNetwork{ { Name: "fake-network-name", }, }, Templates: []bideplmanifest.ReleaseJobRef{ { Name: "fake-release-job-name", Release: "fake-release-name", }, }, Properties: biproperty.Map{ "fake-job-property": "fake-job-property-value", }, }, }, Networks: []bideplmanifest.Network{ { Name: "fake-network-name", Type: "fake-network-type", CloudProperties: biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, }, Properties: biproperty.Map{ "fake-job-property": "fake-global-property-value", //overridden by job property value }, } fakeStage = fakebiui.NewFakeStage() stateBuilder = NewBuilder( mockReleaseJobResolver, mockDependencyCompiler, mockJobListRenderer, mockCompressor, mockBlobstore, logger, ) releasePackageLibyaml = &birelpkg.Package{ Name: "libyaml", Fingerprint: "fake-package-source-fingerprint-libyaml", SHA1: "fake-package-source-sha1-libyaml", Dependencies: []*birelpkg.Package{}, ArchivePath: "fake-package-archive-path-libyaml", // only required by compiler... } releasePackageRuby = &birelpkg.Package{ Name: "ruby", Fingerprint: "fake-package-source-fingerprint-ruby", SHA1: "fake-package-source-sha1-ruby", Dependencies: []*birelpkg.Package{releasePackageLibyaml}, ArchivePath: "fake-package-archive-path-ruby", // only required by compiler... } releasePackageCPI = &birelpkg.Package{ Name: "cpi", Fingerprint: "fake-package-source-fingerprint-cpi", SHA1: "fake-package-source-sha1-cpi", Dependencies: []*birelpkg.Package{releasePackageRuby}, ArchivePath: "fake-package-archive-path-cpi", // only required by compiler... } }) JustBeforeEach(func() { releaseJob := bireljob.Job{ Name: "fake-release-job-name", Fingerprint: "fake-release-job-source-fingerprint", Packages: []*birelpkg.Package{releasePackageCPI, releasePackageRuby}, } mockReleaseJobResolver.EXPECT().Resolve("fake-release-job-name", "fake-release-name").Return(releaseJob, nil) releaseJobs := []bireljob.Job{releaseJob} compiledPackageRefs := []bistatejob.CompiledPackageRef{ { Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", SHA1: "fake-package-compiled-archive-sha1-libyaml", }, { Name: "ruby", Version: "fake-package-source-fingerprint-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", SHA1: "fake-package-compiled-archive-sha1-ruby", }, { Name: "cpi", Version: "fake-package-source-fingerprint-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", SHA1: "fake-package-compiled-archive-sha1-cpi", }, } expectCompile = mockDependencyCompiler.EXPECT().Compile(releaseJobs, fakeStage).Return(compiledPackageRefs, nil).AnyTimes() jobProperties := biproperty.Map{ "fake-job-property": "fake-job-property-value", } globalProperties := biproperty.Map{ "fake-job-property": "fake-global-property-value", } mockJobListRenderer.EXPECT().Render(releaseJobs, jobProperties, globalProperties, "fake-deployment-name").Return(mockRenderedJobList, nil) mockRenderedJobList.EXPECT().DeleteSilently() mockCompressor.EXPECT().Compress(mockRenderedJobList).Return(mockRenderedJobListArchive, nil) mockRenderedJobListArchive.EXPECT().DeleteSilently() mockRenderedJobListArchive.EXPECT().Path().Return("fake-rendered-job-list-archive-path") mockRenderedJobListArchive.EXPECT().SHA1().Return("fake-rendered-job-list-archive-sha1") mockRenderedJobListArchive.EXPECT().Fingerprint().Return("fake-rendered-job-list-fingerprint") mockBlobstore.EXPECT().Add("fake-rendered-job-list-archive-path").Return("fake-rendered-job-list-archive-blob-id", nil) }) It("compiles the dependencies of the jobs", func() { expectCompile.Times(1) _, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) }) It("builds a new instance state with zero-to-many networks", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(state.NetworkInterfaces()).To(ContainElement(NetworkRef{ Name: "fake-network-name", Interface: biproperty.Map{ "type": "fake-network-type", "default": []bideplmanifest.NetworkDefault{"dns", "gateway"}, "cloud_properties": biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, })) Expect(state.NetworkInterfaces()).To(HaveLen(1)) }) It("builds a new instance state with zero-to-many rendered jobs from one or more releases", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(state.RenderedJobs()).To(ContainElement(JobRef{ Name: "fake-release-job-name", Version: "fake-release-job-source-fingerprint", })) // multiple jobs are rendered in a single archive Expect(state.RenderedJobListArchive()).To(Equal(BlobRef{ BlobstoreID: "fake-rendered-job-list-archive-blob-id", SHA1: "fake-rendered-job-list-archive-sha1", })) Expect(state.RenderedJobs()).To(HaveLen(1)) }) It("prints ui stages for compiling packages and rendering job templates", func() { _, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(fakeStage.PerformCalls).To(Equal([]*fakebiui.PerformCall{ // compile stages not produced by mockDependencyCompiler {Name: "Rendering job templates"}, })) }) It("builds a new instance state with the compiled packages required by the release jobs", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, })) }) It("builds a new instance state that includes transitively dependent compiled packages", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", }, })) Expect(state.CompiledPackages()).To(HaveLen(3)) }) Context("when multiple packages have the same dependency", func() { BeforeEach(func() { releasePackageRuby.Dependencies = append(releasePackageRuby.Dependencies, releasePackageLibyaml) }) It("does not recompile dependant packages", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, })) Expect(state.CompiledPackages()).To(ContainElement(PackageRef{ Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", Archive: BlobRef{ SHA1: "fake-package-compiled-archive-sha1-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", }, })) Expect(state.CompiledPackages()).To(HaveLen(3)) }) }) It("builds an instance state that can be converted to an ApplySpec", func() { state, err := stateBuilder.Build(jobName, instanceID, deploymentManifest, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(state.ToApplySpec()).To(Equal(bias.ApplySpec{ Deployment: "fake-deployment-name", Index: 0, Networks: map[string]biproperty.Map{ "fake-network-name": biproperty.Map{ "type": "fake-network-type", "default": []bideplmanifest.NetworkDefault{"dns", "gateway"}, "cloud_properties": biproperty.Map{ "fake-network-cloud-property": "fake-network-cloud-property-value", }, }, }, Job: bias.Job{ Name: "fake-deployment-job-name", Templates: []bias.Blob{ { Name: "fake-release-job-name", Version: "fake-release-job-source-fingerprint", }, }, }, Packages: map[string]bias.Blob{ "cpi": bias.Blob{ Name: "cpi", Version: "fake-package-source-fingerprint-cpi", SHA1: "fake-package-compiled-archive-sha1-cpi", BlobstoreID: "fake-package-compiled-archive-blob-id-cpi", }, "ruby": bias.Blob{ Name: "ruby", Version: "fake-package-source-fingerprint-ruby", SHA1: "fake-package-compiled-archive-sha1-ruby", BlobstoreID: "fake-package-compiled-archive-blob-id-ruby", }, "libyaml": bias.Blob{ Name: "libyaml", Version: "fake-package-source-fingerprint-libyaml", SHA1: "fake-package-compiled-archive-sha1-libyaml", BlobstoreID: "fake-package-compiled-archive-blob-id-libyaml", }, }, RenderedTemplatesArchive: bias.RenderedTemplatesArchiveSpec{ BlobstoreID: "fake-rendered-job-list-archive-blob-id", SHA1: "fake-rendered-job-list-archive-sha1", }, ConfigurationHash: "fake-rendered-job-list-fingerprint", })) }) }) }
renderedJobListBlob := BlobRef{ BlobstoreID: "fake-rendered-job-list-archive-blob-id", SHA1: "fake-rendered-job-list-archive-blob-sha1", } state := NewState( "fake-deployment-name", "fake-job-name", 0, networkInterfaces, renderedJobs, compiledPackages, renderedJobListBlob, "fake-state-hash", ) applySpec := state.ToApplySpec() Expect(applySpec).To(Equal(bias.ApplySpec{ Deployment: "fake-deployment-name", Index: 0, Networks: map[string]biproperty.Map{ "fake-network-name": biproperty.Map{ "ip": "fake-ip", "type": "dynamic", }, }, Job: bias.Job{ Name: "fake-job-name", Templates: []bias.Blob{ { Name: "fake-job-name",