2019-06-05 15:08:55 +00:00
|
|
|
package tunnelhostnamemapper
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2019-06-20 16:18:59 +00:00
|
|
|
"net/url"
|
2019-08-28 15:41:39 +00:00
|
|
|
"reflect"
|
2019-06-05 15:08:55 +00:00
|
|
|
"sync"
|
|
|
|
"testing"
|
2019-08-28 15:41:39 +00:00
|
|
|
"time"
|
2019-06-05 15:08:55 +00:00
|
|
|
|
|
|
|
"github.com/cloudflare/cloudflared/h2mux"
|
|
|
|
"github.com/cloudflare/cloudflared/originservice"
|
2019-08-28 15:41:39 +00:00
|
|
|
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
2019-06-05 15:08:55 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
routines = 1000
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestTunnelHostnameMapperConcurrentAccess(t *testing.T) {
|
|
|
|
thm := NewTunnelHostnameMapper()
|
|
|
|
|
|
|
|
concurrentOps(t, func(i int) {
|
|
|
|
// om is empty
|
|
|
|
os, ok := thm.Get(tunnelHostname(i))
|
|
|
|
assert.False(t, ok)
|
|
|
|
assert.Nil(t, os)
|
|
|
|
})
|
|
|
|
|
2019-06-20 16:18:59 +00:00
|
|
|
firstURL, err := url.Parse("https://127.0.0.1:8080")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
httpOS := originservice.NewHTTPService(http.DefaultTransport, firstURL, false)
|
2019-06-05 15:08:55 +00:00
|
|
|
concurrentOps(t, func(i int) {
|
|
|
|
thm.Add(tunnelHostname(i), httpOS)
|
|
|
|
})
|
|
|
|
|
|
|
|
concurrentOps(t, func(i int) {
|
|
|
|
os, ok := thm.Get(tunnelHostname(i))
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, httpOS, os)
|
|
|
|
})
|
|
|
|
|
2019-06-20 16:18:59 +00:00
|
|
|
secondURL, err := url.Parse("https://127.0.0.1:8080")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
secondHTTPOS := originservice.NewHTTPService(http.DefaultTransport, secondURL, true)
|
2019-06-05 15:08:55 +00:00
|
|
|
concurrentOps(t, func(i int) {
|
|
|
|
// Add should httpOS with secondHTTPOS
|
|
|
|
thm.Add(tunnelHostname(i), secondHTTPOS)
|
|
|
|
})
|
|
|
|
|
|
|
|
concurrentOps(t, func(i int) {
|
|
|
|
os, ok := thm.Get(tunnelHostname(i))
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, secondHTTPOS, os)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func concurrentOps(t *testing.T, f func(i int)) {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(routines)
|
|
|
|
for i := 0; i < routines; i++ {
|
|
|
|
go func(i int) {
|
|
|
|
f(i)
|
|
|
|
wg.Done()
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
func tunnelHostname(i int) h2mux.TunnelHostname {
|
|
|
|
return h2mux.TunnelHostname(fmt.Sprintf("%d.cftunnel.com", i))
|
|
|
|
}
|
2019-08-28 15:41:39 +00:00
|
|
|
|
|
|
|
func Test_toSet(t *testing.T) {
|
|
|
|
|
|
|
|
type args struct {
|
|
|
|
configs []*pogs.ReverseProxyConfig
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
|
|
|
want map[h2mux.TunnelHostname]*pogs.ReverseProxyConfig
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "empty slice should yield empty map",
|
|
|
|
args: args{},
|
|
|
|
want: map[h2mux.TunnelHostname]*pogs.ReverseProxyConfig{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "multiple elements",
|
|
|
|
args: args{[]*pogs.ReverseProxyConfig{sampleConfig1(), sampleConfig2()}},
|
|
|
|
want: map[h2mux.TunnelHostname]*pogs.ReverseProxyConfig{
|
|
|
|
"mock.example.com": sampleConfig1(),
|
|
|
|
"mock2.example.com": sampleConfig2(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
if got := toSet(tt.args.configs); !reflect.DeepEqual(got, tt.want) {
|
|
|
|
t.Errorf("toSet() = %v, want %v", got, tt.want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTunnelHostnameMapper_ToAdd(t *testing.T) {
|
|
|
|
type fields struct {
|
|
|
|
tunnelHostnameToOrigin map[h2mux.TunnelHostname]originservice.OriginService
|
|
|
|
}
|
|
|
|
type args struct {
|
|
|
|
newConfigs []*pogs.ReverseProxyConfig
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
args args
|
|
|
|
wantToAdd []*pogs.ReverseProxyConfig
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Mapper={}, NewConfig={}, toAdd={}",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Mapper={}, NewConfig={x}, toAdd={x}",
|
|
|
|
args: args{newConfigs: []*pogs.ReverseProxyConfig{sampleConfig1()}},
|
|
|
|
wantToAdd: []*pogs.ReverseProxyConfig{sampleConfig1()},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Mapper={x}, NewConfig={x,y}, toAdd={y}",
|
|
|
|
args: args{newConfigs: []*pogs.ReverseProxyConfig{sampleConfig2()}},
|
|
|
|
wantToAdd: []*pogs.ReverseProxyConfig{sampleConfig2()},
|
|
|
|
fields: fields{tunnelHostnameToOrigin: map[h2mux.TunnelHostname]originservice.OriginService{
|
|
|
|
h2mux.TunnelHostname(sampleConfig1().TunnelHostname): &originservice.HelloWorldService{},
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
om := &TunnelHostnameMapper{
|
|
|
|
tunnelHostnameToOrigin: tt.fields.tunnelHostnameToOrigin,
|
|
|
|
}
|
|
|
|
if gotToAdd := om.ToAdd(tt.args.newConfigs); !reflect.DeepEqual(gotToAdd, tt.wantToAdd) {
|
|
|
|
t.Errorf("TunnelHostnameMapper.ToAdd() = %v, want %v", gotToAdd, tt.wantToAdd)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTunnelHostnameMapper_ToRemove(t *testing.T) {
|
|
|
|
type fields struct {
|
|
|
|
tunnelHostnameToOrigin map[h2mux.TunnelHostname]originservice.OriginService
|
|
|
|
}
|
|
|
|
type args struct {
|
|
|
|
newConfigs []*pogs.ReverseProxyConfig
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
args args
|
|
|
|
wantToRemove []h2mux.TunnelHostname
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Mapper={}, NewConfig={}, toRemove={}",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Mapper={x}, NewConfig={}, toRemove={x}",
|
|
|
|
wantToRemove: []h2mux.TunnelHostname{sampleConfig1().TunnelHostname},
|
|
|
|
fields: fields{tunnelHostnameToOrigin: map[h2mux.TunnelHostname]originservice.OriginService{
|
|
|
|
h2mux.TunnelHostname(sampleConfig1().TunnelHostname): &originservice.HelloWorldService{},
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Mapper={x}, NewConfig={x}, toRemove={}",
|
|
|
|
args: args{newConfigs: []*pogs.ReverseProxyConfig{sampleConfig1()}},
|
|
|
|
fields: fields{tunnelHostnameToOrigin: map[h2mux.TunnelHostname]originservice.OriginService{
|
|
|
|
h2mux.TunnelHostname(sampleConfig1().TunnelHostname): &originservice.HelloWorldService{},
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
om := &TunnelHostnameMapper{
|
|
|
|
tunnelHostnameToOrigin: tt.fields.tunnelHostnameToOrigin,
|
|
|
|
}
|
|
|
|
if gotToRemove := om.ToRemove(tt.args.newConfigs); !reflect.DeepEqual(gotToRemove, tt.wantToRemove) {
|
|
|
|
t.Errorf("TunnelHostnameMapper.ToRemove() = %v, want %v", gotToRemove, tt.wantToRemove)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func sampleConfig1() *pogs.ReverseProxyConfig {
|
|
|
|
return &pogs.ReverseProxyConfig{
|
|
|
|
TunnelHostname: "mock.example.com",
|
|
|
|
OriginConfigJSONHandler: &pogs.OriginConfigJSONHandler{OriginConfig: &pogs.HelloWorldOriginConfig{}},
|
|
|
|
Retries: 18,
|
|
|
|
ConnectionTimeout: 5 * time.Second,
|
|
|
|
CompressionQuality: 3,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func sampleConfig2() *pogs.ReverseProxyConfig {
|
|
|
|
return &pogs.ReverseProxyConfig{
|
|
|
|
TunnelHostname: "mock2.example.com",
|
|
|
|
OriginConfigJSONHandler: &pogs.OriginConfigJSONHandler{OriginConfig: &pogs.HelloWorldOriginConfig{}},
|
|
|
|
Retries: 18,
|
|
|
|
ConnectionTimeout: 5 * time.Second,
|
|
|
|
CompressionQuality: 3,
|
|
|
|
}
|
|
|
|
}
|