mirror of
https://github.com/0xERR0R/blocky.git
synced 2026-10-11 21:59:54 +00:00
* fix: allow list group initialization with partial source failures When multiple list sources are configured for a blocking group, a transient error (e.g., timeout) on one source no longer fails the entire group if other sources loaded successfully. Previously, any TransientError would cause the entire group to fail initialization, even when other sources in the group had successfully loaded entries. This left users without any DNS blocking functionality. Now, groups succeed if at least one source loads successfully. Failed sources will be retried on the next refresh cycle, maintaining blocking functionality with available lists. Fixes #1825 * fix: race condition * fix lint error
80 lines
1.3 KiB
Go
80 lines
1.3 KiB
Go
package helpertest
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
const mockCallTimeout = 2 * time.Second
|
|
|
|
type MockCallSequence[T any] struct {
|
|
driver func(chan<- T, chan<- error)
|
|
res chan T
|
|
err chan error
|
|
callCount atomic.Uint32
|
|
initOnce sync.Once
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
func NewMockCallSequence[T any](driver func(chan<- T, chan<- error)) MockCallSequence[T] {
|
|
return MockCallSequence[T]{
|
|
driver: driver,
|
|
}
|
|
}
|
|
|
|
func (m *MockCallSequence[T]) Call() (T, error) {
|
|
m.callCount.Add(1)
|
|
|
|
m.initOnce.Do(func() {
|
|
m.res = make(chan T)
|
|
m.err = make(chan error)
|
|
|
|
// This goroutine never stops
|
|
go func() {
|
|
defer m.Close()
|
|
|
|
m.driver(m.res, m.err)
|
|
}()
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), mockCallTimeout)
|
|
defer cancel()
|
|
|
|
select {
|
|
case t, ok := <-m.res:
|
|
if !ok {
|
|
break
|
|
}
|
|
|
|
return t, nil
|
|
|
|
case err, ok := <-m.err:
|
|
if !ok {
|
|
break
|
|
}
|
|
|
|
var zero T
|
|
|
|
return zero, err
|
|
|
|
case <-ctx.Done():
|
|
panic(fmt.Sprintf("mock call sequence driver timed-out on call %d", m.CallCount()))
|
|
}
|
|
|
|
panic("mock call sequence called after driver returned (or sequence Close was called explicitly)")
|
|
}
|
|
|
|
func (m *MockCallSequence[T]) CallCount() uint {
|
|
return uint(m.callCount.Load())
|
|
}
|
|
|
|
func (m *MockCallSequence[T]) Close() {
|
|
m.closeOnce.Do(func() {
|
|
close(m.res)
|
|
close(m.err)
|
|
})
|
|
}
|