supporttest

package
v1.21.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: GPL-3.0 Imports: 31 Imported by: 0

Documentation

Overview

Package supporttest is the support module's behaviour-test harness: the module's real repositories (tickets, announcements, ads and documents) and the platform's task bookkeeping the marketing tasks write, over a private in-memory SQLite database with miniredis as their cache, together with recording fakes of the module's ports onto the other domains, seeding and reading helpers, a way to make the database refuse statements, the API views of stored rows and a client for the Hertz handlers. Tests check what a flow stored and what a caller sees, not which repository call was made.

The harness builds no service: the subdomain packages, the facade and the handler tests build theirs from Env, so any of them may import it. It also gives the handler tests, which may import no other module, what they need of the identity and platform modules (a signed-in user, the task statuses). Only tests import it.

Index

Constants

View Source
const (
	ClientIP  = "203.0.113.9"
	UserAgent = "support-test/1.0"
	ActorID   = 1
)

ClientIP, UserAgent and ActorID are the request metadata Context carries.

View Source
const (
	TaskPending       = task.StatusPending
	TaskInProgress    = task.StatusInProgress
	TaskCancelled     = task.StatusCancelled
	TaskEnqueueFailed = task.StatusEnqueueFailed
)

The task statuses the marketing tasks move through, re-exported for the handler tests, which may not import the platform module.

Variables

This section is empty.

Functions

func AdView

func AdView(ad ads.Ads) dto.Ads

AdView shows a stored ad.

func AnnouncementView

func AnnouncementView(a announcement.Announcement) dto.Announcement

AnnouncementView shows a stored announcement.

func Context

func Context() context.Context

Context is a request context carrying ClientIP, UserAgent and ActorID, as the access-log and auth middlewares set them for an administrator's request.

func DocumentView

func DocumentView(d document.Document, tags ...string) dto.Document

DocumentView shows a stored document with its content as written and the tags given, which a test states rather than splitting the stored column the way the code under test does.

func EmailScope

func EmailScope(t testing.TB, row task.Task) task.EmailScope

EmailScope decodes the scope a stored email task records.

func QuotaScope

func QuotaScope(t testing.TB, row task.Task) task.QuotaScope

QuotaScope decodes the scope a stored quota task records.

func TicketView

func TicketView(t ticket.Ticket, follows ...ticket.Follow) dto.Ticket

TicketView shows a stored ticket with the follows given, in their order.

func WithMetadata

func WithMetadata(ctx context.Context) context.Context

WithMetadata returns ctx carrying the request metadata Context carries.

func WithUser

func WithUser(ctx context.Context, id int64) context.Context

WithUser returns ctx carrying the signed-in user id, as the auth middleware stores it for the user-facing endpoints.

Types

type AuditLog

type AuditLog struct {
	Rows []*log.SystemLog
	Err  error
}

AuditLog is the platform log port the administrators' mutations are recorded in: every row written, and Err failing every write.

func (*AuditLog) Actions

func (a *AuditLog) Actions(t testing.TB) []log.AdminAction

Actions decodes the administrator actions recorded so far.

func (*AuditLog) Insert

func (a *AuditLog) Insert(_ context.Context, row *log.SystemLog) error

Insert records the row.

type EmailCampaign

type EmailCampaign struct {
	Subject, Content       string
	Scope                  int8
	Recipients, Additional []string
	RegisterStartTime      int64
	RegisterEndTime        int64
	Scheduled              int64
	Interval               uint8
	Limit                  uint64
	Status                 int8
	Total, Current         uint64
	Errors                 string
}

EmailCampaign is a batch email task as the marketing service records it.

type Env

type Env struct {
	DB    *gorm.DB
	Redis *redis.Client
	Mini  *miniredis.Miniredis

	Tickets       repository.TicketRepo
	Announcements repository.AnnouncementRepo
	Ads           repository.AdsRepo
	Documents     repository.DocumentRepo
	// Tasks is the platform's task repository, which records the marketing
	// tasks.
	Tasks repository.TaskRepo
}

Env is one test's database, cache and repositories.

func New

func New(t testing.TB) *Env

New opens a fresh database with the support tables and the task tables.

func (*Env) Ad

func (e *Env) Ad(t testing.TB, row ads.Ads) *ads.Ads

Ad stores an ad as given.

func (*Env) AllTasks

func (e *Env) AllTasks(t testing.TB) []task.Task

AllTasks returns every task row in the order they were created.

func (*Env) Announcement

func (e *Env) Announcement(t testing.TB, row announcement.Announcement) *announcement.Announcement

Announcement stores an announcement; its unset flags are stored false.

func (*Env) Count

func (e *Env) Count(t testing.TB, model any) int64

Count returns how many rows the table of model holds.

func (*Env) Document

func (e *Env) Document(t testing.TB, row document.Document) *document.Document

Document stores a document; an unset switch shows it.

func (*Env) EmailTask

func (e *Env) EmailTask(t testing.TB, c EmailCampaign) int64

EmailTask stores the campaign and returns its task id.

func (*Env) Follow

func (e *Env) Follow(t testing.TB, row ticket.Follow) *ticket.Follow

Follow stores a reply on a ticket; an unset type is text.

func (*Env) Follows

func (e *Env) Follows(t testing.TB, ticketID int64) []ticket.Follow

Follows returns the replies on a ticket in the order they were written.

func (*Env) QuotaTask

func (e *Env) QuotaTask(t testing.TB, q QuotaCampaign) int64

QuotaTask stores the quota task and returns its task id; its total is the number of its objects.

func (*Env) Refuse

func (e *Env) Refuse(t testing.TB, op, table string, skip int, err error) (lift func())

Refuse makes the database refuse the statements of kind op on table with err once the first skip of them succeeded, until the test ends or the returned function lifts the refusal, so a flow's failure paths run against the real repositories. op is the GORM callback kind: "create", "query", "update", "delete" or "row" (a scanned select). A refused statement is not sent to the database.

func (*Env) ReloadAd

func (e *Env) ReloadAd(t testing.TB, id int64) ads.Ads

ReloadAd reads an ad as stored.

func (*Env) ReloadAnnouncement

func (e *Env) ReloadAnnouncement(t testing.TB, id int64) announcement.Announcement

ReloadAnnouncement reads an announcement as stored.

func (*Env) ReloadDocument

func (e *Env) ReloadDocument(t testing.TB, id int64) document.Document

ReloadDocument reads a document as stored.

func (*Env) ReloadTask

func (e *Env) ReloadTask(t testing.TB, id int64) task.Task

ReloadTask reads a task as stored.

func (*Env) ReloadTicket

func (e *Env) ReloadTicket(t testing.TB, id int64) ticket.Ticket

ReloadTicket reads a ticket as stored.

func (*Env) Task

func (e *Env) Task(t testing.TB, row task.Task) *task.Task

Task stores a task row as given.

func (*Env) TaskError

func (e *Env) TaskError(t testing.TB, row task.TaskError)

TaskError stores the failure of one target of a task.

func (*Env) TaskFailure

func (e *Env) TaskFailure(t testing.TB, taskID int64, position uint64, target, reason string, at int64)

TaskFailure stores the failure of the target at position of a task, as a worker records it.

func (*Env) Ticket

func (e *Env) Ticket(t testing.TB, row ticket.Ticket) *ticket.Ticket

Ticket stores a ticket; an unset title is "cannot connect" and an unset status Pending.

type MirroredReply

type MirroredReply struct {
	TicketID      int64
	From, Content string
}

MirroredReply is a ticket reply mirrored to the admin group.

type MirroredStatus

type MirroredStatus struct {
	TicketID int64
	Status   uint8
}

MirroredStatus is a ticket status change mirrored to the admin group.

type Notifier

type Notifier struct {
	Created  []int64
	Replies  []MirroredReply
	Statuses []MirroredStatus
}

Notifier records the ticket lifecycle the module mirrors to the Telegram admin group.

func (*Notifier) TicketCreated

func (n *Notifier) TicketCreated(_ context.Context, t *ticket.Ticket)

TicketCreated records the new ticket's id.

func (*Notifier) TicketReplied

func (n *Notifier) TicketReplied(_ context.Context, ticketID int64, from, content string)

TicketReplied records the reply.

func (*Notifier) TicketStatusChanged

func (n *Notifier) TicketStatusChanged(_ context.Context, ticketID int64, status uint8)

TicketStatusChanged records the status change.

type Queue

type Queue struct {
	Emails   []QueuedEmail
	Quotas   []int64
	Err      error
	Received func(taskID int64)
}

Queue is the marketing task queue. It records every task handed to it; Err refuses them all, and Received, when set, runs as a task arrives, before the queue answers (a worker picking the task up at once).

func (*Queue) EnqueueBatchEmail

func (q *Queue) EnqueueBatchEmail(_ context.Context, taskID int64, processAt time.Time) (string, error)

EnqueueBatchEmail records the campaign.

func (*Queue) EnqueueQuota

func (q *Queue) EnqueueQuota(_ context.Context, taskID int64) error

EnqueueQuota records the quota task.

type QueuedEmail

type QueuedEmail struct {
	TaskID    int64
	ProcessAt time.Time
}

QueuedEmail is a campaign handed to the queue and the time it is to run.

type QuotaCampaign

type QuotaCampaign struct {
	Subscribers        []int64
	IsActive           *bool
	StartTime, EndTime int64
	// Objects are the user subscriptions the task applies to.
	Objects      []int64
	ResetTraffic bool
	Days         uint64
	GiftType     uint8
	GiftValue    uint64
	Status       int8
	Current      uint64
	Errors       string
}

QuotaCampaign is a quota gift task as the marketing service records it.

type QuotaTargets

type QuotaTargets struct {
	IDs []int64
	Err error
	// Queried and Counted record the filters of the queries and counts.
	Queried []usersub.SubscribeFilter
	Counted []usersub.SubscribeFilter
}

QuotaTargets is the subscription port selecting the user subscriptions a quota task applies to: every query answers IDs, and every count their number.

func (*QuotaTargets) CountSubscribesByFilter

func (q *QuotaTargets) CountSubscribesByFilter(_ context.Context, filter *usersub.SubscribeFilter) (int64, error)

CountSubscribesByFilter answers the number of IDs.

func (*QuotaTargets) QuerySubscribeIdsByFilter

func (q *QuotaTargets) QuerySubscribeIdsByFilter(_ context.Context, filter *usersub.SubscribeFilter) ([]int64, error)

QuerySubscribeIdsByFilter answers IDs.

type Recipients

type Recipients struct {
	Emails []string
	Err    error
	// Queried and Counted record the filters of the queries and counts.
	Queried []user.EmailRecipientFilter
	Counted []user.EmailRecipientFilter
}

Recipients is the identity port selecting the recipients of an email campaign: every query answers Emails, and every count their number.

func (*Recipients) CountEmailRecipients

func (r *Recipients) CountEmailRecipients(_ context.Context, filter *user.EmailRecipientFilter) (int64, error)

CountEmailRecipients answers the number of Emails.

func (*Recipients) QueryEmailRecipients

func (r *Recipients) QueryEmailRecipients(_ context.Context, filter *user.EmailRecipientFilter) ([]string, error)

QueryEmailRecipients answers Emails.

type Reply

type Reply struct {
	Status int             `json:"-"`
	Body   string          `json:"-"`
	Code   uint32          `json:"code"`
	Msg    string          `json:"msg"`
	Data   json.RawMessage `json:"data"`
}

Reply is a handler's answer: the HTTP status, the raw body and the envelope decoded from it.

func Serve

func Serve(t testing.TB, h *server.Hertz, method, target, body string) Reply

Serve performs method target on h, with body as a JSON document or, when body is empty, with no body, and decodes the JSON envelope of the answer.

func (Reply) Decode

func (r Reply) Decode(t testing.TB, v any)

Decode fails the test unless the reply is the success envelope, and decodes its data into v.

func (Reply) OK

func (r Reply) OK(t testing.TB, want any)

OK fails the test unless the reply is the success envelope carrying want as its data: a JSON document, or a value to encode. A nil want means the envelope has no data.

func (Reply) Refused

func (r Reply) Refused(t testing.TB, code uint32, msg string)

Refused fails the test unless the reply is HTTP 200 with an error envelope of code whose message contains msg.

type Stopper

type Stopper struct {
	Stopped []int64
}

Stopper records the campaigns whose running worker it was asked to stop.

func (*Stopper) StopBatchEmail

func (s *Stopper) StopBatchEmail(taskID int64)

StopBatchEmail records the campaign.

type Subscriptions

type Subscriptions struct {
	Active map[int64]bool
	Err    error
	// Asked records the users asked about.
	Asked []int64
}

Subscriptions is the subscription port the document rendering asks: the users in Active hold an active subscription, and Err fails every question.

func Subscribed

func Subscribed(ids ...int64) *Subscriptions

Subscribed returns the port answering that exactly ids hold an active subscription.

func (*Subscriptions) HasActiveSubscription

func (s *Subscriptions) HasActiveSubscription(_ context.Context, userID int64) (bool, error)

HasActiveSubscription reports whether userID is in Active.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL