Merge pull request #48 from turniere/ticket/TURNIERE-226

Fix Playoff Matches ending without a winner
This commit is contained in:
Thor77 2019-06-05 17:56:49 +02:00 committed by GitHub
commit 42ee77d0ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 213 additions and 94 deletions

View File

@ -13,22 +13,37 @@ class MatchesController < ApplicationController
# PATCH/PUT /matches/1 # PATCH/PUT /matches/1
def update def update
new_state = match_params['state'] new_state = match_params['state']
Match.transaction do
if @match.update(match_params) if @match.update(match_params)
if new_state == 'finished' handle_match_end if new_state == 'finished'
result = PopulateMatchBelowAndSave.call(match: @match) unless @match.group_match?
unless result.success?
render json: { error: 'Moving Team one stage down failed' }, status: :unprocessable_entity
return
end
end
render json: @match render json: @match
else else
render json: @match.errors, status: :unprocessable_entity render json: @match.errors, status: :unprocessable_entity
raise ActiveRecord::Rollback
end
end end
end end
private private
def handle_match_end
return if @match.group_match?
if @match.winner.nil?
render json: { error: 'Stopping undecided Matches isn\'t allowed in playoff stage' },
status: :unprocessable_entity
raise ActiveRecord::Rollback
end
return if PopulateMatchBelowAndSave.call(match: @match).success?
render json: { error: 'Moving Team one stage down failed' },
status: :unprocessable_entity
raise ActiveRecord::Rollback
end
def validate_params def validate_params
case match_params['state'] case match_params['state']
when 'in_progress' when 'in_progress'

View File

@ -8,6 +8,7 @@ RSpec.describe MatchesController, type: :controller do
@amount_of_stages = 2 @amount_of_stages = 2
@tournament = create(:stage_tournament, stage_count: @amount_of_stages) @tournament = create(:stage_tournament, stage_count: @amount_of_stages)
@running_playoff_match = @tournament.stages.find_by(level: @amount_of_stages).matches.first @running_playoff_match = @tournament.stages.find_by(level: @amount_of_stages).matches.first
@not_ready_playoff_match = create(:running_playoff_match, state: :not_ready)
@match.match_scores = create_pair(:match_score) @match.match_scores = create_pair(:match_score)
end end
@ -27,6 +28,7 @@ RSpec.describe MatchesController, type: :controller do
end end
describe 'POST #update' do describe 'POST #update' do
context 'on a running playoff match' do
let(:valid_update) do let(:valid_update) do
{ {
state: 'in_progress' state: 'in_progress'
@ -39,6 +41,12 @@ RSpec.describe MatchesController, type: :controller do
} }
end end
let(:senseless_update) do
{
state: 'not_ready'
}
end
context 'as owner' do context 'as owner' do
before(:each) do before(:each) do
apply_authentication_headers_for @match.owner apply_authentication_headers_for @match.owner
@ -70,6 +78,8 @@ RSpec.describe MatchesController, type: :controller do
apply_authentication_headers_for @running_playoff_match.owner apply_authentication_headers_for @running_playoff_match.owner
end end
context 'match update succeeds' do
context 'on a decided match' do
before do before do
@running_playoff_match.match_scores.each_with_index do |ms, i| @running_playoff_match.match_scores.each_with_index do |ms, i|
ms.points = i ms.points = i
@ -100,6 +110,71 @@ RSpec.describe MatchesController, type: :controller do
end end
end end
end end
context 'on an undecided match' do
before do
@running_playoff_match.match_scores.each do |ms|
ms.points = 42
ms.save!
end
put :update, params: { id: @running_playoff_match.to_param }.merge(finished)
@running_playoff_match.reload
end
it 'returns an unprocessable entity response' do
expect(response).to have_http_status(:unprocessable_entity)
end
it 'doesn\'t change the matches status' do
expect(@running_playoff_match.state).to eq('in_progress')
end
describe 'doesn\'t update the match below' do
before do
@match_below = @tournament.stages.find_by(level: @amount_of_stages - 1).matches
.find_by(position: @running_playoff_match.position / 2).reload
end
it 'teams' do
expect(@match_below.teams.empty?).to be(true)
end
it 'status' do
expect(@match_below.state).to eq('not_ready')
end
end
end
end
context 'match update fails' do
before do
allow_any_instance_of(Match)
.to receive(:update)
.and_return(false)
end
it 'returns unprocessable entity' do
put :update, params: { id: @running_playoff_match.to_param }.merge(finished)
expect(response).to have_http_status(:unprocessable_entity)
end
end
context 'PopulateMatchBelowAndSave fails' do
before do
expect(PopulateMatchBelowAndSave).to receive(:call).once.with(match: @running_playoff_match)
.and_return(context)
end
context 'when unsuccessful' do
let(:context) { double(:context, success?: false) }
it 'returns unprocessable entity' do
put :update, params: { id: @running_playoff_match.to_param }.merge(finished)
expect(response).to have_http_status(:unprocessable_entity)
end
end
end
end
end end
context 'with invalid params' do context 'with invalid params' do
@ -108,6 +183,13 @@ RSpec.describe MatchesController, type: :controller do
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
end end
end end
context 'with senseless params' do
it 'renders an unprocessable entity response' do
put :update, params: { id: @match.to_param }.merge(senseless_update)
expect(response).to have_http_status(:unprocessable_entity)
end
end
end end
context 'as another user' do context 'as another user' do
@ -123,4 +205,26 @@ RSpec.describe MatchesController, type: :controller do
end end
end end
end end
context 'on a playoff match that isn\'t ready yet' do
let(:invalid_update) do
{
state: 'in_progress'
}
end
context 'as owner' do
before(:each) do
apply_authentication_headers_for @not_ready_playoff_match.owner
end
context 'with invalid params' do
it 'renders an unprocessable entity response' do
put :update, params: { id: @not_ready_playoff_match.to_param }.merge(invalid_update)
expect(response).to have_http_status(:unprocessable_entity)
end
end
end
end
end
end end

View File

@ -15,7 +15,7 @@ FactoryBot.define do
end end
factory :empty_prepared_playoff_match do factory :empty_prepared_playoff_match do
state { :not_started } state { :not_ready }
end end
factory :decided_playoff_match do factory :decided_playoff_match do