Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retry when there's an EOF error while uploading tile #298

Merged
merged 12 commits into from
Dec 19, 2018
20 changes: 14 additions & 6 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@ required=[

[[constraint]]
name = "github.com/onsi/ginkgo"
version = "1.4.0"
version = "1.4.0"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"

[[constraint]]
name = "github.com/gosuri/uilive"
source = "github.com/pivotal/uilive"
branch = "PR-fix-start-panic"
138 changes: 101 additions & 37 deletions acceptance/upload_product_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,52 @@ import (
. "github.com/onsi/gomega"
)

type UploadProductTestServer struct {
UploadHandler http.Handler
}

func (t *UploadProductTestServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var responseString string
w.Header().Set("Content-Type", "application/json")

switch req.URL.Path {
case "/uaa/oauth/token":
responseString = `{
"access_token": "some-opsman-token",
"token_type": "bearer",
"expires_in": 3600
}`
case "/api/v0/diagnostic_report":
responseString = "{}"
case "/api/v0/available_products":
if req.Method == "GET" {
responseString = "[]"
} else if req.Method == "POST" {
auth := req.Header.Get("Authorization")
if auth != "Bearer some-opsman-token" {
w.WriteHeader(http.StatusUnauthorized)
return
}

t.UploadHandler.ServeHTTP(w, req)
return
}
default:
out, err := httputil.DumpRequest(req, true)
Expect(err).NotTo(HaveOccurred())
Fail(fmt.Sprintf("unexpected request: %s", out))
}

w.Write([]byte(responseString))
}

var _ = Describe("upload-product command", func() {
var (
product string
productFile *os.File
server *httptest.Server
product string
productFile *os.File
server *httptest.Server
uploadHandler func(http.ResponseWriter, *http.Request)
snip chan struct{}
)

BeforeEach(func() {
Expand Down Expand Up @@ -52,43 +93,18 @@ name: some-product`)
err = zipper.Close()
Expect(err).NotTo(HaveOccurred())

server = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var responseString string
w.Header().Set("Content-Type", "application/json")

switch req.URL.Path {
case "/uaa/oauth/token":
responseString = `{
"access_token": "some-opsman-token",
"token_type": "bearer",
"expires_in": 3600
}`
case "/api/v0/diagnostic_report":
responseString = "{}"
case "/api/v0/available_products":
if req.Method == "GET" {
responseString = "[]"
} else if req.Method == "POST" {
auth := req.Header.Get("Authorization")
if auth != "Bearer some-opsman-token" {
w.WriteHeader(http.StatusUnauthorized)
return
}
uploadHandler = func(w http.ResponseWriter, req *http.Request) {
err := req.ParseMultipartForm(100)
Expect(err).NotTo(HaveOccurred())

err := req.ParseMultipartForm(100)
Expect(err).NotTo(HaveOccurred())
product = req.MultipartForm.File["product[file]"][0].Filename
w.Write([]byte("{}"))
}

product = req.MultipartForm.File["product[file]"][0].Filename
responseString = "{}"
}
default:
out, err := httputil.DumpRequest(req, true)
Expect(err).NotTo(HaveOccurred())
Fail(fmt.Sprintf("unexpected request: %s", out))
}
})

w.Write([]byte(responseString))
}))
JustBeforeEach(func() {
server = httptest.NewTLSServer(&UploadProductTestServer{UploadHandler: http.HandlerFunc(uploadHandler)})
})

AfterEach(func() {
Expand Down Expand Up @@ -173,5 +189,53 @@ name: some-product`)
Eventually(session.Err, 5).Should(gbytes.Say(`no such file or directory`))
})
})

Context("when the server returns EOF during upload", func() {
BeforeEach(func() {
snip = make(chan struct{})
uploadCallCount := 0
uploadHandler = func(w http.ResponseWriter, req *http.Request) {
uploadCallCount++

if uploadCallCount == 1 {
close(snip)
return
} else {
err := req.ParseMultipartForm(100)
if err != nil {
http.Error(w, fmt.Sprintf("failed to parse request body: %s", err), http.StatusInternalServerError)
return
}

product = req.MultipartForm.File["product[file]"][0].Filename
w.Write([]byte("{}"))
}
}
})

JustBeforeEach(func() {
go func() {
<-snip

server.CloseClientConnections()
}()
})

It("retries the upload", func() {
command := exec.Command(pathToMain,
"--target", server.URL,
"--username", "some-username",
"--password", "some-password",
"--skip-ssl-validation",
"upload-product",
"--product", productFile.Name(),
)

session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())

Eventually(session, 5).Should(gexec.Exit(0))
})
})
})
})
Loading