• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#   Copyright 2019 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import logging
18import time
19import traceback
20from datetime import datetime, timedelta
21from threading import Timer
22
23from blueberry.tests.gd.cert.behavior import when, wait_until
24from blueberry.tests.gd.cert.behavior import IHasBehaviors
25from blueberry.tests.gd.cert.behavior import anything
26from blueberry.tests.gd.cert.behavior import SingleArgumentBehavior
27from blueberry.tests.gd.cert.behavior import ReplyStage
28from blueberry.tests.gd.cert.event_stream import EventStream, FilteringEventStream
29from blueberry.tests.gd.cert.metadata import metadata
30from blueberry.tests.gd.cert.truth import assertThat
31import hci_packets as hci
32
33from mobly import asserts
34from mobly import signals
35from mobly import test_runner
36from mobly import base_test
37
38
39class BogusProto:
40
41    class BogusType:
42
43        def __init__(self):
44            self.name = "BogusProto"
45            self.is_extension = False
46            self.cpp_type = False
47
48        def type(self):
49            return 'BogusRpc'
50
51        def label(self):
52            return "label"
53
54    class BogusDescriptor:
55
56        def __init__(self, name):
57            self.full_name = name
58
59    def __init__(self, value):
60        self.value_ = value
61        self.DESCRIPTOR = BogusProto.BogusDescriptor(str(value))
62
63    def __str__(self):
64        return "BogusRpc value = " + str(self.value_)
65
66    def ListFields(self):
67        for field in [BogusProto.BogusType()]:
68            yield [field, self.value_]
69
70
71class FetchEvents:
72
73    def __init__(self, events, delay_ms):
74        self.events_ = events
75        self.sleep_time_ = (delay_ms * 1.0) / 1000
76        self.index_ = 0
77        self.done_ = False
78        self.then_ = datetime.now()
79
80    def __iter__(self):
81        for event in self.events_:
82            time.sleep(self.sleep_time_)
83            if self.done_:
84                return
85            logging.debug("yielding %d" % event)
86            yield BogusProto(event)
87
88    def done(self):
89        return self.done_
90
91    def cancel(self):
92        logging.debug("cancel")
93        self.done_ = True
94        return None
95
96
97class TestBehaviors(object):
98
99    def __init__(self, parent):
100        self.test_request_behavior = SingleArgumentBehavior(lambda: TestBehaviors.TestRequestReplyStage(parent))
101
102    def test_request(self, matcher):
103        return self.test_request_behavior.begin(matcher)
104
105    class TestRequestReplyStage(ReplyStage):
106
107        def __init__(self, parent):
108            self._parent = parent
109
110        def increment_count(self):
111            self._commit(lambda obj: self._increment_count(obj))
112            return self
113
114        def _increment_count(self, obj):
115            self._parent.count += 1
116            self._parent.captured.append(obj)
117
118
119class ObjectWithBehaviors(IHasBehaviors):
120
121    def __init__(self):
122        self.behaviors = TestBehaviors(self)
123        self.count = 0
124        self.captured = []
125        self.unhandled_count = 0
126
127    def get_behaviors(self):
128        return self.behaviors
129
130    def increment_unhandled(self):
131        self.unhandled_count += 1
132
133
134class CertSelfTest(base_test.BaseTestClass):
135
136    def setup_test(self):
137        return True
138
139    def teardown_test(self):
140        return True
141
142    def test_assert_occurs_at_least_passes(self):
143        with EventStream(FetchEvents(events=[1, 2, 3, 1, 2, 3], delay_ms=40)) as event_stream:
144            event_stream.assert_event_occurs(lambda data: data.value_ == 1,
145                                             timeout=timedelta(milliseconds=300),
146                                             at_least_times=2)
147
148    def test_assert_occurs_passes(self):
149        with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
150            event_stream.assert_event_occurs(lambda data: data.value_ == 1, timeout=timedelta(seconds=1))
151
152    def test_assert_occurs_fails(self):
153        try:
154            with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
155                event_stream.assert_event_occurs(lambda data: data.value_ == 4, timeout=timedelta(seconds=1))
156        except Exception as e:
157            logging.debug(e)
158            return True  # Failed as expected
159        return False
160
161    def test_assert_occurs_at_most_passes(self):
162        with EventStream(FetchEvents(events=[1, 2, 3, 4], delay_ms=50)) as event_stream:
163            event_stream.assert_event_occurs_at_most(lambda data: data.value_ < 4,
164                                                     timeout=timedelta(seconds=1),
165                                                     at_most_times=3)
166
167    def test_assert_occurs_at_most_fails(self):
168        try:
169            with EventStream(FetchEvents(events=[1, 2, 3, 4], delay_ms=50)) as event_stream:
170                event_stream.assert_event_occurs_at_most(lambda data: data.value_ > 1,
171                                                         timeout=timedelta(seconds=1),
172                                                         at_most_times=2)
173        except Exception as e:
174            logging.debug(e)
175            return True  # Failed as expected
176        return False
177
178    def test_skip_a_test(self):
179        asserts.skip("Skipping this test because it's blocked by b/xyz")
180        assert False
181
182    def test_nested_packets(self):
183        handle = 123
184        inside = hci.ReadScanEnable()
185        logging.debug(inside.serialize())
186        logging.debug("building outside")
187        outside = hci.Acl(handle=handle,
188                          packet_boundary_flag=hci.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
189                          broadcast_flag=hci.BroadcastFlag.POINT_TO_POINT,
190                          payload=inside.serialize())
191        logging.debug(outside.serialize())
192        logging.debug("Done!")
193
194    def test_assertThat_boolean_success(self):
195        assertThat(True).isTrue()
196        assertThat(False).isFalse()
197
198    def test_assertThat_boolean_falseIsTrue(self):
199        try:
200            assertThat(False).isTrue()
201        except Exception as e:
202            return True
203        return False
204
205    def test_assertThat_boolean_trueIsFalse(self):
206        try:
207            assertThat(True).isFalse()
208        except Exception as e:
209            return True
210        return False
211
212    def test_assertThat_object_success(self):
213        assertThat("this").isEqualTo("this")
214        assertThat("this").isNotEqualTo("that")
215        assertThat(None).isNone()
216        assertThat("this").isNotNone()
217
218    def test_assertThat_object_isEqualToFails(self):
219        try:
220            assertThat("this").isEqualTo("that")
221        except Exception as e:
222            return True
223        return False
224
225    def test_assertThat_object_isNotEqualToFails(self):
226        try:
227            assertThat("this").isNotEqualTo("this")
228        except Exception as e:
229            return True
230        return False
231
232    def test_assertThat_object_isNoneFails(self):
233        try:
234            assertThat("this").isNone()
235        except Exception as e:
236            return True
237        return False
238
239    def test_assertThat_object_isNotNoneFails(self):
240        try:
241            assertThat(None).isNotNone()
242        except Exception as e:
243            return True
244        return False
245
246    def test_assertThat_eventStream_emits_passes(self):
247        with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
248            assertThat(event_stream).emits(lambda data: data.value_ == 1)
249
250    def test_assertThat_eventStream_emits_then_passes(self):
251        with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
252            assertThat(event_stream).emits(lambda data: data.value_ == 1).then(lambda data: data.value_ == 3)
253
254    def test_assertThat_eventStream_emits_fails(self):
255        try:
256            with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
257                assertThat(event_stream).emits(lambda data: data.value_ == 4)
258        except Exception as e:
259            logging.debug(e)
260            return True  # Failed as expected
261        return False
262
263    def test_assertThat_eventStream_emits_then_fails(self):
264        try:
265            with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
266                assertThat(event_stream).emits(lambda data: data.value_ == 1).emits(lambda data: data.value_ == 4)
267        except Exception as e:
268            logging.debug(e)
269            return True  # Failed as expected
270        return False
271
272    def test_assertThat_eventStream_emitsInOrder_passes(self):
273        with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
274            assertThat(event_stream).emits(lambda data: data.value_ == 1, lambda data: data.value_ == 2).inOrder()
275
276    def test_assertThat_eventStream_emitsInAnyOrder_passes(self):
277        with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
278            assertThat(event_stream).emits(
279                lambda data: data.value_ == 2,
280                lambda data: data.value_ == 1).inAnyOrder().then(lambda data: data.value_ == 3)
281
282    def test_assertThat_eventStream_emitsInOrder_fails(self):
283        try:
284            with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
285                assertThat(event_stream).emits(lambda data: data.value_ == 2, lambda data: data.value_ == 1).inOrder()
286        except Exception as e:
287            logging.debug(e)
288            return True  # Failed as expected
289        return False
290
291    def test_assertThat_eventStream_emitsInAnyOrder_fails(self):
292        try:
293            with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
294                assertThat(event_stream).emits(lambda data: data.value_ == 4,
295                                               lambda data: data.value_ == 1).inAnyOrder()
296        except Exception as e:
297            logging.debug(e)
298            return True  # Failed as expected
299        return False
300
301    def test_assertThat_emitsNone_passes(self):
302        with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
303            assertThat(event_stream).emitsNone(lambda data: data.value_ == 4, timeout=timedelta(seconds=0.15)).thenNone(
304                lambda data: data.value_ == 5, timeout=timedelta(seconds=0.15))
305
306    def test_assertThat_emitsNone_passes_after_1_second(self):
307        with EventStream(FetchEvents(events=[1, 2, 3, 4], delay_ms=400)) as event_stream:
308            assertThat(event_stream).emitsNone(lambda data: data.value_ == 4, timeout=timedelta(seconds=1))
309
310    def test_assertThat_emitsNone_fails(self):
311        try:
312            with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
313                assertThat(event_stream).emitsNone(lambda data: data.value_ == 2, timeout=timedelta(seconds=1))
314        except Exception as e:
315            logging.debug(e)
316            return True  # Failed as expected
317        return False
318
319    def test_assertThat_emitsNone_zero_passes(self):
320        with EventStream(FetchEvents(events=[], delay_ms=50)) as event_stream:
321            assertThat(event_stream).emitsNone(timeout=timedelta(milliseconds=10)).thenNone(timeout=timedelta(
322                milliseconds=10))
323
324    def test_assertThat_emitsNone_zero_passes_after_one_second(self):
325        with EventStream(FetchEvents([1], delay_ms=1500)) as event_stream:
326            assertThat(event_stream).emitsNone(timeout=timedelta(seconds=1.0))
327
328    def test_assertThat_emitsNone_zero_fails(self):
329        try:
330            with EventStream(FetchEvents(events=[17], delay_ms=50)) as event_stream:
331                assertThat(event_stream).emitsNone(timeout=timedelta(seconds=1))
332        except Exception as e:
333            logging.debug(e)
334            return True  # Failed as expected
335        return False
336
337    def test_filtering_event_stream_none_filter_function(self):
338        with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
339            filtered_event_stream = FilteringEventStream(event_stream, None)
340            assertThat(filtered_event_stream) \
341                .emits(lambda data: data.value_ == 1) \
342                .then(lambda data: data.value_ == 3)
343
344    def test_metadata_empty(self):
345
346        @metadata()
347        def simple_pass_test(arg):
348            pass
349
350        try:
351            simple_pass_test(1)
352        except signals.TestFailure:
353            pass
354        except Exception as e:
355            asserts.fail("@metadata() should only raise signals.TestFailure, "
356                         "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
357        else:
358            asserts.fail("@metadata() should not work")
359
360    def test_metadata_empty_no_function_call(self):
361
362        @metadata
363        def simple_pass_test(arg):
364            pass
365
366        try:
367            simple_pass_test(1)
368        except signals.TestFailure:
369            pass
370        except Exception as e:
371            asserts.fail("@metadata should only raise signals.TestFailure, "
372                         "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
373        else:
374            asserts.fail("@metadata should not work")
375
376    def test_metadata_pts_missing_id(self):
377
378        @metadata(pts_test_name="Hello world")
379        def simple_pass_test(arg):
380            pass
381
382        try:
383            simple_pass_test(1)
384        except signals.TestFailure:
385            pass
386        except Exception as e:
387            asserts.fail("should only raise signals.TestFailure, "
388                         "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
389        else:
390            asserts.fail("missing pts_test_id should not work")
391
392    def test_metadata_pts_missing_name(self):
393
394        @metadata(pts_test_id="A/B/C")
395        def simple_pass_test(arg):
396            pass
397
398        try:
399            simple_pass_test(1)
400        except signals.TestFailure:
401            pass
402        except Exception as e:
403            asserts.fail("should only raise signals.TestFailure, "
404                         "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
405        else:
406            asserts.fail("missing pts_test_name should not work")
407
408    def test_metadata_pts_test_id_and_description(self):
409
410        @metadata(pts_test_id="A/B/C", pts_test_name="Hello world")
411        def simple_pass_test(arg):
412            pass
413
414        try:
415            simple_pass_test(1)
416        except signals.TestPass as e:
417            asserts.assert_true("pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras)))
418            asserts.assert_equal(e.extras["pts_test_id"], "A/B/C")
419            asserts.assert_true("pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras)))
420            asserts.assert_equal(e.extras["pts_test_name"], "Hello world")
421        else:
422            asserts.fail("Must throw an exception using @metadata decorator")
423
424    def test_metadata_test_with_exception_stacktrace(self):
425
426        @metadata(pts_test_id="A/B/C", pts_test_name="Hello world")
427        def simple_fail_test(failure_argument):
428            raise ValueError(failure_argument)
429
430        try:
431            simple_fail_test("BEEFBEEF")
432        except signals.TestError as e:
433            asserts.assert_true("pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras)))
434            asserts.assert_equal(e.extras["pts_test_id"], "A/B/C")
435            asserts.assert_true("pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras)))
436            asserts.assert_equal(e.extras["pts_test_name"], "Hello world")
437            trace_str = traceback.format_exc()
438            asserts.assert_true("raise ValueError(failure_argument)" in trace_str,
439                                msg="Failed test method not in error stack trace: %s" % trace_str)
440        else:
441            asserts.fail("Must throw an exception using @metadata decorator")
442
443    def test_fluent_behavior_simple(self):
444        thing = ObjectWithBehaviors()
445
446        when(thing).test_request(anything()).then().increment_count()
447
448        thing.behaviors.test_request_behavior.run("A")
449
450        assertThat(thing.count).isEqualTo(1)
451        assertThat(thing.captured).isEqualTo(["A"])
452
453    def test_fluent_behavior__then_single__captures_one(self):
454        thing = ObjectWithBehaviors()
455
456        thing.behaviors.test_request_behavior.set_default_to_ignore()
457
458        when(thing).test_request(anything()).then().increment_count()
459
460        thing.behaviors.test_request_behavior.run("A")
461        thing.behaviors.test_request_behavior.run("A")
462        thing.behaviors.test_request_behavior.run("A")
463
464        assertThat(thing.count).isEqualTo(1)
465        assertThat(thing.captured).isEqualTo(["A"])
466
467    def test_fluent_behavior__then_times__captures_all(self):
468        thing = ObjectWithBehaviors()
469
470        when(thing).test_request(anything()).then(times=3).increment_count()
471
472        thing.behaviors.test_request_behavior.run("A")
473        thing.behaviors.test_request_behavior.run("B")
474        thing.behaviors.test_request_behavior.run("C")
475
476        assertThat(thing.count).isEqualTo(3)
477        assertThat(thing.captured).isEqualTo(["A", "B", "C"])
478
479    def test_fluent_behavior__always__captures_all(self):
480        thing = ObjectWithBehaviors()
481
482        when(thing).test_request(anything()).always().increment_count()
483
484        thing.behaviors.test_request_behavior.run("A")
485        thing.behaviors.test_request_behavior.run("B")
486        thing.behaviors.test_request_behavior.run("C")
487
488        assertThat(thing.count).isEqualTo(3)
489        assertThat(thing.captured).isEqualTo(["A", "B", "C"])
490
491    def test_fluent_behavior__matcher__captures_relevant(self):
492        thing = ObjectWithBehaviors()
493        thing.behaviors.test_request_behavior.set_default_to_ignore()
494
495        when(thing).test_request(lambda obj: obj == "B").always().increment_count()
496
497        thing.behaviors.test_request_behavior.run("A")
498        thing.behaviors.test_request_behavior.run("B")
499        thing.behaviors.test_request_behavior.run("C")
500
501        assertThat(thing.count).isEqualTo(1)
502        assertThat(thing.captured).isEqualTo(["B"])
503
504    def test_fluent_behavior__then_repeated__captures_relevant(self):
505        thing = ObjectWithBehaviors()
506        thing.behaviors.test_request_behavior.set_default_to_ignore()
507
508        when(thing).test_request(anything()).then().increment_count().increment_count()
509
510        thing.behaviors.test_request_behavior.run("A")
511        thing.behaviors.test_request_behavior.run("B")
512        thing.behaviors.test_request_behavior.run("A")
513
514        assertThat(thing.count).isEqualTo(2)
515        assertThat(thing.captured).isEqualTo(["A", "B"])
516
517    def test_fluent_behavior__fallback__captures_relevant(self):
518        thing = ObjectWithBehaviors()
519        thing.behaviors.test_request_behavior.set_default_to_ignore()
520
521        when(thing).test_request(lambda obj: obj == "B").then(times=1).increment_count()
522        when(thing).test_request(lambda obj: obj == "C").always().increment_count()
523
524        thing.behaviors.test_request_behavior.run("A")
525        thing.behaviors.test_request_behavior.run("B")
526        thing.behaviors.test_request_behavior.run("A")
527        thing.behaviors.test_request_behavior.run("C")
528        thing.behaviors.test_request_behavior.run("B")
529        thing.behaviors.test_request_behavior.run("C")
530
531        assertThat(thing.count).isEqualTo(3)
532        assertThat(thing.captured).isEqualTo(["B", "C", "C"])
533
534    def test_fluent_behavior__default_unhandled_crash(self):
535        thing = ObjectWithBehaviors()
536
537        when(thing).test_request(anything()).then().increment_count()
538
539        thing.behaviors.test_request_behavior.run("A")
540        try:
541            thing.behaviors.test_request_behavior.run("A")
542        except Exception as e:
543            logging.debug(e)
544            return True  # Failed as expected
545        return False
546
547    def test_fluent_behavior__set_default_works(self):
548        thing = ObjectWithBehaviors()
549        thing.behaviors.test_request_behavior.set_default(lambda obj: thing.increment_unhandled())
550
551        when(thing).test_request(anything()).then().increment_count()
552
553        thing.behaviors.test_request_behavior.run("A")
554        thing.behaviors.test_request_behavior.run("A")
555        assertThat(thing.unhandled_count).isEqualTo(1)
556
557    def test_fluent_behavior__wait_until_done(self):
558        thing = ObjectWithBehaviors()
559        is_a = lambda obj: obj == "A"
560        when(thing).test_request(is_a).then().increment_count()
561
562        closure = lambda: thing.behaviors.test_request_behavior.run("A")
563        t = Timer(0.5, closure)
564        t.start()
565
566        wait_until(thing).test_request(is_a).times(1)
567        assertThat(thing.count).isEqualTo(1)
568        assertThat(thing.captured).isEqualTo(["A"])
569
570    def test_fluent_behavior__wait_until_done_different_lambda(self):
571        thing = ObjectWithBehaviors()
572        when(thing).test_request(lambda obj: obj == "A").then().increment_count()
573
574        closure = lambda: thing.behaviors.test_request_behavior.run("A")
575        t = Timer(0.5, closure)
576        t.start()
577
578        wait_until(thing).test_request(lambda obj: obj == "A").times(1)
579        assertThat(thing.count).isEqualTo(1)
580        assertThat(thing.captured).isEqualTo(["A"])
581
582    def test_fluent_behavior__wait_until_done_anything(self):
583        thing = ObjectWithBehaviors()
584        when(thing).test_request(lambda obj: obj == "A").then().increment_count()
585
586        closure = lambda: thing.behaviors.test_request_behavior.run("A")
587        t = Timer(0.5, closure)
588        t.start()
589
590        wait_until(thing).test_request(anything()).times(1)
591        assertThat(thing.count).isEqualTo(1)
592        assertThat(thing.captured).isEqualTo(["A"])
593
594    def test_fluent_behavior__wait_until_done_not_happened(self):
595        thing = ObjectWithBehaviors()
596        thing.behaviors.test_request_behavior.set_default_to_ignore()
597        when(thing).test_request(lambda obj: obj == "A").then().increment_count()
598
599        closure = lambda: thing.behaviors.test_request_behavior.run("B")
600        t = Timer(0.5, closure)
601        t.start()
602        assertThat(wait_until(thing).test_request(lambda obj: obj == "A").times(1)).isFalse()
603
604    def test_fluent_behavior__wait_until_done_with_default(self):
605        thing = ObjectWithBehaviors()
606        thing.behaviors.test_request_behavior.set_default(lambda obj: thing.increment_unhandled())
607
608        closure = lambda: thing.behaviors.test_request_behavior.run("A")
609        t = Timer(0.5, closure)
610        t.start()
611
612        wait_until(thing).test_request(anything()).times(1)
613        assertThat(thing.unhandled_count).isEqualTo(1)
614
615    def test_fluent_behavior__wait_until_done_two_events_AA(self):
616        thing = ObjectWithBehaviors()
617        when(thing).test_request(lambda obj: obj == "A").then().increment_count().increment_count()
618
619        closure1 = lambda: thing.behaviors.test_request_behavior.run("A")
620        t1 = Timer(0.5, closure1)
621        t1.start()
622        closure2 = lambda: thing.behaviors.test_request_behavior.run("A")
623        t2 = Timer(0.5, closure2)
624        t2.start()
625
626        wait_until(thing).test_request(lambda obj: obj == "A").times(2)
627        assertThat(thing.count).isEqualTo(2)
628        assertThat(thing.captured).isEqualTo(["A", "A"])
629
630    def test_fluent_behavior__wait_until_done_two_events_AB(self):
631        thing = ObjectWithBehaviors()
632        when(thing).test_request(anything()).always().increment_count()
633
634        closure1 = lambda: thing.behaviors.test_request_behavior.run("A")
635        t1 = Timer(0.5, closure1)
636        t1.start()
637        closure2 = lambda: thing.behaviors.test_request_behavior.run("B")
638        t2 = Timer(1, closure2)
639        t2.start()
640
641        wait_until(thing).test_request(anything()).times(2)
642        assertThat(thing.count).isEqualTo(2)
643        assertThat(thing.captured).isEqualTo(["A", "B"])
644
645    def test_fluent_behavior__wait_until_done_only_one_event_is_done(self):
646        thing = ObjectWithBehaviors()
647        when(thing).test_request(anything()).always().increment_count()
648
649        closure1 = lambda: thing.behaviors.test_request_behavior.run("A")
650        t1 = Timer(1, closure1)
651        t1.start()
652        closure2 = lambda: thing.behaviors.test_request_behavior.run("B")
653        t2 = Timer(3, closure2)
654        t2.start()
655        assertThat(wait_until(thing).test_request(lambda obj: obj == "A").times(2)).isFalse()
656
657
658if __name__ == '__main__':
659    test_runner.main()
660