test: update beamer e2e contract
This commit is contained in:
parent
988171097c
commit
68b72cc01a
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
class Beamer < ApplicationRecord
|
class Beamer < ApplicationRecord
|
||||||
DEFAULT_NAME = 'default'
|
DEFAULT_NAME = 'default'
|
||||||
|
DEFAULT_CONFIG = { 'match_filter' => 'state:in_progress' }.freeze
|
||||||
DISPLAY_STATES = %w[
|
DISPLAY_STATES = %w[
|
||||||
during_game between_games static_image group_tables
|
during_game between_games static_image group_tables
|
||||||
].freeze
|
].freeze
|
||||||
|
|
|
||||||
|
|
@ -67,27 +67,32 @@ class Tournament < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def sync_configuration_is_complete
|
def sync_configuration_is_complete
|
||||||
return if sync_target_url.blank? && sync_auth_token.blank?
|
return if sync_configuration_blank?
|
||||||
return if sync_target_url.present? && sync_auth_token.present?
|
return if sync_configuration_complete?
|
||||||
return if read_only_mode? && sync_auth_token.present? && sync_target_url.blank?
|
return if follower_sync_token_only?
|
||||||
|
|
||||||
errors.add(:base, 'sync_target_url and sync_auth_token must be configured together')
|
errors.add(:base, 'sync_target_url and sync_auth_token must be configured together')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sync_configuration_blank?
|
||||||
|
sync_target_url.blank? && sync_auth_token.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def sync_configuration_complete?
|
||||||
|
sync_target_url.present? && sync_auth_token.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def follower_sync_token_only?
|
||||||
|
read_only_mode? && sync_auth_token.present? && sync_target_url.blank?
|
||||||
|
end
|
||||||
|
|
||||||
def ensure_default_beamer!
|
def ensure_default_beamer!
|
||||||
beamers.find_or_create_by!(name: Beamer::DEFAULT_NAME) do |beamer|
|
beamers.find_or_create_by!(name: Beamer::DEFAULT_NAME) do |beamer|
|
||||||
beamer.display_state = 'during_game'
|
beamer.display_state = 'during_game'
|
||||||
|
beamer.config = Beamer::DEFAULT_CONFIG
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def sync_configuration_is_complete
|
|
||||||
return if sync_target_url.blank? && sync_auth_token.blank?
|
|
||||||
return if sync_target_url.present? && sync_auth_token.present?
|
|
||||||
return if read_only_mode? && sync_auth_token.present? && sync_target_url.blank?
|
|
||||||
|
|
||||||
errors.add(:base, 'sync_target_url and sync_auth_token must be configured together')
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_follower_sync_token_when_disabling_read_only_mode
|
def clear_follower_sync_token_when_disabling_read_only_mode
|
||||||
return if read_only_mode?
|
return if read_only_mode?
|
||||||
return if sync_target_url.present?
|
return if sync_target_url.present?
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@ class ReplaceBeamerAssetFieldsWithConfig < ActiveRecord::Migration[7.0]
|
||||||
END
|
END
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
|
execute <<~SQL.squish
|
||||||
|
UPDATE beamers
|
||||||
|
SET config = '{"match_filter":"state:in_progress"}'
|
||||||
|
WHERE name = 'default'
|
||||||
|
SQL
|
||||||
|
|
||||||
change_column_default :beamers, :display_state, from: 'matches_all', to: 'during_game'
|
change_column_default :beamers, :display_state, from: 'matches_all', to: 'during_game'
|
||||||
remove_column :beamers, :qr_code_url, :string
|
remove_column :beamers, :qr_code_url, :string
|
||||||
remove_column :beamers, :logo_url, :string
|
remove_column :beamers, :logo_url, :string
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,26 @@ RSpec.describe 'Tournament beamer HTTP E2E' do
|
||||||
|
|
||||||
expect(default_beamer[:status]).to eq(200)
|
expect(default_beamer[:status]).to eq(200)
|
||||||
expect(default_beamer.dig(:json, :name)).to eq('default')
|
expect(default_beamer.dig(:json, :name)).to eq('default')
|
||||||
expect(default_beamer.dig(:json, :display_state)).to eq('matches_all')
|
expect(default_beamer.dig(:json, :display_state)).to eq('during_game')
|
||||||
|
expect(default_beamer.dig(:json, :config)).to eq(match_filter: 'state:in_progress')
|
||||||
expect(default_show[:status]).to eq(200)
|
expect(default_show[:status]).to eq(200)
|
||||||
|
expect(default_show.dig(:json, :config)).to eq(match_filter: 'state:in_progress')
|
||||||
|
|
||||||
create_response = owner_client.post("/tournaments/#{tournament.fetch(:id)}/beamers", body: {
|
create_response = owner_client.post("/tournaments/#{tournament.fetch(:id)}/beamers", body: {
|
||||||
name: 'hall-a',
|
name: 'hall-a',
|
||||||
display_state: 'groups',
|
display_state: 'group_tables',
|
||||||
qr_code_url: 'https://example.com/hall-a',
|
config: {
|
||||||
logo_url: '/logos/hall-a.png'
|
match_filter: 'stage:groups',
|
||||||
|
table_view: 'compact'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
expect(create_response[:status]).to eq(201)
|
expect(create_response[:status]).to eq(201)
|
||||||
beamer = create_response.fetch(:json)
|
beamer = create_response.fetch(:json)
|
||||||
expect(beamer.fetch(:name)).to eq('hall-a')
|
expect(beamer.fetch(:name)).to eq('hall-a')
|
||||||
expect(beamer.fetch(:display_state)).to eq('groups')
|
expect(beamer.fetch(:display_state)).to eq('group_tables')
|
||||||
expect(beamer.fetch(:qr_code_url)).to eq('https://example.com/hall-a')
|
expect(beamer.fetch(:config)).to eq(match_filter: 'stage:groups', table_view: 'compact')
|
||||||
|
expect(beamer).not_to have_key(:qr_code_url)
|
||||||
|
expect(beamer).not_to have_key(:logo_url)
|
||||||
|
|
||||||
index_response = anonymous_client.get("/tournaments/#{tournament.fetch(:id)}/beamers")
|
index_response = anonymous_client.get("/tournaments/#{tournament.fetch(:id)}/beamers")
|
||||||
show_response = anonymous_client.get("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}")
|
show_response = anonymous_client.get("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}")
|
||||||
|
|
@ -65,34 +71,41 @@ RSpec.describe 'Tournament beamer HTTP E2E' do
|
||||||
expect(by_name_response.dig(:json, :id)).to eq(beamer.fetch(:id))
|
expect(by_name_response.dig(:json, :id)).to eq(beamer.fetch(:id))
|
||||||
|
|
||||||
update_response = owner_client.patch("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}", body: {
|
update_response = owner_client.patch("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}", body: {
|
||||||
display_state: 'during_game',
|
display_state: 'static_image',
|
||||||
qr_code_url: 'https://example.com/live',
|
config: {
|
||||||
logo_url: '/logos/live.png'
|
image_key: 'bpwstr_logo'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
expect(update_response[:status]).to eq(200)
|
expect(update_response[:status]).to eq(200)
|
||||||
expect(update_response.dig(:json, :display_state)).to eq('during_game')
|
expect(update_response.dig(:json, :display_state)).to eq('static_image')
|
||||||
expect(update_response.dig(:json, :qr_code_url)).to eq('https://example.com/live')
|
expect(update_response.dig(:json, :config)).to eq(image_key: 'bpwstr_logo')
|
||||||
expect(update_response.dig(:json, :logo_url)).to eq('/logos/live.png')
|
expect(update_response[:json]).not_to have_key(:qr_code_url)
|
||||||
|
expect(update_response[:json]).not_to have_key(:logo_url)
|
||||||
|
|
||||||
invalid_update = owner_client.patch("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}", body: {
|
invalid_update = owner_client.patch("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}", body: {
|
||||||
display_state: 'bogus'
|
display_state: 'bogus'
|
||||||
})
|
})
|
||||||
|
invalid_config_update = owner_client.patch(
|
||||||
|
"/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}",
|
||||||
|
body: { config: ['not-an-object'] }
|
||||||
|
)
|
||||||
duplicate_create = owner_client.post("/tournaments/#{tournament.fetch(:id)}/beamers", body: {
|
duplicate_create = owner_client.post("/tournaments/#{tournament.fetch(:id)}/beamers", body: {
|
||||||
name: 'hall-a',
|
name: 'hall-a',
|
||||||
display_state: 'matches_all'
|
display_state: 'during_game'
|
||||||
})
|
})
|
||||||
forbidden_update = other_client.patch("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}", body: {
|
forbidden_update = other_client.patch("/tournaments/#{tournament.fetch(:id)}/beamers/#{beamer.fetch(:id)}", body: {
|
||||||
display_state: 'groups'
|
display_state: 'group_tables'
|
||||||
})
|
})
|
||||||
unauthenticated_create = anonymous_client.post(
|
unauthenticated_create = anonymous_client.post(
|
||||||
"/tournaments/#{tournament.fetch(:id)}/beamers",
|
"/tournaments/#{tournament.fetch(:id)}/beamers",
|
||||||
body: {
|
body: {
|
||||||
name: 'anon',
|
name: 'anon',
|
||||||
display_state: 'groups'
|
display_state: 'group_tables'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(invalid_update[:status]).to eq(422)
|
expect(invalid_update[:status]).to eq(422)
|
||||||
|
expect(invalid_config_update[:status]).to eq(422)
|
||||||
expect(duplicate_create[:status]).to eq(422)
|
expect(duplicate_create[:status]).to eq(422)
|
||||||
expect(forbidden_update[:status]).to eq(403)
|
expect(forbidden_update[:status]).to eq(403)
|
||||||
expect(unauthenticated_create[:status]).to eq(401)
|
expect(unauthenticated_create[:status]).to eq(401)
|
||||||
|
|
@ -108,7 +121,7 @@ RSpec.describe 'Tournament beamer HTTP E2E' do
|
||||||
)
|
)
|
||||||
locked_update = owner_client.patch(
|
locked_update = owner_client.patch(
|
||||||
beamer_path(read_only_tournament.fetch(:id), read_only_beamer.dig(:json, :id)),
|
beamer_path(read_only_tournament.fetch(:id), read_only_beamer.dig(:json, :id)),
|
||||||
body: { display_state: 'groups' }
|
body: { display_state: 'group_tables' }
|
||||||
)
|
)
|
||||||
expect(locked_update[:status]).to eq(423)
|
expect(locked_update[:status]).to eq(423)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ RSpec.describe 'Tournament follower sync beamer HTTP E2E' do
|
||||||
follower_default = wait_for_follower_beamer!(
|
follower_default = wait_for_follower_beamer!(
|
||||||
tournament_id: follower.fetch(:id),
|
tournament_id: follower.fetch(:id),
|
||||||
beamer_name: 'default',
|
beamer_name: 'default',
|
||||||
display_state: source_default.fetch(:display_state)
|
display_state: source_default.fetch(:display_state),
|
||||||
|
config: source_default.fetch(:config)
|
||||||
)
|
)
|
||||||
expect(follower_default.fetch(:name)).to eq('default')
|
expect(follower_default.fetch(:name)).to eq('default')
|
||||||
|
|
||||||
|
|
@ -49,8 +50,10 @@ RSpec.describe 'Tournament follower sync beamer HTTP E2E' do
|
||||||
beamer_path(source.fetch(:id), source_default.fetch(:id)),
|
beamer_path(source.fetch(:id), source_default.fetch(:id)),
|
||||||
body: {
|
body: {
|
||||||
display_state: 'between_games',
|
display_state: 'between_games',
|
||||||
qr_code_url: 'https://example.com/leader-default',
|
config: {
|
||||||
logo_url: '/logos/default.png'
|
match_filter: 'state:queued',
|
||||||
|
rotation_seconds: 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(leader_default_update[:status]).to eq(200)
|
expect(leader_default_update[:status]).to eq(200)
|
||||||
|
|
@ -60,16 +63,22 @@ RSpec.describe 'Tournament follower sync beamer HTTP E2E' do
|
||||||
tournament_id: follower.fetch(:id),
|
tournament_id: follower.fetch(:id),
|
||||||
beamer_name: 'default',
|
beamer_name: 'default',
|
||||||
display_state: 'between_games',
|
display_state: 'between_games',
|
||||||
qr_code_url: 'https://example.com/leader-default',
|
config: {
|
||||||
logo_url: '/logos/default.png'
|
match_filter: 'state:queued',
|
||||||
|
rotation_seconds: 10
|
||||||
|
}
|
||||||
)
|
)
|
||||||
expect(mirrored_default.fetch(:name)).to eq('default')
|
expect(mirrored_default.fetch(:name)).to eq('default')
|
||||||
|
expect(mirrored_default).not_to have_key(:qr_code_url)
|
||||||
|
expect(mirrored_default).not_to have_key(:logo_url)
|
||||||
|
|
||||||
leader_create = source_client.post("/tournaments/#{source.fetch(:id)}/beamers", body: {
|
leader_create = source_client.post("/tournaments/#{source.fetch(:id)}/beamers", body: {
|
||||||
name: 'stage-left',
|
name: 'stage-left',
|
||||||
display_state: 'groups',
|
display_state: 'group_tables',
|
||||||
qr_code_url: 'https://example.com/stage-left',
|
config: {
|
||||||
logo_url: '/logos/stage-left.png'
|
match_filter: 'stage:groups',
|
||||||
|
table_view: 'compact'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
expect(leader_create[:status]).to eq(201)
|
expect(leader_create[:status]).to eq(201)
|
||||||
sync_now_if_requested!(source.fetch(:id))
|
sync_now_if_requested!(source.fetch(:id))
|
||||||
|
|
@ -77,17 +86,23 @@ RSpec.describe 'Tournament follower sync beamer HTTP E2E' do
|
||||||
mirrored_created = wait_for_follower_beamer!(
|
mirrored_created = wait_for_follower_beamer!(
|
||||||
tournament_id: follower.fetch(:id),
|
tournament_id: follower.fetch(:id),
|
||||||
beamer_name: 'stage-left',
|
beamer_name: 'stage-left',
|
||||||
display_state: 'groups',
|
display_state: 'group_tables',
|
||||||
qr_code_url: 'https://example.com/stage-left',
|
config: {
|
||||||
logo_url: '/logos/stage-left.png'
|
match_filter: 'stage:groups',
|
||||||
|
table_view: 'compact'
|
||||||
|
}
|
||||||
)
|
)
|
||||||
expect(mirrored_created.fetch(:name)).to eq('stage-left')
|
expect(mirrored_created.fetch(:name)).to eq('stage-left')
|
||||||
|
expect(mirrored_created).not_to have_key(:qr_code_url)
|
||||||
|
expect(mirrored_created).not_to have_key(:logo_url)
|
||||||
|
|
||||||
leader_update = source_client.patch(
|
leader_update = source_client.patch(
|
||||||
beamer_path(source.fetch(:id), leader_create.dig(:json, :id)),
|
beamer_path(source.fetch(:id), leader_create.dig(:json, :id)),
|
||||||
body: {
|
body: {
|
||||||
display_state: 'during_game',
|
display_state: 'static_image',
|
||||||
qr_code_url: 'https://example.com/stage-left-live'
|
config: {
|
||||||
|
image_key: 'stage-left-live'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(leader_update[:status]).to eq(200)
|
expect(leader_update[:status]).to eq(200)
|
||||||
|
|
@ -96,14 +111,17 @@ RSpec.describe 'Tournament follower sync beamer HTTP E2E' do
|
||||||
mirrored_updated = wait_for_follower_beamer!(
|
mirrored_updated = wait_for_follower_beamer!(
|
||||||
tournament_id: follower.fetch(:id),
|
tournament_id: follower.fetch(:id),
|
||||||
beamer_name: 'stage-left',
|
beamer_name: 'stage-left',
|
||||||
display_state: 'during_game',
|
display_state: 'static_image',
|
||||||
qr_code_url: 'https://example.com/stage-left-live'
|
config: {
|
||||||
|
image_key: 'stage-left-live'
|
||||||
|
}
|
||||||
)
|
)
|
||||||
expect(mirrored_updated.fetch(:logo_url)).to eq('/logos/stage-left.png')
|
expect(mirrored_updated).not_to have_key(:qr_code_url)
|
||||||
|
expect(mirrored_updated).not_to have_key(:logo_url)
|
||||||
|
|
||||||
locked_follower_update = follower_client.patch(
|
locked_follower_update = follower_client.patch(
|
||||||
beamer_path(follower.fetch(:id), mirrored_updated.fetch(:id)),
|
beamer_path(follower.fetch(:id), mirrored_updated.fetch(:id)),
|
||||||
body: { display_state: 'matches_finished' }
|
body: { display_state: 'during_game' }
|
||||||
)
|
)
|
||||||
expect(locked_follower_update[:status]).to eq(423)
|
expect(locked_follower_update[:status]).to eq(423)
|
||||||
|
|
||||||
|
|
@ -150,7 +168,7 @@ RSpec.describe 'Tournament follower sync beamer HTTP E2E' do
|
||||||
response = follower_read_client.get(beamer_by_name_path(tournament_id), params: { name: beamer_name })
|
response = follower_read_client.get(beamer_by_name_path(tournament_id), params: { name: beamer_name })
|
||||||
if response[:status] == 200 && response.dig(:json, :name) == beamer_name
|
if response[:status] == 200 && response.dig(:json, :name) == beamer_name
|
||||||
beamer = response.fetch(:json)
|
beamer = response.fetch(:json)
|
||||||
return beamer if expected_attrs.all? { |key, value| beamer.fetch(key) == value }
|
return beamer if expected_attrs.all? { |key, value| beamer[key] == value }
|
||||||
end
|
end
|
||||||
|
|
||||||
raise "follower beamer #{beamer_name} not synced within #{timeout}s" if Time.now.utc >= deadline
|
raise "follower beamer #{beamer_name} not synced within #{timeout}s" if Time.now.utc >= deadline
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,10 @@ FactoryBot.define do
|
||||||
|
|
||||||
factory :default_beamer do
|
factory :default_beamer do
|
||||||
name { Beamer::DEFAULT_NAME }
|
name { Beamer::DEFAULT_NAME }
|
||||||
|
config { Beamer::DEFAULT_CONFIG }
|
||||||
|
|
||||||
initialize_with do
|
initialize_with do
|
||||||
tournament.beamers.find_or_initialize_by(name: name)
|
tournament.beamers.find_or_initialize_by(name:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,11 @@ RSpec.describe Tournament, type: :model do
|
||||||
describe 'default beamer' do
|
describe 'default beamer' do
|
||||||
it 'creates a default beamer automatically' do
|
it 'creates a default beamer automatically' do
|
||||||
tournament = create(:tournament)
|
tournament = create(:tournament)
|
||||||
|
default_beamer = tournament.beamers.find_by!(name: Beamer::DEFAULT_NAME)
|
||||||
|
|
||||||
expect(tournament.beamers.pluck(:name)).to include(Beamer::DEFAULT_NAME)
|
expect(tournament.beamers.pluck(:name)).to include(Beamer::DEFAULT_NAME)
|
||||||
|
expect(default_beamer.display_state).to eq('during_game')
|
||||||
|
expect(default_beamer.config).to eq(Beamer::DEFAULT_CONFIG)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue