Merge branch 'TUR-61-fix-final-match-save' into 'master'
TUR-61 Fix final match completion after group stage Closes TUR-61 See merge request turniere/turniere-backend!35
This commit is contained in:
commit
84cdb230fb
|
|
@ -70,7 +70,9 @@ class PlayoffStageService
|
||||||
# @return [Array] the objects that changed and need to be saved
|
# @return [Array] the objects that changed and need to be saved
|
||||||
def populate_match_below(current_match)
|
def populate_match_below(current_match)
|
||||||
current_stage = current_match.stage
|
current_stage = current_match.stage
|
||||||
next_stage = current_stage.tournament.stages.find { |s| s.level == current_stage.level - 1 }
|
next_stage = current_stage.tournament.stages
|
||||||
|
.select { |stage| stage.matches.any? && stage.level < current_stage.level }
|
||||||
|
.max_by(&:level)
|
||||||
# return if next stage does not exist (there are no matches after the finale)
|
# return if next stage does not exist (there are no matches after the finale)
|
||||||
return [] if next_stage.nil?
|
return [] if next_stage.nil?
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ require 'time'
|
||||||
module TurniereE2E
|
module TurniereE2E
|
||||||
class ScenarioRunner
|
class ScenarioRunner
|
||||||
DEFAULT_PASSWORD = 'password123'.freeze
|
DEFAULT_PASSWORD = 'password123'.freeze
|
||||||
FINAL_FINISH_ERROR = 'Moving Team one stage down failed'
|
|
||||||
|
|
||||||
attr_reader :client
|
attr_reader :client
|
||||||
|
|
||||||
|
|
@ -65,12 +64,7 @@ module TurniereE2E
|
||||||
return result(session: session, tournament: tournament, checkpoints: checkpoints, stop_at: stop_at) if stop_at == :before_final_finish_attempt
|
return result(session: session, tournament: tournament, checkpoints: checkpoints, stop_at: stop_at) if stop_at == :before_final_finish_attempt
|
||||||
|
|
||||||
final_match = final_match_of!(tournament)
|
final_match = final_match_of!(tournament)
|
||||||
finish_attempt = play_match!(
|
finish_attempt = play_match!(final_match, winner_name: preferred_playoff_winner_name(final_match))
|
||||||
final_match,
|
|
||||||
winner_name: preferred_playoff_winner_name(final_match),
|
|
||||||
expected_finish_status: 422,
|
|
||||||
expected_finish_error: FINAL_FINISH_ERROR
|
|
||||||
)
|
|
||||||
tournament = fetch_tournament!(tournament.fetch(:id))
|
tournament = fetch_tournament!(tournament.fetch(:id))
|
||||||
checkpoints[:final_finish_attempted] = {
|
checkpoints[:final_finish_attempted] = {
|
||||||
finish_attempt: finish_attempt,
|
finish_attempt: finish_attempt,
|
||||||
|
|
@ -103,12 +97,7 @@ module TurniereE2E
|
||||||
return result(session: session, tournament: tournament, checkpoints: checkpoints, stop_at: stop_at) if stop_at == :before_final_finish_attempt
|
return result(session: session, tournament: tournament, checkpoints: checkpoints, stop_at: stop_at) if stop_at == :before_final_finish_attempt
|
||||||
|
|
||||||
final_match = final_match_of!(tournament)
|
final_match = final_match_of!(tournament)
|
||||||
finish_attempt = play_match!(
|
finish_attempt = play_match!(final_match, winner_name: preferred_playoff_winner_name(final_match))
|
||||||
final_match,
|
|
||||||
winner_name: preferred_playoff_winner_name(final_match),
|
|
||||||
expected_finish_status: 422,
|
|
||||||
expected_finish_error: FINAL_FINISH_ERROR
|
|
||||||
)
|
|
||||||
tournament = fetch_tournament!(tournament.fetch(:id))
|
tournament = fetch_tournament!(tournament.fetch(:id))
|
||||||
checkpoints[:final_finish_attempted] = {
|
checkpoints[:final_finish_attempted] = {
|
||||||
finish_attempt: finish_attempt,
|
finish_attempt: finish_attempt,
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,9 @@ RSpec.describe MatchesController, type: :controller do
|
||||||
|
|
||||||
context 'PopulateMatchBelowAndSave fails' do
|
context 'PopulateMatchBelowAndSave fails' do
|
||||||
before do
|
before do
|
||||||
expect(PopulateMatchBelowAndSave).to receive(:call).once.with(match: @running_playoff_match)
|
expect(PopulateMatchBelowAndSave).to receive(:call).once.with(
|
||||||
|
match: have_attributes(id: @running_playoff_match.id)
|
||||||
|
)
|
||||||
.and_return(context)
|
.and_return(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -204,7 +206,7 @@ RSpec.describe MatchesController, type: :controller do
|
||||||
|
|
||||||
it 'returns unprocessable entity' do
|
it 'returns unprocessable entity' do
|
||||||
# mock match.winner to be the first team of the match to skip winner check here
|
# mock match.winner to be the first team of the match to skip winner check here
|
||||||
allow(@running_playoff_match).to receive(:winner).and_return(@running_playoff_match.match_scores.first.team)
|
allow_any_instance_of(Match).to receive(:winner).and_return(@running_playoff_match.match_scores.first.team)
|
||||||
|
|
||||||
put :update, params: { id: @running_playoff_match.to_param }.merge(finished)
|
put :update, params: { id: @running_playoff_match.to_param }.merge(finished)
|
||||||
expect(response).to have_http_status(:unprocessable_entity)
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ RSpec.describe 'Tournament lifecycle HTTP E2E' do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'drives the main 4x4 group-stage use case over HTTP and preserves the current final-finish behavior' do
|
it 'drives the main 4x4 group-stage use case over HTTP through a finished final' do
|
||||||
result = runner.run_group_stage_main_usecase
|
result = runner.run_group_stage_main_usecase
|
||||||
|
|
||||||
expect(result.dig(:checkpoints, :created, :playoff_teams_amount)).to eq(8)
|
expect(result.dig(:checkpoints, :created, :playoff_teams_amount)).to eq(8)
|
||||||
|
|
@ -35,11 +35,12 @@ RSpec.describe 'Tournament lifecycle HTTP E2E' do
|
||||||
expect(playoff_entry_stage[:match_states].count).to eq(4)
|
expect(playoff_entry_stage[:match_states].count).to eq(4)
|
||||||
|
|
||||||
final_attempt = result.dig(:checkpoints, :final_finish_attempted, :finish_attempt)
|
final_attempt = result.dig(:checkpoints, :final_finish_attempted, :finish_attempt)
|
||||||
expect(final_attempt[:status]).to eq(422)
|
expect(final_attempt[:status]).to eq(200)
|
||||||
expect(final_attempt.dig(:body, :error)).to eq('Moving Team one stage down failed')
|
expect(result.dig(:checkpoints, :final_finish_attempted, :tournament, :stage_summaries)
|
||||||
|
.find { |stage| stage[:level] == 0 }[:match_states]).to eq(['finished'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'drives the 3-group intermediate-round path over HTTP and preserves the current advancing behavior' do
|
it 'drives the 3-group intermediate-round path over HTTP through a finished final' do
|
||||||
result = runner.run_group_stage_intermediate_round
|
result = runner.run_group_stage_intermediate_round
|
||||||
|
|
||||||
created = result.fetch(:checkpoints).fetch(:created)
|
created = result.fetch(:checkpoints).fetch(:created)
|
||||||
|
|
@ -55,8 +56,9 @@ RSpec.describe 'Tournament lifecycle HTTP E2E' do
|
||||||
expect(playoff_entry_stage[:match_states].count('not_started')).to eq(1)
|
expect(playoff_entry_stage[:match_states].count('not_started')).to eq(1)
|
||||||
|
|
||||||
final_attempt = result.dig(:checkpoints, :final_finish_attempted, :finish_attempt)
|
final_attempt = result.dig(:checkpoints, :final_finish_attempted, :finish_attempt)
|
||||||
expect(final_attempt[:status]).to eq(422)
|
expect(final_attempt[:status]).to eq(200)
|
||||||
expect(final_attempt.dig(:body, :error)).to eq('Moving Team one stage down failed')
|
expect(result.dig(:checkpoints, :final_finish_attempted, :tournament, :stage_summaries)
|
||||||
|
.find { |stage| stage[:level] == 0 }[:match_states]).to eq(['finished'])
|
||||||
end
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -20,18 +20,6 @@ The reusable scenario script supports this through:
|
||||||
|
|
||||||
Frontend tests can use the same script against a live backend as long as those credentials point to a confirmed account on that backend.
|
Frontend tests can use the same script against a live backend as long as those credentials point to a confirmed account on that backend.
|
||||||
|
|
||||||
## Group-stage tournaments cannot finish the playoff final through the normal match endpoint
|
|
||||||
|
|
||||||
Observed and covered by `spec/e2e/http/tournament_lifecycle_spec.rb` and `script/e2e_scenarios.rb`:
|
|
||||||
|
|
||||||
- in tournaments that started with a group stage, the playoff final can be started and scored
|
|
||||||
- but `PATCH /matches/:id` with `state=finished` on that final returns:
|
|
||||||
- status `422`
|
|
||||||
- error `"Moving Team one stage down failed"`
|
|
||||||
- the final remains `in_progress`
|
|
||||||
|
|
||||||
This appears to happen because playoff stages count down to level `0`, while the old group stage still exists at level `-1`. The final-finish flow looks for a "stage below" using `current_stage.level - 1`, which resolves to the group stage for finals in group-stage tournaments. The E2E suite preserves this current behavior instead of changing backend code.
|
|
||||||
|
|
||||||
## Group stage to playoff conversion with 3 groups and `playoff_teams_amount = 4`
|
## Group stage to playoff conversion with 3 groups and `playoff_teams_amount = 4`
|
||||||
|
|
||||||
Observed and covered by `spec/e2e/http/tournament_lifecycle_spec.rb` and `script/e2e_scenarios.rb`:
|
Observed and covered by `spec/e2e/http/tournament_lifecycle_spec.rb` and `script/e2e_scenarios.rb`:
|
||||||
|
|
|
||||||
|
|
@ -212,5 +212,22 @@ RSpec.describe PlayoffStageService do
|
||||||
expect(@test.state).to eq('not_started')
|
expect(@test.state).to eq('not_started')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the current match is the final of a tournament with a group stage' do
|
||||||
|
before do
|
||||||
|
@tournament = create(:group_stage_tournament, stage_count: 1)
|
||||||
|
@final_match = @tournament.stages.reject { |stage| stage.level == -1 }.max_by(&:level).matches.first
|
||||||
|
@final_match.state = :finished
|
||||||
|
@final_match.match_scores.each_with_index do |match_score, index|
|
||||||
|
match_score.points = index
|
||||||
|
match_score.save!
|
||||||
|
end
|
||||||
|
@final_match.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not treat the group stage as a lower playoff stage' do
|
||||||
|
expect(PlayoffStageService.populate_match_below(@final_match)).to eq([])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue