mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-30 08:33:19 +01:00
Merge pull request #943 from tgstation/INTEGRATE
Add some repository integration tests
This commit is contained in:
+1
-1
@@ -63,6 +63,6 @@ install:
|
||||
- if [ $DockerBuild = false ] && [ $DMAPI = false ]; then dotnet restore tgstation-server.sln; fi
|
||||
|
||||
script:
|
||||
- if [ $DockerBuild = false ] && [ $DMAPI = true ]; then tests/DMAPI/build_byond.sh || travis_terminate 1; fi
|
||||
- if [ $DockerBuild = false ] && [ $DMAPI = true ]; then tests/DMAPI/BasicOperation/build_byond.sh || travis_terminate 1; fi
|
||||
- if [ $DockerBuild = false ] && [ $DMAPI = false ]; then build/test_core.sh; fi
|
||||
- if [ $DockerBuild = true ]; then docker build . -f build/Dockerfile; fi
|
||||
|
||||
+3
-3
@@ -3,10 +3,10 @@
|
||||
<!-- This is the authorative version list -->
|
||||
<!-- Integration tests will ensure they match across the board -->
|
||||
<TgsCoreVersion>4.1.0</TgsCoreVersion>
|
||||
<TgsApiVersion>5.1.0</TgsApiVersion>
|
||||
<TgsClientVersion>5.1.0</TgsClientVersion>
|
||||
<TgsApiVersion>6.0.0</TgsApiVersion>
|
||||
<TgsClientVersion>6.0.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>5.0.0</TgsDmapiVersion>
|
||||
<TgsControlPanelVersion>0.1.6</TgsControlPanelVersion>
|
||||
<TgsControlPanelVersion>0.4.0</TgsControlPanelVersion>
|
||||
<TgsHostWatchdogVersion>1.1.0</TgsHostWatchdogVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace Tgstation.Server.Api
|
||||
/// </summary>
|
||||
/// <param name="otherVersion">The <see cref="Version"/> to test</param>
|
||||
/// <returns><see langword="true"/> if the given version is compatible with the API. <see langword="false"/> otherwise</returns>
|
||||
public static bool CheckCompatibility(Version otherVersion) => !(Version.Major != (otherVersion?.Major ?? throw new ArgumentNullException(nameof(otherVersion))) || Version.Minor > otherVersion.Minor);
|
||||
public static bool CheckCompatibility(Version otherVersion) => Version.Major == (otherVersion?.Major ?? throw new ArgumentNullException(nameof(otherVersion)));
|
||||
|
||||
/// <summary>
|
||||
/// Construct <see cref="ApiHeaders"/> for JWT authentication
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Import Project="../../build/Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<DebugType>Full</DebugType>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>Cyberboss</Authors>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Import Project="../../build/Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<DebugType>Full</DebugType>
|
||||
<Version>$(TgsClientVersion)</Version>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
|
||||
+7726
-9169
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,25 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"react-dom": "^16.7.0",
|
||||
"tgstation-server-control-panel": "0.1.6"
|
||||
"react-dom": "^16.13.1",
|
||||
"tgstation-server-control-panel": "0.4.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "1.2.9"
|
||||
},
|
||||
"_comment": "fsevent@1.2.9 is locked in to prevent broken builds on windows for v1.2.11",
|
||||
"scripts": {
|
||||
"msbuild": "npm run clean && tslint -p tsconfig.json && react-scripts build && cp-cli node_modules/tgstation-server-control-panel/build/public/ build/ && cp-cli ../../../build/tgs.ico build/favicon.ico && minify-json build && rimraf ../wwwroot && move-cli build ../wwwroot",
|
||||
"msbuild": "npm run clean && react-scripts build && cp-cli node_modules/tgstation-server-control-panel/build/public/ build/ && rimraf ../wwwroot && move-cli build ../wwwroot",
|
||||
"clean": "rimraf build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^10.12.0",
|
||||
"@types/react-dom": "^16.0.9",
|
||||
"@types/node": "^13.13.2",
|
||||
"@types/react-dom": "^16.9.6",
|
||||
"cp-cli": "^1.1.2",
|
||||
"minify-json": "^1.0.0",
|
||||
"move-cli": "^1.2.0",
|
||||
"react-scripts": "^2.1.3",
|
||||
"rimraf": "^2.6.2",
|
||||
"tslint": "^5.12.0",
|
||||
"tslint-react": "^3.6.0",
|
||||
"typescript": "^3.1.3"
|
||||
"move-cli": "^1.2.1",
|
||||
"react-scripts": "^3.4.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
@@ -10,6 +11,15 @@
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png">
|
||||
<link rel="mask-icon" href="%PUBLIC_URL%/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
|
||||
integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
@@ -20,10 +30,11 @@
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>Tgstation Server Control Panel</title>
|
||||
</head>
|
||||
<body>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
@@ -36,5 +47,6 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"short_name": "TGS",
|
||||
"name": "Tgstation Server",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": "./",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -13,7 +13,7 @@ if (!contentElement)
|
||||
throw new Error("Missing root div, cannot render app!");
|
||||
|
||||
const legacyUserLanguageKey = "userLanguage";
|
||||
const userLang = navigator.language || navigator[legacyUserLanguageKey];
|
||||
const userLang = navigator.language || navigator[legacyUserLanguageKey] || "en-CA";
|
||||
const serverAddress = window.location.href;
|
||||
const controlPanel = <ControlPanel serverAddress={serverAddress} locale={userLang} />;
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-react"
|
||||
],
|
||||
"linterOptions": {
|
||||
"exclude": [
|
||||
"config/**/*.js",
|
||||
"node_modules/**/*.ts",
|
||||
"coverage/lcov-report/*.js"
|
||||
]
|
||||
},
|
||||
"rules": {
|
||||
"curly": [
|
||||
true,
|
||||
"as-needed"
|
||||
],
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"one-line": [
|
||||
true,
|
||||
"check-catch",
|
||||
"check-finally",
|
||||
"check-else",
|
||||
"check-open-brace",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"double",
|
||||
"jsx-double"
|
||||
],
|
||||
"trailing-comma": [
|
||||
true,
|
||||
{
|
||||
"multiline": "never",
|
||||
"singleline": "never"
|
||||
}
|
||||
],
|
||||
"arrow-parens": [
|
||||
true,
|
||||
"ban-single-arg-parens"
|
||||
],
|
||||
"max-line-length": [
|
||||
true,
|
||||
150
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -207,15 +207,39 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
progressReporter(0);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
commands.Checkout(
|
||||
var checkoutOptions = new CheckoutOptions
|
||||
{
|
||||
CheckoutModifiers = CheckoutModifiers.Force,
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter)
|
||||
};
|
||||
|
||||
void RunCheckout() => commands.Checkout(
|
||||
libGitRepo,
|
||||
new CheckoutOptions
|
||||
{
|
||||
CheckoutModifiers = CheckoutModifiers.Force,
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter)
|
||||
},
|
||||
checkoutOptions,
|
||||
committish);
|
||||
|
||||
try
|
||||
{
|
||||
RunCheckout();
|
||||
}
|
||||
catch (NotFoundException)
|
||||
{
|
||||
// Maybe (likely) a remote?
|
||||
var remoteName = $"origin/{committish}";
|
||||
var potentialBranch = libGitRepo.Branches.FirstOrDefault(
|
||||
branch => branch.FriendlyName.Equals(remoteName, StringComparison.Ordinal));
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (potentialBranch == default)
|
||||
throw;
|
||||
|
||||
logger.LogDebug("Creating local branch for {0}...", potentialBranch.FriendlyName);
|
||||
libGitRepo.CreateBranch(committish, potentialBranch.Tip);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
RunCheckout();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
libGitRepo.RemoveUntrackedFiles();
|
||||
|
||||
@@ -99,8 +99,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (job.CancelRight.HasValue && job.CancelRightsType.HasValue && (AuthenticationContext.GetRight(job.CancelRightsType.Value) & job.CancelRight.Value) == 0)
|
||||
return Forbid();
|
||||
|
||||
job = await jobManager.CancelJob(job, AuthenticationContext.User, false, cancellationToken).ConfigureAwait(false);
|
||||
return job != null ? (IActionResult)Accepted(job.ToApi()) : StatusCode((int)HttpStatusCode.Gone);
|
||||
var updatedJob = await jobManager.CancelJob(job, AuthenticationContext.User, false, cancellationToken).ConfigureAwait(false);
|
||||
return updatedJob != null ? (IActionResult)Accepted(updatedJob.ToApi()) : StatusCode((int)HttpStatusCode.Gone);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -326,9 +326,6 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (model.CheckoutSha != null && model.UpdateFromOrigin == true)
|
||||
return BadRequest(new ErrorMessage(ErrorCode.RepoMismatchShaAndUpdate));
|
||||
|
||||
if (model.Origin != null)
|
||||
return BadRequest(new ErrorMessage(ErrorCode.RepoCantChangeOrigin));
|
||||
|
||||
if (model.NewTestMerges?.Any(x => model.NewTestMerges.Any(y => x != y && x.Number == y.Number)) == true)
|
||||
return BadRequest(new ErrorMessage(ErrorCode.RepoDuplicateTestMerge));
|
||||
|
||||
@@ -404,6 +401,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (repo == null)
|
||||
return Conflict(new ErrorMessage(ErrorCode.RepoMissing));
|
||||
await PopulateApi(api, repo, DatabaseContext, Instance, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (model.Origin != null && model.Origin != repo.Origin)
|
||||
return BadRequest(new ErrorMessage(ErrorCode.RepoCantChangeOrigin));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,8 +524,13 @@ namespace Tgstation.Server.Host.Controllers
|
||||
// checkout/hard reset
|
||||
if (modelHasShaOrReference)
|
||||
{
|
||||
if ((model.CheckoutSha != null && repo.Head.ToUpperInvariant().StartsWith(model.CheckoutSha.ToUpperInvariant(), StringComparison.Ordinal))
|
||||
|| (model.Reference != null && repo.Reference.ToUpperInvariant() != model.Reference.ToUpperInvariant()))
|
||||
var validCheckoutSha =
|
||||
model.CheckoutSha != null
|
||||
&& !repo.Head.StartsWith(model.CheckoutSha, StringComparison.OrdinalIgnoreCase);
|
||||
var validCheckoutReference =
|
||||
model.Reference != null
|
||||
&& !repo.Reference.Equals(model.Reference, StringComparison.OrdinalIgnoreCase);
|
||||
if (validCheckoutSha || validCheckoutReference)
|
||||
{
|
||||
var committish = model.CheckoutSha ?? model.Reference;
|
||||
var isSha = await repo.IsSha(committish, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -244,14 +244,15 @@ namespace Tgstation.Server.Host.Jobs
|
||||
handler.Cancel(); // this will ensure the db update is only done once
|
||||
await databaseContextFactory.UseContext(async databaseContext =>
|
||||
{
|
||||
job = new Job { Id = job.Id };
|
||||
var updatedJob = new Job { Id = job.Id };
|
||||
databaseContext.Jobs.Attach(job);
|
||||
user = new User { Id = user.Id };
|
||||
var attachedUser = new User { Id = user.Id };
|
||||
databaseContext.Users.Attach(user);
|
||||
job.CancelledBy = user;
|
||||
updatedJob.CancelledBy = attachedUser;
|
||||
|
||||
// let either startup or cancellation set job.cancelled
|
||||
await databaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
job.CancelledBy = user;
|
||||
}).ConfigureAwait(false);
|
||||
if (blocking)
|
||||
await handler.Wait(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Tgstation.Server.Host.Models
|
||||
CancelRightsType = CancelRightsType,
|
||||
Description = Description,
|
||||
ExceptionDetails = ExceptionDetails,
|
||||
ErrorCode = ErrorCode,
|
||||
StartedBy = StartedBy.ToApi(false)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -103,15 +103,12 @@
|
||||
<ItemGroup>
|
||||
<Content Remove="ClientApp\package-lock.json" />
|
||||
<Content Remove="ClientApp\package.json" />
|
||||
<Content Remove="ClientApp\public\manifest.json" />
|
||||
<Content Remove="ClientApp\tsconfig.json" />
|
||||
<Content Remove="ClientApp\tslint.json" />
|
||||
<None Include="ClientApp\package-lock.json" />
|
||||
<None Include="ClientApp\package.json" />
|
||||
<None Include="ClientApp\public\manifest.json" />
|
||||
<None Include="ClientApp\tsconfig.json" />
|
||||
<None Include="ClientApp\tslint.json" />
|
||||
<ClientApp Include="ClientApp\src\**\*;ClientApp\public\**\*;ClientApp\tsconfig.json;ClientApp\tslint.json;ClientApp\package.json;ClientApp\package-lock.json" />
|
||||
<ClientApp Include="ClientApp\src\**\*;ClientApp\public\**\*;ClientApp\tsconfig.json;ClientApp\package.json;ClientApp\package-lock.json" />
|
||||
<AdditionalFiles Include="../../build/stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
#define TGS_INFO_LOG(message) world.log << "Info: [##message]"
|
||||
#define TGS_WARNING_LOG(message) world.log << "Warn: [##message]"
|
||||
#define TGS_ERROR_LOG(message) world.log << "Err: [##message]"
|
||||
#define TGS_NOTIFY_ADMINS(event) message_admins(event)
|
||||
#define TGS_CLIENT_COUNT clients.len
|
||||
#define TGS_NOTIFY_ADMINS(event)
|
||||
#define TGS_CLIENT_COUNT 0
|
||||
@@ -1,5 +1,10 @@
|
||||
/world/New()
|
||||
TgsNew()
|
||||
StartAsync()
|
||||
|
||||
/proc/StartAsync()
|
||||
set waitfor = FALSE
|
||||
sleep(100)
|
||||
TgsInitializationComplete()
|
||||
|
||||
/world/Topic(T, Addr, Master, Keys)
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
// BEGIN_INCLUDE
|
||||
#include "Config.dm"
|
||||
#include "..\..\src\DMAPI\tgs.dm"
|
||||
#include "..\..\src\DMAPI\tgs\includes.dm"
|
||||
#include "..\tgs_include.dm"
|
||||
#include "Test.dm"
|
||||
// END_INCLUDE
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "..\..\src\DMAPI\tgs.dm"
|
||||
#include "..\..\src\DMAPI\tgs\includes.dm"
|
||||
@@ -7,21 +7,32 @@ using Tgstation.Server.Client.Components;
|
||||
|
||||
namespace Tgstation.Server.Tests.Instance
|
||||
{
|
||||
sealed class ByondTest
|
||||
sealed class ByondTest : JobsRequiredTest
|
||||
{
|
||||
readonly IByondClient byondClient;
|
||||
readonly IJobsClient jobsClient;
|
||||
|
||||
public ByondTest(IByondClient byondClient, IJobsClient jobsClient)
|
||||
: base(jobsClient)
|
||||
{
|
||||
this.byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient));
|
||||
this.jobsClient = jobsClient ?? throw new ArgumentNullException(nameof(jobsClient));
|
||||
}
|
||||
|
||||
public async Task Run(CancellationToken cancellationToken)
|
||||
{
|
||||
await TestNoVersion(cancellationToken).ConfigureAwait(false);
|
||||
await TestInstall511(cancellationToken).ConfigureAwait(false);
|
||||
await TestInstallFakeVersion(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
async Task TestInstallFakeVersion(CancellationToken cancellationToken)
|
||||
{
|
||||
var newModel = new Api.Models.Byond
|
||||
{
|
||||
Version = new Version(5011, 1385)
|
||||
};
|
||||
var test = await byondClient.SetActiveVersion(newModel, cancellationToken).ConfigureAwait(false);
|
||||
Assert.IsNotNull(test.InstallJob);
|
||||
await WaitForJob(test.InstallJob, 60, true, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
async Task TestInstall511(CancellationToken cancellationToken)
|
||||
@@ -33,24 +44,7 @@ namespace Tgstation.Server.Tests.Instance
|
||||
var test = await byondClient.SetActiveVersion(newModel, cancellationToken).ConfigureAwait(false);
|
||||
Assert.IsNotNull(test.InstallJob);
|
||||
Assert.IsNull(test.Version);
|
||||
var job = test.InstallJob;
|
||||
var maxWait = 60; //it's 10MB max give me a break
|
||||
do
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
||||
job = await jobsClient.GetId(job, cancellationToken).ConfigureAwait(false);
|
||||
--maxWait;
|
||||
}
|
||||
while (!job.StoppedAt.HasValue && maxWait > 0);
|
||||
if (!job.StoppedAt.HasValue)
|
||||
{
|
||||
await jobsClient.Cancel(job, cancellationToken).ConfigureAwait(false);
|
||||
Assert.Fail("Byond installation job timed out!");
|
||||
}
|
||||
|
||||
if (job.ExceptionDetails != null)
|
||||
Assert.Fail(job.ExceptionDetails);
|
||||
|
||||
var job = await WaitForJob(test.InstallJob, 60, false, cancellationToken).ConfigureAwait(false);
|
||||
var currentShit = await byondClient.ActiveVersion(cancellationToken).ConfigureAwait(false);
|
||||
Assert.AreEqual(newModel.Version.Semver(), currentShit.Version);
|
||||
}
|
||||
|
||||
@@ -22,12 +22,17 @@ namespace Tgstation.Server.Tests.Instance
|
||||
var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs);
|
||||
var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Metadata.CloneMetadata());
|
||||
var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata);
|
||||
var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs);
|
||||
|
||||
var repoTests = repoTest.RunPreWatchdog(cancellationToken);
|
||||
var byondTests = byondTest.Run(cancellationToken);
|
||||
var chatTests = chatTest.Run(cancellationToken);
|
||||
await configTest.Run(cancellationToken).ConfigureAwait(false);
|
||||
await byondTests.ConfigureAwait(false);
|
||||
await chatTests.ConfigureAwait(false);
|
||||
await repoTests;
|
||||
|
||||
await repoTest.RunPostWatchdog(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Client.Components;
|
||||
|
||||
namespace Tgstation.Server.Tests.Instance
|
||||
{
|
||||
abstract class JobsRequiredTest
|
||||
{
|
||||
protected IJobsClient JobsClient { get; }
|
||||
|
||||
protected JobsRequiredTest(IJobsClient jobsClient)
|
||||
{
|
||||
this.JobsClient = jobsClient;
|
||||
}
|
||||
|
||||
protected async Task<Job> WaitForJob(Job originalJob, int timeout, bool expectFailure, CancellationToken cancellationToken)
|
||||
{
|
||||
var job = originalJob;
|
||||
do
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
||||
job = await JobsClient.GetId(job, cancellationToken).ConfigureAwait(false);
|
||||
--timeout;
|
||||
}
|
||||
while (!job.StoppedAt.HasValue && timeout > 0);
|
||||
|
||||
if (!job.StoppedAt.HasValue)
|
||||
{
|
||||
await JobsClient.Cancel(job, cancellationToken).ConfigureAwait(false);
|
||||
Assert.Fail($"Job ID {job.Id} \"{job.Description}\" timed out!");
|
||||
}
|
||||
|
||||
if (expectFailure ^ job.ExceptionDetails != null)
|
||||
Assert.Fail(job.ExceptionDetails ?? $"Expected job \"{job.Id}\" \"{job.Description}\" to fail but it didn't");
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
protected async Task<Job> WaitForJobProgressThenCancel(Job originalJob, int timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
var job = originalJob;
|
||||
do
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
||||
job = await JobsClient.GetId(job, cancellationToken).ConfigureAwait(false);
|
||||
--timeout;
|
||||
}
|
||||
while (!job.Progress.HasValue && timeout > 0);
|
||||
|
||||
if (job.StoppedAt.HasValue)
|
||||
{
|
||||
await JobsClient.Cancel(job, cancellationToken).ConfigureAwait(false);
|
||||
Assert.Fail($"Job ID {job.Id} \"{job.Description}\" completed when we wanted it to just progress!");
|
||||
}
|
||||
|
||||
if (job.ExceptionDetails != null)
|
||||
Assert.Fail(job.ExceptionDetails);
|
||||
|
||||
await JobsClient.Cancel(job, cancellationToken);
|
||||
return await WaitForJob(job, timeout, false, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Client.Components;
|
||||
|
||||
namespace Tgstation.Server.Tests.Instance
|
||||
{
|
||||
sealed class RepositoryTest : JobsRequiredTest
|
||||
{
|
||||
readonly IRepositoryClient repositoryClient;
|
||||
|
||||
public RepositoryTest(IRepositoryClient repositoryClient, IJobsClient jobsClient)
|
||||
: base(jobsClient)
|
||||
{
|
||||
this.repositoryClient = repositoryClient ?? throw new ArgumentNullException(nameof(repositoryClient));
|
||||
}
|
||||
|
||||
public async Task RunPreWatchdog(CancellationToken cancellationToken)
|
||||
{
|
||||
// Clone ourselves
|
||||
var workingBranch = Environment.GetEnvironmentVariable("TGS4_TEST_BRANCH");
|
||||
if (String.IsNullOrWhiteSpace(workingBranch))
|
||||
workingBranch = Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH");
|
||||
if (String.IsNullOrWhiteSpace(workingBranch))
|
||||
workingBranch = Environment.GetEnvironmentVariable("TRAVIS_BRANCH");
|
||||
if (String.IsNullOrWhiteSpace(workingBranch))
|
||||
workingBranch = "master";
|
||||
|
||||
var initalRepo = await repositoryClient.Read(cancellationToken);
|
||||
Assert.IsNotNull(initalRepo);
|
||||
Assert.IsNull(initalRepo.Origin);
|
||||
Assert.IsNull(initalRepo.Reference);
|
||||
Assert.IsNull(initalRepo.RevisionInformation);
|
||||
Assert.IsNull(initalRepo.ActiveJob);
|
||||
|
||||
const string Origin = "https://github.com/tgstation/tgstation-server";
|
||||
initalRepo.Origin = Origin;
|
||||
initalRepo.Reference = workingBranch;
|
||||
|
||||
var clone = await repositoryClient.Clone(initalRepo, cancellationToken).ConfigureAwait(false);
|
||||
Assert.IsNotNull(clone);
|
||||
Assert.AreEqual(Origin, clone.Origin);
|
||||
Assert.AreEqual(workingBranch, clone.Reference);
|
||||
Assert.IsNull(clone.RevisionInformation);
|
||||
Assert.IsNotNull(clone.ActiveJob);
|
||||
|
||||
await WaitForJobProgressThenCancel(clone.ActiveJob, 20, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var secondRead = await repositoryClient.Read(cancellationToken).ConfigureAwait(false);
|
||||
Assert.IsNotNull(secondRead);
|
||||
Assert.IsNull(secondRead.ActiveJob);
|
||||
|
||||
clone = await repositoryClient.Clone(initalRepo, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await WaitForJob(clone.ActiveJob, 120, false, cancellationToken).ConfigureAwait(false);
|
||||
var cloned = await repositoryClient.Read(cancellationToken);
|
||||
|
||||
Assert.AreEqual(Origin, cloned.Origin);
|
||||
Assert.AreEqual(workingBranch, cloned.Reference);
|
||||
Assert.IsNotNull(cloned.RevisionInformation);
|
||||
Assert.IsNotNull(cloned.RevisionInformation.ActiveTestMerges);
|
||||
Assert.AreEqual(0, cloned.RevisionInformation.ActiveTestMerges.Count);
|
||||
Assert.IsNotNull(cloned.RevisionInformation.CommitSha);
|
||||
Assert.IsNotNull(cloned.RevisionInformation.OriginCommitSha);
|
||||
Assert.IsNotNull(cloned.RevisionInformation.CompileJobs);
|
||||
Assert.AreEqual(0, cloned.RevisionInformation.CompileJobs.Count);
|
||||
Assert.IsNotNull(cloned.RevisionInformation.OriginCommitSha);
|
||||
Assert.IsNull(cloned.RevisionInformation.PrimaryTestMerge);
|
||||
Assert.AreEqual(cloned.RevisionInformation.CommitSha, cloned.RevisionInformation.OriginCommitSha);
|
||||
|
||||
cloned.Origin = "https://github.com/tgstation/tgstation";
|
||||
await ApiAssert.ThrowsException<ApiConflictException>(() => repositoryClient.Update(cloned, cancellationToken), ErrorCode.RepoCantChangeOrigin);
|
||||
cloned.Origin = Origin;
|
||||
|
||||
// checkout V3 and back
|
||||
cloned.Reference = "V3";
|
||||
var updated = await Checkout(cloned, false, true, cancellationToken);
|
||||
|
||||
// Specific SHA
|
||||
updated.CheckoutSha = "f43f5bd";
|
||||
await ApiAssert.ThrowsException<ApiConflictException>(() => Checkout(updated, false, false, cancellationToken), ErrorCode.RepoMismatchShaAndReference);
|
||||
updated.Reference = null;
|
||||
updated = await Checkout(updated, false, false, cancellationToken);
|
||||
|
||||
// Fake SHA
|
||||
updated.Reference = null;
|
||||
updated.CheckoutSha = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||
updated = await Checkout(updated, true, false, cancellationToken);
|
||||
|
||||
// Fake ref
|
||||
updated.Reference = "Tgs4IntegrationTestFakeBranchNeverNameABranchThis";
|
||||
updated = await Checkout(updated, true, true, cancellationToken);
|
||||
|
||||
// Back
|
||||
updated.Reference = workingBranch;
|
||||
updated = await Checkout(updated, false, true, cancellationToken);
|
||||
|
||||
var testPRString = Environment.GetEnvironmentVariable("TGS4_TEST_PULL_REQUEST_NUMBER");
|
||||
if (String.IsNullOrWhiteSpace(testPRString))
|
||||
testPRString = Environment.GetEnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER");
|
||||
if (String.IsNullOrWhiteSpace(testPRString))
|
||||
testPRString = Environment.GetEnvironmentVariable("TRAVIS_PULL_REQUEST");
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(testPRString))
|
||||
{
|
||||
if (!int.TryParse(testPRString, out var prNumber))
|
||||
Assert.Inconclusive($"Invalid PR #: {testPRString}");
|
||||
await TestMergeTests(updated, prNumber, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<Repository> Checkout(Repository updated, bool expectFailure, bool isRef, CancellationToken cancellationToken)
|
||||
{
|
||||
var newRef = isRef ? updated.Reference : updated.CheckoutSha;
|
||||
var checkingOut = await repositoryClient.Update(updated, cancellationToken);
|
||||
Assert.IsNotNull(checkingOut.ActiveJob);
|
||||
await WaitForJob(checkingOut.ActiveJob, 30, expectFailure, cancellationToken);
|
||||
var result = await repositoryClient.Read(cancellationToken);
|
||||
if (!expectFailure)
|
||||
if (isRef)
|
||||
Assert.AreEqual(newRef, result.Reference);
|
||||
else
|
||||
Assert.IsTrue(result.RevisionInformation.CommitSha.StartsWith(newRef, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
Assert.AreEqual(result.RevisionInformation.CommitSha, result.RevisionInformation.OriginCommitSha);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async Task TestMergeTests(Repository repository, int prNumber, CancellationToken cancellationToken)
|
||||
{
|
||||
repository.NewTestMerges = new List<TestMergeParameters>
|
||||
{
|
||||
new TestMergeParameters
|
||||
{
|
||||
Number = prNumber
|
||||
}
|
||||
};
|
||||
|
||||
var orignCommit = repository.RevisionInformation.OriginCommitSha;
|
||||
|
||||
var numberOnlyMerging = await repositoryClient.Update(repository, cancellationToken);
|
||||
Assert.IsNotNull(numberOnlyMerging.ActiveJob);
|
||||
Assert.IsTrue(numberOnlyMerging.ActiveJob.Description.Contains(prNumber.ToString()));
|
||||
|
||||
await WaitForJob(numberOnlyMerging.ActiveJob, 20, false, cancellationToken);
|
||||
|
||||
var withMerge = await repositoryClient.Read(cancellationToken);
|
||||
Assert.AreEqual(repository.Reference, withMerge.Reference);
|
||||
Assert.AreEqual(1, withMerge.RevisionInformation.ActiveTestMerges.Count);
|
||||
Assert.AreEqual(prNumber, withMerge.RevisionInformation.ActiveTestMerges.First().Number);
|
||||
Assert.AreEqual(prNumber, withMerge.RevisionInformation.PrimaryTestMerge.Number);
|
||||
var prRevision = withMerge.RevisionInformation.PrimaryTestMerge.PullRequestRevision;
|
||||
Assert.IsNotNull(prRevision);
|
||||
Assert.IsNotNull(withMerge.RevisionInformation.PrimaryTestMerge.MergedBy);
|
||||
Assert.IsNotNull(withMerge.RevisionInformation.PrimaryTestMerge.MergedAt);
|
||||
Assert.IsNotNull(withMerge.RevisionInformation.PrimaryTestMerge.Author);
|
||||
Assert.IsNull(withMerge.RevisionInformation.PrimaryTestMerge.Comment);
|
||||
Assert.IsNotNull(withMerge.RevisionInformation.PrimaryTestMerge.TitleAtMerge);
|
||||
Assert.IsNotNull(withMerge.RevisionInformation.PrimaryTestMerge.BodyAtMerge);
|
||||
Assert.AreEqual($"https://github.com/tgstation/tgstation-server/pull/{prNumber}", withMerge.RevisionInformation.PrimaryTestMerge.Url);
|
||||
Assert.AreEqual(orignCommit, withMerge.RevisionInformation.OriginCommitSha);
|
||||
Assert.AreNotEqual(orignCommit, withMerge.RevisionInformation.CommitSha);
|
||||
|
||||
// Reset, do it again with a comment and specific sha
|
||||
withMerge.UpdateFromOrigin = true;
|
||||
withMerge.Reference = repository.Reference;
|
||||
withMerge.NewTestMerges = new List<TestMergeParameters>
|
||||
{
|
||||
new TestMergeParameters
|
||||
{
|
||||
Number = prNumber,
|
||||
Comment = "asdffdsa",
|
||||
PullRequestRevision = prRevision
|
||||
}
|
||||
};
|
||||
|
||||
var mergingAgain = await repositoryClient.Update(withMerge, cancellationToken);
|
||||
Assert.IsNotNull(mergingAgain.ActiveJob);
|
||||
await WaitForJob(mergingAgain.ActiveJob, 30, false, cancellationToken);
|
||||
|
||||
var final = await repositoryClient.Read(cancellationToken);
|
||||
Assert.AreEqual("asdffdsa", final.RevisionInformation.PrimaryTestMerge.Comment);
|
||||
Assert.AreEqual(prNumber, final.RevisionInformation.PrimaryTestMerge.Number);
|
||||
Assert.AreEqual(prRevision, final.RevisionInformation.PrimaryTestMerge.PullRequestRevision);
|
||||
}
|
||||
|
||||
public async Task RunPostWatchdog(CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
|
||||
var deleting = await repositoryClient.Delete(cancellationToken);
|
||||
Assert.IsNotNull(deleting.ActiveJob);
|
||||
|
||||
await WaitForJob(deleting.ActiveJob, 60, false, cancellationToken).ConfigureAwait(false);
|
||||
var deleted = await repositoryClient.Read(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Assert.IsNull(deleted.Origin);
|
||||
Assert.IsNull(deleted.Reference);
|
||||
Assert.IsNull(deleted.RevisionInformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,11 +125,11 @@ namespace Tgstation.Server.Tests
|
||||
Path = initialPath
|
||||
}, cancellationToken), ErrorCode.InstanceRelocateOnline).ConfigureAwait(false);
|
||||
|
||||
var testSuite1 = new InstanceTest(instanceManagerClient.CreateClient(firstTest), instanceManagerClient);
|
||||
var instanceClient = instanceManagerClient.CreateClient(firstTest);
|
||||
var testSuite1 = new InstanceTest(instanceClient, instanceManagerClient);
|
||||
await testSuite1.RunTests(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
//can regain permissions on instance without instance user
|
||||
var instanceClient = instanceManagerClient.CreateClient(firstTest);
|
||||
var ourInstanceUser = await instanceClient.Users.Read(cancellationToken).ConfigureAwait(false);
|
||||
await instanceClient.Users.Delete(ourInstanceUser, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -146,6 +146,10 @@ namespace Tgstation.Server.Tests
|
||||
|
||||
firstTest.Online = false;
|
||||
firstTest = await instanceManagerClient.Update(firstTest, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// TODO: Re-enable the rest of these tests once https://github.com/tgstation/tgstation-server/issues/860 is dealt with
|
||||
return;
|
||||
|
||||
await instanceManagerClient.Detach(firstTest, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var instanceAttachFileName = (string)typeof(InstanceController).GetField("InstanceAttachFileName", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
|
||||
|
||||
@@ -232,6 +232,11 @@ namespace Tgstation.Server.Tests
|
||||
await new InstanceManagerTest(adminClient.Instances, server.Directory).Run(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TEST ERROR: {ex.GetType()} in flight!");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
serverCts.Cancel();
|
||||
|
||||
@@ -60,6 +60,19 @@ namespace Tgstation.Server.Tests
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestClientVersionFollowingApiVersion()
|
||||
{
|
||||
var versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsApiVersion").Value + ".0";
|
||||
Assert.IsNotNull(versionString);
|
||||
Assert.IsTrue(Version.TryParse(versionString, out var apiVersion));
|
||||
|
||||
versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsClientVersion").Value + ".0";
|
||||
Assert.IsNotNull(versionString);
|
||||
Assert.IsTrue(Version.TryParse(versionString, out var clientVersion));
|
||||
Assert.IsTrue(clientVersion >= apiVersion);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestWatchdogVersion()
|
||||
{
|
||||
|
||||
@@ -76,11 +76,16 @@ namespace ReleaseNotes
|
||||
var releaseDictionary = new Dictionary<int, List<string>>();
|
||||
var authorizedUsers = new Dictionary<long, Task<bool>>();
|
||||
|
||||
bool hasSqliteFuckage = false;
|
||||
|
||||
async Task GetReleaseNotesFromPR(Issue pullRequest)
|
||||
{
|
||||
//need to check it was merged
|
||||
var fullPR = await client.Repository.PullRequest.Get(RepoOwner, RepoName, pullRequest.Number).ConfigureAwait(false);
|
||||
|
||||
if (fullPR.Labels.Any(x => x.Name.Equals("SQLite Unmigratable")))
|
||||
hasSqliteFuckage = true;
|
||||
|
||||
async Task<Milestone> GetMilestone()
|
||||
{
|
||||
if (fullPR.Milestone == null)
|
||||
@@ -242,6 +247,11 @@ namespace ReleaseNotes
|
||||
var hostWatchdogVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsHostWatchdogVersion").Value);
|
||||
|
||||
prefix = $"#### Component Versions\nCore: {coreVersion}\nHTTP API: {apiVersion}\nDreamMaker API: {dmApiVersion}\n[Web Control Panel](https://github.com/tgstation/tgstation-server-control-panel): {webControlVersion}\nHost Watchdog: {hostWatchdogVersion}";
|
||||
|
||||
//hasSqliteFuckage = hasSqliteFuckage && version != new Version(4, 1, 0);
|
||||
if (hasSqliteFuckage)
|
||||
prefix = $"{prefix}{Environment.NewLine}{Environment.NewLine}#### THIS VERSION IS INCOMPATIBLE WITH PREVIOUS SQLITE DATABASES!";
|
||||
|
||||
break;
|
||||
case 3:
|
||||
prefix = "The /tg/station server suite";
|
||||
|
||||
Reference in New Issue
Block a user