Open robert-min opened 1 year ago
type pkgData struct {
Name string `json:"name"`
Version string `json:"version"`
}
type pkgRegisterResult struct {
ID string `json:"id"`
}
func registerPackageData(url string, data pkgData) (pkgRegisterResult, error) {
p := pkgRegisterResult{}
b, err := json.Marshal(data)
if err != nil {
return p, err
}
reader := bytes.NewReader(b)
// url에 byte 정보를 받아서 POST 요청
r, err := http.Post(url, "application/json", reader)
if err != nil {
return p, err
}
defer r.Body.Close()
respData, err := io.ReadAll(r.Body)
if err != nil {
return p, err
}
if r.StatusCode != http.StatusOK {
return p, errors.New(string(respData))
}
err = json.Unmarshal(respData, &p)
return p, err
}
package pkgregister
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"testing"
)
// POST request handler
func packageRegHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
p := pkgData{}
// Package registration response
d := pkgRegisterResult{}
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Convert JSON data included in POST request to pkg
err = json.Unmarshal(data, &p)
if err != nil || len(p.Name) == 0 || len(p.Version) == 0 {
// HTTP 400
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
d.ID = p.Name + "-" + p.Version
jsonData, err := json.Marshal(d)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(jsonData))
} else {
http.Error(w, "Invalid HTTP method specified", http.StatusMethodNotAllowed)
return
}
}
func startTestPackageServer() *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(packageRegHandler))
return ts
}
func TestRegisterPackageData(t *testing.T) {
ts := startTestPackageServer()
defer ts.Close()
p := pkgData{
Name: "mypackage",
Version: "0.1",
}
resp, err := registerPackageData(ts.URL, p)
if err != nil {
t.Fatal(err)
}
if resp.ID != "mypackage-0.1" {
t.Errorf("Expected package id to be mypackage-0.1, Got: %s", resp.ID)
}
}
func TestRegisterEmptyPacakgeData(t *testing.T) {
ts := startTestPackageServer()
defer ts.Close()
p := pkgData{}
resp, err := registerPackageData(ts.URL, p)
if err == nil {
t.Fatal("Expected error to be non-nil, got nil")
}
if len(resp.ID) != 0 {
t.Errorf("Expected package ID to be empty, got: %s", resp.ID)
}
}
multipart/form-data
를 사용하면 키와 값을 포함하느 바디는 물론 요청 내에 파일의 데이터를 포함하여 전송할 수 잇음multipart
패키지를 사용하여 멀티 파트 바디를 읽고 쓰기 위해 필요한 모든 타입과 매서드를 정의func createMultiPartMessage(data pkgData) ([]byte, string, error) {
var b bytes.Buffer
var err error
var fw io.Writer
mw := multipart.NewWriter(&b)
// Set form field and assign object
fw, err = mw.CreateFormField("name")
if err != nil {
return nil, "", err
}
fmt.Fprintf(fw, data.Name)
fw, err = mw.CreateFormField("version")
if err != nil {
return nil, "", err
}
fmt.Fprintf(fw, data.Version)
// Create binary fields and assign "fw"
fw, err = mw.CreateFormFile("filedata", data.Filename)
if err != nil {
return nil, "", err
}
_, err = io.Copy(fw, data.Bytes)
err = mw.Close()
if err != nil {
return nil, "", err
}
contentType := mw.FormDataContentType()
return b.Bytes(), contentType, nil
}
func registerPackageData(url string, data pkgData) (pkgRegisterResult, error) {
p := pkgRegisterResult{}
// Create multipart/form-data payload
payload, contentType, err := createMultiPartMessage(data)
if err != nil {
return p, err
}
reader := bytes.NewReader(payload)
r, err := http.Post(url, contentType, reader)
if err != nil {
return p, err
}
defer r.Body.Close()
respData, err := io.ReadAll(r.Body)
if err != nil {
return p, err
}
err = json.Unmarshal(respData, &p)
return p, err
}
func packageRegHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
d := pkgRegisterResult{}
// 5000 : maximum number of bytes to buffer in memory.
err := r.ParseMultipartForm(5000)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
mForm := r.MultipartForm
// Get file data
f := mForm.File["filedata"][0]
// Construct an artificial package ID to return
d.ID = fmt.Sprintf("%s-%s", mForm.Value["name"][0], mForm.Value["version"][0])
d.Filename = f.Filename
d.Size = f.Size
// Marshal outgoing package registration response
jsonData, err := json.Marshal(d)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, string(jsonData))
} else {
http.Error(w, "Invalid HTTP method specified", http.StatusMethodNotAllowed)
return
}
}
func startTestPackageServer() *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(packageRegHandler))
return ts
}
func TestRegisterPackageData(t *testing.T) {
ts := startTestPackageServer()
defer ts.Close()
p := pkgData{
Name: "mypackage",
Version: "0.1",
Filename: "mypackage-0.1.tar.gz",
Bytes: strings.NewReader("data"),
}
pResult, err := registerPackageData(ts.URL, p)
if err != nil {
t.Fatal(err)
}
if pResult.ID != fmt.Sprintf("%s-%s", p.Name, p.Version) {
t.Errorf("Expected package ID to be %s-%s, Got: %s", p.Name, p.Version, pResult.ID)
}
if pResult.Filename != p.Filename {
t.Errorf("Expected package filename to be %s, Got: %s", p.Filename, pResult.Filename)
}
if pResult.Size != 4 {
t.Errorf("Expected package size to be 4, Got: %d", pResult.Size)
}
}
데이터 송신
{"name": "package1", "version": "1.1"}
{"id": "package1-1.1"}