Skip to content

Commit bb31a5a

Browse files
committed
Fixed that .Switch() did not propagate errors downstream.
1 parent 5e1dcd5 commit bb31a5a

2 files changed

Lines changed: 75 additions & 36 deletions

File tree

src/DynamicData.Tests/Cache/SwitchFixture.cs

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,54 +10,83 @@
1010

1111
namespace DynamicData.Tests.Cache;
1212

13-
public class SwitchFixture : IDisposable
13+
public class SwitchFixture
1414
{
15-
private readonly ChangeSetAggregator<Person, string> _results;
16-
17-
private readonly ISourceCache<Person, string> _source;
18-
19-
private readonly ISubject<ISourceCache<Person, string>> _switchable;
20-
21-
public SwitchFixture()
22-
{
23-
_source = new SourceCache<Person, string>(p => p.Name);
24-
_switchable = new BehaviorSubject<ISourceCache<Person, string>>(_source);
25-
_results = _switchable.Switch().AsAggregator();
26-
}
27-
2815
[Fact]
2916
public void ClearsForNewSource()
3017
{
18+
using var source = new SourceCache<Person, string>(p => p.Name);
19+
using var switchable = new BehaviorSubject<ISourceCache<Person, string>>(source);
20+
var results = switchable.Switch().AsAggregator();
21+
22+
3123
var inital = Enumerable.Range(1, 100).Select(i => new Person("Person" + i, i)).ToArray();
32-
_source.AddOrUpdate(inital);
24+
source.AddOrUpdate(inital);
3325

34-
_results.Data.Count.Should().Be(100);
26+
results.Data.Count.Should().Be(100);
3527

3628
var newSource = new SourceCache<Person, string>(p => p.Name);
37-
_switchable.OnNext(newSource);
29+
switchable.OnNext(newSource);
3830

39-
_results.Data.Count.Should().Be(0);
31+
results.Data.Count.Should().Be(0);
4032

4133
newSource.AddOrUpdate(inital);
42-
_results.Data.Count.Should().Be(100);
34+
results.Data.Count.Should().Be(100);
4335

4436
var nextUpdates = Enumerable.Range(101, 100).Select(i => new Person("Person" + i, i)).ToArray();
4537
newSource.AddOrUpdate(nextUpdates);
46-
_results.Data.Count.Should().Be(200);
38+
results.Data.Count.Should().Be(200);
4739
}
4840

49-
public void Dispose()
41+
[Fact]
42+
public void PoulatesFirstSource()
5043
{
51-
_source.Dispose();
52-
_results.Dispose();
44+
using var source = new SourceCache<Person, string>(p => p.Name);
45+
using var switchable = new BehaviorSubject<ISourceCache<Person, string>>(source);
46+
var results = switchable.Switch().AsAggregator();
47+
48+
49+
var inital = Enumerable.Range(1, 100).Select(i => new Person("Person" + i, i)).ToArray();
50+
source.AddOrUpdate(inital);
51+
52+
results.Data.Count.Should().Be(100);
5353
}
5454

5555
[Fact]
56-
public void PoulatesFirstSource()
56+
public void PropagatesOuterErrors()
5757
{
58+
using var source = new SourceCache<Person, string>(p => p.Name);
59+
using var switchable = new BehaviorSubject<ISourceCache<Person, string>>(source);
60+
var results = switchable.Switch().AsAggregator();
61+
62+
63+
var inital = Enumerable.Range(1, 100).Select(i => new Person("Person" + i, i)).ToArray();
64+
source.AddOrUpdate(inital);
65+
66+
var error = new Exception("Test");
67+
switchable.OnError(error);
68+
69+
results.Error.Should().Be(error);
70+
}
71+
72+
[Fact]
73+
public void PropagatesInnerErrors()
74+
{
75+
using var source = new SourceCache<Person, string>(p => p.Name);
76+
using var switchable = new BehaviorSubject<IObservable<IChangeSet<Person, string>>>(source.Connect());
77+
var results = switchable.Switch().AsAggregator();
78+
79+
5880
var inital = Enumerable.Range(1, 100).Select(i => new Person("Person" + i, i)).ToArray();
59-
_source.AddOrUpdate(inital);
81+
source.AddOrUpdate(inital);
82+
83+
using var source2 = new BehaviorSubject<IChangeSet<Person, string>>(ChangeSet<Person, string>.Empty);
84+
85+
switchable.OnNext(source2);
86+
87+
var error = new Exception("Test");
88+
source2.OnError(error);
6089

61-
_results.Data.Count.Should().Be(100);
90+
results.Error.Should().Be(error);
6291
}
6392
}

src/DynamicData/Cache/Internal/Switch.cs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System.Reactive.Disposables;
66
using System.Reactive.Linq;
7+
using System.Reactive.Subjects;
78

89
namespace DynamicData.Cache.Internal;
910

@@ -20,16 +21,25 @@ public IObservable<IChangeSet<TObject, TKey>> Run() => Observable.Create<IChange
2021

2122
var destination = new LockFreeObservableCache<TObject, TKey>();
2223

24+
var errors = new Subject<IChangeSet<TObject, TKey>>();
25+
2326
var populator = Observable.Switch(
24-
_sources.Do(
25-
_ =>
26-
{
27-
lock (locker)
28-
{
29-
destination.Clear();
30-
}
31-
})).Synchronize(locker).PopulateInto(destination);
32-
33-
return new CompositeDisposable(destination, populator, destination.Connect().SubscribeSafe(observer));
27+
_sources
28+
.Synchronize(locker)
29+
.Do(onNext: _ => destination.Clear(),
30+
onError: error => errors.OnError(error)))
31+
.Synchronize(locker)
32+
.Do(onNext: static _ => { },
33+
onError: error => errors.OnError(error))
34+
.PopulateInto(destination);
35+
36+
return new CompositeDisposable(
37+
destination,
38+
errors,
39+
populator,
40+
Observable.Merge(
41+
destination.Connect(),
42+
errors)
43+
.SubscribeSafe(observer));
3444
});
3545
}

0 commit comments

Comments
 (0)