307 lines
11 KiB
Go
307 lines
11 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 happydns
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// TestScopeType represents the scope level at which a test is performed
|
|
type TestScopeType int
|
|
|
|
const (
|
|
TestScopeInstance TestScopeType = iota
|
|
TestScopeUser
|
|
TestScopeDomain
|
|
TestScopeService
|
|
TestScopeOnDemand
|
|
)
|
|
|
|
// String returns a string representation of the test scope type
|
|
func (t TestScopeType) String() string {
|
|
switch t {
|
|
case TestScopeInstance:
|
|
return "instance"
|
|
case TestScopeUser:
|
|
return "user"
|
|
case TestScopeDomain:
|
|
return "domain"
|
|
case TestScopeService:
|
|
return "service"
|
|
case TestScopeOnDemand:
|
|
return "ondemand"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
// TestExecutionStatus represents the current state of a test execution
|
|
type TestExecutionStatus int
|
|
|
|
const (
|
|
TestExecutionPending TestExecutionStatus = iota
|
|
TestExecutionRunning
|
|
TestExecutionCompleted
|
|
TestExecutionFailed
|
|
)
|
|
|
|
// String returns a string representation of the test execution status
|
|
func (t TestExecutionStatus) String() string {
|
|
switch t {
|
|
case TestExecutionPending:
|
|
return "pending"
|
|
case TestExecutionRunning:
|
|
return "running"
|
|
case TestExecutionCompleted:
|
|
return "completed"
|
|
case TestExecutionFailed:
|
|
return "failed"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
// TestResult stores the result of a test execution
|
|
type TestResult struct {
|
|
// Id is the unique identifier for this test result
|
|
Id Identifier `json:"id" swaggertype:"string"`
|
|
|
|
// PluginName identifies which test plugin was executed
|
|
PluginName string `json:"plugin_name"`
|
|
|
|
// TestType indicates the scope level of the test
|
|
TestType TestScopeType `json:"test_type"`
|
|
|
|
// TargetId is the identifier of the target (User/Domain/Service)
|
|
TargetId Identifier `json:"target_id" swaggertype:"string"`
|
|
|
|
// OwnerId is the owner of the test
|
|
OwnerId Identifier `json:"owner_id" swaggertype:"string"`
|
|
|
|
// ExecutedAt is when the test was executed
|
|
ExecutedAt time.Time `json:"executed_at"`
|
|
|
|
// ScheduledTest indicates if this was a scheduled (true) or on-demand (false) test
|
|
ScheduledTest bool `json:"scheduled_test"`
|
|
|
|
// Options contains the merged plugin configuration used for this test
|
|
Options PluginOptions `json:"options,omitempty"`
|
|
|
|
// Status is the overall test result status
|
|
Status PluginResultStatus `json:"status"`
|
|
|
|
// StatusLine is a summary message of the test result
|
|
StatusLine string `json:"status_line"`
|
|
|
|
// Report contains the full test report (plugin-specific structure)
|
|
Report interface{} `json:"report,omitempty"`
|
|
|
|
// Duration is how long the test took to execute
|
|
Duration time.Duration `json:"duration" swaggertype:"integer"`
|
|
|
|
// Error contains any error message if the execution failed
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// TestSchedule defines a recurring test schedule
|
|
type TestSchedule struct {
|
|
// Id is the unique identifier for this schedule
|
|
Id Identifier `json:"id" swaggertype:"string"`
|
|
|
|
// PluginName identifies which test plugin to execute
|
|
PluginName string `json:"plugin_name"`
|
|
|
|
// OwnerId is the owner of the schedule
|
|
OwnerId Identifier `json:"owner_id" swaggertype:"string"`
|
|
|
|
// TargetType indicates what type of target to test
|
|
TargetType TestScopeType `json:"target_type"`
|
|
|
|
// TargetId is the identifier of the target to test
|
|
TargetId Identifier `json:"target_id" swaggertype:"string"`
|
|
|
|
// Interval is how often to run the test
|
|
Interval time.Duration `json:"interval" swaggertype:"integer"`
|
|
|
|
// Enabled indicates if the schedule is active
|
|
Enabled bool `json:"enabled"`
|
|
|
|
// LastRun is when the test was last executed (nil if never run)
|
|
LastRun *time.Time `json:"last_run,omitempty"`
|
|
|
|
// NextRun is when the test should next be executed
|
|
NextRun time.Time `json:"next_run"`
|
|
|
|
// Options contains plugin-specific configuration
|
|
Options PluginOptions `json:"options,omitempty"`
|
|
}
|
|
|
|
// TestExecution tracks an in-progress or completed test execution
|
|
type TestExecution struct {
|
|
// Id is the unique identifier for this execution
|
|
Id Identifier `json:"id" swaggertype:"string"`
|
|
|
|
// ScheduleId is the schedule that triggered this execution (nil for on-demand)
|
|
ScheduleId *Identifier `json:"schedule_id,omitempty" swaggertype:"string"`
|
|
|
|
// PluginName identifies which test plugin is being executed
|
|
PluginName string `json:"plugin_name"`
|
|
|
|
// OwnerId is the owner of the test
|
|
OwnerId Identifier `json:"owner_id" swaggertype:"string"`
|
|
|
|
// TargetType indicates the scope level of the test
|
|
TargetType TestScopeType `json:"target_type"`
|
|
|
|
// TargetId is the identifier of the target being tested
|
|
TargetId Identifier `json:"target_id" swaggertype:"string"`
|
|
|
|
// Status is the current execution status
|
|
Status TestExecutionStatus `json:"status"`
|
|
|
|
// StartedAt is when the execution began
|
|
StartedAt time.Time `json:"started_at"`
|
|
|
|
// CompletedAt is when the execution finished (nil if still running)
|
|
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
|
|
|
// ResultId links to the TestResult (nil if execution not completed)
|
|
ResultId *Identifier `json:"result_id,omitempty" swaggertype:"string"`
|
|
|
|
// Options contains the plugin configuration for this execution
|
|
Options PluginOptions `json:"options,omitempty"`
|
|
}
|
|
|
|
// SchedulerStatus holds a snapshot of the scheduler state for monitoring
|
|
type SchedulerStatus struct {
|
|
// ConfigEnabled indicates if the scheduler is enabled in the configuration file
|
|
ConfigEnabled bool `json:"config_enabled"`
|
|
|
|
// RuntimeEnabled indicates if the scheduler is currently enabled at runtime
|
|
RuntimeEnabled bool `json:"runtime_enabled"`
|
|
|
|
// Running indicates if the scheduler goroutine is currently running
|
|
Running bool `json:"running"`
|
|
|
|
// WorkerCount is the number of worker goroutines
|
|
WorkerCount int `json:"worker_count"`
|
|
|
|
// QueueSize is the number of items currently waiting in the execution queue
|
|
QueueSize int `json:"queue_size"`
|
|
|
|
// ActiveCount is the number of tests currently being executed
|
|
ActiveCount int `json:"active_count"`
|
|
|
|
// NextSchedules contains the upcoming scheduled tests sorted by next run time
|
|
NextSchedules []*TestSchedule `json:"next_schedules"`
|
|
}
|
|
|
|
// TestResultUsecase defines business logic for test results
|
|
type TestResultUsecase interface {
|
|
// ListTestResultsByTarget retrieves test results for a specific target
|
|
ListTestResultsByTarget(pluginName string, targetType TestScopeType, targetId Identifier, limit int) ([]*TestResult, error)
|
|
|
|
// ListAllTestResultsByTarget retrieves all test results for a target across all plugins
|
|
ListAllTestResultsByTarget(targetType TestScopeType, targetId Identifier, userId Identifier, limit int) ([]*TestResult, error)
|
|
|
|
// GetTestResult retrieves a specific test result
|
|
GetTestResult(pluginName string, targetType TestScopeType, targetId Identifier, resultId Identifier) (*TestResult, error)
|
|
|
|
// CreateTestResult stores a new test result and enforces retention policy
|
|
CreateTestResult(result *TestResult) error
|
|
|
|
// DeleteTestResult removes a specific test result
|
|
DeleteTestResult(pluginName string, targetType TestScopeType, targetId Identifier, resultId Identifier) error
|
|
|
|
// DeleteAllTestResults removes all results for a specific plugin+target combination
|
|
DeleteAllTestResults(pluginName string, targetType TestScopeType, targetId Identifier) error
|
|
|
|
// GetTestExecution retrieves the status of a test execution
|
|
GetTestExecution(executionId Identifier) (*TestExecution, error)
|
|
|
|
// CreateTestExecution creates a new test execution record
|
|
CreateTestExecution(execution *TestExecution) error
|
|
|
|
// UpdateTestExecution updates an existing test execution
|
|
UpdateTestExecution(execution *TestExecution) error
|
|
|
|
// CompleteTestExecution marks an execution as completed with a result
|
|
CompleteTestExecution(executionId Identifier, resultId Identifier) error
|
|
|
|
// FailTestExecution marks an execution as failed
|
|
FailTestExecution(executionId Identifier, errorMsg string) error
|
|
}
|
|
|
|
// TestScheduleUsecase defines business logic for test schedules
|
|
type TestScheduleUsecase interface {
|
|
// ListUserSchedules retrieves all schedules for a specific user
|
|
ListUserSchedules(userId Identifier) ([]*TestSchedule, error)
|
|
|
|
// ListSchedulesByTarget retrieves all schedules for a specific target
|
|
ListSchedulesByTarget(targetType TestScopeType, targetId Identifier) ([]*TestSchedule, error)
|
|
|
|
// GetSchedule retrieves a specific schedule by ID
|
|
GetSchedule(scheduleId Identifier) (*TestSchedule, error)
|
|
|
|
// CreateSchedule creates a new test schedule with validation
|
|
CreateSchedule(schedule *TestSchedule) error
|
|
|
|
// UpdateSchedule updates an existing schedule
|
|
UpdateSchedule(schedule *TestSchedule) error
|
|
|
|
// DeleteSchedule removes a schedule
|
|
DeleteSchedule(scheduleId Identifier) error
|
|
|
|
// EnableSchedule enables a schedule
|
|
EnableSchedule(scheduleId Identifier) error
|
|
|
|
// DisableSchedule disables a schedule
|
|
DisableSchedule(scheduleId Identifier) error
|
|
|
|
// UpdateScheduleAfterRun updates a schedule after it has been executed
|
|
UpdateScheduleAfterRun(scheduleId Identifier) error
|
|
|
|
// ListDueSchedules retrieves all enabled schedules that are due to run
|
|
ListDueSchedules() ([]*TestSchedule, error)
|
|
|
|
// ValidateScheduleOwnership checks if a user owns a schedule
|
|
ValidateScheduleOwnership(scheduleId Identifier, ownerId Identifier) error
|
|
|
|
// DeleteSchedulesForTarget removes all schedules for a target
|
|
DeleteSchedulesForTarget(targetType TestScopeType, targetId Identifier) error
|
|
|
|
// RescheduleUpcomingTests randomizes next run times for all enabled schedules
|
|
// within their respective intervals to spread load evenly.
|
|
RescheduleUpcomingTests() (int, error)
|
|
|
|
// RescheduleOverdueTests reschedules overdue tests to run soon, spread over a
|
|
// short window to avoid scheduler famine after a suspend or server restart.
|
|
RescheduleOverdueTests() (int, error)
|
|
}
|
|
|
|
// AdminSchedulerUsecase is satisfied by both testScheduler and disabledScheduler
|
|
type AdminSchedulerUsecase interface {
|
|
TriggerOnDemandTest(pluginName string, targetType TestScopeType, targetID Identifier, userID Identifier, options PluginOptions) (Identifier, error)
|
|
GetSchedulerStatus() SchedulerStatus
|
|
SetEnabled(enabled bool) error
|
|
RescheduleUpcomingTests() (int, error)
|
|
}
|