@@ -25,7 +25,6 @@ class FunctionMigrationTestFixture : public SchedulerTestFixture
25
25
26
26
~FunctionMigrationTestFixture ()
27
27
{
28
- sch.clearRecordedMessages ();
29
28
faabric::util::setMockMode (false );
30
29
31
30
// Remove all hosts from global set
@@ -89,7 +88,7 @@ TEST_CASE_METHOD(FunctionMigrationTestFixture,
89
88
90
89
TEST_CASE_METHOD (
91
90
FunctionMigrationTestFixture,
92
- " Test function migration thread only works if set in the message" ,
91
+ " Test migration oportunities are only detected if set in the message" ,
93
92
" [scheduler]" )
94
93
{
95
94
// First set resources before calling the functions: one will be allocated
@@ -105,6 +104,7 @@ TEST_CASE_METHOD(
105
104
req->mutable_messages ()->at (0 ).set_inputdata (std::to_string (timeToSleep));
106
105
uint32_t appId = req->messages ().at (0 ).appid ();
107
106
107
+ // Build expected pending migrations
108
108
std::shared_ptr<faabric::PendingMigrations> expectedMigrations;
109
109
SECTION (" Migration not enabled" ) { expectedMigrations = nullptr ; }
110
110
@@ -157,10 +157,9 @@ TEST_CASE_METHOD(
157
157
REQUIRE (sch.canAppBeMigrated (appId) == nullptr );
158
158
}
159
159
160
- TEST_CASE_METHOD (
161
- FunctionMigrationTestFixture,
162
- " Test function migration thread detects migration opportunities" ,
163
- " [scheduler]" )
160
+ TEST_CASE_METHOD (FunctionMigrationTestFixture,
161
+ " Test checking for migration opportunities" ,
162
+ " [scheduler]" )
164
163
{
165
164
std::vector<std::string> hosts = { masterHost, " hostA" };
166
165
std::vector<int > slots = { 1 , 1 };
@@ -170,9 +169,12 @@ TEST_CASE_METHOD(
170
169
auto req = faabric::util::batchExecFactory (" foo" , " sleep" , 2 );
171
170
int timeToSleep = SHORT_TEST_TIMEOUT_MS;
172
171
req->mutable_messages ()->at (0 ).set_inputdata (std::to_string (timeToSleep));
173
- req->mutable_messages ()->at (0 ).set_migrationcheckperiod (2 );
174
172
uint32_t appId = req->messages ().at (0 ).appid ();
175
173
174
+ // By setting the check period to a non-zero value, we are effectively
175
+ // opting in to be considered for migration
176
+ req->mutable_messages ()->at (0 ).set_migrationcheckperiod (2 );
177
+
176
178
auto decision = sch.callFunctions (req);
177
179
178
180
std::shared_ptr<faabric::PendingMigrations> expectedMigrations;
@@ -226,11 +228,11 @@ TEST_CASE_METHOD(
226
228
227
229
TEST_CASE_METHOD (
228
230
FunctionMigrationTestFixture,
229
- " Test detecting migration opportunities with several hosts and requests " ,
231
+ " Test detecting migration opportunities for several messages and hosts " ,
230
232
" [scheduler]" )
231
233
{
232
- // First set resources before calling the functions: one will be allocated
233
- // locally, another one in the remote host
234
+ // First set resources before calling the functions: one request will be
235
+ // allocated to each host
234
236
std::vector<std::string> hosts = { masterHost, " hostA" , " hostB" , " hostC" };
235
237
std::vector<int > slots = { 1 , 1 , 1 , 1 };
236
238
std::vector<int > usedSlots = { 0 , 0 , 0 , 0 };
@@ -239,9 +241,11 @@ TEST_CASE_METHOD(
239
241
auto req = faabric::util::batchExecFactory (" foo" , " sleep" , 4 );
240
242
int timeToSleep = SHORT_TEST_TIMEOUT_MS;
241
243
req->mutable_messages ()->at (0 ).set_inputdata (std::to_string (timeToSleep));
242
- req->mutable_messages ()->at (0 ).set_migrationcheckperiod (2 );
243
244
uint32_t appId = req->messages ().at (0 ).appid ();
244
245
246
+ // Opt in to be considered for migration
247
+ req->mutable_messages ()->at (0 ).set_migrationcheckperiod (2 );
248
+
245
249
auto decision = sch.callFunctions (req);
246
250
247
251
// Set up expectations
@@ -256,17 +260,17 @@ TEST_CASE_METHOD(
256
260
std::vector<int > newUsedSlots = { 1 , 1 , 1 , 1 };
257
261
setHostResources (hosts, newSlots, newUsedSlots);
258
262
259
- // Build expected result
263
+ // Build expected result: two migrations
260
264
faabric::PendingMigrations expected;
261
265
expected.set_appid (appId);
262
- // Migrate last message (scheduled to last host) to first host. This
263
- // fills up the first host.
266
+ // Migration 1: migrate last message (originally scheduled to last host)
267
+ // to first host. This fills up the first host.
264
268
auto * migration1 = expected.add_migrations ();
265
269
migration1->set_messageid (req->messages ().at (3 ).id ());
266
270
migration1->set_srchost (hosts.at (3 ));
267
271
migration1->set_dsthost (hosts.at (0 ));
268
- // Migrate penultimate message (scheduled to penultimate host) to second
269
- // host. This fills up the second host.
272
+ // Migration 2: migrate penultimate message (originally scheduled to
273
+ // penultimate host) to second host. This fills up the second host.
270
274
auto * migration2 = expected.add_migrations ();
271
275
migration2->set_messageid (req->messages ().at (2 ).id ());
272
276
migration2->set_srchost (hosts.at (2 ));
@@ -301,4 +305,78 @@ TEST_CASE_METHOD(
301
305
sch.checkForMigrationOpportunities ();
302
306
REQUIRE (sch.canAppBeMigrated (appId) == nullptr );
303
307
}
308
+
309
+ TEST_CASE_METHOD (
310
+ FunctionMigrationTestFixture,
311
+ " Test function migration thread detects migration opportunities" ,
312
+ " [scheduler]" )
313
+ {
314
+ std::vector<std::string> hosts = { masterHost, " hostA" };
315
+ std::vector<int > slots = { 1 , 1 };
316
+ std::vector<int > usedSlots = { 0 , 0 };
317
+ setHostResources (hosts, slots, usedSlots);
318
+
319
+ auto req = faabric::util::batchExecFactory (" foo" , " sleep" , 2 );
320
+ int checkPeriodSecs = 1 ;
321
+ int timeToSleep = 4 * checkPeriodSecs * 1000 ;
322
+ req->mutable_messages ()->at (0 ).set_inputdata (std::to_string (timeToSleep));
323
+ uint32_t appId = req->messages ().at (0 ).appid ();
324
+
325
+ // Opt in to be migrated
326
+ req->mutable_messages ()->at (0 ).set_migrationcheckperiod (checkPeriodSecs);
327
+
328
+ auto decision = sch.callFunctions (req);
329
+
330
+ std::shared_ptr<faabric::PendingMigrations> expectedMigrations;
331
+
332
+ SECTION (" Can not migrate" ) { expectedMigrations = nullptr ; }
333
+
334
+ // As we don't update the available resources, no migration opportunities
335
+ // will appear, even though we are checking for them
336
+ SECTION (" Can migrate" )
337
+ {
338
+ // Update host resources so that a migration opportunity appears
339
+ updateLocalResources (2 , 1 );
340
+
341
+ // Build expected result
342
+ faabric::PendingMigrations expected;
343
+ expected.set_appid (appId);
344
+ auto * migration = expected.add_migrations ();
345
+ migration->set_messageid (req->messages ().at (1 ).id ());
346
+ migration->set_srchost (hosts.at (1 ));
347
+ migration->set_dsthost (hosts.at (0 ));
348
+ expectedMigrations =
349
+ std::make_shared<faabric::PendingMigrations>(expected);
350
+ }
351
+
352
+ // Instead of directly calling the scheduler function to check for migration
353
+ // opportunites, sleep for enough time (twice the check period) so that a
354
+ // migration is detected by the background thread.
355
+ SLEEP_MS (2 * checkPeriodSecs * 1000 );
356
+
357
+ auto actualMigrations = sch.canAppBeMigrated (appId);
358
+ if (expectedMigrations == nullptr ) {
359
+ REQUIRE (actualMigrations == expectedMigrations);
360
+ } else {
361
+ REQUIRE (actualMigrations->appid () == expectedMigrations->appid ());
362
+ REQUIRE (actualMigrations->migrations_size () ==
363
+ expectedMigrations->migrations_size ());
364
+ for (int i = 0 ; i < actualMigrations->migrations_size (); i++) {
365
+ auto actual = actualMigrations->mutable_migrations ()->at (i);
366
+ auto expected = expectedMigrations->mutable_migrations ()->at (i);
367
+ REQUIRE (actual.messageid () == expected.messageid ());
368
+ REQUIRE (actual.srchost () == expected.srchost ());
369
+ REQUIRE (actual.dsthost () == expected.dsthost ());
370
+ }
371
+ }
372
+
373
+ faabric::Message res =
374
+ sch.getFunctionResult (req->messages ().at (0 ).id (), 2 * timeToSleep);
375
+ REQUIRE (res.returnvalue () == 0 );
376
+
377
+ // Check that after the result is set, the app can't be migrated no more
378
+ sch.checkForMigrationOpportunities ();
379
+ REQUIRE (sch.canAppBeMigrated (appId) == nullptr );
380
+ }
381
+
304
382
}
0 commit comments