Skip to content

Commit

Permalink
Tests (kinda) (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
haxtonsale authored Aug 25, 2019
1 parent 8f2d270 commit 02dfedc
Show file tree
Hide file tree
Showing 8 changed files with 422 additions and 15 deletions.
51 changes: 45 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ sudo: false
addons:
apt_packages:
- lib32stdc++6
- libc6
- libncurses5:i386
- libtinfo5:i386
- libcurl3-gnutls:i386

env:
- SMVERSION=1.10
- SMVERSION=1.10 MMVERSION=1.11

install:
- wget --input-file=http://sourcemod.net/smdrop/$SMVERSION/sourcemod-latest-linux
Expand All @@ -24,8 +28,43 @@ before_script:
- sed -i -e "s/public(HTTPRequestHandle:HTTPRequest, bool:requestSuccessful, HTTPStatusCode:statusCode),/function void (HTTPRequestHandle HTTPRequest, bool requestSuccessful, HTTPStatusCode statusCode);/g" include/steamtools.inc
- sed -i -e "s/public(HTTPRequestHandle:HTTPRequest, bool:requestSuccessful, HTTPStatusCode:statusCode, any:contextData),/function void (HTTPRequestHandle HTTPRequest, bool requestSuccessful, HTTPStatusCode statusCode, any contextData);/g" include/steamtools.inc

- chmod +x compile.sh
- mkdir compiled

script:
- ./compile.sh instagib.sp
- chmod +x ./spcomp

jobs:
include:
- stage: compile
script:
- ./spcomp instagib.sp
- stage: test
script:
- sed -i -e "s,//#define RUN_TESTS,#define RUN_TESTS,g" instagib.sp
- ./spcomp instagib.sp

- mv instagib.smx ../plugins

- cd ../../..

- wget "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz"
- mkdir steamcmd
- tar -xzf steamcmd_linux.tar.gz -C steamcmd
- cd steamcmd
- mkdir tf2
- ./steamcmd.sh +login anonymous +force_install_dir ./tf2 +app_update 232250 +quit
- cd ..
- cp -R addons/ steamcmd/tf2/tf/
- cd steamcmd/tf2/tf

- wget --input-file=https://mms.alliedmods.net/mmsdrop/$MMVERSION/mmsource-latest-linux
- tar -xzf $(cat mmsource-latest-linux)

- wget https://builds.limetech.io/files/tf2items-1.6.4-hg279-linux.zip
- unzip -n tf2items-1.6.4-hg279-linux.zip

- wget https://builds.limetech.io/files/steamtools-0.10.0-git179-54fdc51-linux.zip
- unzip -n steamtools-0.10.0-git179-54fdc51-linux.zip

- chmod -R +w ../

- ../srcds_run +map koth_nucleus +tf_allow_server_hibernation 0 +tf_bot_join_after_player 0 +sv_cheats 1 +mp_autoteambalance 0 || true

- if grep -q "1" addons/sourcemod/logs/test_result.txt; then exit 1; fi
283 changes: 283 additions & 0 deletions scripting/include/smtester.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
#if defined _smtester_included
#endinput
#endif
#define _smtester_included

// TODO: Add documentation lol

#include <profiler>

static int g_AllowedFails;
static bool g_ExitOnFinish;
static bool g_ShouldFinishOnResolve;

static ArrayList g_Tasks;
static StringMap g_AsyncTasks;
static Profiler g_Profiler;

enum SMTester_TaskType
{
TaskType_Node,
TaskType_GoBack,
TaskType_Assert,
TaskType_AsyncAssert_Pending,
TaskType_AsyncAssert_TimedOut,
TaskType_AsyncAssert_Finished,
}

enum struct SMTester_Task
{
SMTester_TaskType type;
char name[64];
any expect;

any result;
char reject_reason[256];
}

stock void SMTester_Start(int allowed_fails = 0, bool exit_on_finish = false)
{
g_AllowedFails = allowed_fails;
g_ExitOnFinish = exit_on_finish;

g_Tasks = new ArrayList(sizeof(SMTester_Task));
g_AsyncTasks = new StringMap();

g_Profiler = new Profiler();
g_Profiler.Start();
}

stock void SMTester_CreateNode(const char[] name)
{
SMTester_Task task;
task.type = TaskType_Node;
strcopy(task.name, sizeof(task.name), name);

g_Tasks.PushArray(task);
}

stock bool SMTester_GoBack(int times = 1)
{
SMTester_Task task;
task.type = TaskType_GoBack;
task.result = times;

g_Tasks.PushArray(task);
}

stock void SMTester_Assert(const char[] name, any value, any expect = true, const char[] reject_reason = "", any ...)
{
SMTester_Task task;
task.type = TaskType_Assert;
task.expect = expect;
task.result = value;
strcopy(task.name, sizeof(task.name), name);

char reject[256];
VFormat(reject, sizeof(reject), reject_reason, 5);
strcopy(task.reject_reason, sizeof(task.reject_reason), reject);

g_Tasks.PushArray(task);
}

// name must be unique.
stock void SMTester_Async(const char[] name, any expect = true, float timeout = 120.0)
{
SMTester_Task task;
task.type = TaskType_AsyncAssert_Pending;
strcopy(task.name, sizeof(task.name), name);
task.expect = expect;

int index = g_Tasks.PushArray(task);
g_AsyncTasks.SetValue(name, index);
CreateTimer(timeout, SMTester_Timer_AsyncTimeout, index);
}

stock void SMTester_AsyncAssert(const char[] name, any result, const char[] reject_reason = "", any ...)
{
if (g_AsyncTasks == null) {
return;
}

int index;
if (g_AsyncTasks.GetValue(name, index)) {
SMTester_Task task;
g_Tasks.GetArray(index, task);
task.type = TaskType_AsyncAssert_Finished;
task.result = result;

char reject[256];
VFormat(reject, sizeof(reject), reject_reason, 4);
strcopy(task.reject_reason, sizeof(task.reject_reason), reject);

g_Tasks.SetArray(index, task);
g_AsyncTasks.Remove(name);

CheckTasks();
}
}

stock void SMTester_Finish()
{
int tests;
int fails;
int currentnode = -1;

if (!g_ShouldFinishOnResolve) {
int len = g_Tasks.Length;
for (int i = 0; i < len; i ++) {
SMTester_Task task;
g_Tasks.GetArray(i, task);

if (task.type == TaskType_AsyncAssert_Pending) {
g_ShouldFinishOnResolve = true;
return;
}
}
}

PrintToServer("\nTest results: %i fails allowed", g_AllowedFails);

int len = g_Tasks.Length;
for (int i = 0; i < len; i ++) {
SMTester_Task task;
g_Tasks.GetArray(i, task);

switch (task.type) {
case (TaskType_Node): {
++currentnode;
PrintToServer("%s%s", GetPadding(currentnode), task.name);
++currentnode;
}

case (TaskType_GoBack): {
currentnode -= task.result*2;
}

case (TaskType_Assert): {
++tests;

if (task.result != task.expect) {
++fails;

char reject_msg[256];
if (task.reject_reason[0] != '\0') {
strcopy(reject_msg, sizeof(reject_msg), task.reject_reason);
} else {
FormatEx(reject_msg, sizeof(reject_msg), "Expected %i, got %i", task.expect, task.result);
}

PrintToServer("%s(-) %s: %s", GetPadding(currentnode), task.name, reject_msg);
} else {
PrintToServer("%s(+) %s", GetPadding(currentnode), task.name);
}
}

case (TaskType_AsyncAssert_TimedOut): {
++tests;
++fails;

PrintToServer("%s(-) %s: Timed out", GetPadding(currentnode), task.name);
}

case (TaskType_AsyncAssert_Finished): {
++tests;

if (task.result != task.expect) {
++fails;

char reject_msg[64];
if (task.reject_reason[0] != '\0') {
strcopy(reject_msg, sizeof(reject_msg), task.reject_reason);
} else {
FormatEx(reject_msg, sizeof(reject_msg), "Expected %i, got %i", task.expect, task.result);
}

PrintToServer("%s(-) %s: %s", GetPadding(currentnode), task.name, reject_msg);
} else {
PrintToServer("%s(+) %s", GetPadding(currentnode), task.name);
}
}
}
}

g_Profiler.Stop();

PrintToServer("\n%i %s passing (%ims)", tests - fails, tests - fails == 1 ? "test" : "tests", RoundFloat(g_Profiler.Time*1000.0));

if (fails) {
PrintToServer("%i %s failing", fails, fails == 1 ? "test" : "tests");
}

PrintToServer(" ");

if (fails > g_AllowedFails) {
Exit(1);
SetFailState("%i Failed %s", fails, fails == 1 ? "Test" : "Tests");
} else {
Exit(0);
}

delete g_Tasks;
delete g_AsyncTasks;
delete g_Profiler;
}

static stock char GetPadding(int nodes)
{
char padding[256];

for (int i = 0; i < nodes; i++) {
Format(padding, sizeof(padding), " %s", padding);
}

return padding;
}

// Lame workaround because i can't exit srcds with code 0 through sm
static stock void Exit(int code)
{
if (g_ExitOnFinish) {
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "/logs/test_result.txt");

Handle file = OpenFile(path, "w");
char codestr[16];
IntToString(code, codestr, sizeof(codestr));
WriteFileString(file, codestr, false);
delete file;

ServerCommand("exit");
}
}

static stock void CheckTasks()
{
if (g_ShouldFinishOnResolve) {
int len = g_Tasks.Length;
for (int i = 0; i < len; i ++) {
SMTester_Task task;
g_Tasks.GetArray(i, task);

// If we still have pending tasks, finish when all of them are finished/timed out
if (task.type == TaskType_AsyncAssert_Pending) {
return;
}
}
SMTester_Finish();
}
}

public Action SMTester_Timer_AsyncTimeout(Handle timer, int index)
{
if (g_Tasks != null) {
SMTester_Task task;
g_Tasks.GetArray(index, task);
if (task.type != TaskType_AsyncAssert_Finished) {
task.type = TaskType_AsyncAssert_TimedOut;
g_Tasks.SetArray(index, task);

CheckTasks();
}
}
}
Loading

0 comments on commit 02dfedc

Please sign in to comment.