├── .gitignore ├── .gitattributes ├── tests ├── fixtures │ ├── boot-world │ │ ├── foo │ │ └── foo2 │ ├── dsta-log │ │ ├── empty-file │ │ ├── server_log.txt │ │ └── server_log_chat.txt │ ├── boot-lists │ │ ├── bar.txt │ │ ├── foo.txt │ │ └── list.txt │ ├── boot-token │ │ ├── token1 │ │ └── token2 │ ├── dsta-console │ │ └── commands.txt │ ├── boot-mods │ │ ├── foo-bar-with-overrides │ │ │ ├── modoverrides.lua │ │ │ └── dedicated_server_mods_setup.lua-tail │ │ ├── foo │ │ │ ├── dedicated_server_mods_setup.lua-tail │ │ │ └── modoverrides.lua │ │ └── foo-bar │ │ │ ├── dedicated_server_mods_setup.lua-tail │ │ │ └── modoverrides.lua │ ├── dsta-help │ │ ├── log │ │ ├── update │ │ ├── console │ │ ├── version │ │ ├── dst-server │ │ └── start │ ├── close-cleanly │ │ └── commands.sh │ ├── console │ │ └── commands.sh │ └── build-mods │ │ ├── one-mod │ │ └── dedicated_server_mods_setup.lua │ │ └── two-mods │ │ └── dedicated_server_mods_setup.lua ├── README.md ├── dependencies │ ├── load.bash │ ├── bats-support │ │ ├── error.bash │ │ ├── lang.bash │ │ └── output.bash │ └── bats-assert │ │ └── assert.bash ├── entrypoint.bats ├── console.bats ├── attach-console.bats ├── test_helper.bash ├── build-mods.bats ├── dsta-version.bats ├── close-cleanly.bats ├── dsta-update.bats ├── dsta-log.bats ├── boot-mods.bats ├── dsta-start.bats ├── dsta-console.bats ├── boot-world.bats ├── boot-aux.bats ├── boot-token.bats ├── boot-lists.bats └── dsta-help.bats ├── docs ├── recipes │ ├── basic │ │ ├── world.env │ │ ├── readme.md │ │ └── docker-compose.yml │ ├── session │ │ ├── world.env │ │ ├── readme.md │ │ └── docker-compose.yml │ ├── update │ │ ├── world.env │ │ ├── health.env │ │ ├── readme.md │ │ └── docker-compose.yml │ ├── world │ │ ├── world.env │ │ ├── readme.md │ │ └── docker-compose.yml │ ├── mods │ │ ├── world.env │ │ ├── readme.md │ │ └── docker-compose.yml │ ├── cluster │ │ ├── overworld.env │ │ ├── underworld.env │ │ ├── readme.md │ │ └── docker-compose.yml │ └── readme.md ├── setup.md ├── commands.md ├── usage.md └── configuration.md ├── MAINTAINERS.md ├── .editorconfig ├── LICENSE.md ├── CONTRIBUTING.md ├── README.md └── CHANGELOG.md /.gitignore: -------------------------------------------------------------------------------- 1 | local.env 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /tests/fixtures/boot-world/foo: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-log/empty-file: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/boot-lists/bar.txt: -------------------------------------------------------------------------------- 1 | bar 2 | -------------------------------------------------------------------------------- /tests/fixtures/boot-lists/foo.txt: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/fixtures/boot-token/token1: -------------------------------------------------------------------------------- 1 | token-1 -------------------------------------------------------------------------------- /tests/fixtures/boot-token/token2: -------------------------------------------------------------------------------- 1 | token-2 -------------------------------------------------------------------------------- /tests/fixtures/boot-world/foo2: -------------------------------------------------------------------------------- 1 | foo2 2 | -------------------------------------------------------------------------------- /docs/recipes/basic/world.env: -------------------------------------------------------------------------------- 1 | NAME="Basic Server Recipe" 2 | -------------------------------------------------------------------------------- /docs/recipes/session/world.env: -------------------------------------------------------------------------------- 1 | NAME="Session Server Recipe" 2 | -------------------------------------------------------------------------------- /docs/recipes/update/world.env: -------------------------------------------------------------------------------- 1 | NAME="Update Server Recipe" 2 | -------------------------------------------------------------------------------- /tests/fixtures/boot-lists/list.txt: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | xy_:z 4 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-console/commands.txt: -------------------------------------------------------------------------------- 1 | foo bar 2 | bar 3 | -------------------------------------------------------------------------------- /docs/recipes/world/world.env: -------------------------------------------------------------------------------- 1 | NAME="Custom World Generation Recipe" 2 | -------------------------------------------------------------------------------- /tests/fixtures/boot-mods/foo-bar-with-overrides/modoverrides.lua: -------------------------------------------------------------------------------- 1 | xyz 2 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-help/log: -------------------------------------------------------------------------------- 1 | usage: dontstarvetogether log [--server|--chat] 2 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-log/server_log.txt: -------------------------------------------------------------------------------- 1 | C3857C96-3757-4A96-8857-75E02CBCE829 2 | -------------------------------------------------------------------------------- /docs/recipes/mods/world.env: -------------------------------------------------------------------------------- 1 | NAME="Server Mods Recipe" 2 | MODS=2328495821,501385076 3 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-log/server_log_chat.txt: -------------------------------------------------------------------------------- 1 | 0E2A1A92-D047-4CAD-AC53-0F42FADAD9F3 2 | -------------------------------------------------------------------------------- /docs/recipes/update/health.env: -------------------------------------------------------------------------------- 1 | AUTOHEAL_CONTAINER_LABEL=autoheal 2 | AUTOHEAL_INTERVAL=60 3 | -------------------------------------------------------------------------------- /tests/fixtures/boot-mods/foo/dedicated_server_mods_setup.lua-tail: -------------------------------------------------------------------------------- 1 | ServerModSetup("foo") 2 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-help/update: -------------------------------------------------------------------------------- 1 | usage: dontstarvetogether update [--all|--game|--mods] 2 | -------------------------------------------------------------------------------- /tests/fixtures/boot-mods/foo/modoverrides.lua: -------------------------------------------------------------------------------- 1 | return { 2 | ["workshop-foo"] = { enabled = true }, 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/boot-mods/foo-bar/dedicated_server_mods_setup.lua-tail: -------------------------------------------------------------------------------- 1 | ServerModSetup("foo") 2 | ServerModSetup("bar") 3 | -------------------------------------------------------------------------------- /tests/fixtures/close-cleanly/commands.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo -n "foo " > /usr/local/share/dsta/console 4 | -------------------------------------------------------------------------------- /tests/fixtures/boot-mods/foo-bar-with-overrides/dedicated_server_mods_setup.lua-tail: -------------------------------------------------------------------------------- 1 | ServerModSetup("foo") 2 | ServerModSetup("bar") 3 | -------------------------------------------------------------------------------- /tests/fixtures/boot-mods/foo-bar/modoverrides.lua: -------------------------------------------------------------------------------- 1 | return { 2 | ["workshop-foo"] = { enabled = true }, 3 | ["workshop-bar"] = { enabled = true }, 4 | } 5 | -------------------------------------------------------------------------------- /tests/fixtures/console/commands.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo foo bar > /usr/local/share/dsta/console 4 | echo bar > /usr/local/share/dsta/console 5 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | ## Usage 4 | 1. Install [`bats`][bats] 5 | 2. Run `bats tests` 6 | 7 | [bats]: https://github.com/bats-core/bats-core/wiki/Install-Bats-Using-a-Package 8 | -------------------------------------------------------------------------------- /docs/recipes/cluster/overworld.env: -------------------------------------------------------------------------------- 1 | NAME="Server Cluster Recipe" 2 | WORLD_PRESET=SURVIVAL_TOGETHER 3 | SHARD_ENABLE=true 4 | SHARD_IS_MASTER=true 5 | SHARD_NAME=overworld 6 | SHARD_CLUSTER_KEY=secret 7 | -------------------------------------------------------------------------------- /docs/recipes/cluster/underworld.env: -------------------------------------------------------------------------------- 1 | WORLD_PRESET=DST_CAVE 2 | SHARD_ENABLE=true 3 | SHARD_IS_MASTER=false 4 | SHARD_NAME=underworld 5 | SHARD_MASTER_IP=overworld 6 | SERVER_PORT=11000 7 | SHARD_CLUSTER_KEY=secret 8 | -------------------------------------------------------------------------------- /tests/dependencies/load.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | load dependencies/bats-support/output 4 | load dependencies/bats-support/error 5 | load dependencies/bats-support/lang 6 | load dependencies/bats-assert/assert 7 | -------------------------------------------------------------------------------- /docs/recipes/mods/readme.md: -------------------------------------------------------------------------------- 1 | # Server Mods Recipe 2 | > Configures and runs a modded server. 3 | 4 | Create a `local.env` for the server token. 5 | ```dotenv 6 | TOKEN=pds-g^KU_... 7 | ``` 8 | 9 | Start the server. 10 | ```shell 11 | docker-compose up -d 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/recipes/basic/readme.md: -------------------------------------------------------------------------------- 1 | # Basic Server Recipe 2 | > Configures and runs a basic server. 3 | 4 | Create a `local.env` for the server token. 5 | ```dotenv 6 | TOKEN=pds-g^KU_... 7 | ``` 8 | 9 | Start the server. 10 | ```shell 11 | docker-compose up -d 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/recipes/update/readme.md: -------------------------------------------------------------------------------- 1 | # Update Server Recipe 2 | > Configures and runs a server with auto-update. 3 | 4 | Create a `local.env` for the server token. 5 | ```dotenv 6 | TOKEN=pds-g^KU_... 7 | ``` 8 | 9 | Start the server. 10 | ```shell 11 | docker-compose up -d 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/recipes/world/readme.md: -------------------------------------------------------------------------------- 1 | # Custom World Generation Recipe 2 | > Configures custom world generation. 3 | 4 | Create a `local.env` for the server token. 5 | ```dotenv 6 | TOKEN=pds-g^KU_... 7 | ``` 8 | 9 | Start the server. 10 | ```shell 11 | docker-compose up -d 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/recipes/session/readme.md: -------------------------------------------------------------------------------- 1 | # Persistent Session Recipe 2 | > Configures and runs a server with a persistent session. 3 | 4 | Create a `local.env` for the server token. 5 | ```dotenv 6 | TOKEN=pds-g^KU_... 7 | ``` 8 | 9 | Start the server. 10 | ```shell 11 | docker-compose up -d 12 | ``` 13 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | > List of project maintainers. 3 | 4 | ## Core Maintainers 5 | 6 | - [Thomas Deinhamer](https://github.com/thasmo) / [@thomasdeinhamer](https://twitter.com/thomasdeinhamer) 7 | - [Brais Gabín](https://github.com/BraisGabin) / [@braisgabin](https://twitter.com/braisgabin) 8 | -------------------------------------------------------------------------------- /docs/recipes/cluster/readme.md: -------------------------------------------------------------------------------- 1 | # Server Cluster Recipe 2 | > Configures and runs a server cluster for a forest and cave world. 3 | 4 | Create a `local.env` for the server token. 5 | ```dotenv 6 | TOKEN=pds-g^KU_... 7 | ``` 8 | 9 | Start the server. 10 | ```shell 11 | docker-compose up -d 12 | ``` 13 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-help/console: -------------------------------------------------------------------------------- 1 | usage: dontstarvetogether console [command ...] 2 | 3 | The console utility executes commands in the Don't Starve Together server console. 4 | The commands are executed in command-line order. 5 | If command is a single dash ('-') or absent, console reads from the standard input. 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = tab 6 | end_of_line = lf 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | indent_style = space 12 | indent_size = 4 13 | trim_trailing_whitespace = false 14 | 15 | [*.yml] 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-help/version: -------------------------------------------------------------------------------- 1 | usage: dontstarvetogether version [--local|--upstream|--check] 2 | 3 | Print the local and upstream version of the DST server. 4 | 5 | --local 6 | Return the local version. 7 | --upstream 8 | Return the currently released upstream version. 9 | --check 10 | Check if the currently running version is up to date. 11 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-help/dst-server: -------------------------------------------------------------------------------- 1 | usage: dontstarvetogether [--help] [] 2 | 3 | The commands are: 4 | start Start the server 5 | console Execute commands on the server console 6 | update Update game and/or mods 7 | log Show a log 8 | version Show the current server version 9 | 10 | See 'dontstarvetogether help ' to read about a specific command. 11 | -------------------------------------------------------------------------------- /tests/entrypoint.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "The image know how to run any kind of command" { 6 | docker run --rm $IMAGE echo OK >"$TMP/std_output" 7 | echo OK >"$TMP/std_output_expected" 8 | diff "$TMP/std_output" "$TMP/std_output_expected" 9 | } 10 | 11 | @test "docker-entrypoint.sh successed if the command successed" { 12 | run $BUILD/entrypoint.sh true 13 | assert_success 14 | } 15 | 16 | @test "docker-entrypoint.sh fails if the command fails" { 17 | run $BUILD/entrypoint.sh false 18 | assert_failure 19 | } 20 | -------------------------------------------------------------------------------- /tests/console.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "write in /usr/local/share/dsta/console is like write in the console" { 6 | fixtures console 7 | 8 | docker run -d --name $CONTAINER $IMAGE 9 | docker cp "$FIXTURE_ROOT/commands.sh" $CONTAINER:/ 10 | docker exec $CONTAINER /commands.sh 11 | wait_until_loaded 12 | sleep 1 13 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 14 | grep -F "RemoteCommandInput: \"foo bar\"" "$TMP/server_log.txt" 15 | grep -F "RemoteCommandInput: \"bar\"" "$TMP/server_log.txt" 16 | } 17 | -------------------------------------------------------------------------------- /docs/recipes/basic/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | world: 4 | image: yeetzone/dontstarvetogether 5 | container_name: world 6 | hostname: world 7 | depends_on: 8 | - data 9 | env_file: 10 | - world.env 11 | - local.env 12 | ports: 13 | - "10999:10999/udp" 14 | volumes: 15 | - type: volume 16 | source: data 17 | target: /data 18 | data: 19 | image: yeetzone/dontstarvetogether-data 20 | volumes: 21 | - type: volume 22 | source: data 23 | target: /data 24 | volumes: 25 | data: 26 | -------------------------------------------------------------------------------- /docs/recipes/mods/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | world: 4 | image: yeetzone/dontstarvetogether 5 | container_name: world 6 | hostname: world 7 | depends_on: 8 | - data 9 | env_file: 10 | - world.env 11 | - local.env 12 | ports: 13 | - "10999:10999/udp" 14 | volumes: 15 | - type: volume 16 | source: data 17 | target: /data 18 | data: 19 | image: yeetzone/dontstarvetogether-data 20 | volumes: 21 | - type: volume 22 | source: data 23 | target: /data 24 | volumes: 25 | data: 26 | -------------------------------------------------------------------------------- /docs/recipes/session/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | world: 4 | image: yeetzone/dontstarvetogether 5 | container_name: world 6 | hostname: world 7 | depends_on: 8 | - data 9 | env_file: 10 | - world.env 11 | - local.env 12 | ports: 13 | - "10999:10999/udp" 14 | volumes: 15 | - type: volume 16 | source: data 17 | target: /data 18 | - type: volume 19 | source: storage 20 | target: /opt/storage/ 21 | data: 22 | image: yeetzone/dontstarvetogether-data 23 | volumes: 24 | - type: volume 25 | source: data 26 | target: /data 27 | volumes: 28 | data: 29 | storage: 30 | -------------------------------------------------------------------------------- /tests/attach-console.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "Send console commands" { 6 | timeout --kill-after 1 20 docker run -i --name $CONTAINER $IMAGE <<-EOF 7 | c_shutdown(true) 8 | EOF 9 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt $TMP/server_log.txt 10 | 11 | grep -Fq "RemoteCommandInput: \"c_shutdown(true)\"" $TMP/server_log.txt 12 | } 13 | 14 | @test "Send console commands with docker attach" { 15 | docker run -id --name $CONTAINER $IMAGE 16 | docker attach $CONTAINER <<-EOF 17 | c_shutdown(true) 18 | EOF 19 | timeout --kill-after 1 20 docker wait $CONTAINER 20 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt $TMP/server_log.txt 21 | 22 | grep -Fq "RemoteCommandInput: \"c_shutdown(true)\"" $TMP/server_log.txt 23 | } 24 | -------------------------------------------------------------------------------- /tests/test_helper.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | load dependencies/load 4 | 5 | export BUILD="$BATS_TEST_DIRNAME/../build" 6 | export IMAGE="yeetzone/dontstarvetogether" 7 | export CONTAINER="yeetzone-test" 8 | export TMP="$BATS_TEST_DIRNAME/tmp" 9 | 10 | fixtures() { 11 | FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures/$1" 12 | RELATIVE_FIXTURE_ROOT="$(bats_trim_filename "$FIXTURE_ROOT")" 13 | } 14 | 15 | setup() { 16 | mkdir "$TMP" 17 | 18 | docker build -t $IMAGE $BUILD 19 | } 20 | 21 | teardown() { 22 | docker rm -fv "$CONTAINER" >/dev/null 23 | rm -rf "$TMP" 24 | } 25 | 26 | wait_until_initializing() { 27 | docker logs --follow $CONTAINER | sed '/Starting Up$/ q' >/dev/null 28 | } 29 | 30 | wait_until_loaded() { 31 | docker logs --follow $CONTAINER | sed '/LOADING LUA SUCCESS$/ q' >/dev/null 32 | } 33 | -------------------------------------------------------------------------------- /docs/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | Setting up the server is pretty easy if you got Docker already running. 4 | Find a quick step-by-step guide how to setup the dedicated server below. 5 | 6 | ## Overview 7 | 8 | 1. Install [Docker Engine][engine-setup]. 9 | 2. Install [Docker Compose][compose-setup]. *(optional but recommended)* 10 | 3. Configure a [`docker-compose.yml`][compose-file] configuration. *(optional but recommended)* 11 | 4. [Start a container][engine-run] i.e. [launch the service][compose-up]. 12 | 13 | [engine-setup]: https://docs.docker.com/engine/installation/ 14 | [compose-setup]: https://docs.docker.com/compose/install/ 15 | [engine-run]: https://docs.docker.com/engine/reference/run/ 16 | [compose-up]: https://docs.docker.com/compose/reference/up/ 17 | [compose-file]: https://docs.docker.com/compose/compose-file/ 18 | -------------------------------------------------------------------------------- /docs/recipes/readme.md: -------------------------------------------------------------------------------- 1 | # Recipes 2 | 3 | Recipes are pre-configured server configurations which can be run, without any further modifications, more or less instantly. 4 | Recipes try to provide simple configurations for common scenarios to further build on. 5 | 6 | [**Basic Server Recipe**](basic/) 7 | Configure and run a basic server. 8 | 9 | [**Server Cluster Recipe**](cluster/) 10 | Configure and run a server cluster for a forest and cave world. 11 | 12 | [**Server Mods Recipe**](mods/) 13 | Configure and run a modded server. 14 | 15 | [**Persistent Session Recipe**](session/) 16 | Configure and run a server with persistent session. 17 | 18 | [**Custom World Generation Recipe**](world/) 19 | Configure custom world generation. 20 | 21 | [**Update Server Recipe**](update/) 22 | Configures and runs a server with auto-update. 23 | -------------------------------------------------------------------------------- /tests/fixtures/dsta-help/start: -------------------------------------------------------------------------------- 1 | usage: dontstarvetogether start [--update=all|none|game|mods] 2 | [--keep-configuration=]...>] 3 | 4 | --update=none 5 | Update nothing, just start the server. This is the default behaviour. 6 | --update=all 7 | Update the game and the mods before launch the server. 8 | --update=game 9 | Update just the game (no the mods) and launch the server. 10 | --update=mods 11 | Update the mods and launch the server. 12 | --keep-configuration 13 | Select which configuration you don't want to overwrite. 14 | You must provide one or more of these values separated by commas: 15 | - token 16 | - cluster 17 | - server 18 | - world 19 | - adminlist 20 | - blocklist 21 | - whitelist 22 | - mods 23 | -------------------------------------------------------------------------------- /docs/recipes/update/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | world: 4 | image: yeetzone/dontstarvetogether 5 | container_name: world 6 | hostname: world 7 | restart: always 8 | labels: 9 | autoheal: "true" 10 | depends_on: 11 | - data 12 | env_file: 13 | - world.env 14 | - local.env 15 | ports: 16 | - "10999:10999/udp" 17 | volumes: 18 | - type: volume 19 | source: data 20 | target: /data 21 | health: 22 | image: willfarrell/autoheal 23 | container_name: health 24 | hostname: health 25 | env_file: 26 | - health.env 27 | - local.env 28 | volumes: 29 | - /var/run/docker.sock:/var/run/docker.sock 30 | data: 31 | image: yeetzone/dontstarvetogether-data 32 | volumes: 33 | - type: volume 34 | source: data 35 | target: /data 36 | volumes: 37 | data: 38 | -------------------------------------------------------------------------------- /docs/recipes/world/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | world: 4 | image: yeetzone/dontstarvetogether 5 | container_name: world 6 | hostname: world 7 | depends_on: 8 | - data 9 | env_file: 10 | - world.env 11 | - local.env 12 | environment: 13 | WORLD_CONFIGURATION: | 14 | return { 15 | override_enabled = true, 16 | overrides = { 17 | krampus = "often", 18 | season_start = "summer", 19 | world_size = "huge", 20 | regrowth = "veryfast", 21 | extrastartingitems = "20", 22 | }, 23 | } 24 | ports: 25 | - "10999:10999/udp" 26 | volumes: 27 | - type: volume 28 | source: data 29 | target: /data 30 | data: 31 | image: yeetzone/dontstarvetogether-data 32 | volumes: 33 | - type: volume 34 | source: data 35 | target: /data 36 | volumes: 37 | data: 38 | -------------------------------------------------------------------------------- /docs/recipes/cluster/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | overworld: 4 | image: yeetzone/dontstarvetogether 5 | container_name: overworld 6 | hostname: overworld 7 | depends_on: 8 | - data 9 | env_file: 10 | - overworld.env 11 | - local.env 12 | ports: 13 | - "10999:10999/udp" 14 | volumes: 15 | - type: volume 16 | source: data 17 | target: /data 18 | underworld: 19 | image: yeetzone/dontstarvetogether 20 | container_name: underworld 21 | hostname: underworld 22 | depends_on: 23 | - data 24 | env_file: 25 | - underworld.env 26 | - local.env 27 | ports: 28 | - "11000:11000/udp" 29 | volumes: 30 | - type: volume 31 | source: data 32 | target: /data 33 | data: 34 | image: yeetzone/dontstarvetogether-data 35 | volumes: 36 | - type: volume 37 | source: data 38 | target: /data 39 | volumes: 40 | data: 41 | -------------------------------------------------------------------------------- /tests/build-mods.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "correct dedicated_server_mods_setup.lua installing one mod" { 6 | fixtures build-mods/one-mod 7 | 8 | docker build --build-arg MODS="378160973" -t $IMAGE $BUILD 9 | docker create --name $CONTAINER $IMAGE 10 | docker cp $CONTAINER:/opt/dst/mods/dedicated_server_mods_setup.lua "$TMP/dedicated_server_mods_setup.lua" 11 | diff --strip-trailing-cr "$TMP/dedicated_server_mods_setup.lua" "$FIXTURE_ROOT/dedicated_server_mods_setup.lua" 12 | } 13 | 14 | @test "correct dedicated_server_mods_setup.lua installing two mods" { 15 | fixtures build-mods/two-mods 16 | 17 | docker build --build-arg MODS="378160973,380423963" -t $IMAGE $BUILD 18 | docker create --name $CONTAINER $IMAGE 19 | docker cp $CONTAINER:/opt/dst/mods/dedicated_server_mods_setup.lua "$TMP/dedicated_server_mods_setup.lua" 20 | diff --strip-trailing-cr "$TMP/dedicated_server_mods_setup.lua" "$FIXTURE_ROOT/dedicated_server_mods_setup.lua" 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/build-mods/one-mod/dedicated_server_mods_setup.lua: -------------------------------------------------------------------------------- 1 | --There are two functions that will install mods, ServerModSetup and ServerModCollectionSetup. Put the calls to the functions in this file and they will be executed on boot. 2 | 3 | --ServerModSetup takes a string of a specific mod's Workshop id. It will download and install the mod to your mod directory on boot. 4 | --The Workshop id can be found at the end of the url to the mod's Workshop page. 5 | --Example: http://steamcommunity.com/sharedfiles/filedetails/?id=350811795 6 | --ServerModSetup("350811795") 7 | 8 | --ServerModCollectionSetup takes a string of a specific mod's Workshop id. It will download all the mods in the collection and install them to the mod directory on boot. 9 | --The Workshop id can be found at the end of the url to the collection's Workshop page. 10 | --Example: http://steamcommunity.com/sharedfiles/filedetails/?id=379114180 11 | --ServerModCollectionSetup("379114180") 12 | ServerModSetup("378160973") 13 | -------------------------------------------------------------------------------- /tests/fixtures/build-mods/two-mods/dedicated_server_mods_setup.lua: -------------------------------------------------------------------------------- 1 | --There are two functions that will install mods, ServerModSetup and ServerModCollectionSetup. Put the calls to the functions in this file and they will be executed on boot. 2 | 3 | --ServerModSetup takes a string of a specific mod's Workshop id. It will download and install the mod to your mod directory on boot. 4 | --The Workshop id can be found at the end of the url to the mod's Workshop page. 5 | --Example: http://steamcommunity.com/sharedfiles/filedetails/?id=350811795 6 | --ServerModSetup("350811795") 7 | 8 | --ServerModCollectionSetup takes a string of a specific mod's Workshop id. It will download all the mods in the collection and install them to the mod directory on boot. 9 | --The Workshop id can be found at the end of the url to the collection's Workshop page. 10 | --Example: http://steamcommunity.com/sharedfiles/filedetails/?id=379114180 11 | --ServerModCollectionSetup("379114180") 12 | ServerModSetup("378160973") 13 | ServerModSetup("380423963") 14 | -------------------------------------------------------------------------------- /tests/dsta-version.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "dontstarvetogether version" { 6 | docker run --rm $IMAGE dontstarvetogether version 7 | } 8 | 9 | @test "dontstarvetogether version --local" { 10 | run docker run --rm $IMAGE dontstarvetogether version --local 11 | assert_success 12 | assert_output --regexp '^[0-9]+$' 13 | } 14 | 15 | @test "dontstarvetogether version --upstream" { 16 | run docker run --rm $IMAGE dontstarvetogether version --upstream 17 | assert_success 18 | assert_output --regexp '^[0-9]+$' 19 | } 20 | 21 | @test "dontstarvetogether version --check" { 22 | run docker run --rm $IMAGE dontstarvetogether version --check 23 | if [ $status -eq 0 ]; then 24 | assert_output "Version is up to date." 25 | else 26 | assert_output "Version is outdated." 27 | fi 28 | } 29 | 30 | @test "dontstarvetogether version unknown flag" { 31 | fixtures dsta-help 32 | 33 | run docker run --rm $IMAGE dontstarvetogether version --foo 34 | assert_failure 35 | cat "$FIXTURE_ROOT/version" | assert_output 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Thomas "Thasmo" Deinhamer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/dependencies/bats-support/error.bash: -------------------------------------------------------------------------------- 1 | # 2 | # bats-support - Supporting library for Bats test helpers 3 | # 4 | # Written in 2016 by Zoltan Tombol 5 | # 6 | # To the extent possible under law, the author(s) have dedicated all 7 | # copyright and related and neighboring rights to this software to the 8 | # public domain worldwide. This software is distributed without any 9 | # warranty. 10 | # 11 | # You should have received a copy of the CC0 Public Domain Dedication 12 | # along with this software. If not, see 13 | # . 14 | # 15 | 16 | # 17 | # error.bash 18 | # ---------- 19 | # 20 | # Functions implementing error reporting. Used by public helper 21 | # functions or test suits directly. 22 | # 23 | 24 | # Fail and display a message. When no parameters are specified, the 25 | # message is read from the standard input. Other functions use this to 26 | # report failure. 27 | # 28 | # Globals: 29 | # none 30 | # Arguments: 31 | # $@ - [=STDIN] message 32 | # Returns: 33 | # 1 - always 34 | # Inputs: 35 | # STDIN - [=$@] message 36 | # Outputs: 37 | # STDERR - message 38 | fail() { 39 | (( $# == 0 )) && batslib_err || batslib_err "$@" 40 | return 1 41 | } 42 | -------------------------------------------------------------------------------- /tests/close-cleanly.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "close cleanly after docker stop" { 6 | docker run -d --name $CONTAINER $IMAGE 7 | wait_until_loaded 8 | docker stop $CONTAINER 9 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 10 | grep -q "Shutting down$" "$TMP/server_log.txt" 11 | } 12 | 13 | @test "close cleanly after docker stop with dirty console" { 14 | fixtures close-cleanly 15 | 16 | docker run -d --name $CONTAINER $IMAGE 17 | wait_until_loaded 18 | docker cp "$FIXTURE_ROOT/commands.sh" $CONTAINER:/ 19 | docker exec $CONTAINER /commands.sh 20 | docker stop $CONTAINER 21 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 22 | grep -q "Shutting down$" "$TMP/server_log.txt" 23 | } 24 | 25 | @test "close cleanly after kill 1" { 26 | fixtures close-cleanly 27 | 28 | docker run -d --name $CONTAINER $IMAGE 29 | wait_until_loaded 30 | docker exec $CONTAINER bash -c "kill 1" 31 | timeout --kill-after 1 12 docker wait $CONTAINER 32 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 33 | grep -q "Shutting down$" "$TMP/server_log.txt" 34 | } 35 | 36 | @test "close cleanly after kill -SIGINT 1" { 37 | fixtures close-cleanly 38 | 39 | docker run -d --name $CONTAINER $IMAGE 40 | wait_until_loaded 41 | docker exec $CONTAINER bash -c "kill -SIGINT 1" 42 | timeout --kill-after 1 12 docker wait $CONTAINER 43 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 44 | grep -q "Shutting down$" "$TMP/server_log.txt" 45 | } 46 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | # Commands 2 | 3 | Commands are used to start the server with specific options, 4 | control it and get information about it, while it's running. 5 | 6 | ## `start` 7 | Start the DST server. 8 | 9 | **Options** 10 | * `--update` Enable or disable running updates on boot. 11 | 12 | **Examples** 13 | * `dontstarvetogether start` Start the server, do not update. 14 | * `dontstarvetogether start --update` Start the server and update the game files. 15 | 16 | ## `version` 17 | Print the game's version. 18 | 19 | **Options** 20 | * `--local` Print the current running version of the game. 21 | * `--upstream` Print the current released version of the game. 22 | * `--check` Check if the upstream version is newer than the local running one. 23 | 24 | **Examples** 25 | * `dontstarvetogether version` Print the current running version and the available upstream version. 26 | * `dontstarvetogether version --local` Print the current running version of the game. 27 | * `dontstarvetogether version --upstream` Print the current available, released version of the game. 28 | * `dontstarvetogether version --check` Check if the upstream version is newer than the running version. 29 | 30 | ## `log` 31 | Read contents of various game-server log files. 32 | 33 | **Options** 34 | * `--server` Print the server log. 35 | * `--chat` Print the chat log 36 | 37 | **Examples** 38 | * `dontstarvetogether log --server` Print the server log. 39 | * `dontstarvetogether log --chat` Print the chat log. 40 | 41 | ## `console` 42 | Execute a command on the in-game server-console. 43 | 44 | **Examples** 45 | * `dontstarvetogether console c_reset()` Run `c_reset()` on the console which resets the world. 46 | * `dontstarvetogether console c_announce('Hello!')` Run `c_announce('Hello!')` on the console which broadcasts a message. 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | > Thank you for considering contributing to the project. 3 | 4 | ## Features and Bugs 5 | 6 | Should you experience any bugs or have a feature wish, you can 7 | let us know by [creating a new issue][issues-create] on GitHub. 8 | 9 | Before creating a new issue search for existing issues. 10 | Maybe it has already been reported by someone else. 11 | 12 | ## Pull Requests 13 | 14 | We'd like to encourage you to contribute code and we do appreciate all help 15 | on making this a better project. Especially look out for issues tagged with 16 | [`contribution`][issues-contribute], which are free to grab and work on. 17 | Let us know if you consider working on one. 18 | 19 | To stay on track we ask you to respect the following **contribution rules**: 20 | 21 | - Fork the repository when working on a contribution. 22 | - Create pull requests for the `master` branch only. 23 | - Use an `editorconfig` compliant editor and/or respect the [settings][file-editorconfig]. 24 | - Update the [`CHANGELOG`][file-changelog], [`README`][file-readme] or documentation, if relevant. 25 | 26 | ## Contact 27 | 28 | Feel free to contact us if you have questions or feedback. 29 | 30 | - Join our [Discord][contact-discord] server. 31 | - Use the [discussions][contact-discussions] on GitHub. 32 | 33 | [issues-create]: https://github.com/yeetzone/docker-dontstarvetogether/issues/new/ 34 | [issues-contribute]: https://github.com/yeetzone/docker-dontstarvetogether/labels/contribution 35 | [file-editorconfig]: https://github.com/yeetzone/docker-dontstarvetogether/blob/develop/.editorconfig 36 | [file-readme]: https://github.com/yeetzone/docker-dontstarvetogether/blob/develop/README.md 37 | [file-changelog]: https://github.com/yeetzone/docker-dontstarvetogether/blob/develop/CHANGELOG.md 38 | [contact-discord]: https://go.yeet.zone/discord 39 | [contact-discussions]: https://github.com/yeetzone/docker-dontstarvetogether/discussions 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Don't Starve Together 2 | > Dockerfile for building a [`Don't Starve Together`][website] dedicated server image. 3 | 4 | --- 5 | 6 | This repository provides a `Dockerfile` for building a dedicated server 7 | for the online multi-player survival game [*Don't Starve Together*][website]. 8 | 9 | `Docker Hub` hosts our image [`yeetzone/dontstarvetogether`][hub]. 10 | 11 | ## Features 12 | - Configuration via **environment** variables. 13 | - **World** generation via default **presets**. 14 | - **World** generation via **custom** level data. 15 | - **Mods** with custom **configuration**. 16 | - Connected worlds via **sharding**. 17 | - Control the server directly on the **CLI**. 18 | - World **persistence** via volumes. 19 | 20 | ## Documentation 21 | - [Configuration][docs-configuration] · *Overview of options for customizing the server.* 22 | - [Commands][docs-commands] · *List of available CLI commands to manage the server.* 23 | - [Recipes][docs-recipes] · *Collection of pre-defined server setups.* 24 | 25 | ## Support 26 | - [Discord][support-discord] · *Join our Discord server if you have questions.* 27 | - [Discussions][support-github] · *Use GitHub discussions to suggest changes or ask questions.* 28 | 29 | ## Contribution 30 | Do you want to contribute to the project? 31 | Check out our [contribution guide][contribution-guide]. 32 | 33 | --- 34 | 35 | [![forthebadge](https://forthebadge.com/images/badges/open-source.svg)](https://forthebadge.com/) 36 | [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com/) 37 | 38 | [docs-configuration]: /docs/configuration.md 39 | [docs-commands]: /docs/commands.md 40 | [docs-recipes]: /docs/recipes/ 41 | [support-discord]: https://go.yeet.zone/discord 42 | [support-github]: https://github.com/yeetzone/docker-dontstarvetogether/discussions 43 | [contribution-guide]: /CONTRIBUTING.md 44 | [hub]: https://hub.docker.com/r/yeetzone/dontstarvetogether 45 | [website]: https://www.dontstarvetogether.com/ 46 | -------------------------------------------------------------------------------- /tests/dsta-update.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "dontstarvetogether update" { 6 | fixtures dsta-help 7 | 8 | run docker run --rm $IMAGE dontstarvetogether update 9 | assert_success 10 | assert_line "Success! App '343050' already up to date." 11 | assert_line --partial "DownloadMods" 12 | } 13 | 14 | @test "dontstarvetogether update --all" { 15 | fixtures dsta-help 16 | 17 | run docker run --rm $IMAGE dontstarvetogether update --all 18 | assert_success 19 | assert_line "Success! App '343050' already up to date." 20 | assert_line --partial "DownloadMods" 21 | } 22 | 23 | @test "dontstarvetogether update --game" { 24 | fixtures dsta-help 25 | 26 | run docker run --rm $IMAGE dontstarvetogether update --game 27 | assert_success 28 | assert_line "Success! App '343050' already up to date." 29 | refute_line --partial "DownloadMods" 30 | } 31 | 32 | @test "dontstarvetogether update --mods" { 33 | fixtures dsta-help 34 | 35 | run docker run --rm $IMAGE dontstarvetogether update --mods 36 | assert_success 37 | refute_line "Success! App '343050' already up to date." 38 | assert_line --partial "DownloadMods" 39 | } 40 | 41 | @test "dontstarvetogether update -- too much flags 1" { 42 | fixtures dsta-help 43 | 44 | run docker run --rm $IMAGE dontstarvetogether update --game --mods 45 | assert_failure 46 | cat $FIXTURE_ROOT/update | assert_output 47 | } 48 | 49 | @test "dontstarvetogether update -- too much flags 2" { 50 | fixtures dsta-help 51 | 52 | run docker run --rm $IMAGE dontstarvetogether update --all --game 53 | assert_failure 54 | cat $FIXTURE_ROOT/update | assert_output 55 | } 56 | 57 | @test "dontstarvetogether update -- repeat flags" { 58 | fixtures dsta-help 59 | 60 | run docker run --rm $IMAGE dontstarvetogether update --game --game 61 | assert_failure 62 | cat $FIXTURE_ROOT/update | assert_output 63 | } 64 | 65 | @test "dontstarvetogether update -- Unknown argument" { 66 | fixtures dsta-help 67 | 68 | run docker run --rm $IMAGE dontstarvetogether update foo 69 | assert_failure 70 | cat $FIXTURE_ROOT/update | assert_output 71 | } 72 | 73 | @test "dontstarvetogether update -- Unknown flag" { 74 | fixtures dsta-help 75 | 76 | run docker run --rm $IMAGE dontstarvetogether update --foo 77 | assert_failure 78 | cat $FIXTURE_ROOT/update | assert_output 79 | } 80 | -------------------------------------------------------------------------------- /tests/dependencies/bats-support/lang.bash: -------------------------------------------------------------------------------- 1 | # 2 | # bats-util - Various auxiliary functions for Bats 3 | # 4 | # Written in 2016 by Zoltan Tombol 5 | # 6 | # To the extent possible under law, the author(s) have dedicated all 7 | # copyright and related and neighboring rights to this software to the 8 | # public domain worldwide. This software is distributed without any 9 | # warranty. 10 | # 11 | # You should have received a copy of the CC0 Public Domain Dedication 12 | # along with this software. If not, see 13 | # . 14 | # 15 | 16 | # 17 | # lang.bash 18 | # --------- 19 | # 20 | # Bash language and execution related functions. Used by public helper 21 | # functions. 22 | # 23 | 24 | # Check whether the calling function was called from a given function. 25 | # 26 | # By default, direct invocation is checked. The function succeeds if the 27 | # calling function was called directly from the given function. In other 28 | # words, if the given function is the next element on the call stack. 29 | # 30 | # When `--indirect' is specified, indirect invocation is checked. The 31 | # function succeeds if the calling function was called from the given 32 | # function with any number of intermediate calls. In other words, if the 33 | # given function can be found somewhere on the call stack. 34 | # 35 | # Direct invocation is a form of indirect invocation with zero 36 | # intermediate calls. 37 | # 38 | # Globals: 39 | # FUNCNAME 40 | # Options: 41 | # -i, --indirect - check indirect invocation 42 | # Arguments: 43 | # $1 - calling function's name 44 | # Returns: 45 | # 0 - current function was called from the given function 46 | # 1 - otherwise 47 | batslib_is_caller() { 48 | local -i is_mode_direct=1 49 | 50 | # Handle options. 51 | while (( $# > 0 )); do 52 | case "$1" in 53 | -i|--indirect) is_mode_direct=0; shift ;; 54 | --) shift; break ;; 55 | *) break ;; 56 | esac 57 | done 58 | 59 | # Arguments. 60 | local -r func="$1" 61 | 62 | # Check call stack. 63 | if (( is_mode_direct )); then 64 | [[ $func == "${FUNCNAME[2]}" ]] && return 0 65 | else 66 | local -i depth 67 | for (( depth=2; depth<${#FUNCNAME[@]}; ++depth )); do 68 | [[ $func == "${FUNCNAME[$depth]}" ]] && return 0 69 | done 70 | fi 71 | 72 | return 1 73 | } 74 | -------------------------------------------------------------------------------- /tests/dsta-log.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "Get the logs" { 6 | fixtures dsta-log 7 | 8 | docker run -d --name $CONTAINER $IMAGE sleep infinity 9 | docker exec $CONTAINER mkdir /var/lib/dsta/cluster/shard 10 | docker exec $CONTAINER chown steam:steam /var/lib/dsta/cluster/shard 11 | docker cp "$FIXTURE_ROOT/server_log.txt" $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt 12 | docker cp "$FIXTURE_ROOT/server_log_chat.txt" $CONTAINER:/var/lib/dsta/cluster/shard/server_log_chat.txt 13 | 14 | docker exec $CONTAINER dontstarvetogether log >"$TMP/server_log.txt" 15 | diff "$TMP/server_log.txt" "$FIXTURE_ROOT/server_log.txt" 16 | docker exec $CONTAINER dontstarvetogether log --server >"$TMP/server_log.txt" 17 | diff "$TMP/server_log.txt" "$FIXTURE_ROOT/server_log.txt" 18 | docker exec $CONTAINER dontstarvetogether log --chat >"$TMP/server_log_chat.txt" 19 | diff "$TMP/server_log_chat.txt" "$FIXTURE_ROOT/server_log_chat.txt" 20 | } 21 | 22 | @test "Empty logs when the files doesn't exist" { 23 | fixtures dsta-log 24 | 25 | docker run --rm -e NAME=foo $IMAGE dontstarvetogether log >"$TMP/std_output.txt" 2>"$TMP/err_output.txt" 26 | diff "$TMP/std_output.txt" "$FIXTURE_ROOT/empty-file" 27 | diff "$TMP/err_output.txt" "$FIXTURE_ROOT/empty-file" 28 | 29 | docker run --rm -e NAME=foo $IMAGE dontstarvetogether log --server >"$TMP/std_output.txt" 2>"$TMP/err_output.txt" 30 | diff "$TMP/std_output.txt" "$FIXTURE_ROOT/empty-file" 31 | diff "$TMP/err_output.txt" "$FIXTURE_ROOT/empty-file" 32 | 33 | docker run --rm -e NAME=foo $IMAGE dontstarvetogether log --chat >"$TMP/std_output.txt" 2>"$TMP/err_output.txt" 34 | diff "$TMP/std_output.txt" "$FIXTURE_ROOT/empty-file" 35 | diff "$TMP/err_output.txt" "$FIXTURE_ROOT/empty-file" 36 | } 37 | 38 | @test "dontstarvetogether log fails with double flag" { 39 | fixtures dsta-help 40 | 41 | run docker run --rm $IMAGE dontstarvetogether log --server --chat 42 | assert_failure 43 | cat "$FIXTURE_ROOT/log" | assert_output 44 | } 45 | 46 | @test "dontstarvetogether log fails with unknown flag" { 47 | fixtures dsta-help 48 | 49 | run docker run --rm $IMAGE dontstarvetogether log --type 50 | assert_failure 51 | cat "$FIXTURE_ROOT/log" | assert_output 52 | } 53 | 54 | @test "dontstarvetogether log fails with parameter" { 55 | fixtures dsta-help 56 | 57 | run docker run --rm $IMAGE dontstarvetogether log asd 58 | assert_failure 59 | cat "$FIXTURE_ROOT/log" | assert_output 60 | } 61 | -------------------------------------------------------------------------------- /tests/boot-mods.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "Configure one mod" { 6 | fixtures boot-mods/foo 7 | 8 | docker run -d -e MODS="foo" --name $CONTAINER $IMAGE 9 | wait_until_initializing 10 | docker cp $CONTAINER:/opt/dst/mods/dedicated_server_mods_setup.lua "$TMP/dedicated_server_mods_setup.lua" 11 | tail -n 2 "$TMP/dedicated_server_mods_setup.lua" >"$TMP/dedicated_server_mods_setup.lua-tail" 12 | diff "$TMP/dedicated_server_mods_setup.lua-tail" "$FIXTURE_ROOT/dedicated_server_mods_setup.lua-tail" 13 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/modoverrides.lua "$TMP/modoverrides.lua" 14 | diff "$TMP/modoverrides.lua" "$FIXTURE_ROOT/modoverrides.lua" 15 | } 16 | 17 | @test "Configure two mods" { 18 | fixtures boot-mods/foo-bar 19 | 20 | docker run -d -e MODS="foo,bar" --name $CONTAINER $IMAGE 21 | wait_until_initializing 22 | docker cp $CONTAINER:/opt/dst/mods/dedicated_server_mods_setup.lua "$TMP/dedicated_server_mods_setup.lua" 23 | tail -n 3 "$TMP/dedicated_server_mods_setup.lua" >"$TMP/dedicated_server_mods_setup.lua-tail" 24 | diff "$TMP/dedicated_server_mods_setup.lua-tail" "$FIXTURE_ROOT/dedicated_server_mods_setup.lua-tail" 25 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/modoverrides.lua "$TMP/modoverrides.lua" 26 | diff "$TMP/modoverrides.lua" "$FIXTURE_ROOT/modoverrides.lua" 27 | } 28 | 29 | @test "Configure two mods with mods overrides" { 30 | fixtures boot-mods/foo-bar-with-overrides 31 | 32 | docker run -d -e MODS="foo,bar" -e MODS_OVERRIDES="xyz" --name $CONTAINER $IMAGE 33 | wait_until_initializing 34 | docker cp $CONTAINER:/opt/dst/mods/dedicated_server_mods_setup.lua "$TMP/dedicated_server_mods_setup.lua" 35 | tail -n 3 "$TMP/dedicated_server_mods_setup.lua" >"$TMP/dedicated_server_mods_setup.lua-tail" 36 | diff "$TMP/dedicated_server_mods_setup.lua-tail" "$FIXTURE_ROOT/dedicated_server_mods_setup.lua-tail" 37 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/modoverrides.lua "$TMP/modoverrides.lua" 38 | diff "$TMP/modoverrides.lua" "$FIXTURE_ROOT/modoverrides.lua" 39 | } 40 | 41 | @test "modoverrides.lua is not created by default" { 42 | docker run -d --name $CONTAINER $IMAGE 43 | wait_until_initializing 44 | run docker cp $CONTAINER:/var/lib/dsta/cluster/shard/modoverrides.lua "$TMP/modoverrides.lua" 45 | assert_failure 46 | } 47 | 48 | @test "Just set mods overrides doesn't create modoverrides.lua" { 49 | docker run -d -e MODS_OVERRIDES="xyz" --name $CONTAINER $IMAGE 50 | wait_until_initializing 51 | run docker cp $CONTAINER:/var/lib/dsta/cluster/shard/modoverrides.lua "$TMP/modoverrides.lua" 52 | assert_failure 53 | } 54 | -------------------------------------------------------------------------------- /tests/dsta-start.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "dontstarvetogether start" { 6 | docker run -d --name $CONTAINER $IMAGE dontstarvetogether start 7 | wait_until_loaded 8 | if [ -z "`docker ps -qf name=$container_id`" ]; then 9 | false 10 | fi 11 | run docker logs $CONTAINER 12 | refute_line --partial "Success! App '343050' already up to date." 13 | refute_line --partial "DownloadMods" 14 | } 15 | 16 | @test "dontstarvetogether start --update=none" { 17 | docker run -d --name $CONTAINER $IMAGE dontstarvetogether start --update=none 18 | wait_until_loaded 19 | if [ -z "`docker ps -qf name=$container_id`" ]; then 20 | false 21 | fi 22 | run docker logs $CONTAINER 23 | refute_line --partial "Success! App '343050' already up to date." 24 | refute_line --partial "DownloadMods" 25 | } 26 | 27 | @test "dontstarvetogether start --update=all" { 28 | docker run -d --name $CONTAINER $IMAGE dontstarvetogether start --update=all 29 | wait_until_loaded 30 | if [ -z "`docker ps -qf name=$container_id`" ]; then 31 | false 32 | fi 33 | run docker logs $CONTAINER 34 | assert_line --partial "Success! App '343050' already up to date." 35 | assert_line --partial "DownloadMods" 36 | } 37 | 38 | @test "dontstarvetogether start --update=game" { 39 | docker run -d --name $CONTAINER $IMAGE dontstarvetogether start --update=game 40 | wait_until_loaded 41 | if [ -z "`docker ps -qf name=$container_id`" ]; then 42 | false 43 | fi 44 | run docker logs $CONTAINER 45 | assert_line --partial "Success! App '343050' already up to date." 46 | refute_line --partial "DownloadMods" 47 | } 48 | 49 | @test "dontstarvetogether start --update=mods" { 50 | docker run -d --name $CONTAINER $IMAGE dontstarvetogether start --update=mods 51 | wait_until_loaded 52 | if [ -z "`docker ps -qf name=$container_id`" ]; then 53 | false 54 | fi 55 | run docker logs $CONTAINER 56 | refute_line --partial "Success! App '343050' already up to date." 57 | assert_line --partial "DownloadMods" 58 | } 59 | 60 | @test "dontstarvetogether start fails with unknow value in flag" { 61 | fixtures dsta-help 62 | 63 | run docker run --rm $IMAGE dontstarvetogether start --update=foo 64 | assert_failure 65 | cat "$FIXTURE_ROOT/start" | assert_output 66 | } 67 | 68 | @test "dontstarvetogether start fails with unknown flag" { 69 | fixtures dsta-help 70 | 71 | run docker run --rm $IMAGE dontstarvetogether start --game 72 | assert_failure 73 | cat "$FIXTURE_ROOT/start" | assert_output 74 | } 75 | 76 | @test "dontstarvetogether start fails with parameter" { 77 | fixtures dsta-help 78 | 79 | run docker run --rm $IMAGE dontstarvetogether start asd 80 | assert_failure 81 | cat "$FIXTURE_ROOT/start" | assert_output 82 | } 83 | -------------------------------------------------------------------------------- /tests/dsta-console.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "dontstarvetogether console redirect" { 6 | fixtures dsta-console 7 | 8 | docker run -d --name $CONTAINER $IMAGE 9 | docker exec -i $CONTAINER dontstarvetogether console <"$FIXTURE_ROOT/commands.txt" 10 | wait_until_loaded 11 | sleep 1 12 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 13 | 14 | grep -F "RemoteCommandInput: \"foo bar\"" "$TMP/server_log.txt" 15 | grep -F "RemoteCommandInput: \"bar\"" "$TMP/server_log.txt" 16 | } 17 | 18 | @test "dontstarvetogether console - redirect" { 19 | fixtures dsta-console 20 | 21 | docker run -d --name $CONTAINER $IMAGE 22 | docker exec -i $CONTAINER dontstarvetogether console - <"$FIXTURE_ROOT/commands.txt" 23 | wait_until_loaded 24 | sleep 1 25 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 26 | 27 | grep -F "RemoteCommandInput: \"foo bar\"" "$TMP/server_log.txt" 28 | grep -F "RemoteCommandInput: \"bar\"" "$TMP/server_log.txt" 29 | } 30 | 31 | @test "dontstarvetogether console command" { 32 | docker run -d --name $CONTAINER $IMAGE 33 | docker exec -i $CONTAINER dontstarvetogether console "asdf" 34 | wait_until_loaded 35 | sleep 1 36 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 37 | 38 | grep -F "RemoteCommandInput: \"asdf\"" "$TMP/server_log.txt" 39 | } 40 | 41 | @test "dontstarvetogether console command with redirect" { 42 | fixtures dsta-console 43 | 44 | docker run -d --name $CONTAINER $IMAGE 45 | docker exec -i $CONTAINER dontstarvetogether console "asdf" - "aaaaa" <"$FIXTURE_ROOT/commands.txt" 46 | wait_until_loaded 47 | sleep 1 48 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 49 | 50 | grep -F "RemoteCommandInput: \"asdf\"" "$TMP/server_log.txt" 51 | grep -F "RemoteCommandInput: \"foo bar\"" "$TMP/server_log.txt" 52 | grep -F "RemoteCommandInput: \"bar\"" "$TMP/server_log.txt" 53 | grep -F "RemoteCommandInput: \"aaaaa\"" "$TMP/server_log.txt" 54 | } 55 | 56 | @test "dontstarvetogether console command with redirect but not -" { 57 | fixtures dsta-console 58 | 59 | docker run -d --name $CONTAINER $IMAGE 60 | docker exec -i $CONTAINER dontstarvetogether console "asdf" "aaaaa" <"$FIXTURE_ROOT/commands.txt" 61 | wait_until_loaded 62 | sleep 1 63 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 64 | 65 | grep -F "RemoteCommandInput: \"asdf\"" "$TMP/server_log.txt" 66 | grep -F "RemoteCommandInput: \"aaaaa\"" "$TMP/server_log.txt" 67 | run grep -F "RemoteCommandInput: \"foo bar\"" "$TMP/server_log.txt" 68 | assert_failure 69 | run grep -F "RemoteCommandInput: \"bar\"" "$TMP/server_log.txt" 70 | assert_failure 71 | } 72 | -------------------------------------------------------------------------------- /docs/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Server-lifecycle is controlled via default [Docker Engine][engine-cli] or [Docker Compose][compose-cli] 4 | commands. Every time the server is restarted manually it performs an update-task to check if the 5 | game or installed mods provide updates and will download and install them. Thus it can take some 6 | minutes before the server shows up on the server-list. 7 | 8 | ## Basic Commands 9 | Basic commands to maintain the DST:A Dedicated Server. 10 | 11 | **Start the Server** 12 | Starts the server. On boot the game-server checks for updates and performs them. 13 | Docker Engine: 14 | `docker run -itd -p 10999:10999/udp -e TOKEN="server-token" yeetzone/dontstarvetogether` 15 | Docker Compose: 16 | `docker-compose up -d` 17 | 18 | **Stop the Server** 19 | Stops the server. 20 | Docker Engine: 21 | `docker stop ` 22 | Docker Compose: 23 | `docker-compose stop` 24 | 25 | **Restart the Server** 26 | Restarts the server. On boot the game-server checks for updates and performs them. 27 | Docker Engine: 28 | `docker restart ` 29 | Docker Compose: 30 | `docker-compose restart` 31 | 32 | **Remove the Server** 33 | Deletes the server. 34 | Docker Engine: 35 | `docker rm -f ` 36 | Docker Compose: 37 | `docker-compose rm -f` 38 | 39 | **Execute console command** 40 | Runs commands on the game's console. 41 | Docker Engine: 42 | `docker exec dst-server console "c_announce('Having fun?')"` 43 | 44 | **Print default log** 45 | Prints the server's default log. 46 | Docker Engine: 47 | `docker exec dst-server log` 48 | 49 | **Print chat log** 50 | Prints the server's chat log. 51 | Docker Engine: 52 | `docker exec dst-server log --chat` 53 | 54 | ## Advanced Commands 55 | More advanced commands to maintain the server-image and other stuff. 56 | 57 | **Update the Server-Image** 58 | Updates the [`yeetzone/dontstarvetogether`][image] image from the Docker Hub if updates are available. 59 | Docker Engine: 60 | `docker pull yeetzone/dontstarvetogether` 61 | Docker Compose: 62 | `docker-compose pull` 63 | 64 | **List all created servers/containers** 65 | Prints an overview of all available servers. 66 | Docker Engine: 67 | `docker ps -a` 68 | Docker Compose: 69 | `docker-compose ps` 70 | 71 | **Attach to the Server** 72 | Attaches the terminal to a running server which enables input of server [commands][reference-commands] 73 | and to observe the server output. To detach without stopping the server press `ctrl+p` followed by `ctrl+q`. 74 | Docker Engine: 75 | `docker attach ` 76 | 77 | **Execute custom command** 78 | Runs a custom command in the container. 79 | Docker Engine: 80 | `docker exec echo "Running my custom command."` 81 | 82 | [engine-cli]: https://docs.docker.com/engine/reference/commandline/ 83 | [compose-cli]: https://docs.docker.com/compose/reference/ 84 | [reference-commands]: http://dont-starve-game.wikia.com/wiki/Console/Don't_Starve_Together_Commands 85 | [image]: https://hub.docker.com/r/yeetzone/dontstarvetogether/ 86 | -------------------------------------------------------------------------------- /tests/boot-world.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "set LEVELDATA_OVERRIDES creates leveldataoverride.lua" { 6 | fixtures boot-world 7 | 8 | docker run -d -e LEVELDATA_OVERRIDES="foo" --name $CONTAINER $IMAGE 9 | wait_until_initializing 10 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 11 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo" 12 | } 13 | 14 | @test "no keep and not provide LEVELDATA_OVERRIDES doesn't create leveldataoverride.lua" { 15 | docker run -d --name $CONTAINER $IMAGE 16 | wait_until_initializing 17 | run docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 18 | assert_failure 19 | } 20 | 21 | @test "overwrite LEVELDATA_OVERRIDES" { 22 | fixtures boot-world 23 | VOLUME="test-keep-token" 24 | 25 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e LEVELDATA_OVERRIDES="foo" --name $CONTAINER $IMAGE 26 | wait_until_initializing 27 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 28 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo" 29 | docker rm -f $CONTAINER 30 | 31 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e LEVELDATA_OVERRIDES="foo2" --name $CONTAINER $IMAGE 32 | wait_until_initializing 33 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 34 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo2" 35 | } 36 | 37 | @test "keep world and set LEVELDATA_OVERRIDES" { 38 | fixtures boot-world 39 | VOLUME="test-keep-token" 40 | 41 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e LEVELDATA_OVERRIDES="foo" --name $CONTAINER $IMAGE 42 | wait_until_initializing 43 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 44 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo" 45 | docker rm -f $CONTAINER 46 | 47 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e LEVELDATA_OVERRIDES="foo2" --name $CONTAINER $IMAGE --keep=world 48 | wait_until_initializing 49 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 50 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo" 51 | } 52 | 53 | @test "keep world but not set LEVELDATA_OVERRIDES" { 54 | fixtures boot-world 55 | VOLUME="test-keep-token" 56 | 57 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e LEVELDATA_OVERRIDES="foo" --name $CONTAINER $IMAGE 58 | wait_until_initializing 59 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 60 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo" 61 | docker rm -f $CONTAINER 62 | 63 | docker run -d -v $VOLUME:/var/lib/dsta/cluster --name $CONTAINER $IMAGE --keep=world 64 | wait_until_initializing 65 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 66 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo" 67 | } 68 | 69 | @test "not keep world and not set LEVELDATA_OVERRIDES" { 70 | fixtures boot-world 71 | VOLUME="test-keep-token" 72 | 73 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e LEVELDATA_OVERRIDES="foo" --name $CONTAINER $IMAGE 74 | wait_until_initializing 75 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 76 | diff "$TMP/leveldataoverride.lua" "$FIXTURE_ROOT/foo" 77 | docker rm -f $CONTAINER 78 | 79 | docker run -d -v $VOLUME:/var/lib/dsta/cluster --name $CONTAINER $IMAGE 80 | wait_until_initializing 81 | run docker cp $CONTAINER:/var/lib/dsta/cluster/shard/leveldataoverride.lua "$TMP/leveldataoverride.lua" 82 | assert_failure 83 | } 84 | -------------------------------------------------------------------------------- /tests/boot-aux.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | source $BUILD/static/boot/functions.sh 5 | 6 | @test "Test validate_bool 1" { 7 | export FOO="" 8 | run validate_bool FOO 9 | assert_success 10 | } 11 | 12 | @test "Test validate_bool 2" { 13 | export FOO="true" 14 | run validate_bool FOO 15 | assert_success 16 | } 17 | 18 | @test "Test validate_bool 3" { 19 | export FOO="false" 20 | run validate_bool FOO 21 | assert_success 22 | } 23 | 24 | @test "Test validate_bool 4" { 25 | export FOO="bar" 26 | run validate_bool FOO 27 | assert_failure 28 | } 29 | 30 | @test "Test validate_int 1" { 31 | export FOO="" 32 | run validate_int FOO 1 10 33 | assert_success 34 | } 35 | 36 | @test "Test validate_int 2" { 37 | export FOO="1" 38 | run validate_int FOO 1 10 39 | assert_success 40 | } 41 | 42 | @test "Test validate_int 3" { 43 | export FOO="5" 44 | run validate_int FOO 1 10 45 | assert_success 46 | } 47 | 48 | @test "Test validate_int 4" { 49 | export FOO="10" 50 | run validate_int FOO 1 10 51 | assert_success 52 | } 53 | 54 | @test "Test validate_int 5" { 55 | export FOO="0" 56 | run validate_int FOO 1 10 57 | assert_failure 58 | } 59 | 60 | @test "Test validate_int 6" { 61 | export FOO="11" 62 | run validate_int FOO 1 10 63 | assert_failure 64 | } 65 | 66 | @test "Test validate_int 7" { 67 | export FOO="1100" 68 | run validate_int FOO 1 10 69 | assert_failure 70 | } 71 | 72 | @test "Test validate_port 1" { 73 | export FOO="" 74 | run validate_port FOO 75 | assert_success 76 | } 77 | 78 | @test "Test validate_port 2" { 79 | export FOO="1" 80 | run validate_port FOO 81 | assert_success 82 | } 83 | 84 | @test "Test validate_port 3" { 85 | export FOO="10999" 86 | run validate_port FOO 87 | assert_success 88 | } 89 | 90 | @test "Test validate_port 4" { 91 | export FOO="65535" 92 | run validate_port FOO 93 | assert_success 94 | } 95 | 96 | @test "Test validate_port 5" { 97 | export FOO="0" 98 | run validate_port FOO 99 | assert_failure 100 | } 101 | 102 | @test "Test validate_port 6" { 103 | export FOO="65536" 104 | run validate_port FOO 105 | assert_failure 106 | } 107 | 108 | @test "Test validate_port 7" { 109 | export FOO="655350" 110 | run validate_port FOO 111 | assert_failure 112 | } 113 | 114 | @test "Test validate_enum 1" { 115 | export FOO="" 116 | run validate_enum FOO a b c 117 | assert_success 118 | } 119 | 120 | @test "Test validate_enum 2" { 121 | export FOO="a" 122 | run validate_enum FOO a b c 123 | assert_success 124 | } 125 | 126 | @test "Test validate_enum 3" { 127 | export FOO="b" 128 | run validate_enum FOO a b c 129 | assert_success 130 | } 131 | 132 | @test "Test validate_enum 4" { 133 | export FOO="c" 134 | run validate_enum FOO a b c 135 | assert_success 136 | } 137 | 138 | @test "Test validate_enum 5" { 139 | export FOO="d" 140 | run validate_enum FOO a b c 141 | assert_failure 142 | } 143 | 144 | @test "Test validate_enum 6" { 145 | export FOO="1" 146 | run validate_enum FOO a b c 147 | assert_failure 148 | } 149 | 150 | @test "Test validate_enum 7" { 151 | export FOO="1" 152 | run validate_enum FOO 1 2 3 153 | assert_success 154 | } 155 | 156 | @test "Test validate_enum 8" { 157 | export FOO="2" 158 | run validate_enum FOO 1 2 3 159 | assert_success 160 | } 161 | 162 | @test "Test validate_enum 9" { 163 | export FOO="3" 164 | run validate_enum FOO 1 2 3 165 | assert_success 166 | } 167 | 168 | @test "Test validate_enum 10" { 169 | export FOO="4" 170 | run validate_enum FOO 1 2 3 171 | assert_failure 172 | } 173 | 174 | @test "Test validate_enum 11" { 175 | export FOO="a" 176 | run validate_enum FOO 1 2 3 177 | assert_failure 178 | } 179 | -------------------------------------------------------------------------------- /tests/boot-token.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "set token creates cluster_token.txt" { 6 | fixtures boot-token 7 | 8 | docker run -d -e TOKEN="token-1" --name $CONTAINER $IMAGE 9 | wait_until_initializing 10 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 11 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 12 | } 13 | 14 | @test "not keep and not provide token" { 15 | fixtures boot-token 16 | 17 | docker run -d --name $CONTAINER $IMAGE 18 | wait_until_initializing 19 | run docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 20 | assert_failure 21 | } 22 | 23 | @test "overwrite token" { 24 | fixtures boot-token 25 | 26 | VOLUME="test-keep-token" 27 | 28 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-1" --name $CONTAINER $IMAGE 29 | wait_until_initializing 30 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 31 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 32 | docker rm -f $CONTAINER 33 | 34 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-2" --name $CONTAINER $IMAGE 35 | wait_until_initializing 36 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 37 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token2" 38 | } 39 | 40 | @test "keep token" { 41 | fixtures boot-token 42 | 43 | VOLUME="test-keep-token" 44 | 45 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-1" --name $CONTAINER $IMAGE 46 | wait_until_initializing 47 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 48 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 49 | docker rm -f $CONTAINER 50 | 51 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-2" --name $CONTAINER $IMAGE --keep-configuration=token 52 | wait_until_initializing 53 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 54 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 55 | } 56 | 57 | @test "multiple keep values" { 58 | fixtures boot-token 59 | 60 | VOLUME="test-keep-token" 61 | 62 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-1" --name $CONTAINER $IMAGE 63 | wait_until_initializing 64 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 65 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 66 | docker rm -f $CONTAINER 67 | 68 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-2" --name $CONTAINER $IMAGE --keep-configuration=token,whitelist 69 | wait_until_initializing 70 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 71 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 72 | } 73 | 74 | @test "keep but not the token" { 75 | fixtures boot-token 76 | 77 | VOLUME="test-keep-token" 78 | 79 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-1" --name $CONTAINER $IMAGE 80 | wait_until_initializing 81 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 82 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 83 | docker rm -f $CONTAINER 84 | 85 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-2" --name $CONTAINER $IMAGE --keep-configuration=whitelist 86 | wait_until_initializing 87 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 88 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token2" 89 | } 90 | 91 | @test "not keep and not provide token" { 92 | fixtures boot-token 93 | 94 | VOLUME="test-keep-token" 95 | 96 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e TOKEN="token-1" --name $CONTAINER $IMAGE 97 | wait_until_initializing 98 | docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 99 | diff "$TMP/cluster_token.txt" "$FIXTURE_ROOT/token1" 100 | docker rm -f $CONTAINER 101 | 102 | docker run -d -v $VOLUME:/var/lib/dsta/cluster --name $CONTAINER $IMAGE 103 | wait_until_initializing 104 | run docker cp $CONTAINER:/var/lib/dsta/cluster/cluster_token.txt "$TMP/cluster_token.txt" 105 | assert_failure 106 | } 107 | -------------------------------------------------------------------------------- /tests/boot-lists.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | export VOLUME="test-keep-lists" 6 | 7 | ##### 8 | # Adminlist 9 | ##### 10 | @test "load ADMINLIST in correct format" { 11 | load_list_in_correct_format ADMINLIST adminlist 12 | } 13 | 14 | @test "set ADMINLIST creates file" { 15 | set_variable_creates_file ADMINLIST adminlist 16 | } 17 | 18 | @test "no set ADMINLIST does't create file" { 19 | no_set_varibale_doesnt_create_file ADMINLIST adminlist 20 | } 21 | 22 | @test "overwrite ADMINLIST" { 23 | overwrite_list ADMINLIST adminlist 24 | } 25 | 26 | @test "keep ADMINLIST" { 27 | keep_list ADMINLIST adminlist 28 | } 29 | 30 | @test "no keep and no provide ADMINLIST" { 31 | no_keep_and_not_provide ADMINLIST adminlist 32 | } 33 | 34 | ##### 35 | # Whitelist 36 | ##### 37 | @test "load WHITELIST in correct format" { 38 | load_list_in_correct_format WHITELIST whitelist 39 | } 40 | 41 | @test "set WHITELIST creates file" { 42 | set_variable_creates_file WHITELIST whitelist 43 | } 44 | 45 | @test "no set WHITELIST does't create file" { 46 | no_set_varibale_doesnt_create_file WHITELIST whitelist 47 | } 48 | 49 | @test "overwrite WHITELIST" { 50 | overwrite_list WHITELIST whitelist 51 | } 52 | 53 | @test "keep WHITELIST" { 54 | keep_list WHITELIST whitelist 55 | } 56 | 57 | @test "no keep and no provide WHITELIST" { 58 | no_keep_and_not_provide WHITELIST whitelist 59 | } 60 | 61 | ##### 62 | # Blocklist 63 | ##### 64 | @test "load BLOCKLIST in correct format" { 65 | load_list_in_correct_format BLOCKLIST blocklist 66 | } 67 | 68 | @test "set BLOCKLIST creates file" { 69 | set_variable_creates_file BLOCKLIST blocklist 70 | } 71 | 72 | @test "no set BLOCKLIST does't create file" { 73 | no_set_varibale_doesnt_create_file BLOCKLIST blocklist 74 | } 75 | 76 | @test "overwrite BLOCKLIST" { 77 | overwrite_list BLOCKLIST blocklist 78 | } 79 | 80 | @test "keep BLOCKLIST" { 81 | keep_list BLOCKLIST blocklist 82 | } 83 | 84 | @test "no keep and no provide BLOCKLIST" { 85 | no_keep_and_not_provide BLOCKLIST blocklist 86 | } 87 | 88 | load_list_in_correct_format() { 89 | fixtures boot-lists 90 | 91 | docker run -d -e $1="foo,bar,xy_:z" --name $CONTAINER $IMAGE 92 | wait_until_initializing 93 | docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 94 | diff "$TMP/$2.txt" "$FIXTURE_ROOT/list.txt" 95 | wait_until_loaded 96 | docker cp $CONTAINER:/var/lib/dsta/cluster/shard/server_log.txt "$TMP/server_log.txt" 97 | grep -E "$2\.txt.*\(Success\)" "$TMP/server_log.txt" 98 | } 99 | 100 | set_variable_creates_file() { 101 | fixtures boot-lists 102 | 103 | docker run -d -e $1="foo" --name $CONTAINER $IMAGE 104 | wait_until_initializing 105 | docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 106 | diff "$TMP/$2.txt" "$FIXTURE_ROOT/foo.txt" 107 | } 108 | 109 | no_set_varibale_doesnt_create_file() { 110 | docker run -d --name $CONTAINER $IMAGE 111 | wait_until_initializing 112 | run docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 113 | assert_failure 114 | } 115 | 116 | overwrite_list() { 117 | fixtures boot-lists 118 | 119 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e $1="foo" --name $CONTAINER $IMAGE 120 | wait_until_initializing 121 | docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 122 | diff "$TMP/$2.txt" "$FIXTURE_ROOT/foo.txt" 123 | docker rm -f $CONTAINER 124 | 125 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e $1="bar" --name $CONTAINER $IMAGE 126 | wait_until_initializing 127 | docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 128 | diff "$TMP/$2.txt" "$FIXTURE_ROOT/bar.txt" 129 | } 130 | 131 | keep_list() { 132 | fixtures boot-lists 133 | 134 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e $1="foo" --name $CONTAINER $IMAGE 135 | wait_until_initializing 136 | docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 137 | diff "$TMP/$2.txt" "$FIXTURE_ROOT/foo.txt" 138 | docker rm -f $CONTAINER 139 | 140 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e $1="bar" --name $CONTAINER $IMAGE --keep-configuration=$2 141 | wait_until_initializing 142 | docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 143 | diff "$TMP/$2.txt" "$FIXTURE_ROOT/foo.txt" 144 | } 145 | 146 | no_keep_and_not_provide() { 147 | fixtures boot-lists 148 | 149 | docker run -d -v $VOLUME:/var/lib/dsta/cluster -e $1="foo" --name $CONTAINER $IMAGE 150 | wait_until_initializing 151 | docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 152 | diff "$TMP/$2.txt" "$FIXTURE_ROOT/foo.txt" 153 | docker rm -f $CONTAINER 154 | 155 | docker run -d -v $VOLUME:/var/lib/dsta/cluster --name $CONTAINER $IMAGE 156 | wait_until_initializing 157 | run docker cp $CONTAINER:/var/lib/dsta/cluster/$2.txt "$TMP/$2.txt" 158 | assert_failure 159 | } 160 | -------------------------------------------------------------------------------- /tests/dsta-help.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | ##### 6 | # dst-server 7 | ##### 8 | @test "dst-server" { 9 | fixtures dsta-help 10 | 11 | run docker run --rm $IMAGE dst-server 12 | assert_failure 13 | cat "$FIXTURE_ROOT/dst-server" | assert_output 14 | } 15 | 16 | @test "dontstarvetogether help" { 17 | fixtures dsta-help 18 | 19 | run docker run --rm $IMAGE dontstarvetogether help 20 | assert_success 21 | cat "$FIXTURE_ROOT/dst-server" | assert_output 22 | } 23 | 24 | @test "dontstarvetogether --help" { 25 | fixtures dsta-help 26 | 27 | run docker run --rm $IMAGE dontstarvetogether --help 28 | assert_success 29 | cat "$FIXTURE_ROOT/dst-server" | assert_output 30 | } 31 | 32 | @test "dontstarvetogether with unknown argument" { 33 | fixtures dsta-help 34 | 35 | run docker run --rm $IMAGE dontstarvetogether foo 36 | assert_failure 37 | cat "$FIXTURE_ROOT/dst-server" | assert_output 38 | } 39 | 40 | @test "dontstarvetogether with unknown flag" { 41 | fixtures dsta-help 42 | 43 | run docker run --rm $IMAGE dontstarvetogether --foo 44 | assert_failure 45 | cat "$FIXTURE_ROOT/dst-server" | assert_output 46 | } 47 | 48 | ##### 49 | # dontstarvetogether start 50 | ##### 51 | @test "dontstarvetogether help start" { 52 | fixtures dsta-help 53 | 54 | run docker run --rm $IMAGE dontstarvetogether help start 55 | assert_success 56 | cat "$FIXTURE_ROOT/start" | assert_output 57 | } 58 | 59 | @test "dontstarvetogether --help start" { 60 | fixtures dsta-help 61 | 62 | run docker run --rm $IMAGE dontstarvetogether --help start 63 | assert_success 64 | cat "$FIXTURE_ROOT/start" | assert_output 65 | } 66 | 67 | @test "dontstarvetogether start --help" { 68 | fixtures dsta-help 69 | 70 | run docker run --rm $IMAGE dontstarvetogether start --help 71 | assert_success 72 | cat "$FIXTURE_ROOT/start" | assert_output 73 | } 74 | 75 | ##### 76 | # dontstarvetogether update 77 | ##### 78 | @test "dontstarvetogether help update" { 79 | fixtures dsta-help 80 | 81 | run docker run --rm $IMAGE dontstarvetogether help update 82 | assert_success 83 | cat "$FIXTURE_ROOT/update" | assert_output 84 | } 85 | 86 | @test "dontstarvetogether --help update" { 87 | fixtures dsta-help 88 | 89 | run docker run --rm $IMAGE dontstarvetogether --help update 90 | assert_success 91 | cat "$FIXTURE_ROOT/update" | assert_output 92 | } 93 | 94 | @test "dontstarvetogether update --help" { 95 | fixtures dsta-help 96 | 97 | run docker run --rm $IMAGE dontstarvetogether update --help 98 | assert_success 99 | cat "$FIXTURE_ROOT/update" | assert_output 100 | } 101 | 102 | ##### 103 | # dontstarvetogether log 104 | ##### 105 | @test "dontstarvetogether help log" { 106 | fixtures dsta-help 107 | 108 | run docker run --rm $IMAGE dontstarvetogether help log 109 | assert_success 110 | cat "$FIXTURE_ROOT/log" | assert_output 111 | } 112 | 113 | @test "dontstarvetogether --help log" { 114 | fixtures dsta-help 115 | 116 | run docker run --rm $IMAGE dontstarvetogether --help log 117 | assert_success 118 | cat "$FIXTURE_ROOT/log" | assert_output 119 | } 120 | 121 | @test "dontstarvetogether log --help" { 122 | fixtures dsta-help 123 | 124 | run docker run --rm $IMAGE dontstarvetogether log --help 125 | assert_success 126 | cat "$FIXTURE_ROOT/log" | assert_output 127 | } 128 | 129 | ##### 130 | # dontstarvetogether console 131 | ##### 132 | @test "dontstarvetogether help console" { 133 | fixtures dsta-help 134 | 135 | run docker run --rm $IMAGE dontstarvetogether help console 136 | assert_success 137 | cat "$FIXTURE_ROOT/console" | assert_output 138 | } 139 | 140 | @test "dontstarvetogether --help console" { 141 | fixtures dsta-help 142 | 143 | run docker run --rm $IMAGE dontstarvetogether --help console 144 | assert_success 145 | cat "$FIXTURE_ROOT/console" | assert_output 146 | } 147 | 148 | @test "dontstarvetogether console --help" { 149 | fixtures dsta-help 150 | 151 | run docker run --rm $IMAGE dontstarvetogether console --help 152 | assert_success 153 | cat "$FIXTURE_ROOT/console" | assert_output 154 | } 155 | 156 | ##### 157 | # dontstarvetogether version 158 | ##### 159 | @test "dontstarvetogether help version" { 160 | fixtures dsta-help 161 | 162 | run docker run --rm $IMAGE dontstarvetogether help version 163 | assert_success 164 | cat "$FIXTURE_ROOT/version" | assert_output 165 | } 166 | 167 | @test "dontstarvetogether --help version" { 168 | fixtures dsta-help 169 | 170 | run docker run --rm $IMAGE dontstarvetogether --help version 171 | assert_success 172 | cat "$FIXTURE_ROOT/version" | assert_output 173 | } 174 | 175 | @test "dontstarvetogether version --help" { 176 | fixtures dsta-help 177 | 178 | run docker run --rm $IMAGE dontstarvetogether version --help 179 | assert_success 180 | cat "$FIXTURE_ROOT/version" | assert_output 181 | } 182 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [next] 4 | 5 | ### Changed 6 | - Update base image to `dstacademy/steamcmd:0.4`. 7 | 8 | ## [0.8.0] 9 | 10 | ### Added 11 | - Introduce a `MODS` build-variable to support pre-built images with pre-installed mods. 12 | - Add support for the `leveldataoverride.lua` file via the `LEVELDATA_OVERRIDES` env-variable. 13 | - Configure the Docker `HEALTHCHECK` command running `dst-server version --check`. 14 | - Add a `keep-configuration` boot option to define how existing configuration files should be handled. 15 | 16 | ### Changed 17 | - Update the base-image to `dstacademy/steamcmd:0.3`. 18 | - Overwrite configuration files by default when starting a container. 19 | - Do not expose/configure a default port in the `Dockerfile` anymore. 20 | - Refactor tests to use `bats`. 21 | 22 | ### Removed 23 | - Remove the `WORLD_OVERRIDES` env-variable and `worldgenoverride.lua` file. 24 | - Remove support for the `WORLD_PRESET` env-variable in favor of `LEVELDATA_OVERRIDES`. 25 | 26 | ## [0.7.1] 27 | 28 | ### Added 29 | - Add the label `academy.dst.config.update` to the image for supporting auto-update strategies. 30 | 31 | ## [0.7.0] 32 | 33 | ### Added 34 | - Add `DST_BRANCH` and `DST_BRANCH_PASSWORD` build arguments to enable building beta-branch images. 35 | - Support providing options only on the Docker `CMD` command. 36 | - Document the `SERVER_PORT` configuration variable. 37 | 38 | ### Changed 39 | - Update the base-image to `dstacademy/steamcmd:0.2.1`. 40 | - Rename the repository name on GitHub and on Docker Hub. 41 | - Do not update the game and mods by default when starting a server/container. 42 | - Remove default value for `MAX_PLAYERS` to use the game's default value. 43 | - Remove default value for `GAME_MODE` to use the game's default value. 44 | - Remove default value for `VOTE_KICK_ENABLE` to use the game's default value. 45 | - Remove default value for `PAUSE_WHEN_EMPTY` to use the game's default value. 46 | - Optimize configuration creation script to handle some options better. 47 | 48 | ### Removed 49 | - Remove the `Vagrantfile`. 50 | 51 | ### Fixed 52 | - Update examples documentation to use correct configuration variables. 53 | - Do not overwrite mod configuration files when the game-files get updated. 54 | - Use the correct configuration variable for enabling/disabling vote-kicking. 55 | - Rename obsolete setting `offline_server` to `offline_cluster`. 56 | 57 | ## [0.6.0] 58 | 59 | ### Added 60 | - Add `BACKUP_LOG_COUNT` environment variable to configure backups for the log files. 61 | - Add `VOTE_ENABLE` environment variable for configuring voting. 62 | - Add `LANGUAGE` environment variable for setting the server's language. 63 | - Implement the `version` command. 64 | 65 | ### Changed 66 | - Update gosu to version 1.9. 67 | - Use our own `steamcmd` image as base-image. 68 | 69 | ### Removed 70 | - Remove the Vagrantfile. 71 | - Remove deprecated console arguments `console` and `backup_logs`. 72 | 73 | ## [0.5.0] 74 | 75 | ### Added 76 | - Add the `backup_logs` argument to create a backup of the old logs. 77 | - Implement validation for environment variables. 78 | - Add the environment variable `LAN_ONLY`. 79 | - Add the environment variable `MAX_SNAPSHOTS`. 80 | 81 | ### Changed 82 | - Adopt the new file structure based on clusters. 83 | - Move the token outside the settings files. 84 | - Set a default of `10888` for `SHARD_MASTER_PORT`. 85 | - Use `boxcutter/ubuntu1510` as the Vagrant base-box. 86 | - Change the Vagrant base-box name to be compatible with more providers. 87 | - Rename environment variable `SERVER_TOKEN` to `TOKEN`. 88 | - Rename environment variable `SERVER_NAME` to `NAME`. 89 | - Rename environment variable `SERVER_DESCRIPTION` to `DESCRIPTION`. 90 | - Rename environment variable `SERVER_NAME_PREFIX` to `NAME_PREFIX`. 91 | - Rename environment variable `SERVER_PASSWORD` to `PASSWORD`. 92 | - Rename environment variable `SERVER_INTENTION` to `INTENTION`. 93 | 94 | ### Removed 95 | - Remove environment variable `AUTOCOMPILER_ENABLE`. 96 | - Remove environment variable `CONNECTION_TIMEOUT`. 97 | - Remove environment variable `MODS_ENABLE`. 98 | - Remove environment variable `STEAM_CLOUD_DISABLE`. 99 | 100 | ## [0.4.0] 101 | 102 | ### Added 103 | - Add test cases to ensure code functionality. 104 | - Introduce sub-commands `start`, `update`, `log` and `console`. 105 | - Add `MODS_FORCE` variable to enable mods for development. 106 | 107 | ### Changed 108 | - Relocate DST files in the image. 109 | - Rename some environment variables for a more consistent naming scheme. 110 | - Set `AUTOCOMPILER_ENABLE` to `false` by default. 111 | 112 | ### Removed 113 | - Remove `UPDATE_ON_BOOT` environment variable. 114 | - Remove `WORKDIR` directive from the Dockerfile. 115 | 116 | ## [0.3.0] 117 | 118 | ### Added 119 | - Add `UPDATE_ON_BOOT` variable to configure update-behavior on boot. 120 | - Add `SERVER_NAME_PREFIX` variable to configure a prefix for the server's name. 121 | 122 | ### Changed 123 | - Generate a random server name if no name was configured. 124 | - Use the Debian base image instead of Ubuntu. 125 | - Relocate Steam and DST files in the image. 126 | - Create separate users for running Steam and the DST server. 127 | 128 | ### Removed 129 | - Remove the `CONF_DIR` environment variable. 130 | - Remove the `STORAGE_ROOT` environment variable. 131 | - Remove the `STEAM_APP_ID` environment variable. 132 | 133 | ## [0.2.0] 134 | 135 | ### Added 136 | - Make the null-renderer `conf_dir` argument configurable. 137 | - Make world generation configurable via the `WORLD_OVERRIDES` variable. 138 | - Make the Steam App-ID configurable via the `STEAM_APP_ID` variable. 139 | - Support volume-mounting. 140 | 141 | ### Changed 142 | - Improve the `docker-compose.yml` configuration. 143 | - Improve the entrypoint script. 144 | 145 | ## [0.1.0] 146 | 147 | ### Added 148 | - Initial release. 149 | 150 | [next]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.8.0...HEAD 151 | [0.8.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.7.1...v0.8.0 152 | [0.7.1]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.7.0...v0.7.1 153 | [0.7.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.6.0...v0.7.0 154 | [0.6.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.5.0...v0.6.0 155 | [0.5.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.4.0...v0.5.0 156 | [0.4.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.3.0...v0.4.0 157 | [0.3.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.2.0...v0.3.0 158 | [0.2.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/v0.1.0...v0.2.0 159 | [0.1.0]: https://github.com/dst-academy/docker-dontstarvetogether/compare/da19beb5479033b82dd6dc1200bb0cf6724904c3...v0.1.0 160 | -------------------------------------------------------------------------------- /tests/dependencies/bats-support/output.bash: -------------------------------------------------------------------------------- 1 | # 2 | # bats-support - Supporting library for Bats test helpers 3 | # 4 | # Written in 2016 by Zoltan Tombol 5 | # 6 | # To the extent possible under law, the author(s) have dedicated all 7 | # copyright and related and neighboring rights to this software to the 8 | # public domain worldwide. This software is distributed without any 9 | # warranty. 10 | # 11 | # You should have received a copy of the CC0 Public Domain Dedication 12 | # along with this software. If not, see 13 | # . 14 | # 15 | 16 | # 17 | # output.bash 18 | # ----------- 19 | # 20 | # Private functions implementing output formatting. Used by public 21 | # helper functions. 22 | # 23 | 24 | # Print a message to the standard error. When no parameters are 25 | # specified, the message is read from the standard input. 26 | # 27 | # Globals: 28 | # none 29 | # Arguments: 30 | # $@ - [=STDIN] message 31 | # Returns: 32 | # none 33 | # Inputs: 34 | # STDIN - [=$@] message 35 | # Outputs: 36 | # STDERR - message 37 | batslib_err() { 38 | { if (( $# > 0 )); then 39 | echo "$@" 40 | else 41 | cat - 42 | fi 43 | } >&2 44 | } 45 | 46 | # Count the number of lines in the given string. 47 | # 48 | # TODO(ztombol): Fix tests and remove this note after #93 is resolved! 49 | # NOTE: Due to a bug in Bats, `batslib_count_lines "$output"' does not 50 | # give the same result as `${#lines[@]}' when the output contains 51 | # empty lines. 52 | # See PR #93 (https://github.com/sstephenson/bats/pull/93). 53 | # 54 | # Globals: 55 | # none 56 | # Arguments: 57 | # $1 - string 58 | # Returns: 59 | # none 60 | # Outputs: 61 | # STDOUT - number of lines 62 | batslib_count_lines() { 63 | local -i n_lines=0 64 | local line 65 | while IFS='' read -r line || [[ -n $line ]]; do 66 | (( ++n_lines )) 67 | done < <(printf '%s' "$1") 68 | echo "$n_lines" 69 | } 70 | 71 | # Determine whether all strings are single-line. 72 | # 73 | # Globals: 74 | # none 75 | # Arguments: 76 | # $@ - strings 77 | # Returns: 78 | # 0 - all strings are single-line 79 | # 1 - otherwise 80 | batslib_is_single_line() { 81 | for string in "$@"; do 82 | (( $(batslib_count_lines "$string") > 1 )) && return 1 83 | done 84 | return 0 85 | } 86 | 87 | # Determine the length of the longest key that has a single-line value. 88 | # 89 | # This function is useful in determining the correct width of the key 90 | # column in two-column format when some keys may have multi-line values 91 | # and thus should be excluded. 92 | # 93 | # Globals: 94 | # none 95 | # Arguments: 96 | # $odd - key 97 | # $even - value of the previous key 98 | # Returns: 99 | # none 100 | # Outputs: 101 | # STDOUT - length of longest key 102 | batslib_get_max_single_line_key_width() { 103 | local -i max_len=-1 104 | while (( $# != 0 )); do 105 | local -i key_len="${#1}" 106 | batslib_is_single_line "$2" && (( key_len > max_len )) && max_len="$key_len" 107 | shift 2 108 | done 109 | echo "$max_len" 110 | } 111 | 112 | # Print key-value pairs in two-column format. 113 | # 114 | # Keys are displayed in the first column, and their corresponding values 115 | # in the second. To evenly line up values, the key column is fixed-width 116 | # and its width is specified with the first parameter (possibly computed 117 | # using `batslib_get_max_single_line_key_width'). 118 | # 119 | # Globals: 120 | # none 121 | # Arguments: 122 | # $1 - width of key column 123 | # $even - key 124 | # $odd - value of the previous key 125 | # Returns: 126 | # none 127 | # Outputs: 128 | # STDOUT - formatted key-value pairs 129 | batslib_print_kv_single() { 130 | local -ir col_width="$1"; shift 131 | while (( $# != 0 )); do 132 | printf '%-*s : %s\n' "$col_width" "$1" "$2" 133 | shift 2 134 | done 135 | } 136 | 137 | # Print key-value pairs in multi-line format. 138 | # 139 | # The key is displayed first with the number of lines of its 140 | # corresponding value in parenthesis. Next, starting on the next line, 141 | # the value is displayed. For better readability, it is recommended to 142 | # indent values using `batslib_prefix'. 143 | # 144 | # Globals: 145 | # none 146 | # Arguments: 147 | # $odd - key 148 | # $even - value of the previous key 149 | # Returns: 150 | # none 151 | # Outputs: 152 | # STDOUT - formatted key-value pairs 153 | batslib_print_kv_multi() { 154 | while (( $# != 0 )); do 155 | printf '%s (%d lines):\n' "$1" "$( batslib_count_lines "$2" )" 156 | printf '%s\n' "$2" 157 | shift 2 158 | done 159 | } 160 | 161 | # Print all key-value pairs in either two-column or multi-line format 162 | # depending on whether all values are single-line. 163 | # 164 | # If all values are single-line, print all pairs in two-column format 165 | # with the specified key column width (identical to using 166 | # `batslib_print_kv_single'). 167 | # 168 | # Otherwise, print all pairs in multi-line format after indenting values 169 | # with two spaces for readability (identical to using `batslib_prefix' 170 | # and `batslib_print_kv_multi') 171 | # 172 | # Globals: 173 | # none 174 | # Arguments: 175 | # $1 - width of key column (for two-column format) 176 | # $even - key 177 | # $odd - value of the previous key 178 | # Returns: 179 | # none 180 | # Outputs: 181 | # STDOUT - formatted key-value pairs 182 | batslib_print_kv_single_or_multi() { 183 | local -ir width="$1"; shift 184 | local -a pairs=( "$@" ) 185 | 186 | local -a values=() 187 | local -i i 188 | for (( i=1; i < ${#pairs[@]}; i+=2 )); do 189 | values+=( "${pairs[$i]}" ) 190 | done 191 | 192 | if batslib_is_single_line "${values[@]}"; then 193 | batslib_print_kv_single "$width" "${pairs[@]}" 194 | else 195 | local -i i 196 | for (( i=1; i < ${#pairs[@]}; i+=2 )); do 197 | pairs[$i]="$( batslib_prefix < <(printf '%s' "${pairs[$i]}") )" 198 | done 199 | batslib_print_kv_multi "${pairs[@]}" 200 | fi 201 | } 202 | 203 | # Prefix each line read from the standard input with the given string. 204 | # 205 | # Globals: 206 | # none 207 | # Arguments: 208 | # $1 - [= ] prefix string 209 | # Returns: 210 | # none 211 | # Inputs: 212 | # STDIN - lines 213 | # Outputs: 214 | # STDOUT - prefixed lines 215 | batslib_prefix() { 216 | local -r prefix="${1:- }" 217 | local line 218 | while IFS='' read -r line || [[ -n $line ]]; do 219 | printf '%s%s\n' "$prefix" "$line" 220 | done 221 | } 222 | 223 | # Mark select lines of the text read from the standard input by 224 | # overwriting their beginning with the given string. 225 | # 226 | # Usually the input is indented by a few spaces using `batslib_prefix' 227 | # first. 228 | # 229 | # Globals: 230 | # none 231 | # Arguments: 232 | # $1 - marking string 233 | # $@ - indices (zero-based) of lines to mark 234 | # Returns: 235 | # none 236 | # Inputs: 237 | # STDIN - lines 238 | # Outputs: 239 | # STDOUT - lines after marking 240 | batslib_mark() { 241 | local -r symbol="$1"; shift 242 | # Sort line numbers. 243 | set -- $( sort -nu <<< "$( printf '%d\n' "$@" )" ) 244 | 245 | local line 246 | local -i idx=0 247 | while IFS='' read -r line || [[ -n $line ]]; do 248 | if (( ${1:--1} == idx )); then 249 | printf '%s\n' "${symbol}${line:${#symbol}}" 250 | shift 251 | else 252 | printf '%s\n' "$line" 253 | fi 254 | (( ++idx )) 255 | done 256 | } 257 | 258 | # Enclose the input text in header and footer lines. 259 | # 260 | # The header contains the given string as title. The output is preceded 261 | # and followed by an additional newline to make it stand out more. 262 | # 263 | # Globals: 264 | # none 265 | # Arguments: 266 | # $1 - title 267 | # Returns: 268 | # none 269 | # Inputs: 270 | # STDIN - text 271 | # Outputs: 272 | # STDOUT - decorated text 273 | batslib_decorate() { 274 | echo 275 | echo "-- $1 --" 276 | cat - 277 | echo '--' 278 | echo 279 | } 280 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | Configuration of the server happens through environment variables, which can be passed to 4 | the `docker run` call via CLI directly or using a separate file. Optionally it's recommended 5 | to use `docker-compose` instead, which makes it easier to configure all environment variables. 6 | 7 | **Example**: 8 | ```sh 9 | docker run -itd -p 10999:10999/udp -e TOKEN="token" -e NAME="name" -e MAX_PLAYERS=10 yeetzone/dontstarvetogether 10 | ``` 11 | 12 | You can chain as many variables as you need. If you want to pass lots of them, it's easier and more 13 | convenient to create an `.env` file and pass it's path to the command. 14 | 15 | **Examples**: 16 | ```sh 17 | docker run -itd --env-file=.env yeetzone/dontstarvetogether 18 | ``` 19 | 20 | An `.env` file's contents must look like this and can hold all needed variables: 21 | ```ini 22 | TOKEN=token 23 | NAME=name 24 | MAX_PLAYERS=10 25 | ``` 26 | 27 | ## Environment Variables 28 | Environment variables can be used to customize certain settings of the server. Most of the 29 | available environment variables correspond to the `settings.ini` variables used by DST. 30 | 31 | **TOKEN** *required* 32 | Defines the server's token which is needed to run it. 33 | To [generate a token][howto-token] you need a copy of DST. 34 | - *string* 35 | 36 | **NAME** 37 | Sets the server's name. Shows up on the public server-list and in-game. 38 | Setting a custom server-name is not required but highly recommended. 39 | If no name is configured, a random name will be generated. 40 | - *string* *[default: *RANDOM*]* 41 | 42 | **NAME_PREFIX** 43 | Defines text to prepend to the server's name. 44 | - *string* 45 | 46 | **DESCRIPTION** 47 | Sets the server's description. Shows up on the public server-list and in-game. 48 | - *string* *[default: Powered by DST-Academy.]* 49 | 50 | **LANGUAGE** 51 | Sets the server's language. 52 | - en *[default]* 53 | - de 54 | - it 55 | - fr 56 | - es 57 | - pt 58 | - pl 59 | - ru 60 | - ko 61 | - zh 62 | - zhr 63 | 64 | **PASSWORD** 65 | Defines a server password so only players knowing the password can connect. 66 | - *string* 67 | 68 | **SERVER_PORT** 69 | Defines the port on which the game-server runs inside the Docker container. 70 | - *number* *[default: 10999]* 71 | 72 | **OFFLINE_ENABLE** 73 | Controls if the server is listed and accessible publicly. 74 | - true 75 | - false *[default]* 76 | 77 | **LAN_ONLY** 78 | Controls if the server is accessible from LAN only. 79 | - true 80 | - false *[default]* 81 | 82 | **MAX_PLAYERS** 83 | Sets the maximum number of allowed players to connect and play simultaneously. Heavily influences 84 | overall performance and gameplay-experience of the server. Be sure the hardware has enough power 85 | to provide a smooth experience for the configured number of players. 86 | - *number* *[default: 16]* 87 | 88 | **WHITELIST_SLOTS** 89 | Reserves player-slots for administrator and/or other players and adds up to the total number of 90 | players which can connect to the server. The sum of `MAX_PLAYERS` and `WHITELIST_SLOTS` determines 91 | how many players can connect to the server simultaneously. 92 | - *number* *[default: 0]* 93 | 94 | **ADMINLIST** 95 | Klei UserIDs to add to the adminlist.txt file. Gives players in the list Administrator priveliges. 96 | A players Klei UserID can be found my clicking "Account" in the bottom right of the main menu. 97 | - *CSV of Klei UserIDs* 98 | *Example:* `KU_G_cla3ou,KU_yDc5M7bx,KU_ad39dik` 99 | 100 | **WHITELIST** 101 | Klei UserIDs to add to the whitelist.txt file. 102 | A players Klei UserID can be found my clicking "Account" in the bottom right of the main menu. 103 | - *CSV of Klei UserIDs* 104 | *Example:* `KU_G_cla3ou,KU_yDc5M7bx,KU_ad39dik` 105 | 106 | **BLOCKLIST** 107 | Klei UserIDs to add to the blocklist.txt file. 108 | A players Klei UserID can be found my clicking "Account" in the bottom right of the main menu. 109 | - *CSV of Klei UserIDs* 110 | *Example:* `KU_G_cla3ou,KU_yDc5M7bx,KU_ad39dik` 111 | 112 | **PVP_ENABLE** 113 | Enables/disables PVP, which basically defines if players can attack each other. 114 | - true 115 | - false *[default]* 116 | 117 | **GAME_MODE** 118 | Defines which game-mode the server runs on. 119 | - survival *[default]* 120 | - endless 121 | - wilderness 122 | 123 | **INTENTION** 124 | Configures the server's gameplay-intention for players. The default value depends on **GAME_MODE**. 125 | - social 126 | - cooperative 127 | - competitive 128 | - madness 129 | 130 | **AUTOSAVER_ENABLE** 131 | Enables/disables automatic saving of the world's state after each in-game day. 132 | - true *[default]* 133 | - false 134 | 135 | **TICK_RATE** 136 | Sets the servers tick-rate. A higher tick-rate means a smoother 137 | gameplay but also more bandwidth is needed and more CPU-power is used. 138 | - 15 *[default]* 139 | - 20 140 | - 30 141 | - 60 142 | 143 | **VOTE_ENABLE** 144 | Enables/disables voting on the server. 145 | - true *[default]* 146 | - false 147 | 148 | **VOTE_KICK_ENABLE** 149 | Enables/disables the possibility to kick players via voting. 150 | - true *[default]* 151 | - false 152 | 153 | **PAUSE_WHEN_EMPTY** 154 | Enables/disables pausing of the world when no player is connected. 155 | - true 156 | - false *[default]* 157 | 158 | **STEAM_AUTHENTICATION_PORT** 159 | Sets the authentication port-number for Steam. Generally it's not needed to change this. 160 | - *number* *[default: 8766]* 161 | 162 | **STEAM_MASTER_SERVER_PORT** 163 | Sets the master-server port-number for Steam. Generally it's not needed to change this. 164 | - *number* *[default: 27016]* 165 | 166 | **STEAM_GROUP_ID** 167 | Relates the server to a corresponding steam-group. 168 | - *number* 169 | 170 | **STEAM_GROUP_ONLY** 171 | Enables/disables joining for steam-group members only. Non-group members won't be able to join. 172 | - true 173 | - false *[default]* 174 | 175 | **STEAM_GROUP_ADMINS** 176 | Enables/disables promoting steam-group officers to server administrators. 177 | - true 178 | - false *[default]* 179 | 180 | **CONSOLE_ENABLE** 181 | Disables/enables the ingame-console for administrators. 182 | - true *[default]* 183 | - false 184 | 185 | **SHARD_ENABLE** 186 | Enables/disables sharding for connecting multiple servers to one big world. 187 | - true 188 | - false *[default]* 189 | 190 | **SHARD_NAME** 191 | Sets a unique name for this server-shard. 192 | - *string* 193 | 194 | **SHARD_ID** 195 | Sets a unique shard ID for this server-shard. 196 | - *number* 197 | *Example:* `1` 198 | 199 | **SHARD_IS_MASTER** 200 | Defines whether this server is the main server. 201 | - true 202 | - false *[default]* 203 | 204 | **SHARD_MASTER_IP** 205 | Defines the master-server's IP address for slave-servers. 206 | - *ip-address* 207 | 208 | **SHARD_MASTER_PORT** 209 | Defines the master-server's port. This needs to be set to 210 | the same port for the master-server and all slave-servers. 211 | - *port-number* *[default: 10888]* 212 | 213 | **SHARD_BIND_IP** 214 | Configures the IP-address for which to allow incoming shard-connections from. 215 | Generally this should not be changed to work with Docker properly. 216 | - *ip-address* *[default: 0.0.0.0]* 217 | 218 | **SHARD_CLUSTER_KEY** 219 | Sets a unique and secret cluster key for validating incoming shard-connections. 220 | This needs to be the same for the master-server and all slave-servers. 221 | - *string* 222 | *Example:* `secret-and-equal-for-all-shards` 223 | 224 | **WORLD_PRESET** 225 | Sets a pre-defined preset in the `worldgenoverride.lua` file. 226 | - SURVIVAL_TOGETHER_CLASSIC 227 | - SURVIVAL_TOGETHER *[default]* 228 | - SURVIVAL_DEFAULT_PLUS 229 | - DST_CAVE 230 | - DST_CAVE_PLUS 231 | - COMPLETE_DARKNESS 232 | - MOD_MISSING 233 | 234 | **WORLD_CONFIGURATION** 235 | Sets the configuration for world generation. Basically it's just the content for the 236 | `worldgenoverride.lua` file. As this value can be pretty large it's recommended to put the 237 | configuration into a separate file and read it into the variable beforehand. 238 | - *string* 239 | 240 | **MODS** 241 | Defines mods to install and enable. 242 | - *string*, CSV of workshop IDs 243 | *Example:* `378160973,492173795,407705132` 244 | 245 | **MODS_CONFIGURATION** 246 | Sets the configuration for all mods. Basically it's just the content for the 247 | `modsoverrides.lua` file. As this value can be pretty large it's recommended to 248 | put the configuration into a separate file and read it into the variable beforehand. 249 | - *string* 250 | 251 | **BACKUP_LOG_COUNT** 252 | Enables the backup of server logs when rebooting the server. 253 | - *number* *[default: 0]* 254 | 255 | **ENCODE_USER_PATH** 256 | Enables path encoding to be compatible with case-insensitive operating systems. 257 | - true *[default]* 258 | - false 259 | 260 | [howto-token]: https://dontstarve.fandom.com/wiki/Guides/Don%E2%80%99t_Starve_Together_Dedicated_Servers#Server_Tokens 261 | -------------------------------------------------------------------------------- /tests/dependencies/bats-assert/assert.bash: -------------------------------------------------------------------------------- 1 | # 2 | # bats-assert - Common assertions for Bats 3 | # 4 | # Written in 2016 by Zoltan Tombol 5 | # 6 | # To the extent possible under law, the author(s) have dedicated all 7 | # copyright and related and neighboring rights to this software to the 8 | # public domain worldwide. This software is distributed without any 9 | # warranty. 10 | # 11 | # You should have received a copy of the CC0 Public Domain Dedication 12 | # along with this software. If not, see 13 | # . 14 | # 15 | 16 | # 17 | # assert.bash 18 | # ----------- 19 | # 20 | # Assertions are functions that perform a test and output relevant 21 | # information on failure to help debugging. They return 1 on failure 22 | # and 0 otherwise. 23 | # 24 | # All output is formatted for readability using the functions of 25 | # `output.bash' and sent to the standard error. 26 | # 27 | 28 | # Fail and display the expression if it evaluates to false. 29 | # 30 | # NOTE: The expression must be a simple command. Compound commands, such 31 | # as `[[', can be used only when executed with `bash -c'. 32 | # 33 | # Globals: 34 | # none 35 | # Arguments: 36 | # $1 - expression 37 | # Returns: 38 | # 0 - expression evaluates to TRUE 39 | # 1 - otherwise 40 | # Outputs: 41 | # STDERR - details, on failure 42 | assert() { 43 | if ! "$@"; then 44 | batslib_print_kv_single 10 'expression' "$*" \ 45 | | batslib_decorate 'assertion failed' \ 46 | | fail 47 | fi 48 | } 49 | 50 | # Fail and display the expression if it evaluates to true. 51 | # 52 | # NOTE: The expression must be a simple command. Compound commands, such 53 | # as `[[', can be used only when executed with `bash -c'. 54 | # 55 | # Globals: 56 | # none 57 | # Arguments: 58 | # $1 - expression 59 | # Returns: 60 | # 0 - expression evaluates to FALSE 61 | # 1 - otherwise 62 | # Outputs: 63 | # STDERR - details, on failure 64 | refute() { 65 | if "$@"; then 66 | batslib_print_kv_single 10 'expression' "$*" \ 67 | | batslib_decorate 'assertion succeeded, but it was expected to fail' \ 68 | | fail 69 | fi 70 | } 71 | 72 | # Fail and display details if the expected and actual values do not 73 | # equal. Details include both values. 74 | # 75 | # Globals: 76 | # none 77 | # Arguments: 78 | # $1 - actual value 79 | # $2 - expected value 80 | # Returns: 81 | # 0 - values equal 82 | # 1 - otherwise 83 | # Outputs: 84 | # STDERR - details, on failure 85 | assert_equal() { 86 | if [[ $1 != "$2" ]]; then 87 | batslib_print_kv_single_or_multi 8 \ 88 | 'expected' "$2" \ 89 | 'actual' "$1" \ 90 | | batslib_decorate 'values do not equal' \ 91 | | fail 92 | fi 93 | } 94 | 95 | # Fail and display details if `$status' is not 0. Details include 96 | # `$status' and `$output'. 97 | # 98 | # Globals: 99 | # status 100 | # output 101 | # Arguments: 102 | # none 103 | # Returns: 104 | # 0 - `$status' is 0 105 | # 1 - otherwise 106 | # Outputs: 107 | # STDERR - details, on failure 108 | assert_success() { 109 | if (( status != 0 )); then 110 | { local -ir width=6 111 | batslib_print_kv_single "$width" 'status' "$status" 112 | batslib_print_kv_single_or_multi "$width" 'output' "$output" 113 | } | batslib_decorate 'command failed' \ 114 | | fail 115 | fi 116 | } 117 | 118 | # Fail and display details if `$status' is 0. Details include `$output'. 119 | # 120 | # Optionally, when the expected status is specified, fail when it does 121 | # not equal `$status'. In this case, details include the expected and 122 | # actual status, and `$output'. 123 | # 124 | # Globals: 125 | # status 126 | # output 127 | # Arguments: 128 | # $1 - [opt] expected status 129 | # Returns: 130 | # 0 - `$status' is not 0, or 131 | # `$status' equals the expected status 132 | # 1 - otherwise 133 | # Outputs: 134 | # STDERR - details, on failure 135 | assert_failure() { 136 | (( $# > 0 )) && local -r expected="$1" 137 | if (( status == 0 )); then 138 | batslib_print_kv_single_or_multi 6 'output' "$output" \ 139 | | batslib_decorate 'command succeeded, but it was expected to fail' \ 140 | | fail 141 | elif (( $# > 0 )) && (( status != expected )); then 142 | { local -ir width=8 143 | batslib_print_kv_single "$width" \ 144 | 'expected' "$expected" \ 145 | 'actual' "$status" 146 | batslib_print_kv_single_or_multi "$width" \ 147 | 'output' "$output" 148 | } | batslib_decorate 'command failed as expected, but status differs' \ 149 | | fail 150 | fi 151 | } 152 | 153 | # Fail and display details if `$output' does not match the expected 154 | # output. The expected output can be specified either by the first 155 | # parameter or on the standard input. 156 | # 157 | # By default, literal matching is performed. The assertion fails if the 158 | # expected output does not equal `$output'. Details include both values. 159 | # 160 | # Option `--partial' enables partial matching. The assertion fails if 161 | # the expected substring cannot be found in `$output'. 162 | # 163 | # Option `--regexp' enables regular expression matching. The assertion 164 | # fails if the extended regular expression does not match `$output'. An 165 | # invalid regular expression causes an error to be displayed. 166 | # 167 | # It is an error to use partial and regular expression matching 168 | # simultaneously. 169 | # 170 | # Globals: 171 | # output 172 | # Options: 173 | # -p, --partial - partial matching 174 | # -e, --regexp - extended regular expression matching 175 | # Arguments: 176 | # $1 - [=STDIN] expected output 177 | # Returns: 178 | # 0 - expected matches the actual output 179 | # 1 - otherwise 180 | # Inputs: 181 | # STDIN - [=$1] expected output 182 | # Outputs: 183 | # STDERR - details, on failure 184 | # error message, on error 185 | assert_output() { 186 | local -i is_mode_partial=0 187 | local -i is_mode_regexp=0 188 | 189 | # Handle options. 190 | while (( $# > 0 )); do 191 | case "$1" in 192 | -p|--partial) is_mode_partial=1; shift ;; 193 | -e|--regexp) is_mode_regexp=1; shift ;; 194 | --) shift; break ;; 195 | *) break ;; 196 | esac 197 | done 198 | 199 | if (( is_mode_partial )) && (( is_mode_regexp )); then 200 | echo "\`--partial' and \`--regexp' are mutually exclusive" \ 201 | | batslib_decorate 'ERROR: assert_output' \ 202 | | fail 203 | return $? 204 | fi 205 | 206 | # Arguments. 207 | local expected 208 | (( $# == 0 )) && expected="$(cat -)" || expected="$1" 209 | 210 | # Matching. 211 | if (( is_mode_regexp )); then 212 | if [[ '' =~ $expected ]] || (( $? == 2 )); then 213 | echo "Invalid extended regular expression: \`$expected'" \ 214 | | batslib_decorate 'ERROR: assert_output' \ 215 | | fail 216 | return $? 217 | fi 218 | if ! [[ $output =~ $expected ]]; then 219 | batslib_print_kv_single_or_multi 6 \ 220 | 'regexp' "$expected" \ 221 | 'output' "$output" \ 222 | | batslib_decorate 'regular expression does not match output' \ 223 | | fail 224 | fi 225 | elif (( is_mode_partial )); then 226 | if [[ $output != *"$expected"* ]]; then 227 | batslib_print_kv_single_or_multi 9 \ 228 | 'substring' "$expected" \ 229 | 'output' "$output" \ 230 | | batslib_decorate 'output does not contain substring' \ 231 | | fail 232 | fi 233 | else 234 | if [[ $output != "$expected" ]]; then 235 | batslib_print_kv_single_or_multi 8 \ 236 | 'expected' "$expected" \ 237 | 'actual' "$output" \ 238 | | batslib_decorate 'output differs' \ 239 | | fail 240 | fi 241 | fi 242 | } 243 | 244 | # Fail and display details if `$output' matches the unexpected output. 245 | # The unexpected output can be specified either by the first parameter 246 | # or on the standard input. 247 | # 248 | # By default, literal matching is performed. The assertion fails if the 249 | # unexpected output equals `$output'. Details include `$output'. 250 | # 251 | # Option `--partial' enables partial matching. The assertion fails if 252 | # the unexpected substring is found in `$output'. The unexpected 253 | # substring is added to details. 254 | # 255 | # Option `--regexp' enables regular expression matching. The assertion 256 | # fails if the extended regular expression does matches `$output'. The 257 | # regular expression is added to details. An invalid regular expression 258 | # causes an error to be displayed. 259 | # 260 | # It is an error to use partial and regular expression matching 261 | # simultaneously. 262 | # 263 | # Globals: 264 | # output 265 | # Options: 266 | # -p, --partial - partial matching 267 | # -e, --regexp - extended regular expression matching 268 | # Arguments: 269 | # $1 - [=STDIN] unexpected output 270 | # Returns: 271 | # 0 - unexpected matches the actual output 272 | # 1 - otherwise 273 | # Inputs: 274 | # STDIN - [=$1] unexpected output 275 | # Outputs: 276 | # STDERR - details, on failure 277 | # error message, on error 278 | refute_output() { 279 | local -i is_mode_partial=0 280 | local -i is_mode_regexp=0 281 | 282 | # Handle options. 283 | while (( $# > 0 )); do 284 | case "$1" in 285 | -p|--partial) is_mode_partial=1; shift ;; 286 | -e|--regexp) is_mode_regexp=1; shift ;; 287 | --) shift; break ;; 288 | *) break ;; 289 | esac 290 | done 291 | 292 | if (( is_mode_partial )) && (( is_mode_regexp )); then 293 | echo "\`--partial' and \`--regexp' are mutually exclusive" \ 294 | | batslib_decorate 'ERROR: refute_output' \ 295 | | fail 296 | return $? 297 | fi 298 | 299 | # Arguments. 300 | local unexpected 301 | (( $# == 0 )) && unexpected="$(cat -)" || unexpected="$1" 302 | 303 | if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then 304 | echo "Invalid extended regular expression: \`$unexpected'" \ 305 | | batslib_decorate 'ERROR: refute_output' \ 306 | | fail 307 | return $? 308 | fi 309 | 310 | # Matching. 311 | if (( is_mode_regexp )); then 312 | if [[ $output =~ $unexpected ]] || (( $? == 0 )); then 313 | batslib_print_kv_single_or_multi 6 \ 314 | 'regexp' "$unexpected" \ 315 | 'output' "$output" \ 316 | | batslib_decorate 'regular expression should not match output' \ 317 | | fail 318 | fi 319 | elif (( is_mode_partial )); then 320 | if [[ $output == *"$unexpected"* ]]; then 321 | batslib_print_kv_single_or_multi 9 \ 322 | 'substring' "$unexpected" \ 323 | 'output' "$output" \ 324 | | batslib_decorate 'output should not contain substring' \ 325 | | fail 326 | fi 327 | else 328 | if [[ $output == "$unexpected" ]]; then 329 | batslib_print_kv_single_or_multi 6 \ 330 | 'output' "$output" \ 331 | | batslib_decorate 'output equals, but it was expected to differ' \ 332 | | fail 333 | fi 334 | fi 335 | } 336 | 337 | # Fail and display details if the expected line is not found in the 338 | # output (default) or in a specific line of it. 339 | # 340 | # By default, the entire output is searched for the expected line. The 341 | # expected line is matched against every element of `${lines[@]}'. If no 342 | # match is found, the assertion fails. Details include the expected line 343 | # and `${lines[@]}'. 344 | # 345 | # When `--index ' is specified, only the -th line is matched. 346 | # If the expected line does not match `${lines[]}', the assertion 347 | # fails. Details include and the compared lines. 348 | # 349 | # By default, literal matching is performed. A literal match fails if 350 | # the expected string does not equal the matched string. 351 | # 352 | # Option `--partial' enables partial matching. A partial match fails if 353 | # the expected substring is not found in the target string. 354 | # 355 | # Option `--regexp' enables regular expression matching. A regular 356 | # expression match fails if the extended regular expression does not 357 | # match the target string. An invalid regular expression causes an error 358 | # to be displayed. 359 | # 360 | # It is an error to use partial and regular expression matching 361 | # simultaneously. 362 | # 363 | # Mandatory arguments to long options are mandatory for short options 364 | # too. 365 | # 366 | # Globals: 367 | # output 368 | # lines 369 | # Options: 370 | # -n, --index - match the -th line 371 | # -p, --partial - partial matching 372 | # -e, --regexp - extended regular expression matching 373 | # Arguments: 374 | # $1 - expected line 375 | # Returns: 376 | # 0 - match found 377 | # 1 - otherwise 378 | # Outputs: 379 | # STDERR - details, on failure 380 | # error message, on error 381 | # FIXME(ztombol): Display `${lines[@]}' instead of `$output'! 382 | assert_line() { 383 | local -i is_match_line=0 384 | local -i is_mode_partial=0 385 | local -i is_mode_regexp=0 386 | 387 | # Handle options. 388 | while (( $# > 0 )); do 389 | case "$1" in 390 | -n|--index) 391 | if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then 392 | echo "\`--index' requires an integer argument: \`$2'" \ 393 | | batslib_decorate 'ERROR: assert_line' \ 394 | | fail 395 | return $? 396 | fi 397 | is_match_line=1 398 | local -ri idx="$2" 399 | shift 2 400 | ;; 401 | -p|--partial) is_mode_partial=1; shift ;; 402 | -e|--regexp) is_mode_regexp=1; shift ;; 403 | --) shift; break ;; 404 | *) break ;; 405 | esac 406 | done 407 | 408 | if (( is_mode_partial )) && (( is_mode_regexp )); then 409 | echo "\`--partial' and \`--regexp' are mutually exclusive" \ 410 | | batslib_decorate 'ERROR: assert_line' \ 411 | | fail 412 | return $? 413 | fi 414 | 415 | # Arguments. 416 | local -r expected="$1" 417 | 418 | if (( is_mode_regexp == 1 )) && [[ '' =~ $expected ]] || (( $? == 2 )); then 419 | echo "Invalid extended regular expression: \`$expected'" \ 420 | | batslib_decorate 'ERROR: assert_line' \ 421 | | fail 422 | return $? 423 | fi 424 | 425 | # Matching. 426 | if (( is_match_line )); then 427 | # Specific line. 428 | if (( is_mode_regexp )); then 429 | if ! [[ ${lines[$idx]} =~ $expected ]]; then 430 | batslib_print_kv_single 6 \ 431 | 'index' "$idx" \ 432 | 'regexp' "$expected" \ 433 | 'line' "${lines[$idx]}" \ 434 | | batslib_decorate 'regular expression does not match line' \ 435 | | fail 436 | fi 437 | elif (( is_mode_partial )); then 438 | if [[ ${lines[$idx]} != *"$expected"* ]]; then 439 | batslib_print_kv_single 9 \ 440 | 'index' "$idx" \ 441 | 'substring' "$expected" \ 442 | 'line' "${lines[$idx]}" \ 443 | | batslib_decorate 'line does not contain substring' \ 444 | | fail 445 | fi 446 | else 447 | if [[ ${lines[$idx]} != "$expected" ]]; then 448 | batslib_print_kv_single 8 \ 449 | 'index' "$idx" \ 450 | 'expected' "$expected" \ 451 | 'actual' "${lines[$idx]}" \ 452 | | batslib_decorate 'line differs' \ 453 | | fail 454 | fi 455 | fi 456 | else 457 | # Contained in output. 458 | if (( is_mode_regexp )); then 459 | local -i idx 460 | for (( idx = 0; idx < ${#lines[@]}; ++idx )); do 461 | [[ ${lines[$idx]} =~ $expected ]] && return 0 462 | done 463 | { local -ar single=( 464 | 'regexp' "$expected" 465 | ) 466 | local -ar may_be_multi=( 467 | 'output' "$output" 468 | ) 469 | local -ir width="$( batslib_get_max_single_line_key_width \ 470 | "${single[@]}" "${may_be_multi[@]}" )" 471 | batslib_print_kv_single "$width" "${single[@]}" 472 | batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" 473 | } | batslib_decorate 'no output line matches regular expression' \ 474 | | fail 475 | elif (( is_mode_partial )); then 476 | local -i idx 477 | for (( idx = 0; idx < ${#lines[@]}; ++idx )); do 478 | [[ ${lines[$idx]} == *"$expected"* ]] && return 0 479 | done 480 | { local -ar single=( 481 | 'substring' "$expected" 482 | ) 483 | local -ar may_be_multi=( 484 | 'output' "$output" 485 | ) 486 | local -ir width="$( batslib_get_max_single_line_key_width \ 487 | "${single[@]}" "${may_be_multi[@]}" )" 488 | batslib_print_kv_single "$width" "${single[@]}" 489 | batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" 490 | } | batslib_decorate 'no output line contains substring' \ 491 | | fail 492 | else 493 | local -i idx 494 | for (( idx = 0; idx < ${#lines[@]}; ++idx )); do 495 | [[ ${lines[$idx]} == "$expected" ]] && return 0 496 | done 497 | { local -ar single=( 498 | 'line' "$expected" 499 | ) 500 | local -ar may_be_multi=( 501 | 'output' "$output" 502 | ) 503 | local -ir width="$( batslib_get_max_single_line_key_width \ 504 | "${single[@]}" "${may_be_multi[@]}" )" 505 | batslib_print_kv_single "$width" "${single[@]}" 506 | batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" 507 | } | batslib_decorate 'output does not contain line' \ 508 | | fail 509 | fi 510 | fi 511 | } 512 | 513 | # Fail and display details if the unexpected line is found in the output 514 | # (default) or in a specific line of it. 515 | # 516 | # By default, the entire output is searched for the unexpected line. The 517 | # unexpected line is matched against every element of `${lines[@]}'. If 518 | # a match is found, the assertion fails. Details include the unexpected 519 | # line, the index of the first match and `${lines[@]}' with the matching 520 | # line highlighted if `${lines[@]}' is longer than one line. 521 | # 522 | # When `--index ' is specified, only the -th line is matched. 523 | # If the unexpected line matches `${lines[]}', the assertion fails. 524 | # Details include and the unexpected line. 525 | # 526 | # By default, literal matching is performed. A literal match fails if 527 | # the unexpected string does not equal the matched string. 528 | # 529 | # Option `--partial' enables partial matching. A partial match fails if 530 | # the unexpected substring is found in the target string. When used with 531 | # `--index ', the unexpected substring is also displayed on 532 | # failure. 533 | # 534 | # Option `--regexp' enables regular expression matching. A regular 535 | # expression match fails if the extended regular expression matches the 536 | # target string. When used with `--index ', the regular expression 537 | # is also displayed on failure. An invalid regular expression causes an 538 | # error to be displayed. 539 | # 540 | # It is an error to use partial and regular expression matching 541 | # simultaneously. 542 | # 543 | # Mandatory arguments to long options are mandatory for short options 544 | # too. 545 | # 546 | # Globals: 547 | # output 548 | # lines 549 | # Options: 550 | # -n, --index - match the -th line 551 | # -p, --partial - partial matching 552 | # -e, --regexp - extended regular expression matching 553 | # Arguments: 554 | # $1 - unexpected line 555 | # Returns: 556 | # 0 - match not found 557 | # 1 - otherwise 558 | # Outputs: 559 | # STDERR - details, on failure 560 | # error message, on error 561 | # FIXME(ztombol): Display `${lines[@]}' instead of `$output'! 562 | refute_line() { 563 | local -i is_match_line=0 564 | local -i is_mode_partial=0 565 | local -i is_mode_regexp=0 566 | 567 | # Handle options. 568 | while (( $# > 0 )); do 569 | case "$1" in 570 | -n|--index) 571 | if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then 572 | echo "\`--index' requires an integer argument: \`$2'" \ 573 | | batslib_decorate 'ERROR: refute_line' \ 574 | | fail 575 | return $? 576 | fi 577 | is_match_line=1 578 | local -ri idx="$2" 579 | shift 2 580 | ;; 581 | -p|--partial) is_mode_partial=1; shift ;; 582 | -e|--regexp) is_mode_regexp=1; shift ;; 583 | --) shift; break ;; 584 | *) break ;; 585 | esac 586 | done 587 | 588 | if (( is_mode_partial )) && (( is_mode_regexp )); then 589 | echo "\`--partial' and \`--regexp' are mutually exclusive" \ 590 | | batslib_decorate 'ERROR: refute_line' \ 591 | | fail 592 | return $? 593 | fi 594 | 595 | # Arguments. 596 | local -r unexpected="$1" 597 | 598 | if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then 599 | echo "Invalid extended regular expression: \`$unexpected'" \ 600 | | batslib_decorate 'ERROR: refute_line' \ 601 | | fail 602 | return $? 603 | fi 604 | 605 | # Matching. 606 | if (( is_match_line )); then 607 | # Specific line. 608 | if (( is_mode_regexp )); then 609 | if [[ ${lines[$idx]} =~ $unexpected ]] || (( $? == 0 )); then 610 | batslib_print_kv_single 6 \ 611 | 'index' "$idx" \ 612 | 'regexp' "$unexpected" \ 613 | 'line' "${lines[$idx]}" \ 614 | | batslib_decorate 'regular expression should not match line' \ 615 | | fail 616 | fi 617 | elif (( is_mode_partial )); then 618 | if [[ ${lines[$idx]} == *"$unexpected"* ]]; then 619 | batslib_print_kv_single 9 \ 620 | 'index' "$idx" \ 621 | 'substring' "$unexpected" \ 622 | 'line' "${lines[$idx]}" \ 623 | | batslib_decorate 'line should not contain substring' \ 624 | | fail 625 | fi 626 | else 627 | if [[ ${lines[$idx]} == "$unexpected" ]]; then 628 | batslib_print_kv_single 5 \ 629 | 'index' "$idx" \ 630 | 'line' "${lines[$idx]}" \ 631 | | batslib_decorate 'line should differ' \ 632 | | fail 633 | fi 634 | fi 635 | else 636 | # Line contained in output. 637 | if (( is_mode_regexp )); then 638 | local -i idx 639 | for (( idx = 0; idx < ${#lines[@]}; ++idx )); do 640 | if [[ ${lines[$idx]} =~ $unexpected ]]; then 641 | { local -ar single=( 642 | 'regexp' "$unexpected" 643 | 'index' "$idx" 644 | ) 645 | local -a may_be_multi=( 646 | 'output' "$output" 647 | ) 648 | local -ir width="$( batslib_get_max_single_line_key_width \ 649 | "${single[@]}" "${may_be_multi[@]}" )" 650 | batslib_print_kv_single "$width" "${single[@]}" 651 | if batslib_is_single_line "${may_be_multi[1]}"; then 652 | batslib_print_kv_single "$width" "${may_be_multi[@]}" 653 | else 654 | may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" \ 655 | | batslib_prefix \ 656 | | batslib_mark '>' "$idx" )" 657 | batslib_print_kv_multi "${may_be_multi[@]}" 658 | fi 659 | } | batslib_decorate 'no line should match the regular expression' \ 660 | | fail 661 | return $? 662 | fi 663 | done 664 | elif (( is_mode_partial )); then 665 | local -i idx 666 | for (( idx = 0; idx < ${#lines[@]}; ++idx )); do 667 | if [[ ${lines[$idx]} == *"$unexpected"* ]]; then 668 | { local -ar single=( 669 | 'substring' "$unexpected" 670 | 'index' "$idx" 671 | ) 672 | local -a may_be_multi=( 673 | 'output' "$output" 674 | ) 675 | local -ir width="$( batslib_get_max_single_line_key_width \ 676 | "${single[@]}" "${may_be_multi[@]}" )" 677 | batslib_print_kv_single "$width" "${single[@]}" 678 | if batslib_is_single_line "${may_be_multi[1]}"; then 679 | batslib_print_kv_single "$width" "${may_be_multi[@]}" 680 | else 681 | may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" \ 682 | | batslib_prefix \ 683 | | batslib_mark '>' "$idx" )" 684 | batslib_print_kv_multi "${may_be_multi[@]}" 685 | fi 686 | } | batslib_decorate 'no line should contain substring' \ 687 | | fail 688 | return $? 689 | fi 690 | done 691 | else 692 | local -i idx 693 | for (( idx = 0; idx < ${#lines[@]}; ++idx )); do 694 | if [[ ${lines[$idx]} == "$unexpected" ]]; then 695 | { local -ar single=( 696 | 'line' "$unexpected" 697 | 'index' "$idx" 698 | ) 699 | local -a may_be_multi=( 700 | 'output' "$output" 701 | ) 702 | local -ir width="$( batslib_get_max_single_line_key_width \ 703 | "${single[@]}" "${may_be_multi[@]}" )" 704 | batslib_print_kv_single "$width" "${single[@]}" 705 | if batslib_is_single_line "${may_be_multi[1]}"; then 706 | batslib_print_kv_single "$width" "${may_be_multi[@]}" 707 | else 708 | may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" \ 709 | | batslib_prefix \ 710 | | batslib_mark '>' "$idx" )" 711 | batslib_print_kv_multi "${may_be_multi[@]}" 712 | fi 713 | } | batslib_decorate 'line should not be in output' \ 714 | | fail 715 | return $? 716 | fi 717 | done 718 | fi 719 | fi 720 | } 721 | --------------------------------------------------------------------------------