Skip to content

Commit

Permalink
fix: shared ignore lobby bug (#519)
Browse files Browse the repository at this point in the history
  • Loading branch information
npaton authored Mar 17, 2024
1 parent 7ccf0a0 commit 9e24313
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 11 deletions.
6 changes: 6 additions & 0 deletions .changeset/lobby-shared-ignore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@empirica/core": patch
---

Fix an issue with the shared/ignore lobby configuration, and more generally with
a number of players in a game that is not equal to the `treatment.playerCount`.
11 changes: 10 additions & 1 deletion lib/@empirica/core/src/admin/classic/models.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AddScopeInput, State } from "@empirica/tajriba";
import { debug, trace } from "console";
import { z } from "zod";
import { Constructor } from "../../shared/helpers";
import { Attributable } from "../../shared/scopes";
Expand All @@ -8,7 +9,6 @@ import { AddScopePayload, StepPayload } from "../context";
import { EventContext } from "../events";
import { Scope } from "../scopes";
import { AttrInput, attrs, scopeConstructor } from "./helpers";
import { debug, trace } from "console";

const isString = z.string().parse;
const isOptionalNumber = z.number().optional().parse;
Expand Down Expand Up @@ -171,10 +171,15 @@ export class Game extends BatchOwned {
// Starts the game if it is not already started.
start() {
if (!this.get("start")) {
this.setActualPlayerCount();
this.set("start", true);
}
}

private setActualPlayerCount() {
this.set("actualPlayerCount", this.players.length);
}

async assignPlayer(player: Player) {
if (this.hasEnded) {
throw new Error("cannot assign player to ended Game");
Expand Down Expand Up @@ -302,6 +307,8 @@ export class Game extends BatchOwned {
nodeIDs: otherNodeIDs,
},
]);

this.setActualPlayerCount();
}

// Remove player from running game
Expand Down Expand Up @@ -366,6 +373,8 @@ export class Game extends BatchOwned {
nodeIDs: otherNodeIDs,
},
]);

this.setActualPlayerCount();
}

addRound(attributes: { [key: string]: JsonValue } | AttrInput[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,9 @@ function useAllReady() {
return false;
}

const treatment = game.get("treatment") as { playerCount: number };
const playerCount = game.get("actualPlayerCount") as number | undefined;

const playerCount = treatment!["playerCount"];

if (players.length < playerCount) {
if (playerCount !== undefined && players.length < playerCount) {
return false;
}

Expand Down
4 changes: 4 additions & 0 deletions lib/admin-ui/src/components/batches/NewBatch.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
];
if (assignmentMethod !== "custom" || window["rawCustomConfig"]) {
if (window["rawLobbyConfig"]) {
lobby = JSON.parse(window["rawLobbyConfig"]);
}
attributes.push({
key: "lobbyConfig",
val: JSON.stringify(lobby),
Expand Down
6 changes: 3 additions & 3 deletions modd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
# prep: ln -s ../../../lib/admin-ui/dist internal/templates/source/admin-ui
# }

# internal/templates/sources/**/* {
# prep: go generate ./internal/templates/...
# }
internal/templates/sources/**/* {
prep: go generate ./internal/templates/...
}

go.mod go.sum **/*.go !**/*_test.go ../tajriba/**/*.go !../tajriba/**/*_test.go !internal/graph/generated.go !internal/graph/models_gen.go internal/graph/*.resolvers.go {
prep: go install -race -ldflags "-X 'github.com/empiricaly/empirica/internal/build.DevBuild=true' -X 'github.com/empiricaly/empirica/internal/build.SHA=abcd123' -X 'github.com/empiricaly/empirica/internal/build.Tag=v1.2.3' -X 'github.com/empiricaly/empirica/internal/build.Branch=thisbranch' -X 'github.com/empiricaly/empirica/internal/build.BuildNum=42' -X 'github.com/empiricaly/empirica/internal/build.Time=$(date -u +'%Y-%m-%dT%H:%M:%SZ')'" ./cmds/empirica
Expand Down
25 changes: 22 additions & 3 deletions tests/stress/tests/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,18 @@ export function quickGame(playerCount, roundCount, stageCount, factors = {}) {
}

/**
* @param {Object} params Information about the user.
* @param {string} [params.treatmentName] The name of the user.
* @param {Object} [params.treatmentConfig] The email of the user.
* @param {Object} params The parameters for the new batch.
* @param {string} [params.treatmentName] The name of the treatment to select.
* @param {Object} [params.treatmentConfig] The raw treatment config to use.
* @param {string?} [params.lobbyName] The name of the lobby to select.
* @param {Object} [params.lobbyConfig] The raw lobby config to use.
* @param {number} [params.gameCount] The email of the user.
*/
export const adminNewBatch = ({
treatmentName = "10player",
treatmentConfig = null,
lobbyName = null,
lobbyConfig = null,
gameCount = 1,
}) =>
new Step("new batch", async (actor) => {
Expand Down Expand Up @@ -97,6 +101,21 @@ export const adminNewBatch = ({
}
}

if (lobbyName) {
await actor.page
.locator('[data-test="lobbySelect"]')
.selectOption({ label: lobbyName });

await actor.screenshot("lobby-selected");
}

if (lobbyConfig !== null) {
// Fill in a custom lobby
await actor.page.evaluate((lobbyConfig) => {
window["rawLobbyConfig"] = JSON.stringify(lobbyConfig);
}, lobbyConfig);
}

// Create the batch
await actor.page.getByTestId("createBatchButton").click();

Expand Down
69 changes: 69 additions & 0 deletions tests/stress/tests/lobby.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// @ts-check
/// <reference path="./index.d.ts" />

const { test } = require("@playwright/test");
import { Context } from "./context";
import { adminNewBatch, quickGame } from "./admin";
import {
playerStart,
submitStage,
waitGameFinished,
waitNextStage,
} from "./player";
import { sleep } from "./utils";

// At the moment, we use the same empirica server for all tests, so we need to
// run them serially. This will change when we have a dedicated server for each
// test.
test.describe.configure({ mode: "serial" });

// This test is a test for the lobby with configuration shared/ignore, which
// means that all players share a timer and we ignore the fact that there are
// not enough players to start the game, and start the game with the players
// that are available.
// To test this, we set a very short duration for the lobby, and we start the
// game with only one player, even with a player count of 2.
test("lobby shared ignore", async ({ browser }) => {
const ctx = new Context(browser);

const playerCount = 2;
const roundCount = 1;
const stageCount = 2;
const totalStages = roundCount * stageCount;

await ctx.start();
await ctx.addPlayers(playerCount);
ctx.players[0].logWS();
ctx.players[0].listenScope("game");

await ctx.applyAdmin(
adminNewBatch({
treatmentConfig: quickGame(playerCount, roundCount, stageCount),
lobbyConfig: {
name: "Fast shared ignore",
kind: "shared",
duration: 5_000_000_000,
strategy: "ignore",
},
})
);

for (let i = 0; i < totalStages; i++) {
if (i === 0) {
// ONLY Player 0 starts the game
// Player 1 is ignored
// Lobby-ignore should start the game with only one player
await ctx.players[0].apply(playerStart);
} else {
await ctx.players[0].apply(waitNextStage);
}

await ctx.players[0].screenshot(`stage-${i}`);

await ctx.players[0].apply(submitStage);
}

await ctx.players[0].apply(waitGameFinished);

await ctx.close();
});

0 comments on commit 9e24313

Please sign in to comment.