happyDomain/internal/usecase/testresult/testresult_usecase.go

206 lines
7 KiB
Go

// This file is part of the happyDomain (R) project.
// Copyright (c) 2020-2026 happyDomain
// Authors: Pierre-Olivier Mercier, et al.
//
// This program is offered under a commercial and under the AGPL license.
// For commercial licensing, contact us at <contact@happydomain.org>.
//
// For AGPL licensing:
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package testresult
import (
"fmt"
"time"
"git.happydns.org/happyDomain/model"
)
// TestResultUsecase implements business logic for test results
type TestResultUsecase struct {
storage TestResultStorage
options *happydns.Options
}
// NewTestResultUsecase creates a new test result usecase
func NewTestResultUsecase(storage TestResultStorage, options *happydns.Options) *TestResultUsecase {
return &TestResultUsecase{
storage: storage,
options: options,
}
}
// ListTestResultsByTarget retrieves test results for a specific target
func (u *TestResultUsecase) ListTestResultsByTarget(pluginName string, targetType happydns.TestScopeType, targetId happydns.Identifier, limit int) ([]*happydns.TestResult, error) {
// Apply default limit if not specified
if limit <= 0 {
limit = 5 // Default to 5 most recent results
}
return u.storage.ListTestResults(pluginName, targetType, targetId, limit)
}
// ListAllTestResultsByTarget retrieves all test results for a target across all plugins
func (u *TestResultUsecase) ListAllTestResultsByTarget(targetType happydns.TestScopeType, targetId happydns.Identifier, userId happydns.Identifier, limit int) ([]*happydns.TestResult, error) {
// Get all results for the user and filter by target
allResults, err := u.storage.ListTestResultsByUser(userId, 0)
if err != nil {
return nil, err
}
// Filter by target
var results []*happydns.TestResult
for _, r := range allResults {
if r.TestType == targetType && r.TargetId.Equals(targetId) {
results = append(results, r)
}
}
// Apply limit
if limit > 0 && len(results) > limit {
results = results[:limit]
}
return results, nil
}
// GetTestResult retrieves a specific test result
func (u *TestResultUsecase) GetTestResult(pluginName string, targetType happydns.TestScopeType, targetId happydns.Identifier, resultId happydns.Identifier) (*happydns.TestResult, error) {
return u.storage.GetTestResult(pluginName, targetType, targetId, resultId)
}
// CreateTestResult stores a new test result and enforces retention policy
func (u *TestResultUsecase) CreateTestResult(result *happydns.TestResult) error {
// Store the result
if err := u.storage.CreateTestResult(result); err != nil {
return err
}
// Enforce retention policy
maxResults := u.options.MaxResultsPerTest
if maxResults <= 0 {
maxResults = 100 // Default
}
return u.storage.DeleteOldTestResults(result.PluginName, result.TestType, result.TargetId, maxResults)
}
// DeleteTestResult removes a specific test result
func (u *TestResultUsecase) DeleteTestResult(pluginName string, targetType happydns.TestScopeType, targetId happydns.Identifier, resultId happydns.Identifier) error {
return u.storage.DeleteTestResult(pluginName, targetType, targetId, resultId)
}
// DeleteAllTestResults removes all results for a specific plugin+target combination
func (u *TestResultUsecase) DeleteAllTestResults(pluginName string, targetType happydns.TestScopeType, targetId happydns.Identifier) error {
// Get all results first
results, err := u.storage.ListTestResults(pluginName, targetType, targetId, 0)
if err != nil {
return err
}
// Delete each result
for _, r := range results {
if err := u.storage.DeleteTestResult(pluginName, targetType, targetId, r.Id); err != nil {
return err
}
}
return nil
}
// CleanupOldResults removes test results older than the configured retention period
func (u *TestResultUsecase) CleanupOldResults() error {
retentionDays := u.options.ResultRetentionDays
if retentionDays <= 0 {
retentionDays = 90 // Default
}
cutoffTime := time.Now().AddDate(0, 0, -retentionDays)
return u.storage.DeleteTestResultsBefore(cutoffTime)
}
// GetTestExecution retrieves the status of a test execution
func (u *TestResultUsecase) GetTestExecution(executionId happydns.Identifier) (*happydns.TestExecution, error) {
return u.storage.GetTestExecution(executionId)
}
// CreateTestExecution creates a new test execution record
func (u *TestResultUsecase) CreateTestExecution(execution *happydns.TestExecution) error {
if execution.StartedAt.IsZero() {
execution.StartedAt = time.Now()
}
return u.storage.CreateTestExecution(execution)
}
// UpdateTestExecution updates an existing test execution
func (u *TestResultUsecase) UpdateTestExecution(execution *happydns.TestExecution) error {
return u.storage.UpdateTestExecution(execution)
}
// CompleteTestExecution marks an execution as completed with a result
func (u *TestResultUsecase) CompleteTestExecution(executionId happydns.Identifier, resultId happydns.Identifier) error {
execution, err := u.storage.GetTestExecution(executionId)
if err != nil {
return err
}
now := time.Now()
execution.Status = happydns.TestExecutionCompleted
execution.CompletedAt = &now
execution.ResultId = &resultId
return u.storage.UpdateTestExecution(execution)
}
// FailTestExecution marks an execution as failed
func (u *TestResultUsecase) FailTestExecution(executionId happydns.Identifier, errorMsg string) error {
execution, err := u.storage.GetTestExecution(executionId)
if err != nil {
return err
}
now := time.Now()
execution.Status = happydns.TestExecutionFailed
execution.CompletedAt = &now
// Store error in a result
result := &happydns.TestResult{
PluginName: execution.PluginName,
TestType: execution.TargetType,
TargetId: execution.TargetId,
OwnerId: execution.OwnerId,
ExecutedAt: time.Now(),
ScheduledTest: execution.ScheduleId != nil,
Options: execution.Options,
Status: happydns.PluginResultStatusKO,
StatusLine: "Execution failed",
Error: errorMsg,
Duration: now.Sub(execution.StartedAt),
}
if err := u.CreateTestResult(result); err != nil {
return fmt.Errorf("failed to create error result: %w", err)
}
execution.ResultId = &result.Id
return u.storage.UpdateTestExecution(execution)
}
// DeleteCompletedExecutions removes completed or failed execution records older than olderThan
func (u *TestResultUsecase) DeleteCompletedExecutions(olderThan time.Duration) error {
cutoffTime := time.Now().Add(-olderThan)
return u.storage.DeleteCompletedExecutionsBefore(cutoffTime)
}