From f18c37401e1d99f27b4bcb4f6723990f2fed37fc Mon Sep 17 00:00:00 2001 From: Malaber Date: Thu, 16 Apr 2026 10:06:55 +0200 Subject: [PATCH] Revert "Drop follow sync debug tasks" This reverts commit 6fdcbb9d570bab602689a602d8eff951741c8a63. --- tasks.py | 392 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) diff --git a/tasks.py b/tasks.py index 6f639c8..206f382 100644 --- a/tasks.py +++ b/tasks.py @@ -1102,6 +1102,398 @@ def docker_blackbox_follow_bootstrap_users( ) +@task(name="docker-blackbox-follow-debug-auth") +def docker_blackbox_follow_debug_auth( + c, + source_host_port=BLACKBOX_SOURCE_HOST_PORT, + follower_host_port=BLACKBOX_FOLLOWER_HOST_PORT, + app_image=PRODUCTION_TAG, + runner_image=TEST_TAG, + postgres_image=BLACKBOX_POSTGRES_IMAGE, +): + """Debug source/follower login and first authenticated create inside local follower blackbox runner.""" + env = _follow_compose_env( + source_host_port=source_host_port, + follower_host_port=follower_host_port, + app_image=app_image, + runner_image=runner_image, + postgres_image=postgres_image, + ) + + script = """ +require_relative 'e2e/lib/api_client' + +def inspect_client(base_url) + client = TurniereE2E::ApiClient.new(base_url: base_url) + login = client.login!(email: ENV.fetch('TURNIERE_E2E_EMAIL'), password: ENV.fetch('TURNIERE_E2E_PASSWORD')) + puts({ base_url: base_url, login_status: login[:status], login_headers: login[:headers].slice('access-token', 'client', 'uid', 'expiry', 'token-type', 'authorization'), authenticated: client.authenticated? }.inspect) + + create = client.post('/tournaments', body: { + name: "Debug #{base_url}", + description: 'Debug tournament', + public: false, + teams: [ + { name: 'One' }, + { name: 'Two' }, + { name: 'Three' }, + { name: 'Four' } + ] + }) + puts({ base_url: base_url, create_status: create[:status], create_json: create[:json], create_headers: create[:headers].slice('access-token', 'client', 'uid', 'expiry', 'token-type', 'authorization') }.inspect) +end + +inspect_client(ENV.fetch('TURNIERE_SOURCE_E2E_BASE_URL')) +inspect_client(ENV.fetch('TURNIERE_FOLLOWER_E2E_BASE_URL')) +""" + command = [ + "run", + "--rm", + "e2e", + "ruby", + "-e", + script, + ] + print(_format_command(_docker_compose_cmd(project_name=BLACKBOX_FOLLOW_PROJECT, compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE) + command)) + result = _compose_run( + command, + env=env, + capture_output=True, + check=False, + project_name=BLACKBOX_FOLLOW_PROJECT, + compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE, + ) + if result.stdout: + print(result.stdout.rstrip()) + if result.stderr: + print(result.stderr.rstrip()) + + if result.returncode != 0: + raise subprocess.CalledProcessError( + result.returncode, + result.args, + output=result.stdout, + stderr=result.stderr, + ) + + +@task(name="docker-blackbox-follow-debug-seed") +def docker_blackbox_follow_debug_seed( + c, + source_host_port=BLACKBOX_SOURCE_HOST_PORT, + follower_host_port=BLACKBOX_FOLLOWER_HOST_PORT, + app_image=PRODUCTION_TAG, + runner_image=TEST_TAG, + postgres_image=BLACKBOX_POSTGRES_IMAGE, +): + """Debug repeated mixed tournament creation inside local follower blackbox runner.""" + env = _follow_compose_env( + source_host_port=source_host_port, + follower_host_port=follower_host_port, + app_image=app_image, + runner_image=runner_image, + postgres_image=postgres_image, + ) + + script = """ +require_relative 'e2e/lib/api_client' + +def create_playoff_payload(name) + { + name: name, + description: 'Debug playoff tournament', + public: false, + teams: [ + { name: 'One' }, + { name: 'Two' }, + { name: 'Three' }, + { name: 'Four' } + ] + } +end + +def create_group_payload(name) + { + name: name, + description: 'Debug group tournament', + public: true, + group_stage: true, + playoff_teams_amount: 8, + teams: 4.times.flat_map do |group_index| + 4.times.map do |seed_index| + { name: "#{name}-G#{group_index + 1}-S#{seed_index + 1}", group: group_index } + end + end + } +end + +def inspect_seed(base_url) + client = TurniereE2E::ApiClient.new(base_url: base_url) + login = client.login!(email: ENV.fetch('TURNIERE_E2E_EMAIL'), password: ENV.fetch('TURNIERE_E2E_PASSWORD')) + puts({ base_url: base_url, login_status: login[:status], authenticated: client.authenticated? }.inspect) + + [ + ['playoff-1', create_playoff_payload('Debug Playoff 1')], + ['group-1', create_group_payload('Debug Group 1')], + ['playoff-2', create_playoff_payload('Debug Playoff 2')], + ['group-2', create_group_payload('Debug Group 2')] + ].each do |label, payload| + response = client.post('/tournaments', body: payload) + puts({ + base_url: base_url, + step: label, + status: response[:status], + json: response[:json], + headers: response[:headers].slice('access-token', 'client', 'uid', 'expiry', 'token-type', 'authorization'), + authenticated: client.authenticated? + }.inspect) + end +end + +inspect_seed(ENV.fetch('TURNIERE_SOURCE_E2E_BASE_URL')) +inspect_seed(ENV.fetch('TURNIERE_FOLLOWER_E2E_BASE_URL')) +""" + command = [ + "run", + "--rm", + "e2e", + "ruby", + "-e", + script, + ] + print(_format_command(_docker_compose_cmd(project_name=BLACKBOX_FOLLOW_PROJECT, compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE) + command)) + result = _compose_run( + command, + env=env, + capture_output=True, + check=False, + project_name=BLACKBOX_FOLLOW_PROJECT, + compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE, + ) + if result.stdout: + print(result.stdout.rstrip()) + if result.stderr: + print(result.stderr.rstrip()) + + if result.returncode != 0: + raise subprocess.CalledProcessError( + result.returncode, + result.args, + output=result.stdout, + stderr=result.stderr, + ) + + +@task(name="docker-blackbox-follow-debug-group-create") +def docker_blackbox_follow_debug_group_create( + c, + source_host_port=BLACKBOX_SOURCE_HOST_PORT, + follower_host_port=BLACKBOX_FOLLOWER_HOST_PORT, + app_image=PRODUCTION_TAG, + runner_image=TEST_TAG, + postgres_image=BLACKBOX_POSTGRES_IMAGE, +): + """Debug single fresh-login group-stage tournament creation inside local follower blackbox runner.""" + env = _follow_compose_env( + source_host_port=source_host_port, + follower_host_port=follower_host_port, + app_image=app_image, + runner_image=runner_image, + postgres_image=postgres_image, + ) + + script = """ +require_relative 'e2e/lib/api_client' + +def create_group_payload(name) + { + name: name, + description: 'Debug group tournament', + public: true, + group_stage: true, + playoff_teams_amount: 8, + teams: 4.times.flat_map do |group_index| + 4.times.map do |seed_index| + { name: "#{name}-G#{group_index + 1}-S#{seed_index + 1}", group: group_index } + end + end + } +end + +def inspect_group_create(base_url) + client = TurniereE2E::ApiClient.new(base_url: base_url) + login = client.login!(email: ENV.fetch('TURNIERE_E2E_EMAIL'), password: ENV.fetch('TURNIERE_E2E_PASSWORD')) + puts({ base_url: base_url, login_status: login[:status], authenticated: client.authenticated? }.inspect) + response = client.post('/tournaments', body: create_group_payload('Fresh Debug Group')) + puts({ base_url: base_url, create_status: response[:status], create_json: response[:json], create_headers: response[:headers].slice('access-token', 'client', 'uid', 'expiry', 'token-type', 'authorization') }.inspect) +end + +inspect_group_create(ENV.fetch('TURNIERE_SOURCE_E2E_BASE_URL')) +inspect_group_create(ENV.fetch('TURNIERE_FOLLOWER_E2E_BASE_URL')) +""" + command = [ + "run", + "--rm", + "e2e", + "ruby", + "-e", + script, + ] + print(_format_command(_docker_compose_cmd(project_name=BLACKBOX_FOLLOW_PROJECT, compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE) + command)) + result = _compose_run( + command, + env=env, + capture_output=True, + check=False, + project_name=BLACKBOX_FOLLOW_PROJECT, + compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE, + ) + if result.stdout: + print(result.stdout.rstrip()) + if result.stderr: + print(result.stderr.rstrip()) + + if result.returncode != 0: + raise subprocess.CalledProcessError( + result.returncode, + result.args, + output=result.stdout, + stderr=result.stderr, + ) + + +@task(name="docker-blackbox-follow-debug-sync") +def docker_blackbox_follow_debug_sync( + c, + source_host_port=BLACKBOX_SOURCE_HOST_PORT, + follower_host_port=BLACKBOX_FOLLOWER_HOST_PORT, + app_image=PRODUCTION_TAG, + runner_image=TEST_TAG, + postgres_image=BLACKBOX_POSTGRES_IMAGE, + log_tail=120, +): + """Print local follower blackbox sync queue state and recent app logs.""" + env = _follow_compose_env( + source_host_port=source_host_port, + follower_host_port=follower_host_port, + app_image=app_image, + runner_image=runner_image, + postgres_image=postgres_image, + ) + + script = """ +puts '== Source tournaments ==' +Tournament.order(:id).pluck(:id, :name, :read_only_mode, :sync_target_url, :sync_last_pushed_at, :sync_last_push_error).each { |row| p row } +puts '== Source sync queue ==' +TournamentSyncQueueEntry.order(:id).pluck(:id, :tournament_id, :status, :attempts, :last_error, :next_attempt_at, :last_attempt_at).each { |row| p row } +puts '== Follower tournaments ==' +Tournament.order(:id).pluck(:id, :name, :read_only_mode, :sync_target_url, :sync_last_pushed_at, :sync_last_push_error).each { |row| p row } +""" + + for service, db_host in (("source-app", "source-postgres"), ("follower-app", "follower-postgres")): + _print_header(f"Sync state from {service}") + db_name = BLACKBOX_SOURCE_DB_NAME if service == "source-app" else BLACKBOX_FOLLOWER_DB_NAME + service_env = _production_env_for(db_host, db_name) + runner = _compose_run( + ["run", "--rm", "-e", f"POSTGRES_URL={service_env['POSTGRES_URL']}", "-e", f"POSTGRES_USERNAME={service_env['POSTGRES_USERNAME']}", "-e", f"POSTGRES_PASSWORD={service_env['POSTGRES_PASSWORD']}", "-e", f"SECRET_KEY_BASE={service_env['SECRET_KEY_BASE']}", "-e", f"MAILGUN_API_KEY={service_env['MAILGUN_API_KEY']}", "-e", f"MAILGUN_DOMAIN={service_env['MAILGUN_DOMAIN']}", "-e", f"RAILS_LOG_TO_STDOUT={service_env['RAILS_LOG_TO_STDOUT']}", "-e", f"RAILS_SERVE_STATIC_FILES={service_env['RAILS_SERVE_STATIC_FILES']}", "-e", "RAILS_ENV=production", "e2e", "bundle", "exec", "rails", "runner", script], + env=env, + capture_output=True, + check=False, + project_name=BLACKBOX_FOLLOW_PROJECT, + compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE, + ) + if runner.stdout: + print(runner.stdout.rstrip()) + if runner.stderr: + print(runner.stderr.rstrip()) + if runner.returncode != 0: + raise subprocess.CalledProcessError( + runner.returncode, + runner.args, + output=runner.stdout, + stderr=runner.stderr, + ) + + _print_header(f"Recent logs from {service}") + logs = _compose_run( + ["logs", "--tail", str(log_tail), service], + env=env, + capture_output=True, + check=False, + project_name=BLACKBOX_FOLLOW_PROJECT, + compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE, + ) + output = logs.stdout or logs.stderr or "" + print(output.rstrip()) + + +@task(name="docker-blackbox-follow-debug-compare") +def docker_blackbox_follow_debug_compare( + c, + source_host_port=BLACKBOX_SOURCE_HOST_PORT, + follower_host_port=BLACKBOX_FOLLOWER_HOST_PORT, + app_image=PRODUCTION_TAG, + runner_image=TEST_TAG, + postgres_image=BLACKBOX_POSTGRES_IMAGE, +): + """Compare latest leader tournament and follower read-only tournament via HTTP API.""" + env = _follow_compose_env( + source_host_port=source_host_port, + follower_host_port=follower_host_port, + app_image=app_image, + runner_image=runner_image, + postgres_image=postgres_image, + ) + + script = """ +def signature(tournament) + { + id: tournament.id, + name: tournament.name, + public: tournament.public, + playoff_teams_amount: tournament.playoff_teams_amount, + instant_finalists_amount: tournament.instant_finalists_amount, + intermediate_round_participants_amount: tournament.intermediate_round_participants_amount, + sync_source_tournament_id: tournament.respond_to?(:sync_source_tournament_id) ? tournament.sync_source_tournament_id : nil, + team_names: tournament.teams.order(:id).pluck(:name), + stage_levels: tournament.stages.order(:level).map { |stage| [stage.level, stage.state, stage.groups.count, stage.matches.count] }, + total_matches: tournament.matches.count, + decider_matches: tournament.matches.count(&:decider?) + } +end + +tournament = if ENV['FOLLOW_COMPARE_MODE'] == 'leader' + Tournament.where.not(sync_target_url: nil).order(:id).last + else + Tournament.where(read_only_mode: true).order(:id).last + end + +puts signature(tournament).inspect +""" + + for mode, db_host, db_name in (("leader", "source-postgres", BLACKBOX_SOURCE_DB_NAME), ("follower", "follower-postgres", BLACKBOX_FOLLOWER_DB_NAME)): + _print_header(f"Compare {mode} tournament") + service_env = _production_env_for(db_host, db_name) + runner = _compose_run( + ["run", "--rm", "-e", f"POSTGRES_URL={service_env['POSTGRES_URL']}", "-e", f"POSTGRES_USERNAME={service_env['POSTGRES_USERNAME']}", "-e", f"POSTGRES_PASSWORD={service_env['POSTGRES_PASSWORD']}", "-e", f"SECRET_KEY_BASE={service_env['SECRET_KEY_BASE']}", "-e", f"MAILGUN_API_KEY={service_env['MAILGUN_API_KEY']}", "-e", f"MAILGUN_DOMAIN={service_env['MAILGUN_DOMAIN']}", "-e", f"RAILS_LOG_TO_STDOUT={service_env['RAILS_LOG_TO_STDOUT']}", "-e", f"RAILS_SERVE_STATIC_FILES={service_env['RAILS_SERVE_STATIC_FILES']}", "-e", "RAILS_ENV=production", "-e", f"FOLLOW_COMPARE_MODE={mode}", "e2e", "bundle", "exec", "rails", "runner", script], + env=env, + capture_output=True, + check=False, + project_name=BLACKBOX_FOLLOW_PROJECT, + compose_file=BLACKBOX_FOLLOW_COMPOSE_FILE, + ) + if runner.stdout: + print(runner.stdout.rstrip()) + if runner.stderr: + print(runner.stderr.rstrip()) + if runner.returncode != 0: + raise subprocess.CalledProcessError( + runner.returncode, + runner.args, + output=runner.stdout, + stderr=runner.stderr, + ) + + @task(name="docker-blackbox-follow-run") def docker_blackbox_follow_run( c,