Beispiel #1
0
func TestTrackTrackCargo(t *testing.T) {
	var (
		cargos         = repository.NewInMemcargo()
		handlingEvents = repository.NewInMemHandlingEvent()
		service        = NewService(cargos, handlingEvents)
	)

	c := cargo.New("TEST", cargo.RouteSpecification{
		Origin:          "SESTO",
		Destination:     "FIHEL",
		ArrivalDeadline: time.Date(2005, 12, 4, 0, 0, 0, 0, time.UTC),
	})
	cargos.Store(c)

	ctx := context.Background()

	logger := log.NewLogfmtLogger(ioutil.Discard)

	h := MakeHandler(ctx, service, logger)

	req, _ := http.NewRequest("GET", "http://example.com/tracking/v1/cargos/TEST", nil)
	rec := httptest.NewRecorder()

	h.ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("rec.Code = %d; want = %d", rec.Code, http.StatusOK)
	}

	if content := rec.Header().Get("Content-Type"); content != "application/json; charset=utf-8" {
		t.Errorf("Content-Type = %q; want = %q", content, "application/json; charset=utf-8")
	}

	var response trackCargoResponse
	if err := json.NewDecoder(rec.Body).Decode(&response); err != nil {
		t.Error(err)
	}

	if response.Err != nil {
		t.Errorf("response.Err = %q", response.Err)
	}

	var eta time.Time

	want := Cargo{
		TrackingID:           "TEST",
		Origin:               "SESTO",
		Destination:          "FIHEL",
		ArrivalDeadline:      time.Date(2005, 12, 4, 0, 0, 0, 0, time.UTC),
		ETA:                  eta.In(time.UTC),
		StatusText:           "Not received",
		NextExpectedActivity: "There are currently no expected activities for this cargo.",
		Events:               nil,
	}

	if !reflect.DeepEqual(want, *response.Cargo) {
		t.Errorf("response.Cargo = %#v; want = %#v", response.Cargo, want)
	}
}
Beispiel #2
0
func (s *S) TestInspectUnloadedCargo(c *C) {

	var (
		cargoRepository         = repository.NewInMemcargo()
		handlingEventRepository = repository.NewInMemHandlingEvent()
		cargoEventHandler       = &stubEventHandler{make([]interface{}, 0)}

		inspectionService = &service{
			cargoRepository:         cargoRepository,
			handlingEventRepository: handlingEventRepository,
			cargoEventHandler:       cargoEventHandler,
		}
	)

	trackingID := cargo.TrackingID("ABC123")
	unloadedCargo := cargo.New(trackingID, cargo.RouteSpecification{
		Origin:      location.SESTO,
		Destination: location.CNHKG,
	})

	var voyageNumber voyage.Number = "001A"

	unloadedCargo.AssignToRoute(cargo.Itinerary{Legs: []cargo.Leg{
		{VoyageNumber: voyageNumber, LoadLocation: location.SESTO, UnloadLocation: location.AUMEL},
		{VoyageNumber: voyageNumber, LoadLocation: location.AUMEL, UnloadLocation: location.CNHKG},
	}})

	cargoRepository.Store(unloadedCargo)

	storeEvent(handlingEventRepository, trackingID, voyageNumber, cargo.Receive, location.SESTO)
	storeEvent(handlingEventRepository, trackingID, voyageNumber, cargo.Load, location.SESTO)
	storeEvent(handlingEventRepository, trackingID, voyageNumber, cargo.Unload, location.AUMEL)
	storeEvent(handlingEventRepository, trackingID, voyageNumber, cargo.Load, location.AUMEL)
	storeEvent(handlingEventRepository, trackingID, voyageNumber, cargo.Unload, location.CNHKG)

	c.Check(len(cargoEventHandler.handledEvents), Equals, 0)

	inspectionService.InspectCargo(trackingID)

	c.Check(len(cargoEventHandler.handledEvents), Equals, 1)
}
Beispiel #3
0
func TestTrackUnknownCargo(t *testing.T) {
	var (
		cargos         = repository.NewInMemcargo()
		handlingEvents = repository.NewInMemHandlingEvent()
		service        = NewService(cargos, handlingEvents)
	)

	ctx := context.Background()

	logger := log.NewLogfmtLogger(ioutil.Discard)

	h := MakeHandler(ctx, service, logger)

	req, _ := http.NewRequest("GET", "http://example.com/tracking/v1/cargos/not_found", nil)
	rec := httptest.NewRecorder()

	h.ServeHTTP(rec, req)

	if rec.Code != http.StatusNotFound {
		t.Errorf("rec.Code = %d; want = %d", rec.Code, http.StatusNotFound)
	}

	wantContent := "application/json; charset=utf-8"
	if got := rec.Header().Get("Content-Type"); got != wantContent {
		t.Errorf("Content-Type = %q; want = %q", got, wantContent)
	}

	var response map[string]interface{}
	if err := json.NewDecoder(rec.Body).Decode(&response); err != nil {
		t.Error(err)
	}

	err, ok := response["error"]
	if !ok {
		t.Error("missing error")
	}
	if err != "unknown cargo" {
		t.Errorf(`"error": %q; want = %q`, err, "unknown cargo")
	}
}
Beispiel #4
0
func main() {
	var (
		addr   = envString("PORT", defaultPort)
		rsurl  = envString("ROUTINGSERVICE_URL", defaultRoutingServiceURL)
		dburl  = envString("MONGODB_URL", defaultMongoDBURL)
		dbname = envString("DB_NAME", defaultDBName)

		httpAddr          = flag.String("http.addr", ":"+addr, "HTTP listen address")
		routingServiceURL = flag.String("service.routing", rsurl, "routing service URL")
		mongoDBURL        = flag.String("db.url", dburl, "MongoDB URL")
		databaseName      = flag.String("db.name", dbname, "MongoDB database name")
		inmem             = flag.Bool("inmem", false, "use in-memory repositories")

		ctx = context.Background()
	)

	flag.Parse()

	var logger log.Logger
	logger = log.NewLogfmtLogger(os.Stderr)
	logger = &serializedLogger{Logger: logger}
	logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC)

	// Setup repositories
	var (
		cargos         cargo.Repository
		locations      location.Repository
		voyages        voyage.Repository
		handlingEvents cargo.HandlingEventRepository
	)

	if *inmem {
		cargos = repository.NewInMemcargo()
		locations = repository.NewInMemLocation()
		voyages = repository.NewInMemVoyage()
		handlingEvents = repository.NewInMemHandlingEvent()
	} else {
		session, err := mgo.Dial(*mongoDBURL)
		if err != nil {
			panic(err)
		}
		defer session.Close()

		session.SetMode(mgo.Monotonic, true)

		cargos, _ = repository.NewMongoCargo(*databaseName, session)
		locations, _ = repository.NewMongoLocation(*databaseName, session)
		voyages, _ = repository.NewMongoVoyage(*databaseName, session)
		handlingEvents = repository.NewMongoHandlingEvent(*databaseName, session)
	}

	// Configure some questionable dependencies.
	var (
		handlingEventFactory = cargo.HandlingEventFactory{
			CargoRepository:    cargos,
			VoyageRepository:   voyages,
			LocationRepository: locations,
		}
		handlingEventHandler = handling.NewEventHandler(
			inspection.NewService(cargos, handlingEvents, nil),
		)
	)

	// Facilitate testing by adding some cargos.
	storeTestData(cargos)

	fieldKeys := []string{"method"}

	var rs routing.Service
	rs = routing.NewProxyingMiddleware(*routingServiceURL, ctx)(rs)

	var bs booking.Service
	bs = booking.NewService(cargos, locations, handlingEvents, rs)
	bs = booking.NewLoggingService(log.NewContext(logger).With("component", "booking"), bs)
	bs = booking.NewInstrumentingService(
		kitprometheus.NewCounter(stdprometheus.CounterOpts{
			Namespace: "api",
			Subsystem: "booking_service",
			Name:      "request_count",
			Help:      "Number of requests received.",
		}, fieldKeys),
		metrics.NewTimeHistogram(time.Microsecond, kitprometheus.NewSummary(stdprometheus.SummaryOpts{
			Namespace: "api",
			Subsystem: "booking_service",
			Name:      "request_latency_microseconds",
			Help:      "Total duration of requests in microseconds.",
		}, fieldKeys)), bs)

	var ts tracking.Service
	ts = tracking.NewService(cargos, handlingEvents)
	ts = tracking.NewLoggingService(log.NewContext(logger).With("component", "tracking"), ts)
	ts = tracking.NewInstrumentingService(
		kitprometheus.NewCounter(stdprometheus.CounterOpts{
			Namespace: "api",
			Subsystem: "tracking_service",
			Name:      "request_count",
			Help:      "Number of requests received.",
		}, fieldKeys),
		metrics.NewTimeHistogram(time.Microsecond, kitprometheus.NewSummary(stdprometheus.SummaryOpts{
			Namespace: "api",
			Subsystem: "tracking_service",
			Name:      "request_latency_microseconds",
			Help:      "Total duration of requests in microseconds.",
		}, fieldKeys)), ts)

	var hs handling.Service
	hs = handling.NewService(handlingEvents, handlingEventFactory, handlingEventHandler)
	hs = handling.NewLoggingService(log.NewContext(logger).With("component", "handling"), hs)
	hs = handling.NewInstrumentingService(
		kitprometheus.NewCounter(stdprometheus.CounterOpts{
			Namespace: "api",
			Subsystem: "handling_service",
			Name:      "request_count",
			Help:      "Number of requests received.",
		}, fieldKeys),
		metrics.NewTimeHistogram(time.Microsecond, kitprometheus.NewSummary(stdprometheus.SummaryOpts{
			Namespace: "api",
			Subsystem: "handling_service",
			Name:      "request_latency_microseconds",
			Help:      "Total duration of requests in microseconds.",
		}, fieldKeys)), hs)

	httpLogger := log.NewContext(logger).With("component", "http")

	mux := http.NewServeMux()

	mux.Handle("/booking/v1/", booking.MakeHandler(ctx, bs, httpLogger))
	mux.Handle("/tracking/v1/", tracking.MakeHandler(ctx, ts, httpLogger))
	mux.Handle("/handling/v1/", handling.MakeHandler(ctx, hs, httpLogger))

	http.Handle("/", accessControl(mux))
	http.Handle("/metrics", stdprometheus.Handler())

	errs := make(chan error, 2)
	go func() {
		logger.Log("transport", "http", "address", *httpAddr, "msg", "listening")
		errs <- http.ListenAndServe(*httpAddr, nil)
	}()
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT)
		errs <- fmt.Errorf("%s", <-c)
	}()

	logger.Log("terminated", <-errs)
}