Skip to content

Commit b72346d

Browse files
authored
Merge pull request #30 from x1unix/dev
Refactor and cover Go Playground client
2 parents 9790533 + 68317ae commit b72346d

File tree

9 files changed

+507
-63
lines changed

9 files changed

+507
-63
lines changed

pkg/goplay/client.go

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ import (
55
"context"
66
"fmt"
77
"io"
8+
"net"
89
"net/http"
910
"net/url"
1011
"strings"
12+
"time"
1113
)
1214

1315
const (
14-
userAgent = "goplay.x1unix.com/1.0 (http://goplay.x1unix.com/)"
15-
goPlayURL = "https://play.golang.org"
16+
defaultUserAgent = "goplay.tools/1.0 (http://goplay.tools/)"
17+
playgroundUrl = "https://play.golang.org"
1618

1719
// maxSnippetSize value taken from
1820
// https://github.com/golang/playground/blob/master/app/goplay/share.go
@@ -22,33 +24,61 @@ const (
2224
// ErrSnippetTooLarge is snippet max size limit error
2325
var ErrSnippetTooLarge = fmt.Errorf("code snippet too large (max %d bytes)", maxSnippetSize)
2426

25-
func newRequest(ctx context.Context, method, queryPath string, body io.Reader) (*http.Request, error) {
26-
uri := goPlayURL + "/" + queryPath
27+
type Client struct {
28+
client http.Client
29+
baseUrl string
30+
userAgent string
31+
}
32+
33+
// NewClient returns new Go playground client
34+
func NewClient(baseUrl, userAgent string, timeout time.Duration) *Client {
35+
return &Client{
36+
baseUrl: baseUrl,
37+
userAgent: userAgent,
38+
client: http.Client{
39+
Timeout: timeout,
40+
Transport: &http.Transport{
41+
DialContext: (&net.Dialer{
42+
Timeout: timeout,
43+
}).DialContext,
44+
TLSHandshakeTimeout: timeout,
45+
},
46+
},
47+
}
48+
}
49+
50+
// NewDefaultClient returns Go Playground client with defaults
51+
func NewDefaultClient() *Client {
52+
return NewClient(playgroundUrl, defaultUserAgent, 15*time.Second)
53+
}
54+
55+
func (c *Client) newRequest(ctx context.Context, method, queryPath string, body io.Reader) (*http.Request, error) {
56+
uri := c.baseUrl + "/" + queryPath
2757
req, err := http.NewRequestWithContext(ctx, method, uri, body)
2858
if err != nil {
2959
return nil, err
3060
}
3161

32-
req.Header.Add("User-Agent", userAgent)
62+
req.Header.Add("User-Agent", c.userAgent)
3363
return req, nil
3464
}
3565

36-
func getRequest(ctx context.Context, queryPath string) (*http.Response, error) {
37-
req, err := newRequest(ctx, http.MethodGet, queryPath, nil)
66+
func (c *Client) getRequest(ctx context.Context, queryPath string) (*http.Response, error) {
67+
req, err := c.newRequest(ctx, http.MethodGet, queryPath, nil)
3868
if err != nil {
3969
return nil, nil
4070
}
4171

42-
return http.DefaultClient.Do(req)
72+
return c.client.Do(req)
4373
}
4474

45-
func doRequest(ctx context.Context, method, url, contentType string, body io.Reader) ([]byte, error) {
46-
req, err := newRequest(ctx, method, url, body)
75+
func (c *Client) doRequest(ctx context.Context, method, url, contentType string, body io.Reader) ([]byte, error) {
76+
req, err := c.newRequest(ctx, method, url, body)
4777
if err != nil {
4878
return nil, err
4979
}
5080
req.Header.Add("Content-Type", contentType)
51-
response, err := http.DefaultClient.Do(req)
81+
response, err := c.client.Do(req)
5282
if err != nil {
5383
return nil, err
5484
}
@@ -66,8 +96,8 @@ func doRequest(ctx context.Context, method, url, contentType string, body io.Rea
6696
return bodyBytes.Bytes(), nil
6797
}
6898

69-
func postForm(ctx context.Context, url string, data url.Values) ([]byte, error) {
70-
return doRequest(
99+
func (c *Client) postForm(ctx context.Context, url string, data url.Values) ([]byte, error) {
100+
return c.doRequest(
71101
ctx, "POST", url,
72102
"application/x-www-form-urlencoded", strings.NewReader(data.Encode()),
73103
)

pkg/goplay/client_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package goplay
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestNewDefaultClient(t *testing.T) {
10+
c := NewDefaultClient()
11+
require.Equal(t, c.baseUrl, playgroundUrl)
12+
require.Equal(t, c.userAgent, defaultUserAgent)
13+
}

pkg/goplay/errors_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package goplay
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestCompileFailedError_Error(t *testing.T) {
12+
msg := "test"
13+
err := CompileFailedError{msg: msg}
14+
require.Equal(t, msg, err.Error())
15+
}
16+
17+
func TestIsCompileError(t *testing.T) {
18+
errs := []struct {
19+
err error
20+
want bool
21+
}{
22+
{
23+
err: CompileFailedError{},
24+
want: true,
25+
},
26+
{
27+
err: errors.New("test"),
28+
},
29+
{
30+
err: ErrSnippetNotFound,
31+
},
32+
}
33+
34+
for _, c := range errs {
35+
t.Run(fmt.Sprintf("%T", c.err), func(t *testing.T) {
36+
require.Equal(t, c.want, IsCompileError(c.err))
37+
})
38+
}
39+
}

pkg/goplay/methods.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,13 @@ func ValidateContentLength(itemLen int) error {
1717
if itemLen > maxSnippetSize {
1818
return ErrSnippetTooLarge
1919
}
20-
2120
return nil
2221
}
2322

2423
// GetSnippet returns snippet from Go playground
25-
func GetSnippet(ctx context.Context, snippetID string) (*Snippet, error) {
24+
func (c *Client) GetSnippet(ctx context.Context, snippetID string) (*Snippet, error) {
2625
fileName := snippetID + ".go"
27-
resp, err := getRequest(ctx, "p/"+fileName)
26+
resp, err := c.getRequest(ctx, "p/"+fileName)
2827
if err != nil {
2928
return nil, err
3029
}
@@ -49,8 +48,8 @@ func GetSnippet(ctx context.Context, snippetID string) (*Snippet, error) {
4948
}
5049

5150
// Share shares snippet to go playground
52-
func Share(ctx context.Context, src io.Reader) (string, error) {
53-
resp, err := doRequest(ctx, http.MethodPost, "share", "text/plain", src)
51+
func (c *Client) Share(ctx context.Context, src io.Reader) (string, error) {
52+
resp, err := c.doRequest(ctx, http.MethodPost, "share", "text/plain", src)
5453
if err != nil {
5554
return "", err
5655
}
@@ -60,12 +59,12 @@ func Share(ctx context.Context, src io.Reader) (string, error) {
6059
}
6160

6261
// GoImports performs Goimports
63-
func GoImports(ctx context.Context, src []byte) (*FmtResponse, error) {
62+
func (c *Client) GoImports(ctx context.Context, src []byte) (*FmtResponse, error) {
6463
form := url.Values{}
6564
form.Add("imports", "true")
6665
form.Add("body", string(src))
6766

68-
resp, err := postForm(ctx, "fmt", form)
67+
resp, err := c.postForm(ctx, "fmt", form)
6968
if err != nil {
7069
return nil, fmt.Errorf("failed to contact Go Playground - %s", err)
7170
}
@@ -83,20 +82,20 @@ func GoImports(ctx context.Context, src []byte) (*FmtResponse, error) {
8382
}
8483

8584
// Compile runs code in goplayground and returns response
86-
func Compile(ctx context.Context, src []byte) (*CompileResponse, error) {
85+
func (c *Client) Compile(ctx context.Context, src []byte) (*CompileResponse, error) {
8786
form := url.Values{}
8887
form.Add("body", string(src))
8988
form.Add("version", "2")
9089

91-
resp, err := postForm(ctx, "compile", form)
90+
resp, err := c.postForm(ctx, "compile", form)
9291
if err != nil {
9392
return nil, err
9493
}
9594

9695
dest := &CompileResponse{}
9796
if err := json.Unmarshal(resp, dest); err != nil {
9897
// return response text as errors
99-
return nil, fmt.Errorf("error from %q: %s", goPlayURL, string(resp))
98+
return nil, fmt.Errorf("error from %q: %s", c.baseUrl, string(resp))
10099
}
101100

102101
return dest, err

0 commit comments

Comments
 (0)