Files
doormile_backend/controllers/logisticsRouting_test.go

138 lines
6.2 KiB
Go

package controllers
import (
"testing"
"doormile/constants"
)
// The bulk-upload test sheet, checked against the rule that actually decides.
//
// krow_talent_app/tests/fixtures/doormile-logistics-test.xlsx carries 16 rows
// and an "Expected Routing" column saying, in words, what each one should do.
// That column is only a claim until something checks it, and the thing that
// decides is here, in Go — so it is checked here rather than restated in a
// JavaScript test, which would only prove that two copies of the rule agree
// with each other.
//
// If a row of the sheet is edited, this table is what says whether the sheet is
// still testing what it says it tests.
//
// Pickup is the sheet's single sender: Jayanthi's kitchen, Edayarpalayam,
// Coimbatore 641025.
const (
sheetPickupPincode = "641025"
sheetPickupLat = 11.0168
sheetPickupLng = 76.9558
)
func TestBulkTestSheetRoutesAsDocumented(t *testing.T) {
cases := []struct {
row int
receiver string
pincode string
lat, lng float64
wantLocal bool
wantAction string
wantConsStat string // with the hub-handover flow ON
why string
}{
// Customer -> Base. A different postal area, so the parcel cannot be
// carried to the receiver by the collecting rider.
{1, "Suresh Kumar", "600001", 13.091, 80.285, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "641 -> 600, Chennai"},
{2, "Priya Raghavan", "600028", 13.018, 80.256, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "641 -> 600, Chennai"},
{3, "Anil Reddy", "500081", 17.44, 78.3489, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "interstate, Hyderabad"},
{4, "Meera Krishnan", "500032", 17.4156, 78.3378, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "interstate with COD"},
{5, "Rahul Menon", "560001", 12.975, 77.606, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "interstate, Bengaluru"},
{6, "Divya Nair", "560066", 12.9698, 77.75, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "interstate with COD"},
{7, "Karthik Subramani", "625001", 9.9195, 78.119, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "same state, different area"},
{8, "Lakshmi Devi", "636001", 11.664, 78.146, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "same state, different area"},
// Customer -> Customer. The control group: if any of these routes to a
// base, the prefix rule has broken.
{9, "Ganesh Iyer", "641004", 11.029, 76.993, true, constants.NextActionDeliver, constants.ConsignmentOutForDelivery, "same 641 area"},
{10, "Revathi Balaji", "641012", 11.018, 76.966, true, constants.NextActionDeliver, constants.ConsignmentOutForDelivery, "same 641 area, COD"},
{11, "Vignesh Murugan", "641025", 11.008, 76.928, true, constants.NextActionDeliver, constants.ConsignmentOutForDelivery, "identical pincode"},
{12, "Anitha Selvam", "641038", 11.023, 76.945, true, constants.NextActionDeliver, constants.ConsignmentOutForDelivery, "same 641 area"},
// No pincode: the decision falls to straight-line distance. Both
// outcomes are present, because a fallback that only ever answers one
// way is not being tested.
{13, "Mohan Das", "", 11.05, 77.01, true, constants.NextActionDeliver, constants.ConsignmentOutForDelivery, "~8km, inside the 30km fallback"},
{14, "Sridhar Venkat", "", 13.0827, 80.2707, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "~430km, far outside the fallback"},
{15, "Bhavani Shankar", "64", 13.06, 80.24, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "2-digit pincode is unusable, distance decides"},
// The row that proves the prefix rule outranks distance.
{16, "Ramesh Palanisamy", "642001", 10.658, 77.008, false, constants.NextActionInwardAtHub, constants.ConsignmentCreated, "~40km but 642 is a different area"},
}
if len(cases) != 16 {
t.Fatalf("the sheet has 16 rows, this table has %d — they must not drift apart", len(cases))
}
for _, tc := range cases {
t.Run(tc.receiver, func(t *testing.T) {
gotLocal := isHyperlocalBooking(
sheetPickupPincode, tc.pincode,
sheetPickupLat, sheetPickupLng,
tc.lat, tc.lng,
)
if gotLocal != tc.wantLocal {
t.Fatalf("row %d (%s): hyperlocal = %v, want %v — %s",
tc.row, tc.receiver, gotLocal, tc.wantLocal, tc.why)
}
// What the rider is actually told to do with it, from the same
// helper pickup-complete and the queue read both use.
status := constants.ConsignmentCreated
if gotLocal {
status = constants.ConsignmentOutForDelivery
}
if status != tc.wantConsStat {
t.Errorf("row %d: consignment state %s, want %s", tc.row, status, tc.wantConsStat)
}
if got := nextActionForConsignment(status); got != tc.wantAction {
t.Errorf("row %d: next_action %s, want %s", tc.row, got, tc.wantAction)
}
})
}
}
// The sheet is only worth uploading if it actually splits both ways. A file
// that turned out to be all-hyperlocal would pass every assertion above and
// still test nothing — which is exactly the problem with the tenant's own
// export that this sheet was written to replace.
func TestBulkTestSheetExercisesBothLegs(t *testing.T) {
type dest struct {
pincode string
lat, lng float64
}
dests := []dest{
{"600001", 13.091, 80.285}, {"600028", 13.018, 80.256},
{"500081", 17.44, 78.3489}, {"500032", 17.4156, 78.3378},
{"560001", 12.975, 77.606}, {"560066", 12.9698, 77.75},
{"625001", 9.9195, 78.119}, {"636001", 11.664, 78.146},
{"641004", 11.029, 76.993}, {"641012", 11.018, 76.966},
{"641025", 11.008, 76.928}, {"641038", 11.023, 76.945},
{"", 11.05, 77.01}, {"", 13.0827, 80.2707},
{"64", 13.06, 80.24}, {"642001", 10.658, 77.008},
}
var local, hub int
for _, d := range dests {
if isHyperlocalBooking(sheetPickupPincode, d.pincode, sheetPickupLat, sheetPickupLng, d.lat, d.lng) {
local++
} else {
hub++
}
}
if hub < 5 {
t.Errorf("only %d rows route through a base — too few to exercise the handover flow", hub)
}
if local < 3 {
t.Errorf("only %d rows go direct to the customer — no control group", local)
}
t.Logf("sheet splits %d base-handover / %d direct-to-customer", hub, local)
}