feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
26
spec/factories/accounts.go
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
1
spec/factories/init.go
Обычный файл
@@ -0,0 +1 @@
|
||||
package factories
|
||||
63
spec/factories/messages.go
Обычный файл
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
Обычный файл
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
Обычный файл
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(¬ification.Account).Error
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
notification.AccountID = notification.Account.ID
|
||||
}
|
||||
err := models.DB().Save(¬ification).Error
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = notification.PersistRelations()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return notification
|
||||
}
|
||||
72
spec/factories/users.go
Обычный файл
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
|
||||
}
|
||||
Ссылка в новой задаче
Block a user