diff --git a/src/github.com/matrix-org/go-neb/matrix/matrix.go b/src/github.com/matrix-org/go-neb/matrix/matrix.go index 1834ca2..e03c9eb 100644 --- a/src/github.com/matrix-org/go-neb/matrix/matrix.go +++ b/src/github.com/matrix-org/go-neb/matrix/matrix.go @@ -156,7 +156,7 @@ func (cli *Client) SendText(roomID, text string) (string, error) { // UploadLink uploads an HTTP URL and then returns an MXC URI. func (cli *Client) UploadLink(link string) (string, error) { - res, err := http.Get(link) + res, err := cli.httpClient.Get(link) if res != nil { defer res.Body.Close() } diff --git a/src/github.com/matrix-org/go-neb/services/guggy/guggy.go b/src/github.com/matrix-org/go-neb/services/guggy/guggy.go index e661fa3..940a416 100644 --- a/src/github.com/matrix-org/go-neb/services/guggy/guggy.go +++ b/src/github.com/matrix-org/go-neb/services/guggy/guggy.go @@ -18,6 +18,8 @@ import ( // ServiceType of the Guggy service const ServiceType = "guggy" +var httpClient = &http.Client{} + type guggyQuery struct { // "mp4" or "gif" Format string `json:"format"` @@ -93,8 +95,6 @@ func (s *Service) cmdGuggy(client *matrix.Client, roomID, userID string, args [] func (s *Service) text2gifGuggy(querySentence string) (*guggyGifResult, error) { log.Info("Transforming to GIF query ", querySentence) - client := &http.Client{} - var query guggyQuery query.Format = "gif" query.Sentence = querySentence @@ -114,7 +114,7 @@ func (s *Service) text2gifGuggy(querySentence string) (*guggyGifResult, error) { req.Header.Add("Content-Type", "application/json") req.Header.Add("apiKey", s.APIKey) - res, err := client.Do(req) + res, err := httpClient.Do(req) if res != nil { defer res.Body.Close() } diff --git a/src/github.com/matrix-org/go-neb/services/guggy/guggy_test.go b/src/github.com/matrix-org/go-neb/services/guggy/guggy_test.go new file mode 100644 index 0000000..b7d5a05 --- /dev/null +++ b/src/github.com/matrix-org/go-neb/services/guggy/guggy_test.go @@ -0,0 +1,110 @@ +package guggy + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/matrix-org/go-neb/database" + "github.com/matrix-org/go-neb/matrix" + "github.com/matrix-org/go-neb/types" + "io/ioutil" + "net/http" + "net/url" + "strings" + "testing" +) + +type MockTransport struct { + roundTrip func(*http.Request) (*http.Response, error) +} + +func (t MockTransport) RoundTrip(req *http.Request) (*http.Response, error) { + return t.roundTrip(req) +} + +// TODO: It would be nice to tabularise this test so we can try failing different combinations of responses to make +// sure all cases are handled, rather than just the general case as is here. +func TestCommand(t *testing.T) { + database.SetServiceDB(&database.NopStorage{}) + apiKey := "secret" + guggyImageURL := "https://guggy.com/gifs/23ryf872fg" + + // Mock the response from Guggy + guggyTrans := struct{ MockTransport }{} + guggyTrans.roundTrip = func(req *http.Request) (*http.Response, error) { + guggyURL := "https://text2gif.guggy.com/guggify" + if req.URL.String() != guggyURL { + t.Fatalf("Bad URL: got %s want %s", req.URL.String(), guggyURL) + } + if req.Method != "POST" { + t.Fatalf("Bad method: got %s want POST", req.Method) + } + if req.Header.Get("apiKey") != apiKey { + t.Fatalf("Bad apiKey: got %s want %s", req.Header.Get("apiKey"), apiKey) + } + // check the query is in the request body + var reqBody guggyQuery + if err := json.NewDecoder(req.Body).Decode(&reqBody); err != nil { + t.Fatalf("Failed to read request body: %s", err) + } + if reqBody.Sentence != "hey listen!" { + t.Fatalf("Bad query: got '%s' want '%s'", reqBody.Sentence, "hey listen!") + } + + res := guggyGifResult{ + Width: 64, + Height: 64, + ReqID: "12345", + GIF: guggyImageURL, + } + b, err := json.Marshal(res) + if err != nil { + t.Fatalf("Failed to marshal guggy response", err) + } + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBuffer(b)), + }, nil + } + // clobber the guggy service http client instance + httpClient = &http.Client{Transport: guggyTrans} + + // Create the Guggy service + srv, err := types.CreateService("id", ServiceType, "@guggybot:hyrule", []byte( + `{"api_key":"`+apiKey+`"}`, + )) + if err != nil { + t.Fatal("Failed to create Guggy service: ", err) + } + guggy := srv.(*Service) + + // Mock the response from Matrix + matrixTrans := struct{ MockTransport }{} + matrixTrans.roundTrip = func(req *http.Request) (*http.Response, error) { + if req.URL.String() == guggyImageURL { // getting the guggy image + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString("some image data")), + }, nil + } else if strings.Contains(req.URL.String(), "_matrix/media/r0/upload") { // uploading the image to matrix + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`{"content_uri":"mxc://foo/bar"}`)), + }, nil + } + return nil, fmt.Errorf("Unknown URL: %s", req.URL.String()) + } + u, _ := url.Parse("https://hyrule") + matrixCli := matrix.NewClient(&http.Client{Transport: matrixTrans}, u, "its_a_secret", "@guggybot:hyrule") + + // Execute the matrix !command + cmds := guggy.Commands(matrixCli) + if len(cmds) != 1 { + t.Fatalf("Unexpected number of commands: %d", len(cmds)) + } + cmd := cmds[0] + _, err = cmd.Command("!someroom:hyrule", "@navi:hyrule", []string{"hey", "listen!"}) + if err != nil { + t.Fatalf("Failed to process command: ", err.Error()) + } +}