2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <folly/Baton.h>
20 #include <folly/experimental/observer/SimpleObservable.h>
21 #include <folly/portability/GTest.h>
23 using namespace folly::observer;
25 TEST(Observer, Observable) {
26 SimpleObservable<int> observable(42);
27 auto observer = observable.getObserver();
29 EXPECT_EQ(42, **observer);
32 auto waitingObserver = makeObserver([observer, &baton]() {
39 observable.setValue(24);
41 EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
43 EXPECT_EQ(24, **observer);
46 TEST(Observer, MakeObserver) {
47 SimpleObservable<int> observable(42);
49 auto observer = makeObserver([child = observable.getObserver()]() {
53 EXPECT_EQ(43, **observer);
56 auto waitingObserver = makeObserver([observer, &baton]() {
63 observable.setValue(24);
65 EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
67 EXPECT_EQ(25, **observer);
70 TEST(Observer, MakeObserverDiamond) {
71 SimpleObservable<int> observable(42);
73 auto observer1 = makeObserver([child = observable.getObserver()]() {
77 auto observer2 = makeObserver([child = observable.getObserver()]() {
78 return std::make_shared<int>(**child + 2);
81 auto observer = makeObserver(
82 [observer1, observer2]() { return (**observer1) * (**observer2); });
84 EXPECT_EQ(43 * 44, *observer.getSnapshot());
87 auto waitingObserver = makeObserver([observer, &baton]() {
94 observable.setValue(24);
96 EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
98 EXPECT_EQ(25 * 26, **observer);
101 TEST(Observer, CreateException) {
102 struct ExpectedException {};
104 auto observer = makeObserver(
105 []() -> std::shared_ptr<int> { throw ExpectedException(); }),
110 makeObserver([]() -> std::shared_ptr<int> { return nullptr; }),
114 TEST(Observer, NullValue) {
115 SimpleObservable<int> observable(41);
116 auto oddObserver = makeObserver([innerObserver = observable.getObserver()]() {
117 auto value = **innerObserver;
119 if (value % 2 != 0) {
123 throw std::logic_error("I prefer odd numbers");
126 folly::Baton<> baton;
127 auto waitingObserver = makeObserver([oddObserver, &baton]() {
130 return folly::Unit();
134 EXPECT_EQ(82, **oddObserver);
136 observable.setValue(2);
138 // Waiting observer shouldn't be updated
139 EXPECT_FALSE(baton.timed_wait(std::chrono::seconds{1}));
142 EXPECT_EQ(82, **oddObserver);
144 observable.setValue(23);
146 EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
148 EXPECT_EQ(46, **oddObserver);
151 TEST(Observer, Cycle) {
152 SimpleObservable<int> observable(0);
153 auto observer = observable.getObserver();
154 folly::Optional<Observer<int>> observerB;
156 auto observerA = makeObserver([observer, &observerB]() {
157 auto value = **observer;
164 observerB = makeObserver([observerA]() { return **observerA; });
166 auto collectObserver = makeObserver([observer, observerA, &observerB]() {
167 auto value = **observer;
168 auto valueA = **observerA;
169 auto valueB = ***observerB;
173 EXPECT_EQ(0, valueB);
175 EXPECT_EQ(1, valueA);
176 EXPECT_EQ(0, valueB);
178 } else if (value == 2) {
179 EXPECT_EQ(value, valueA);
180 EXPECT_TRUE(valueB == 0 || valueB == 2);
182 EXPECT_EQ(value, valueA);
183 EXPECT_EQ(value, valueB);
189 folly::Baton<> baton;
190 auto waitingObserver = makeObserver([collectObserver, &baton]() {
193 return folly::Unit();
197 EXPECT_EQ(0, **collectObserver);
199 for (size_t i = 1; i <= 3; ++i) {
200 observable.setValue(i);
202 EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
205 EXPECT_EQ(i, **collectObserver);
209 TEST(Observer, Stress) {
210 SimpleObservable<int> observable(0);
212 folly::Synchronized<std::vector<int>> values;
214 auto observer = makeObserver([ child = observable.getObserver(), &values ]() {
215 auto value = **child * 10;
217 [&](std::vector<int>& values) { values.push_back(value); });
221 EXPECT_EQ(0, **observer);
222 values.withRLock([](const std::vector<int>& values) {
223 EXPECT_EQ(1, values.size());
224 EXPECT_EQ(0, values.back());
227 constexpr size_t numIters = 10000;
229 for (size_t i = 1; i <= numIters; ++i) {
230 observable.setValue(i);
233 while (**observer != numIters * 10) {
234 std::this_thread::yield();
237 values.withRLock([numIters = numIters](const std::vector<int>& values) {
238 EXPECT_EQ(numIters * 10, values.back());
239 EXPECT_LT(values.size(), numIters / 2);
240 EXPECT_GT(values.size(), 10);
242 for (auto value : values) {
243 EXPECT_EQ(0, value % 10);
246 for (size_t i = 0; i < values.size() - 1; ++i) {
247 EXPECT_LE(values[i], values[i + 1]);
252 TEST(Observer, TLObserver) {
253 auto createTLObserver = [](int value) {
254 return folly::observer::makeTLObserver([=] { return value; });
258 std::make_unique<folly::observer::TLObserver<int>>(createTLObserver(42));
260 k = std::make_unique<folly::observer::TLObserver<int>>(createTLObserver(41));