Skip to content
This repository was archived by the owner on Mar 6, 2022. It is now read-only.

Commit bc8990d

Browse files
committed
start refactoring a bit. create a separate package for getting public ip with tests.
1 parent 2eb5d3e commit bc8990d

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ require (
1515
github.com/onsi/ginkgo v1.12.0 // indirect
1616
github.com/onsi/gomega v1.9.0 // indirect
1717
github.com/pkg/errors v0.9.1
18+
github.com/sirupsen/logrus v1.2.0
1819
github.com/spf13/cobra v1.0.0
1920
github.com/spf13/viper v1.6.3
21+
github.com/stretchr/testify v1.5.1
2022
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904
2123
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
24+
golang.org/x/text v0.3.2 // indirect
2225
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
2326
gopkg.in/ini.v1 v1.55.0 // indirect
2427
)

go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE
128128
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
129129
github.com/klauspost/reedsolomon v1.7.0 h1:pLFmRKGko2ZieiTGyo9DahLCIuljyxm+Zzhz/fYEonE=
130130
github.com/klauspost/reedsolomon v1.7.0/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
131+
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
131132
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
132133
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
133134
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -195,6 +196,7 @@ github.com/shadowsocks/go-shadowsocks2 v0.1.0/go.mod h1:/0aFGbhK8mtOX4J/6kTJsPLZ
195196
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba h1:tJgNXb3S+RkB4kNPi6N5OmEWe3m+Y3Qs6LUMiNDAONM=
196197
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba/go.mod h1:mttDPaeLm87u74HMrP+n2tugXvIKWcwff/cqSX0lehY=
197198
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
199+
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
198200
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
199201
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
200202
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -292,8 +294,11 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwg
292294
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
293295
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
294296
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
297+
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
298+
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
295299
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
296300
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
301+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
297302
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
298303
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
299304
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package awspublicip
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"github.com/dan-v/awslambdaproxy/pkg/server/publicip"
7+
"io/ioutil"
8+
"net"
9+
"net/http"
10+
"time"
11+
)
12+
13+
const (
14+
DefaultHTTPTimeout = time.Second * 10
15+
AWSProviderURL = "http://checkip.amazonaws.com/"
16+
)
17+
18+
type PublicIPClient struct {
19+
providerURL string
20+
httpClient *http.Client
21+
}
22+
23+
func New() *PublicIPClient {
24+
return &PublicIPClient{
25+
providerURL: AWSProviderURL,
26+
httpClient: &http.Client{
27+
Timeout: DefaultHTTPTimeout,
28+
},
29+
}
30+
}
31+
32+
func (p *PublicIPClient) GetIP() (string, error) {
33+
resp, err := p.httpClient.Get(p.providerURL)
34+
if err != nil {
35+
return "", fmt.Errorf("http request to get ip address from %v failed: %w", p.providerURL, err)
36+
}
37+
defer resp.Body.Close()
38+
39+
buf, err := ioutil.ReadAll(resp.Body)
40+
if err != nil {
41+
return "", fmt.Errorf("reading response body from %v failed: %w", p.providerURL, err)
42+
}
43+
44+
ip := string(bytes.TrimSpace(buf))
45+
if net.ParseIP(ip) == nil {
46+
return "", fmt.Errorf("unable to parse ip %v: %w",
47+
publicip.ErrInvalidIPAddress, publicip.ErrInvalidIPAddress)
48+
}
49+
return ip, nil
50+
}
51+
52+
func (p *PublicIPClient) ProviderURL() string {
53+
return p.providerURL
54+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package awspublicip
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"github.com/dan-v/awslambdaproxy/pkg/server/publicip"
8+
"github.com/stretchr/testify/assert"
9+
"net/http"
10+
"net/http/httptest"
11+
"testing"
12+
"time"
13+
)
14+
15+
func TestPublicIPClient_GetIP(t *testing.T) {
16+
tests := []struct {
17+
name string
18+
handler func(w http.ResponseWriter, r *http.Request)
19+
expected string
20+
error error
21+
}{
22+
{
23+
name: "valid ip address returns as expected",
24+
handler: func(w http.ResponseWriter, r *http.Request) {
25+
fmt.Fprintln(w, "1.1.1.1")
26+
},
27+
expected: "1.1.1.1",
28+
error: nil,
29+
},
30+
{
31+
name: "valid ip address with padding returns trimmed",
32+
handler: func(w http.ResponseWriter, r *http.Request) {
33+
fmt.Fprintln(w, " 1.1.1.1 ")
34+
},
35+
expected: "1.1.1.1",
36+
error: nil,
37+
},
38+
{
39+
name: "invalid ip results in error",
40+
handler: func(w http.ResponseWriter, r *http.Request) {
41+
fmt.Fprintln(w, "invalid")
42+
},
43+
expected: "",
44+
error: publicip.ErrInvalidIPAddress,
45+
},
46+
{
47+
name: "empty response results in error",
48+
handler: func(w http.ResponseWriter, r *http.Request) {
49+
fmt.Fprintln(w, "")
50+
},
51+
expected: "",
52+
error: publicip.ErrInvalidIPAddress,
53+
},
54+
{
55+
name: "server timeout causes deadline exceeded error",
56+
handler: func(w http.ResponseWriter, r *http.Request) {
57+
time.Sleep(20 * time.Millisecond)
58+
},
59+
expected: "",
60+
error: context.DeadlineExceeded,
61+
},
62+
{
63+
name: "invalid content length causes body read error",
64+
handler: func(w http.ResponseWriter, r *http.Request) {
65+
w.Header().Set("Content-Length", "1")
66+
},
67+
expected: "",
68+
error: errors.New("unexpected EOF"),
69+
},
70+
}
71+
for _, tt := range tests {
72+
t.Run(tt.name, func(t *testing.T) {
73+
ts := httptest.NewServer(http.HandlerFunc(tt.handler))
74+
defer ts.Close()
75+
76+
p := New()
77+
p.providerURL = ts.URL
78+
p.httpClient.Timeout = time.Millisecond * 10
79+
ip, err := p.GetIP()
80+
if tt.error != nil {
81+
assert.Contains(t, errors.Unwrap(err).Error(), tt.error.Error())
82+
} else {
83+
assert.NoError(t, err)
84+
}
85+
assert.Equal(t, tt.expected, ip)
86+
})
87+
}
88+
}
89+
90+
func TestPublicIPClient_ProviderURL(t *testing.T) {
91+
p := New()
92+
assert.Equal(t, AWSProviderURL, p.ProviderURL())
93+
}

0 commit comments

Comments
 (0)