Mock Service

Testing Service for player sided integration and system tests

Mock Service

What is the mock service?

The mock service is a test microservice created for the purpose of allowing player services to mock the events and certain event sequences of the many core services that are part of the microservice dungeon ecosystem, for integration and system testing purposes.

It mocks all 25 types of events that currently exist within the core services and sends them to the player service on demand in simple form and in form of more complex test scenarios.

To do so, the mock service replaces the core services, including the game service, creating a test environment, in which the mock service handles all communication with the player service.

To visualize:

Mock service simplified

Prerequisites

  • Docker

Installation

The image of the mock service is available in the container registry of the MSD Repository at:

registry.gitlab.com/the-microservice-dungeon/devops-team/msd-image-registry/mock-service:latest

You can pull the mock service image from there and run it locally, on your machine, via docker. If you want to know how you can do that, you can check out the [event handling testing guide](content/en/docs/Getting Started/event_handling_tests_using_the_mock_service.md) in the player guide section, under the aspect of Running the mock service locally.

Environment

Must be running:

  • Kafka/Redpanda
  • RabbitMQ
  • kafka-rabbitmq-connector

How does it work?

The mock service offers a set of rest controllers called event generators, that generate the different events published by the core services and publishes them to the kafka/redpanda broker.

Events can either be fully customized via json as part of the rest request or randomized by providing no request payload at all. Generated events are forwarded to the kafka/redpanda broker.

In order for these events to be forwarded to the respective queue of the player, the player must register himself, with the mock service, first. Afterwards, by passing their own player id as header value to their requests, the generated events will be forwarded to the respective rabbitmq queue by the kafka-rabbitmq-connector.

It is alternatively also possible to play through entire test scenarios. A test scenario represents a certain sub-part of the entire game context and can be configured by the player service. A game-like test scenario can be created, joined, and started the same way a normal game can via the game service. The only difference is the addition of a configuration step, that is performed after the joining and before the start of the test scenario.

Both functionalities are explained, in more detail, below.

Simple event generation

If you followed the [event handling testing guide](content/en/docs/Getting Started/event_handling_tests_using_the_mock_service.md) mentioned in the previous section, on running the mock service on your local machine, the running mock service should be available under the following url:

http://localhost:8098

You can now start by registering yourself with the mock service.

POST

http://localhost:8098/players

Header values

"Content-Type":"application/json"

request format

{
    "name":"...",
    "email":"..."
}

response format

{
    "playerId":"...",
    "name":"...",
    "email":"...",
    "playerExchange":"...",
    "playerQueue":"..."
}

After your player has been registered with the mock service, you can start generating events. A fully qualified event generation request looks like this:

POST

http://localhost:8098/{coreService}/events/{eventType}

Header values

"Content-Type":"application/json",
"playerId":"..."

request format

Can be either empty for a randomly configured event, or the event values must be specified. Example for a robot attacked event:

{
    "attacker":{
        "robotId":"...",
        "health":"...",
        ...
    },
    "target":{
        "robotId":"...",
        "robotId":"...",
        ...
    }
}

response format

Returns the generated event as json payload.

{
    "attacker":{
        "robotId":"...",
        "health":"...",
        ...
    },
    "target":{
        "robotId":"...",
        "robotId":"...",
        ...
    }
}

Placeholders

{coreService}

- game
- map
- trading
- robot

{eventType}

The respective event type in UpperCamelCase, as in:

- PlanetDiscovered
- RobotAttacked
...

For more detail and information regarding the rest-api, take a look at the open api specification [here](content/en/docs/Reference/Test/Mock Service/openapi.md)

Test scenarios

Test scenarios can be used for system tests in the player service. These test scenarios are, in essence, a game, that is created and started with a certain pre-existing state and configurations of the players choosing and certain conditions that apply to it.

There are currently 3 test scenarios: (work in progress…)

  • Default
  • Map Exploration
  • Fight

In general, the way to start the test scenario is similar to starting a game in the core services. This is to not change or complicate the rest interaction between the player service and the “player-interface-service”. That, in this case, being the mock service instead of the game service. The only additional rest interaction necessary, is the test scenario configuration rest call, that is performed after the game creation and player registration rest calls and before the game start rest call.

If you need an introduction to the basic rest calls of creating, joining and starting of a game, you can refer to the api specification of the game service.

Below, there is a general introduction to the various test scenarios. An example configuration rest call will be displayed as well. These are just examples. You can configure your test scenarios as you please. For more information regarding the rest-api, please refer to the concrete api specification [here](content/en/docs/Reference/Test/Mock Service/openapi.md)

Please also be aware, that configuring certain more freely configurable test scenarios, such as the fight scenario, will require a certain understanding of the microservice dungeon domain and the inner workings of the core services. An example:

Understanding that the planet map is implemented as a grid, with each planet being assigned a certain x and y coordinate, is necessary. The map can be visualized as such, with an x marking a planet and an empty space marking an inaccessible hole in the planet grid:

     |  0  1  2  3  4           Legend:
  ---|---------------
  0  |  x  x  x  _  x           x : Planet
  1  |  _  x  x  x  x           _ : Inaccessible
  2  |  x  x  x  _  x               empty Space
  3  |  x  x  x  x  x
  4  |  _  x  x  x  x

It must be understood, that the value map size, which can often be configured in a test scenario, describes the length of the axis of the grid, not the planet amount. The map grid displayed above would have a map size of 5, leaving space for a potential maximum of 25 planets. It is also important to understand, that the map grids origin is located in the upper left corner, and not the lower left one. This means that moving a robot, for example, north, from the planet at location (1, 2), would land the robot at the planet at location (1, 1) instead of location (1, 3).

Being aware of these certain inner workings of the core services, is a necessity to properly configure your test scenarios. You can learn more about the core services in their respective docs section here:

Now onto the introduction of the respective test scenarios.

Default test scenario

The default test scenario is basically the same as a normal game, played in the core services. It can therefore be used for very comprehensive system tests for the player service, but generally functions like a normal game would in the core services and has no specific conditions attached to it.

The player can receive all 25 types of events in this test scenario.

There are two types of configurations that can be set before the test scenario starts:

  • map size
  • plentiful resources flag

These two configuration values allow the player service to set the map size of the test scenario and whether all planets should contain resources. The specific configuration settings rest call would look like this:

POST

http://localhost:8098//games/{gameId}/configureTestScenario

Header values

"Content-Type":"application/json",

request format

{
    "testScenario":"default",
    "testScenarioSettings":{
        "mapSize":5,
        "plentiful":true
    }
}

response format

{
    "gameId":"...",
    "testScenario":"default"
}

No local state has to be set in the player service, before the test scenario starts.

Map-Exploration test scenario

The map exploration test scenario is about testing the map related functionalities of the player service. It generates a map of configurable size and also a configurable amount of explorer robots. The explorer robots can be used to explore the map to obtain the relevant events. In this test scenario, the player service can test, whether the dynamic map building and resource setting, as well as, the robot movement and mining functions are working correctly. For isolation purposes, unrelated events are being suppressed.

The player can receive the following 9 types of events in this test scenario:

  • RobotSpawnedEvent
  • ResourceMinedEvent
  • RobotRegeneratedEvent
  • RobotMovedEvent
  • ResourceMinedEvent
  • PlanetDiscoveredEvent
  • RoundStatusEvent
  • GameStatusEvent
  • ErrorEvent

There are three types of configurations that can be set before the test scenario starts:

  • map size
  • plentiful resources flag
  • explorer robot amount

These three configuration values allow the player service to set the map size of the test scenario, whether all planets should contain resources and the amount of explorer robots, as desired. The specific configuration settings rest call would look like this:

POST

http://localhost:8098//games/{gameId}/configureTestScenario

Header values

"Content-Type":"application/json",

request format

{
    "testScenario":"map_exploration",
    "testScenarioSettings":{
        "mapSize":5,
        "plentiful":true,
        "explorerAmount":5
    }
}

response format

{
    "gameId":"...",
    "testScenario":"map_exploration"
}

No local state has to be set in the player service, before the test scenario starts.

Fight test scenario

The fight test scenario is about testing the fight related functionalities of the player service. It generates a map of configurable size and also a configurable planets themselves, configuring id, position and movement difficulty. The player service can also configure himself and his enemy, including their respective bank account balance and lastly, the player can fully determine the amount and quality of both the friendly and the hostile robots involved in the fight. For the hostile robots, actions can be pre-determined by the player, or not and left to be randomized during the test scenario execution by the mock service. In this test scenario, the player service can test his strategy, can play around and explore the effects the different robot levels and whether fight related functions of the player are working correctly. For isolation purposes, unrelated events are being suppressed.

The player can receive the following 11 types of events in this test scenario:

  • RobotsRevealedEvent
  • RobotRestoredAttributesEvent
  • RobotRegeneratedEvent
  • RobotMovedEvent
  • RobotAttackedEvent
  • RoundStatusEvent
  • GameStatusEvent
  • BankAccountClearedEvent
  • BankAccountTransactionBookedEvent
  • BankAccountInitializedEvent
  • ErrorEvent

The configurations that can be set before the test scenario starts are:

  • map size

  • planets

  • player

  • enemy

  • friendly robots

  • hostile robots

These configuration values allow the player service to set the map size of the test scenario, the planets themselves and the enemy, as well as all the robots involved in the fight, as desired. The specific configuration settings rest call would look like this:

POST

http://localhost:8098//games/{gameId}/configureTestScenario

Header values

"Content-Type":"application/json",

request format

{
    "testScenario":"fight",
    "testScenarioSettings":{
        "mapSize":2,
        "planets":[{
            "id":"1fab2af5-852b-45f4-a9c3-a5432609a87b",
            "x":0,
            "y":0,
            "movementDifficulty":3
        },
        {
            "id":"e52820a3-90a8-4e1c-a015-65ece79a4d0c",
            "x":0,
            "y":1,
            "movementDifficulty":2
        },
        {
            "id":"b42820a3-30a8-4e1c-c015-65dce79a4d0c",
            "x":1,
            "y":1,
            "movementDifficulty":3
        }],
        "player":{
            "id":"a5c3b8d9-f5c1-4e48-ad83-4e2b95502cc1",
            "balance":500.0,
            "name":"test-player",
            "email":"player@mail.com"
        },
        "enemy":{
            "id":"8a52271e-adac-4bb4-8fcc-a569b930a6a7",
            "balance":500.0,
            "name":"test-enemy",
            "email":"enemy@mail.com"
        },
        "friendlyRobots":[{
            "id":"cb1484bb-5821-44d5-ba64-ac2e835ab140",
            "planet":{
                "id":"95603c3e-8f64-4b36-a793-b31f5e042780",
                "x":0,
                "y":0,
                "movementDifficulty":3
            },
            "healthLevel":1,
            "energyLevel":1,
            "energyRegenLevel":1,
            "damageLevel":1,
            "miningLevel":1,
            "miningSpeedLevel":2,
            "health":50,
            "energy":50
        }],
        "enemyRobots":[{
            "id":"c1218c21-53bc-4110-b4b2-151fcc61f6fe",
            "planet":{
                "id":"38e094b4-9e45-4d56-9d1f-3b6130b0803d",
                "x":0,
                "y":1,
                "movementDifficulty":2
            },
            "healthLevel":1,
            "energyLevel":1,
            "energyRegenLevel":1,
            "damageLevel":2,
            "miningLevel":1,
            "miningSpeedLevel":2,
            "health":50,
            "energy":50,
            "nextOrders":[
                "move_north",
                "move_east",
                "move_south",
                "move_west",
                "attack",
                "regenerate",
                "buy_health",
                "buy_energy"
            ]
        }]
    }
}

response format

{
    "gameId":"...",
    "testScenario":"fight"
}

The local state has to be set as follows, in the player service, before the test scenario starts:

  • the map with the defined planets must be created (using the given uuids as ids)
  • the player entity with the given name, mail and bank balance must be created (using the given uuid as id)
  • the friendly robots with their levels and health/energy values must be created and placed on the specified planet (using the given uuids as ids)

Performing a test scenario

Now that the various test scenarios have been introduced, the utilization will be explained below.

  1. In order to perform a test scenario, the player has to first register themselves as a player with the mock service. At this point, the player receives his rabbitmq exchange and queue. This interaction should be familiar to the player from the game service api.
  2. The player should create the game/test scenario. This interaction should be familiar to the player from the game service api.
  3. The player joins the newly created game/test scenario. This interaction should be familiar to the player from the game service api.
  4. This is the point at which the player configures the test scenario depending on his choice of test scenario and his preferred configurations. This step differs from the familiar game service api and is explained above during the introduction of the different test scenarios.
  5. Lastly, the player starts the game/test scenario as he would with the game service. The test scenario should now start and the player can commence his event handling tests.

Source code

The mock service source code is located in the MSD gitlab group in the test services section.


OpenAPI

OpenAPI

AsyncAPI

AsyncAPI

Last modified February 4, 2025: fix go & npm dependencies (8ff1fa0)