Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Issue36 - Eureka integration #46

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
44 changes: 44 additions & 0 deletions discovery/eureka.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package discovery

import (
"errors"
"net/http"
)

//TODO: This should become a discovery interface. And Eureka just the first implementation
type EurekaClient struct {
eurekaUrl string
}

var errNoEurekaConnection = errors.New("Unable to reach Eureka server")
var errEurekaUnexpectedHttpResponseCode = errors.New("Eureka returned a non 200 http response code")

func NewEurekaClient(eurekaUrl string) (ec EurekaClient, err error) {
ec.eurekaUrl = eurekaUrl
resp, err := http.Get(eurekaUrl)
if err != nil {
return ec, errNoEurekaConnection
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return ec,errEurekaUnexpectedHttpResponseCode
}
return ec, nil
}

var errNoIpsFound = errors.New("No IPs associated to the requested App name")
dcaba marked this conversation as resolved.
Show resolved Hide resolved

func (ec EurekaClient) GetIPs(appName string) ([]string, error) {
eurekaAppUrl := ec.eurekaUrl + "/v2/apps/" + appName
resp, err := http.Get(eurekaAppUrl)
if err != nil {
return []string{}, errNoEurekaConnection
}
defer resp.Body.Close()
if resp.StatusCode == 404 {
return []string{},errNoIpsFound
} else if resp.StatusCode != 200 {
return []string{},errEurekaUnexpectedHttpResponseCode
}
return nil, nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guessed you will return the string array with the IPs here instead of nil...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIP, WIP, WIP... ;)

}
119 changes: 119 additions & 0 deletions discovery/eureka_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package discovery

import (
"gopkg.in/ory-am/dockertest.v3"
dc "github.com/fsouza/go-dockerclient"
dcaba marked this conversation as resolved.
Show resolved Hide resolved
"github.com/jaume-pinyol/fargo"
"log"
"os"
"testing"
"strconv"
"github.com/op/go-logging"
)

var eurekaTestPort int = 8080
var eurekaTestUrl string = "http://127.0.0.1:" + strconv.Itoa(eurekaTestPort) + "/eureka"

func TestMain(m *testing.M) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean with TestMain?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

// uses a sensible default on windows (tcp/http) and linux/osx (socket)
pool, err := dockertest.NewPool("")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you using "dockertest" instead of "dockertest.v3"? has the dot no sense?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if err != nil {
log.Fatalf("Could not connect to docker: %s", err)
}
// pulls an image, creates a container based on it and runs it
resource, err := pool.RunWithOptions(&dockertest.RunOptions{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this resource is the Eureka container running, isn't it? a more descriptive name could be great 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 . I was following the examples to strictly 😸

Repository: "netflixoss/eureka",
Tag: "1.3.1",
PortBindings: map[dc.Port][]dc.PortBinding{
dc.Port(strconv.Itoa(eurekaTestPort) + "/tcp"): {{HostIP: "", HostPort: strconv.Itoa(eurekaTestPort)}},
},
})
if err != nil {
log.Fatalf("Could not start resource: %s", err)
}

// exponential backoff-retry, because the application in the container might not be ready to accept connections yet
if err := pool.Retry(func() error {
_, err := NewEurekaClient(eurekaTestUrl)
return err
}); err != nil {
log.Fatalf("Could not connect to the docker resource: %s", err)
}

code := m.Run()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is Run from Testing doing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the previous reference about what TestMain actually does


// You can't defer this because os.Exit doesn't care for defer
if err := pool.Purge(resource); err != nil {
log.Fatalf("Could not purge resource: %s", err)
}

os.Exit(code)
}

func TestEurekaClientNoEureka(t *testing.T) {
_, err := NewEurekaClient("http://localhost:9999/thisshouldntwork")
if err != errNoEurekaConnection {
t.Fatal("We shouldnt reach eureka if Eureka hostname/port is completely wrong")
}
}

func TestEurekaClientWrongEurekaContext(t *testing.T) {
_, err := NewEurekaClient(eurekaTestUrl + "badsuffix")
if err != errEurekaUnexpectedHttpResponseCode {
t.Fatal("Eureka should be reachable but, when asking a wrong URL, it should return a non 200 response code")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmmm, reaching this point I suspect that the m.Run() in TestMain does is to start the Eureka server to run the other tests after that. am I right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nops. TestMain does run Eureka (and kills it when tests finish), and in the middle, with m.Run , actually runs all your tests there. Its a mechanism allowing you to wrap all your tests and do things at the beginning and end (init only covers the first part, so that's why golang released this in... 1.5?)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 seen in your comment above

}
}

func TestEurekaClientUnknownApp(t *testing.T) {
appName := "unknown"
eurekaClient, err := NewEurekaClient(eurekaTestUrl)
if err != nil {
t.Fatal("We cannot connect to the specified eureka server:", err)
}
t.Log("Connection to Eureka established")
_, err = eurekaClient.GetIPs(appName)
if err != errNoIpsFound {
t.Fatal("Eureka did return something different from an No-IPs-error associated to the unknown App")
}
}

func TestEurekaClientValidApp(t *testing.T) {
appName := "testApp"
ipAddr := "192.0.2.1"
port := 10080
registerDummyAppInTestEureka(appName, ipAddr, port)
eurekaClient, err := NewEurekaClient(eurekaTestUrl)
if err != nil {
t.Fatal("We cannot connect to the specified eureka server:", err)
}
t.Log("Connection to Eureka established")
ipsFromEureka, err := eurekaClient.GetIPs(appName)
if err != nil {
t.Fatal("Eureka returned an error when requesting the IPs:", err)
}
if len(ipsFromEureka) != 1 || ipsFromEureka[0] != ipAddr {
t.Fatal("Eureka returned a set of IPs we did not expect for our service:", ipsFromEureka )
}

}
func registerDummyAppInTestEureka(appName string, ipAddr string, port int) {
logging.SetLevel(logging.ERROR, "fargo")
fargoclient := fargo.NewConn(eurekaTestUrl + "/v2")
appInstance := &fargo.Instance{
HostName: "dummyhost",
Port: port,
SecurePort: port,
App: appName,
IPAddr: ipAddr,
VipAddress: ipAddr,
SecureVipAddress: ipAddr,
DataCenterInfo: fargo.DataCenterInfo{Name: fargo.MyOwn},
Status: fargo.UP,
Overriddenstatus: fargo.UNKNOWN,
HealthCheckUrl: "http://" + ipAddr + ":" + "8080" + "/healthcheck",
StatusPageUrl: "http://" + ipAddr + ":" + "8080" + "/healthcheck",
HomePageUrl: "http://" + ipAddr + ":" + "8080" + "/",
AsgName: "dummyAsg",
}
fargoclient.RegisterInstance(appInstance)
}