Merged in bugfix/errhandling (pull request #89)

Error handling

* basic
This commit is contained in:
Michael McGuinness
2025-03-05 19:49:03 +00:00
parent c78ca26a6f
commit 8f409e60a8
36 changed files with 965 additions and 641 deletions
+9 -5
View File
@@ -3,6 +3,7 @@ package doccleanrunner
import (
"context"
"encoding/json"
"log/slog"
documentclean "queryorchestration/internal/document/clean"
@@ -34,22 +35,25 @@ type Body struct {
ID uuid.UUID `json:"id" validate:"required,uuid"`
}
func (s Runner) Process(ctx context.Context, req *types.Message) error {
func (s Runner) Process(ctx context.Context, req *types.Message) bool {
var body Body
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
err = s.svc.Clean.Clean(ctx, body.ID)
if err != nil {
return err
slog.Error("unable to process", "error", err)
return false
}
return nil
return true
}
+94 -83
View File
@@ -59,97 +59,108 @@ func TestDocCleanRunner(t *testing.T) {
})
assert.NotNil(t, runner)
bod := doccleanrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(bod)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
t.Run("valid", func(t *testing.T) {
bod := doccleanrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(bod)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
doc := document.Document{
ID: bod.ID,
JobID: uuid.New(),
Hash: "example_hash",
}
inloc := document.Location{
Bucket: "bucket_name",
Key: "/i/am/here",
}
dbid := database.MustToDBUUID(doc.ID)
doc := document.Document{
ID: bod.ID,
JobID: uuid.New(),
Hash: "example_hash",
}
inloc := document.Location{
Bucket: "bucket_name",
Key: "/i/am/here",
}
dbid := database.MustToDBUUID(doc.ID)
pool.ExpectQuery("name: HasDocumentCleanEntry :one").WithArgs(dbid).WillReturnRows(
pgxmock.NewRows([]string{"isclean"}).
AddRow(false),
)
pool.ExpectQuery("name: GetDocument :one").WithArgs(dbid).
WillReturnRows(
pgxmock.NewRows([]string{"id", "jobId", "hash"}).
AddRow(dbid, database.MustToDBUUID(doc.JobID), doc.Hash),
pool.ExpectQuery("name: HasDocumentCleanEntry :one").WithArgs(dbid).WillReturnRows(
pgxmock.NewRows([]string{"isclean"}).
AddRow(false),
)
pool.ExpectQuery("name: GetDocumentEntry :one").WithArgs(dbid).WillReturnRows(
pgxmock.NewRows([]string{"documentId", "bucket", "key"}).
AddRow(dbid, inloc.Bucket, inloc.Key),
)
mimeType := "application/pdf"
dbmimetype := repository.NullCleanmimetype{
Valid: true,
Cleanmimetype: repository.Cleanmimetype(mimeType),
}
pool.ExpectBegin()
cleanid := database.MustToDBUUID(uuid.New())
pool.ExpectQuery("name: GetMostRecentDocumentCleanEntry :one").WithArgs(dbid).
WillReturnRows(
pgxmock.NewRows([]string{"id", "documentId", "bucket", "key", "version", "mimetype", "fail"}),
pool.ExpectQuery("name: GetDocument :one").WithArgs(dbid).
WillReturnRows(
pgxmock.NewRows([]string{"id", "jobId", "hash"}).
AddRow(dbid, database.MustToDBUUID(doc.JobID), doc.Hash),
)
pool.ExpectQuery("name: GetDocumentEntry :one").WithArgs(dbid).WillReturnRows(
pgxmock.NewRows([]string{"documentId", "bucket", "key"}).
AddRow(dbid, inloc.Bucket, inloc.Key),
)
pool.ExpectQuery("name: AddDocumentClean :one").WithArgs(dbid, &inloc.Bucket, &inloc.Key, dbmimetype, repository.NullCleanfailtype{}).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(cleanid),
)
pool.ExpectExec("name: AddDocumentCleanEntry :exec").WithArgs(cleanid, int32(1)).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectCommit()
mimeType := "application/pdf"
dbmimetype := repository.NullCleanmimetype{
Valid: true,
Cleanmimetype: repository.Cleanmimetype(mimeType),
}
pool.ExpectBegin()
cleanid := database.MustToDBUUID(uuid.New())
pool.ExpectQuery("name: GetMostRecentDocumentCleanEntry :one").WithArgs(dbid).
WillReturnRows(
pgxmock.NewRows([]string{"id", "documentId", "bucket", "key", "version", "mimetype", "fail"}),
)
pool.ExpectQuery("name: AddDocumentClean :one").WithArgs(dbid, &inloc.Bucket, &inloc.Key, dbmimetype, repository.NullCleanfailtype{}).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(cleanid),
)
pool.ExpectExec("name: AddDocumentCleanEntry :exec").WithArgs(cleanid, int32(1)).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectCommit()
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.DocumentTextURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", doc.ID.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.DocumentTextURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", doc.ID.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockStore.EXPECT().
HeadObject(
mock.Anything,
mock.MatchedBy(func(in *s3.HeadObjectInput) bool {
return *in.Bucket == inloc.Bucket && *in.Key == inloc.Key
}),
mock.Anything,
).
Return(&s3.HeadObjectOutput{
ContentType: &mimeType,
}, nil)
mockStore.EXPECT().
HeadObject(
mock.Anything,
mock.MatchedBy(func(in *s3.HeadObjectInput) bool {
return *in.Bucket == inloc.Bucket && *in.Key == inloc.Key
}),
mock.Anything,
).
Return(&s3.HeadObjectOutput{
ContentType: &mimeType,
}, nil)
bodyMsg := io.NopCloser(strings.NewReader(pdfHelloWorld))
mockStore.EXPECT().
GetObject(
mock.Anything,
mock.MatchedBy(func(in *s3.GetObjectInput) bool {
return *in.Bucket == inloc.Bucket && *in.Key == inloc.Key
}),
mock.Anything,
).
Return(&s3.GetObjectOutput{
Body: bodyMsg,
}, nil)
bodyMsg := io.NopCloser(strings.NewReader(pdfHelloWorld))
mockStore.EXPECT().
GetObject(
mock.Anything,
mock.MatchedBy(func(in *s3.GetObjectInput) bool {
return *in.Bucket == inloc.Bucket && *in.Key == inloc.Key
}),
mock.Anything,
).
Return(&s3.GetObjectOutput{
Body: bodyMsg,
}, nil)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}
const pdfHelloWorld = `%PDF-1.4
+43 -35
View File
@@ -3,8 +3,6 @@ package docinitrunner
import (
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"queryorchestration/internal/document"
@@ -62,54 +60,64 @@ type S3EventNotification struct {
Records []S3EventRecord `json:"Records"`
}
func (s Runner) Process(ctx context.Context, req *types.Message) error {
type S3Events string
const (
S3EventObjectCreatedPut = "ObjectCreated:Put"
)
func (s Runner) Process(ctx context.Context, req *types.Message) bool {
var body S3EventNotification
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
hasErr := false
for _, record := range body.Records {
err := func() error {
if record.EventName != "ObjectCreated:Put" {
return fmt.Errorf("invalid event name: %s", record.EventName)
}
jobID, err := s.svc.Document.GetJobIDFromKey(record.S3.Object.Key)
if err != nil {
return err
}
_, err = s.svc.Document.Create(ctx, &documentinit.Create{
JobID: jobID,
Location: document.Location{
Bucket: record.S3.Bucket.Name,
Key: record.S3.Object.Key,
},
Hash: record.S3.Object.ETag,
})
if err != nil {
return err
}
return nil
}()
err := s.processRecord(ctx, record)
if err != nil {
hasErr = true
slog.Error("Error processing record", "err", err)
slog.Error("unable to process", "error", err)
return false
}
}
if hasErr {
return errors.New("error processing records")
return true
}
func (s Runner) processRecord(ctx context.Context, record S3EventRecord) error {
if !s.isSupportedEvent(record.EventName) {
slog.Warn("unsupported event", "name", record.EventName)
return nil
}
jobID, err := s.svc.Document.GetJobIDFromKey(record.S3.Object.Key)
if err != nil {
slog.Error("unable to find job id", "key", record.S3.Object.Key, "error", err)
return nil
}
_, err = s.svc.Document.Create(ctx, &documentinit.Create{
JobID: jobID,
Location: document.Location{
Bucket: record.S3.Bucket.Name,
Key: record.S3.Object.Key,
},
Hash: record.S3.Object.ETag,
})
if err != nil {
return err
}
return nil
}
func (s Runner) isSupportedEvent(name string) bool {
return name == S3EventObjectCreatedPut
}
+178 -60
View File
@@ -1,4 +1,4 @@
package docinitrunner_test
package docinitrunner
import (
"context"
@@ -6,7 +6,6 @@ import (
"fmt"
"testing"
docinitrunner "queryorchestration/api/docInitRunner"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"queryorchestration/internal/document"
@@ -43,73 +42,192 @@ func TestDocInitRunner(t *testing.T) {
mockSQS := queuemock.NewMockSQSClient(t)
cfg.QueueClient = mockSQS
runner := docinitrunner.New(validator.New(), &docinitrunner.Services{
runner := New(validator.New(), &Services{
Document: documentinit.New(cfg),
})
assert.NotNil(t, runner)
j := job.Job{
ID: uuid.New(),
ClientID: uuid.New(),
}
bucketName := "bucketName"
location := fmt.Sprintf("%s/%s/aaa", j.ClientID.String(), j.ID.String())
docinfo := document.Document{
ID: uuid.New(),
JobID: j.ID,
Hash: "example_hash",
}
doc := docinitrunner.S3EventNotification{
Records: []docinitrunner.S3EventRecord{
{
EventName: "ObjectCreated:Put",
S3: docinitrunner.S3EventRecordDetails{
Bucket: docinitrunner.S3Bucket{
Name: bucketName,
},
Object: docinitrunner.S3Object{
Key: location,
ETag: docinfo.Hash,
t.Run("valid", func(t *testing.T) {
j := job.Job{
ID: uuid.New(),
ClientID: uuid.New(),
}
bucketName := "bucketName"
location := fmt.Sprintf("%s/%s/aaa", j.ClientID.String(), j.ID.String())
docinfo := document.Document{
ID: uuid.New(),
JobID: j.ID,
Hash: "example_hash",
}
doc := S3EventNotification{
Records: []S3EventRecord{
{
EventName: "ObjectCreated:Put",
S3: S3EventRecordDetails{
Bucket: S3Bucket{
Name: bucketName,
},
Object: S3Object{
Key: location,
ETag: docinfo.Hash,
},
},
},
},
},
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
pool.ExpectQuery("name: GetDocumentIDByHash :one").WithArgs(docinfo.Hash, database.MustToDBUUID(j.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id"}),
)
pool.ExpectBegin()
pool.ExpectQuery("name: CreateDocument :one").WithArgs(database.MustToDBUUID(j.ID), docinfo.Hash).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(docinfo.ID)),
)
pool.ExpectExec("name: AddDocumentEntry :exec").WithArgs(database.MustToDBUUID(docinfo.ID), bucketName, location).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectCommit()
pool.ExpectQuery("name: GetDocument :one").WithArgs(database.MustToDBUUID(docinfo.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "jobId", "hash"}).
AddRow(database.MustToDBUUID(docinfo.ID), database.MustToDBUUID(docinfo.JobID), "example"),
pool.ExpectQuery("name: GetDocumentIDByHash :one").WithArgs(docinfo.Hash, database.MustToDBUUID(j.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id"}),
)
pool.ExpectBegin()
pool.ExpectQuery("name: CreateDocument :one").WithArgs(database.MustToDBUUID(j.ID), docinfo.Hash).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(docinfo.ID)),
)
pool.ExpectExec("name: AddDocumentEntry :exec").WithArgs(database.MustToDBUUID(docinfo.ID), bucketName, location).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectCommit()
pool.ExpectQuery("name: GetDocument :one").WithArgs(database.MustToDBUUID(docinfo.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "jobId", "hash"}).
AddRow(database.MustToDBUUID(docinfo.ID), database.MustToDBUUID(docinfo.JobID), "example"),
)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.DocumentSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", docinfo.ID.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.DocumentSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", docinfo.ID.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}
func TestProcessRecord(t *testing.T) {
ctx := context.Background()
pool, err := pgxmock.NewPool()
require.NoError(t, err)
cfg := &DocInitConfig{}
cfg.DBPool = pool
cfg.DBQueries = repository.New(pool)
mockSQS := queuemock.NewMockSQSClient(t)
cfg.QueueClient = mockSQS
runner := New(validator.New(), &Services{
Document: documentinit.New(cfg),
})
assert.NotNil(t, runner)
t.Run("valid", func(t *testing.T) {
j := job.Job{
ID: uuid.New(),
ClientID: uuid.New(),
}
bucketName := "bucketName"
location := fmt.Sprintf("%s/%s/aaa", j.ClientID.String(), j.ID.String())
docinfo := document.Document{
ID: uuid.New(),
JobID: j.ID,
Hash: "example_hash",
}
record := S3EventRecord{
EventName: S3EventObjectCreatedPut,
S3: S3EventRecordDetails{
Bucket: S3Bucket{
Name: bucketName,
},
Object: S3Object{
Key: location,
ETag: docinfo.Hash,
},
},
}
pool.ExpectQuery("name: GetDocumentIDByHash :one").WithArgs(docinfo.Hash, database.MustToDBUUID(j.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id"}),
)
pool.ExpectBegin()
pool.ExpectQuery("name: CreateDocument :one").WithArgs(database.MustToDBUUID(j.ID), docinfo.Hash).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(docinfo.ID)),
)
pool.ExpectExec("name: AddDocumentEntry :exec").WithArgs(database.MustToDBUUID(docinfo.ID), bucketName, location).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectCommit()
pool.ExpectQuery("name: GetDocument :one").WithArgs(database.MustToDBUUID(docinfo.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "jobId", "hash"}).
AddRow(database.MustToDBUUID(docinfo.ID), database.MustToDBUUID(docinfo.JobID), "example"),
)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.DocumentSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", docinfo.ID.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
err = runner.processRecord(ctx, record)
assert.NoError(t, err)
})
t.Run("invalid_event", func(t *testing.T) {
record := S3EventRecord{
EventName: "invalid_event",
}
err = runner.processRecord(ctx, record)
assert.NoError(t, err)
})
t.Run("invalid id", func(t *testing.T) {
location := fmt.Sprintf("%s/cc/aaa", uuid.New())
record := S3EventRecord{
EventName: S3EventObjectCreatedPut,
S3: S3EventRecordDetails{
Object: S3Object{
Key: location,
},
},
}
err = runner.processRecord(ctx, record)
assert.NoError(t, err)
})
}
func TestIsSupportedEvent(t *testing.T) {
runner := Runner{}
t.Run("put", func(t *testing.T) {
assert.True(t, runner.isSupportedEvent(S3EventObjectCreatedPut))
})
t.Run("invalid", func(t *testing.T) {
assert.False(t, runner.isSupportedEvent("invalid"))
})
}
+9 -5
View File
@@ -3,6 +3,7 @@ package docsyncrunner
import (
"context"
"encoding/json"
"log/slog"
documentsync "queryorchestration/internal/document/sync"
@@ -34,22 +35,25 @@ type Body struct {
ID uuid.UUID `json:"id" validate:"required,uuid"`
}
func (s Runner) Process(ctx context.Context, req *types.Message) error {
func (s Runner) Process(ctx context.Context, req *types.Message) bool {
var body Body
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
err = s.svc.Document.Sync(ctx, body.ID)
if err != nil {
return err
slog.Error("unable to process", "error", err)
return false
}
return nil
return true
}
+42 -31
View File
@@ -48,38 +48,49 @@ func TestDocInitRunner(t *testing.T) {
})
assert.NotNil(t, runner)
j := job.Job{
ID: uuid.New(),
}
docinfo := document.Document{
ID: uuid.New(),
JobID: j.ID,
}
doc := docsyncrunner.Body{
ID: docinfo.ID,
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
t.Run("valid", func(t *testing.T) {
j := job.Job{
ID: uuid.New(),
}
docinfo := document.Document{
ID: uuid.New(),
JobID: j.ID,
}
doc := docsyncrunner.Body{
ID: docinfo.ID,
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
pool.ExpectQuery("name: GetDocument :one").WithArgs(database.MustToDBUUID(docinfo.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "jobId", "hash"}).
AddRow(database.MustToDBUUID(docinfo.ID), database.MustToDBUUID(docinfo.JobID), "example"),
)
pool.ExpectQuery("name: GetJob :one").WithArgs(database.MustToDBUUID(j.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id", "clientId", "canSync"}).
AddRow(database.MustToDBUUID(j.ID), database.MustToDBUUID(j.ClientID), j.CanSync),
)
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(j.ClientID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(j.ClientID), "client_name", true),
pool.ExpectQuery("name: GetDocument :one").WithArgs(database.MustToDBUUID(docinfo.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "jobId", "hash"}).
AddRow(database.MustToDBUUID(docinfo.ID), database.MustToDBUUID(docinfo.JobID), "example"),
)
pool.ExpectQuery("name: GetJob :one").WithArgs(database.MustToDBUUID(j.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id", "clientId", "canSync"}).
AddRow(database.MustToDBUUID(j.ID), database.MustToDBUUID(j.ClientID), j.CanSync),
)
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(j.ClientID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(j.ClientID), "client_name", true),
)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}
+9 -5
View File
@@ -3,6 +3,7 @@ package doctextrunner
import (
"context"
"encoding/json"
"log/slog"
documenttext "queryorchestration/internal/document/text"
@@ -34,22 +35,25 @@ type Body struct {
ID uuid.UUID `json:"id" validate:"required,uuid"`
}
func (s Runner) Process(ctx context.Context, req *types.Message) error {
func (s Runner) Process(ctx context.Context, req *types.Message) bool {
var body Body
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
err = s.svc.Text.Extract(ctx, body.ID)
if err != nil {
return err
slog.Error("unable to process", "error", err)
return false
}
return nil
return true
}
+55 -40
View File
@@ -51,48 +51,63 @@ func TestDocCleanRunner(t *testing.T) {
})
assert.NotNil(t, runner)
doc := doctextrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
t.Run("valid", func(t *testing.T) {
doc := doctextrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
inloc := document.Location{
Bucket: "bucket_name",
Key: "/i/am/here",
}
inloc := document.Location{
Bucket: "bucket_name",
Key: "/i/am/here",
}
pool.ExpectQuery("name: IsDocumentTextExtracted :one").WithArgs(database.MustToDBUUID(doc.ID)).WillReturnRows(
pgxmock.NewRows([]string{"isextracted"}).
AddRow(false),
)
cleanId := database.MustToDBUUID(uuid.New())
mimeType := "application/pdf"
dbmimetype := repository.NullCleanmimetype{
Valid: true,
Cleanmimetype: repository.Cleanmimetype(mimeType),
}
pool.ExpectQuery("name: GetDocumentCleanEntry :one").WithArgs(database.MustToDBUUID(doc.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id", "documentId", "bucket", "key", "version", "mimetype", "fail"}).
AddRow(cleanId, database.MustToDBUUID(doc.ID), &inloc.Bucket, &inloc.Key, int32(1), dbmimetype, repository.NullCleanfailtype{}),
)
pool.ExpectExec("name: AddDocumentTextEntry :exec").WithArgs(int32(1), inloc.Bucket, inloc.Key, cleanId).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectQuery("name: IsDocumentTextExtracted :one").WithArgs(database.MustToDBUUID(doc.ID)).WillReturnRows(
pgxmock.NewRows([]string{"isextracted"}).
AddRow(false),
)
cleanId := database.MustToDBUUID(uuid.New())
mimeType := "application/pdf"
dbmimetype := repository.NullCleanmimetype{
Valid: true,
Cleanmimetype: repository.Cleanmimetype(mimeType),
}
pool.ExpectQuery("name: GetCleanEntryByDocId :one").WithArgs(database.MustToDBUUID(doc.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id", "documentId", "bucket", "key", "version", "mimetype", "fail"}).
AddRow(cleanId, database.MustToDBUUID(doc.ID), &inloc.Bucket, &inloc.Key, int32(1), dbmimetype, repository.NullCleanfailtype{}),
)
pool.ExpectQuery("name: GetCleanEntry :one").WithArgs(cleanId).WillReturnRows(
pgxmock.NewRows([]string{"id", "documentId", "bucket", "key", "version", "mimetype", "fail"}).
AddRow(cleanId, database.MustToDBUUID(doc.ID), &inloc.Bucket, &inloc.Key, int32(1), dbmimetype, repository.NullCleanfailtype{}),
)
pool.ExpectExec("name: AddDocumentTextEntry :exec").WithArgs(int32(1), inloc.Bucket, inloc.Key, cleanId).
WillReturnResult(pgxmock.NewResult("", 1))
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.QuerySyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", doc.ID.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.QuerySyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", doc.ID.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}
+9 -5
View File
@@ -3,6 +3,7 @@ package jobsyncrunner
import (
"context"
"encoding/json"
"log/slog"
jobsync "queryorchestration/internal/job/sync"
@@ -34,22 +35,25 @@ type Body struct {
ID uuid.UUID `json:"id" validate:"required,uuid"`
}
func (s *Runner) Process(ctx context.Context, req *types.Message) error {
func (s *Runner) Process(ctx context.Context, req *types.Message) bool {
var body Body
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
err = s.svc.JobSync.Sync(ctx, body.ID)
if err != nil {
return err
slog.Error("unable to process", "error", err)
return false
}
return nil
return true
}
+38 -27
View File
@@ -49,34 +49,45 @@ func TestQueryRunner(t *testing.T) {
})
assert.NotNil(t, runner)
bod := jobsyncrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(bod)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
t.Run("valid", func(t *testing.T) {
bod := jobsyncrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(bod)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
docId := uuid.New()
docId := uuid.New()
total := int64(1)
pool.ExpectQuery("name: ListJobDocumentIDsBatch :many").WithArgs(database.MustToDBUUID(bod.ID), int32(100), int32(0)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "totalCount"}).
AddRow(database.MustToDBUUID(docId), &total),
)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.DocumentSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", docId.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
total := int64(1)
pool.ExpectQuery("name: ListJobDocumentIDsBatch :many").WithArgs(database.MustToDBUUID(bod.ID), int32(100), int32(0)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "totalCount"}).
AddRow(database.MustToDBUUID(docId), &total),
)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.DocumentSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", docId.String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}
+9 -5
View File
@@ -3,6 +3,7 @@ package queryrunner
import (
"context"
"encoding/json"
"log/slog"
resultset "queryorchestration/internal/query/result/set"
@@ -35,16 +36,18 @@ type Body struct {
QueryID uuid.UUID `json:"query_id" validate:"required,uuid"`
}
func (s *Runner) Process(ctx context.Context, req *types.Message) error {
func (s *Runner) Process(ctx context.Context, req *types.Message) bool {
var body Body
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
err = s.svc.ResultSet.Set(ctx, &resultset.Set{
@@ -52,8 +55,9 @@ func (s *Runner) Process(ctx context.Context, req *types.Message) error {
QueryID: body.QueryID,
})
if err != nil {
return err
slog.Error("unable to process", "error", err)
return false
}
return nil
return true
}
+85 -74
View File
@@ -58,85 +58,96 @@ func TestQueryRunner(t *testing.T) {
})
assert.NotNil(t, runner)
doc := resultset.Set{
DocumentID: uuid.New(),
QueryID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
t.Run("valid", func(t *testing.T) {
doc := resultset.Set{
DocumentID: uuid.New(),
QueryID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
qcfg := "{\"path\":\"examplekey\"}"
query := &resultprocessor.Query{
ID: doc.QueryID,
Version: 2,
RequiredQueryIDs: &[]uuid.UUID{uuid.New()},
Config: &qcfg,
}
params := &resultset.Set{
DocumentID: doc.DocumentID,
}
qcfg := "{\"path\":\"examplekey\"}"
query := &resultprocessor.Query{
ID: doc.QueryID,
Version: 2,
RequiredQueryIDs: &[]uuid.UUID{uuid.New()},
Config: &qcfg,
}
params := &resultset.Set{
DocumentID: doc.DocumentID,
}
cleanEntryId := uuid.New()
textEntryId := uuid.New()
pool.ExpectQuery("name: GetDocumentTextEntry :one").WithArgs(database.MustToDBUUID(params.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "documentId", "bucket", "key", "version", "cleanEntryId"}).
AddRow(database.MustToDBUUID(textEntryId), database.MustToDBUUID(params.DocumentID), "buket", "/i/am/here", int32(1), database.MustToDBUUID(cleanEntryId)),
cleanEntryId := uuid.New()
textEntryId := uuid.New()
pool.ExpectQuery("name: GetTextEntryByDocId :one").WithArgs(database.MustToDBUUID(params.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "documentId", "bucket", "key", "version", "cleanEntryId"}).
AddRow(database.MustToDBUUID(textEntryId), database.MustToDBUUID(params.DocumentID), "buket", "/i/am/here", int32(1), database.MustToDBUUID(cleanEntryId)),
)
pool.ExpectQuery("name: GetQuery :one").WithArgs(database.MustToDBUUID(query.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id", "type", "activeVersion", "latestVersion", "config", "requiredIds"}).
AddRow(database.MustToDBUUID(query.ID), repository.QuerytypeJsonExtractor, query.Version, query.Version, []byte(*query.Config), database.MustToDBUUIDArray(*query.RequiredQueryIDs)),
)
pool.ExpectQuery("name: GetQuery :one").WithArgs(database.MustToDBUUID(query.ID)).WillReturnRows(
pgxmock.NewRows([]string{"id", "type", "activeVersion", "latestVersion", "config", "requiredIds"}).
AddRow(database.MustToDBUUID(query.ID), repository.QuerytypeJsonExtractor, query.Version, query.Version, []byte(*query.Config), database.MustToDBUUIDArray(*query.RequiredQueryIDs)),
)
pool.ExpectQuery("name: GetQueryWithVersion :one").WithArgs(database.MustToDBUUID(query.ID), &query.Version).WillReturnRows(
pgxmock.NewRows([]string{"id", "type", "activeVersion", "latestVersion", "config", "requiredIds"}).
AddRow(database.MustToDBUUID(query.ID), repository.QuerytypeJsonExtractor, query.Version, query.Version, []byte(*query.Config), database.MustToDBUUIDArray(*query.RequiredQueryIDs)),
)
requiredResultId := uuid.New()
strVal := "{\"examplekey\":\"example_value\"}"
pool.ExpectQuery("name: ListQueryRequirementValues :many").WithArgs(database.MustToDBUUID(query.ID), &query.Version, database.MustToDBUUID(params.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "queryId", "type", "value"}).
AddRow(database.MustToDBUUID(requiredResultId), database.MustToDBUUID((*query.RequiredQueryIDs)[0]), repository.QuerytypeContextFull, &strVal),
pool.ExpectQuery("name: GetQueryWithVersion :one").WithArgs(database.MustToDBUUID(query.ID), &query.Version).WillReturnRows(
pgxmock.NewRows([]string{"id", "type", "activeVersion", "latestVersion", "config", "requiredIds"}).
AddRow(database.MustToDBUUID(query.ID), repository.QuerytypeJsonExtractor, query.Version, query.Version, []byte(*query.Config), database.MustToDBUUIDArray(*query.RequiredQueryIDs)),
)
pool.ExpectQuery("name: GetActiveQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID)).WillReturnRows(
pgxmock.NewRows([]string{"config"}).
AddRow([]byte(qcfg)),
)
pool.ExpectBegin()
resultId := uuid.New()
pool.ExpectQuery("name: AddResult :one").WithArgs(database.MustToDBUUID(query.ID), pgxmock.AnyArg(), database.MustToDBUUID(textEntryId), query.Version).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(resultId)),
)
pool.ExpectQuery("name: ListQueryRequirementValues :many").WithArgs(database.MustToDBUUID(query.ID), &query.Version, database.MustToDBUUID(params.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "queryId", "type", "value"}).
AddRow(database.MustToDBUUID(requiredResultId), database.MustToDBUUID((*query.RequiredQueryIDs)[0]), repository.QuerytypeContextFull, &strVal),
)
pool.ExpectExec("name: AddResultDependency :exec").WithArgs(database.MustToDBUUID(resultId), database.MustToDBUUID(requiredResultId)).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectCommit()
pool.ExpectQuery("name: ListQueryDirectDependentsByDocumentID :many").WithArgs(database.MustToDBUUID(query.ID), database.MustToDBUUID(doc.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"queryId"}).
AddRow(database.MustToDBUUID((*query.RequiredQueryIDs)[0])),
requiredResultId := uuid.New()
strVal := "{\"examplekey\":\"example_value\"}"
pool.ExpectQuery("name: ListQueryRequirementValues :many").WithArgs(database.MustToDBUUID(query.ID), &query.Version, database.MustToDBUUID(params.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "queryId", "type", "value"}).
AddRow(database.MustToDBUUID(requiredResultId), database.MustToDBUUID((*query.RequiredQueryIDs)[0]), repository.QuerytypeContextFull, &strVal),
)
pool.ExpectQuery("name: GetActiveQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID)).WillReturnRows(
pgxmock.NewRows([]string{"config"}).
AddRow([]byte(qcfg)),
)
pool.ExpectBegin()
resultId := uuid.New()
pool.ExpectQuery("name: AddResult :one").WithArgs(database.MustToDBUUID(query.ID), pgxmock.AnyArg(), database.MustToDBUUID(textEntryId), query.Version).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(resultId)),
)
pool.ExpectQuery("name: ListQueryRequirementValues :many").WithArgs(database.MustToDBUUID(query.ID), &query.Version, database.MustToDBUUID(params.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "queryId", "type", "value"}).
AddRow(database.MustToDBUUID(requiredResultId), database.MustToDBUUID((*query.RequiredQueryIDs)[0]), repository.QuerytypeContextFull, &strVal),
)
pool.ExpectExec("name: AddResultDependency :exec").WithArgs(database.MustToDBUUID(resultId), database.MustToDBUUID(requiredResultId)).
WillReturnResult(pgxmock.NewResult("", 1))
pool.ExpectCommit()
pool.ExpectQuery("name: ListQueryDirectDependentsByDocumentID :many").WithArgs(database.MustToDBUUID(query.ID), database.MustToDBUUID(doc.DocumentID)).
WillReturnRows(
pgxmock.NewRows([]string{"queryId"}).
AddRow(database.MustToDBUUID((*query.RequiredQueryIDs)[0])),
)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.QueryURL && *in.MessageBody == fmt.Sprintf("{\"document_id\":\"%s\",\"query_id\":\"%s\"}", params.DocumentID.String(), (*query.RequiredQueryIDs)[0].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.QueryURL && *in.MessageBody == fmt.Sprintf("{\"document_id\":\"%s\",\"query_id\":\"%s\"}", params.DocumentID.String(), (*query.RequiredQueryIDs)[0].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}
+9 -5
View File
@@ -3,6 +3,7 @@ package querysyncrunner
import (
"context"
"encoding/json"
"log/slog"
querysync "queryorchestration/internal/query/sync"
@@ -34,22 +35,25 @@ type Body struct {
ID uuid.UUID `json:"id" validate:"required,uuid"`
}
func (s *Runner) Process(ctx context.Context, req *types.Message) error {
func (s *Runner) Process(ctx context.Context, req *types.Message) bool {
var body Body
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
err = s.svc.QuerySync.Sync(ctx, body.ID)
if err != nil {
return err
slog.Error("unable to process", "error", err)
return false
}
return nil
return true
}
+44 -33
View File
@@ -52,41 +52,52 @@ func TestQueryRunner(t *testing.T) {
})
assert.NotNil(t, runner)
doc := querysyncrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
t.Run("valid", func(t *testing.T) {
doc := querysyncrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
qs := []uuid.UUID{
uuid.New(),
}
qs := []uuid.UUID{
uuid.New(),
}
pool.ExpectQuery("name: IsDocumentTextExtracted :one").WithArgs(database.MustToDBUUID(doc.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"isextracted"}).
AddRow(true),
)
pool.ExpectQuery("name: ListUnsyncedNoDepsQueriesByDocId :many").WithArgs(database.MustToDBUUID(doc.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(qs[0])),
)
pool.ExpectQuery("name: IsDocumentTextExtracted :one").WithArgs(database.MustToDBUUID(doc.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"isextracted"}).
AddRow(true),
)
pool.ExpectQuery("name: ListUnsyncedNoDepsQueriesByDocId :many").WithArgs(database.MustToDBUUID(doc.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(qs[0])),
)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.QueryURL && *in.MessageBody == fmt.Sprintf("{\"document_id\":\"%s\",\"query_id\":\"%s\"}", doc.ID.String(), qs[0].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.QueryURL && *in.MessageBody == fmt.Sprintf("{\"document_id\":\"%s\",\"query_id\":\"%s\"}", doc.ID.String(), qs[0].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}
+9 -5
View File
@@ -3,6 +3,7 @@ package queryversionsyncrunner
import (
"context"
"encoding/json"
"log/slog"
queryversionsync "queryorchestration/internal/query/versionsync"
@@ -34,22 +35,25 @@ type Body struct {
ID uuid.UUID `json:"id" validate:"required,uuid"`
}
func (s *Runner) Process(ctx context.Context, req *types.Message) error {
func (s *Runner) Process(ctx context.Context, req *types.Message) bool {
var body Body
err := json.Unmarshal([]byte(*req.Body), &body)
if err != nil {
return err
slog.Error("parsing body", "messageId", *req.MessageId, "body", *req.Body)
return true
}
err = s.validator.Struct(body)
if err != nil {
return err
slog.Error("invalid body", "messageId", *req.MessageId, "error", err)
return true
}
err = s.svc.Sync.Sync(ctx, body.ID)
if err != nil {
return err
slog.Error("unable to process", "error", err)
return false
}
return nil
return true
}
+50 -39
View File
@@ -49,47 +49,58 @@ func TestQueryRunner(t *testing.T) {
})
assert.NotNil(t, runner)
doc := queryversionsyncrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
t.Run("valid", func(t *testing.T) {
doc := queryversionsyncrunner.Body{
ID: uuid.New(),
}
bodyBytes, err := json.Marshal(doc)
assert.NoError(t, err)
body := string(bodyBytes)
msg := &types.Message{
Body: &body,
}
jobIds := []uuid.UUID{
uuid.New(),
uuid.New(),
}
jobIds := []uuid.UUID{
uuid.New(),
uuid.New(),
}
pool.ExpectQuery("name: ListQueryJobIDs :many").WithArgs(database.MustToDBUUID(doc.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"jobId"}).
AddRow(database.MustToDBUUID(jobIds[0])).
AddRow(database.MustToDBUUID(jobIds[1])),
)
pool.ExpectQuery("name: ListQueryJobIDs :many").WithArgs(database.MustToDBUUID(doc.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"jobId"}).
AddRow(database.MustToDBUUID(jobIds[0])).
AddRow(database.MustToDBUUID(jobIds[1])),
)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.JobSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", jobIds[0].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.JobSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", jobIds[1].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.JobSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", jobIds[0].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
mockSQS.EXPECT().
SendMessage(
mock.Anything,
mock.MatchedBy(func(in *sqs.SendMessageInput) bool {
return *in.QueueUrl == cfg.JobSyncURL && *in.MessageBody == fmt.Sprintf("{\"id\":\"%s\"}", jobIds[1].String())
}),
mock.Anything,
).
Return(&sqs.SendMessageOutput{}, nil)
err = runner.Process(ctx, msg)
assert.NoError(t, err)
assert.True(t, runner.Process(ctx, msg))
})
t.Run("invalid body", func(t *testing.T) {
body := "definitely invalid"
msgId := "id"
msg := &types.Message{
Body: &body,
MessageId: &msgId,
}
assert.True(t, runner.Process(ctx, msg))
})
}