feat(bash): startup-scripts reworked + bash scripts workflow integration (#22401)

This commit is contained in:
Yehonal 2025-07-01 15:35:54 +02:00 committed by GitHub
parent d3130f0d39
commit e1b2689c3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 4125 additions and 384 deletions

View File

@ -17,12 +17,14 @@
"workspaceFolder": "/azerothcore",
// Set *default* container specific settings.json values on container create.
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.shell.linux": null
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-vscode-remote.remote-containers",
"notskm.clang-tidy",
"xaver.clang-format",
"bbenoist.doxygen",
@ -32,8 +34,11 @@
"github.vscode-pull-request-github",
"eamodio.gitlens",
"cschlosser.doxdocgen",
"sanaajani.taskrunnercode"
],
"sanaajani.taskrunnercode",
"mads-hartmann.bash-ide-vscode"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

82
.github/workflows/dashboard-ci.yml vendored Normal file
View File

@ -0,0 +1,82 @@
name: Dashboard CI
description: |
This workflow runs tests and builds for the AzerothCore dashboard.
It includes testing of bash scripts and integration testing of the AzerothCore server.
Do not remove this if something is broken here and you don't know how to fix it, ping Yehonal instead.
on:
push:
branches:
- 'master'
pull_request:
types:
- opened
- reopened
- synchronize
workflow_dispatch:
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref }}, ${{ github.workflow }})
cancel-in-progress: true
env:
CONTINUOUS_INTEGRATION: true
MYSQL_ROOT_PASSWORD: root
jobs:
test-bash-scripts:
name: Test Bash Scripts
runs-on: ubuntu-24.04
if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Install requirements
run: |
sudo apt install -y bats
./acore.sh install-deps
- name: Run bash script tests for ${{ matrix.test-module }}
env:
TERM: xterm-256color
run: |
cd apps/test-framework
./run-tests.sh --tap
build-and-test:
name: Build and Integration Test
runs-on: ubuntu-24.04
if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Configure AzerothCore settings
run: |
# Create basic configuration
cp conf/dist/config.sh conf/config.sh
# Configure dashboard
sed -i 's/MTHREADS=.*/MTHREADS="4"/' conf/config.sh
- name: Run complete installation (deps, compile, database, client-data)
run: |
# This runs: install-deps, compile, database setup, client-data download
./acore.sh init
timeout-minutes: 120
- name: Test authserver dry-run
run: |
cd env/dist/bin
timeout 5m ./authserver -dry-run
continue-on-error: false
- name: Test worldserver dry-run
run: |
cd env/dist/bin
timeout 5m ./worldserver -dry-run
continue-on-error: false

View File

@ -10,6 +10,9 @@
"github.vscode-pull-request-github",
"eamodio.gitlens",
"cschlosser.doxdocgen",
"sanaajani.taskrunnercode"
"sanaajani.taskrunnercode",
"mads-hartmann.bash-ide-vscode",
"jetmartin.bats",
"ms-vscode.makefile-tools",
]
}

View File

@ -115,5 +115,12 @@
"xutility": "cpp",
"*.ipp": "cpp",
"resumable": "cpp"
}
},
"deno.enable": true,
"deno.path": "deps/deno/bin/deno",
"deno.lint": true,
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"C_Cpp.default.compilerPath": "/usr/bin/clang"
}

View File

@ -35,6 +35,9 @@ set(CMAKE_BUILD_WITH_INSTALL_RPATH 0)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH 1)
# Export compile commands for IDE support
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(AC_PATH_ROOT "${CMAKE_SOURCE_DIR}")
# set macro-directory

View File

@ -1,3 +1,7 @@
#!/usr/bin/env bash
# Set SUDO variable - one liner
SUDO=$([ "$EUID" -ne 0 ] && echo "sudo" || echo "")
function comp_clean() {
DIRTOCLEAN=${BUILDPATH:-var/build/obj}
@ -134,23 +138,21 @@ function comp_compile() {
mkdir -p "$confDir"
echo "Cmake install..."
sudo cmake --install . --config $CTYPE
$SUDO cmake --install . --config $CTYPE
popd >> /dev/null || exit 1
# set all aplications SUID bit
echo "Setting permissions on binary files"
find "$AC_BINPATH_FULL" -mindepth 1 -maxdepth 1 -type f -exec sudo chown root:root -- {} +
find "$AC_BINPATH_FULL" -mindepth 1 -maxdepth 1 -type f -exec sudo chmod u+s -- {} +
find "$AC_BINPATH_FULL" -mindepth 1 -maxdepth 1 -type f -exec $SUDO chown root:root -- {} +
find "$AC_BINPATH_FULL" -mindepth 1 -maxdepth 1 -type f -exec $SUDO chmod u+s -- {} +
if [[ -n "$DOCKER" ]]; then
[[ -f "$confDir/worldserver.conf.dist" ]] && \
cp -nv "$confDir/worldserver.conf.dist" "$confDir/worldserver.conf"
cp -v --update=none "$confDir/worldserver.conf.dist" "$confDir/worldserver.conf"
[[ -f "$confDir/authserver.conf.dist" ]] && \
cp -nv "$confDir/authserver.conf.dist" "$confDir/authserver.conf"
cp -v --update=none "$confDir/authserver.conf.dist" "$confDir/authserver.conf"
[[ -f "$confDir/dbimport.conf.dist" ]] && \
cp -nv "$confDir/dbimport.conf.dist" "$confDir/dbimport.conf"
fi
cp -v --update=none "$confDir/dbimport.conf.dist" "$confDir/dbimport.conf"
echo "Done"
;;

View File

@ -10,7 +10,7 @@ fi
function ac_on_after_build() {
# move the run engine
cp -rvf "$AC_PATH_APPS/startup-scripts/"* "$BINPATH"
cp -rvf "$AC_PATH_APPS/startup-scripts/src/"* "$BINPATH"
}
registerHooks "ON_AFTER_BUILD" ac_on_after_build

View File

@ -1,3 +1,8 @@
#!/usr/bin/env bash
# Set SUDO variable - one liner
SUDO=$([ "$EUID" -ne 0 ] && echo "sudo" || echo "")
function inst_configureOS() {
echo "Platform: $OSTYPE"
case "$OSTYPE" in
@ -45,6 +50,42 @@ function inst_configureOS() {
esac
}
# Use the data/sql/create/create_mysql.sql to initialize the database
function inst_dbCreate() {
echo "Creating database..."
# Attempt to connect with MYSQL_ROOT_PASSWORD
if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
if $SUDO mysql -u root -p"$MYSQL_ROOT_PASSWORD" < "$AC_PATH_ROOT/data/sql/create/create_mysql.sql" 2>/dev/null; then
echo "Database created successfully."
return 0
else
echo "Failed to connect with provided password, falling back to interactive mode..."
fi
fi
# In CI environments or when no password is set, try without password first
if [[ "$CONTINUOUS_INTEGRATION" == "true" ]]; then
echo "CI environment detected, attempting connection without password..."
if $SUDO mysql -u root < "$AC_PATH_ROOT/data/sql/create/create_mysql.sql" 2>/dev/null; then
echo "Database created successfully."
return 0
else
echo "Failed to connect without password, falling back to interactive mode..."
fi
fi
# Try with password (interactive mode)
echo "Please enter your sudo and your MySQL root password if prompted."
$SUDO mysql -u root -p < "$AC_PATH_ROOT/data/sql/create/create_mysql.sql"
if [ $? -ne 0 ]; then
echo "Database creation failed. Please check your MySQL server and credentials."
exit 1
fi
echo "Database created successfully."
}
function inst_updateRepo() {
cd "$AC_PATH_ROOT"
if [ ! -z $INSTALLER_PULL_FROM ]; then
@ -73,7 +114,8 @@ function inst_cleanCompile() {
function inst_allInOne() {
inst_configureOS
inst_compile
dbasm_import true true true
inst_dbCreate
inst_download_client_data
}
function inst_getVersionBranch() {
@ -215,7 +257,7 @@ function inst_module_remove {
function inst_simple_restarter {
echo "Running $1 ..."
bash "$AC_PATH_APPS/startup-scripts/simple-restarter" "$AC_BINPATH_FULL" "$1"
bash "$AC_PATH_APPS/startup-scripts/src/simple-restarter" "$AC_BINPATH_FULL" "$1"
echo
#disown -a
#jobs -l

View File

@ -2,8 +2,11 @@
CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Set SUDO variable - one liner
SUDO=$([ "$EUID" -ne 0 ] && echo "sudo" || echo "")
if ! command -v lsb_release &>/dev/null ; then
sudo apt-get install -y lsb-release
$SUDO apt-get install -y lsb-release
fi
DEBIAN_VERSION=$(lsb_release -sr)
@ -18,18 +21,18 @@ if [[ $DEBIAN_VERSION -lt $DEBIAN_VERSION_MIN ]]; then
echo "########## ########## ##########"
fi
sudo apt-get update -y
$SUDO apt-get update -y
sudo apt-get install -y gdbserver gdb unzip curl \
$SUDO apt-get install -y gdbserver gdb unzip curl \
libncurses-dev libreadline-dev clang g++ \
gcc git cmake make ccache \
libssl-dev libbz2-dev \
libboost-all-dev gnupg wget
libboost-all-dev gnupg wget jq screen tmux
VAR_PATH="$CURRENT_PATH/../../../../var"
# run noninteractive install for MYSQL 8.4 LTS
wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb -P "$VAR_PATH"
sudo DEBIAN_FRONTEND="noninteractive" dpkg -i "$VAR_PATH/mysql-apt-config_0.8.32-1_all.deb"
sudo apt-get update
sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server libmysqlclient-dev
DEBIAN_FRONTEND="noninteractive" $SUDO dpkg -i "$VAR_PATH/mysql-apt-config_0.8.32-1_all.deb"
$SUDO apt-get update
DEBIAN_FRONTEND="noninteractive" $SUDO apt-get install -y mysql-server libmysqlclient-dev

View File

@ -2,8 +2,11 @@
CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Set SUDO variable - one liner
SUDO=$([ "$EUID" -ne 0 ] && echo "sudo" || echo "")
if ! command -v lsb_release &>/dev/null ; then
sudo apt-get install -y lsb-release
$SUDO apt-get install -y lsb-release
fi
UBUNTU_VERSION=$(lsb_release -sr);
@ -23,28 +26,29 @@ case $UBUNTU_VERSION in
;;
esac
sudo apt update
$SUDO apt update
# shared deps
sudo DEBIAN_FRONTEND="noninteractive" \
apt-get -y install ccache clang cmake curl google-perftools libmysqlclient-dev make unzip
if [[ $CONTINUOUS_INTEGRATION || $DOCKER ]]; then
# TODO: update CI / Docker section for Ubuntu 22.04+
sudo add-apt-repository -y ppa:mhier/libboost-latest && sudo apt update && sudo apt-get -y install build-essential cmake-data \
libboost1.74-dev libbz2-dev libncurses5-dev libmysql++-dev libgoogle-perftools-dev libreadline6-dev libssl-dev libtool \
openssl zlib1g-dev
else
sudo DEBIAN_FRONTEND="noninteractive" \
apt-get install -y g++ gdb gdbserver gcc git \
libboost-all-dev libbz2-dev libncurses-dev libreadline-dev \
libssl-dev
DEBIAN_FRONTEND="noninteractive" $SUDO \
apt-get -y install ccache clang cmake curl google-perftools libmysqlclient-dev make unzip jq screen tmux \
libreadline-dev libncurses5-dev libncursesw5-dev libbz2-dev git gcc g++ libssl-dev \
libncurses-dev libboost-all-dev gdb gdbserver
VAR_PATH="$CURRENT_PATH/../../../../var"
# Do not install MySQL if we are in docker (It will be used a docker container instead) or we are explicitly skipping it.
if [[ $DOCKER != 1 && $SKIP_MYSQL_INSTALL != 1 ]]; then
# run noninteractive install for MYSQL 8.4 LTS
wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb -P "$VAR_PATH"
sudo DEBIAN_FRONTEND="noninteractive" dpkg -i "$VAR_PATH/mysql-apt-config_0.8.32-1_all.deb"
sudo apt-get update
sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server
DEBIAN_FRONTEND="noninteractive" $SUDO dpkg -i "$VAR_PATH/mysql-apt-config_0.8.32-1_all.deb"
$SUDO apt-get update
DEBIAN_FRONTEND="noninteractive" $SUDO apt-get install -y mysql-server
fi
if [[ $CONTINUOUS_INTEGRATION ]]; then
$SUDO systemctl enable mysql.service
$SUDO systemctl start mysql.service
fi

View File

@ -19,7 +19,9 @@ options=(
"run-worldserver (rw): execute a simple restarter for worldserver" # 11
"run-authserver (ra): execute a simple restarter for authserver" # 12
"docker (dr): Run docker tools" # 13
"quit: Exit from this menu" # 14
"version (v): Show AzerothCore version" # 14
"service-manager (sm): Run service manager to run authserver and worldserver in background" # 15
"quit: Exit from this menu" # 16
)
function _switch() {
@ -72,7 +74,11 @@ function _switch() {
printf "AzerothCore Rev. %s\n" "$ACORE_VERSION"
exit
;;
""|"quit"|"15")
""|"sm"|"service-manager"|"15")
bash "$AC_PATH_APPS/startup-scripts/src/service-manager.sh" "${@:2}"
exit
;;
""|"quit"|"16")
echo "Goodbye!"
exit
;;

View File

@ -0,0 +1,497 @@
# AzerothCore Startup Scripts
A comprehensive suite of scripts for managing AzerothCore server instances with advanced session management, automatic restart capabilities, and production-ready service management.
## 📋 Table of Contents
- [Overview](#overview)
- [Components](#components)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [Detailed Usage](#detailed-usage)
- [Multiple Realms Setup](#multiple-realms-setup)
- [Service Management](#service-management)
- [Troubleshooting](#troubleshooting)
## 🎯 Overview
The AzerothCore startup scripts provide multiple approaches to running server instances:
1. **Development/Testing**: Simple execution for debugging and development
2. **Production with Restarts**: Automatic restart on crashes with crash detection
3. **Background Services**: Production-ready service management with PM2 or systemd
4. **Session Management**: Interactive console access via tmux/screen
All scripts are integrated into the `acore.sh` dashboard for easy access.
### 📦 Automatic Deployment
**Important**: When you compile AzerothCore using the acore dashboard (`./acore.sh compiler build`), all startup scripts are automatically copied from `apps/startup-scripts/src/` to your `bin/` folder. This means:
- ✅ **Portable Deployment**: You can copy the entire `bin/` folder to different servers
- ✅ **Self-Contained**: All restart and service management tools travel with your binaries
- ✅ **No Additional Setup**: Scripts work immediately after deployment
- ✅ **Production Ready**: Deploy to production servers without needing the full source code
This makes it easy to deploy your compiled binaries along with the management scripts to production environments where you may not have the full AzerothCore source code.
## 🔧 Components
### Core Scripts
- **`run-engine`**: Advanced script with session management and configuration priority
- **`simple-restarter`**: Wrapper around starter with restart functionality (legacy compatibility)
- **`starter`**: Basic binary execution with optional GDB support
- **`service-manager.sh`**: Production service management with PM2/systemd
### Configuration
- **`conf.sh.dist`**: Default configuration template
- **`conf.sh`**: User configuration (create from .dist)
- **`gdb.conf`**: GDB debugging configuration
### Examples
- **`restarter-auth.sh`**: Auth server restart example
- **`restarter-world.sh`**: World server restart example
- **`starter-auth.sh`**: Auth server basic start example
- **`starter-world.sh`**: World server basic start example
## 🚀 Quick Start
### 1. Basic Server Start (Development)
```bash
# Start authserver directly
./starter /path/to/bin authserver
# Start worldserver with config
./starter /path/to/bin worldserver "" /path/to/worldserver.conf
```
### 2. Start with Auto-Restart
```bash
# Using simple-restarter (legacy)
./simple-restarter /path/to/bin authserver
# Using run-engine (recommended)
./run-engine restart authserver --bin-path /path/to/bin
```
### 3. Production Service Management
```bash
# Create and start a service
./service-manager.sh create auth authserver --bin-path /path/to/bin
# List all services
./service-manager.sh list
# Stop a service
./service-manager.sh stop auth
```
### 4. Using acore.sh Dashboard
```bash
# Interactive dashboard
./acore.sh
# Direct commands
./acore.sh run-authserver # Start authserver with restart
./acore.sh run-worldserver # Start worldserver with restart
./acore.sh service-manager # Access service manager
```
## ⚙️ Configuration
### Configuration Priority (Highest to Lowest)
1. **`conf.sh`** - User configuration file
2. **Command line arguments** - Runtime parameters
3. **Environment variables** - `RUN_ENGINE_*` variables
4. **`conf.sh.dist`** - Default configuration
### Creating Configuration
```bash
# Copy default configuration
cp scripts/conf.sh.dist scripts/conf.sh
# Edit your configuration
nano scripts/conf.sh
```
### Key Configuration Options
```bash
# Binary settings
export BINPATH="/path/to/azerothcore/bin"
export SERVERBIN="worldserver" # or "authserver"
export CONFIG="/path/to/worldserver.conf"
# Session management
export SESSION_MANAGER="tmux" # none|auto|tmux|screen
export SESSION_NAME="ac-world"
# Debugging
export GDB_ENABLED="1" # 0 or 1
export GDB="/path/to/gdb.conf"
# Logging
export LOGS_PATH="/path/to/logs"
export CRASHES_PATH="/path/to/crashes"
export LOG_PREFIX_NAME="realm1"
```
## 📖 Detailed Usage
### 1. Run Engine
The `run-engine` is the most advanced script with multiple operation modes:
#### Basic Execution
```bash
# Start server once
./run-engine start worldserver --bin-path /path/to/bin
# Start with configuration file
./run-engine start worldserver --config ./conf-world.sh
# Start with specific server config
./run-engine start worldserver --server-config /path/to/worldserver.conf
```
#### Restart Mode
```bash
# Automatic restart on crash
./run-engine restart worldserver --bin-path /path/to/bin
# Restart with session management
./run-engine restart worldserver --session-manager tmux
```
#### Session Management
```bash
# Start in tmux session
./run-engine start worldserver --session-manager tmux
# Attach to existing session
tmux attach-session -t worldserver
# Start in screen session
./run-engine start worldserver --session-manager screen
# Attach to screen session
screen -r worldserver
```
#### Configuration Options
```bash
./run-engine restart worldserver \
--bin-path /path/to/bin \
--server-config /path/to/worldserver.conf \
--session-manager tmux \
--gdb-enabled 1 \
--logs-path /path/to/logs \
--crashes-path /path/to/crashes
```
### 2. Simple Restarter
Legacy-compatible wrapper with restart functionality:
```bash
# Basic restart
./simple-restarter /path/to/bin worldserver
# With full parameters
./simple-restarter \
/path/to/bin \
worldserver \
./gdb.conf \
/path/to/worldserver.conf \
/path/to/system.log \
/path/to/system.err \
1 \
/path/to/crashes
```
**Parameters:**
1. Binary path (required)
2. Binary name (required)
3. GDB configuration file (optional)
4. Server configuration file (optional)
5. System log file (optional)
6. System error file (optional)
7. GDB enabled flag (0/1, optional)
8. Crashes directory path (optional)
### 3. Starter
Basic execution script without restart functionality:
```bash
# Simple start
./starter /path/to/bin worldserver
# With GDB debugging
./starter /path/to/bin worldserver ./gdb.conf /path/to/worldserver.conf "" "" 1
```
### 4. Service Manager
Production-ready service management:
#### Creating Services
```bash
# Auto-detect provider (PM2 or systemd)
./service-manager.sh create auth authserver --bin-path /path/to/bin
# Force PM2
./service-manager.sh create world worldserver --provider pm2 --bin-path /path/to/bin
# Force systemd
./service-manager.sh create world worldserver --provider systemd --bin-path /path/to/bin
```
#### Service Operations
```bash
# Start/stop services
./service-manager.sh start auth
./service-manager.sh stop world
./service-manager.sh restart auth
# View logs
./service-manager.sh logs world
./service-manager.sh logs world --follow
# Attach to console (interactive)
./service-manager.sh attach world
# List services
./service-manager.sh list
./service-manager.sh list pm2
./service-manager.sh list systemd
# Delete service
./service-manager.sh delete auth
```
#### Service Configuration
```bash
# Update service settings
./service-manager.sh update world --session-manager screen --gdb-enabled 1
# Edit configuration
./service-manager.sh edit world
```
## 🌍 Multiple Realms Setup
### Method 1: Using Service Manager (Recommended)
```bash
# Create multiple world server instances
./service-manager.sh create world1 worldserver \
--bin-path /path/to/bin \
--server-config /path/to/worldserver-realm1.conf
./service-manager.sh create world2 worldserver \
--bin-path /path/to/bin \
--server-config /path/to/worldserver-realm2.conf
# Single auth server for all realms
./service-manager.sh create auth authserver \
--bin-path /path/to/bin \
--server-config /path/to/authserver.conf
```
### Method 2: Using Run Engine with Different Configurations
Create separate configuration files for each realm:
**conf-realm1.sh:**
```bash
export BINPATH="/path/to/bin"
export SERVERBIN="worldserver"
export CONFIG="/path/to/worldserver-realm1.conf"
export SESSION_NAME="ac-realm1"
export LOG_PREFIX_NAME="realm1"
export LOGS_PATH="/path/to/logs/realm1"
```
**conf-realm2.sh:**
```bash
export BINPATH="/path/to/bin"
export SERVERBIN="worldserver"
export CONFIG="/path/to/worldserver-realm2.conf"
export SESSION_NAME="ac-realm2"
export LOG_PREFIX_NAME="realm2"
export LOGS_PATH="/path/to/logs/realm2"
```
Start each realm:
```bash
./run-engine restart worldserver --config ./conf-realm1.sh
./run-engine restart worldserver --config ./conf-realm2.sh
```
### Method 3: Using Examples with Custom Configurations
Copy and modify the example scripts:
```bash
# Copy examples
cp examples/restarter-world.sh restarter-realm1.sh
cp examples/restarter-world.sh restarter-realm2.sh
# Edit each script to point to different configuration files
# Then run:
./restarter-realm1.sh
./restarter-realm2.sh
```
## 🛠️ Service Management
### PM2 Services
When using PM2 as the service provider:
```bash
# PM2-specific commands
pm2 list # List all PM2 processes
pm2 logs auth # View logs
pm2 monit # Real-time monitoring
pm2 restart auth # Restart service
pm2 delete auth # Remove service
# Save PM2 configuration
pm2 save
pm2 startup # Auto-start on boot
```
### Systemd Services
When using systemd as the service provider:
```bash
# Systemd commands
systemctl --user status acore-auth # Check status
systemctl --user logs acore-auth # View logs
systemctl --user restart acore-auth # Restart
systemctl --user enable acore-auth # Enable auto-start
# For system services (requires sudo)
sudo systemctl status acore-auth
sudo systemctl enable acore-auth
```
### Session Management in Services
Services can be configured with session managers for interactive access:
```bash
# Create service with tmux
./service-manager.sh create world worldserver \
--bin-path /path/to/bin \
--session-manager tmux
# Attach to the session
./service-manager.sh attach world
# or directly:
tmux attach-session -t worldserver
```
## 🎮 Integration with acore.sh Dashboard
The startup scripts are fully integrated into the AzerothCore dashboard:
### Direct Commands
```bash
# Run servers with simple restart (development/testing)
./acore.sh run-worldserver # Option 11 or 'rw'
./acore.sh run-authserver # Option 12 or 'ra'
# Access service manager (production)
./acore.sh service-manager # Option 15 or 'sm'
# Examples:
./acore.sh rw # Quick worldserver start
./acore.sh ra # Quick authserver start
./acore.sh sm create auth authserver --bin-path /path/to/bin
```
### What Happens Behind the Scenes
- **run-worldserver/run-authserver**: Calls `simple-restarter` with appropriate binary
- **service-manager**: Provides full access to the service management interface
- Scripts automatically use the correct binary path from your build configuration
## 🐛 Troubleshooting
### Common Issues
#### 1. Binary Not Found
```bash
Error: Binary '/path/to/bin/worldserver' not found
```
**Solution**: Check binary path and ensure servers are compiled
```bash
# Check if binary exists
ls -la /path/to/bin/worldserver
# Compile if needed
./acore.sh compiler build
```
#### 2. Configuration File Issues
```bash
Error: Configuration file not found
```
**Solution**: Create configuration from template
```bash
cp scripts/conf.sh.dist scripts/conf.sh
# Edit conf.sh with correct paths
```
#### 3. Session Manager Not Available
```bash
Warning: tmux not found, falling back to direct execution
```
**Solution**: Install required session manager
```bash
# Ubuntu/Debian
sudo apt install tmux screen
# CentOS/RHEL
sudo yum install tmux screen
```
#### 4. Permission Issues (systemd)
```bash
Failed to create systemd service
```
**Solution**: Check user permissions or use --system flag
```bash
# For user services (no sudo required)
./service-manager.sh create auth authserver --bin-path /path/to/bin
# For system services (requires sudo)
./service-manager.sh create auth authserver --bin-path /path/to/bin --system
```
#### 5. PM2 Not Found
```bash
Error: PM2 is not installed
```
**Solution**: Install PM2
```bash
npm install -g pm2
# or
sudo npm install -g pm2
```

View File

@ -1,50 +0,0 @@
# enable/disable GDB execution
export GDB_ENABLED=0
# [optional] gdb file
# default: gdb.conf
export GDB=""
# directory where binary are stored
export BINPATH=""
# Put here the pid you configured on your worldserver.conf file
# needed when GDB_ENABLED=1
export SERVERPID=""
# path to configuration file (including the file name)
# ex: /home/user/azerothcore/etc/worldserver.conf
export CONFIG=""
# path of log files
# needed by restarter to store its logs
export LOGS_PATH="";
# exec name
# ex: worldserver
export SERVERBIN=""
# prefix name for log files
# to avoid collision with other restarters
export LOG_PREFIX_NAME=""
# [optional] name of screen service
# if no specified, screen util won't be used
export SCREEN_NAME=""
# [optional] overwrite default screen options: -A -m -d -S
# WARNING: if you are running it under a systemd service
# please do not remove -m -d arguments from screen if are you using it,
# or keep WITH_CONSOLE=0 .
# otherwise the journald-logging system will take 100% of CPU slowing
# down the whole machine. It's because a systemd service should have
# low console output.
export SCREEN_OPTIONS=""
# enable/disable it to show the output
# within console, if disable the output will be redirect to
# logging files
#
export WITH_CONSOLE=0

View File

@ -1,14 +0,0 @@
#!/usr/bin/env bash
PATH_RUNENGINE="./"
source "$PATH_RUNENGINE/run-engine"
# you must create your conf
# copying conf.sh.dist
# and renaming as below
source "./conf-auth.sh"
restarter

View File

@ -1,14 +0,0 @@
#!/usr/bin/env bash
PATH_RUNENGINE="./"
source "$PATH_RUNENGINE/run-engine"
# you must create your conf
# copying conf.sh.dist
# and renaming as below
source "./conf-world.sh"
restarter

View File

@ -1,13 +0,0 @@
#!/usr/bin/env bash
PATH_RUNENGINE="./"
source "$PATH_RUNENGINE/run-engine"
# you must create your conf
# copying conf.sh.dist
# and renaming as below
source "./conf-auth.sh"
starter

View File

@ -1,14 +0,0 @@
#!/usr/bin/env bash
PATH_RUNENGINE="./"
source "$PATH_RUNENGINE/run-engine"
# you must create your conf
# copying conf.sh.dist
# and renaming as below
source "./conf-world.sh"
starter

View File

@ -1,115 +0,0 @@
export RUN_ENGINE_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# load default conf
if [ -e "$RUN_ENGINE_PATH/conf.dist" ]; then
source "$RUN_ENGINE_PATH/conf.sh.dist"
fi
function finish {
if [ ! -z "$SCREEN_NAME" ]; then
screen -X -S "$SCREEN_NAME" quit
fi
}
# disabled for now, but could be useful if we want
# shutdown the process if restarter crashes for some reason
# trap finish EXIT
function configureFiles() {
TRACE_BEGIN_STRING="SIGSEGV"
TRACE_FILE="$LOGS_PATH/"$LOG_PREFIX_NAME"_trace.log"
ERR_FILE="$LOGS_PATH/"$LOG_PREFIX_NAME"_error.log"
SYSLOG="$LOGS_PATH/"$LOG_PREFIX_NAME"_system.log"
SYSERR="$LOGS_PATH/"$LOG_PREFIX_NAME"_system.err"
LINKS_FILE="$LOGS_PATH/"$LOG_PREFIX_NAME"_crash_links.link"
}
function checkStatus() {
local ret=1
# wipe do : destroy old screens + ls
#screen -wipe
#if screen -ls $1 | grep -q "No Sockets found"
#then
# return 0
#fi
local gdbres=$(pgrep -f "gdb -x $GDB --batch $SERVERBIN")
if [[ $GDB_ENABLED -eq 1 && ! -z $gdbres ]]; then
return 1
fi
#
# This is a specific check for Azeroth Core in case of screen failure
# It is possible since same binary file cannot be launched with same configuration file
# This is an extra check
#
local binres=$(pgrep -f "$SERVERBIN -c $CONFIG")
if [ ! -z $binres ]; then
return 1
fi
return 0
}
function run() {
echo $1
if [ ! -z $1 ]; then
local OPTIONS="-A -m -d -S"
if [ ! -z "$SCREEN_OPTIONS" ]; then
OPTIONS=$SCREEN_OPTIONS
fi
echo "> Starting with screen ( screen $OPTIONS )"
screen $OPTIONS $1 "$RUN_ENGINE_PATH/starter" $2 $3 "$4" "$5" "$6" $7 "$BINPATH/crashes"
else
$RUN_ENGINE_PATH/starter $2 $3 "$4" "$5" "$6" $7 "$BINPATH/crashes"
fi
}
function starter() {
cd $BINPATH
mkdir -p "$LOGS_PATH"
mkdir -p "$BINPATH"/crashes
configureFiles
run "$SCREEN_NAME" "$SERVERBIN" "$GDB" "$CONFIG" "$SYSLOG" "$SYSERR" "$GDB_ENABLED"
}
function restarter() {
cd $BINPATH
mkdir -p "$LOGS_PATH"
mkdir -p "$BINPATH"/crashes
configureFiles
if [ ! -f $TRACE_FILE ]; then
touch $TRACE_FILE
fi
while :
do
if checkStatus $SCREEN_NAME; then
DATE=$(date)
echo "Restarting $SCREEN_NAME Core blizz($DATE)"
if [ $GDB_ENABLED -eq 1 ]; then
echo "GDB enabled"
grep -B 10 -A 1800 "$TRACE_BEGIN_STRING" "$SYSLOG" >> "$TRACE_FILE"
cat "$SYSERR" > "$ERR_FILE"
run "$SCREEN_NAME" "$SERVERBIN" "$GDB" "$CONFIG" "$SYSLOG" "$SYSERR" 1
fi
if [ $GDB_ENABLED -eq 0 ]; then
echo "GDB disabled"
run "$SCREEN_NAME" "$SERVERBIN" null "$CONFIG" null null 0
fi
fi
sleep 10
done
}

View File

@ -1,70 +0,0 @@
#!/usr/bin/env bash
#PARAMETER 1: directory
#PARAMETER 2: binary file
#PARAMETER 3: gdb on/off
bin_path="${1:-$AC_RESTARTER_BINPATH}"
bin_file="${2:-$AC_RESTARTER_BINFILE}"
with_gdb="${3:-$AC_RESTARTER_WITHGDB}"
CURRENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd )
_instant_crash_count=0
_restart_count=0
if [ "$#" -ne 2 ]; then
echo "Usage: $0 path filename"
echo "Example: $0 $HOME/azerothcore/bin worldserver"
exit 1
fi
while true
do
if [ ! -f "$bin_path/$bin_file" ]; then
echo "$bin_path/$bin_file doesn't exists!"
exit 1
fi
STARTING_TIME=$(date +%s)
cd "$bin_path";
if [ "$with_gdb" = true ]; then
echo "Running with GDB enabled"
gdb -x "$CURRENT_PATH/gdb.conf" --batch "./$bin_file"
else
echo "Running without GDB"
"./$bin_file"
fi
_exit_code=$?
echo "exit code: $_exit_code"
# stop restarter on SIGKILL (disabled for now)
# 128 + 9 (SIGKILL)
#if [ $_exit_code -eq 137 ]; then
# echo "$bin_file has been killed"
# exit 0
#fi
echo "$bin_file terminated, restarting..."
ENDING_TIME=$(date +%s)
DIFFERENCE=$(( $ENDING_TIME - $STARTING_TIME ))
((_restart_count++))
echo "$bin_file Terminated after $DIFFERENCE seconds, termination count: : $_restart_count"
if [ $DIFFERENCE -lt 10 ]; then
# increment instant crash if runtime is lower than 10 seconds
((_instant_crash_count++))
else
_instant_crash_count=0 # reset count
fi
if [ $_instant_crash_count -gt 5 ]; then
echo "$bin_file Restarter exited. Infinite crash loop prevented. Please check your system"
exit 1
fi
done

1
apps/startup-scripts/src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
logs

View File

@ -0,0 +1,57 @@
# AzerothCore Run Engine Default Configuration
# This file contains default values that can be overridden by environment variables
# Priority order: conf.sh > environment variables > conf.sh.dist (this file)
# Enable/disable GDB execution
export GDB_ENABLED="${RUN_ENGINE_GDB_ENABLED:-0}"
# [optional] GDB configuration file
# default: gdb.conf
export GDB="${RUN_ENGINE_GDB:-}"
# Directory where binaries are stored
export BINPATH="${RUN_ENGINE_BINPATH:-}"
# Server binary name (e.g., worldserver, authserver)
export SERVERBIN="${RUN_ENGINE_SERVERBIN:-}"
# Path to server configuration file (including the file name)
# ex: /home/user/azerothcore/etc/worldserver.conf
export CONFIG="${RUN_ENGINE_CONFIG:-}"
# Session manager to use: none|auto|tmux|screen
# auto will detect the best available option
export SESSION_MANAGER="${RUN_ENGINE_SESSION_MANAGER:-none}"
# Default session manager (fallback when SESSION_MANAGER is not set)
export DEFAULT_SESSION_MANAGER="${RUN_ENGINE_DEFAULT_SESSION_MANAGER:-none}"
# Path of the crashes directory
# If not specified, it will be created in the same directory as logs named "crashes"
export CRASHES_PATH="${RUN_ENGINE_CRASHES_PATH:-}"
# Path of log files directory
export LOGS_PATH="${RUN_ENGINE_LOGS_PATH:-}"
# Prefix name for log files to avoid collision with other instances
export LOG_PREFIX_NAME="${RUN_ENGINE_LOG_PREFIX_NAME:-}"
# [optional] Name of session (tmux session or screen session)
# If not specified, a default name will be generated based on server binary
export SESSION_NAME="${RUN_ENGINE_SESSION_NAME:-}"
# [optional] Screen-specific options: -A -m -d -S
# WARNING: if you are running it under a systemd service
# please do not remove -m -d arguments from screen if you are using it,
# or keep WITH_CONSOLE=0. Otherwise the journald-logging system will take
# 100% of CPU slowing down the whole machine.
export SCREEN_OPTIONS="${RUN_ENGINE_SCREEN_OPTIONS:-}"
# Enable/disable console output
# If disabled, output will be redirected to logging files
export WITH_CONSOLE="${RUN_ENGINE_WITH_CONSOLE:-0}"
# Server PID (needed when GDB_ENABLED=1)
export SERVERPID="${RUN_ENGINE_SERVERPID:-}"

View File

@ -0,0 +1,48 @@
#!/usr/bin/env bash
# AzerothCore Auth Server Restarter Example
# This example shows how to use the run-engine with restart functionality for authserver
PATH_RUNENGINE="./"
CONFIG_FILE="./conf-auth.sh"
# Method 1: Using configuration file (recommended)
if [ -f "$CONFIG_FILE" ]; then
echo "Starting authserver with restart loop using config file: $CONFIG_FILE"
source "$CONFIG_FILE"
"$PATH_RUNENGINE/run-engine" restart "$SERVERBIN" --config "$CONFIG_FILE"
else
echo "Error: Configuration file not found: $CONFIG_FILE"
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
echo "Make sure to set: export SERVERBIN=\"authserver\""
echo ""
echo "Alternative: Start with binary path directly"
echo "Example: $PATH_RUNENGINE/run-engine restart /path/to/bin/authserver"
echo "Example: $PATH_RUNENGINE/run-engine restart authserver # if in PATH"
exit 1
fi
# Method 2: Direct binary path (full path)
# Uncomment the line below to start with full binary path
#
# "$PATH_RUNENGINE/run-engine" restart /home/user/azerothcore/bin/authserver --server-config /path/to/authserver.conf
# Method 3: Binary name only (system PATH)
# Uncomment the line below if authserver is in your system PATH
#
# "$PATH_RUNENGINE/run-engine" restart authserver --server-config /path/to/authserver.conf
# Method 4: With session manager (tmux/screen)
# Uncomment the line below to use tmux session
#
# "$PATH_RUNENGINE/run-engine" restart authserver --session-manager tmux --server-config /path/to/authserver.conf
# Method 5: Environment variables only
# Uncomment the lines below for environment variable configuration
#
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
# export RUN_ENGINE_SERVERBIN="authserver"
# export RUN_ENGINE_CONFIG="/path/to/authserver.conf"
# "$PATH_RUNENGINE/run-engine" restart authserver

View File

@ -0,0 +1,47 @@
#!/usr/bin/env bash
# AzerothCore World Server Restarter Example
# This example shows how to use the run-engine with restart functionality for worldserver
PATH_RUNENGINE="./"
CONFIG_FILE="./conf-world.sh"
# Method 1: Using configuration file (recommended)
if [ -f "$CONFIG_FILE" ]; then
echo "Starting worldserver with restart loop using config file: $CONFIG_FILE"
"$PATH_RUNENGINE/run-engine" restart "$SERVERBIN" --config "$CONFIG_FILE"
else
echo "Error: Configuration file not found: $CONFIG_FILE"
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
echo "Make sure to set: export SERVERBIN=\"worldserver\""
echo ""
echo "Alternative: Start with binary path directly"
echo "Example: $PATH_RUNENGINE/run-engine restart /path/to/bin/worldserver"
echo "Example: $PATH_RUNENGINE/run-engine restart worldserver # if in PATH"
exit 1
fi
# Method 2: Direct binary path (full path)
# Uncomment the line below to start with full binary path
#
# "$PATH_RUNENGINE/run-engine" restart /home/user/azerothcore/bin/worldserver --server-config /path/to/worldserver.conf
# Method 3: Binary name only (system PATH)
# Uncomment the line below if worldserver is in your system PATH
#
# "$PATH_RUNENGINE/run-engine" restart worldserver --server-config /path/to/worldserver.conf
# Method 4: With session manager (tmux/screen)
# Uncomment the line below to use tmux session
#
# "$PATH_RUNENGINE/run-engine" restart worldserver --session-manager tmux --server-config /path/to/worldserver.conf
# Method 5: Environment variables only
# Uncomment the lines below for environment variable configuration
#
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
# export RUN_ENGINE_SERVERBIN="worldserver"
# export RUN_ENGINE_CONFIG="/path/to/worldserver.conf"
# "$PATH_RUNENGINE/run-engine" restart worldserver

View File

@ -0,0 +1,46 @@
#!/usr/bin/env bash
# AzerothCore Auth Server Starter Example
# This example shows how to use the run-engine to start authserver without restart loop
PATH_RUNENGINE="./"
CONFIG_FILE="./conf-auth.sh"
# Method 1: Using configuration file (recommended)
if [ -f "$CONFIG_FILE" ]; then
echo "Starting authserver (single run) with config file: $CONFIG_FILE"
"$PATH_RUNENGINE/run-engine" start "$SERVERBIN" --config "$CONFIG_FILE"
else
echo "Error: Configuration file not found: $CONFIG_FILE"
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
echo "Make sure to set: export SERVERBIN=\"authserver\""
echo ""
echo "Alternative: Start with binary path directly"
echo "Example: $PATH_RUNENGINE/run-engine start /path/to/bin/authserver"
echo "Example: $PATH_RUNENGINE/run-engine start authserver # if in PATH"
exit 1
fi
# Method 2: Direct binary path (full path)
# Uncomment the line below to start with full binary path
#
# "$PATH_RUNENGINE/run-engine" start /home/user/azerothcore/bin/authserver --server-config /path/to/authserver.conf
# Method 3: Binary name only (system PATH)
# Uncomment the line below if authserver is in your system PATH
#
# "$PATH_RUNENGINE/run-engine" start authserver --server-config /path/to/authserver.conf
# Method 4: With session manager (tmux/screen)
# Uncomment the line below to use tmux session
#
# "$PATH_RUNENGINE/run-engine" start authserver --session-manager tmux --server-config /path/to/authserver.conf
# Method 5: Environment variables only
# Uncomment the lines below for environment variable configuration
#
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
# export RUN_ENGINE_SERVERBIN="authserver"
# export RUN_ENGINE_CONFIG="/path/to/authserver.conf"
# "$PATH_RUNENGINE/run-engine" start authserver

View File

@ -0,0 +1,47 @@
#!/usr/bin/env bash
# AzerothCore World Server Starter Example
# This example shows how to use the run-engine to start worldserver without restart loop
PATH_RUNENGINE="./"
CONFIG_FILE="./conf-world.sh"
# Method 1: Using configuration file (recommended)
if [ -f "$CONFIG_FILE" ]; then
echo "Starting worldserver (single run) with config file: $CONFIG_FILE"
"$PATH_RUNENGINE/run-engine" start "$SERVERBIN" --config "$CONFIG_FILE"
else
echo "Error: Configuration file not found: $CONFIG_FILE"
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
echo "Make sure to set: export SERVERBIN=\"worldserver\""
echo ""
echo "Alternative: Start with binary path directly"
echo "Example: $PATH_RUNENGINE/run-engine start /path/to/bin/worldserver"
echo "Example: $PATH_RUNENGINE/run-engine start worldserver # if in PATH"
exit 1
fi
# Method 2: Direct binary path (full path)
# Uncomment the line below to start with full binary path
#
# "$PATH_RUNENGINE/run-engine" start /home/user/azerothcore/bin/worldserver --server-config /path/to/worldserver.conf
# Method 3: Binary name only (system PATH)
# Uncomment the line below if worldserver is in your system PATH
#
# "$PATH_RUNENGINE/run-engine" start worldserver --server-config /path/to/worldserver.conf
# Method 4: With session manager (tmux/screen)
# Uncomment the line below to use tmux session
#
# "$PATH_RUNENGINE/run-engine" start worldserver --session-manager tmux --server-config /path/to/worldserver.conf
# Method 5: Environment variables only
# Uncomment the lines below for environment variable configuration
#
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
# export RUN_ENGINE_SERVERBIN="worldserver"
# export RUN_ENGINE_CONFIG="/path/to/worldserver.conf"
# "$PATH_RUNENGINE/run-engine" start worldserver

View File

@ -0,0 +1,467 @@
#!/usr/bin/env bash
# AzerothCore Run Engine
# Advanced script for running AzerothCore services with session management and restart capabilities
#
# This script can be sourced to provide functions or executed directly with parameters
#
# Configuration Priority Order (highest to lowest):
# 1. conf.sh - User configuration file (highest priority)
# 2. Command line arguments (--config, --server-config, etc.)
# 3. Environment variables (RUN_ENGINE_*)
# 4. conf.sh.dist - Default configuration (lowest priority)
#
# Environment Variables:
# RUN_ENGINE_CONFIG_FILE - Path to temporary configuration file (optional)
# RUN_ENGINE_SESSION_MANAGER - Session manager (none|auto|tmux|screen, default: auto)
# RUN_ENGINE_BINPATH - Binary directory path
# RUN_ENGINE_SERVERBIN - Server binary name (worldserver|authserver)
# RUN_ENGINE_CONFIG - Server configuration file path
# RUN_ENGINE_LOGS_PATH - Directory for log files
# RUN_ENGINE_CRASHES_PATH - Directory for crash dumps
# RUN_ENGINE_SESSION_NAME - Session name for tmux/screen
export RUN_ENGINE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Configuration priority order:
# 1. conf.sh (highest priority - user overrides)
# 2. Environment variables (RUN_ENGINE_*)
# 3. conf.sh.dist (lowest priority - defaults)
# Load default configuration first (sets defaults from environment variables)
if [ -e "$RUN_ENGINE_PATH/conf.sh.dist" ]; then
source "$RUN_ENGINE_PATH/conf.sh.dist"
fi
# Load user configuration if exists (this takes priority over everything)
if [ -e "$RUN_ENGINE_PATH/conf.sh" ]; then
source "$RUN_ENGINE_PATH/conf.sh"
fi
# Load configuration
function load_config() {
local config_file="$1"
# If a specific config file is provided via command line, load it
# This allows temporary overrides for specific runs
if [ -n "$config_file" ] && [ -e "$config_file" ]; then
echo "Loading configuration from: $config_file"
source "$config_file"
elif [ -n "$RUN_ENGINE_CONFIG_FILE" ] && [ -e "$RUN_ENGINE_CONFIG_FILE" ]; then
echo "Loading configuration from environment: $RUN_ENGINE_CONFIG_FILE"
source "$RUN_ENGINE_CONFIG_FILE"
fi
# Final override with any remaining environment variables
# This ensures that even after loading config files, environment variables take precedence
BINPATH="${RUN_ENGINE_BINPATH:-$BINPATH}"
SERVERBIN="${RUN_ENGINE_SERVERBIN:-$SERVERBIN}"
CONFIG="${RUN_ENGINE_CONFIG:-$CONFIG}"
SESSION_MANAGER="${RUN_ENGINE_SESSION_MANAGER:-$SESSION_MANAGER}"
LOGS_PATH="${RUN_ENGINE_LOGS_PATH:-$LOGS_PATH}"
CRASHES_PATH="${RUN_ENGINE_CRASHES_PATH:-$CRASHES_PATH}"
}
# Detect available session manager
function detect_session_manager() {
if command -v tmux >/dev/null 2>&1; then
echo "tmux"
elif command -v screen >/dev/null 2>&1; then
echo "screen"
else
echo "none"
fi
}
# Determine which session manager to use
function get_session_manager() {
local requested="$1"
case "$requested" in
"none")
echo "none"
;;
"auto")
detect_session_manager
;;
"tmux")
if command -v tmux >/dev/null 2>&1; then
echo "tmux"
else
echo "error"
fi
;;
"screen")
if command -v screen >/dev/null 2>&1; then
echo "screen"
else
echo "error"
fi
;;
*)
echo "none"
;;
esac
}
# Configure log files
function configure_files() {
TRACE_BEGIN_STRING="SIGSEGV"
TRACE_FILE="$LOGS_PATH/${LOG_PREFIX_NAME}_trace.log"
ERR_FILE="$LOGS_PATH/${LOG_PREFIX_NAME}_error.log"
SYSLOG="$LOGS_PATH/${LOG_PREFIX_NAME}_system.log"
SYSERR="$LOGS_PATH/${LOG_PREFIX_NAME}_system.err"
LINKS_FILE="$LOGS_PATH/${LOG_PREFIX_NAME}_crash_links.link"
}
# Check if service is running
function check_status() {
local session_name="$1"
local ret=1
# Check for GDB process
local gdbres=$(pgrep -f "gdb.*--batch.*$SERVERBIN")
if [[ "$GDB_ENABLED" -eq 1 && -n "$gdbres" ]]; then
return 1
fi
# Check for binary process
local binres=$(pgrep -f "$SERVERBIN -c $CONFIG")
if [ -n "$binres" ]; then
return 1
fi
# Check session manager
if [ -n "$session_name" ]; then
case "$(get_session_manager "${SESSION_MANAGER:-auto}")" in
"tmux")
tmux has-session -t "$session_name" 2>/dev/null && return 1
;;
"screen")
screen -ls "$session_name" 2>/dev/null | grep -q "$session_name" && return 1
;;
esac
fi
return 0
}
# Run with session manager
function run_with_session() {
local session_manager="$1"
local session_name="$2"
local wrapper="$3"
shift 3
local args=("$@")
if [ "$wrapper" = "simple-restarter" ]; then
script_path="$RUN_ENGINE_PATH/simple-restarter"
else
script_path="$RUN_ENGINE_PATH/starter"
fi
case "$session_manager" in
"tmux")
echo "> Starting with tmux session: $session_name - attach with 'tmux attach -t $session_name'"
tmux new-session -d -s "$session_name" -- "$script_path" "${args[@]}"
;;
"screen")
local OPTIONS="-A -m -d -S"
if [ -n "$SCREEN_OPTIONS" ]; then
OPTIONS="$SCREEN_OPTIONS"
fi
echo "> Starting with screen session: $session_name (options: $OPTIONS) - attach with 'screen -r $session_name'"
echo "screen $OPTIONS \"$session_name\" -- \"$script_path\" ${args[*]}"
screen $OPTIONS "$session_name" -- "$script_path" "${args[@]}"
;;
"none"|*)
echo "> Starting without session manager"
"$script_path" "${args[@]}"
;;
esac
}
# Parse command line arguments
function parse_arguments() {
local mode="$1"
local serverbin="$2"
shift 2
local config_file=""
local serverconfig=""
local session_manager=""
# Parse named arguments
while [[ $# -gt 0 ]]; do
case $1 in
--config)
config_file="$2"
shift 2
;;
--server-config)
serverconfig="$2"
shift 2
;;
--session-manager)
session_manager="$2"
shift 2
;;
*)
echo "Unknown argument: $1"
return 1
;;
esac
done
# Export parsed values for use by start_service
export PARSED_MODE="$mode"
export PARSED_SERVERBIN="$serverbin"
export PARSED_CONFIG_FILE="$config_file"
export PARSED_SERVERCONFIG="$serverconfig"
export PARSED_SESSION_MANAGER="$session_manager"
}
# Start service (single run or with simple-restarter)
function start_service() {
local config_file="$1"
local serverbin_path="$2"
local serverconfig="$3"
local use_restarter="${4:-false}"
local session_manager_choice="$5"
# Load configuration first
load_config "$config_file"
# if no session manager is specified, get it from config
if [ -z "$session_manager_choice" ]; then
session_manager_choice="$SESSION_MANAGER"
fi
# Parse serverbin_path to extract BINPATH and SERVERBIN
if [ -n "$serverbin_path" ]; then
# If it's a full path, extract directory and binary name
if [[ "$serverbin_path" == */* ]]; then
BINPATH="$(dirname "$serverbin_path")"
SERVERBIN="$(basename "$serverbin_path")"
else
# If it's just a binary name, use it as-is (system PATH)
SERVERBIN="$serverbin_path"
BINPATH="${BINPATH:-""}" # Empty means use current directory or system PATH
fi
fi
# Use environment/config values if not set from command line
BINPATH="${BINPATH:-$RUN_ENGINE_BINPATH}"
SERVERBIN="${SERVERBIN:-$RUN_ENGINE_SERVERBIN}"
CONFIG="${serverconfig:-$RUN_ENGINE_CONFIG}"
echo "SERVERBIN: $SERVERBIN"
# Validate required parameters
if [ -z "$SERVERBIN" ]; then
echo "Error: SERVERBIN is required"
echo "Could not determine server binary from: $serverbin_path"
echo "Provide it as:"
echo " - Full path: $0 <mode> /path/to/bin/worldserver"
echo " - Binary name: $0 <mode> worldserver"
echo " - Environment variables: RUN_ENGINE_SERVERBIN"
echo " - Configuration file with SERVERBIN variable"
return 1
fi
# If BINPATH is set, validate binary exists and create log paths
if [ -n "$BINPATH" ]; then
if [ ! -d "$BINPATH" ]; then
echo "Error: BINPATH not found: $BINPATH"
return 1
fi
# Set up directories and logging relative to BINPATH
LOGS_PATH="${LOGS_PATH:-"$BINPATH/logs"}"
mkdir -p "$LOGS_PATH"
mkdir -p "$LOGS_PATH/crashes"
else
# For system binaries, try to detect binary location and create logs accordingly
local detected_binpath=""
# Try to find binary in system PATH
local binary_location=$(which "$SERVERBIN" 2>/dev/null)
if [ -n "$binary_location" ]; then
detected_binpath="$(dirname "$binary_location")"
echo "Binary found in system PATH: $binary_location"
# Set BINPATH to the detected location so starter script can find the binary
BINPATH="$detected_binpath"
fi
# Set up log paths based on detected or fallback location
if [ -n "$detected_binpath" ]; then
LOGS_PATH="${LOGS_PATH:-"$detected_binpath/logs"}"
else
# Fallback to current directory for logs
LOGS_PATH="${LOGS_PATH:-./logs}"
fi
CRASHES_PATH="${CRASHES_PATH:-"$LOGS_PATH/crashes"}"
mkdir -p "$LOGS_PATH"
mkdir -p "$CRASHES_PATH"
fi
# Set up logging names
LOG_PREFIX_NAME="${LOG_PREFIX_NAME:-${SERVERBIN%server}}"
# Set up session name (with backward compatibility for SCREEN_NAME)
SESSION_NAME="${SESSION_NAME:-$SCREEN_NAME}"
SESSION_NAME="${SESSION_NAME:-AC-${SERVERBIN%server}}"
configure_files
local session_manager=$(get_session_manager "$session_manager_choice")
if [ "$session_manager" = "error" ]; then
echo "Error: Invalid session manager specified: $session_manager_choice, is it installed?"
exit 1
fi
echo "Using session manager: $session_manager"
echo "Starting server: $SERVERBIN"
if [ -n "$CONFIG" ]; then
echo "Server config: $CONFIG"
else
echo "Server config: default (not specified)"
fi
if [ "$use_restarter" = "true" ]; then
# Use simple-restarter for restart functionality
local gdb_enabled="${GDB_ENABLED:-0}"
run_with_session "$session_manager" "$SESSION_NAME" "simple-restarter" "$BINPATH" "$SERVERBIN" "$GDB" "$CONFIG" "$SYSLOG" "$SYSERR" "$gdb_enabled" "$CRASHES_PATH"
else
# Single run using starter
local gdb_enabled="${GDB_ENABLED:-0}"
run_with_session "$session_manager" "$SESSION_NAME" "starter" "$BINPATH" "$SERVERBIN" "$GDB" "$CONFIG" "$SYSLOG" "$SYSERR" "$gdb_enabled" "$CRASHES_PATH"
fi
}
# Cleanup function
function finish() {
local session_manager=$(get_session_manager "${SESSION_MANAGER:-auto}")
if [ -n "$SESSION_NAME" ]; then
case "$session_manager" in
"tmux")
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
;;
"screen")
screen -X -S "$SESSION_NAME" quit 2>/dev/null || true
;;
esac
fi
}
# Legacy compatibility functions for old examples
function restarter() {
echo "Legacy function 'restarter' called - redirecting to new API"
start_service "" "" "" "true" "${SESSION_MANAGER:-auto}"
}
function starter() {
echo "Legacy function 'starter' called - redirecting to new API"
start_service "" "" "" "false" "${SESSION_MANAGER:-auto}"
}
# Set trap for cleanup (currently disabled to avoid interfering with systemd)
# trap finish EXIT
# Main execution when script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
case "${1:-help}" in
"start"|"restart")
if [ $# -lt 2 ]; then
echo "Error: Missing required arguments"
echo "Usage: $0 <mode> <serverbin> [options]"
echo "Example: $0 start worldserver --config ./conf-world.sh --server-config worldserver.conf"
exit 1
fi
# Parse arguments
if ! parse_arguments "$@"; then
exit 1
fi
# Determine restart mode
use_restarter="false"
if [ "$PARSED_MODE" = "restart" ]; then
use_restarter="true"
fi
# Start service with parsed arguments
start_service "$PARSED_CONFIG_FILE" "$PARSED_SERVERBIN" "$PARSED_SERVERCONFIG" "$use_restarter" "$PARSED_SESSION_MANAGER"
;;
"help"|*)
echo "AzerothCore Run Engine"
echo ""
echo "Usage: $0 <mode> <serverbin> [options]"
echo ""
echo "Modes:"
echo " start - Start service once (no restart on crash)"
echo " restart - Start service with restart on crash (uses simple-restarter)"
echo ""
echo "Required Parameters:"
echo " serverbin - Server binary (full path or binary name)"
echo " Full path: /path/to/bin/worldserver"
echo " Binary name: worldserver (uses system PATH)"
echo ""
echo "Options:"
echo " --config <file> - Path to configuration file"
echo " --server-config <file> - Server configuration file (sets -c parameter)"
echo " --session-manager <type> - Session manager: none|auto|tmux|screen (default: auto)"
echo ""
echo "Configuration Priority (highest to lowest):"
echo " 1. conf.sh - User configuration file"
echo " 2. Command line arguments (--config, --server-config, etc.)"
echo " 3. Environment variables (RUN_ENGINE_*)"
echo " 4. conf.sh.dist - Default configuration"
echo ""
echo "Environment Variables:"
echo " RUN_ENGINE_CONFIG_FILE - Config file path"
echo " RUN_ENGINE_SESSION_MANAGER - Session manager (default: auto)"
echo " RUN_ENGINE_BINPATH - Binary directory path"
echo " RUN_ENGINE_SERVERBIN - Server binary name"
echo " RUN_ENGINE_CONFIG - Server configuration file"
echo " RUN_ENGINE_LOGS_PATH - Directory for log files"
echo " RUN_ENGINE_CRASHES_PATH - Directory for crash dumps"
echo " RUN_ENGINE_SESSION_NAME - Session name for tmux/screen"
echo ""
echo "Examples:"
echo ""
echo " # Using full path to binary"
echo " $0 start /home/user/ac/bin/worldserver"
echo ""
echo " # Using binary name (system PATH)"
echo " $0 start worldserver"
echo ""
echo " # With configuration file"
echo " $0 start worldserver --config ./conf-world.sh"
echo ""
echo " # With server configuration (sets -c parameter)"
echo " $0 start /path/to/bin/worldserver --server-config /etc/worldserver.conf"
echo ""
echo " # With session manager"
echo " $0 restart worldserver --session-manager tmux"
echo ""
echo " # Complete example"
echo " $0 restart /home/user/ac/bin/worldserver --config ./conf-world.sh --server-config worldserver.conf --session-manager screen"
echo ""
echo "Binary Resolution:"
echo " - Full path (contains /): Extracts directory and binary name"
echo " - Binary name only: Uses system PATH to find executable"
echo " Auto-detection will check current directory first, then system PATH"
echo ""
echo "Server Config:"
echo " If --server-config is specified, it's passed as -c parameter to the server."
echo " If not specified, the server will use its default configuration."
;;
esac
fi

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
#!/usr/bin/env bash
# AzerothCore Simple Restarter
# This script is a wrapper around the starter script that provides restart functionality
# and maintains compatibility with the acore dashboard
#
# Usage: simple-restarter <binary> [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path]
#
# Parameters (same as starter):
# $1 - Binary to execute (required)
# $2 - GDB configuration file (optional)
# $3 - Configuration file path (optional)
# $4 - System log file (optional)
# $5 - System error file (optional)
# $6 - GDB enabled flag (0/1, optional)
# $7 - Crashes directory path (optional)
# Get script directory
CURRENT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Parameters (same as starter)
BINPATH="$1"
BINFILE="$2"
GDB_FILE="$3"
CONFIG="$4"
SYSLOG="$5"
SYSERR="$6"
GDB_ENABLED="${7:-0}"
CRASHES_PATH="$8"
BINARY="$BINPATH/$BINFILE"
# Default values (same as starter)
DEFAULT_CRASHES_PATH="./crashes"
DEFAULT_GDB_FILE="$CURRENT_PATH/gdb.conf"
# Set defaults if not provided
CRASHES_PATH="${CRASHES_PATH:-$DEFAULT_CRASHES_PATH}"
GDB_FILE="${GDB_FILE:-$DEFAULT_GDB_FILE}"
# Counters for crash detection
_instant_crash_count=0
_restart_count=0
# Check if starter script exists
STARTER_SCRIPT="$CURRENT_PATH/starter"
if [ ! -f "$STARTER_SCRIPT" ]; then
echo "Error: starter script not found at $STARTER_SCRIPT"
exit 1
fi
# Main restart loop
while true; do
STARTING_TIME=$(date +%s)
# Use starter script to launch the binary with all parameters
"$STARTER_SCRIPT" "$BINPATH" "$BINFILE" "$GDB_FILE" "$CONFIG" "$SYSLOG" "$SYSERR" "$GDB_ENABLED" "$CRASHES_PATH"
_exit_code=$?
echo "$(basename "$BINARY") terminated with exit code: $_exit_code"
# Calculate runtime
ENDING_TIME=$(date +%s)
DIFFERENCE=$((ENDING_TIME - STARTING_TIME))
((_restart_count++))
echo "$(basename "$BINARY") terminated after $DIFFERENCE seconds, restart count: $_restart_count"
# Crash loop detection
if [ $DIFFERENCE -lt 10 ]; then
# Increment instant crash count if runtime is lower than 10 seconds
((_instant_crash_count++))
echo "Warning: Quick restart detected ($DIFFERENCE seconds) - instant crash count: $_instant_crash_count"
else
# Reset count on successful longer run
_instant_crash_count=0
fi
# Prevent infinite crash loops
if [ $_instant_crash_count -gt 5 ]; then
echo "Error: $(basename "$BINARY") restarter exited. Infinite crash loop prevented (6 crashes in under 10 seconds each)"
echo "Please check your system configuration and logs"
exit 1
fi
echo "$(basename "$BINARY") will restart in 3 seconds..."
sleep 3
done

117
apps/startup-scripts/src/starter Executable file
View File

@ -0,0 +1,117 @@
#!/usr/bin/env bash
# AzerothCore Starter Script
# This script handles the execution of AzerothCore binaries with optional GDB support
#
# Usage: starter <binary> [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path]
#
# Parameters:
# $1 - Binary to execute (required)
# $2 - GDB configuration file (optional)
# $3 - Configuration file path (optional)
# $4 - System log file (optional)
# $5 - System error file (optional)
# $6 - GDB enabled flag (0/1, optional)
# $7 - Crashes directory path (optional)
BINPATH="$1"
BINFILE="$2"
GDB_FILE="$3"
CONFIG="$4"
SYSLOG="$5"
SYSERR="$6"
GDB_ENABLED="${7:-0}"
CRASHES_PATH="$8"
BINARY=$(realpath "$BINPATH/$BINFILE")
# Default values
CURRENT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_CRASHES_PATH="$CURRENT_PATH/logs/crashes"
DEFAULT_GDB_FILE="$CURRENT_PATH/gdb.conf"
# Set defaults if not provided
CONFIG="${CONFIG:-""}"
CRASHES_PATH="${CRASHES_PATH:-$DEFAULT_CRASHES_PATH}"
GDB_FILE="${GDB_FILE:-$DEFAULT_GDB_FILE}"
# Validate binary
if [ -z "$BINARY" ]; then
echo "Error: Binary parameter is required"
echo "Usage: $0 <binary> [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path]"
exit 1
fi
if [ ! -f "$BINARY" ]; then
echo "Error: Binary '$BINARY' not found"
exit 1
fi
# Create crashes directory if it doesn't exist
mkdir -p "$CRASHES_PATH"
cd $BINPATH || {
echo "Error: Could not change to binary path '$BINPATH'"
exit 1
}
EXECPATH=$(realpath "$BINFILE")
if [ "$GDB_ENABLED" -eq 1 ]; then
echo "Starting $EXECPATH with GDB enabled"
# Generate GDB configuration on the fly
TIMESTAMP=$(date +%Y-%m-%d-%H-%M-%S)
GDB_TEMP_FILE="$CRASHES_PATH/gdb-$TIMESTAMP.conf"
GDB_OUTPUT_FILE="$CRASHES_PATH/gdb-$TIMESTAMP.txt"
# Create GDB configuration
cat > "$GDB_TEMP_FILE" << EOF
set logging file $GDB_OUTPUT_FILE
set logging enabled on
set debug timestamp
EOF
# Add run command with config if specified
if [ -n "$CONFIG" ]; then
echo "run -c $CONFIG" >> "$GDB_TEMP_FILE"
else
echo "run" >> "$GDB_TEMP_FILE"
fi
cat >> "$GDB_TEMP_FILE" << EOF
bt
bt full
info thread
thread apply all backtrace full
EOF
# Create log files if specified
if [ -n "$SYSLOG" ]; then
[ ! -f "$SYSLOG" ] && touch "$SYSLOG"
fi
if [ -n "$SYSERR" ]; then
[ ! -f "$SYSERR" ] && touch "$SYSERR"
fi
# Execute with GDB
if [ "${WITH_CONSOLE:-0}" -eq 0 ] && [ -n "$SYSLOG" ] && [ -n "$SYSERR" ]; then
gdb -x "$GDB_TEMP_FILE" --batch "$EXECPATH" >> "$SYSLOG" 2>> "$SYSERR"
else
echo "> Console enabled"
if [ -n "$SYSLOG" ] && [ -n "$SYSERR" ]; then
gdb -x "$GDB_TEMP_FILE" --batch "$EXECPATH" > >(tee "$SYSLOG") 2> >(tee "$SYSERR" >&2)
else
gdb -x "$GDB_TEMP_FILE" --batch "$EXECPATH"
fi
fi
# Cleanup temporary GDB file
rm -f "$GDB_TEMP_FILE"
else
if [ -n "$CONFIG" ]; then
script -q -e -c "$EXECPATH -c \"$CONFIG\""
else
script -q -e -c "$EXECPATH"
fi
fi

View File

@ -1,32 +0,0 @@
#!/usr/bin/env bash
GDB_FILE="$2"
CONFIG="$3"
SYSLOG="$4"
SYSERR="$5"
GDB_ENABLED="$6"
CRASHES_PATH="$7"
if [ $GDB_ENABLED -eq 1 ]; then
echo "set logging file "$CRASHES_PATH"/gdb-$(date +%Y-%m-%d-%H-%M-%S).txt" > "$GDB_FILE"
echo "set logging enabled on" >> "$GDB_FILE"
echo "set debug timestamp" >> "$GDB_FILE"
echo "run -c $3" >> "$GDB_FILE"
echo "bt" >> "$GDB_FILE"
echo "bt full" >> "$GDB_FILE"
echo "info thread" >> "$GDB_FILE"
echo "thread apply all backtrace full" >> "$GDB_FILE"
[ ! -f "$SYSLOG" ] && touch "$SYSLOG"
[ ! -f "$SYSERR" ] && touch "$SYSERR"
if [ $WITH_CONSOLE -eq 0 ]; then
gdb -x $GDB_FILE --batch $1 >> "$SYSLOG" 2>> "$SYSERR"
else
echo "> Console enabled"
gdb -x $GDB_FILE --batch $1 > >(tee ${SYSLOG}) 2> >(tee ${SYSERR} >&2)
fi
elif [ $GDB_ENABLED -eq 0 ]; then
"./$1" -c "$CONFIG"
fi

View File

@ -0,0 +1,14 @@
# BATS Test Configuration
# Set test timeout (in seconds)
export BATS_TEST_TIMEOUT=30
# Enable verbose output for debugging
export BATS_VERBOSE_RUN=1
# Test output format
export BATS_FORMATTER=pretty
# Enable colored output
export BATS_NO_PARALLELIZE_ACROSS_FILES=1
export BATS_NO_PARALLELIZE_WITHIN_FILE=1

View File

@ -0,0 +1,147 @@
#!/usr/bin/env bats
# AzerothCore Startup Scripts Test Suite
# This script tests the basic functionality of the startup scripts using the unified test framework
# Load the AzerothCore test framework
load '../../test-framework/bats_libs/acore-support'
load '../../test-framework/bats_libs/acore-assert'
# Setup that runs before each test
setup() {
startup_scripts_setup
export SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/../src" && pwd)"
}
# Cleanup that runs after each test
teardown() {
acore_test_teardown
}
# ===== STARTER SCRIPT TESTS =====
@test "starter: should fail with missing parameters" {
run timeout 3s "$SCRIPT_DIR/starter" '' ''
[ "$status" -ne 0 ]
[[ "$output" =~ "Error: Binary '/' not found" ]]
}
@test "starter: should start with valid binary" {
cd "$TEST_DIR"
run timeout 5s "$SCRIPT_DIR/starter" "$TEST_DIR/bin" "test-server" "" "$TEST_DIR/test-server.conf" "" "" 0
debug_on_failure
# The starter might have issues with the script command, so we check for specific behavior
# Either it should succeed or show a specific error we can work with
[[ "$output" =~ "Test server starting" ]] || [[ "$output" =~ "script:" ]] || [[ "$status" -eq 124 ]]
}
@test "starter: should validate binary path exists" {
run "$SCRIPT_DIR/starter" "/nonexistent/path" "test-server"
[ "$status" -ne 0 ]
[[ "$output" =~ "Binary parameter is required" ]] || [[ "$output" =~ "No such file or directory" ]]
}
# ===== SIMPLE RESTARTER TESTS =====
@test "simple-restarter: should fail with missing parameters" {
run timeout 3s "$SCRIPT_DIR/simple-restarter" '' ''
[ "$status" -ne 0 ]
[[ "$output" =~ "Error: Binary '/' not found" ]]
}
@test "simple-restarter: should fail with missing binary" {
run timeout 3s "$SCRIPT_DIR/simple-restarter" "$TEST_DIR/bin" 'nonexistent'
[ "$status" -ne 0 ]
[[ "$output" =~ "not found" ]] || [[ "$output" =~ "terminated with exit code" ]]
}
@test "simple-restarter: should detect starter script" {
# Test that it finds the starter script
run timeout 1s "$SCRIPT_DIR/simple-restarter" '' ''
# Should not fail because starter script is missing
[[ ! "$output" =~ "starter script not found" ]]
}
# ===== RUN-ENGINE TESTS =====
@test "run-engine: should show help" {
run "$SCRIPT_DIR/run-engine" help
[ "$status" -eq 0 ]
[[ "$output" =~ "AzerothCore Run Engine" ]]
}
@test "run-engine: should validate parameters for start command" {
run "$SCRIPT_DIR/run-engine" start
[ "$status" -ne 0 ]
[[ "$output" =~ "Missing required arguments" ]]
}
@test "run-engine: should detect binary with full path" {
run timeout 5s "$SCRIPT_DIR/run-engine" start "$TEST_DIR/bin/test-server" --server-config "$TEST_DIR/test-server.conf"
debug_on_failure
[[ "$output" =~ "Starting server: test-server" ]] || [[ "$status" -eq 124 ]]
}
@test "run-engine: should detect binary in current directory" {
cd "$TEST_DIR/bin"
run timeout 5s "$SCRIPT_DIR/run-engine" start test-server --server-config "$TEST_DIR/test-server.conf"
debug_on_failure
[[ "$output" =~ "Binary found in current directory" ]] || [[ "$output" =~ "Starting server: test-server" ]] || [[ "$status" -eq 124 ]]
}
@test "run-engine: should support restart mode" {
run timeout 5s "$SCRIPT_DIR/run-engine" restart "$TEST_DIR/bin/test-server" --server-config "$TEST_DIR/test-server.conf"
debug_on_failure
[[ "$output" =~ "Starting server: test-server" ]] || [[ "$status" -eq 124 ]]
}
# ===== SERVICE MANAGER TESTS =====
@test "service-manager: should show help" {
run "$SCRIPT_DIR/service-manager.sh" help
[ "$status" -eq 0 ]
[[ "$output" =~ "AzerothCore Service Setup" ]]
}
@test "service-manager: should validate create command parameters" {
run "$SCRIPT_DIR/service-manager.sh" create
[ "$status" -ne 0 ]
[[ "$output" =~ "Missing required arguments" ]] || [[ "$output" =~ "Error:" ]]
}
# ===== EXAMPLE SCRIPTS TESTS =====
@test "examples: restarter-world should show configuration error" {
run "$SCRIPT_DIR/examples/restarter-world.sh"
[[ "$output" =~ "Configuration file not found" ]]
}
@test "examples: starter-auth should show configuration error" {
run "$SCRIPT_DIR/examples/starter-auth.sh"
[[ "$output" =~ "Configuration file not found" ]]
}
@test "examples: restarter-auth should show configuration error" {
run "$SCRIPT_DIR/examples/restarter-auth.sh"
[[ "$output" =~ "Configuration file not found" ]]
}
@test "examples: restarter-world should show alternative suggestions" {
run "$SCRIPT_DIR/examples/restarter-world.sh"
[[ "$output" =~ "Alternative: Start with binary path directly" ]]
}
# ===== INTEGRATION TESTS =====
@test "integration: starter and simple-restarter work together" {
# Test that simple-restarter can use starter
run timeout 5s "$SCRIPT_DIR/simple-restarter" "$TEST_DIR/bin" "test-server"
# Should start and then restart at least once
[[ "$output" =~ "terminated with exit code" ]] || [[ "$status" -eq 124 ]]
}
@test "integration: run-engine can handle missing config gracefully" {
run timeout 3s "$SCRIPT_DIR/run-engine" start "$TEST_DIR/bin/test-server"
# Should either work or give a meaningful error
[[ "$status" -eq 124 ]] || [[ "$status" -eq 0 ]] || [[ "$output" =~ "config" ]]
}

View File

@ -0,0 +1,335 @@
# AzerothCore Test Framework
This is the centralized test framework for all AzerothCore bash scripts. It provides a unified way to write, run, and manage tests across all modules.
## Structure
```
apps/test-framework/
├── run-tests.sh # Universal test runner (single entry point)
├── README.md # This documentation
├── bats_libs/ # Custom BATS libraries
│ ├── acore-support.bash # Test setup and helpers
│ └── acore-assert.bash # Custom assertions
└── helpers/ # Test utilities
└── test_common.sh # Common test functions and setup
```
## Quick Start
### From any module directory:
```bash
# Run tests for current module
../test-framework/run-tests.sh --dir .
```
### From test-framework directory:
```bash
# Run all tests in all modules
./run-tests.sh --all
# Run tests for specific module
./run-tests.sh startup-scripts
# List available modules
./run-tests.sh --list
# Run tests with debug info
./run-tests.sh --all --debug
```
### From project root:
```bash
# Run all tests
apps/test-framework/run-tests.sh --all
# Run specific module
apps/test-framework/run-tests.sh startup-scripts
# Run with verbose output
apps/test-framework/run-tests.sh startup-scripts --verbose
```
## Usage
### Basic Commands
```bash
# Run all tests
./run-tests.sh --all
# Run tests for specific module
./run-tests.sh startup-scripts
# Run tests matching pattern
./run-tests.sh --filter starter
# Run tests in specific directory
./run-tests.sh --dir apps/docker
# Show available modules
./run-tests.sh --list
# Show test count
./run-tests.sh --count
```
### Output Formats
```bash
# Pretty output (default)
./run-tests.sh --pretty
# TAP output for CI/CD
./run-tests.sh --tap
# Verbose output with debug info
./run-tests.sh --verbose --debug
```
## Writing Tests
### Basic Test Structure
```bash
#!/usr/bin/env bats
# Load the AzerothCore test framework
load '../../test-framework/bats_libs/acore-support'
load '../../test-framework/bats_libs/acore-assert'
setup() {
acore_test_setup # Standard setup
# or
startup_scripts_setup # For startup scripts
# or
compiler_setup # For compiler tests
# or
docker_setup # For docker tests
}
teardown() {
acore_test_teardown
}
@test "my test description" {
run my_command
assert_success
assert_output "expected output"
}
```
### Available Setup Functions
- `acore_test_setup` - Basic setup for all tests
- `startup_scripts_setup` - Setup for startup script tests
- `compiler_setup` - Setup for compiler tests
- `docker_setup` - Setup for docker tests
- `extractor_setup` - Setup for extractor tests
### Custom Assertions
```bash
# Assert binary exists and is executable
assert_binary_exists "$TEST_DIR/bin/authserver"
# Assert server started correctly
assert_acore_server_started "$output" "authserver"
# Assert config was loaded
assert_config_loaded "$output" "authserver.conf"
# Assert build success
assert_build_success "$output"
# Assert timeout occurred (for long-running processes)
assert_timeout "$status"
# Assert log contains content
assert_log_contains "$log_file" "Server started"
```
### Test Environment Variables
When using the framework, these variables are automatically set:
- `$TEST_DIR` - Temporary test directory
- `$AC_TEST_ROOT` - Project root directory
- `$AC_TEST_APPS` - Apps directory
- `$BUILDPATH` - Build directory path
- `$SRCPATH` - Source directory path
- `$BINPATH` - Binary directory path
- `$LOGS_PATH` - Logs directory path
### Helper Functions
```bash
# Create test binary
create_test_binary "authserver" 0 2 "Server started"
# Create test config
create_test_config "authserver.conf" "Database.Info = \"127.0.0.1;3306;root;pass;db\""
# Create AzerothCore specific binaries and configs
create_acore_binaries
create_acore_configs
# Run command with timeout
run_with_timeout 5s my_command
# Wait for condition
wait_for_condition "test -f $TEST_DIR/ready" 10 1
# Debug test failure
debug_on_failure
```
## Module Integration
### Adding Tests to a New Module
1. Create a `test/` directory in your module:
```bash
mkdir apps/my-module/test
```
2. Create test files (ending in `.bats`):
```bash
touch apps/my-module/test/test_my_feature.bats
```
3. Write your tests using the framework (see examples above)
### Running Tests
From your module directory:
```bash
../test-framework/run-tests.sh --dir .
```
From the test framework:
```bash
./run-tests.sh my-module
```
From project root:
```bash
apps/test-framework/run-tests.sh my-module
```
## CI/CD Integration
For continuous integration, use TAP output:
```bash
# In your CI script
cd apps/test-framework
./run-tests.sh --all --tap > test-results.tap
# Or from project root
apps/test-framework/run-tests.sh --all --tap > test-results.tap
```
## Available Commands
All functionality is available through the single `run-tests.sh` script:
### Basic Test Execution
- `./run-tests.sh --all` - Run all tests in all modules
- `./run-tests.sh <module>` - Run tests for specific module
- `./run-tests.sh --dir <path>` - Run tests in specific directory
- `./run-tests.sh --list` - List available modules
- `./run-tests.sh --count` - Show test count
### Output Control
- `./run-tests.sh --verbose` - Verbose output with debug info
- `./run-tests.sh --tap` - TAP output for CI/CD
- `./run-tests.sh --debug` - Debug mode with failure details
- `./run-tests.sh --pretty` - Pretty output (default)
### Test Filtering
- `./run-tests.sh --filter <pattern>` - Run tests matching pattern
- `./run-tests.sh <module> --filter <pattern>` - Filter within module
### Utility Functions
- `./run-tests.sh --help` - Show help message
- Install BATS: Use your system package manager (`apt install bats`, `brew install bats-core`, etc.)
### Direct Script Usage
## Examples
### Running Specific Tests
```bash
# Run only starter-related tests
./run-tests.sh --filter starter
# Run only tests in startup-scripts module
./run-tests.sh startup-scripts
# Run all tests with verbose output
./run-tests.sh --all --verbose
# Run tests in specific directory with debug
./run-tests.sh --dir apps/docker --debug
```
### Development Workflow
```bash
# While developing, run tests frequently from module directory
cd apps/my-module
../test-framework/run-tests.sh --dir .
# Debug failing tests
../test-framework/run-tests.sh --dir . --debug --verbose
# Run specific test pattern
../test-framework/run-tests.sh --dir . --filter my-feature
# From project root - run all tests
apps/test-framework/run-tests.sh --all
# Quick test count check
apps/test-framework/run-tests.sh --count
```
## Benefits
1. **No Boilerplate**: Minimal setup required for new test modules
2. **Consistent Environment**: All tests use the same setup/teardown
3. **Reusable Utilities**: Common functions available across all tests
4. **Centralized Management**: Single place to update test infrastructure
5. **Flexible Execution**: Run tests for one module, multiple modules, or all modules
6. **CI/CD Ready**: TAP output format supported
7. **Easy Debugging**: Built-in debug helpers and verbose output
## Dependencies
- [BATS (Bash Automated Testing System)](https://github.com/bats-core/bats-core)
- Standard Unix utilities (find, grep, timeout, etc.)
Install BATS with your system package manager:
```bash
# Ubuntu/Debian
sudo apt update && sudo apt install bats
# Fedora/RHEL
sudo dnf install bats
# macOS
brew install bats-core
# Arch Linux
sudo pacman -S bats
```
## Contributing
When adding new test utilities:
1. Add common functions to `helpers/test_common.sh`
2. Add BATS-specific helpers to `bats_libs/acore-support.bash`
3. Add custom assertions to `bats_libs/acore-assert.bash`
4. Update this README with new functionality

View File

@ -0,0 +1,178 @@
#!/usr/bin/env bash
# AzerothCore BATS Assertions Library
# Custom assertions for AzerothCore testing
# Assert that a binary exists and is executable
assert_binary_exists() {
local binary_path="$1"
local message="${2:-Binary should exist and be executable}"
if [[ ! -f "$binary_path" ]]; then
echo "Binary not found: $binary_path"
echo "$message"
return 1
fi
if [[ ! -x "$binary_path" ]]; then
echo "Binary not executable: $binary_path"
echo "$message"
return 1
fi
}
# Assert that output contains specific AzerothCore patterns
assert_acore_server_started() {
local output="$1"
local server_type="$2"
local message="${3:-Server should show startup message}"
if [[ ! "$output" =~ $server_type.*starting ]]; then
echo "Server start message not found for $server_type"
echo "Expected pattern: '$server_type.*starting'"
echo "Actual output: $output"
echo "$message"
return 1
fi
}
# Assert that configuration file was loaded
assert_config_loaded() {
local output="$1"
local config_file="$2"
local message="${3:-Configuration file should be loaded}"
if [[ ! "$output" =~ config.*$config_file ]] && [[ ! "$output" =~ $config_file ]]; then
echo "Configuration file loading not detected: $config_file"
echo "Expected to find: config.*$config_file OR $config_file"
echo "Actual output: $output"
echo "$message"
return 1
fi
}
# Assert that a process exited with expected code
assert_exit_code() {
local actual_code="$1"
local expected_code="$2"
local message="${3:-Process should exit with expected code}"
if [[ "$actual_code" -ne "$expected_code" ]]; then
echo "Expected exit code: $expected_code"
echo "Actual exit code: $actual_code"
echo "$message"
return 1
fi
}
# Assert that output contains specific error pattern
assert_error_message() {
local output="$1"
local error_pattern="$2"
local message="${3:-Output should contain expected error message}"
if [[ ! "$output" =~ $error_pattern ]]; then
echo "Expected error pattern not found: $error_pattern"
echo "Actual output: $output"
echo "$message"
return 1
fi
}
# Assert that a file was created
assert_file_created() {
local file_path="$1"
local message="${2:-File should be created}"
if [[ ! -f "$file_path" ]]; then
echo "File not created: $file_path"
echo "$message"
return 1
fi
}
# Assert that a directory was created
assert_directory_created() {
local dir_path="$1"
local message="${2:-Directory should be created}"
if [[ ! -d "$dir_path" ]]; then
echo "Directory not created: $dir_path"
echo "$message"
return 1
fi
}
# Assert that output contains success message
assert_success_message() {
local output="$1"
local success_pattern="${2:-success|completed|finished|done}"
local message="${3:-Output should contain success message}"
if [[ ! "$output" =~ $success_pattern ]]; then
echo "Success message not found"
echo "Expected pattern: $success_pattern"
echo "Actual output: $output"
echo "$message"
return 1
fi
}
# Assert that build was successful
assert_build_success() {
local output="$1"
local message="${2:-Build should complete successfully}"
local build_success_patterns="Build completed|compilation successful|build.*success|make.*success"
assert_success_message "$output" "$build_success_patterns" "$message"
}
# Assert that server is responsive
assert_server_responsive() {
local output="$1"
local server_type="$2"
local message="${3:-Server should be responsive}"
if [[ ! "$output" =~ $server_type.*initialized ]] && [[ ! "$output" =~ $server_type.*ready ]]; then
echo "Server responsiveness not detected for $server_type"
echo "Expected pattern: '$server_type.*initialized' OR '$server_type.*ready'"
echo "Actual output: $output"
echo "$message"
return 1
fi
}
# Assert that timeout occurred (for long-running processes)
assert_timeout() {
local exit_code="$1"
local message="${2:-Process should timeout as expected}"
if [[ "$exit_code" -ne 124 ]]; then
echo "Expected timeout (exit code 124)"
echo "Actual exit code: $exit_code"
echo "$message"
return 1
fi
}
# Assert that log file contains expected content
assert_log_contains() {
local log_file="$1"
local expected_content="$2"
local message="${3:-Log file should contain expected content}"
if [[ ! -f "$log_file" ]]; then
echo "Log file not found: $log_file"
echo "$message"
return 1
fi
if ! grep -q "$expected_content" "$log_file"; then
echo "Expected content not found in log: $expected_content"
echo "Log file: $log_file"
echo "Log contents:"
cat "$log_file" | head -20
echo "$message"
return 1
fi
}

View File

@ -0,0 +1,116 @@
#!/usr/bin/env bash
# AzerothCore BATS Support Library
# Additional helper functions for BATS testing
# Load common test utilities
source "$(dirname "${BASH_SOURCE[0]}")/../helpers/test_common.sh"
# Standard setup for all AzerothCore tests
acore_test_setup() {
setup_test_env
create_acore_binaries
create_acore_configs
}
# Standard teardown for all AzerothCore tests
acore_test_teardown() {
cleanup_test_env
}
# Quick setup for startup script tests
startup_scripts_setup() {
acore_test_setup
create_test_script_config "test" "test-server"
# Create additional test binary for startup scripts
create_test_binary "test-server" 0 2 "Test server starting with config:"
# Create the test-server.conf file that tests expect
cat > "$TEST_DIR/test-server.conf" << EOF
# Test server configuration file
# Generated by AzerothCore test framework
Database.Info = "127.0.0.1;3306;acore;acore;acore_world"
LoginDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_auth"
CharacterDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_characters"
EOF
}
# Quick setup for compiler tests
compiler_setup() {
acore_test_setup
# Create mock build tools
create_test_binary "gcc" 0 1
create_test_binary "g++" 0 1
create_test_binary "ninja" 0 2
# Create mock CMake files
mkdir -p "$TEST_DIR/build"
touch "$TEST_DIR/build/CMakeCache.txt"
echo "CMAKE_BUILD_TYPE:STRING=RelWithDebInfo" > "$TEST_DIR/build/CMakeCache.txt"
}
# Quick setup for docker tests
docker_setup() {
acore_test_setup
# Create mock docker commands
create_test_binary "docker" 0 1 "Docker container started"
create_test_binary "docker-compose" 0 2 "Docker Compose services started"
# Create test docker files
cat > "$TEST_DIR/Dockerfile" << 'EOF'
FROM ubuntu:20.04
RUN apt-get update
EOF
cat > "$TEST_DIR/docker-compose.yml" << 'EOF'
version: '3.8'
services:
test-service:
image: ubuntu:20.04
EOF
}
# Quick setup for extractor tests
extractor_setup() {
acore_test_setup
# Create mock client data directories
mkdir -p "$TEST_DIR/client"/{Maps,vmaps,mmaps,dbc}
# Create some test data files
echo "Test map data" > "$TEST_DIR/client/Maps/test.map"
echo "Test DBC data" > "$TEST_DIR/client/dbc/test.dbc"
}
# Helper to run command with timeout and capture output
run_with_timeout() {
local timeout_duration="$1"
shift
run timeout "$timeout_duration" "$@"
}
# Helper to check if a process is running
process_running() {
local process_name="$1"
pgrep -f "$process_name" >/dev/null 2>&1
}
# Helper to wait for a condition
wait_for_condition() {
local condition="$1"
local timeout="${2:-10}"
local interval="${3:-1}"
local count=0
while ! eval "$condition"; do
sleep "$interval"
count=$((count + interval))
if [[ $count -ge $timeout ]]; then
return 1
fi
done
return 0
}

View File

@ -0,0 +1,143 @@
#!/usr/bin/env bash
# AzerothCore Test Common Utilities
# Shared functions and setup for all BATS tests
export AC_TEST_FRAMEWORK_VERSION="1.0.0"
# Get paths
AC_TEST_FRAMEWORK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
AC_PROJECT_ROOT="$(cd "$AC_TEST_FRAMEWORK_DIR/../.." && pwd)"
# Common test environment setup
setup_test_env() {
export TEST_DIR="$(mktemp -d)"
export AC_TEST_ROOT="$AC_PROJECT_ROOT"
export AC_TEST_APPS="$AC_TEST_ROOT/apps"
# Create standard test directory structure
mkdir -p "$TEST_DIR"/{bin,etc,logs,data,crashes,build}
# Set up test-specific environment variables
export ORIGINAL_PATH="$PATH"
export PATH="$TEST_DIR/bin:$PATH"
# Common environment variables for AzerothCore
export BUILDPATH="$TEST_DIR/build"
export SRCPATH="$AC_TEST_ROOT"
export BINPATH="$TEST_DIR/bin"
export LOGS_PATH="$TEST_DIR/logs"
}
cleanup_test_env() {
if [[ -n "$TEST_DIR" && -d "$TEST_DIR" ]]; then
rm -rf "$TEST_DIR"
fi
if [[ -n "$ORIGINAL_PATH" ]]; then
export PATH="$ORIGINAL_PATH"
fi
}
# Create standard test binary
create_test_binary() {
local binary_name="$1"
local exit_code="${2:-0}"
local runtime="${3:-2}"
local extra_output="${4:-""}"
cat > "$TEST_DIR/bin/$binary_name" << EOF
#!/usr/bin/env bash
echo "$binary_name starting with config: \$2"
echo "$binary_name running for $runtime seconds..."
if [[ -n "$extra_output" ]]; then
echo "$extra_output"
fi
sleep $runtime
echo "$binary_name exiting with code $exit_code"
exit $exit_code
EOF
chmod +x "$TEST_DIR/bin/$binary_name"
}
# Create test configuration file
create_test_config() {
local config_name="$1"
local content="$2"
cat > "$TEST_DIR/etc/$config_name" << EOF
# Test configuration file: $config_name
# Generated by AzerothCore test framework
$content
EOF
}
# Create AzerothCore specific test binaries
create_acore_binaries() {
create_test_binary "authserver" 0 1 "AuthServer initialized"
create_test_binary "worldserver" 0 2 "WorldServer initialized"
create_test_binary "cmake" 0 1 "CMake configured"
create_test_binary "make" 0 2 "Build completed"
create_test_binary "mapextractor" 0 3 "Map extraction completed"
create_test_binary "vmap4extractor" 0 2 "VMap extraction completed"
create_test_binary "vmap4assembler" 0 1 "VMap assembly completed"
create_test_binary "mmaps_generator" 0 5 "MMap generation completed"
}
# Create AzerothCore specific test configs
create_acore_configs() {
create_test_config "authserver.conf" 'Database.Info = "127.0.0.1;3306;acore;acore;acore_auth"
LoginDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_auth"'
create_test_config "worldserver.conf" 'Database.Info = "127.0.0.1;3306;acore;acore;acore_world"
LoginDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_auth"
CharacterDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_characters"'
create_test_config "config.sh" "export BUILDPATH=\"$TEST_DIR/build\"
export SRCPATH=\"$AC_TEST_ROOT\"
export BINPATH=\"$TEST_DIR/bin\"
export LOGS_PATH=\"$TEST_DIR/logs\""
}
# Create a test script configuration (for startup scripts)
create_test_script_config() {
local script_name="$1"
local binary_name="${2:-authserver}"
cat > "$TEST_DIR/conf-$script_name.sh" << EOF
export BINPATH="$TEST_DIR/bin"
export SERVERBIN="$binary_name"
export CONFIG="$TEST_DIR/etc/$binary_name.conf"
export LOGS_PATH="$TEST_DIR/logs"
export LOG_PREFIX_NAME="$script_name"
export SCREEN_NAME="AC-$script_name"
export GDB_ENABLED=0
export WITH_CONSOLE=1
EOF
}
# Debug helper function
debug_on_failure() {
if [[ "$status" -ne 0 ]]; then
echo "Command failed with status: $status" >&3
echo "Output was:" >&3
echo "$output" >&3
if [[ -n "$TEST_DIR" ]]; then
echo "Test directory contents:" >&3
ls -la "$TEST_DIR" >&3 2>/dev/null || true
fi
fi
}
# Print test environment info
print_test_env() {
echo "Test Environment:" >&3
echo " TEST_DIR: $TEST_DIR" >&3
echo " AC_TEST_ROOT: $AC_TEST_ROOT" >&3
echo " AC_TEST_APPS: $AC_TEST_APPS" >&3
echo " PATH: $PATH" >&3
}
# Check if running in test mode
is_test_mode() {
[[ -n "$BATS_TEST_FILENAME" ]] || [[ -n "$TEST_DIR" ]]
}

290
apps/test-framework/run-tests.sh Executable file
View File

@ -0,0 +1,290 @@
#!/usr/bin/env bash
# AzerothCore Universal Test Runner
# This script provides a unified way to run BATS tests across all modules
# Get the script directory and project root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
show_help() {
echo -e "${BLUE}AzerothCore Universal Test Runner${NC}"
echo ""
echo "Usage: $0 [OPTIONS] [TEST_MODULES...]"
echo ""
echo "Options:"
echo " -h, --help Show this help message"
echo " -v, --verbose Enable verbose output"
echo " -t, --tap Use TAP output format (for CI/CD)"
echo " -p, --pretty Use pretty output format (default)"
echo " -f, --filter Run only tests matching pattern"
echo " -c, --count Show test count only"
echo " -d, --debug Enable debug mode (shows output on failure)"
echo " -l, --list List available test modules"
echo " --dir <path> Run tests in specific directory"
echo " --all Run all tests in all modules"
echo ""
echo "Test Modules:"
echo " startup-scripts - Startup script tests"
echo " compiler - Compiler script tests"
echo " docker - Docker-related tests"
echo " installer - Installer script tests"
echo ""
echo "Examples:"
echo " $0 # Run tests in current directory"
echo " $0 --all # Run all tests in all modules"
echo " $0 startup-scripts # Run startup-scripts tests only"
echo " $0 --dir apps/docker # Run tests in specific directory"
echo " $0 --verbose startup-scripts # Run with verbose output"
echo " $0 --filter starter # Run only tests matching 'starter'"
echo " $0 --tap # Output in TAP format for CI"
}
# Parse command line arguments
VERBOSE=false
TAP=false
PRETTY=true
FILTER=""
COUNT_ONLY=false
DEBUG=false
LIST_MODULES=false
RUN_ALL=false
TEST_DIRS=()
TEST_MODULES=()
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-v|--verbose)
VERBOSE=true
shift
;;
-t|--tap)
TAP=true
PRETTY=false
shift
;;
-p|--pretty)
PRETTY=true
TAP=false
shift
;;
-f|--filter)
FILTER="$2"
shift 2
;;
-c|--count)
COUNT_ONLY=true
shift
;;
-d|--debug)
DEBUG=true
shift
;;
-l|--list)
LIST_MODULES=true
shift
;;
--dir)
TEST_DIRS+=("$2")
shift 2
;;
--all)
RUN_ALL=true
shift
;;
*.bats)
# Individual test files
TEST_FILES+=("$1")
shift
;;
*)
# Assume it's a module name
TEST_MODULES+=("$1")
shift
;;
esac
done
# Check if BATS is installed
if ! command -v bats >/dev/null 2>&1; then
echo -e "${RED}Error: BATS is not installed${NC}"
echo "Please install BATS first:"
echo " sudo apt install bats # On Ubuntu/Debian"
echo " brew install bats-core # On macOS"
echo "Or run: make install-bats"
exit 1
fi
# Function to find test directories
find_test_directories() {
local search_paths=()
if [[ "$RUN_ALL" == true ]]; then
# Find all test directories
mapfile -t search_paths < <(find "$PROJECT_ROOT/apps" -type d -name "test" 2>/dev/null)
elif [[ ${#TEST_DIRS[@]} -gt 0 ]]; then
# Use specified directories
for dir in "${TEST_DIRS[@]}"; do
if [[ -d "$PROJECT_ROOT/$dir/test" ]]; then
search_paths+=("$PROJECT_ROOT/$dir/test")
elif [[ -d "$dir/test" ]]; then
search_paths+=("$dir/test")
elif [[ -d "$dir" ]]; then
search_paths+=("$dir")
else
echo -e "${YELLOW}Warning: Test directory not found: $dir${NC}"
fi
done
elif [[ ${#TEST_MODULES[@]} -gt 0 ]]; then
# Use specified modules
for module in "${TEST_MODULES[@]}"; do
if [[ -d "$PROJECT_ROOT/apps/$module/test" ]]; then
search_paths+=("$PROJECT_ROOT/apps/$module/test")
else
echo -e "${YELLOW}Warning: Module test directory not found: $module${NC}"
fi
done
else
# Default: use current directory or startup-scripts if run from test-framework
if [[ "$(basename "$PWD")" == "test-framework" ]]; then
search_paths=("$PROJECT_ROOT/apps/startup-scripts/test")
elif [[ -d "./test" ]]; then
search_paths=("./test")
else
echo -e "${YELLOW}No test directory found. Use --all or specify a module.${NC}"
exit 0
fi
fi
echo "${search_paths[@]}"
}
# Function to list available modules
list_modules() {
echo -e "${BLUE}Available test modules:${NC}"
find "$PROJECT_ROOT/apps" -type d -name "test" 2>/dev/null | while read -r test_dir; do
module_name=$(basename "$(dirname "$test_dir")")
test_count=$(find "$test_dir" -name "*.bats" | wc -l)
echo -e " ${GREEN}$module_name${NC} ($test_count test files)"
done
}
# Show available modules if requested
if [[ "$LIST_MODULES" == true ]]; then
list_modules
exit 0
fi
# Find test directories
TEST_SEARCH_PATHS=($(find_test_directories))
if [[ ${#TEST_SEARCH_PATHS[@]} -eq 0 ]]; then
echo -e "${YELLOW}No test directories found.${NC}"
echo "Use --list to see available modules."
exit 0
fi
# Collect all test files
TEST_FILES=()
for test_dir in "${TEST_SEARCH_PATHS[@]}"; do
if [[ -d "$test_dir" ]]; then
if [[ -n "$FILTER" ]]; then
# Find test files matching filter
mapfile -t filtered_files < <(find "$test_dir" -name "*.bats" -exec grep -l "$FILTER" {} \; 2>/dev/null)
TEST_FILES+=("${filtered_files[@]}")
else
# Use all test files in directory
mapfile -t dir_files < <(find "$test_dir" -name "*.bats" 2>/dev/null)
TEST_FILES+=("${dir_files[@]}")
fi
fi
done
if [[ ${#TEST_FILES[@]} -eq 0 ]]; then
if [[ -n "$FILTER" ]]; then
echo -e "${YELLOW}No test files found matching filter: $FILTER${NC}"
else
echo -e "${YELLOW}No test files found in specified directories.${NC}"
fi
exit 0
fi
# Show test count only
if [[ "$COUNT_ONLY" == true ]]; then
total_tests=0
for file in "${TEST_FILES[@]}"; do
count=$(grep -c "^@test" "$file" 2>/dev/null || echo 0)
total_tests=$((total_tests + count))
done
echo "Total tests: $total_tests"
echo "Test files: ${#TEST_FILES[@]}"
echo "Test directories: ${#TEST_SEARCH_PATHS[@]}"
exit 0
fi
# Build BATS command
BATS_CMD="bats"
# Set output format
if [[ "$TAP" == true ]]; then
BATS_CMD+=" --formatter tap"
elif [[ "$PRETTY" == true ]]; then
BATS_CMD+=" --formatter pretty"
fi
# Enable verbose output
if [[ "$VERBOSE" == true ]]; then
BATS_CMD+=" --verbose-run"
fi
# Add filter if specified
if [[ -n "$FILTER" ]]; then
BATS_CMD+=" --filter '$FILTER'"
fi
# Add test files
BATS_CMD+=" ${TEST_FILES[*]}"
echo -e "${BLUE}Running AzerothCore Tests${NC}"
echo -e "${YELLOW}Test directories: ${TEST_SEARCH_PATHS[*]}${NC}"
echo -e "${YELLOW}Test files: ${#TEST_FILES[@]}${NC}"
if [[ -n "$FILTER" ]]; then
echo -e "${YELLOW}Filter: $FILTER${NC}"
fi
echo ""
# Run tests
if [[ "$DEBUG" == true ]]; then
echo -e "${YELLOW}Command: $BATS_CMD${NC}"
echo ""
fi
# Execute BATS
if eval "$BATS_CMD"; then
echo ""
echo -e "${GREEN}✅ All tests passed!${NC}"
exit 0
else
exit_code=$?
echo ""
echo -e "${RED}❌ Some tests failed!${NC}"
if [[ "$DEBUG" == true ]]; then
echo -e "${YELLOW}Tip: Check the output above for detailed error information${NC}"
echo -e "${YELLOW}You can also run individual tests for more detailed debugging:${NC}"
echo -e "${YELLOW} $0 --verbose --filter <test_name>${NC}"
fi
exit $exit_code
fi

5
conf/dist/config.sh vendored
View File

@ -14,6 +14,10 @@ BINPATH="$AC_PATH_ROOT/env/dist"
# Change it if you really know what you're doing.
# OSTYPE=""
# Configuration for the installer to skip the MySQL installation.
# This is useful when your MySQL is in a container or another machine.
SKIP_MYSQL_INSTALL=${SKIP_MYSQL_INSTALL:-false}
# When using linux, our installer automatically get information about your distro
# using lsb_release. If your distro is not supported but it's based on ubuntu or debian,
# please change it to one of these values.
@ -84,6 +88,7 @@ CCOREPCH=${CCOREPCH:-ON}
CAPPS_BUILD=${CAPPS_BUILD:-all}
# build tools list variable
# example: none, db-only, maps-only, all
CTOOLS_BUILD=${CTOOLS_BUILD:-none}
# build apps list

View File

@ -3,11 +3,12 @@ CREATE USER 'acore'@'localhost' IDENTIFIED BY 'acore' WITH MAX_QUERIES_PER_HOUR
GRANT ALL PRIVILEGES ON * . * TO 'acore'@'localhost' WITH GRANT OPTION;
CREATE DATABASE `acore_world` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci;
-- Create databases for AzerothCore, only if they do not exist
CREATE DATABASE IF NOT EXISTS `acore_world` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE `acore_characters` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `acore_characters` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE `acore_auth` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `acore_auth` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON `acore_world` . * TO 'acore'@'localhost' WITH GRANT OPTION;