Skip to content

Commit cad0a26

Browse files
authored
Merge pull request #482 from GSA-TTS/fix-docker-build-issue
Fix Docker lifecycle creation issue
2 parents 2048735 + 9f80aa7 commit cad0a26

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

operation/push.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,10 @@ func (p *AppPushOperation) uploadBitsPackage(ctx context.Context, app *resource.
351351
func (p *AppPushOperation) buildDroplet(ctx context.Context, pkg *resource.Package, manifest *AppManifest) (*resource.Droplet, error) {
352352
newBuild := resource.NewBuildCreate(pkg.GUID)
353353
if pkg.Type == resource.LifecycleDocker.String() {
354-
newBuild.Lifecycle = &resource.Lifecycle{Type: pkg.Type}
354+
newBuild.Lifecycle = &resource.Lifecycle{
355+
Type: pkg.Type,
356+
Data: &resource.DockerLifecycle{}, // Empty docker lifecycle data
357+
}
355358
} else {
356359
newBuild.Lifecycle = &resource.Lifecycle{
357360
Type: resource.LifecycleBuildpack.String(),

operation/push_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/cloudfoundry/go-cfclient/v3/client"
1111
"github.com/cloudfoundry/go-cfclient/v3/config"
12+
"github.com/cloudfoundry/go-cfclient/v3/resource"
1213
"github.com/cloudfoundry/go-cfclient/v3/testutil"
1314

1415
"github.com/stretchr/testify/require"
@@ -142,3 +143,113 @@ func TestAppPush(t *testing.T) {
142143
_, err = pusher.Push(context.Background(), manifest, fakeAppZipReader)
143144
require.NoError(t, err)
144145
}
146+
147+
func TestDockerLifecycleBuildCreation(t *testing.T) {
148+
serverURL := testutil.SetupFakeAPIServer()
149+
defer testutil.Teardown()
150+
151+
g := testutil.NewObjectJSONGenerator()
152+
build := g.Build("STAGED")
153+
droplet := g.Droplet()
154+
155+
manifest := &AppManifest{
156+
Name: "test-docker-app",
157+
Docker: &AppManifestDocker{
158+
Image: "kennethreitz/httpbin",
159+
},
160+
}
161+
162+
// Create a docker package manually for testing
163+
dockerPkg := &resource.Package{
164+
Type: "docker",
165+
Resource: resource.Resource{
166+
GUID: "docker-package-guid",
167+
},
168+
}
169+
170+
// Mock the API calls for docker build creation
171+
testutil.SetupMultiple([]testutil.MockRoute{
172+
{
173+
Method: http.MethodPost,
174+
Endpoint: "/v3/builds",
175+
Output: g.Single(build.JSON),
176+
Status: http.StatusCreated,
177+
// Verify that the lifecycle data contains proper docker lifecycle structure
178+
PostForm: `{"package":{"guid":"docker-package-guid"},"lifecycle":{"type":"docker","data":{}}}`,
179+
},
180+
{
181+
Method: http.MethodGet,
182+
Endpoint: fmt.Sprintf("/v3/builds/%s", build.GUID),
183+
Output: g.Single(build.JSON),
184+
Status: http.StatusOK,
185+
},
186+
{
187+
Method: http.MethodGet,
188+
Endpoint: "/v3/packages/docker-package-guid/droplets",
189+
Output: g.SinglePaged(droplet.JSON),
190+
Status: http.StatusOK,
191+
},
192+
}, t)
193+
194+
c, _ := config.New(serverURL, config.Token("", "fake-refresh-token"), config.SkipTLSValidation())
195+
cf, err := client.New(c)
196+
require.NoError(t, err)
197+
198+
pusher := NewAppPushOperation(cf, "", "")
199+
200+
// Test the buildDroplet method specifically with a docker package
201+
resultDroplet, err := pusher.buildDroplet(context.Background(), dockerPkg, manifest)
202+
require.NoError(t, err, "Docker lifecycle build should not fail")
203+
require.NotNil(t, resultDroplet, "Docker lifecycle build should return a droplet")
204+
}
205+
206+
// TestDockerLifecycleStructure tests that docker builds have the correct lifecycle structure
207+
func TestDockerLifecycleStructure(t *testing.T) {
208+
// Test the lifecycle structure directly without HTTP mocking
209+
dockerPkg := &resource.Package{
210+
Type: resource.LifecycleDocker.String(),
211+
Resource: resource.Resource{
212+
GUID: "test-docker-package",
213+
},
214+
}
215+
216+
// Create build request directly to test lifecycle structure
217+
buildCreate := resource.NewBuildCreate(dockerPkg.GUID)
218+
219+
// Apply the same logic as in buildDroplet method
220+
if dockerPkg.Type == resource.LifecycleDocker.String() {
221+
buildCreate.Lifecycle = &resource.Lifecycle{
222+
Type: dockerPkg.Type,
223+
Data: &resource.DockerLifecycle{}, // Empty docker lifecycle data
224+
}
225+
}
226+
227+
// Verify the structure
228+
require.NotNil(t, buildCreate.Lifecycle, "Docker build should have lifecycle")
229+
require.Equal(t, "docker", buildCreate.Lifecycle.Type, "Docker build should have docker lifecycle type")
230+
require.NotNil(t, buildCreate.Lifecycle.Data, "Docker build should have lifecycle data")
231+
232+
// Verify it's the correct type
233+
dockerLifecycle, ok := buildCreate.Lifecycle.Data.(*resource.DockerLifecycle)
234+
require.True(t, ok, "Docker build lifecycle data should be DockerLifecycle type")
235+
require.NotNil(t, dockerLifecycle, "Docker lifecycle data should not be nil")
236+
}
237+
238+
// TestDockerLifecycleJSONMarshaling tests that docker lifecycle marshals to correct JSON
239+
func TestDockerLifecycleJSONMarshaling(t *testing.T) {
240+
dockerLifecycle := &resource.Lifecycle{
241+
Type: "docker",
242+
Data: &resource.DockerLifecycle{}, // Empty docker lifecycle data
243+
}
244+
245+
// Test JSON marshaling to ensure it produces the expected structure
246+
// This is what the CF API expects: {"type":"docker","data":{}}
247+
expectedJSON := `{"type":"docker","data":{}}`
248+
249+
// Marshal the lifecycle
250+
actualJSON, err := dockerLifecycle.MarshalJSON()
251+
require.NoError(t, err, "Docker lifecycle should marshal without error")
252+
253+
// Verify the JSON structure matches expectations
254+
require.JSONEq(t, expectedJSON, string(actualJSON), "Docker lifecycle JSON should match expected format")
255+
}

0 commit comments

Comments
 (0)