Skip to content

Commit

Permalink
šŸ› ļø Refactor: Resume function now calls EnqueueCriteria with the propeā€¦
Browse files Browse the repository at this point in the history
ā€¦r search criteria execution id
  • Loading branch information
lhbelfanti committed Sep 28, 2024
1 parent 51c937b commit 43e59d8
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 39 deletions.
2 changes: 1 addition & 1 deletion cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func main() {
enqueueCriteria := criteria.MakeEnqueue(selectCriteriaByID, selectExecutionsByStatuses, scrapperEnqueueCriteria)

selectLastDayExecutedByCriteriaID := criteria.MakeSelectLastDayExecutedByCriteriaID(db)
resumeCriteria := criteria.MakeResume(selectCriteriaByID, selectLastDayExecutedByCriteriaID, scrapperEnqueueCriteria)
resumeCriteria := criteria.MakeResume(selectCriteriaByID, selectLastDayExecutedByCriteriaID, selectExecutionsByStatuses, scrapperEnqueueCriteria)
initCriteria := criteria.MakeInit(selectExecutionsByStatuses, resumeCriteria)

insertCriteriaExecution := criteria.MakeInsertExecution(db)
Expand Down
9 changes: 9 additions & 0 deletions cmd/api/search/criteria/daos.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ type (
Status string `json:"status"`
SearchCriteriaID int `json:"search_criteria_id"`
}

// ExecutionDayDAO represents a search criteria execution day
ExecutionDayDAO struct {
ID int `json:"id"`
ExecutionDate time.Time `json:"execution_date"`
TweetsQuantity int `json:"tweets_quantity"`
ErrorReason string `json:"error_reason"`
SearchCriteriaExecutionID int `json:"search_criteria_execution_id"`
}
)

const (
Expand Down
33 changes: 27 additions & 6 deletions cmd/api/search/criteria/enqueue.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package criteria
import (
"context"
"errors"
"time"

"ahbcc/internal/log"
"ahbcc/internal/scrapper"
Expand Down Expand Up @@ -51,26 +52,46 @@ func MakeEnqueue(selectCriteriaByID SelectByID, selectExecutionsByStatuses Selec
}

// MakeResume creates a new Resume
func MakeResume(selectCriteriaByID SelectByID, selectLastDayExecutedByCriteria SelectLastDayExecutedByCriteriaID, enqueueCriteria scrapper.EnqueueCriteria) Resume {
func MakeResume(selectCriteriaByID SelectByID, selectLastDayExecutedByCriteria SelectLastDayExecutedByCriteriaID, selectExecutionsByStatuses SelectExecutionsByStatuses, enqueueCriteria scrapper.EnqueueCriteria) Resume {
return func(ctx context.Context, criteriaID int) error {
criteriaDAO, err := selectCriteriaByID(ctx, criteriaID)
if err != nil {
log.Error(ctx, err.Error())
return FailedToExecuteSelectCriteriaByID
}

lastDayExecutedDate, err := selectLastDayExecutedByCriteria(ctx, criteriaID)
searchCriteriaExecutionID := -1
lastExecutionDayExecuted, err := selectLastDayExecutedByCriteria(ctx, criteriaID)
if err != nil {
// if err == NoExecutionDaysFoundForTheGivenCriteriaID the criteria hasnā€™t started yet, but it was enqueued once before
if !errors.Is(err, NoExecutionDaysFoundForTheGivenCriteriaID) {
log.Error(ctx, err.Error())
return FailedToExecuteSelectLastDayExecutedByCriteriaID
} else {
// The criteria hasn't started yet, but it was enqueued once before (it is in a PENDING state for example)
executionsDAO, err := selectExecutionsByStatuses(ctx, []string{PendingStatus, InProgressStatus})
if err != nil {
log.Error(ctx, err.Error())
return FailedToExecuteSelectExecutionsByStatuses
}

for _, execution := range executionsDAO {
if execution.SearchCriteriaID == criteriaID {
searchCriteriaExecutionID = execution.ID
break
}
}
}
} else { // The criteria has been executed once before and is needed to start from the last day it was executed
criteriaDAO.Since = lastDayExecutedDate
} else {
// The criteria has been executed once before and is needed to start from the next day of the last day it was executed
criteriaDAO.Since = lastExecutionDayExecuted.ExecutionDate.Add(24 * time.Hour)
searchCriteriaExecutionID = lastExecutionDayExecuted.SearchCriteriaExecutionID
}

err = enqueueCriteria(ctx, criteriaDAO.toCriteriaDTO(), 0)
if searchCriteriaExecutionID == -1 {
return FailedToRetrieveSearchCriteriaExecutionID
}

err = enqueueCriteria(ctx, criteriaDAO.toCriteriaDTO(), searchCriteriaExecutionID)
if err != nil {
log.Error(ctx, err.Error())
return FailedToExecuteEnqueueCriteria
Expand Down
74 changes: 61 additions & 13 deletions cmd/api/search/criteria/enqueue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,56 +85,104 @@ func TestEnqueue_failsWhenEnqueueCriteriaThrowsError(t *testing.T) {
assert.Equal(t, want, got)
}

func TestResume_success(t *testing.T) {
func TestResume_successWhenSelectLastDayExecutedReturnsAnExecutionDay(t *testing.T) {
mockSelectCriteriaByID := criteria.MockSelectByID(criteria.MockCriteriaDAO(), nil)
mockDate := time.Date(2024, time.September, 19, 0, 0, 0, 0, time.Local)
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(mockDate, nil)
mockExecutionDayDAO := criteria.ExecutionDayDAO{ExecutionDate: mockDate, SearchCriteriaExecutionID: 1}
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(mockExecutionDayDAO, nil)
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(criteria.MockExecutionsDAO(), nil)
mockEnqueueCriteria := scrapper.MockEnqueueCriteria(nil)

resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockSelectExecutionsByStatuses, mockEnqueueCriteria)

got := resumeCriteria(context.Background(), 2)

assert.Nil(t, got)
}

func TestResume_successWhenSelectLastDayExecutedDoesntReturnAnExecutionDay(t *testing.T) {
mockSelectCriteriaByID := criteria.MockSelectByID(criteria.MockCriteriaDAO(), nil)
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(criteria.ExecutionDayDAO{}, criteria.NoExecutionDaysFoundForTheGivenCriteriaID)
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(criteria.MockExecutionsDAO(), nil)
mockEnqueueCriteria := scrapper.MockEnqueueCriteria(nil)

resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockEnqueueCriteria)
resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockSelectExecutionsByStatuses, mockEnqueueCriteria)

got := resumeCriteria(context.Background(), 1)
got := resumeCriteria(context.Background(), 2)

assert.Nil(t, got)
}

func TestResume_failsWhenSelectCriteriaByIDThrowsError(t *testing.T) {
mockSelectCriteriaByID := criteria.MockSelectByID(criteria.MockCriteriaDAO(), errors.New("failed to execute select criteria by id"))
mockDate := time.Date(2024, time.September, 19, 0, 0, 0, 0, time.Local)
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(mockDate, nil)
mockExecutionDayDAO := criteria.ExecutionDayDAO{ExecutionDate: mockDate, SearchCriteriaExecutionID: 1}
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(mockExecutionDayDAO, nil)
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(criteria.MockExecutionsDAO(), nil)
mockEnqueueCriteria := scrapper.MockEnqueueCriteria(nil)

resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockEnqueueCriteria)
resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockSelectExecutionsByStatuses, mockEnqueueCriteria)

want := criteria.FailedToExecuteSelectCriteriaByID
got := resumeCriteria(context.Background(), 1)
got := resumeCriteria(context.Background(), 2)

assert.Equal(t, want, got)
}

func TestResume_failsWhenSelectLastDayExecutedByCriteriaThrowsError(t *testing.T) {
mockSelectCriteriaByID := criteria.MockSelectByID(criteria.MockCriteriaDAO(), nil)
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(time.Time{}, errors.New("failed to execute select last day executed by criteria id"))
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(criteria.ExecutionDayDAO{}, errors.New("failed to execute select last day executed by criteria id"))
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(criteria.MockExecutionsDAO(), nil)
mockEnqueueCriteria := scrapper.MockEnqueueCriteria(nil)

resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockEnqueueCriteria)
resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockSelectExecutionsByStatuses, mockEnqueueCriteria)

want := criteria.FailedToExecuteSelectLastDayExecutedByCriteriaID
got := resumeCriteria(context.Background(), 1)
got := resumeCriteria(context.Background(), 2)

assert.Equal(t, want, got)
}

func TestResume_failsWhenSelectExecutionsByStatusesThrowsError(t *testing.T) {
mockSelectCriteriaByID := criteria.MockSelectByID(criteria.MockCriteriaDAO(), nil)
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(criteria.ExecutionDayDAO{}, criteria.NoExecutionDaysFoundForTheGivenCriteriaID)
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(criteria.MockExecutionsDAO(), errors.New("failed to execute select executions by statuses"))
mockEnqueueCriteria := scrapper.MockEnqueueCriteria(nil)

resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockSelectExecutionsByStatuses, mockEnqueueCriteria)

want := criteria.FailedToExecuteSelectExecutionsByStatuses
got := resumeCriteria(context.Background(), 2)

assert.Equal(t, want, got)
}

func TestResume_failsWhenEnqueueCriteriaThrowsError(t *testing.T) {
mockSelectCriteriaByID := criteria.MockSelectByID(criteria.MockCriteriaDAO(), nil)
mockDate := time.Date(2024, time.September, 19, 0, 0, 0, 0, time.Local)
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(mockDate, nil)
mockExecutionDayDAO := criteria.ExecutionDayDAO{ExecutionDate: mockDate, SearchCriteriaExecutionID: 1}
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(mockExecutionDayDAO, nil)
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(criteria.MockExecutionsDAO(), nil)
mockEnqueueCriteria := scrapper.MockEnqueueCriteria(errors.New("failed to execute enqueue criteria"))

resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockEnqueueCriteria)
resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockSelectExecutionsByStatuses, mockEnqueueCriteria)

want := criteria.FailedToExecuteEnqueueCriteria
got := resumeCriteria(context.Background(), 1)
got := resumeCriteria(context.Background(), 2)

assert.Equal(t, want, got)
}

func TestResume_failsWhenSelectLastDayExecutedDoesntReturnAnExecutionDayAndTheExecutionsInTheDBDoesntBelongToTheCriteria(t *testing.T) {
mockSelectCriteriaByID := criteria.MockSelectByID(criteria.MockCriteriaDAO(), nil)
mockSelectLastDayExecutedByCriteriaID := criteria.MockSelectLastDayExecutedByCriteriaID(criteria.ExecutionDayDAO{}, criteria.NoExecutionDaysFoundForTheGivenCriteriaID)
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(criteria.MockExecutionsDAO(), nil)
mockEnqueueCriteria := scrapper.MockEnqueueCriteria(nil)

resumeCriteria := criteria.MakeResume(mockSelectCriteriaByID, mockSelectLastDayExecutedByCriteriaID, mockSelectExecutionsByStatuses, mockEnqueueCriteria)

want := criteria.FailedToRetrieveSearchCriteriaExecutionID
got := resumeCriteria(context.Background(), 9999) // some random number for a criteria that is not present in the DB

assert.Equal(t, got, want)
}
1 change: 1 addition & 0 deletions cmd/api/search/criteria/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
FailedToExecuteSelectExecutionsByStatuses = errors.New("failed to execute select executions by statuses")
AnExecutionOfThisCriteriaIDIsAlreadyEnqueued = errors.New("an execution of this criteria is already enqueued")
FailedToExecuteEnqueueCriteria = errors.New("failed to execute enqueue criteria")
FailedToRetrieveSearchCriteriaExecutionID = errors.New("failed to retrieve search criteria execution id")

FailedToInsertSearchCriteriaExecution = errors.New("failed to insert search criteria execution")
FailedToUpdateSearchCriteriaExecution = errors.New("failed to update search criteria execution")
Expand Down
10 changes: 8 additions & 2 deletions cmd/api/search/criteria/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package criteria

import (
"context"
"errors"

"ahbcc/internal/log"
)
Expand All @@ -21,8 +22,13 @@ func MakeInit(selectExecutionsByStatuses SelectExecutionsByStatuses, resume Resu
for _, execution := range executionsDAO {
err = resume(ctx, execution.SearchCriteriaID)
if err != nil {
log.Error(ctx, err.Error())
return FailedToExecuteEnqueueCriteria
if !errors.Is(err, FailedToRetrieveSearchCriteriaExecutionID) {
log.Error(ctx, err.Error())
return FailedToExecuteEnqueueCriteria
} else {
// If the search criteria does not have an active execution, there is nothing to enqueue
continue
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions cmd/api/search/criteria/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ func TestInit_success(t *testing.T) {
assert.Nil(t, got)
}

func TestInit_successWhenResumeThrowsErrorFailedToRetrieveSearchCriteriaExecutionID(t *testing.T) {
mockExecutionsDAO := criteria.MockExecutionsDAO()
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(mockExecutionsDAO, nil)
mockResume := criteria.MockResume(criteria.FailedToRetrieveSearchCriteriaExecutionID)

init := criteria.MakeInit(mockSelectExecutionsByStatuses, mockResume)

got := init(context.Background())

assert.Nil(t, got)
}

func TestInit_failsWhenSelectExecutionsByStatusesThrowsError(t *testing.T) {
mockSelectExecutionsByStatuses := criteria.MockSelectExecutionsByStatuses(nil, errors.New("failed while executing select executions by statuses"))
mockResume := criteria.MockResume(nil)
Expand Down
4 changes: 2 additions & 2 deletions cmd/api/search/criteria/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func MockSelectExecutionsByStatuses(executionsDAO []ExecutionDAO, err error) Sel
}

// MockSelectLastDayExecutedByCriteriaID mocks SelectLastDayExecutedByCriteriaID function
func MockSelectLastDayExecutedByCriteriaID(lastDayExecuted time.Time, err error) SelectLastDayExecutedByCriteriaID {
return func(ctx context.Context, id int) (time.Time, error) {
func MockSelectLastDayExecutedByCriteriaID(lastDayExecuted ExecutionDayDAO, err error) SelectLastDayExecutedByCriteriaID {
return func(ctx context.Context, id int) (ExecutionDayDAO, error) {
return lastDayExecuted, err
}
}
Expand Down
23 changes: 12 additions & 11 deletions cmd/api/search/criteria/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"

"github.com/jackc/pgx/v5"
"strings"

"ahbcc/internal/database"
"ahbcc/internal/log"
Expand All @@ -24,7 +22,7 @@ type (
SelectExecutionsByStatuses func(ctx context.Context, statuses []string) ([]ExecutionDAO, error)

// SelectLastDayExecutedByCriteriaID returns the last day executed for the given criteria
SelectLastDayExecutedByCriteriaID func(ctx context.Context, id int) (time.Time, error)
SelectLastDayExecutedByCriteriaID func(ctx context.Context, id int) (ExecutionDayDAO, error)
)

// MakeSelectByID creates a new SelectByID
Expand Down Expand Up @@ -122,7 +120,7 @@ func MakeSelectExecutionsByStatuses(db database.Connection, collectRows database
// MakeSelectLastDayExecutedByCriteriaID creates a new SelectLastDayExecutedByCriteriaID
func MakeSelectLastDayExecutedByCriteriaID(db database.Connection) SelectLastDayExecutedByCriteriaID {
const query string = `
SELECT sced.execution_date
SELECT sced.execution_date, sced.search_criteria_execution_id
FROM search_criteria_execution_days sced
JOIN search_criteria_executions sce
ON sced.search_criteria_execution_id = sce.id
Expand All @@ -131,17 +129,20 @@ func MakeSelectLastDayExecutedByCriteriaID(db database.Connection) SelectLastDay
LIMIT 1;
`

return func(ctx context.Context, criteriaID int) (time.Time, error) {
var lastDayExecutedDate time.Time
err := db.QueryRow(ctx, query, criteriaID).Scan(&lastDayExecutedDate)
return func(ctx context.Context, criteriaID int) (ExecutionDayDAO, error) {
var lastExecutionDayExecuted ExecutionDayDAO
err := db.QueryRow(ctx, query, criteriaID).Scan(
&lastExecutionDayExecuted.ExecutionDate,
&lastExecutionDayExecuted.SearchCriteriaExecutionID,
)
if errors.Is(err, pgx.ErrNoRows) {
log.Error(ctx, err.Error())
return time.Time{}, NoExecutionDaysFoundForTheGivenCriteriaID
return ExecutionDayDAO{}, NoExecutionDaysFoundForTheGivenCriteriaID
} else if err != nil {
log.Error(ctx, err.Error())
return time.Time{}, FailedToRetrieveLastDayExecutedDate
return ExecutionDayDAO{}, FailedToRetrieveLastDayExecutedDate
}

return lastDayExecutedDate, nil
return lastExecutionDayExecuted, nil
}
}
9 changes: 5 additions & 4 deletions cmd/api/search/criteria/select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,17 @@ func TestSelectExecutionsByStatuses_failsWhenCollectRowsThrowsError(t *testing.T
mockPgxRows.AssertExpectations(t)
}

func TestSelectLastDayExecutedByCriteriaID_success(t *testing.T) {
func TestSelectLastExecutionDayExecutedByCriteriaID_success(t *testing.T) {
mockPostgresConnection := new(database.MockPostgresConnection)
mockPgxRow := new(database.MockPgxRow)
mockDate := time.Date(2024, 9, 19, 0, 0, 0, 0, time.Local)
database.MockScan(mockPgxRow, []any{mockDate}, t)
mockExecutionID := 1
database.MockScan(mockPgxRow, []any{mockDate, mockExecutionID}, t)
mockPostgresConnection.On("QueryRow", mock.Anything, mock.Anything, mock.Anything).Return(mockPgxRow)

selectLastDayExecutedByCriteriaID := criteria.MakeSelectLastDayExecutedByCriteriaID(mockPostgresConnection)

want := mockDate
want := criteria.ExecutionDayDAO{ExecutionDate: mockDate, SearchCriteriaExecutionID: mockExecutionID}
got, err := selectLastDayExecutedByCriteriaID(context.Background(), 1)

assert.Nil(t, err)
Expand All @@ -180,7 +181,7 @@ func TestSelectLastDayExecutedByCriteriaID_success(t *testing.T) {
mockPgxRow.AssertExpectations(t)
}

func TestSelectLastDayExecutedByCriteriaID_failsWhenSelectOperationFails(t *testing.T) {
func TestSelectLastExecutionDayExecutedByCriteriaID_failsWhenSelectOperationFails(t *testing.T) {
tests := []struct {
err error
expected error
Expand Down

0 comments on commit 43e59d8

Please sign in to comment.