feat: external ip provider plain
This commit is contained in:
56
pkg/externalIpProvider/plain/plain.go
Normal file
56
pkg/externalIpProvider/plain/plain.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package externalIpProvider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
externalIpProvider "realdnydns/pkg/externalIpProvider"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExternalIpProviderImplPlain struct {
|
||||||
|
IPProviderURL string
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlainExternalIpProviderConfig struct {
|
||||||
|
Url string `yaml:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config PlainExternalIpProviderConfig) (externalIpProvider.ExternalIpProvider, error) {
|
||||||
|
if config.Url == "" {
|
||||||
|
return nil, errors.New("url is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ExternalIpProviderImplPlain{
|
||||||
|
config.Url,
|
||||||
|
&http.Client{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ExternalIpProviderImplPlain) GetExternalIp() (net.IP, error) {
|
||||||
|
parsedUrl, err := url.Parse(p.IPProviderURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := p.HTTPClient.Get(parsedUrl.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return nil, errors.New("unexpected status code")
|
||||||
|
}
|
||||||
|
|
||||||
|
responseBody := make([]byte, res.ContentLength)
|
||||||
|
res.Body.Read(responseBody)
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
parsedIp := net.ParseIP(string(responseBody))
|
||||||
|
if parsedIp == nil {
|
||||||
|
return nil, errors.New("unable to parse ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedIp, nil
|
||||||
|
}
|
||||||
150
pkg/externalIpProvider/plain/plain_test.go
Normal file
150
pkg/externalIpProvider/plain/plain_test.go
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
package externalIpProvider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
t.Run("returns external ip provider", testNew())
|
||||||
|
t.Run("returns error when url is empty", testNewEmptyUrl())
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNew() func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
provider, err := New(PlainExternalIpProviderConfig{
|
||||||
|
Url: "http://localhost",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPlain() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider == nil {
|
||||||
|
t.Fatalf("NewPlain() returned nil provider")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNewEmptyUrl() func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
_, err := New(PlainExternalIpProviderConfig{})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("NewPlain() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetExternal(t *testing.T) {
|
||||||
|
t.Run("returns external ip", testGetExternalIp())
|
||||||
|
t.Run("returns error when unable to parse ip", testGetExternalIpUnparsableIp())
|
||||||
|
t.Run("returns error when unexpected status code", testGetExternalIpUnexpectedStatusCode())
|
||||||
|
t.Run("returns error when unable to parse url", testGetExternalIpUnableToParseUrl())
|
||||||
|
t.Run("returns error when unable to get", testGetExternalIpUnableToGet())
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetExternalIp() func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
mockServer := httptest.NewServer(http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("127.0.0.1"))
|
||||||
|
},
|
||||||
|
))
|
||||||
|
defer mockServer.Close()
|
||||||
|
|
||||||
|
provider, err := New(PlainExternalIpProviderConfig{
|
||||||
|
Url: mockServer.URL,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPlain() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ip, err := provider.GetExternalIp()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetExternalIp() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip.String() != "127.0.0.1" {
|
||||||
|
t.Fatalf("GetExternalIp() returned unexpected ip: %v instead of 127.0.0.1", ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetExternalIpUnparsableIp() func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
mockServer := httptest.NewServer(http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("not an ip"))
|
||||||
|
},
|
||||||
|
))
|
||||||
|
defer mockServer.Close()
|
||||||
|
|
||||||
|
provider, err := New(PlainExternalIpProviderConfig{
|
||||||
|
Url: mockServer.URL,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPlain() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = provider.GetExternalIp()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("GetExternalIp() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetExternalIpUnexpectedStatusCode() func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
mockServer := httptest.NewServer(http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
},
|
||||||
|
))
|
||||||
|
defer mockServer.Close()
|
||||||
|
|
||||||
|
provider, err := New(PlainExternalIpProviderConfig{
|
||||||
|
Url: mockServer.URL,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPlain() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = provider.GetExternalIp()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("GetExternalIp() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetExternalIpUnableToParseUrl() func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
provider, err := New(PlainExternalIpProviderConfig{
|
||||||
|
Url: "not a url !'§%&",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPlain() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = provider.GetExternalIp()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("GetExternalIp() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetExternalIpUnableToGet() func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
// force error by using a non-responding url, beware of side effects
|
||||||
|
provider, err := New(PlainExternalIpProviderConfig{
|
||||||
|
Url: "http://localhost:1234",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPlain() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = provider.GetExternalIp()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("GetExternalIp() returned unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user