diff --git a/examples/shipping/README.md b/examples/shipping/README.md index cbcc4df..1a9a14e 100644 --- a/examples/shipping/README.md +++ b/examples/shipping/README.md @@ -16,7 +16,7 @@ There are also a few pure domain packages that contain some intricate business-logic. They provide domain objects and services that are used by each application service to provide interesting use-cases for the user. -`repository` contains in-memory implementations for the repositories found in the domain packages. +`inmem` contains in-memory implementations for the repositories found in the domain packages. The `routing` package provides a _domain service_ that is used to query an external application for possible routes. diff --git a/examples/shipping/booking/endpoint.go b/examples/shipping/booking/endpoint.go index b9864d2..fe74955 100644 --- a/examples/shipping/booking/endpoint.go +++ b/examples/shipping/booking/endpoint.go @@ -6,6 +6,7 @@ "golang.org/x/net/context" "github.com/go-kit/kit/endpoint" + "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" ) diff --git a/examples/shipping/booking/instrumenting.go b/examples/shipping/booking/instrumenting.go index 8531796..b9b03b9 100644 --- a/examples/shipping/booking/instrumenting.go +++ b/examples/shipping/booking/instrumenting.go @@ -16,21 +16,21 @@ } // NewInstrumentingService returns an instance of an instrumenting Service. -func NewInstrumentingService(requestCount metrics.Counter, requestLatency metrics.Histogram, s Service) Service { +func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service { return &instrumentingService{ - requestCount: requestCount, - requestLatency: requestLatency, + requestCount: counter, + requestLatency: latency, Service: s, } } -func (s *instrumentingService) BookNewCargo(origin, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error) { +func (s *instrumentingService) BookNewCargo(origin, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) { defer func(begin time.Time) { s.requestCount.With("method", "book").Add(1) s.requestLatency.With("method", "book").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.BookNewCargo(origin, destination, arrivalDeadline) + return s.Service.BookNewCargo(origin, destination, deadline) } func (s *instrumentingService) LoadCargo(id cargo.TrackingID) (c Cargo, err error) { diff --git a/examples/shipping/booking/logging.go b/examples/shipping/booking/logging.go index 3a04576..931d430 100644 --- a/examples/shipping/booking/logging.go +++ b/examples/shipping/booking/logging.go @@ -3,9 +3,10 @@ import ( "time" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" - "github.com/go-kit/kit/log" ) type loggingService struct { @@ -18,18 +19,18 @@ return &loggingService{logger, s} } -func (s *loggingService) BookNewCargo(origin location.UNLocode, destination location.UNLocode, arrivalDeadline time.Time) (id cargo.TrackingID, err error) { +func (s *loggingService) BookNewCargo(origin location.UNLocode, destination location.UNLocode, deadline time.Time) (id cargo.TrackingID, err error) { defer func(begin time.Time) { s.logger.Log( "method", "book", "origin", origin, "destination", destination, - "arrival_deadline", arrivalDeadline, + "arrival_deadline", deadline, "took", time.Since(begin), "err", err, ) }(time.Now()) - return s.Service.BookNewCargo(origin, destination, arrivalDeadline) + return s.Service.BookNewCargo(origin, destination, deadline) } func (s *loggingService) LoadCargo(id cargo.TrackingID) (c Cargo, err error) { diff --git a/examples/shipping/booking/service.go b/examples/shipping/booking/service.go index 47605f8..8689a5a 100644 --- a/examples/shipping/booking/service.go +++ b/examples/shipping/booking/service.go @@ -18,21 +18,21 @@ type Service interface { // BookNewCargo registers a new cargo in the tracking system, not yet // routed. - BookNewCargo(origin location.UNLocode, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error) + BookNewCargo(origin location.UNLocode, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) // LoadCargo returns a read model of a cargo. - LoadCargo(trackingID cargo.TrackingID) (Cargo, error) + LoadCargo(id cargo.TrackingID) (Cargo, error) // RequestPossibleRoutesForCargo requests a list of itineraries describing // possible routes for this cargo. - RequestPossibleRoutesForCargo(trackingID cargo.TrackingID) []cargo.Itinerary + RequestPossibleRoutesForCargo(id cargo.TrackingID) []cargo.Itinerary // AssignCargoToRoute assigns a cargo to the route specified by the // itinerary. - AssignCargoToRoute(trackingID cargo.TrackingID, itinerary cargo.Itinerary) error + AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) error // ChangeDestination changes the destination of a cargo. - ChangeDestination(trackingID cargo.TrackingID, unLocode location.UNLocode) error + ChangeDestination(id cargo.TrackingID, destination location.UNLocode) error // Cargos returns a list of all cargos that have been booked. Cargos() []Cargo @@ -42,10 +42,10 @@ } type service struct { - cargoRepository cargo.Repository - locationRepository location.Repository - routingService routing.Service - handlingEventRepository cargo.HandlingEventRepository + cargos cargo.Repository + locations location.Repository + handlingEvents cargo.HandlingEventRepository + routingService routing.Service } func (s *service) AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) error { @@ -53,22 +53,18 @@ return ErrInvalidArgument } - c, err := s.cargoRepository.Find(id) + c, err := s.cargos.Find(id) if err != nil { return err } c.AssignToRoute(itinerary) - if err := s.cargoRepository.Store(c); err != nil { - return err - } - - return nil + return s.cargos.Store(c) } -func (s *service) BookNewCargo(origin, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error) { - if origin == "" || destination == "" || arrivalDeadline.IsZero() { +func (s *service) BookNewCargo(origin, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) { + if origin == "" || destination == "" || deadline.IsZero() { return "", ErrInvalidArgument } @@ -76,29 +72,29 @@ rs := cargo.RouteSpecification{ Origin: origin, Destination: destination, - ArrivalDeadline: arrivalDeadline, + ArrivalDeadline: deadline, } c := cargo.New(id, rs) - if err := s.cargoRepository.Store(c); err != nil { + if err := s.cargos.Store(c); err != nil { return "", err } return c.TrackingID, nil } -func (s *service) LoadCargo(trackingID cargo.TrackingID) (Cargo, error) { - if trackingID == "" { +func (s *service) LoadCargo(id cargo.TrackingID) (Cargo, error) { + if id == "" { return Cargo{}, ErrInvalidArgument } - c, err := s.cargoRepository.Find(trackingID) + c, err := s.cargos.Find(id) if err != nil { return Cargo{}, err } - return assemble(c, s.handlingEventRepository), nil + return assemble(c, s.handlingEvents), nil } func (s *service) ChangeDestination(id cargo.TrackingID, destination location.UNLocode) error { @@ -106,12 +102,12 @@ return ErrInvalidArgument } - c, err := s.cargoRepository.Find(id) + c, err := s.cargos.Find(id) if err != nil { return err } - l, err := s.locationRepository.Find(destination) + l, err := s.locations.Find(destination) if err != nil { return err } @@ -122,7 +118,7 @@ ArrivalDeadline: c.RouteSpecification.ArrivalDeadline, }) - if err := s.cargoRepository.Store(c); err != nil { + if err := s.cargos.Store(c); err != nil { return err } @@ -134,7 +130,7 @@ return nil } - c, err := s.cargoRepository.Find(id) + c, err := s.cargos.Find(id) if err != nil { return []cargo.Itinerary{} } @@ -144,15 +140,15 @@ func (s *service) Cargos() []Cargo { var result []Cargo - for _, c := range s.cargoRepository.FindAll() { - result = append(result, assemble(c, s.handlingEventRepository)) + for _, c := range s.cargos.FindAll() { + result = append(result, assemble(c, s.handlingEvents)) } return result } func (s *service) Locations() []Location { var result []Location - for _, v := range s.locationRepository.FindAll() { + for _, v := range s.locations.FindAll() { result = append(result, Location{ UNLocode: string(v.UNLocode), Name: v.Name, @@ -162,12 +158,12 @@ } // NewService creates a booking service with necessary dependencies. -func NewService(cr cargo.Repository, lr location.Repository, her cargo.HandlingEventRepository, rs routing.Service) Service { +func NewService(cargos cargo.Repository, locations location.Repository, events cargo.HandlingEventRepository, rs routing.Service) Service { return &service{ - cargoRepository: cr, - locationRepository: lr, - handlingEventRepository: her, - routingService: rs, + cargos: cargos, + locations: locations, + handlingEvents: events, + routingService: rs, } } @@ -188,7 +184,7 @@ TrackingID string `json:"tracking_id"` } -func assemble(c *cargo.Cargo, her cargo.HandlingEventRepository) Cargo { +func assemble(c *cargo.Cargo, events cargo.HandlingEventRepository) Cargo { return Cargo{ TrackingID: string(c.TrackingID), Origin: string(c.Origin), diff --git a/examples/shipping/booking/transport.go b/examples/shipping/booking/transport.go index 7cf5994..e445773 100644 --- a/examples/shipping/booking/transport.go +++ b/examples/shipping/booking/transport.go @@ -9,10 +9,11 @@ "github.com/gorilla/mux" "golang.org/x/net/context" + kitlog "github.com/go-kit/kit/log" + kithttp "github.com/go-kit/kit/transport/http" + "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" - kitlog "github.com/go-kit/kit/log" - kithttp "github.com/go-kit/kit/transport/http" ) // MakeHandler returns a handler for the booking service. @@ -81,7 +82,6 @@ r.Handle("/booking/v1/cargos/{id}/assign_to_route", assignToRouteHandler).Methods("POST") r.Handle("/booking/v1/cargos/{id}/change_destination", changeDestinationHandler).Methods("POST") r.Handle("/booking/v1/locations", listLocationsHandler).Methods("GET") - r.Handle("/booking/v1/docs", http.StripPrefix("/booking/v1/docs", http.FileServer(http.Dir("booking/docs")))) return r } diff --git a/examples/shipping/cargo/cargo.go b/examples/shipping/cargo/cargo.go index d4bb5f4..a9440f5 100644 --- a/examples/shipping/cargo/cargo.go +++ b/examples/shipping/cargo/cargo.go @@ -57,7 +57,7 @@ // Repository provides access a cargo store. type Repository interface { Store(cargo *Cargo) error - Find(trackingID TrackingID) (*Cargo, error) + Find(id TrackingID) (*Cargo, error) FindAll() []*Cargo } diff --git a/examples/shipping/cargo/handling.go b/examples/shipping/cargo/handling.go index 5f77bc4..bec8509 100644 --- a/examples/shipping/cargo/handling.go +++ b/examples/shipping/cargo/handling.go @@ -92,10 +92,10 @@ } // CreateHandlingEvent creates a validated handling event. -func (f *HandlingEventFactory) CreateHandlingEvent(registrationTime time.Time, completionTime time.Time, trackingID TrackingID, +func (f *HandlingEventFactory) CreateHandlingEvent(registered time.Time, completed time.Time, id TrackingID, voyageNumber voyage.Number, unLocode location.UNLocode, eventType HandlingEventType) (HandlingEvent, error) { - if _, err := f.CargoRepository.Find(trackingID); err != nil { + if _, err := f.CargoRepository.Find(id); err != nil { return HandlingEvent{}, err } @@ -111,7 +111,7 @@ } return HandlingEvent{ - TrackingID: trackingID, + TrackingID: id, Activity: HandlingActivity{ Type: eventType, Location: unLocode, diff --git a/examples/shipping/handling/endpoint.go b/examples/shipping/handling/endpoint.go index e10bdda..0ee3f22 100644 --- a/examples/shipping/handling/endpoint.go +++ b/examples/shipping/handling/endpoint.go @@ -6,6 +6,7 @@ "golang.org/x/net/context" "github.com/go-kit/kit/endpoint" + "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" diff --git a/examples/shipping/handling/instrumenting.go b/examples/shipping/handling/instrumenting.go index 065eca6..fecce04 100644 --- a/examples/shipping/handling/instrumenting.go +++ b/examples/shipping/handling/instrumenting.go @@ -17,15 +17,15 @@ } // NewInstrumentingService returns an instance of an instrumenting Service. -func NewInstrumentingService(requestCount metrics.Counter, requestLatency metrics.Histogram, s Service) Service { +func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service { return &instrumentingService{ - requestCount: requestCount, - requestLatency: requestLatency, + requestCount: counter, + requestLatency: latency, Service: s, } } -func (s *instrumentingService) RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyage voyage.Number, +func (s *instrumentingService) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, loc location.UNLocode, eventType cargo.HandlingEventType) error { defer func(begin time.Time) { @@ -33,5 +33,5 @@ s.requestLatency.With("method", "register_incident").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.RegisterHandlingEvent(completionTime, trackingID, voyage, loc, eventType) + return s.Service.RegisterHandlingEvent(completed, id, voyageNumber, loc, eventType) } diff --git a/examples/shipping/handling/logging.go b/examples/shipping/handling/logging.go index 26457ac..84722fb 100644 --- a/examples/shipping/handling/logging.go +++ b/examples/shipping/handling/logging.go @@ -3,10 +3,11 @@ import ( "time" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" - "github.com/go-kit/kit/log" ) type loggingService struct { @@ -19,19 +20,19 @@ return &loggingService{logger, s} } -func (s *loggingService) RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyageNumber voyage.Number, +func (s *loggingService) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, unLocode location.UNLocode, eventType cargo.HandlingEventType) (err error) { defer func(begin time.Time) { s.logger.Log( "method", "register_incident", - "tracking_id", trackingID, + "tracking_id", id, "location", unLocode, "voyage", voyageNumber, "event_type", eventType, - "completion_time", completionTime, + "completion_time", completed, "took", time.Since(begin), "err", err, ) }(time.Now()) - return s.Service.RegisterHandlingEvent(completionTime, trackingID, voyageNumber, unLocode, eventType) + return s.Service.RegisterHandlingEvent(completed, id, voyageNumber, unLocode, eventType) } diff --git a/examples/shipping/handling/service.go b/examples/shipping/handling/service.go index f548f4c..83d503a 100644 --- a/examples/shipping/handling/service.go +++ b/examples/shipping/handling/service.go @@ -24,7 +24,7 @@ type Service interface { // RegisterHandlingEvent registers a handling event in the system, and // notifies interested parties that a cargo has been handled. - RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyageNumber voyage.Number, + RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, unLocode location.UNLocode, eventType cargo.HandlingEventType) error } @@ -34,13 +34,13 @@ handlingEventHandler EventHandler } -func (s *service) RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyage voyage.Number, +func (s *service) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, loc location.UNLocode, eventType cargo.HandlingEventType) error { - if completionTime.IsZero() || trackingID == "" || loc == "" || eventType == cargo.NotHandled { + if completed.IsZero() || id == "" || loc == "" || eventType == cargo.NotHandled { return ErrInvalidArgument } - e, err := s.handlingEventFactory.CreateHandlingEvent(time.Now(), completionTime, trackingID, voyage, loc, eventType) + e, err := s.handlingEventFactory.CreateHandlingEvent(time.Now(), completed, id, voyageNumber, loc, eventType) if err != nil { return err } diff --git a/examples/shipping/handling/transport.go b/examples/shipping/handling/transport.go index 1777ad6..e5d2c44 100644 --- a/examples/shipping/handling/transport.go +++ b/examples/shipping/handling/transport.go @@ -8,11 +8,12 @@ "github.com/gorilla/mux" "golang.org/x/net/context" + kitlog "github.com/go-kit/kit/log" + kithttp "github.com/go-kit/kit/transport/http" + "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" - kitlog "github.com/go-kit/kit/log" - kithttp "github.com/go-kit/kit/transport/http" ) // MakeHandler returns a handler for the handling service. diff --git a/examples/shipping/inmem/inmem.go b/examples/shipping/inmem/inmem.go new file mode 100644 index 0000000..f941b7e --- /dev/null +++ b/examples/shipping/inmem/inmem.go @@ -0,0 +1,142 @@ +// Package inmem provides in-memory implementations of all the domain repositories. +package inmem + +import ( + "sync" + + "github.com/go-kit/kit/examples/shipping/cargo" + "github.com/go-kit/kit/examples/shipping/location" + "github.com/go-kit/kit/examples/shipping/voyage" +) + +type cargoRepository struct { + mtx sync.RWMutex + cargos map[cargo.TrackingID]*cargo.Cargo +} + +func (r *cargoRepository) Store(c *cargo.Cargo) error { + r.mtx.Lock() + defer r.mtx.Unlock() + r.cargos[c.TrackingID] = c + return nil +} + +func (r *cargoRepository) Find(id cargo.TrackingID) (*cargo.Cargo, error) { + r.mtx.RLock() + defer r.mtx.RUnlock() + if val, ok := r.cargos[id]; ok { + return val, nil + } + return nil, cargo.ErrUnknown +} + +func (r *cargoRepository) FindAll() []*cargo.Cargo { + r.mtx.RLock() + defer r.mtx.RUnlock() + c := make([]*cargo.Cargo, 0, len(r.cargos)) + for _, val := range r.cargos { + c = append(c, val) + } + return c +} + +// NewCargoRepository returns a new instance of a in-memory cargo repository. +func NewCargoRepository() cargo.Repository { + return &cargoRepository{ + cargos: make(map[cargo.TrackingID]*cargo.Cargo), + } +} + +type locationRepository struct { + locations map[location.UNLocode]*location.Location +} + +func (r *locationRepository) Find(locode location.UNLocode) (*location.Location, error) { + if l, ok := r.locations[locode]; ok { + return l, nil + } + return nil, location.ErrUnknown +} + +func (r *locationRepository) FindAll() []*location.Location { + l := make([]*location.Location, 0, len(r.locations)) + for _, val := range r.locations { + l = append(l, val) + } + return l +} + +// NewLocationRepository returns a new instance of a in-memory location repository. +func NewLocationRepository() location.Repository { + r := &locationRepository{ + locations: make(map[location.UNLocode]*location.Location), + } + + r.locations[location.SESTO] = location.Stockholm + r.locations[location.AUMEL] = location.Melbourne + r.locations[location.CNHKG] = location.Hongkong + r.locations[location.JNTKO] = location.Tokyo + r.locations[location.NLRTM] = location.Rotterdam + r.locations[location.DEHAM] = location.Hamburg + + return r +} + +type voyageRepository struct { + voyages map[voyage.Number]*voyage.Voyage +} + +func (r *voyageRepository) Find(voyageNumber voyage.Number) (*voyage.Voyage, error) { + if v, ok := r.voyages[voyageNumber]; ok { + return v, nil + } + + return nil, voyage.ErrUnknown +} + +// NewVoyageRepository returns a new instance of a in-memory voyage repository. +func NewVoyageRepository() voyage.Repository { + r := &voyageRepository{ + voyages: make(map[voyage.Number]*voyage.Voyage), + } + + r.voyages[voyage.V100.Number] = voyage.V100 + r.voyages[voyage.V300.Number] = voyage.V300 + r.voyages[voyage.V400.Number] = voyage.V400 + + r.voyages[voyage.V0100S.Number] = voyage.V0100S + r.voyages[voyage.V0200T.Number] = voyage.V0200T + r.voyages[voyage.V0300A.Number] = voyage.V0300A + r.voyages[voyage.V0301S.Number] = voyage.V0301S + r.voyages[voyage.V0400S.Number] = voyage.V0400S + + return r +} + +type handlingEventRepository struct { + mtx sync.RWMutex + events map[cargo.TrackingID][]cargo.HandlingEvent +} + +func (r *handlingEventRepository) Store(e cargo.HandlingEvent) { + r.mtx.Lock() + defer r.mtx.Unlock() + // Make array if it's the first event with this tracking ID. + if _, ok := r.events[e.TrackingID]; !ok { + r.events[e.TrackingID] = make([]cargo.HandlingEvent, 0) + } + r.events[e.TrackingID] = append(r.events[e.TrackingID], e) +} + +func (r *handlingEventRepository) QueryHandlingHistory(id cargo.TrackingID) cargo.HandlingHistory { + r.mtx.RLock() + defer r.mtx.RUnlock() + return cargo.HandlingHistory{HandlingEvents: r.events[id]} +} + +// NewHandlingEventRepository returns a new instance of a in-memory handling event repository. +func NewHandlingEventRepository() cargo.HandlingEventRepository { + return &handlingEventRepository{ + events: make(map[cargo.TrackingID][]cargo.HandlingEvent), + } +} diff --git a/examples/shipping/inspection/inspection.go b/examples/shipping/inspection/inspection.go index a3f7147..91cceb0 100644 --- a/examples/shipping/inspection/inspection.go +++ b/examples/shipping/inspection/inspection.go @@ -14,38 +14,38 @@ // InspectCargo inspects cargo and send relevant notifications to // interested parties, for example if a cargo has been misdirected, or // unloaded at the final destination. - InspectCargo(trackingID cargo.TrackingID) + InspectCargo(id cargo.TrackingID) } type service struct { - cargoRepository cargo.Repository - handlingEventRepository cargo.HandlingEventRepository - cargoEventHandler EventHandler + cargos cargo.Repository + events cargo.HandlingEventRepository + handler EventHandler } // TODO: Should be transactional -func (s *service) InspectCargo(trackingID cargo.TrackingID) { - c, err := s.cargoRepository.Find(trackingID) +func (s *service) InspectCargo(id cargo.TrackingID) { + c, err := s.cargos.Find(id) if err != nil { return } - h := s.handlingEventRepository.QueryHandlingHistory(trackingID) + h := s.events.QueryHandlingHistory(id) c.DeriveDeliveryProgress(h) if c.Delivery.IsMisdirected { - s.cargoEventHandler.CargoWasMisdirected(c) + s.handler.CargoWasMisdirected(c) } if c.Delivery.IsUnloadedAtDestination { - s.cargoEventHandler.CargoHasArrived(c) + s.handler.CargoHasArrived(c) } - s.cargoRepository.Store(c) + s.cargos.Store(c) } // NewService creates a inspection service with necessary dependencies. -func NewService(cargoRepository cargo.Repository, handlingEventRepository cargo.HandlingEventRepository, eventHandler EventHandler) Service { - return &service{cargoRepository, handlingEventRepository, eventHandler} +func NewService(cargos cargo.Repository, events cargo.HandlingEventRepository, handler EventHandler) Service { + return &service{cargos, events, handler} } diff --git a/examples/shipping/location/location.go b/examples/shipping/location/location.go index 5129380..4a9d2f9 100644 --- a/examples/shipping/location/location.go +++ b/examples/shipping/location/location.go @@ -22,6 +22,6 @@ // Repository provides access a location store. type Repository interface { - Find(locode UNLocode) (Location, error) - FindAll() []Location + Find(locode UNLocode) (*Location, error) + FindAll() []*Location } diff --git a/examples/shipping/location/sample_locations.go b/examples/shipping/location/sample_locations.go index de0d4c1..7fd34ef 100644 --- a/examples/shipping/location/sample_locations.go +++ b/examples/shipping/location/sample_locations.go @@ -15,13 +15,13 @@ // Sample locations. var ( - Stockholm = Location{SESTO, "Stockholm"} - Melbourne = Location{AUMEL, "Melbourne"} - Hongkong = Location{CNHKG, "Hongkong"} - NewYork = Location{USNYC, "New York"} - Chicago = Location{USCHI, "Chicago"} - Tokyo = Location{JNTKO, "Tokyo"} - Hamburg = Location{DEHAM, "Hamburg"} - Rotterdam = Location{NLRTM, "Rotterdam"} - Helsinki = Location{FIHEL, "Helsinki"} + Stockholm = &Location{SESTO, "Stockholm"} + Melbourne = &Location{AUMEL, "Melbourne"} + Hongkong = &Location{CNHKG, "Hongkong"} + NewYork = &Location{USNYC, "New York"} + Chicago = &Location{USCHI, "Chicago"} + Tokyo = &Location{JNTKO, "Tokyo"} + Hamburg = &Location{DEHAM, "Hamburg"} + Rotterdam = &Location{NLRTM, "Rotterdam"} + Helsinki = &Location{FIHEL, "Helsinki"} ) diff --git a/examples/shipping/main.go b/examples/shipping/main.go index 3800cf1..4fbcd94 100644 --- a/examples/shipping/main.go +++ b/examples/shipping/main.go @@ -19,9 +19,9 @@ "github.com/go-kit/kit/examples/shipping/booking" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/handling" + "github.com/go-kit/kit/examples/shipping/inmem" "github.com/go-kit/kit/examples/shipping/inspection" "github.com/go-kit/kit/examples/shipping/location" - "github.com/go-kit/kit/examples/shipping/repository" "github.com/go-kit/kit/examples/shipping/routing" "github.com/go-kit/kit/examples/shipping/tracking" ) @@ -50,10 +50,10 @@ logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC) var ( - cargos = repository.NewCargo() - locations = repository.NewLocation() - voyages = repository.NewVoyage() - handlingEvents = repository.NewHandlingEvent() + cargos = inmem.NewCargoRepository() + locations = inmem.NewLocationRepository() + voyages = inmem.NewVoyageRepository() + handlingEvents = inmem.NewHandlingEventRepository() ) // Configure some questionable dependencies. @@ -74,7 +74,7 @@ fieldKeys := []string{"method"} var rs routing.Service - rs = routing.NewProxyingMiddleware(*routingServiceURL, ctx)(rs) + rs = routing.NewProxyingMiddleware(ctx, *routingServiceURL)(rs) var bs booking.Service bs = booking.NewService(cargos, locations, handlingEvents, rs) @@ -186,14 +186,18 @@ Destination: location.SESTO, ArrivalDeadline: time.Now().AddDate(0, 0, 7), }) - _ = r.Store(test1) + if err := r.Store(test1); err != nil { + panic(err) + } test2 := cargo.New("ABC123", cargo.RouteSpecification{ Origin: location.SESTO, Destination: location.CNHKG, ArrivalDeadline: time.Now().AddDate(0, 0, 14), }) - _ = r.Store(test2) + if err := r.Store(test2); err != nil { + panic(err) + } } type serializedLogger struct { diff --git a/examples/shipping/mock/mock.go b/examples/shipping/mock/mock.go new file mode 100644 index 0000000..04d60da --- /dev/null +++ b/examples/shipping/mock/mock.go @@ -0,0 +1,103 @@ +package mock + +import ( + "github.com/go-kit/kit/examples/shipping/cargo" + "github.com/go-kit/kit/examples/shipping/location" + "github.com/go-kit/kit/examples/shipping/voyage" +) + +// CargoRepository is a mock cargo repository. +type CargoRepository struct { + StoreFn func(c *cargo.Cargo) error + StoreInvoked bool + + FindFn func(id cargo.TrackingID) (*cargo.Cargo, error) + FindInvoked bool + + FindAllFn func() []*cargo.Cargo + FindAllInvoked bool +} + +// Store calls the StoreFn. +func (r *CargoRepository) Store(c *cargo.Cargo) error { + r.StoreInvoked = true + return r.StoreFn(c) +} + +// Find calls the FindFn. +func (r *CargoRepository) Find(id cargo.TrackingID) (*cargo.Cargo, error) { + r.FindInvoked = true + return r.FindFn(id) +} + +// FindAll calls the FindAllFn. +func (r *CargoRepository) FindAll() []*cargo.Cargo { + r.FindAllInvoked = true + return r.FindAllFn() +} + +// LocationRepository is a mock location repository. +type LocationRepository struct { + FindFn func(location.UNLocode) (*location.Location, error) + FindInvoked bool + + FindAllFn func() []*location.Location + FindAllInvoked bool +} + +// Find calls the FindFn. +func (r *LocationRepository) Find(locode location.UNLocode) (*location.Location, error) { + r.FindInvoked = true + return r.FindFn(locode) +} + +// FindAll calls the FindAllFn. +func (r *LocationRepository) FindAll() []*location.Location { + r.FindAllInvoked = true + return r.FindAllFn() +} + +// VoyageRepository is a mock voyage repository. +type VoyageRepository struct { + FindFn func(voyage.Number) (*voyage.Voyage, error) + FindInvoked bool +} + +// Find calls the FindFn. +func (r *VoyageRepository) Find(number voyage.Number) (*voyage.Voyage, error) { + r.FindInvoked = true + return r.FindFn(number) +} + +// HandlingEventRepository is a mock handling events repository. +type HandlingEventRepository struct { + StoreFn func(cargo.HandlingEvent) + StoreInvoked bool + + QueryHandlingHistoryFn func(cargo.TrackingID) cargo.HandlingHistory + QueryHandlingHistoryInvoked bool +} + +// Store calls the StoreFn. +func (r *HandlingEventRepository) Store(e cargo.HandlingEvent) { + r.StoreInvoked = true + r.StoreFn(e) +} + +// QueryHandlingHistory calls the QueryHandlingHistoryFn. +func (r *HandlingEventRepository) QueryHandlingHistory(id cargo.TrackingID) cargo.HandlingHistory { + r.QueryHandlingHistoryInvoked = true + return r.QueryHandlingHistoryFn(id) +} + +// RoutingService provides a mock routing service. +type RoutingService struct { + FetchRoutesFn func(cargo.RouteSpecification) []cargo.Itinerary + FetchRoutesInvoked bool +} + +// FetchRoutesForSpecification calls the FetchRoutesFn. +func (s *RoutingService) FetchRoutesForSpecification(rs cargo.RouteSpecification) []cargo.Itinerary { + s.FetchRoutesInvoked = true + return s.FetchRoutesFn(rs) +} diff --git a/examples/shipping/repository/repositories.go b/examples/shipping/repository/repositories.go deleted file mode 100644 index 714d0a8..0000000 --- a/examples/shipping/repository/repositories.go +++ /dev/null @@ -1,142 +0,0 @@ -// Package repository provides implementations of all the domain repositories. -package repository - -import ( - "sync" - - "github.com/go-kit/kit/examples/shipping/cargo" - "github.com/go-kit/kit/examples/shipping/location" - "github.com/go-kit/kit/examples/shipping/voyage" -) - -type cargoRepository struct { - mtx sync.RWMutex - cargos map[cargo.TrackingID]*cargo.Cargo -} - -func (r *cargoRepository) Store(c *cargo.Cargo) error { - r.mtx.Lock() - defer r.mtx.Unlock() - r.cargos[c.TrackingID] = c - return nil -} - -func (r *cargoRepository) Find(trackingID cargo.TrackingID) (*cargo.Cargo, error) { - r.mtx.RLock() - defer r.mtx.RUnlock() - if val, ok := r.cargos[trackingID]; ok { - return val, nil - } - return nil, cargo.ErrUnknown -} - -func (r *cargoRepository) FindAll() []*cargo.Cargo { - r.mtx.RLock() - defer r.mtx.RUnlock() - c := make([]*cargo.Cargo, 0, len(r.cargos)) - for _, val := range r.cargos { - c = append(c, val) - } - return c -} - -// NewCargo returns a new instance of a in-memory cargo repository. -func NewCargo() cargo.Repository { - return &cargoRepository{ - cargos: make(map[cargo.TrackingID]*cargo.Cargo), - } -} - -type locationRepository struct { - locations map[location.UNLocode]location.Location -} - -func (r *locationRepository) Find(locode location.UNLocode) (location.Location, error) { - if l, ok := r.locations[locode]; ok { - return l, nil - } - return location.Location{}, location.ErrUnknown -} - -func (r *locationRepository) FindAll() []location.Location { - l := make([]location.Location, 0, len(r.locations)) - for _, val := range r.locations { - l = append(l, val) - } - return l -} - -// NewLocation returns a new instance of a in-memory location repository. -func NewLocation() location.Repository { - r := &locationRepository{ - locations: make(map[location.UNLocode]location.Location), - } - - r.locations[location.SESTO] = location.Stockholm - r.locations[location.AUMEL] = location.Melbourne - r.locations[location.CNHKG] = location.Hongkong - r.locations[location.JNTKO] = location.Tokyo - r.locations[location.NLRTM] = location.Rotterdam - r.locations[location.DEHAM] = location.Hamburg - - return r -} - -type voyageRepository struct { - voyages map[voyage.Number]*voyage.Voyage -} - -func (r *voyageRepository) Find(voyageNumber voyage.Number) (*voyage.Voyage, error) { - if v, ok := r.voyages[voyageNumber]; ok { - return v, nil - } - - return nil, voyage.ErrUnknown -} - -// NewVoyage returns a new instance of a in-memory voyage repository. -func NewVoyage() voyage.Repository { - r := &voyageRepository{ - voyages: make(map[voyage.Number]*voyage.Voyage), - } - - r.voyages[voyage.V100.Number] = voyage.V100 - r.voyages[voyage.V300.Number] = voyage.V300 - r.voyages[voyage.V400.Number] = voyage.V400 - - r.voyages[voyage.V0100S.Number] = voyage.V0100S - r.voyages[voyage.V0200T.Number] = voyage.V0200T - r.voyages[voyage.V0300A.Number] = voyage.V0300A - r.voyages[voyage.V0301S.Number] = voyage.V0301S - r.voyages[voyage.V0400S.Number] = voyage.V0400S - - return r -} - -type handlingEventRepository struct { - mtx sync.RWMutex - events map[cargo.TrackingID][]cargo.HandlingEvent -} - -func (r *handlingEventRepository) Store(e cargo.HandlingEvent) { - r.mtx.Lock() - defer r.mtx.Unlock() - // Make array if it's the first event with this tracking ID. - if _, ok := r.events[e.TrackingID]; !ok { - r.events[e.TrackingID] = make([]cargo.HandlingEvent, 0) - } - r.events[e.TrackingID] = append(r.events[e.TrackingID], e) -} - -func (r *handlingEventRepository) QueryHandlingHistory(trackingID cargo.TrackingID) cargo.HandlingHistory { - r.mtx.RLock() - defer r.mtx.RUnlock() - return cargo.HandlingHistory{HandlingEvents: r.events[trackingID]} -} - -// NewHandlingEvent returns a new instance of a in-memory handling event repository. -func NewHandlingEvent() cargo.HandlingEventRepository { - return &handlingEventRepository{ - events: make(map[cargo.TrackingID][]cargo.HandlingEvent), - } -} diff --git a/examples/shipping/routing/proxying.go b/examples/shipping/routing/proxying.go index 3051caf..a53f265 100644 --- a/examples/shipping/routing/proxying.go +++ b/examples/shipping/routing/proxying.go @@ -10,10 +10,11 @@ "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" + kithttp "github.com/go-kit/kit/transport/http" + "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" - kithttp "github.com/go-kit/kit/transport/http" ) type proxyService struct { @@ -56,7 +57,7 @@ type ServiceMiddleware func(Service) Service // NewProxyingMiddleware returns a new instance of a proxying middleware. -func NewProxyingMiddleware(proxyURL string, ctx context.Context) ServiceMiddleware { +func NewProxyingMiddleware(ctx context.Context, proxyURL string) ServiceMiddleware { return func(next Service) Service { var e endpoint.Endpoint e = makeFetchRoutesEndpoint(ctx, proxyURL) diff --git a/examples/shipping/tracking/instrumenting.go b/examples/shipping/tracking/instrumenting.go index c2016d2..f5dc018 100644 --- a/examples/shipping/tracking/instrumenting.go +++ b/examples/shipping/tracking/instrumenting.go @@ -13,10 +13,10 @@ } // NewInstrumentingService returns an instance of an instrumenting Service. -func NewInstrumentingService(requestCount metrics.Counter, requestLatency metrics.Histogram, s Service) Service { +func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service { return &instrumentingService{ - requestCount: requestCount, - requestLatency: requestLatency, + requestCount: counter, + requestLatency: latency, Service: s, } } diff --git a/examples/shipping/tracking/service.go b/examples/shipping/tracking/service.go index d5b9273..b0e360b 100644 --- a/examples/shipping/tracking/service.go +++ b/examples/shipping/tracking/service.go @@ -37,10 +37,10 @@ } // NewService returns a new instance of the default Service. -func NewService(cargos cargo.Repository, handlingEvents cargo.HandlingEventRepository) Service { +func NewService(cargos cargo.Repository, events cargo.HandlingEventRepository) Service { return &service{ cargos: cargos, - handlingEvents: handlingEvents, + handlingEvents: events, } } @@ -71,7 +71,7 @@ Expected bool `json:"expected"` } -func assemble(c *cargo.Cargo, her cargo.HandlingEventRepository) Cargo { +func assemble(c *cargo.Cargo, events cargo.HandlingEventRepository) Cargo { return Cargo{ TrackingID: string(c.TrackingID), Origin: string(c.Origin), @@ -80,7 +80,7 @@ NextExpectedActivity: nextExpectedActivity(c), ArrivalDeadline: c.RouteSpecification.ArrivalDeadline, StatusText: assembleStatusText(c), - Events: assembleEvents(c, her), + Events: assembleEvents(c, events), } } @@ -129,8 +129,8 @@ } } -func assembleEvents(c *cargo.Cargo, r cargo.HandlingEventRepository) []Event { - h := r.QueryHandlingHistory(c.TrackingID) +func assembleEvents(c *cargo.Cargo, handlingEvents cargo.HandlingEventRepository) []Event { + h := handlingEvents.QueryHandlingHistory(c.TrackingID) var events []Event for _, e := range h.HandlingEvents { diff --git a/examples/shipping/tracking/transport.go b/examples/shipping/tracking/transport.go index 9cac1ec..3cdb9b1 100644 --- a/examples/shipping/tracking/transport.go +++ b/examples/shipping/tracking/transport.go @@ -8,9 +8,10 @@ "github.com/gorilla/mux" "golang.org/x/net/context" - "github.com/go-kit/kit/examples/shipping/cargo" kitlog "github.com/go-kit/kit/log" kithttp "github.com/go-kit/kit/transport/http" + + "github.com/go-kit/kit/examples/shipping/cargo" ) // MakeHandler returns a handler for the tracking service. diff --git a/examples/shipping/voyage/sample_voyages.go b/examples/shipping/voyage/sample_voyages.go index 51b7a05..751f588 100644 --- a/examples/shipping/voyage/sample_voyages.go +++ b/examples/shipping/voyage/sample_voyages.go @@ -6,25 +6,25 @@ var ( V100 = New("V100", Schedule{ []CarrierMovement{ - {DepartureLocation: location.Hongkong, ArrivalLocation: location.Tokyo}, - {DepartureLocation: location.Tokyo, ArrivalLocation: location.NewYork}, + {DepartureLocation: location.CNHKG, ArrivalLocation: location.JNTKO}, + {DepartureLocation: location.JNTKO, ArrivalLocation: location.USNYC}, }, }) V300 = New("V300", Schedule{ []CarrierMovement{ - {DepartureLocation: location.Tokyo, ArrivalLocation: location.Rotterdam}, - {DepartureLocation: location.Rotterdam, ArrivalLocation: location.Hamburg}, - {DepartureLocation: location.Hamburg, ArrivalLocation: location.Melbourne}, - {DepartureLocation: location.Melbourne, ArrivalLocation: location.Tokyo}, + {DepartureLocation: location.JNTKO, ArrivalLocation: location.NLRTM}, + {DepartureLocation: location.NLRTM, ArrivalLocation: location.DEHAM}, + {DepartureLocation: location.DEHAM, ArrivalLocation: location.AUMEL}, + {DepartureLocation: location.AUMEL, ArrivalLocation: location.JNTKO}, }, }) V400 = New("V400", Schedule{ []CarrierMovement{ - {DepartureLocation: location.Hamburg, ArrivalLocation: location.Stockholm}, - {DepartureLocation: location.Stockholm, ArrivalLocation: location.Helsinki}, - {DepartureLocation: location.Helsinki, ArrivalLocation: location.Hamburg}, + {DepartureLocation: location.DEHAM, ArrivalLocation: location.SESTO}, + {DepartureLocation: location.SESTO, ArrivalLocation: location.FIHEL}, + {DepartureLocation: location.FIHEL, ArrivalLocation: location.DEHAM}, }, }) ) diff --git a/examples/shipping/voyage/voyage.go b/examples/shipping/voyage/voyage.go index 57a70b0..37366af 100644 --- a/examples/shipping/voyage/voyage.go +++ b/examples/shipping/voyage/voyage.go @@ -29,8 +29,8 @@ // CarrierMovement is a vessel voyage from one location to another. type CarrierMovement struct { - DepartureLocation location.Location - ArrivalLocation location.Location + DepartureLocation location.UNLocode + ArrivalLocation location.UNLocode DepartureTime time.Time ArrivalTime time.Time }