-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move http from server package to protocol package
Protocol package handles the different types of incoming requests rq accepts. Currently http is the only protocol but this allows other protocols to use the interface. Ie: Websockets - Created a payload struct which we use between channels. - Moved the errorLog logger interface to this package because no other package needs to reuse it. - Changes to the start method: - Added a wg which allows us to control the goroutine from the server package. - Added a slice of renderer channels which we send incoming requests to. - Added a slice of quit channels to close renderers in the case that the http protocol has a fatal error.
- Loading branch information
Showing
4 changed files
with
253 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
package protocol | ||
|
||
import ( | ||
"bytes" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
) | ||
|
||
func TestResponseCodeFlag(t *testing.T) { | ||
tests := []int{200, 404, 201, 500} | ||
|
||
for _, respCode := range tests { | ||
httpServer := Http{ResponseCode: respCode} | ||
srv := httptest.NewServer(httpServer.routes()) | ||
req, err := http.NewRequest(http.MethodGet, srv.URL+"/", nil) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if resp.StatusCode != respCode { | ||
t.Errorf("Expected %d, got %d", respCode, resp.StatusCode) | ||
} | ||
resp.Body.Close() | ||
srv.Close() | ||
} | ||
} | ||
|
||
func TestLogRequestOneRenderer(t *testing.T) { | ||
testTable := []struct { | ||
method string | ||
path string | ||
body string | ||
expectedParams string | ||
headerKey string | ||
headerValue string | ||
}{ | ||
{ | ||
http.MethodGet, | ||
"/foo", | ||
"", | ||
"", | ||
"Foo", | ||
"Bar", | ||
}, | ||
{ | ||
http.MethodPost, | ||
"/foo/bar", | ||
"{\"foo\": \"bar\"}", | ||
"{\"foo\" => \"bar\"}", | ||
"Content-Type", | ||
"application/json", | ||
}, | ||
{ | ||
http.MethodDelete, | ||
"/foo/1", | ||
"", | ||
"", | ||
"Bearer", | ||
"hello!", | ||
}, | ||
{ | ||
http.MethodGet, | ||
"/foo/bar?hello=world", | ||
"", | ||
"{\"hello\" => \"world\"}", | ||
"Content-Type", | ||
"application/json!", | ||
}, | ||
} | ||
|
||
rpChannel := make(chan RequestPayload, len(testTable)) | ||
httpServer := Http{ResponseCode: 200, rendererChannels: []chan RequestPayload{rpChannel}} | ||
srv := httptest.NewServer(httpServer.routes()) | ||
defer srv.Close() | ||
|
||
for _, test := range testTable { | ||
b := bytes.NewBuffer([]byte(test.body)) | ||
req, err := http.NewRequest(test.method, srv.URL+test.path, b) | ||
|
||
if test.headerKey != "" { | ||
req.Header.Set(test.headerKey, test.headerValue) | ||
} | ||
|
||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
resp.Body.Close() | ||
|
||
rp := <-rpChannel | ||
|
||
if rp.Fields.Method != test.method { | ||
t.Errorf("Expected %s, got %s", test.method, rp.Fields.Method) | ||
} | ||
|
||
if rp.Fields.Url != test.path { | ||
t.Errorf("Expected %s, got %s", test.path, rp.Fields.Url) | ||
} | ||
|
||
if rp.Params != test.expectedParams { | ||
t.Errorf("Expected %s, got %s", test.expectedParams, rp.Params) | ||
} | ||
|
||
expectedHeaderValue := rp.Headers[test.headerKey][0] | ||
if expectedHeaderValue != test.headerValue { | ||
t.Errorf("Expected %s, got %s", expectedHeaderValue, test.headerValue) | ||
} | ||
} | ||
} | ||
|
||
func TestLogRequestManyRenderers(t *testing.T) { | ||
testTable := []struct { | ||
method string | ||
path string | ||
Body string | ||
expectedParams string | ||
}{ | ||
{http.MethodGet, "/foo", "", ""}, | ||
{http.MethodPost, "/foo/bar", "{\"foo\": \"bar\"}", "{\"foo\" => \"bar\"}"}, | ||
{http.MethodDelete, "/foo/1", "", ""}, | ||
{http.MethodGet, "/foo/bar?hello=world", "", "{\"hello\" => \"world\"}"}, | ||
} | ||
|
||
rpChannelA := make(chan RequestPayload, len(testTable)) | ||
rpChannelB := make(chan RequestPayload, len(testTable)) | ||
httpServer := Http{ | ||
ResponseCode: 200, | ||
rendererChannels: []chan RequestPayload{rpChannelA, rpChannelB}} | ||
srv := httptest.NewServer(httpServer.routes()) | ||
defer srv.Close() | ||
|
||
for _, test := range testTable { | ||
b := bytes.NewBuffer([]byte(test.Body)) | ||
req, err := http.NewRequest(test.method, srv.URL+test.path, b) | ||
|
||
if test.Body != "" { | ||
req.Header.Set("Content-Type", "application/json") | ||
} | ||
|
||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
resp.Body.Close() | ||
|
||
rpA := <-rpChannelA | ||
rpB := <-rpChannelB | ||
|
||
if rpA.Fields.Method != test.method { | ||
t.Errorf("Expected %s, got %s", test.method, rpA.Fields.Method) | ||
} | ||
|
||
if rpA.Fields.Url != test.path { | ||
t.Errorf("Expected %s, got %s", test.path, rpA.Fields.Url) | ||
} | ||
|
||
if rpA.Params != test.expectedParams { | ||
t.Errorf("Expected %s, got %s", test.expectedParams, rpA.Params) | ||
} | ||
|
||
if rpB.Fields.Method != test.method { | ||
t.Errorf("Expected %s, got %s", test.method, rpB.Fields.Method) | ||
} | ||
|
||
if rpB.Fields.Url != test.path { | ||
t.Errorf("Expected %s, got %s", test.path, rpB.Fields.Url) | ||
} | ||
|
||
if rpB.Params != test.expectedParams { | ||
t.Errorf("Expected %s, got %s", test.expectedParams, rpB.Params) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package protocol | ||
|
||
import ( | ||
"sync" | ||
|
||
"github.com/aaronvb/logrequest" | ||
) | ||
|
||
// Protocol is the interface for the servers that accept incoming requests. | ||
// Incoming requests are then sent to the renderers through the RequestPayload channel. | ||
// If a protocol closes(ie: from and error), we use the second channel which is used to | ||
// send an int(1 signals quit). | ||
type Protocol interface { | ||
Start(*sync.WaitGroup, []chan RequestPayload, []chan int) | ||
} | ||
|
||
// RequestPayload is the request payload we receive from an incoming request that we use with | ||
// the renderers. | ||
type RequestPayload struct { | ||
Fields logrequest.RequestFields `json:"fields"` | ||
Headers map[string][]string `json:"headers"` | ||
Params string `json:"params"` | ||
} |
Oops, something went wrong.