feat: publish standalone worker

Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
Gleb Tv
2026-07-13 17:55:14 +03:00
Коммит 2c7a0236da
309 изменённых файлов: 44004 добавлений и 0 удалений

26
spec/factories/accounts.go Обычный файл
Просмотреть файл

@@ -0,0 +1,26 @@
// Package factories provides functionality.
package factories
import (
"github.com/icrowley/fake"
"rsgit.ru/rsmon/rsmon/app/models"
)
// AccountFactory provides functionality.
func AccountFactory() models.Account {
account := models.Account{
Name: fake.Company(),
}
return account
}
// PersistedAccount provides functionality.
func PersistedAccount() models.Account {
account := AccountFactory()
err := models.DB().Save(&account).Error
if err != nil {
panic(err)
}
return account
}

35
spec/factories/checks.go Обычный файл
Просмотреть файл

@@ -0,0 +1,35 @@
package factories
import (
"gorm.io/datatypes"
"rsgit.ru/rsmon/rsmon/app/models"
)
// CheckFactory provides functionality.
func CheckFactory(monitor *models.Monitor, kind string) models.Check {
if monitor == nil {
panic("CheckFactory requires monitor")
}
checkName := "test check"
check := models.Check{
Name: &checkName,
Kind: kind,
Monitor: monitor,
Settings: datatypes.JSON("{}"),
}
return check
}
// PersistedCheck provides functionality.
func PersistedCheck(monitor *models.Monitor, kind string) models.Check {
check := CheckFactory(monitor, kind)
err := models.DB().Save(&check).Error
if err != nil {
panic(err)
}
return check
}

56
spec/factories/contacts.go Обычный файл
Просмотреть файл

@@ -0,0 +1,56 @@
package factories
import (
"github.com/icrowley/fake"
"rsgit.ru/rsmon/rsmon/app/models"
)
// ContactFactory provides functionality.
func ContactFactory(account *models.Account, user *models.User) models.Contact {
contact := models.Contact{
Name: fake.Company(),
}
if account == nil {
c := AccountFactory()
account = &c
}
contact.Account = account
contact.AccountID = &account.ID
if user == nil {
c := UserFactory()
user = &c
}
contact.User = user
contact.UserID = &user.ID
return contact
}
// PersistedContact provides functionality.
func PersistedContact(account *models.Account, user *models.User) models.Contact {
contact := ContactFactory(account, user)
if contact.Account.ID == 0 {
err := models.DB().Save(&contact.Account).Error
if err != nil {
panic(err)
}
contact.AccountID = &contact.Account.ID
}
if contact.User.ID == 0 {
err := models.DB().Save(&contact.User).Error
if err != nil {
panic(err)
}
contact.UserID = &contact.User.ID
}
err := models.DB().Save(&contact).Error
if err != nil {
panic(err)
}
return contact
}

38
spec/factories/events.go Обычный файл
Просмотреть файл

@@ -0,0 +1,38 @@
package factories
import (
"rsgit.ru/rsmon/rsmon/app/models"
)
// EventFactory provides functionality.
func EventFactory(monitor *models.Monitor, state, reason string) models.Event {
event := models.Event{
Monitor: monitor,
Checks: monitor.Checks,
State: state,
Errors: 10,
Oks: 0,
Reason: reason,
}
return event
}
// PersistedEvent provides functionality.
func PersistedEvent(monitor *models.Monitor, state, reason string) models.Event {
event := EventFactory(monitor, state, reason)
if event.Monitor.ID == 0 {
err := models.DB().Save(event.Monitor).Error
if err != nil {
panic(err)
}
event.MonitorID = event.Monitor.ID
}
err := models.DB().Save(&event).Error
if err != nil {
panic(err)
}
return event
}

40
spec/factories/groups.go Обычный файл
Просмотреть файл

@@ -0,0 +1,40 @@
package factories
import (
"github.com/icrowley/fake"
"rsgit.ru/rsmon/rsmon/app/models"
)
// GroupFactory provides functionality.
func GroupFactory(account *models.Account) models.Group {
group := models.Group{
Name: fake.Company(),
}
if account == nil {
c := AccountFactory()
account = &c
}
group.Account = account
group.AccountID = account.ID
return group
}
// PersistedGroup provides functionality.
func PersistedGroup(account *models.Account) models.Group {
group := GroupFactory(account)
if group.Account.ID == 0 {
err := models.DB().Save(&group.Account).Error
if err != nil {
panic(err)
}
group.AccountID = group.Account.ID
}
err := models.DB().Save(&group).Error
if err != nil {
panic(err)
}
return group
}

1
spec/factories/init.go Обычный файл
Просмотреть файл

@@ -0,0 +1 @@
package factories

63
spec/factories/messages.go Обычный файл
Просмотреть файл

@@ -0,0 +1,63 @@
package factories
import (
"time"
"github.com/lib/pq"
"rsgit.ru/rsmon/rsmon/app/models"
)
// MessageFactory provides functionality.
func MessageFactory() models.Message {
ts := time.Date(2019, time.January, 3, 3, 4, 4, 0, time.UTC)
monitor := MonitorFactory(nil, "test monitor")
check := CheckFactory(&monitor, "http")
e := "testerr"
check.Error = &e
event := models.Event{
Monitor: &monitor,
StartTime: &ts,
EndTime: nil,
Duration: 60,
Errors: 3,
Oks: 0,
State: "current",
Reason: "test error",
ChecksDown: pq.StringArray{check.Kind},
Checks: []models.Check{
check,
},
}
message := models.Message{
Contact: &models.Contact{
Kind: "email",
},
Kind: "down",
Events: []models.Event{
event,
},
}
return message
}
// ExpMessageFactory provides functionality.
func ExpMessageFactory() models.Message {
monitor := MonitorFactory(nil, "test monitor")
check := CheckFactory(&monitor, "http")
message := models.Message{
Contact: &models.Contact{
Kind: "email",
},
Kind: "exp",
Check: &check,
}
return message
}

60
spec/factories/monitors.go Обычный файл
Просмотреть файл

@@ -0,0 +1,60 @@
package factories
import (
"github.com/icrowley/fake"
"rsgit.ru/rsmon/rsmon/app/models"
)
// MonitorFactory provides functionality.
func MonitorFactory(group *models.Group, name string) models.Monitor {
if name == "" {
name = fake.Company()
}
host := fake.DomainName()
monitor := models.Monitor{
Enabled: true,
Name: &name,
Host: host,
}
if group == nil {
g := GroupFactory(nil)
group = &g
}
monitor.Group = group
monitor.GroupID = group.ID
return monitor
}
// PersistedMonitor provides functionality.
func PersistedMonitor(group *models.Group) models.Monitor {
monitor := MonitorFactory(group, "")
if monitor.Group.ID == 0 {
err := models.DB().Save(&monitor.Group).Error
if err != nil {
panic(err)
}
monitor.GroupID = monitor.Group.ID
}
err := models.DB().Save(&monitor).Error
if err != nil {
panic(err)
}
return monitor
}
// MonitorWithNotification provides functionality.
func MonitorWithNotification() (models.Contact, models.Notification, models.Monitor) {
user := PersistedUser("test@test.ru", "123")
account, err := models.CreateAccountForUser(fake.Company(), &user)
if err != nil {
panic(err)
}
contact := PersistedContact(account, &user)
group := PersistedGroup(account)
notification := PersistedNotification(account, []int64{contact.ID}, []int64{group.ID}, 300, false)
monitor := PersistedMonitor(&group)
return contact, notification, monitor
}

53
spec/factories/notifications.go Обычный файл
Просмотреть файл

@@ -0,0 +1,53 @@
package factories
import (
"github.com/icrowley/fake"
"rsgit.ru/rsmon/rsmon/app/models"
)
// NotificationFactory provides functionality.
func NotificationFactory(account *models.Account, contactIDs, groupIDs []int64, alertDelay int64, notifyRestore bool) models.Notification {
BeforeExpiration := int64(3600)
notification := models.Notification{
Name: fake.Company(),
ContactIDs: contactIDs,
GroupIDs: groupIDs,
AlertDelay: &alertDelay,
NotifyDown: true,
NotifyRestore: notifyRestore,
BeforeExpiration: &BeforeExpiration,
}
if account == nil {
c := AccountFactory()
account = &c
}
notification.Account = account
notification.AccountID = account.ID
return notification
}
// PersistedNotification provides functionality.
func PersistedNotification(account *models.Account, contactIDs, groupIDs []int64, alertDelay int64, notifyRestore bool) models.Notification { //nolint:lll
notification := NotificationFactory(account, contactIDs, groupIDs, alertDelay, notifyRestore)
if notification.Account.ID == 0 {
err := models.DB().Save(&notification.Account).Error
if err != nil {
panic(err)
}
notification.AccountID = notification.Account.ID
}
err := models.DB().Save(&notification).Error
if err != nil {
panic(err)
}
err = notification.PersistRelations()
if err != nil {
panic(err)
}
return notification
}

72
spec/factories/users.go Обычный файл
Просмотреть файл

@@ -0,0 +1,72 @@
package factories
import (
"fmt"
"os"
"strings"
"sync/atomic"
"time"
"github.com/icrowley/fake"
"rsgit.ru/rsmon/rsmon/app/models"
"rsgit.ru/rsmon/rsmon/app/models/authidentity"
)
var userCounter uint64
// processPrefix is unique per OS process so that parallel test binaries
// (e.g. notifier and sender running at the same time with go test ./...)
// do not generate duplicate email addresses when given the same base email.
var processPrefix = fmt.Sprintf("%d%d", os.Getpid(), time.Now().UnixNano()%1000000)
// UserFactory creates a new User with a random email.
func UserFactory() models.User {
email := fake.EmailAddress()
user := models.User{
Email: &email,
}
return user
}
// AuthIdentity creates an AuthIdentity for the given user.
func AuthIdentity(user *models.User, _ string) authidentity.AuthIdentity {
t := time.Now()
ai := authidentity.AuthIdentity{
Basic: authidentity.Basic{
UserID: &user.ID,
Provider: "password",
UID: *user.Email,
ConfirmedAt: &t,
},
}
return ai
}
// PersistedUser creates and persists a user with the given email and password.
func PersistedUser(email, password string) models.User {
user := UserFactory()
if email == "" {
email = fake.EmailAddress()
} else {
id := atomic.AddUint64(&userCounter, 1)
atIdx := len(email) - len(email[strings.Index(email, "@"):]) //nolint:gocritic // offBy1: strings.Index is always valid for emails
// Embed both the process prefix and counter so emails are unique across
// parallel test binaries AND across sequential calls within a binary.
email = email[:atIdx] + "+" + processPrefix + fmt.Sprintf("%d", id) + email[atIdx:]
}
user.Email = &email
err := models.DB().Save(&user).Error
if err != nil {
panic(err)
}
ai := AuthIdentity(&user, password)
err = models.DB().Save(&ai).Error
if err != nil {
panic(err)
}
return user
}