|
177 | 177 | expect(before_cbx_task).not_to have_received(:run) |
178 | 178 | end |
179 | 179 | end |
| 180 | + |
| 181 | + describe 'error in :change_state callback' do |
| 182 | + subject do |
| 183 | + super() |
| 184 | + rescue error_class |
| 185 | + end |
| 186 | + |
| 187 | + let(:error_class) { Class.new(StandardError) } |
| 188 | + |
| 189 | + before do |
| 190 | + should_raise = true |
| 191 | + instance.define_callback( |
| 192 | + :change_state, :before, |
| 193 | + proc { |
| 194 | + if should_raise |
| 195 | + should_raise = false |
| 196 | + raise error_class, "That's unexpected!" |
| 197 | + end |
| 198 | + } |
| 199 | + ) |
| 200 | + callbacks_definitions |
| 201 | + end |
| 202 | + |
| 203 | + it_behaves_like 'asynchronous execution' |
| 204 | + end |
180 | 205 | end |
181 | 206 |
|
182 | 207 | describe '#stop' do |
|
384 | 409 | expect { subject }.to change { instance.state }.from("running").to("halting") |
385 | 410 | end |
386 | 411 | it 'changes the state to "stopped" after async_shutdown_time seconds' do |
387 | | - expect { subject; sleep async_shutdown_time + test_adjustment_time }.to change { |
388 | | - instance.state |
| 412 | + timeout = async_shutdown_time + test_adjustment_time |
| 413 | + expect { subject }.to change { |
| 414 | + dv(instance).deferred_wait(timeout: timeout) { _1.state == 'stopped' }.state |
389 | 415 | }.from("running").to("stopped") |
390 | 416 | end |
391 | | - it "releases runner's thread after async_shutdown_time seconds" do |
392 | | - expect { subject; sleep async_shutdown_time + test_adjustment_time }.to change { |
393 | | - instance.instance_variable_get(:@runner) |
| 417 | + it "releases runner's thread pointer after async_shutdown_time seconds" do |
| 418 | + timeout = async_shutdown_time + test_adjustment_time |
| 419 | + expect { subject }.to change { |
| 420 | + dv(instance).deferred_wait(timeout: timeout) { |
| 421 | + _1.instance_variable_get(:@runner).nil? |
| 422 | + }.instance_variable_get(:@runner) |
394 | 423 | }.from(instance_of(Thread)).to(nil) |
395 | 424 | end |
396 | | - it 'stops runners from processing further' do |
| 425 | + it "removes runner's thread" do |
397 | 426 | subject |
398 | 427 | thread = instance.instance_variable_get(:@runner) |
399 | 428 | aggregate_failures do |
|
402 | 431 | expect(Thread.list).not_to include(thread) |
403 | 432 | end |
404 | 433 | end |
| 434 | + it 'stops runners from processing further' do |
| 435 | + subject |
| 436 | + sleep async_shutdown_time |
| 437 | + expect { sleep run_interval }.not_to change { perform_async_results.size } |
| 438 | + end |
405 | 439 | end |
406 | 440 |
|
407 | 441 | context 'when state is "dead"' do |
|
437 | 471 | dv(instance).deferred_wait(timeout: async_shutdown_time) { _1.state == 'stopped' }.state |
438 | 472 | }.from('dead').to('stopped') |
439 | 473 | end |
440 | | - it "releases runner's thread after async_shutdown_time seconds" do |
441 | | - expect { subject; sleep async_shutdown_time }.to change { |
442 | | - instance.instance_variable_get(:@runner) |
| 474 | + it "releases runner's thread pointer after async_shutdown_time seconds" do |
| 475 | + expect { subject }.to change { |
| 476 | + dv(instance).deferred_wait(timeout: async_shutdown_time) { |
| 477 | + _1.instance_variable_get(:@runner).nil? |
| 478 | + }.instance_variable_get(:@runner) |
443 | 479 | }.from(instance_of(Thread)).to(nil) |
444 | 480 | end |
445 | | - it 'stops runners from processing further' do |
| 481 | + it "does not include runner's thread in the threads list" do |
446 | 482 | subject |
447 | 483 | thread = instance.instance_variable_get(:@runner) |
448 | | - sleep 0.1 |
449 | 484 | expect(Thread.list).not_to include(thread) |
450 | 485 | end |
451 | 486 | end |
452 | 487 | end |
| 488 | + |
| 489 | + describe 'error in :change_state callback' do |
| 490 | + subject do |
| 491 | + super() |
| 492 | + rescue error_class |
| 493 | + end |
| 494 | + |
| 495 | + let(:after_stopped_task) { double('After runner is stopped') } |
| 496 | + let(:perform_async_results) { [] } |
| 497 | + |
| 498 | + let(:error_class) { Class.new(StandardError) } |
| 499 | + |
| 500 | + # Adds some extra time needed ruby to apply changes from background thread to current thread |
| 501 | + let(:test_adjustment_time) { 0.2 } |
| 502 | + |
| 503 | + before do |
| 504 | + allow(after_stopped_task).to receive(:run) |
| 505 | + instance.define_callback(:after_runner_stopped, :before, proc { after_stopped_task.run }) |
| 506 | + instance.define_callback(:process_async, :before, proc { perform_async_results.push(:the_result) }) |
| 507 | + instance.start |
| 508 | + instance.define_callback( |
| 509 | + :change_state, :before, |
| 510 | + proc { |
| 511 | + # Disable stderr outputs |
| 512 | + Thread.report_on_exception = false |
| 513 | + raise error_class, "That's unexpected!" |
| 514 | + } |
| 515 | + ) |
| 516 | + dv(instance).wait_until(timeout: 0.1) { _1.state == 'running' } |
| 517 | + end |
| 518 | + |
| 519 | + it 'spawns another thread to stop the current runner' do |
| 520 | + expect { subject }.to change { Thread.list.size }.by(1) |
| 521 | + end |
| 522 | + it 'does not executes :after_runner_stopped action' do |
| 523 | + subject |
| 524 | + dv(instance).wait_until(timeout: async_shutdown_time) { instance.stopped? } |
| 525 | + expect(after_stopped_task).not_to have_received(:run) |
| 526 | + end |
| 527 | + it 'changes the state to "halting"' do |
| 528 | + expect { subject }.to change { instance.state }.from("running").to("halting") |
| 529 | + end |
| 530 | + it 'changes the state to "stopped" after async_shutdown_time seconds' do |
| 531 | + timeout = async_shutdown_time + test_adjustment_time |
| 532 | + expect { subject }.to change { |
| 533 | + dv(instance).deferred_wait(timeout: timeout) { _1.state == 'stopped' }.state |
| 534 | + }.from("running").to("stopped") |
| 535 | + end |
| 536 | + it "releases runner's thread pointer after async_shutdown_time seconds" do |
| 537 | + timeout = async_shutdown_time + test_adjustment_time |
| 538 | + expect { subject }.to change { |
| 539 | + dv(instance).deferred_wait(timeout: timeout) { |
| 540 | + _1.instance_variable_get(:@runner).nil? |
| 541 | + }.instance_variable_get(:@runner) |
| 542 | + }.from(instance_of(Thread)).to(nil) |
| 543 | + end |
| 544 | + it "removes runner's thread" do |
| 545 | + subject |
| 546 | + thread = instance.instance_variable_get(:@runner) |
| 547 | + aggregate_failures do |
| 548 | + expect(Thread.list).to include(thread) |
| 549 | + sleep async_shutdown_time |
| 550 | + expect(Thread.list).not_to include(thread) |
| 551 | + end |
| 552 | + end |
| 553 | + it 'stops runners from processing further' do |
| 554 | + subject |
| 555 | + sleep async_shutdown_time |
| 556 | + expect { sleep run_interval }.not_to change { perform_async_results.size } |
| 557 | + end |
| 558 | + end |
453 | 559 | end |
454 | 560 |
|
455 | 561 | describe '#restore' do |
|
0 commit comments