Skip to content
This repository has been archived by the owner on May 2, 2018. It is now read-only.

Commit

Permalink
Fixed '/__id' and '/people' endpoints.
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosroman committed Nov 23, 2016
1 parent 08723db commit bdd9076
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 23 deletions.
24 changes: 22 additions & 2 deletions people/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/Financial-Times/service-status-go/gtg"
log "github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
"io"
"net/http"
)

Expand All @@ -20,15 +21,34 @@ func NewPeopleHandler(service PeopleService) PeopleHandler {
}

func (h *PeopleHandler) GetPeople(writer http.ResponseWriter, req *http.Request) {
writer.Header().Add("Content-Type", "application/json")
if !h.service.isInitialised() {
writeStatusServiceUnavailable(writer)
return
}
obj, found := h.service.getPeople()
writeJSONResponse(obj, found, writer)

if c, _ := h.service.getCount(); c == 0 {
writeJSONMessageWithStatus(writer, "People not found", http.StatusNotFound)
return
}

pv, err := h.service.getPeople()

if err != nil {
writeJSONMessageWithStatus(writer, err.Error(), http.StatusInternalServerError)
return
}

log.Info("Creating buffer...")
//buf := make([]byte, 0, 4*1024)
defer pv.Close()
writer.WriteHeader(http.StatusOK)
log.Info("Status written")
io.Copy(writer, &pv)
}

func (h *PeopleHandler) GetCount(writer http.ResponseWriter, req *http.Request) {
writer.Header().Add("Content-Type", "application/json")
if !h.service.isInitialised() {
writeStatusServiceUnavailable(writer)
return
Expand Down
50 changes: 44 additions & 6 deletions people/handlers_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package people

import (
"encoding/json"
"errors"
"fmt"
"github.com/Financial-Times/go-fthealth/v1a"
Expand All @@ -9,6 +10,8 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"regexp"
Expand All @@ -19,7 +22,8 @@ import (

const (
testUUID = "bba39990-c78d-3629-ae83-808c333c6dbc"
getPeopleResponse = "[{\"apiUrl\":\"http://localhost:8080/transformers/people/bba39990-c78d-3629-ae83-808c333c6dbc\"}]\n"
getPeopleResponse = "[{\"apiUrl\":\"http://localhost:8080/transformers/people/bba39990-c78d-3629-ae83-808c333c6dbc\"}]"
getPeopleByUUIDResponse = "[{\"UUID\":\"bba39990-c78d-3629-ae83-808c333c6dbc\"}]"
getPersonByUUIDResponse = "{\"uuid\":\"bba39990-c78d-3629-ae83-808c333c6dbc\",\"prefLabel\":\"European Union\",\"type\":\"Organisation\",\"alternativeIdentifiers\":{\"TME\":[\"MTE3-U3ViamVjdHM=\"],\"uuids\":[\"bba39990-c78d-3629-ae83-808c333c6dbc\"]}}\n"
)

Expand Down Expand Up @@ -65,6 +69,7 @@ func TestHandlers(t *testing.T) {
&dummyService{
found: true,
initialised: true,
count: 1,
people: []person{{UUID: testUUID}}},
http.StatusOK,
"application/json",
Expand Down Expand Up @@ -103,12 +108,12 @@ func TestHandlers(t *testing.T) {
{"Not found - get people",
newRequest("GET", "/transformers/people"),
&dummyService{
found: false,
initialised: true,
count: 0,
people: []person{}},
http.StatusNotFound,
"application/json",
"{\"message\": \"Person not found\"}\n"},
"{\"message\": \"People not found\"}\n"},
{"Service unavailable - get people",
newRequest("GET", "/transformers/people"),
&dummyService{
Expand Down Expand Up @@ -215,14 +220,16 @@ func TestHandlers(t *testing.T) {
router(test.dummyService).ServeHTTP(rec, test.req)
assert.Equal(t, test.statusCode, rec.Code, fmt.Sprintf("%s: Wrong response code, was %d, should be %d", test.name, rec.Code, test.statusCode))

b, err := ioutil.ReadAll(rec.Body)
assert.NoError(t, err)
body := string(b)
if strings.HasPrefix(test.body, "regex=") {
regex := strings.TrimPrefix(test.body, "regex=")
body := rec.Body.String()
matched, err := regexp.MatchString(regex, body)
assert.NoError(t, err)
assert.True(t, matched, fmt.Sprintf("Could not match regex:\n %s \nin body:\n %s", regex, body))
} else {
assert.Equal(t, test.body, rec.Body.String(), fmt.Sprintf("%s: Wrong body", test.name))
assert.Equal(t, test.body, body, fmt.Sprintf("%s: Wrong body", test.name))
}
}
}
Expand Down Expand Up @@ -263,14 +270,44 @@ type dummyService struct {
wg *sync.WaitGroup
}

func (s *dummyService) getPeople() ([]personLink, bool) {
func (s *dummyService) getPeopleOld() ([]personLink, bool) {
var links []personLink
for _, sub := range s.people {
links = append(links, personLink{APIURL: "http://localhost:8080/transformers/people/" + sub.UUID})
}
return links, s.found
}

func (s *dummyService) getPeople() (io.PipeReader, error) {
pv, pw := io.Pipe()
go func() {
var links []personLink
for _, sub := range s.people {
links = append(links, personLink{APIURL: "http://localhost:8080/transformers/people/" + sub.UUID})
}
b, _ := json.Marshal(links)
log.Infof("Writting bytes... %v", string(b))
pw.Write(b)
pw.Close()
}()
return *pv, nil
}

func (s *dummyService) getPeopleByUUID() (io.PipeReader, error) {
pv, pw := io.Pipe()
go func() {
var links []personUUID
for _, sub := range s.people {
links = append(links, personUUID{UUID: sub.UUID})
}
b, _ := json.Marshal(links)
log.Infof("Writting bytes... %v", string(b))
pw.Write(b)
pw.Close()
}()
return *pv, nil
}

func (s *dummyService) getCount() (int, error) {
return s.count, s.err
}
Expand Down Expand Up @@ -303,6 +340,7 @@ func router(s PeopleService) *mux.Router {
m.HandleFunc("/transformers/people", h.GetPeople).Methods("GET")
m.HandleFunc("/transformers/people/__count", h.GetCount).Methods("GET")
m.HandleFunc("/transformers/people/__reload", h.Reload).Methods("POST")
m.HandleFunc("/transformers/people/__id", h.GetPersonByUUID).Methods("GET")
m.HandleFunc("/transformers/people/{uuid}", h.GetPersonByUUID).Methods("GET")
m.HandleFunc("/__health", v1a.Handler("V1 People Transformer Healthchecks", "Checks for the health of the service", h.HealthCheck()))
g2gHandler := status.NewGoodToGoHandler(gtg.StatusChecker(h.G2GCheck))
Expand Down
4 changes: 4 additions & 0 deletions people/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ type alternativeIdentifiers struct {
type personLink struct {
APIURL string `json:"apiUrl"`
}

type personUUID struct {
UUID string `json:"ID"`
}
76 changes: 64 additions & 12 deletions people/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/Financial-Times/tme-reader/tmereader"
log "github.com/Sirupsen/logrus"
"github.com/boltdb/bolt"
"github.com/pborman/uuid"
"io"
"sync"
"time"
)
Expand All @@ -19,7 +19,8 @@ const (
)

type PeopleService interface {
getPeople() ([]personLink, bool)
getPeople() (io.PipeReader, error)
getPeopleByUUID() (io.PipeReader, error)
getPersonByUUID(uuid string) (person, bool, error)
getCount() (int, error)
isInitialised() bool
Expand All @@ -32,7 +33,6 @@ type peopleServiceImpl struct {
sync.RWMutex
repository tmereader.Repository
baseURL string
personLinks []personLink
taxonomyName string
maxTmeRecords int
initialised bool
Expand Down Expand Up @@ -107,13 +107,68 @@ func (s *peopleServiceImpl) getCount() (int, error) {
return count, err
}

func (s *peopleServiceImpl) getPeople() ([]personLink, bool) {
func (s *peopleServiceImpl) getPeople() (io.PipeReader, error) {
s.RLock()
defer s.RUnlock()
if len(s.personLinks) > 0 {
return s.personLinks, true
}
return s.personLinks, false
pv, pw := io.Pipe()
go func() {
defer s.RUnlock()
defer pw.Close()
io.WriteString(pw, "[")
s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(cacheBucket))
c := b.Cursor()
encoder := json.NewEncoder(pw)
var k []byte
k, _ = c.First()
for {
if k == nil {
break
}
pl := personLink{APIURL: s.baseURL + "/" + string(k[:])}
if err := encoder.Encode(pl); err != nil {
return err
}
if k, _ = c.Next(); k != nil {
io.WriteString(pw, ",")
}
}
return nil
})
io.WriteString(pw, "]")
}()
return *pv, nil
}

func (s *peopleServiceImpl) getPeopleByUUID() (io.PipeReader, error) {
s.RLock()
pv, pw := io.Pipe()
go func() {
defer s.RUnlock()
defer pw.Close()
io.WriteString(pw, "[")
s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(cacheBucket))
c := b.Cursor()
encoder := json.NewEncoder(pw)
var k []byte
k, _ = c.First()
for {
if k == nil {
break
}
pl := personUUID{UUID: string(k[:])}
if err := encoder.Encode(pl); err != nil {
return err
}
if k, _ = c.Next(); k != nil {
io.WriteString(pw, ",")
}
}
return nil
})
io.WriteString(pw, "]")
}()
return *pv, nil
}

func (s *peopleServiceImpl) getPersonByUUID(uuid string) (person, bool, error) {
Expand Down Expand Up @@ -204,9 +259,6 @@ func (s *peopleServiceImpl) processTerms(terms []interface{}, c chan<- []person)
var cacheToBeWritten []person
for _, iTerm := range terms {
t := iTerm.(term)
tmeIdentifier := buildTmeIdentifier(t.RawID, s.taxonomyName)
personUUID := uuid.NewMD5(uuid.UUID{}, []byte(tmeIdentifier)).String()
s.personLinks = append(s.personLinks, personLink{APIURL: s.baseURL + "/" + personUUID})
cacheToBeWritten = append(cacheToBeWritten, transformPerson(t, s.taxonomyName))
}
c <- cacheToBeWritten
Expand Down
55 changes: 52 additions & 3 deletions people/service_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package people

import (
"encoding/json"
"github.com/Financial-Times/tme-reader/tmereader"
log "github.com/Sirupsen/logrus"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"os"
"sync"
Expand Down Expand Up @@ -40,9 +42,56 @@ func TestGetPeople(t *testing.T) {
defer service.Shutdown()
waitTillInit(t, service)
waitTillDataLoaded(t, service)
peopleLinks, found := service.getPeople()
assert.True(t, found)
assert.Len(t, peopleLinks, 2)
pv, err := service.getPeople()

var wg sync.WaitGroup
var res []personLink
wg.Add(1)
go func(reader io.Reader, w *sync.WaitGroup) {
var err error
jsonBlob, err := ioutil.ReadAll(reader)
assert.NoError(t, err)
log.Infof("Got bytes: %v", string(jsonBlob[:]))
err = json.Unmarshal(jsonBlob, &res)
assert.NoError(t, err)
wg.Done()
}(&pv, &wg)
wg.Wait()

assert.NoError(t, err)
assert.Len(t, res, 2)
assert.Equal(t, "/base/url/28d66fcc-bb56-363d-80c1-f2d957ef58cf", res[0].APIURL)
assert.Equal(t, "/base/url/be2e7e2b-0fa2-3969-a69b-74c46e754032", res[1].APIURL)
}

func TestGetPeopleByUUID(t *testing.T) {
tmpfile := getTempFile(t)
defer os.Remove(tmpfile.Name())
repo := dummyRepo{terms: []term{{CanonicalName: "Bob", RawID: "bob"}, {CanonicalName: "Fred", RawID: "fred"}}}
service := createTestPeopleService(&repo, tmpfile.Name())
defer service.Shutdown()
waitTillInit(t, service)
waitTillDataLoaded(t, service)
pv, err := service.getPeopleByUUID()

var wg sync.WaitGroup
var res []personUUID
wg.Add(1)
go func(reader io.Reader, w *sync.WaitGroup) {
var err error
jsonBlob, err := ioutil.ReadAll(reader)
assert.NoError(t, err)
log.Infof("Got bytes: %v", string(jsonBlob[:]))
err = json.Unmarshal(jsonBlob, &res)
assert.NoError(t, err)
wg.Done()
}(&pv, &wg)
wg.Wait()

assert.NoError(t, err)
assert.Len(t, res, 2)
assert.Equal(t, "28d66fcc-bb56-363d-80c1-f2d957ef58cf", res[0].UUID)
assert.Equal(t, "be2e7e2b-0fa2-3969-a69b-74c46e754032", res[1].UUID)
}

func TestGetCount(t *testing.T) {
Expand Down

0 comments on commit bdd9076

Please sign in to comment.