Skip to content

Commit 951178a

Browse files
committed
Merge upstream/master: resolve conflicts in game_live/index.ex and tests
2 parents 6735fe8 + c14f115 commit 951178a

File tree

9 files changed

+1558
-49
lines changed

9 files changed

+1558
-49
lines changed

.github/workflows/copi-deploy-staging.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,16 @@
6262
- name: Run tests
6363
working-directory: copi.owasp.org
6464
run: |
65-
mix test --cover --export-coverage default --test-coverage "threshold: 0"
65+
mix test --cover --export-coverage default || true
6666
- name: Generate coverage report
6767
working-directory: copi.owasp.org
68-
run: mix coveralls.cobertura --exclude test --import-cover cover
68+
run: mix coveralls.cobertura --exclude test --import-cover cover || true
6969
# Upload Code Coverage for Codeclimate
7070
- uses: qltysh/qlty-action/coverage@a19242102d17e497f437d7466aa01b528537e899 # v2.2.0
7171
with:
7272
token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
7373
total-parts-count: 3
74-
add-prefix: copi.owasp.org
74+
add-prefix: copi.owasp.org/lib
7575
files: copi.owasp.org/cover/cobertura.xml
7676
- name: Setup Flyctl
7777
uses: superfly/flyctl-actions/setup-flyctl@63da3ecc5e2793b98a3f2519b3d75d4f4c11cec2

copi.owasp.org/coveralls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"coverage_options": {
1515
"treat_no_relevant_lines_as_covered": true,
1616
"output_dir": "cover/",
17-
"minimum_coverage": 85
17+
"minimum_coverage": 90
1818
}
1919
}

copi.owasp.org/lib/copi_web/live/game_live/index.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ defmodule CopiWeb.GameLive.Index do
22
use CopiWeb, :live_view
33
use Phoenix.Component
44

5-
alias Copi.Cornucopia
65
alias Copi.Cornucopia.Game
76

87
@impl true
98
def mount(_params, session, socket) do
10-
ip = socket.assigns[:client_ip] || Map.get(session, "client_ip") || Copi.IPHelper.get_ip_from_socket(socket)
9+
# V15.3.5: Use only existing, trusted IP values from assigns or session
10+
ip = socket.assigns[:client_ip] || Map.get(session, "client_ip")
1111
{:ok, assign(assign(socket, :client_ip, ip), :games, nil)}
1212
end
1313

copi.owasp.org/test/copi_web/live/game_live/show_test.exs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,21 @@ defmodule CopiWeb.GameLive.ShowTest do
104104
:timer.sleep(50)
105105
assert render(show_live) =~ game.name
106106
end
107+
108+
test "handle_info updates game when matching topic received", %{conn: conn, game: game} do
109+
{:ok, show_live, _html} = live(conn, "/games/#{game.id}")
110+
111+
{:ok, updated_game} = Cornucopia.Game.find(game.id)
112+
113+
send(show_live.pid, %{
114+
topic: "game:#{game.id}",
115+
event: "game:updated",
116+
payload: updated_game
117+
})
118+
119+
:timer.sleep(50)
120+
assert render(show_live) =~ game.name
121+
end
107122
end
108123

109124
describe "Show helper functions" do
@@ -149,6 +164,5 @@ defmodule CopiWeb.GameLive.ShowTest do
149164
assert {:cont, updated_socket} = Show.put_uri_hook(%{}, "/games/round/1", socket)
150165
assert updated_socket.assigns.uri == "/games/round/1"
151166
end
152-
153167
end
154168
end
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
defmodule CopiWeb.PlayerLive.ShowTest do
2+
use CopiWeb.ConnCase, async: false
3+
4+
import Phoenix.LiveViewTest
5+
6+
alias Copi.Cornucopia
7+
8+
@game_attrs %{name: "show test game"}
9+
10+
defp create_player(_) do
11+
{:ok, game} = Cornucopia.create_game(@game_attrs)
12+
{:ok, player} = Cornucopia.create_player(%{name: "Player 1", game_id: game.id})
13+
%{player: player}
14+
end
15+
16+
describe "Show - additional coverage" do
17+
setup [:create_player]
18+
19+
test "handle_info :proceed_to_next_round advances rounds_played", %{conn: conn, player: player} do
20+
game_id = player.game_id
21+
{:ok, game} = Cornucopia.Game.find(game_id)
22+
23+
Copi.Repo.update!(
24+
Ecto.Changeset.change(game, started_at: DateTime.truncate(DateTime.utc_now(), :second))
25+
)
26+
27+
{:ok, show_live, _html} = live(conn, "/games/#{game_id}/players/#{player.id}")
28+
29+
send(show_live.pid, :proceed_to_next_round)
30+
:timer.sleep(100)
31+
32+
{:ok, updated_game} = Cornucopia.Game.find(game_id)
33+
assert updated_game.rounds_played == 1
34+
end
35+
36+
test "handle_info :proceed_to_next_round sets finished_at on last round", %{conn: conn, player: player} do
37+
game_id = player.game_id
38+
{:ok, game} = Cornucopia.Game.find(game_id)
39+
40+
Copi.Repo.update!(
41+
Ecto.Changeset.change(game, started_at: DateTime.truncate(DateTime.utc_now(), :second))
42+
)
43+
44+
# A played card with no nil-round cards remaining → last_round? returns true
45+
{:ok, card} =
46+
Cornucopia.create_card(%{
47+
category: "C", value: "V", description: "D", edition: "webapp",
48+
version: "2.2", external_id: "ST1", language: "en", misc: "misc",
49+
owasp_scp: [], owasp_devguide: [], owasp_asvs: [], owasp_appsensor: [],
50+
capec: [], safecode: [], owasp_mastg: [], owasp_masvs: []
51+
})
52+
53+
Copi.Repo.insert!(%Copi.Cornucopia.DealtCard{
54+
player_id: player.id, card_id: card.id, played_in_round: 1
55+
})
56+
57+
{:ok, show_live, _html} = live(conn, "/games/#{game_id}/players/#{player.id}")
58+
59+
send(show_live.pid, :proceed_to_next_round)
60+
:timer.sleep(100)
61+
62+
{:ok, updated_game} = Cornucopia.Game.find(game_id)
63+
assert updated_game.finished_at != nil
64+
end
65+
66+
test "next_round is no-op when round is open and cannot continue", %{conn: conn, player: player} do
67+
game_id = player.game_id
68+
{:ok, game} = Cornucopia.Game.find(game_id)
69+
70+
# Start game but add no dealt cards and no continue votes → round_open? true, can_continue? false
71+
Copi.Repo.update!(
72+
Ecto.Changeset.change(game, started_at: DateTime.truncate(DateTime.utc_now(), :second))
73+
)
74+
75+
{:ok, show_live, _html} = live(conn, "/games/#{game_id}/players/#{player.id}")
76+
html = render_click(show_live, "next_round", %{})
77+
assert is_binary(html)
78+
79+
{:ok, unchanged_game} = Cornucopia.Game.find(game_id)
80+
assert unchanged_game.rounds_played == 0
81+
end
82+
83+
test "next_round proceeds when majority continue votes reached", %{conn: conn, player: player} do
84+
game_id = player.game_id
85+
{:ok, game} = Cornucopia.Game.find(game_id)
86+
87+
Copi.Repo.update!(
88+
Ecto.Changeset.change(game, started_at: DateTime.truncate(DateTime.utc_now(), :second))
89+
)
90+
91+
# 1 player + 1 continue vote → majority reached (1 > div(1,2) = 0), round_open? true
92+
Copi.Repo.insert!(%Copi.Cornucopia.ContinueVote{player_id: player.id, game_id: game_id})
93+
94+
{:ok, show_live, _html} = live(conn, "/games/#{game_id}/players/#{player.id}")
95+
render_click(show_live, "next_round", %{})
96+
97+
# Wait for the async :proceed_to_next_round message (100ms delay + buffer)
98+
:timer.sleep(300)
99+
100+
{:ok, updated_game} = Cornucopia.Game.find(game_id)
101+
assert updated_game.rounds_played == 1
102+
end
103+
104+
test "helper functions return expected values", %{conn: _conn, player: _player} do
105+
alias CopiWeb.PlayerLive.Show
106+
107+
assert Show.ordered_cards([]) == []
108+
assert Show.unplayed_cards([]) == []
109+
assert Show.played_cards([], 1) == []
110+
assert Show.card_played_in_round([], 1) == nil
111+
# With no players, no one is still to play → round_open? is false → round_closed? is true
112+
assert Show.round_closed?(%{players: [], rounds_played: 0}) == true
113+
114+
assert Show.display_game_session("webapp") == "Cornucopia Web Session:"
115+
assert Show.display_game_session("ecommerce") == "Cornucopia Web Session:"
116+
assert Show.display_game_session("mobileapp") == "Cornucopia Mobile Session:"
117+
assert Show.display_game_session("masvs") == "Cornucopia Mobile Session:"
118+
assert Show.display_game_session("cumulus") == "OWASP Cumulus Session:"
119+
assert Show.display_game_session("mlsec") == "Elevation of MLSec Session:"
120+
assert Show.display_game_session("eop") == "EoP Session:"
121+
end
122+
end
123+
end

cornucopia.owasp.org/data/website/pages/about/en/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ Cornucopia is developed, maintained, updated and promoted by a worldwide team of
108108
- Abhijit Sahoo
109109
- Max Alejandro Gómez Sánchez Vergaray
110110
- Tao Sauvage
111+
- Riccardo Sirigu
111112
- Prasun Srivastav
112113
- Aditya Srivastava
113114
- Johan Sydseter

cornucopia.owasp.org/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"vite": "^7.3.1",
3434
"vitest": "^4.0.17",
3535
"wait-on": "^9.0.4",
36-
"wrangler": "4.68.1"
36+
"wrangler": "4.69.0"
3737
},
3838
"type": "module",
3939
"dependencies": {

0 commit comments

Comments
 (0)