Skip to content

Commit f62d085

Browse files
hop-on: send current sim. task instead of next inside of sim. step (#196)
1 parent 3c75fe4 commit f62d085

File tree

2 files changed

+142
-13
lines changed

2 files changed

+142
-13
lines changed

SilKit/source/services/orchestration/Test_TimeSyncService.cpp

Lines changed: 131 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,31 @@ using namespace SilKit::Util;
5151
using ::SilKit::Core::Tests::DummyParticipant;
5252

5353

54-
class Test_TimeSyncService : public testing::Test
54+
class MockParticipant : public DummyParticipant
5555
{
56-
protected:
57-
struct Callbacks
58-
{
59-
MOCK_METHOD(void, CommunicationReadyHandler, ());
60-
MOCK_METHOD(void, StartingHandler, ());
61-
MOCK_METHOD(void, StopHandler, ());
62-
MOCK_METHOD(void, ShutdownHandler, ());
63-
MOCK_METHOD(void, SimTask, (std::chrono::nanoseconds));
64-
};
56+
public:
57+
MOCK_METHOD(void, SendMsg,
58+
(const SilKit::Core::IServiceEndpoint* from, const SilKit::Services::Orchestration::NextSimTask& msg),
59+
(override));
60+
};
61+
6562

63+
class Test_TimeSyncService : public testing::Test
64+
{
6665
protected: // CTor
6766
Test_TimeSyncService()
6867
{
68+
ON_CALL(participant.mockServiceDiscovery, RegisterServiceDiscoveryHandler)
69+
.WillByDefault([this](SilKit::Core::Discovery::ServiceDiscoveryHandler handler) {
70+
serviceDiscoveryHandlers.emplace_back(std::move(handler));
71+
});
72+
73+
ON_CALL(participant,
74+
SendMsg(An<const SilKit::Core::IServiceEndpoint*>(), An<const Services::Orchestration::NextSimTask&>()))
75+
.WillByDefault(
76+
[this](const SilKit::Core::IServiceEndpoint* /* from */,
77+
const Services::Orchestration::NextSimTask& msg) { sentNextSimTasks.emplace_back(msg); });
78+
6979
// this CTor calls CreateTimeSyncService implicitly
7080
lifecycleService = std::make_unique<LifecycleService>(&participant);
7181
lifecycleService->SetLifecycleConfiguration(LifecycleConfiguration{OperationMode::Coordinated});
@@ -96,10 +106,12 @@ class Test_TimeSyncService : public testing::Test
96106
// Members
97107
NiceMock<MockServiceEndpoint> endpoint{"P1", "N1", "C1"};
98108

99-
NiceMock<DummyParticipant> participant;
100-
Callbacks callbacks;
109+
NiceMock<MockParticipant> participant;
101110
Config::HealthCheck healthCheckConfig;
102111

112+
std::vector<SilKit::Core::Discovery::ServiceDiscoveryHandler> serviceDiscoveryHandlers;
113+
std::vector<SilKit::Services::Orchestration::NextSimTask> sentNextSimTasks;
114+
103115
std::unique_ptr<LifecycleService> lifecycleService;
104116
TimeProvider timeProvider{};
105117
std::unique_ptr<TimeSyncService> timeSyncService;
@@ -161,4 +173,111 @@ TEST_F(Test_TimeSyncService, async_simtask_mismatching_number_of_complete_calls)
161173
ASSERT_EQ(numAsyncTaskCalled, 3) << "Calling too many CompleteSimulationStep() should not wreak havoc";
162174
}
163175

176+
auto MakeTimeSyncServiceDescriptor() -> SilKit::Core::ServiceDescriptor
177+
{
178+
SilKit::Core::ServiceDescriptor sd;
179+
sd.SetServiceType(Core::ServiceType::InternalController);
180+
sd.SetParticipantNameAndComputeId("Hopper");
181+
sd.SetNetworkName("default");
182+
sd.SetNetworkType(Config::NetworkType::Undefined);
183+
sd.SetServiceName("XXX");
184+
sd.SetServiceId(1234);
185+
sd.SetSupplementalDataItem(SilKit::Core::Discovery::controllerType, "TimeSyncService");
186+
sd.SetSupplementalDataItem(SilKit::Core::Discovery::timeSyncActive, "1");
187+
188+
return sd;
189+
}
190+
191+
TEST_F(Test_TimeSyncService, hop_on_during_simulation_step)
192+
{
193+
using SilKit::Core::Discovery::ServiceDiscoveryEvent;
194+
195+
ASSERT_EQ(serviceDiscoveryHandlers.size(), 1);
196+
197+
std::vector<std::chrono::nanoseconds> simulationStepNows;
198+
timeSyncService->SetSimulationStepHandlerAsync([&simulationStepNows](auto now, auto) { simulationStepNows.emplace_back(now); }, 1ms);
199+
200+
PrepareLifecycle();
201+
202+
// After 'starting' the first (now == 0ns) NextSimTask message has been sent (which indicates that we're ready to
203+
// execute the first step)
204+
ASSERT_EQ(sentNextSimTasks.size(), 1);
205+
ASSERT_EQ(sentNextSimTasks[0].timePoint, 0ms);
206+
// The first simulation step is triggered by received NextSimTask message
207+
ASSERT_EQ(simulationStepNows.size(), 0);
208+
209+
// Trigger the first simulation step
210+
timeSyncService->ReceiveMsg(&endpoint, {0ms});
211+
ASSERT_EQ(simulationStepNows.size(), 1);
212+
ASSERT_EQ(simulationStepNows[0], 0ms);
213+
214+
// Complete the first simulation step
215+
timeSyncService->CompleteSimulationStep();
216+
// Completion triggers sending the next simulation step message
217+
ASSERT_EQ(sentNextSimTasks.size(), 2);
218+
ASSERT_EQ(sentNextSimTasks[1].timePoint, 1ms);
219+
220+
// Reception of the next simulation step message (from a remote peer) triggers the second simulation step
221+
timeSyncService->ReceiveMsg(&endpoint, {1ms});
222+
ASSERT_EQ(simulationStepNows.size(), 2);
223+
ASSERT_EQ(simulationStepNows[1], 1ms);
224+
225+
// Trigger 'hop-on' which will cause an additional NextSimTask to be sent (with the 'current' timestamp)
226+
serviceDiscoveryHandlers[0](ServiceDiscoveryEvent::Type::ServiceCreated, MakeTimeSyncServiceDescriptor());
227+
ASSERT_EQ(sentNextSimTasks.size(), 3);
228+
ASSERT_EQ(sentNextSimTasks[2].timePoint, 1ms);
229+
230+
// Complete the second simulation step
231+
timeSyncService->CompleteSimulationStep();
232+
// Completion triggers sending the next simulation step message
233+
ASSERT_EQ(sentNextSimTasks.size(), 4);
234+
ASSERT_EQ(sentNextSimTasks[3].timePoint, 2ms);
235+
}
236+
237+
TEST_F(Test_TimeSyncService, hop_on_outside_simulation_step)
238+
{
239+
using SilKit::Core::Discovery::ServiceDiscoveryEvent;
240+
241+
ASSERT_EQ(serviceDiscoveryHandlers.size(), 1);
242+
243+
std::vector<std::chrono::nanoseconds> simulationStepNows;
244+
timeSyncService->SetSimulationStepHandlerAsync([&simulationStepNows](auto now, auto) { simulationStepNows.emplace_back(now); }, 1ms);
245+
246+
PrepareLifecycle();
247+
248+
// After 'starting' the first (now == 0ns) NextSimTask message has been sent (which indicates that we're ready to
249+
// execute the first step)
250+
ASSERT_EQ(sentNextSimTasks.size(), 1);
251+
ASSERT_EQ(sentNextSimTasks[0].timePoint, 0ms);
252+
// The first simulation step is triggered by received NextSimTask message
253+
ASSERT_EQ(simulationStepNows.size(), 0);
254+
255+
// Trigger the first simulation step
256+
timeSyncService->ReceiveMsg(&endpoint, {0ms});
257+
ASSERT_EQ(simulationStepNows.size(), 1);
258+
ASSERT_EQ(simulationStepNows[0], 0ms);
259+
260+
// Complete the first simulation step
261+
timeSyncService->CompleteSimulationStep();
262+
// Completion triggers sending the next simulation step message
263+
ASSERT_EQ(sentNextSimTasks.size(), 2);
264+
ASSERT_EQ(sentNextSimTasks[1].timePoint, 1ms);
265+
266+
// Reception of the next simulation step message (from a remote peer) triggers the second simulation step
267+
timeSyncService->ReceiveMsg(&endpoint, {1ms});
268+
ASSERT_EQ(simulationStepNows.size(), 2);
269+
ASSERT_EQ(simulationStepNows[1], 1ms);
270+
271+
// Complete the second simulation step
272+
timeSyncService->CompleteSimulationStep();
273+
// Completion triggers sending the next simulation step message
274+
ASSERT_EQ(sentNextSimTasks.size(), 3);
275+
ASSERT_EQ(sentNextSimTasks[2].timePoint, 2ms);
276+
277+
// Trigger 'hop-on' which will cause an additional NextSimTask to be sent (with the 'next' timestamp)
278+
serviceDiscoveryHandlers[0](ServiceDiscoveryEvent::Type::ServiceCreated, MakeTimeSyncServiceDescriptor());
279+
ASSERT_EQ(sentNextSimTasks.size(), 4);
280+
ASSERT_EQ(sentNextSimTasks[3].timePoint, 2ms);
281+
}
282+
164283
} // namespace

SilKit/source/services/orchestration/TimeSyncService.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,17 @@ TimeSyncService::TimeSyncService(Core::IParticipantInternal* participant, ITimeP
370370
"Participant \'{}\' is joining an already running simulation. Resending our "
371371
"NextSimTask.",
372372
descriptorParticipantName);
373-
SendMsg(_timeConfiguration.NextSimStep());
373+
374+
if (GetTimeSyncPolicy()->IsExecutingSimStep())
375+
{
376+
Debug(_participant->GetLogger(), "Sending currently executing simulation step");
377+
SendMsg(_timeConfiguration.CurrentSimStep());
378+
}
379+
else
380+
{
381+
Debug(_participant->GetLogger(), "Sending next simulation step");
382+
SendMsg(_timeConfiguration.NextSimStep());
383+
}
374384
}
375385
}
376386
else if (discoveryEventType == Core::Discovery::ServiceDiscoveryEvent::Type::ServiceRemoved)

0 commit comments

Comments
 (0)