actor_ut.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include <library/cpp/testing/unittest/registar.h>
  2. #include "actor.h"
  3. #include "queue_in_actor.h"
  4. #include <library/cpp/messagebus/misc/test_sync.h>
  5. #include <util/generic/object_counter.h>
  6. #include <util/system/event.h>
  7. using namespace NActor;
  8. template <typename TThis>
  9. struct TTestActorBase: public TAtomicRefCount<TThis>, public TActor<TThis> {
  10. TTestSync Started;
  11. TTestSync Acted;
  12. TTestActorBase(TExecutor* executor)
  13. : TActor<TThis>(executor)
  14. {
  15. }
  16. void Act(TDefaultTag) {
  17. Started.Inc();
  18. static_cast<TThis*>(this)->Act2();
  19. Acted.Inc();
  20. }
  21. };
  22. struct TNopActor: public TTestActorBase<TNopActor> {
  23. TObjectCounter<TNopActor> AllocCounter;
  24. TNopActor(TExecutor* executor)
  25. : TTestActorBase<TNopActor>(executor)
  26. {
  27. }
  28. void Act2() {
  29. }
  30. };
  31. struct TWaitForSignalActor: public TTestActorBase<TWaitForSignalActor> {
  32. TWaitForSignalActor(TExecutor* executor)
  33. : TTestActorBase<TWaitForSignalActor>(executor)
  34. {
  35. }
  36. TSystemEvent WaitFor;
  37. void Act2() {
  38. WaitFor.Wait();
  39. }
  40. };
  41. struct TDecrementAndSendActor: public TTestActorBase<TDecrementAndSendActor>, public TQueueInActor<TDecrementAndSendActor, int> {
  42. TSystemEvent Done;
  43. TDecrementAndSendActor* Next;
  44. TDecrementAndSendActor(TExecutor* executor)
  45. : TTestActorBase<TDecrementAndSendActor>(executor)
  46. , Next(nullptr)
  47. {
  48. }
  49. void ProcessItem(TDefaultTag, TDefaultTag, int n) {
  50. if (n == 0) {
  51. Done.Signal();
  52. } else {
  53. Next->EnqueueAndSchedule(n - 1);
  54. }
  55. }
  56. void Act(TDefaultTag) {
  57. DequeueAll();
  58. }
  59. };
  60. struct TObjectCountChecker {
  61. TObjectCountChecker() {
  62. CheckCounts();
  63. }
  64. ~TObjectCountChecker() {
  65. CheckCounts();
  66. }
  67. void CheckCounts() {
  68. UNIT_ASSERT_VALUES_EQUAL(TAtomicBase(0), TObjectCounter<TNopActor>::ObjectCount());
  69. UNIT_ASSERT_VALUES_EQUAL(TAtomicBase(0), TObjectCounter<TWaitForSignalActor>::ObjectCount());
  70. UNIT_ASSERT_VALUES_EQUAL(TAtomicBase(0), TObjectCounter<TDecrementAndSendActor>::ObjectCount());
  71. }
  72. };
  73. Y_UNIT_TEST_SUITE(TActor) {
  74. Y_UNIT_TEST(Simple) {
  75. TObjectCountChecker objectCountChecker;
  76. TExecutor executor(4);
  77. TIntrusivePtr<TNopActor> actor(new TNopActor(&executor));
  78. actor->Schedule();
  79. actor->Acted.WaitFor(1u);
  80. }
  81. Y_UNIT_TEST(ScheduleAfterStart) {
  82. TObjectCountChecker objectCountChecker;
  83. TExecutor executor(4);
  84. TIntrusivePtr<TWaitForSignalActor> actor(new TWaitForSignalActor(&executor));
  85. actor->Schedule();
  86. actor->Started.WaitFor(1);
  87. actor->Schedule();
  88. actor->WaitFor.Signal();
  89. // make sure Act is called second time
  90. actor->Acted.WaitFor(2u);
  91. }
  92. void ComplexImpl(int queueSize, int actorCount) {
  93. TObjectCountChecker objectCountChecker;
  94. TExecutor executor(queueSize);
  95. TVector<TIntrusivePtr<TDecrementAndSendActor>> actors;
  96. for (int i = 0; i < actorCount; ++i) {
  97. actors.push_back(new TDecrementAndSendActor(&executor));
  98. }
  99. for (int i = 0; i < actorCount; ++i) {
  100. actors.at(i)->Next = &*actors.at((i + 1) % actorCount);
  101. }
  102. for (int i = 0; i < actorCount; ++i) {
  103. actors.at(i)->EnqueueAndSchedule(10000);
  104. }
  105. for (int i = 0; i < actorCount; ++i) {
  106. actors.at(i)->Done.WaitI();
  107. }
  108. }
  109. Y_UNIT_TEST(ComplexContention) {
  110. ComplexImpl(4, 6);
  111. }
  112. Y_UNIT_TEST(ComplexNoContention) {
  113. ComplexImpl(6, 4);
  114. }
  115. }