mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Add comprehensive geographical data models (GeographicalFeature, TransportMode, TransportProfile, TransportOption) - Implement geographical feature repository with PostGIS support and spatial queries - Create transportation service for cost calculation and route optimization - Build spatial resource matcher for geographical resource matching - Develop environmental impact service for site environmental scoring - Implement facility location optimizer with multi-criteria analysis - Add geographical data migration service for SQLite to PostgreSQL migration - Create database migrations for geographical features and site footprints - Update geospatial service integration and server initialization - Add CLI command for geographical data synchronization - Implement complete test coverage for all geographical components (28 test cases) - Update test infrastructure for geographical table creation and PostGIS handling This implements advanced geospatial capabilities including transportation cost modeling, environmental impact assessment, and facility location optimization for the Turash platform.
201 lines
8.5 KiB
Go
201 lines
8.5 KiB
Go
package service_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
"bugulma/backend/internal/geospatial"
|
|
"bugulma/backend/internal/service"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type TransportationServiceTestSuite struct {
|
|
suite.Suite
|
|
geoCalc geospatial.Calculator
|
|
svc *service.TransportationService
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) SetupTest() {
|
|
suite.geoCalc = geospatial.NewCalculatorWithDefaults()
|
|
suite.svc = service.NewTransportationService(suite.geoCalc)
|
|
}
|
|
|
|
func TestTransportationService(t *testing.T) {
|
|
suite.Run(t, new(TransportationServiceTestSuite))
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestNewTransportationService() {
|
|
assert.NotNil(suite.T(), suite.svc)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_Truck() {
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModeTruck, 15.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Verify cost calculation (Berlin to Hamburg, ~290km, truck cost ~€0.12/km)
|
|
assert.Greater(suite.T(), cost.CostEur, 30.0) // Should be around €34.80
|
|
assert.Greater(suite.T(), cost.StraightDistanceKm, 280.0)
|
|
assert.Greater(suite.T(), cost.RoadDistanceKm, cost.StraightDistanceKm) // Road distance > straight distance
|
|
assert.Greater(suite.T(), cost.TimeHours, 4.0) // Should take several hours
|
|
assert.Equal(suite.T(), domain.TransportModeTruck, cost.TransportMode)
|
|
assert.Equal(suite.T(), 1.0, cost.EnvironmentalFactor) // Truck baseline
|
|
assert.Greater(suite.T(), cost.CapacityUtilization, 50.0) // 15/25 = 60% utilization
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_Rail() {
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModeRail, 50.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Rail should be cheaper than truck
|
|
assert.Greater(suite.T(), cost.CostEur, 20.0) // Should be around €23.20 (rail €0.08/km)
|
|
assert.Equal(suite.T(), domain.TransportModeRail, cost.TransportMode)
|
|
assert.Equal(suite.T(), 0.7, cost.EnvironmentalFactor) // Rail better for environment
|
|
assert.Greater(suite.T(), cost.CapacityUtilization, 10.0) // 50/100 = 50% utilization
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_Pipeline() {
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModePipe, 500.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Pipeline should be cheapest
|
|
assert.Greater(suite.T(), cost.CostEur, 5.0) // Should be around €5.80 (pipeline €0.02/km)
|
|
assert.Equal(suite.T(), domain.TransportModePipe, cost.TransportMode)
|
|
assert.Equal(suite.T(), 0.5, cost.EnvironmentalFactor) // Pipeline best for environment
|
|
assert.Greater(suite.T(), cost.CapacityUtilization, 5.0) // 500/1000 = 50% utilization
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_VolumeExceedsCapacity() {
|
|
// Try to transport 150 tons with truck (max 25 tons)
|
|
_, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModeTruck, 150.0)
|
|
assert.Error(suite.T(), err)
|
|
assert.Contains(suite.T(), err.Error(), "transport volume exceeds capacity")
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestFindOptimalTransportRoutes() {
|
|
options, err := suite.svc.FindOptimalTransportRoutes(52.5200, 13.4050, 53.5511, 9.9937, 20.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Len(suite.T(), options, 3) // Should return all 3 transport modes
|
|
|
|
// Verify all transport modes are present
|
|
modeCount := make(map[domain.TransportMode]bool)
|
|
for _, option := range options {
|
|
modeCount[option.TransportMode] = true
|
|
}
|
|
assert.True(suite.T(), modeCount[domain.TransportModeTruck])
|
|
assert.True(suite.T(), modeCount[domain.TransportModeRail])
|
|
assert.True(suite.T(), modeCount[domain.TransportModePipe])
|
|
|
|
// Verify they're sorted by overall score (highest first)
|
|
for i := 0; i < len(options)-1; i++ {
|
|
assert.GreaterOrEqual(suite.T(), options[i].OverallScore, options[i+1].OverallScore)
|
|
}
|
|
|
|
// Pipeline should generally have the highest score due to cost and environment
|
|
// (though this depends on the exact scoring algorithm)
|
|
found := false
|
|
for _, option := range options {
|
|
if option.TransportMode == domain.TransportModePipe {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(suite.T(), found)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestFindOptimalTransportRoutes_LargeVolume() {
|
|
// Test with large volume that excludes some transport modes
|
|
options, err := suite.svc.FindOptimalTransportRoutes(52.5200, 13.4050, 53.5511, 9.9937, 150.0)
|
|
assert.NoError(suite.T(), err)
|
|
|
|
// Truck should be excluded (25 ton capacity), others should remain
|
|
for _, option := range options {
|
|
assert.NotEqual(suite.T(), domain.TransportModeTruck, option.TransportMode)
|
|
}
|
|
|
|
assert.Len(suite.T(), options, 2) // Rail and Pipeline only
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_Truck() {
|
|
profile, err := suite.svc.GetTransportProfile(domain.TransportModeTruck)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), 0.12, profile.CostPerKm)
|
|
assert.Equal(suite.T(), 60.0, profile.SpeedKmH)
|
|
assert.Equal(suite.T(), 25.0, profile.MaxCapacity)
|
|
assert.Equal(suite.T(), 1.0, profile.EnvironmentalFactor)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_Rail() {
|
|
profile, err := suite.svc.GetTransportProfile(domain.TransportModeRail)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), 0.08, profile.CostPerKm)
|
|
assert.Equal(suite.T(), 40.0, profile.SpeedKmH)
|
|
assert.Equal(suite.T(), 100.0, profile.MaxCapacity)
|
|
assert.Equal(suite.T(), 0.7, profile.EnvironmentalFactor)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_Pipeline() {
|
|
profile, err := suite.svc.GetTransportProfile(domain.TransportModePipe)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), 0.05, profile.CostPerKm)
|
|
assert.Equal(suite.T(), 100.0, profile.SpeedKmH)
|
|
assert.Equal(suite.T(), 1000.0, profile.MaxCapacity)
|
|
assert.Equal(suite.T(), 0.5, profile.EnvironmentalFactor)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_InvalidMode() {
|
|
_, err := suite.svc.GetTransportProfile(domain.TransportMode("invalid"))
|
|
assert.Error(suite.T(), err)
|
|
assert.Contains(suite.T(), err.Error(), "invalid transport mode")
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestTransportCost_SameLocation() {
|
|
// Test transport cost for same location (should still have some cost)
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 52.5200, 13.4050, domain.TransportModeTruck, 10.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Distance should be very small
|
|
assert.Less(suite.T(), cost.StraightDistanceKm, 0.1)
|
|
assert.GreaterOrEqual(suite.T(), cost.CostEur, 0.0) // Should still have some cost
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestTransportOptions_CompleteData() {
|
|
options, err := suite.svc.FindOptimalTransportRoutes(50.1109, 8.6821, 52.5200, 13.4050, 10.0) // Frankfurt to Berlin
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotEmpty(suite.T(), options)
|
|
|
|
// Verify all required fields are populated
|
|
for _, option := range options {
|
|
assert.NotEqual(suite.T(), domain.TransportMode(""), option.TransportMode)
|
|
assert.Greater(suite.T(), option.DistanceKm, 500.0) // Frankfurt to Berlin is ~550km
|
|
assert.Greater(suite.T(), option.CostEur, 10.0) // Should have meaningful cost
|
|
assert.Greater(suite.T(), option.TimeHours, 5.0) // Should take several hours
|
|
assert.GreaterOrEqual(suite.T(), option.EnvironmentalScore, 5.0) // Should have environmental score
|
|
assert.GreaterOrEqual(suite.T(), option.CapacityUtilization, 10.0) // Should have utilization percentage
|
|
assert.NotEqual(suite.T(), 0.0, option.OverallScore) // Should have overall score
|
|
}
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestEnvironmentalFactor_Impact() {
|
|
// Test that environmental factor affects scoring
|
|
options, err := suite.svc.FindOptimalTransportRoutes(52.5200, 13.4050, 53.5511, 9.9937, 10.0)
|
|
assert.NoError(suite.T(), err)
|
|
|
|
// Find pipeline option (should have highest environmental score)
|
|
var pipelineOption *domain.TransportOption
|
|
for _, option := range options {
|
|
if option.TransportMode == domain.TransportModePipe {
|
|
pipelineOption = option
|
|
break
|
|
}
|
|
}
|
|
|
|
assert.NotNil(suite.T(), pipelineOption)
|
|
assert.Equal(suite.T(), 10.0, pipelineOption.EnvironmentalScore) // Pipeline has factor 0.5, score = 10/0.5 = 10
|
|
}
|