/* * Computoser is a music-composition algorithm and a website to present the results * Copyright (C) 2012-2014 Bozhidar Bozhanov * * Computoser is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Computoser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Computoser. If not, see <http://www.gnu.org/licenses/>. */ package com.music.websocket; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.IOException; import java.util.Deque; import java.util.LinkedList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketMessage; import org.springframework.web.socket.WebSocketSession; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.music.model.persistent.Piece; import com.music.model.prefs.UserPreferences; import com.music.service.PieceService; import com.music.web.websocket.Game; import com.music.web.websocket.GameHandler; import com.music.web.websocket.dto.GameAction; import com.music.web.websocket.dto.GameEvent; import com.music.web.websocket.dto.GameEventType; import com.music.web.websocket.dto.GameMessage; public class GameTest { private ObjectMapper mapper = new ObjectMapper(); @Mock private PieceService pieceServiceMock; private Piece piece; private Map<String, Deque<WebSocketMessage<?>>> messages = new ConcurrentHashMap<>(); @Before public void init() { MockitoAnnotations.initMocks(this); piece = new Piece(); piece.setId(1L); piece.setTempo(60); piece.setMetreNumerator(4); piece.setMetreDenominator(8); piece.setMainInstrument(1); when(pieceServiceMock.getPiece(anyLong())).thenReturn(piece); when(pieceServiceMock.getNextPieceId(Mockito.<UserPreferences>any())).thenReturn(piece.getId()); } private WebSocketSession getSession(final String id) { messages.put(id, new LinkedList<WebSocketMessage<?>>()); WebSocketSession session = mock(WebSocketSession.class); try { doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { messages.get(id).offer((WebSocketMessage<?>) invocation.getArguments()[0]); return null; } }).when(session).sendMessage(Mockito.<WebSocketMessage<?>>any()); } catch (IOException e) { throw new IllegalStateException(e); } when(session.getId()).thenReturn(id); return session; } @Test public void gameInitializedTest() throws Exception { GameHandler handler = new GameHandler(); initializeGame(handler); GameEvent response = mapper.readValue(messages.get("1").removeLast().getPayload().toString(), GameEvent.class); Assert.assertEquals(GameEventType.GAME_INITIALIZED, response.getType()); Assert.assertEquals(1, handler.getGames().size()); Game game = handler.getGames().values().iterator().next(); Assert.assertEquals(game.getId(), response.getGameId()); } private void initializeGame(GameHandler handler) { try { GameMessage msg = new GameMessage(); msg.setAction(GameAction.INITIALIZE); msg.setPlayerName("Game starter"); TextMessage message = getTextMessage(msg); WebSocketSession session = getSession("1"); handler.afterConnectionEstablished(session); handler.handleMessage(session, message); } catch (Exception ex) { throw new IllegalStateException(ex); } } private TextMessage getTextMessage(GameMessage msg) { String payload; try { payload = mapper.writeValueAsString(msg); } catch (JsonProcessingException e) { throw new IllegalStateException(e); } TextMessage message = new TextMessage(payload); return message; } @Test public void gameStartedTest() throws Exception { GameHandler handler = new GameHandler(); handler.setPieceService(pieceServiceMock); initializeGame(handler); Game game = handler.getGames().values().iterator().next(); GameMessage startMsg = new GameMessage(); startMsg.setAction(GameAction.START); startMsg.setGameId(game.getId()); WebSocketSession session = getSession("1"); handler.handleMessage(session, getTextMessage(startMsg)); GameEvent responseNewPiece = mapper.readValue(messages.get("1").removeLast().getPayload().toString(), GameEvent.class); GameEvent responseGameStarted = mapper.readValue(messages.get("1").removeLast().getPayload().toString(), GameEvent.class); Assert.assertEquals(GameEventType.GAME_STARTED, responseGameStarted.getType()); Assert.assertEquals(GameEventType.NEW_PIECE, responseNewPiece.getType()); Assert.assertEquals(piece.getId(), responseNewPiece.getPieceId()); } @Test public void playerJoinedTest() throws Exception { GameHandler handler = new GameHandler(); handler.setPieceService(pieceServiceMock); initializeGame(handler); Game game = handler.getGames().values().iterator().next(); GameMessage playerJoinMsg = new GameMessage(); playerJoinMsg.setAction(GameAction.JOIN); playerJoinMsg.setPlayerName("AAA"); playerJoinMsg.setGameId(game.getId()); getSession("1"); WebSocketSession player2Session = getSession("2"); handler.afterConnectionEstablished(player2Session); handler.handleMessage(player2Session, getTextMessage(playerJoinMsg)); GameEvent playerJoinedEvent = mapper.readValue(messages.get("1").removeLast().getPayload().toString(), GameEvent.class); Assert.assertEquals(GameEventType.PLAYER_JOINED, playerJoinedEvent.getType()); Assert.assertEquals(playerJoinedEvent.getPlayerId(), "2"); Assert.assertTrue(messages.get("2").size() == 1); // player received a 'player_joined' event for each other player in the game } @Test public void derivedMetreTest() { Game game = new Game("1", null); Piece piece = new Piece(); piece.setMetreNumerator(4); piece.setMetreDenominator(4); Assert.assertFalse(game.isNotDerivedMetre(piece, new int[] {8, 8})); Assert.assertTrue(game.isNotDerivedMetre(piece, new int[] {4, 8})); piece.setMetreNumerator(8); piece.setMetreDenominator(8); Assert.assertFalse(game.isNotDerivedMetre(piece, new int[] {4, 4})); Assert.assertTrue(game.isNotDerivedMetre(piece, new int[] {2, 4})); piece.setMetreNumerator(2); piece.setMetreDenominator(4); Assert.assertFalse(game.isNotDerivedMetre(piece, new int[] {4, 8})); Assert.assertFalse(game.isNotDerivedMetre(piece, new int[] {2, 4})); Assert.assertTrue(game.isNotDerivedMetre(piece, new int[] {4, 4})); } @Test public void gameFinishedTest() throws Exception { GameHandler handler = new GameHandler(); handler.setPieceService(pieceServiceMock); initializeGame(handler); Game game = handler.getGames().values().iterator().next(); GameMessage playerJoinMsg = new GameMessage(); playerJoinMsg.setAction(GameAction.JOIN); playerJoinMsg.setPlayerName("AAA"); playerJoinMsg.setGameId(game.getId()); WebSocketSession session = getSession("1"); handler.handleMessage(session, getTextMessage(playerJoinMsg)); game.setSecondsBeforeNextPiece(0); // Answer all three questions for (int i = 0; i < 3; i ++) { game.sendNextPiece(); GameMessage answerMsg = new GameMessage(); answerMsg.setAction(GameAction.ANSWER); com.music.web.websocket.dto.Answer answer = new com.music.web.websocket.dto.Answer(); answer.setMainInstrument(0); answer.setMetreNumerator(2); answer.setMetreDenominator(4); answer.setTempo(80); answerMsg.setAnswer(answer); answerMsg.setGameId(game.getId()); handler.handleMessage(session, getTextMessage(answerMsg)); } Assert.assertFalse(game.isStarted()); Assert.assertTrue(game.getResults().getRanking().contains("1")); Assert.assertTrue(game.getResults().getScores().containsKey(playerJoinMsg.getPlayerName())); } //TODO two async players test, automatic new piece test, timeout new piece test }