Add unit tests for dashboard repository and enhance BSON handling
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -20,6 +20,12 @@ const noticesCollectionName = "notices"
|
||||
// keeping counts aligned with the tender panel (MinIO is the source of truth for scraped docs).
|
||||
const scrapedScopeCacheTTL = 5 * time.Minute
|
||||
|
||||
const (
|
||||
scrapedScopeResolveTimeout = 2 * time.Minute
|
||||
statisticsQueryTimeout = 2 * time.Minute
|
||||
maxScrapedFolderInClause = 5000
|
||||
)
|
||||
|
||||
// scrapedTendersScope is the resolved Mongo filter for tenders with scraped documents.
|
||||
// zero is set when MinIO reports no procedure folders; callers must return zero without querying.
|
||||
type scrapedTendersScope struct {
|
||||
@@ -28,12 +34,15 @@ type scrapedTendersScope struct {
|
||||
}
|
||||
|
||||
func (r *repository) Statistics(ctx context.Context, days int, startUnix int64) (*StatisticsReportResponse, error) {
|
||||
queryCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), statisticsQueryTimeout)
|
||||
defer cancel()
|
||||
|
||||
now := time.Now().UTC()
|
||||
endDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
|
||||
startDay := endDay.AddDate(0, 0, -(days - 1))
|
||||
|
||||
// Resolve scraped-document scope from MinIO (cached); falls back to Mongo flags on error.
|
||||
scrapedScope, err := r.cachedScrapedTendersScope(ctx)
|
||||
scrapedScope, err := r.cachedScrapedTendersScope(queryCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -46,7 +55,7 @@ func (r *repository) Statistics(ctx context.Context, days int, startUnix int64)
|
||||
totalTranslated int64
|
||||
)
|
||||
|
||||
g, gctx := errgroup.WithContext(ctx)
|
||||
g, gctx := errgroup.WithContext(queryCtx)
|
||||
|
||||
g.Go(func() error {
|
||||
// Use created_at (first ingest time). processing_metadata.scraped_at is reset on
|
||||
@@ -221,7 +230,10 @@ func (r *repository) cachedScrapedTendersScope(ctx context.Context) (scrapedTend
|
||||
}
|
||||
r.scrapedScopeMu.Unlock()
|
||||
|
||||
scope, resolveErr := r.resolveScrapedTendersScope(ctx)
|
||||
resolveCtx, cancel := context.WithTimeout(context.Background(), scrapedScopeResolveTimeout)
|
||||
defer cancel()
|
||||
|
||||
scope, resolveErr := r.resolveScrapedTendersScope(resolveCtx)
|
||||
if resolveErr != nil {
|
||||
r.logger.Warn("MinIO scraped scope unavailable, using Mongo fallback for dashboard statistics", map[string]interface{}{
|
||||
"error": resolveErr.Error(),
|
||||
@@ -250,19 +262,18 @@ func (r *repository) resolveScrapedTendersScope(ctx context.Context) (scrapedTen
|
||||
return scrapedTendersScope{}, err
|
||||
}
|
||||
if len(folderIDs) > 0 {
|
||||
if len(folderIDs) > maxScrapedFolderInClause {
|
||||
r.logger.Warn("Too many MinIO procedure folders for dashboard statistics, using Mongo fallback", map[string]interface{}{
|
||||
"folder_count": len(folderIDs),
|
||||
"max_in_clause": maxScrapedFolderInClause,
|
||||
})
|
||||
return mongoScrapedTendersScope(), nil
|
||||
}
|
||||
return scrapedTendersScope{
|
||||
match: bson.M{"contract_folder_id": bson.M{"$in": folderIDs}},
|
||||
}, nil
|
||||
}
|
||||
if r.procedureLister != nil {
|
||||
return scrapedTendersScope{zero: true}, nil
|
||||
}
|
||||
return scrapedTendersScope{
|
||||
match: bson.M{
|
||||
"processing_metadata.documents_scraped": true,
|
||||
"scraped_documents": bson.M{"$exists": true, "$ne": bson.A{}},
|
||||
},
|
||||
}, nil
|
||||
return mongoScrapedTendersScope(), nil
|
||||
}
|
||||
|
||||
func (r *repository) scrapedDocumentsFolderIDs(ctx context.Context) ([]string, error) {
|
||||
|
||||
Reference in New Issue
Block a user