mirror of
https://github.com/miniflux/v2.git
synced 2025-08-26 18:21:01 +00:00
In general, duration is used as time unit representation. At some places when int is returned, there's no documentation which unit is used. So just convert to time.Duration ASAP.
378 lines
11 KiB
Go
378 lines
11 KiB
Go
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package model // import "miniflux.app/v2/internal/model"
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"miniflux.app/v2/internal/config"
|
|
)
|
|
|
|
const (
|
|
largeWeeklyCount = 10080
|
|
noRefreshDelay = 0
|
|
)
|
|
|
|
func TestFeedCategorySetter(t *testing.T) {
|
|
feed := &Feed{}
|
|
feed.WithCategoryID(int64(123))
|
|
|
|
if feed.Category == nil {
|
|
t.Fatal(`The category field should not be null`)
|
|
}
|
|
|
|
if feed.Category.ID != int64(123) {
|
|
t.Error(`The category ID must be set`)
|
|
}
|
|
}
|
|
|
|
func TestFeedErrorCounter(t *testing.T) {
|
|
feed := &Feed{}
|
|
feed.WithTranslatedErrorMessage("Some Error")
|
|
|
|
if feed.ParsingErrorMsg != "Some Error" {
|
|
t.Error(`The error message must be set`)
|
|
}
|
|
|
|
if feed.ParsingErrorCount != 1 {
|
|
t.Error(`The error counter must be set to 1`)
|
|
}
|
|
|
|
feed.ResetErrorCounter()
|
|
|
|
if feed.ParsingErrorMsg != "" {
|
|
t.Error(`The error message must be removed`)
|
|
}
|
|
|
|
if feed.ParsingErrorCount != 0 {
|
|
t.Error(`The error counter must be set to 0`)
|
|
}
|
|
}
|
|
|
|
func TestFeedCheckedNow(t *testing.T) {
|
|
feed := &Feed{}
|
|
feed.FeedURL = "https://example.org/feed"
|
|
feed.CheckedNow()
|
|
|
|
if feed.SiteURL != feed.FeedURL {
|
|
t.Error(`The site URL must not be empty`)
|
|
}
|
|
|
|
if feed.CheckedAt.IsZero() {
|
|
t.Error(`The checked date must be set`)
|
|
}
|
|
}
|
|
|
|
func checkTargetInterval(t *testing.T, feed *Feed, targetInterval time.Duration, timeBefore time.Time, message string) {
|
|
if feed.NextCheckAt.Before(timeBefore.Add(targetInterval)) {
|
|
t.Errorf(`The next_check_at should be after timeBefore + %s`, message)
|
|
}
|
|
if feed.NextCheckAt.After(time.Now().Add(targetInterval)) {
|
|
t.Errorf(`The next_check_at should be before now + %s`, message)
|
|
}
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckRoundRobinDefault(t *testing.T) {
|
|
os.Clearenv()
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
feed.ScheduleNextCheck(0, noRefreshDelay)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
targetInterval := config.Opts.SchedulerRoundRobinMinInterval()
|
|
checkTargetInterval(t, feed, targetInterval, timeBefore, "TestFeedScheduleNextCheckRoundRobinDefault")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckRoundRobinWithRefreshDelayAboveMinInterval(t *testing.T) {
|
|
os.Clearenv()
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
|
|
feed.ScheduleNextCheck(0, config.Opts.SchedulerRoundRobinMinInterval()+30)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
expectedInterval := config.Opts.SchedulerRoundRobinMinInterval() + 30
|
|
checkTargetInterval(t, feed, expectedInterval, timeBefore, "TestFeedScheduleNextCheckRoundRobinWithRefreshDelayAboveMinInterval")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckRoundRobinWithRefreshDelayBelowMinInterval(t *testing.T) {
|
|
os.Clearenv()
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
|
|
feed.ScheduleNextCheck(0, config.Opts.SchedulerRoundRobinMinInterval()-30)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
expectedInterval := config.Opts.SchedulerRoundRobinMinInterval()
|
|
checkTargetInterval(t, feed, expectedInterval, timeBefore, "TestFeedScheduleNextCheckRoundRobinWithRefreshDelayBelowMinInterval")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckRoundRobinWithRefreshDelayAboveMaxInterval(t *testing.T) {
|
|
os.Clearenv()
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
|
|
feed.ScheduleNextCheck(0, config.Opts.SchedulerRoundRobinMaxInterval()+30)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
expectedInterval := config.Opts.SchedulerRoundRobinMaxInterval()
|
|
checkTargetInterval(t, feed, expectedInterval, timeBefore, "TestFeedScheduleNextCheckRoundRobinWithRefreshDelayAboveMaxInterval")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckRoundRobinMinInterval(t *testing.T) {
|
|
minInterval := 1
|
|
os.Clearenv()
|
|
os.Setenv("POLLING_SCHEDULER", "round_robin")
|
|
os.Setenv("SCHEDULER_ROUND_ROBIN_MIN_INTERVAL", strconv.Itoa(minInterval))
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
feed.ScheduleNextCheck(0, noRefreshDelay)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
expectedInterval := time.Duration(minInterval) * time.Minute
|
|
checkTargetInterval(t, feed, expectedInterval, timeBefore, "TestFeedScheduleNextCheckRoundRobinMinInterval")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckEntryFrequencyMaxInterval(t *testing.T) {
|
|
maxInterval := 5
|
|
minInterval := 1
|
|
os.Clearenv()
|
|
os.Setenv("POLLING_SCHEDULER", "entry_frequency")
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL", strconv.Itoa(maxInterval))
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL", strconv.Itoa(minInterval))
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
// Use a very small weekly count to trigger the max interval
|
|
weeklyCount := 1
|
|
feed.ScheduleNextCheck(weeklyCount, noRefreshDelay)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
targetInterval := time.Duration(maxInterval) * time.Minute
|
|
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency max interval")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckEntryFrequencyMaxIntervalZeroWeeklyCount(t *testing.T) {
|
|
maxInterval := 5
|
|
minInterval := 1
|
|
os.Clearenv()
|
|
os.Setenv("POLLING_SCHEDULER", "entry_frequency")
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL", strconv.Itoa(maxInterval))
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL", strconv.Itoa(minInterval))
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
// Use a very small weekly count to trigger the max interval
|
|
weeklyCount := 0
|
|
feed.ScheduleNextCheck(weeklyCount, noRefreshDelay)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
targetInterval := time.Duration(maxInterval) * time.Minute
|
|
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency max interval")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckEntryFrequencyMinInterval(t *testing.T) {
|
|
maxInterval := 500
|
|
minInterval := 100
|
|
os.Clearenv()
|
|
os.Setenv("POLLING_SCHEDULER", "entry_frequency")
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL", strconv.Itoa(maxInterval))
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL", strconv.Itoa(minInterval))
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
// Use a very large weekly count to trigger the min interval
|
|
weeklyCount := largeWeeklyCount
|
|
feed.ScheduleNextCheck(weeklyCount, noRefreshDelay)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
targetInterval := time.Duration(minInterval) * time.Minute
|
|
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency min interval")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckEntryFrequencyFactor(t *testing.T) {
|
|
factor := 2
|
|
os.Clearenv()
|
|
os.Setenv("POLLING_SCHEDULER", "entry_frequency")
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_FACTOR", strconv.Itoa(factor))
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
weeklyCount := 7
|
|
feed.ScheduleNextCheck(weeklyCount, noRefreshDelay)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
targetInterval := config.Opts.SchedulerEntryFrequencyMaxInterval() / time.Duration(factor)
|
|
checkTargetInterval(t, feed, targetInterval, timeBefore, "factor * count")
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckEntryFrequencySmallNewTTL(t *testing.T) {
|
|
// If the feed has a TTL defined, we use it to make sure we don't check it too often.
|
|
maxInterval := 500
|
|
minInterval := 100
|
|
os.Clearenv()
|
|
os.Setenv("POLLING_SCHEDULER", "entry_frequency")
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL", strconv.Itoa(maxInterval))
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL", strconv.Itoa(minInterval))
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
// Use a very large weekly count to trigger the min interval
|
|
weeklyCount := largeWeeklyCount
|
|
// TTL is smaller than minInterval.
|
|
newTTL := time.Duration(minInterval) * time.Minute / 2
|
|
feed.ScheduleNextCheck(weeklyCount, newTTL)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
targetInterval := time.Duration(minInterval) * time.Minute
|
|
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency min interval")
|
|
|
|
if feed.NextCheckAt.Before(timeBefore.Add(newTTL)) {
|
|
t.Error(`The next_check_at should be after timeBefore + TTL`)
|
|
}
|
|
}
|
|
|
|
func TestFeedScheduleNextCheckEntryFrequencyLargeNewTTL(t *testing.T) {
|
|
// If the feed has a TTL defined, we use it to make sure we don't check it too often.
|
|
maxInterval := 500
|
|
minInterval := 100
|
|
os.Clearenv()
|
|
os.Setenv("POLLING_SCHEDULER", "entry_frequency")
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL", strconv.Itoa(maxInterval))
|
|
os.Setenv("SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL", strconv.Itoa(minInterval))
|
|
|
|
var err error
|
|
parser := config.NewParser()
|
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
|
if err != nil {
|
|
t.Fatalf(`Parsing failure: %v`, err)
|
|
}
|
|
|
|
timeBefore := time.Now()
|
|
feed := &Feed{}
|
|
// Use a very large weekly count to trigger the min interval
|
|
weeklyCount := largeWeeklyCount
|
|
// TTL is larger than minInterval.
|
|
newTTL := time.Duration(minInterval) * time.Minute * 2
|
|
feed.ScheduleNextCheck(weeklyCount, newTTL)
|
|
|
|
if feed.NextCheckAt.IsZero() {
|
|
t.Error(`The next_check_at must be set`)
|
|
}
|
|
|
|
targetInterval := newTTL
|
|
checkTargetInterval(t, feed, targetInterval, timeBefore, "TTL")
|
|
|
|
if feed.NextCheckAt.Before(timeBefore.Add(time.Minute * time.Duration(minInterval))) {
|
|
t.Error(`The next_check_at should be after timeBefore + entry frequency min interval`)
|
|
}
|
|
}
|