Пример #1
0
func TestErrorStatusWithCustomMessage(t *testing.T) {
	cfg := config.New()
	u, err := url.Parse("https://lfs-server.com/objects/oid")
	if err != nil {
		t.Fatal(err)
	}

	statuses := map[int]string{
		400: "not panic",
		401: "not panic",
		403: "not panic",
		404: "not panic",
		405: "not panic",
		406: "not panic",
		429: "not panic",
		500: "panic",
		501: "not panic",
		503: "panic",
		504: "panic",
		507: "not panic",
		509: "not panic",
	}

	for status, panicMsg := range statuses {
		cliErr := &ClientError{
			Message: fmt.Sprintf("custom error for %d", status),
		}

		by, err := json.Marshal(cliErr)
		if err != nil {
			t.Errorf("Error building json for status %d: %s", status, err)
			continue
		}

		res := &http.Response{
			StatusCode: status,
			Header:     make(http.Header),
			Body:       ioutil.NopCloser(bytes.NewReader(by)),
			Request:    &http.Request{URL: u},
		}
		res.Header.Set("Content-Type", "application/vnd.git-lfs+json; charset=utf-8")

		err = handleResponse(cfg, res, nil)
		if err == nil {
			t.Errorf("No error from HTTP %d", status)
			continue
		}

		expected := fmt.Sprintf("custom error for %d", status)
		if actual := err.Error(); !strings.HasSuffix(actual, expected) {
			t.Errorf("Expected for HTTP %d:\n%s\nACTUAL:\n%s", status, expected, actual)
			continue
		}

		if errors.IsFatalError(err) == (panicMsg != "panic") {
			t.Errorf("Error for HTTP %d should %s", status, panicMsg)
			continue
		}
	}
}
Пример #2
0
func errorWith(err error, fatalErrFn func(error, string, ...interface{}), errFn func(string, ...interface{})) {
	if Debugging || errors.IsFatalError(err) {
		fatalErrFn(err, "%s", err)
		return
	}

	errFn("%s", err)
}
Пример #3
0
func TestUploadApiError(t *testing.T) {
	SetupTestCredentialsFunc()
	repo := test.NewRepo(t)
	repo.Pushd()
	defer func() {
		repo.Popd()
		repo.Cleanup()
		RestoreCredentialsFunc()
	}()

	mux := http.NewServeMux()
	server := httptest.NewServer(mux)
	tmp := tempdir(t)
	defer server.Close()
	defer os.RemoveAll(tmp)

	postCalled := false

	mux.HandleFunc("/media/objects", func(w http.ResponseWriter, r *http.Request) {
		postCalled = true
		w.WriteHeader(404)
	})

	cfg := config.NewFrom(config.Values{
		Git: map[string]string{
			"lfs.url": server.URL + "/media",
		},
	})

	oidPath, _ := lfs.LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
	if err := ioutil.WriteFile(oidPath, []byte("test"), 0744); err != nil {
		t.Fatal(err)
	}

	oid := filepath.Base(oidPath)
	stat, _ := os.Stat(oidPath)
	_, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: oid, Size: stat.Size()}, "upload", []string{"basic"})
	if err == nil {
		t.Fatal(err)
	}

	if errors.IsFatalError(err) {
		t.Fatal("should not panic")
	}

	if isDockerConnectionError(err) {
		return
	}

	expected := "LFS: " + fmt.Sprintf(httputil.GetDefaultError(404), server.URL+"/media/objects")
	if err.Error() != expected {
		t.Fatalf("Expected: %s\nGot: %s", expected, err.Error())
	}

	if !postCalled {
		t.Errorf("POST not called")
	}
}
Пример #4
0
func buildTestData() (oidsExist, oidsMissing []TestObject, err error) {
	const oidCount = 50
	oidsExist = make([]TestObject, 0, oidCount)
	oidsMissing = make([]TestObject, 0, oidCount)

	// Build test data for existing files & upload
	// Use test repo for this to simplify the process of making sure data matches oid
	// We're not performing a real test at this point (although an upload fail will break it)
	var callback testDataCallback
	repo := test.NewRepo(&callback)
	repo.Pushd()
	defer repo.Cleanup()
	// just one commit
	commit := test.CommitInput{CommitterName: "A N Other", CommitterEmail: "*****@*****.**"}
	var totalSize int64
	for i := 0; i < oidCount; i++ {
		filename := fmt.Sprintf("file%d.dat", i)
		sz := int64(rand.Intn(200)) + 50
		commit.Files = append(commit.Files, &test.FileInput{Filename: filename, Size: sz})
		totalSize += sz
	}
	outputs := repo.AddCommits([]*test.CommitInput{&commit})

	// now upload
	uploadQueue := lfs.NewUploadQueue(len(oidsExist), totalSize, false)
	for _, f := range outputs[0].Files {
		oidsExist = append(oidsExist, TestObject{Oid: f.Oid, Size: f.Size})

		u, err := lfs.NewUploadable(f.Oid, "Test file")
		if err != nil {
			return nil, nil, err
		}
		uploadQueue.Add(u)
	}
	uploadQueue.Wait()

	for _, err := range uploadQueue.Errors() {
		if errors.IsFatalError(err) {
			exit("Fatal error setting up test data: %s", err)
		}
	}

	// Generate SHAs for missing files, random but repeatable
	// No actual file content needed for these
	rand.Seed(int64(oidCount))
	runningSha := sha256.New()
	for i := 0; i < oidCount; i++ {
		runningSha.Write([]byte{byte(rand.Intn(256))})
		oid := hex.EncodeToString(runningSha.Sum(nil))
		sz := int64(rand.Intn(200)) + 50
		oidsMissing = append(oidsMissing, TestObject{Oid: oid, Size: sz})
	}
	return oidsExist, oidsMissing, nil
}
Пример #5
0
func TestDownloadAPIError(t *testing.T) {
	SetupTestCredentialsFunc()
	defer func() {
		RestoreCredentialsFunc()
	}()

	mux := http.NewServeMux()
	server := httptest.NewServer(mux)
	defer server.Close()

	tmp := tempdir(t)
	defer os.RemoveAll(tmp)

	mux.HandleFunc("/media/objects/oid", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(404)
	})

	cfg := config.NewFrom(config.Values{
		Git: map[string]string{
			"lfs.batch": "false",
			"lfs.url":   server.URL + "/media",
		},
	})

	_, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: "oid"}, "download", []string{"basic"})
	if err == nil {
		t.Fatal("no error?")
	}

	if errors.IsFatalError(err) {
		t.Fatal("should not panic")
	}

	if isDockerConnectionError(err) {
		return
	}

	expected := fmt.Sprintf(httputil.GetDefaultError(404), server.URL+"/media/objects/oid")
	if err.Error() != expected {
		t.Fatalf("Expected: %s\nGot: %s", expected, err.Error())
	}

}
Пример #6
0
func TestUploadVerifyError(t *testing.T) {
	SetupTestCredentialsFunc()
	repo := test.NewRepo(t)
	repo.Pushd()
	defer func() {
		repo.Popd()
		repo.Cleanup()
		RestoreCredentialsFunc()
	}()

	mux := http.NewServeMux()
	server := httptest.NewServer(mux)
	tmp := tempdir(t)
	defer server.Close()
	defer os.RemoveAll(tmp)

	postCalled := false
	verifyCalled := false

	mux.HandleFunc("/media/objects", func(w http.ResponseWriter, r *http.Request) {
		t.Logf("Server: %s %s", r.Method, r.URL)

		if r.Method != "POST" {
			w.WriteHeader(405)
			return
		}

		if r.Header.Get("Accept") != api.MediaType {
			t.Errorf("Invalid Accept")
		}

		if r.Header.Get("Content-Type") != api.MediaType {
			t.Errorf("Invalid Content-Type")
		}

		buf := &bytes.Buffer{}
		tee := io.TeeReader(r.Body, buf)
		reqObj := &api.ObjectResource{}
		err := json.NewDecoder(tee).Decode(reqObj)
		t.Logf("request header: %v", r.Header)
		t.Logf("request body: %s", buf.String())
		if err != nil {
			t.Fatal(err)
		}

		if reqObj.Oid != "988881adc9fc3655077dc2d4d757d480b5ea0e11" {
			t.Errorf("invalid oid from request: %s", reqObj.Oid)
		}

		if reqObj.Size != 4 {
			t.Errorf("invalid size from request: %d", reqObj.Size)
		}

		obj := &api.ObjectResource{
			Oid:  reqObj.Oid,
			Size: reqObj.Size,
			Actions: map[string]*api.LinkRelation{
				"upload": &api.LinkRelation{
					Href:   server.URL + "/upload",
					Header: map[string]string{"A": "1"},
				},
				"verify": &api.LinkRelation{
					Href:   server.URL + "/verify",
					Header: map[string]string{"B": "2"},
				},
			},
		}

		by, err := json.Marshal(obj)
		if err != nil {
			t.Fatal(err)
		}

		postCalled = true
		head := w.Header()
		head.Set("Content-Type", api.MediaType)
		head.Set("Content-Length", strconv.Itoa(len(by)))
		w.WriteHeader(202)
		w.Write(by)
	})

	mux.HandleFunc("/verify", func(w http.ResponseWriter, r *http.Request) {
		verifyCalled = true
		w.WriteHeader(404)
	})

	cfg := config.NewFrom(config.Values{
		Git: map[string]string{
			"lfs.url": server.URL + "/media",
		},
	})

	oidPath, _ := lfs.LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11")
	if err := ioutil.WriteFile(oidPath, []byte("test"), 0744); err != nil {
		t.Fatal(err)
	}

	oid := filepath.Base(oidPath)
	stat, _ := os.Stat(oidPath)
	o, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: oid, Size: stat.Size()}, "upload", []string{"basic"})
	if err != nil {
		if isDockerConnectionError(err) {
			return
		}
		t.Fatal(err)
	}
	err = api.VerifyUpload(cfg, o)
	if err == nil {
		t.Fatal("verify should fail")
	}

	if errors.IsFatalError(err) {
		t.Fatal("should not panic")
	}

	expected := fmt.Sprintf(httputil.GetDefaultError(404), server.URL+"/verify")
	if err.Error() != expected {
		t.Fatalf("Expected: %s\nGot: %s", expected, err.Error())
	}

	if !postCalled {
		t.Errorf("POST not called")
	}

	if !verifyCalled {
		t.Errorf("verify not called")
	}

}
Пример #7
0
func TestErrorStatusWithDefaultMessage(t *testing.T) {
	cfg := config.New()
	rawurl := "https://lfs-server.com/objects/oid"
	u, err := url.Parse(rawurl)
	if err != nil {
		t.Fatal(err)
	}

	statuses := map[int][]string{
		400: {defaultErrors[400], "not panic"},
		401: {defaultErrors[401], "not panic"},
		403: {defaultErrors[401], "not panic"},
		404: {defaultErrors[404], "not panic"},
		405: {defaultErrors[400] + " from HTTP 405", "not panic"},
		406: {defaultErrors[400] + " from HTTP 406", "not panic"},
		429: {defaultErrors[429], "not panic"},
		500: {defaultErrors[500], "panic"},
		501: {defaultErrors[500] + " from HTTP 501", "not panic"},
		503: {defaultErrors[500] + " from HTTP 503", "panic"},
		504: {defaultErrors[500] + " from HTTP 504", "panic"},
		507: {defaultErrors[507], "not panic"},
		509: {defaultErrors[509], "not panic"},
	}

	for status, results := range statuses {
		cliErr := &ClientError{
			Message: fmt.Sprintf("custom error for %d", status),
		}

		by, err := json.Marshal(cliErr)
		if err != nil {
			t.Errorf("Error building json for status %d: %s", status, err)
			continue
		}

		res := &http.Response{
			StatusCode: status,
			Header:     make(http.Header),
			Body:       ioutil.NopCloser(bytes.NewReader(by)),
			Request:    &http.Request{URL: u},
		}

		// purposely wrong content type so it falls back to default
		res.Header.Set("Content-Type", "application/vnd.git-lfs+json2")

		err = handleResponse(cfg, res, nil)
		if err == nil {
			t.Errorf("No error from HTTP %d", status)
			continue
		}

		expected := fmt.Sprintf(results[0], rawurl)
		if actual := err.Error(); !strings.HasSuffix(actual, expected) {
			t.Errorf("Expected for HTTP %d:\n%s\nACTUAL:\n%s", status, expected, actual)
			continue
		}

		if errors.IsFatalError(err) == (results[1] != "panic") {
			t.Errorf("Error for HTTP %d should %s", status, results[1])
			continue
		}
	}
}