3 changed files with 269 additions and 249 deletions
@ -1,249 +0,0 @@ |
|||
package handlers |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/json" |
|||
"io/ioutil" |
|||
"net/http" |
|||
"net/url" |
|||
"strings" |
|||
"testing" |
|||
|
|||
"github.com/gin-gonic/gin" |
|||
"github.com/maxibanki/golang-url-shortener/store" |
|||
) |
|||
|
|||
const ( |
|||
testURL = "https://www.google.de/" |
|||
) |
|||
|
|||
// var server *httptest.Server
|
|||
|
|||
func TestCreateB(t *testing.T) { |
|||
TestCreateBackend(t) |
|||
} |
|||
|
|||
func TestCreateEntry(t *testing.T) { |
|||
tt := []struct { |
|||
name string |
|||
ignoreResponse bool |
|||
contentType string |
|||
authToken string |
|||
response gin.H |
|||
requestBody URLUtil |
|||
statusCode int |
|||
}{ |
|||
{ |
|||
name: "body is nil", |
|||
response: gin.H{"error": "EOF"}, |
|||
statusCode: http.StatusBadRequest, |
|||
contentType: "application/json; charset=utf-8", |
|||
ignoreResponse: true, |
|||
}, |
|||
{ |
|||
name: "short URL generation", |
|||
requestBody: URLUtil{ |
|||
URL: "https://www.google.de/", |
|||
}, |
|||
statusCode: http.StatusOK, |
|||
contentType: "application/json; charset=utf-8", |
|||
}, |
|||
{ |
|||
name: "no valid URL", |
|||
requestBody: URLUtil{ |
|||
URL: "this is really not a URL", |
|||
}, |
|||
statusCode: http.StatusBadRequest, |
|||
contentType: "application/json; charset=utf-8", |
|||
response: gin.H{"error": store.ErrNoValidURL.Error()}, |
|||
ignoreResponse: true, |
|||
}, |
|||
} |
|||
for _, tc := range tt { |
|||
t.Run(tc.name, func(t *testing.T) { |
|||
var reqBody []byte |
|||
if tc.requestBody.URL != "" { |
|||
json, err := json.Marshal(tc.requestBody) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal json: %v", err) |
|||
} |
|||
reqBody = json |
|||
} else { |
|||
reqBody = nil |
|||
} |
|||
respBody := createEntryWithJSON(t, reqBody, tc.contentType, tc.statusCode) |
|||
if len(tc.response) > 0 { |
|||
raw := makeJSON(t, tc.response) |
|||
if string(respBody) != raw { |
|||
t.Fatalf("expected body: %s; got: %s", tc.response, respBody) |
|||
} |
|||
} |
|||
if tc.ignoreResponse { |
|||
return |
|||
} |
|||
var parsed URLUtil |
|||
if err := json.Unmarshal(respBody, &parsed); err != nil { |
|||
t.Fatalf("could not unmarshal data: %v", err) |
|||
} |
|||
t.Run("test if shorted URL is correct", func(t *testing.T) { |
|||
testRedirect(t, parsed.URL, tc.requestBody.URL) |
|||
}) |
|||
}) |
|||
} |
|||
} |
|||
|
|||
func TestHandleInfo(t *testing.T) { |
|||
t.Run("check existing entry", func(t *testing.T) { |
|||
reqBody, err := json.Marshal(store.Entry{ |
|||
URL: testURL, |
|||
}) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal json: %v", err) |
|||
} |
|||
respBody := createEntryWithJSON(t, reqBody, "application/json; charset=utf-8", http.StatusOK) |
|||
var parsed URLUtil |
|||
if err = json.Unmarshal(respBody, &parsed); err != nil { |
|||
t.Fatalf("could not unmarshal data: %v", err) |
|||
} |
|||
body, err := json.Marshal(struct { |
|||
ID string |
|||
}{ |
|||
ID: strings.Replace(parsed.URL, server.URL+"/", "", 1), |
|||
}) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal the body: %v", err) |
|||
} |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBuffer(body)) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not post to the backend: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusOK { |
|||
t.Errorf("expected status %d; got %d", http.StatusOK, resp.StatusCode) |
|||
} |
|||
var entry store.Entry |
|||
if err = json.NewDecoder(resp.Body).Decode(&entry); err != nil { |
|||
t.Fatalf("could not unmarshal data: %v", err) |
|||
} |
|||
if entry.URL != testURL { |
|||
t.Fatalf("url is not the expected one: %s; got: %s", testURL, entry.URL) |
|||
} |
|||
}) |
|||
t.Run("invalid body", func(t *testing.T) { |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBuffer(nil)) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not post to the backend: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusBadRequest { |
|||
t.Errorf("expected status %d; got %d", http.StatusBadRequest, resp.StatusCode) |
|||
} |
|||
body, err := ioutil.ReadAll(resp.Body) |
|||
if err != nil { |
|||
t.Fatalf("could not read the body: %v", err) |
|||
} |
|||
body = bytes.TrimSpace(body) |
|||
raw := makeJSON(t, gin.H{ |
|||
"error": "EOF", |
|||
}) |
|||
if string(body) != raw { |
|||
t.Fatalf("body is not the expected one: %s", body) |
|||
} |
|||
}) |
|||
t.Run("no ID provided", func(t *testing.T) { |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBufferString("{}")) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not post to the backend: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusBadRequest { |
|||
t.Errorf("expected status %d; got %d", http.StatusBadRequest, resp.StatusCode) |
|||
} |
|||
body, err := ioutil.ReadAll(resp.Body) |
|||
body = bytes.TrimSpace(body) |
|||
if err != nil { |
|||
t.Fatalf("could not read the body: %v", err) |
|||
} |
|||
raw := makeJSON(t, gin.H{ |
|||
"error": "Key: '.ID' Error:Field validation for 'ID' failed on the 'required' tag", |
|||
}) |
|||
if string(body) != raw { |
|||
t.Fatalf("body is not the expected one: %s", body) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
func makeJSON(t *testing.T, data interface{}) string { |
|||
raw, err := json.Marshal(data) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal json: %v", err) |
|||
} |
|||
return string(raw) |
|||
} |
|||
|
|||
func createEntryWithJSON(t *testing.T, reqBody []byte, contentType string, statusCode int) []byte { |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/create", bytes.NewBuffer(reqBody)) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not do request: %v", err) |
|||
} |
|||
respBody, err := ioutil.ReadAll(resp.Body) |
|||
if err != nil { |
|||
t.Fatalf("could not read body: %v", err) |
|||
} |
|||
if resp.Header.Get("Content-Type") != contentType { |
|||
t.Fatalf("content-type is not the expected one: %s; got: %s", contentType, resp.Header.Get("Content-Type")) |
|||
} |
|||
if resp.StatusCode != statusCode { |
|||
t.Errorf("expected status %d; got %d", statusCode, resp.StatusCode) |
|||
} |
|||
return bytes.TrimSpace(respBody) |
|||
} |
|||
|
|||
func testRedirect(t *testing.T, shortURL, longURL string) { |
|||
client := &http.Client{ |
|||
CheckRedirect: func(req *http.Request, via []*http.Request) error { |
|||
return http.ErrUseLastResponse |
|||
}, // don't follow redirects
|
|||
} |
|||
u, err := url.Parse(shortURL) |
|||
if err != nil { |
|||
t.Fatalf("could not parse shorted URL: %v", err) |
|||
} |
|||
resp, err := client.Do(&http.Request{ |
|||
URL: u, |
|||
}) |
|||
if err != nil { |
|||
t.Fatalf("could not do http request to shorted URL: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusTemporaryRedirect { |
|||
t.Fatalf("expected status code: %d; got: %d", http.StatusTemporaryRedirect, resp.StatusCode) |
|||
} |
|||
if resp.Header.Get("Location") != longURL { |
|||
t.Fatalf("redirect URL is not correct") |
|||
} |
|||
} |
|||
|
|||
func TestCloseB(t *testing.T) { |
|||
TestCloseBackend(t) |
|||
} |
|||
@ -1,2 +1,245 @@ |
|||
package handlers |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/json" |
|||
"io/ioutil" |
|||
"net/http" |
|||
"net/url" |
|||
"strings" |
|||
"testing" |
|||
|
|||
"github.com/gin-gonic/gin" |
|||
"github.com/maxibanki/golang-url-shortener/store" |
|||
) |
|||
|
|||
const testURL = "https://www.google.de/" |
|||
|
|||
func TestCreateB(t *testing.T) { |
|||
TestCreateBackend(t) |
|||
} |
|||
|
|||
func TestCreateEntry(t *testing.T) { |
|||
tt := []struct { |
|||
name string |
|||
ignoreResponse bool |
|||
contentType string |
|||
authToken string |
|||
response gin.H |
|||
requestBody URLUtil |
|||
statusCode int |
|||
}{ |
|||
{ |
|||
name: "body is nil", |
|||
response: gin.H{"error": "EOF"}, |
|||
statusCode: http.StatusBadRequest, |
|||
contentType: "application/json; charset=utf-8", |
|||
ignoreResponse: true, |
|||
}, |
|||
{ |
|||
name: "short URL generation", |
|||
requestBody: URLUtil{ |
|||
URL: "https://www.google.de/", |
|||
}, |
|||
statusCode: http.StatusOK, |
|||
contentType: "application/json; charset=utf-8", |
|||
}, |
|||
{ |
|||
name: "no valid URL", |
|||
requestBody: URLUtil{ |
|||
URL: "this is really not a URL", |
|||
}, |
|||
statusCode: http.StatusBadRequest, |
|||
contentType: "application/json; charset=utf-8", |
|||
response: gin.H{"error": store.ErrNoValidURL.Error()}, |
|||
ignoreResponse: true, |
|||
}, |
|||
} |
|||
for _, tc := range tt { |
|||
t.Run(tc.name, func(t *testing.T) { |
|||
var reqBody []byte |
|||
if tc.requestBody.URL != "" { |
|||
json, err := json.Marshal(tc.requestBody) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal json: %v", err) |
|||
} |
|||
reqBody = json |
|||
} else { |
|||
reqBody = nil |
|||
} |
|||
respBody := createEntryWithJSON(t, reqBody, tc.contentType, tc.statusCode) |
|||
if len(tc.response) > 0 { |
|||
raw := makeJSON(t, tc.response) |
|||
if string(respBody) != raw { |
|||
t.Fatalf("expected body: %s; got: %s", tc.response, respBody) |
|||
} |
|||
} |
|||
if tc.ignoreResponse { |
|||
return |
|||
} |
|||
var parsed URLUtil |
|||
if err := json.Unmarshal(respBody, &parsed); err != nil { |
|||
t.Fatalf("could not unmarshal data: %v", err) |
|||
} |
|||
t.Run("test if shorted URL is correct", func(t *testing.T) { |
|||
testRedirect(t, parsed.URL, tc.requestBody.URL) |
|||
}) |
|||
}) |
|||
} |
|||
} |
|||
|
|||
func TestHandleInfo(t *testing.T) { |
|||
t.Run("check existing entry", func(t *testing.T) { |
|||
reqBody, err := json.Marshal(store.Entry{ |
|||
URL: testURL, |
|||
}) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal json: %v", err) |
|||
} |
|||
respBody := createEntryWithJSON(t, reqBody, "application/json; charset=utf-8", http.StatusOK) |
|||
var parsed URLUtil |
|||
if err = json.Unmarshal(respBody, &parsed); err != nil { |
|||
t.Fatalf("could not unmarshal data: %v", err) |
|||
} |
|||
body, err := json.Marshal(struct { |
|||
ID string |
|||
}{ |
|||
ID: strings.Replace(parsed.URL, server.URL+"/", "", 1), |
|||
}) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal the body: %v", err) |
|||
} |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBuffer(body)) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not post to the backend: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusOK { |
|||
t.Errorf("expected status %d; got %d", http.StatusOK, resp.StatusCode) |
|||
} |
|||
var entry store.Entry |
|||
if err = json.NewDecoder(resp.Body).Decode(&entry); err != nil { |
|||
t.Fatalf("could not unmarshal data: %v", err) |
|||
} |
|||
if entry.URL != testURL { |
|||
t.Fatalf("url is not the expected one: %s; got: %s", testURL, entry.URL) |
|||
} |
|||
}) |
|||
t.Run("invalid body", func(t *testing.T) { |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBuffer(nil)) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not post to the backend: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusBadRequest { |
|||
t.Errorf("expected status %d; got %d", http.StatusBadRequest, resp.StatusCode) |
|||
} |
|||
body, err := ioutil.ReadAll(resp.Body) |
|||
if err != nil { |
|||
t.Fatalf("could not read the body: %v", err) |
|||
} |
|||
body = bytes.TrimSpace(body) |
|||
raw := makeJSON(t, gin.H{ |
|||
"error": "EOF", |
|||
}) |
|||
if string(body) != raw { |
|||
t.Fatalf("body is not the expected one: %s", body) |
|||
} |
|||
}) |
|||
t.Run("no ID provided", func(t *testing.T) { |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBufferString("{}")) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not post to the backend: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusBadRequest { |
|||
t.Errorf("expected status %d; got %d", http.StatusBadRequest, resp.StatusCode) |
|||
} |
|||
body, err := ioutil.ReadAll(resp.Body) |
|||
body = bytes.TrimSpace(body) |
|||
if err != nil { |
|||
t.Fatalf("could not read the body: %v", err) |
|||
} |
|||
raw := makeJSON(t, gin.H{ |
|||
"error": "Key: '.ID' Error:Field validation for 'ID' failed on the 'required' tag", |
|||
}) |
|||
if string(body) != raw { |
|||
t.Fatalf("body is not the expected one: %s", body) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
func makeJSON(t *testing.T, data interface{}) string { |
|||
raw, err := json.Marshal(data) |
|||
if err != nil { |
|||
t.Fatalf("could not marshal json: %v", err) |
|||
} |
|||
return string(raw) |
|||
} |
|||
|
|||
func createEntryWithJSON(t *testing.T, reqBody []byte, contentType string, statusCode int) []byte { |
|||
req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/create", bytes.NewBuffer(reqBody)) |
|||
if err != nil { |
|||
t.Fatalf("could not create request %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
req.Header.Set("Authorization", tokenString) |
|||
resp, err := http.DefaultClient.Do(req) |
|||
if err != nil { |
|||
t.Fatalf("could not do request: %v", err) |
|||
} |
|||
respBody, err := ioutil.ReadAll(resp.Body) |
|||
if err != nil { |
|||
t.Fatalf("could not read body: %v", err) |
|||
} |
|||
if resp.Header.Get("Content-Type") != contentType { |
|||
t.Fatalf("content-type is not the expected one: %s; got: %s", contentType, resp.Header.Get("Content-Type")) |
|||
} |
|||
if resp.StatusCode != statusCode { |
|||
t.Errorf("expected status %d; got %d", statusCode, resp.StatusCode) |
|||
} |
|||
return bytes.TrimSpace(respBody) |
|||
} |
|||
|
|||
func testRedirect(t *testing.T, shortURL, longURL string) { |
|||
client := &http.Client{ |
|||
CheckRedirect: func(req *http.Request, via []*http.Request) error { |
|||
return http.ErrUseLastResponse |
|||
}, // don't follow redirects
|
|||
} |
|||
u, err := url.Parse(shortURL) |
|||
if err != nil { |
|||
t.Fatalf("could not parse shorted URL: %v", err) |
|||
} |
|||
resp, err := client.Do(&http.Request{ |
|||
URL: u, |
|||
}) |
|||
if err != nil { |
|||
t.Fatalf("could not do http request to shorted URL: %v", err) |
|||
} |
|||
if resp.StatusCode != http.StatusTemporaryRedirect { |
|||
t.Fatalf("expected status code: %d; got: %d", http.StatusTemporaryRedirect, resp.StatusCode) |
|||
} |
|||
if resp.Header.Get("Location") != longURL { |
|||
t.Fatalf("redirect URL is not correct") |
|||
} |
|||
} |
|||
|
|||
func TestCloseB(t *testing.T) { |
|||
TestCloseBackend(t) |
|||
} |
|||
|
|||
Loading…
Reference in new issue