Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions flypg/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"net/url"
"time"

"github.com/PuerkitoBio/rehttp"
Expand All @@ -16,14 +16,16 @@ import (
"github.com/superfly/flyctl/terminal"
)

const flypgPort = "5500"

type Client struct {
httpClient *http.Client
BaseURL string
}

// NewFromInstance creates a new Client that targets a specific instance(address)
func NewFromInstance(address string, dialer agent.Dialer) *Client {
url := fmt.Sprintf("http://%s:5500", address)
url := formatPGBaseURL(address)
terminal.Debugf("flypg will connect to: %s\n", url)

return &Client{
Expand All @@ -32,6 +34,15 @@ func NewFromInstance(address string, dialer agent.Dialer) *Client {
}
}

func formatPGBaseURL(address string) string {
hostport := net.JoinHostPort(address, flypgPort)

return (&url.URL{
Scheme: "http",
Host: hostport,
}).String()
}

func newHttpClient(dialer agent.Dialer) *http.Client {
transport := &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
Expand Down
79 changes: 79 additions & 0 deletions flypg/http_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package flypg

// Run: go test ./flypg (repo root) or cd flypg && go test .
//
// Do not run go test flypg/http_test.go — that compiles only this file, so
// NewFromInstance and flypgPort from http.go are undefined.

import (
"net/url"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestFormatPGBaseURL_IPv4(t *testing.T) {
client := NewFromInstance("192.168.1.1", nil)
assert.Equal(t, "http://192.168.1.1:5500", client.BaseURL)
assertParsableFlyPGURL(t, client.BaseURL, "192.168.1.1", "5500")
}

func TestFormatPGBaseURL_IPv6(t *testing.T) {
client := NewFromInstance("fdaa:2:be18:a7b:620:7ff8:9a20:2", nil)
assert.Equal(t, "http://[fdaa:2:be18:a7b:620:7ff8:9a20:2]:5500", client.BaseURL)
assertParsableFlyPGURL(t, client.BaseURL, "fdaa:2:be18:a7b:620:7ff8:9a20:2", "5500")
}

func TestFormatPGBaseURL_Hostname(t *testing.T) {
client := NewFromInstance("myapp.internal", nil)
assert.Equal(t, "http://myapp.internal:5500", client.BaseURL)
assertParsableFlyPGURL(t, client.BaseURL, "myapp.internal", "5500")
}

func TestFormatPGBaseURL_Table(t *testing.T) {
port := flypgPort
tests := []struct {
name string
address string
wantBaseURL string
wantHostname string
}{
{
name: "ipv4",
address: "10.0.0.1",
wantBaseURL: "http://10.0.0.1:5500",
wantHostname: "10.0.0.1",
},
{
name: "ipv6_compressed",
address: "2001:db8::1",
wantBaseURL: "http://[2001:db8::1]:5500",
wantHostname: "2001:db8::1",
},
{
name: "hostname",
address: "pg.example.internal",
wantBaseURL: "http://pg.example.internal:5500",
wantHostname: "pg.example.internal",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NewFromInstance(tt.address, nil).BaseURL
assert.Equal(t, tt.wantBaseURL, got)
assertParsableFlyPGURL(t, got, tt.wantHostname, port)
})
}
}

// assertParsableFlyPGURL checks the base URL parses and Hostname/Port match expectations
// (same rules as net/http for dialing).
func assertParsableFlyPGURL(t *testing.T, raw, wantHostname, wantPort string) {
t.Helper()
u, err := url.Parse(raw)
require.NoError(t, err)
assert.Equal(t, "http", u.Scheme)
assert.Equal(t, wantHostname, u.Hostname())
assert.Equal(t, wantPort, u.Port())
}
Loading