Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions internal/service/domain/treecluster/treecluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ func (s *TreeClusterService) Create(ctx context.Context, createTc *domain.TreeCl
return nil, service.MapError(ctx, err, service.ErrorLogAll)
}

if err := s.UpdateWateringStatuses(ctx); err != nil {
log.Warn("failed to update watering status after creating tree cluster", "error", err, "cluster_id", c.ID)
}

if err := s.updateTreeClusterPosition(ctx, c.ID); err != nil {
log.Debug("error while update the cluster locations", "error", err, "cluster_id", c.ID)
return nil, service.MapError(ctx, err, service.ErrorLogAll)
Expand Down Expand Up @@ -177,6 +181,10 @@ func (s *TreeClusterService) Update(ctx context.Context, id int32, tcUpdate *dom
}
log.Info("tree cluster updated successfully", "cluster_id", id)

if err := s.UpdateWateringStatuses(ctx); err != nil {
log.Warn("failed to update watering status after updating tree cluster", "error", err, "cluster_id", id)
}

var eventTreeClusters []*domain.TreeCluster
if len(trees) > 0 {
eventTreeClusters = utils.Filter(utils.Map(trees, func(t *domain.Tree) *domain.TreeCluster {
Expand Down Expand Up @@ -232,27 +240,28 @@ func (s *TreeClusterService) UpdateWateringStatuses(ctx context.Context) error {

cutoffTime := time.Now().Add(-24 * time.Hour) // 1 day ago
for _, cluster := range treeClusters {
// Do nothing if watering status is not »just watered«
if cluster.WateringStatus != domain.WateringStatusJustWatered {
continue
}
var wateringStatus domain.WateringStatus

if cluster.LastWatered.Before(cutoffTime) {
wateringStatus, err := s.getWateringStatusOfTreeCluster(ctx, cluster.ID)
if cluster.Trees == nil || (cluster.Trees != nil && len(cluster.Trees) == 0) {
// tree cluster has no trees
wateringStatus = domain.WateringStatusUnknown
} else if cluster.LastWatered != nil && cluster.LastWatered.Before(cutoffTime) {
wateringStatus, err = s.getWateringStatusOfTreeCluster(ctx, cluster.ID)
if err != nil {
log.Error("failed to get watering status of cluster", "cluster_id", cluster.ID, "error", err)
return err
}
}

if wateringStatus != "" {
err = s.treeClusterRepo.Update(ctx, cluster.ID, func(tc *domain.TreeCluster, _ storage.TreeClusterRepository) (bool, error) {
tc.WateringStatus = wateringStatus
return true, nil
})

if err != nil {
log.Error("failed to update watering status of tree cluster", "cluster_id", cluster.ID, "error", err)
} else {
log.Debug("watering status of tree cluster is updated by scheduler", "cluster_id", cluster.ID)
log.Debug("watering status of tree cluster is updated", "cluster_id", cluster.ID)
}
}
}
Expand Down
44 changes: 37 additions & 7 deletions internal/service/domain/treecluster/treecluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ func TestTreeClusterService_Create(t *testing.T) {
mock.Anything,
).Return(expectedCluster, nil)

// UpdateWateringStatuses
clusterRepo.EXPECT().GetAll(mock.Anything, entities.TreeClusterQuery{}).Return(testClusters, int64(len(testClusters)), nil)

clusterRepo.EXPECT().GetAllLatestSensorDataByClusterID(
ctx,
int32(1),
Expand Down Expand Up @@ -208,6 +211,9 @@ func TestTreeClusterService_Create(t *testing.T) {
mock.Anything,
).Return(expectedCluster, nil)

// UpdateWateringStatuses
clusterRepo.EXPECT().GetAll(mock.Anything, entities.TreeClusterQuery{}).Return(testClusters, int64(len(testClusters)), nil)

clusterRepo.EXPECT().GetAllLatestSensorDataByClusterID(
ctx,
int32(2),
Expand Down Expand Up @@ -297,6 +303,9 @@ func TestTreeClusterService_Create(t *testing.T) {
mock.Anything,
).Return(expectedCluster, nil)

// UpdateWateringStatuses
clusterRepo.EXPECT().GetAll(mock.Anything, entities.TreeClusterQuery{}).Return(testClusters, int64(len(testClusters)), nil)

clusterRepo.EXPECT().GetAllLatestSensorDataByClusterID(
ctx,
int32(1),
Expand Down Expand Up @@ -390,6 +399,9 @@ func TestTreeClusterService_Update(t *testing.T) {
mock.Anything,
).Return(nil)

// UpdateWateringStatuses
clusterRepo.EXPECT().GetAll(mock.Anything, entities.TreeClusterQuery{}).Return(testClusters, int64(len(testClusters)), nil)

// when
result, err := svc.Update(ctx, clusterID, updatedCluster)

Expand Down Expand Up @@ -432,6 +444,9 @@ func TestTreeClusterService_Update(t *testing.T) {
mock.Anything,
).Return(nil)

// UpdateWateringStatuses
clusterRepo.EXPECT().GetAll(mock.Anything, entities.TreeClusterQuery{}).Return(testClusters, int64(len(testClusters)), nil)

// when
result, err := svc.Update(ctx, expectedCluster.ID, updatedClusterEmptyTrees)

Expand Down Expand Up @@ -590,6 +605,9 @@ func TestTreeClusterService_EventSystem(t *testing.T) {
mock.Anything,
).Return(nil)

// UpdateWateringStatuses
clusterRepo.EXPECT().GetAll(mock.Anything, entities.TreeClusterQuery{}).Return(testClusters, int64(len(testClusters)), nil)

svc := NewTreeClusterService(clusterRepo, treeRepo, regionRepo, eventManager)

// when
Expand Down Expand Up @@ -696,11 +714,13 @@ func TestTreeClusterService_UpdateWateringStatuses(t *testing.T) {
staleCluster := &entities.TreeCluster{
ID: 1,
LastWatered: &staleDate, // Older than 24h
Trees: testTrees,
WateringStatus: entities.WateringStatusJustWatered,
}
recentCluster := &entities.TreeCluster{
ID: 2,
LastWatered: &recentDate,
Trees: testTrees,
WateringStatus: entities.WateringStatusJustWatered,
}
expectList := []*entities.TreeCluster{staleCluster, recentCluster}
Expand All @@ -722,34 +742,43 @@ func TestTreeClusterService_UpdateWateringStatuses(t *testing.T) {
clusterRepo.AssertExpectations(t)
})

t.Run("should do nothing when there are no tree cluster with correct watering status", func(t *testing.T) {
t.Run("should update watering status to unknown when tree cluster has no trees", func(t *testing.T) {
// given
ctx := context.Background()
clusterRepo := storageMock.NewMockTreeClusterRepository(t)
treeRepo := storageMock.NewMockTreeRepository(t)
regionRepo := storageMock.NewMockRegionRepository(t)
svc := NewTreeClusterService(clusterRepo, treeRepo, regionRepo, globalEventManager)

staleDate := time.Now().Add(-34 * time.Hour)
recentDate := time.Now().Add(-2 * time.Hour)
recentCluster := &entities.TreeCluster{

staleCluster := &entities.TreeCluster{
ID: 1,
LastWatered: &staleDate, // Older than 24h
Trees: nil,
WateringStatus: entities.WateringStatusJustWatered,
}
recentCluster := &entities.TreeCluster{
ID: 2,
LastWatered: &recentDate,
Trees: nil,
WateringStatus: entities.WateringStatusJustWatered,
}

expectList := []*entities.TreeCluster{recentCluster}
expectList := []*entities.TreeCluster{staleCluster, recentCluster}

// when
clusterRepo.EXPECT().GetAll(mock.Anything, entities.TreeClusterQuery{}).Return(expectList, int64(len(expectList)), nil)
clusterRepo.EXPECT().Update(mock.Anything, staleCluster.ID, mock.Anything).Return(nil)
clusterRepo.EXPECT().Update(mock.Anything, recentCluster.ID, mock.Anything).Return(nil)

err := svc.UpdateWateringStatuses(ctx)

// then
assert.NoError(t, err)
clusterRepo.AssertCalled(t, "GetAll", mock.Anything, entities.TreeClusterQuery{})
clusterRepo.AssertNotCalled(t, "GetAllLatestSensorDataByClusterID")
clusterRepo.AssertNotCalled(t, "GetBySensorIDs")
clusterRepo.AssertNotCalled(t, "Update")
clusterRepo.AssertCalled(t, "Update", mock.Anything, staleCluster.ID, mock.Anything)
clusterRepo.AssertCalled(t, "Update", mock.Anything, recentCluster.ID, mock.Anything)
clusterRepo.AssertExpectations(t)
})

Expand Down Expand Up @@ -789,6 +818,7 @@ func TestTreeClusterService_UpdateWateringStatuses(t *testing.T) {
staleCluster := &entities.TreeCluster{
ID: 1,
LastWatered: &staleDate, // Older than 24h
Trees: testTrees,
WateringStatus: entities.WateringStatusJustWatered,
}
expectList := []*entities.TreeCluster{staleCluster}
Expand Down