Fixed: All the tests

pull/928/head
ta264 5 years ago committed by Qstick
parent 9392c13364
commit ee7d47d044

@ -281,6 +281,7 @@ stages:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(osName) Unit Tests'
failTaskOnFailedTests: true
- stage: Integration_Automation
displayName: Integration / Automation
@ -294,6 +295,10 @@ stages:
osName: 'Linux'
imageName: 'ubuntu-16.04'
pattern: 'Lidarr.**.linux.tar.gz'
Mac:
osName: 'Mac'
imageName: 'macos-10.13'
pattern: 'Lidarr.**.osx.tar.gz'
Windows:
osName: 'Windows'
imageName: 'vs2017-win2016'
@ -308,6 +313,14 @@ stages:
sudo tar xf chromaprint-fpcalc-1.4.3-linux-x86_64.tar.gz --strip-components=1 --directory /usr/bin
displayName: Install fpcalc
condition: and(succeeded(), eq(variables['osName'], 'Linux'))
- bash: |
SYMLINK=5_18_1
MONOPREFIX=/Library/Frameworks/Mono.framework/Versions/$SYMLINK
echo "##vso[task.setvariable variable=DYLD_FALLBACK_LIBRARY_PATH;].:$MONOPREFIX/lib:/lib:/usr/lib:$DYLD_LIBRARY_FALLBACK_PATH"
echo "##vso[task.setvariable variable=PKG_CONFIG_PATH;]$MONOPREFIX/lib/pkgconfig:$MONOPREFIX/share/pkgconfig:$PKG_CONFIG_PATH"
echo "##vso[task.setvariable variable=PATH;]$MONOPREFIX/bin:$PATH"
displayName: Set Mono Version
condition: and(succeeded(), eq(variables['osName'], 'Mac'))
- checkout: none
- task: DownloadPipelineArtifact@2
displayName: Download Test Artifact
@ -342,6 +355,7 @@ stages:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(osName) Integration Tests'
failTaskOnFailedTests: true
displayName: Publish Test Results
- job: Automation
@ -351,14 +365,17 @@ stages:
osName: 'Linux'
imageName: 'ubuntu-16.04'
pattern: 'Lidarr.**.linux.tar.gz'
failBuild: true
Mac:
osName: 'Mac'
imageName: 'macos-10.13' # Fails due to firefox not being installed on image
pattern: 'Lidarr.**.osx.tar.gz'
failBuild: false
Windows:
osName: 'Windows'
imageName: 'vs2017-win2016'
pattern: 'Lidarr.**.windows.zip'
failBuild: true
pool:
vmImage: $(imageName)
@ -413,6 +430,7 @@ stages:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(osName) Automation Tests'
failTaskOnFailedTests: $(failBuild)
displayName: Publish Test Results
- stage: Analyze

@ -6,6 +6,7 @@ using Nancy.Responses;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using Lidarr.Http;
using NLog;
namespace Lidarr.Api.V1.Logs
{
@ -54,6 +55,8 @@ namespace Lidarr.Api.V1.Logs
private Response GetLogFileResponse(string filename)
{
LogManager.Flush();
var filePath = GetLogFilePath(filename);
if (!_diskProvider.FileExists(filePath))

@ -245,14 +245,20 @@ namespace NzbDrone.Common.Test.DiskTests
}
[Test]
[Ignore("No longer behaving this way in a Windows 10 Feature Update")]
public void should_not_be_able_to_rename_open_hardlinks_with_fileshare_none()
{
WindowsOnly();
Assert.Throws<IOException>(() => DoHardLinkRename(FileShare.None));
}
[Test]
[Ignore("No longer behaving this way in a Windows 10 Feature Update")]
public void should_not_be_able_to_rename_open_hardlinks_with_fileshare_write()
{
WindowsOnly();
Assert.Throws<IOException>(() => DoHardLinkRename(FileShare.Read));
}
}

@ -64,6 +64,7 @@ namespace NzbDrone.Common.Test
}
[Test]
[Platform(Exclude="MacOsX")]
public void Should_be_able_to_start_process()
{
var process = StartDummyProcess();
@ -79,6 +80,7 @@ namespace NzbDrone.Common.Test
[Test]
[Platform(Exclude="MacOsX")]
public void kill_all_should_kill_all_process_with_name()
{
var dummy1 = StartDummyProcess();
@ -92,7 +94,8 @@ namespace NzbDrone.Common.Test
private Process StartDummyProcess()
{
return Subject.Start(Path.Combine(TestContext.CurrentContext.TestDirectory, DummyApp.DUMMY_PROCCESS_NAME + ".exe"));
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, DummyApp.DUMMY_PROCCESS_NAME + ".exe");
return Subject.Start(path);
}
[Test]

@ -1,4 +1,5 @@
using System;
using System.Security.Principal;
using System.ServiceProcess;
using FluentAssertions;
using NUnit.Framework;
@ -61,6 +62,10 @@ namespace NzbDrone.Common.Test
[Test]
public void Service_should_be_installed_and_then_uninstalled()
{
if (!IsAnAdministrator())
{
Assert.Inconclusive("Can't run test without Administrator rights");
}
Subject.ServiceExist(TEMP_SERVICE_NAME).Should().BeFalse("Service already installed");
Subject.Install(TEMP_SERVICE_NAME);
@ -100,8 +105,13 @@ namespace NzbDrone.Common.Test
}
[Test]
public void should_throw_if_starting_a_running_serivce()
public void should_throw_if_starting_a_running_service()
{
if (!IsAnAdministrator())
{
Assert.Inconclusive("Can't run test without Administrator rights");
}
Subject.GetService(ALWAYS_INSTALLED_SERVICE).Status
.Should().NotBe(ServiceControllerStatus.Running);
@ -127,5 +137,10 @@ namespace NzbDrone.Common.Test
ExceptionVerification.ExpectedWarns(1);
}
private static bool IsAnAdministrator()
{
var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
}

@ -142,7 +142,7 @@ namespace NzbDrone.Common.EnvironmentInfo
}
var lowerCurrentDir = Directory.GetCurrentDirectory().ToLower();
if (lowerCurrentDir.Contains("teamcity")) return false;
if (lowerCurrentDir.Contains("vsts")) return false;
if (lowerCurrentDir.Contains("buildagent")) return false;
if (lowerCurrentDir.Contains("_output")) return false;

@ -328,6 +328,8 @@ namespace NzbDrone.Common.Processes
var monoProcesses = Process.GetProcessesByName("mono")
.Union(Process.GetProcessesByName("mono-sgen"))
.Union(Process.GetProcessesByName("mono-sgen32"))
.Union(Process.GetProcessesByName("mono-sgen64"))
.Where(process =>
process.Modules.Cast<ProcessModule>()
.Any(module =>

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using FluentMigrator.Runner;
@ -115,21 +116,14 @@ namespace NzbDrone.Core.Test.Framework
[TearDown]
public void TearDown()
{
if (TestFolderInfo != null && Directory.Exists(TestFolderInfo.AppDataFolder))
// Make sure there are no lingering connections. (When this happens it means we haven't disposed something properly)
GC.Collect();
GC.WaitForPendingFinalizers();
SQLiteConnection.ClearAllPools();
if (TestFolderInfo != null)
{
var files = Directory.GetFiles(TestFolderInfo.AppDataFolder);
foreach (var file in files)
{
try
{
File.Delete(file);
}
catch (Exception)
{
}
}
DeleteTempFolder(TestFolderInfo.AppDataFolder);
}
}
}

@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.Instrumentation
{
_logger.Info(_uniqueMessage);
Thread.Sleep(600);
Thread.Sleep(1000);
StoredModel.Message.Should().Be(_uniqueMessage);
VerifyLog(StoredModel, LogLevel.Info);
@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.Instrumentation
_logger.Info(message);
Thread.Sleep(600);
Thread.Sleep(1000);
StoredModel.Message.Should().HaveLength(message.Length);
StoredModel.Message.Should().Be(message);
@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.Instrumentation
_logger.Info(Guid.NewGuid());
}
Thread.Sleep(600);
Thread.Sleep(1000);
MapRepository.Instance.EnableTraceLogging = true;
}
@ -88,7 +88,7 @@ namespace NzbDrone.Core.Test.Instrumentation
_logger.Error(ex, _uniqueMessage);
Thread.Sleep(600);
Thread.Sleep(1000);
VerifyLog(StoredModel, LogLevel.Error);
StoredModel.Message.Should().Be(_uniqueMessage + ": " + ex.Message);
@ -106,7 +106,7 @@ namespace NzbDrone.Core.Test.Instrumentation
_logger.Error(ex, _uniqueMessage);
Thread.Sleep(600);
Thread.Sleep(1000);
StoredModel.Message.Should().Be(ex.Message);
@ -121,7 +121,7 @@ namespace NzbDrone.Core.Test.Instrumentation
var epFile = new TrackFile();
_logger.Debug("File {0} no longer exists on disk. removing from database.", epFile.Path);
Thread.Sleep(600);
Thread.Sleep(1000);
epFile.Path.Should().BeNull();
}

@ -18,7 +18,6 @@ namespace NzbDrone.Core.Test.Messaging.Commands
private CommandQueue _commandQueue;
private Mock<IExecute<CommandA>> _executorA;
private Mock<IExecute<CommandB>> _executorB;
private bool _commandExecuted = false;
[SetUp]
public void Setup()
@ -53,26 +52,34 @@ namespace NzbDrone.Core.Test.Messaging.Commands
.Returns(_commandQueue.GetConsumingEnumerable);
}
private void QueueAndWaitForExecution(CommandModel commandModel)
private void QueueAndWaitForExecution(CommandModel commandModel, bool waitPublish = false)
{
Thread.Sleep(10);
var waitEventComplete = new ManualResetEventSlim();
var waitEventPublish = new ManualResetEventSlim();
Mocker.GetMock<IManageCommandQueue>()
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), It.IsAny<string>()))
.Callback(() => _commandExecuted = true);
.Callback(() => waitEventComplete.Set());
Mocker.GetMock<IManageCommandQueue>()
.Setup(s => s.Fail(It.Is<CommandModel>(c => c == commandModel), It.IsAny<string>(), It.IsAny<Exception>()))
.Callback(() => _commandExecuted = true);
.Callback(() => waitEventComplete.Set());
Mocker.GetMock<IEventAggregator>()
.Setup(s => s.PublishEvent<CommandExecutedEvent>(It.IsAny<CommandExecutedEvent>()))
.Callback(() => waitEventPublish.Set());
_commandQueue.Add(commandModel);
while (!_commandExecuted)
if (!waitEventComplete.Wait(2000))
{
Thread.Sleep(100);
Assert.Fail("Command did not Complete/Fail within 2 sec");
}
Thread.Sleep(10);
if (waitPublish && !waitEventPublish.Wait(500))
{
Assert.Fail("Command did not Publish within 500 msec");
}
}
[Test]
@ -138,9 +145,7 @@ namespace NzbDrone.Core.Test.Messaging.Commands
VerifyEventPublished<CommandExecutedEvent>();
Thread.Sleep(10);
ExceptionVerification.ExpectedErrors(1);
ExceptionVerification.WaitForErrors(1, 500);
}
[Test]
@ -175,18 +180,17 @@ namespace NzbDrone.Core.Test.Messaging.Commands
QueueAndWaitForExecution(commandModel);
Mocker.GetMock<IManageCommandQueue>()
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandA.CompletionMessage))
.Callback(() => _commandExecuted = true);
.Verify(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandA.CompletionMessage), Times.Once());
}
[Test]
public void should_use_last_progress_message_if_completion_message_is_null()
{
GivenCommandQueue();
var commandA = new CommandA();
var commandB = new CommandB();
var commandModel = new CommandModel
{
Body = commandA,
Body = commandB,
Message = "Do work"
};
@ -195,8 +199,7 @@ namespace NzbDrone.Core.Test.Messaging.Commands
QueueAndWaitForExecution(commandModel);
Mocker.GetMock<IManageCommandQueue>()
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandModel.Message))
.Callback(() => _commandExecuted = true);
.Verify(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandModel.Message), Times.Once());
}
}

@ -7,6 +7,7 @@ using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Music;
using NzbDrone.Core.Validation.Paths;
using NzbDrone.Test.Common;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Core.Test.ValidationTests
{
@ -52,8 +53,9 @@ namespace NzbDrone.Core.Test.ValidationTests
{
MonoOnly();
var bin = OsInfo.IsOsx ? "/System" : "/bin";
var artist = Builder<Artist>.CreateNew()
.With(s => s.Path = "/bin")
.With(s => s.Path = bin)
.Build();
_validator.Validate(artist).IsValid.Should().BeFalse();
@ -64,9 +66,10 @@ namespace NzbDrone.Core.Test.ValidationTests
{
MonoOnly();
var bin = OsInfo.IsOsx ? "/System" : "/bin";
var artist = Builder<Artist>.CreateNew()
.With(s => s.Path = "/bin/test")
.Build();
.With(s => s.Path = Path.Combine(bin, "test"))
.Build();
_validator.Validate(artist).IsValid.Should().BeFalse();
}

@ -50,6 +50,8 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
{
runner.MigrateUp(true);
}
processor.Dispose();
}
catch (SQLiteException)
{
@ -57,7 +59,6 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
SQLiteConnection.ClearAllPools();
throw;
}
sw.Stop();

@ -23,27 +23,27 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test]
public void should_be_able_to_get_albums()
{
var artist = EnsureArtist("aaaa_aaaaa_asaaaaa", "Alien Ant Farm", true);
var artist = EnsureArtist("cc2c9c3c-b7bc-4b8b-84d8-4fbd8779e493", "Adele", true);
var request = Calendar.BuildRequest();
request.AddParameter("start", new DateTime(2015, 10, 1).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2015, 10, 3).ToString("s") + "Z");
request.AddParameter("start", new DateTime(2015, 11, 19).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2015, 11, 21).ToString("s") + "Z");
var items = Calendar.Get<List<AlbumResource>>(request);
items = items.Where(v => v.ArtistId == artist.Id).ToList();
items.Should().HaveCount(1);
items.First().Title.Should().Be("The Troll Farmer");
items.First().Title.Should().Be("25");
}
[Test]
public void should_not_be_able_to_get_unmonitored_albums()
{
var artist = EnsureArtist("aaaa_aaaaa_asaaaaa", "Alien Ant Farm", false);
var artist = EnsureArtist("cc2c9c3c-b7bc-4b8b-84d8-4fbd8779e493", "Adele", false);
var request = Calendar.BuildRequest();
request.AddParameter("start", new DateTime(2015, 10, 1).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2015, 10, 3).ToString("s") + "Z");
request.AddParameter("start", new DateTime(2015, 11, 19).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2015, 11, 21).ToString("s") + "Z");
request.AddParameter("unmonitored", "false");
var items = Calendar.Get<List<AlbumResource>>(request);
@ -55,18 +55,18 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test]
public void should_be_able_to_get_unmonitored_albums()
{
var artist = EnsureArtist("aaaa_aaaaa_asaaaaa", "Alien Ant Farm", false);
var artist = EnsureArtist("cc2c9c3c-b7bc-4b8b-84d8-4fbd8779e493", "Adele", false);
var request = Calendar.BuildRequest();
request.AddParameter("start", new DateTime(2015, 10, 1).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2015, 10, 3).ToString("s") + "Z");
request.AddParameter("start", new DateTime(2015, 11, 19).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2015, 11, 21).ToString("s") + "Z");
request.AddParameter("unmonitored", "true");
var items = Calendar.Get<List<AlbumResource>>(request);
items = items.Where(v => v.ArtistId == artist.Id).ToList();
items.Should().HaveCount(1);
items.First().Title.Should().Be("The Troll Farmer");
items.First().Title.Should().Be("25");
}
}
}

@ -1,6 +1,6 @@
using FluentAssertions;
using NUnit.Framework;
using Lidarr.Api.V1.Commands;
using NzbDrone.Integration.Test.Client;
namespace NzbDrone.Integration.Test.ApiTests
{
@ -11,7 +11,7 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test]
public void should_be_able_to_run_rss_sync()
{
var response = Commands.Post(new CommandResource { Name = "rsssync" });
var response = Commands.Post(new SimpleCommandResource { Name = "rsssync" });
response.Id.Should().NotBe(0);
}

@ -3,7 +3,6 @@ using FluentAssertions;
using NUnit.Framework;
using Lidarr.Api.V1.Artist;
using System.Linq;
using NzbDrone.Test.Common;
namespace NzbDrone.Integration.Test.ApiTests
{
@ -15,30 +14,16 @@ namespace NzbDrone.Integration.Test.ApiTests
[SetUp]
public void Setup()
{
_artist = GivenArtistWithTracks();
_artist = EnsureArtist("8ac6cc32-8ddf-43b1-9ac4-4b04f9053176", "Alien Ant Farm");
}
private ArtistResource GivenArtistWithTracks()
{
var newArtist = Artist.Lookup("archer").Single(c => c.ForeignArtistId == "110381");
newArtist.QualityProfileId = 1;
newArtist.Path = @"C:\Test\Archer".AsOsAgnostic();
newArtist = Artist.Post(newArtist);
WaitForCompletion(() => Tracks.GetTracksInArtist(newArtist.Id).Count > 0);
return newArtist;
}
[Test]
[Test, Order(0)]
public void should_be_able_to_get_all_tracks_in_artist()
{
Tracks.GetTracksInArtist(_artist.Id).Count.Should().BeGreaterThan(0);
}
[Test]
[Test, Order(1)]
public void should_be_able_to_get_a_single_track()
{
var tracks = Tracks.GetTracksInArtist(_artist.Id);

@ -36,15 +36,15 @@ namespace NzbDrone.Integration.Test.ApiTests
var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc");
result.Records.First().Artist.Should().NotBeNull();
result.Records.First().Artist.ArtistName.Should().Be("The Blacklist");
result.Records.First().Artist.ArtistName.Should().Be("Alien Ant Farm");
}
[Test, Order(1)]
public void cutoff_should_have_monitored_items()
{
EnsureProfileCutoff(1, Quality.MP3_256);
EnsureProfileCutoff(1, "Lossless");
var artist = EnsureArtist("8ac6cc32-8ddf-43b1-9ac4-4b04f9053176", "Alien Ant Farm", true);
EnsureTrackFile(artist, 1, 1, Quality.MP3_192);
EnsureTrackFile(artist, 1, 1, 1, Quality.MP3_192);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc");
@ -64,9 +64,9 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test, Order(1)]
public void cutoff_should_not_have_unmonitored_items()
{
EnsureProfileCutoff(1, Quality.MP3_256);
EnsureProfileCutoff(1, "Lossless");
var artist = EnsureArtist("8ac6cc32-8ddf-43b1-9ac4-4b04f9053176", "Alien Ant Farm", false);
EnsureTrackFile(artist, 1, 1, Quality.MP3_192);
EnsureTrackFile(artist, 1, 1, 1, Quality.MP3_192);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc");
@ -76,9 +76,9 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test, Order(1)]
public void cutoff_should_have_artist()
{
EnsureProfileCutoff(1, Quality.MP3_256);
EnsureProfileCutoff(1, "Lossless");
var artist = EnsureArtist("8ac6cc32-8ddf-43b1-9ac4-4b04f9053176", "Alien Ant Farm", true);
EnsureTrackFile(artist, 1, 1, Quality.MP3_192);
EnsureTrackFile(artist, 1, 1, 1, Quality.MP3_192);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc");
@ -99,9 +99,9 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test, Order(2)]
public void cutoff_should_have_unmonitored_items()
{
EnsureProfileCutoff(1, Quality.MP3_256);
EnsureProfileCutoff(1, "Lossless");
var artist = EnsureArtist("8ac6cc32-8ddf-43b1-9ac4-4b04f9053176", "Alien Ant Farm", false);
EnsureTrackFile(artist, 1, 1, Quality.MP3_192);
EnsureTrackFile(artist, 1, 1, 1, Quality.MP3_192);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc", "monitored", "false");

@ -40,7 +40,7 @@ namespace NzbDrone.Integration.Test.Client
return request;
}
public T Execute<T>(IRestRequest request, HttpStatusCode statusCode) where T : class, new()
public string Execute(IRestRequest request, HttpStatusCode statusCode)
{
_logger.Info("{0}: {1}", request.Method, _restClient.BuildUri(request));
@ -58,7 +58,14 @@ namespace NzbDrone.Integration.Test.Client
response.StatusCode.Should().Be(statusCode);
return Json.Deserialize<T>(response.Content);
return response.Content;
}
public T Execute<T>(IRestRequest request, HttpStatusCode statusCode) where T : class, new()
{
var content = Execute(request, statusCode);
return Json.Deserialize<T>(content);
}
private static void AssertDisableCache(IList<Parameter> headers)

@ -1,23 +1,47 @@
using Lidarr.Api.V1.Commands;
using RestSharp;
using NzbDrone.Core.Messaging.Commands;
using FluentAssertions;
using System.Threading;
using NUnit.Framework;
using System.Linq;
using System;
using Lidarr.Http.REST;
using Newtonsoft.Json;
namespace NzbDrone.Integration.Test.Client
{
public class CommandClient : ClientBase<CommandResource>
public class SimpleCommandResource : RestResource
{
public string Name { get; set; }
public string CommandName { get; set; }
public string Message { get; set; }
public CommandPriority Priority { get; set; }
public CommandStatus Status { get; set; }
public DateTime Queued { get; set; }
public DateTime? Started { get; set; }
public DateTime? Ended { get; set; }
public TimeSpan? Duration { get; set; }
public string Exception { get; set; }
public CommandTrigger Trigger { get; set; }
[JsonIgnore]
public Command Body { get; set; }
[JsonProperty("body")]
public Command BodyReadOnly { get { return Body; } }
}
public class CommandClient : ClientBase<SimpleCommandResource>
{
public CommandClient(IRestClient restClient, string apiKey)
: base(restClient, apiKey)
: base(restClient, apiKey, "command")
{
}
public CommandResource PostAndWait(CommandResource command)
public SimpleCommandResource PostAndWait<T>(T command) where T : Command, new()
{
var result = Post(command);
var request = BuildRequest();
request.AddBody(command);
var result = Post<SimpleCommandResource>(request);
result.Id.Should().NotBe(0);
for (var i = 0; i < 50; i++)

@ -0,0 +1,24 @@
using System;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
{
public class LogsClient : ClientBase
{
public LogsClient(IRestClient restClient, string apiKey)
: base(restClient, apiKey, "log/file")
{
}
public string[] GetLogFileLines(string filename)
{
var request = BuildRequest(filename);
var content = Execute(request, System.Net.HttpStatusCode.OK);
var lines = content.Split('\n');
lines = Array.ConvertAll(lines, s => s.TrimEnd('\r'));
Array.Resize(ref lines, lines.Length - 1);
return lines;
}
}
}

@ -1,4 +1,4 @@
using System.IO;
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
@ -15,16 +15,20 @@ namespace NzbDrone.Integration.Test
config.LogLevel = "Trace";
HostConfig.Put(config);
var logFile = Path.Combine(_runner.AppData, "logs", "Lidarr.trace.txt");
var logLines = File.ReadAllLines(logFile);
var resultGet = Artist.All();
var logFile = "Lidarr.trace.txt";
var logLines = Logs.GetLogFileLines(logFile);
var result = Artist.InvalidPost(new Lidarr.Api.V1.Artist.ArtistResource());
logLines = File.ReadAllLines(logFile).Skip(logLines.Length).ToArray();
// Skip 2 and 1 to ignore the logs endpoint
logLines = Logs.GetLogFileLines(logFile).Skip(logLines.Length + 2).ToArray();
Array.Resize(ref logLines, logLines.Length - 1);
logLines.Should().Contain(v => v.Contains("|Trace|Http|Req"));
logLines.Should().Contain(v => v.Contains("|Trace|Http|Res"));
logLines.Should().Contain(v => v.Contains("|Debug|Api|"));
logLines.Should().Contain(v => v.Contains("|Trace|Http|Req") && v.Contains("/api/v1/artist/"));
logLines.Should().Contain(v => v.Contains("|Trace|Http|Res") && v.Contains("/api/v1/artist/: 400.BadRequest"));
logLines.Should().Contain(v => v.Contains("|Debug|Api|") && v.Contains("/api/v1/artist/: 400.BadRequest"));
}
}
}

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
@ -30,6 +31,8 @@ using NzbDrone.Integration.Test.Client;
using NzbDrone.SignalR;
using NzbDrone.Test.Common.Categories;
using RestSharp;
using NzbDrone.Core.MediaFiles.TrackImport.Manual;
using NzbDrone.Test.Common;
namespace NzbDrone.Integration.Test
{
@ -46,6 +49,7 @@ namespace NzbDrone.Integration.Test
public ClientBase<HistoryResource> History;
public ClientBase<HostConfigResource> HostConfig;
public IndexerClient Indexers;
public LogsClient Logs;
public ClientBase<NamingConfigResource> NamingConfig;
public NotificationClient Notifications;
public ClientBase<QualityProfileResource> Profiles;
@ -108,6 +112,7 @@ namespace NzbDrone.Integration.Test
History = new ClientBase<HistoryResource>(RestClient, ApiKey);
HostConfig = new ClientBase<HostConfigResource>(RestClient, ApiKey, "config/host");
Indexers = new IndexerClient(RestClient, ApiKey);
Logs = new LogsClient(RestClient, ApiKey);
NamingConfig = new ClientBase<NamingConfigResource>(RestClient, ApiKey, "config/naming");
Notifications = new NotificationClient(RestClient, ApiKey);
Profiles = new ClientBase<QualityProfileResource>(RestClient, ApiKey);
@ -129,7 +134,10 @@ namespace NzbDrone.Integration.Test
[SetUp]
public void IntegrationSetUp()
{
TempDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "_test_" + DateTime.UtcNow.Ticks);
TempDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "_test_" + TestBase.GetUID());
// Wait for things to get quiet, otherwise the previous test might influence the current one.
Commands.WaitAll();
}
[TearDown]
@ -150,6 +158,17 @@ namespace NzbDrone.Integration.Test
_signalrConnection = null;
_signalRReceived = new List<SignalRMessage>();
}
if (Directory.Exists(TempDirectory))
{
try
{
Directory.Delete(TempDirectory, true);
}
catch
{
}
}
}
public string GetTempDirectory(params string[] args)
@ -227,19 +246,27 @@ namespace NzbDrone.Integration.Test
WaitForCompletion(() => Tracks.GetTracksInArtist(result.Id).Count > 0);
}
var changed = false;
if (result.RootFolderPath != ArtistRootFolder)
{
changed = true;
result.RootFolderPath = ArtistRootFolder;
result.Path = Path.Combine(ArtistRootFolder, result.ArtistName);
}
if (monitored.HasValue)
{
var changed = false;
if (result.Monitored != monitored.Value)
{
result.Monitored = monitored.Value;
changed = true;
}
}
if (changed)
{
Artist.Put(result);
}
if (changed)
{
Artist.Put(result);
}
return result;
@ -256,35 +283,45 @@ namespace NzbDrone.Integration.Test
}
}
public TrackFileResource EnsureTrackFile(ArtistResource artist, int albumId, int track, Quality quality)
public void EnsureTrackFile(ArtistResource artist, int albumId, int albumReleaseId, int trackId, Quality quality)
{
var result = Tracks.GetTracksInArtist(artist.Id).Single(v => v.AlbumId == albumId && v.AbsoluteTrackNumber == track);
var result = Tracks.GetTracksInArtist(artist.Id).Single(v => v.Id == trackId);
if (result.TrackFile == null)
{
var path = Path.Combine(ArtistRootFolder, artist.ArtistName, string.Format("{0} - {1} - Track.mp3", track, artist.ArtistName));
var path = Path.Combine(ArtistRootFolder, artist.ArtistName, "Track.mp3");
Directory.CreateDirectory(Path.GetDirectoryName(path));
File.WriteAllText(path, "Fake Track");
Commands.PostAndWait(new CommandResource { Name = "refreshartist", Body = new RefreshArtistCommand(artist.Id) });
Commands.PostAndWait(new ManualImportCommand {
Files = new List<ManualImportFile> {
new ManualImportFile {
Path = path,
ArtistId = artist.Id,
AlbumId = albumId,
AlbumReleaseId = albumReleaseId,
TrackIds = new List<int> { trackId },
Quality = new QualityModel(quality)
}
}
});
Commands.WaitAll();
result = Tracks.GetTracksInArtist(artist.Id).Single(v => v.AlbumId == albumId && v.AbsoluteTrackNumber == track);
var track = Tracks.GetTracksInArtist(artist.Id).Single(x => x.Id == trackId);
result.TrackFile.Should().NotBeNull();
track.TrackFileId.Should().NotBe(0);
}
return result.TrackFile;
}
public QualityProfileResource EnsureProfileCutoff(int profileId, Quality cutoff)
public QualityProfileResource EnsureProfileCutoff(int profileId, string cutoff)
{
var profile = Profiles.Get(profileId);
var cutoffItem = profile.Items.First(x => x.Name == cutoff);
if (profile.Cutoff != cutoff.Id)
if (profile.Cutoff != cutoffItem.Id)
{
profile.Cutoff = cutoff.Id;
profile.Cutoff = cutoffItem.Id;
profile = Profiles.Put(profile);
}

@ -74,6 +74,7 @@
<Compile Include="Client\CommandClient.cs" />
<Compile Include="Client\ReleaseClient.cs" />
<Compile Include="Client\ArtistClient.cs" />
<Compile Include="Client\LogsClient.cs" />
<Compile Include="ApiTests\CommandFixture.cs" />
<Compile Include="CorsFixture.cs" />
<Compile Include="ApiTests\TrackFixture.cs" />
@ -190,4 +191,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

@ -8,7 +8,7 @@ using NzbDrone.Test.Common;
namespace NzbDrone.Mono.Test.EnvironmentInfo
{
[TestFixture]
[Platform("Mono")]
[Platform("Linux")]
public class ReleaseFileVersionAdapterFixture : TestBase<ReleaseFileVersionAdapter>
{
[SetUp]
@ -26,4 +26,4 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo
info.Version.Should().NotBeNullOrWhiteSpace();
}
}
}
}

@ -15,7 +15,7 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters
{
[Test]
[IntegrationTest]
[Platform("Mono")]
[Platform("Linux")]
public void should_get_version_info_from_actual_linux()
{
Mocker.SetConstant<IDiskProvider>(Mocker.Resolve<DiskProvider>());
@ -79,4 +79,4 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters
}
}
}
}

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using NLog;
using NLog.Targets;
using NUnit.Framework;
@ -11,17 +12,27 @@ namespace NzbDrone.Test.Common
{
private static List<LogEventInfo> _logs = new List<LogEventInfo>();
private static ManualResetEventSlim _waitEvent = new ManualResetEventSlim();
protected override void Write(LogEventInfo logEvent)
{
if (logEvent.Level >= LogLevel.Warn)
lock (_logs)
{
_logs.Add(logEvent);
if (logEvent.Level >= LogLevel.Warn)
{
_logs.Add(logEvent);
_waitEvent.Set();
}
}
}
public static void Reset()
{
_logs = new List<LogEventInfo>();
lock (_logs)
{
_logs.Clear();
_waitEvent.Reset();
}
}
public static void AssertNoUnexpectedLogs()
@ -47,6 +58,29 @@ namespace NzbDrone.Test.Common
return errors;
}
public static void WaitForErrors(int count, int msec)
{
while (true)
{
lock (_logs)
{
var levelLogs = _logs.Where(l => l.Level == LogLevel.Error).ToList();
if (levelLogs.Count >= count)
{
break;
}
_waitEvent.Reset();
}
if (!_waitEvent.Wait(msec))
break;
}
Expected(LogLevel.Error, count);
}
public static void ExpectedErrors(int count)
{
Expected(LogLevel.Error, count);
@ -74,50 +108,62 @@ namespace NzbDrone.Test.Common
public static void MarkInconclusive(Type exception)
{
var inconclusiveLogs = _logs.Where(l => l.Exception != null && l.Exception.GetType() == exception).ToList();
if (inconclusiveLogs.Any())
lock (_logs)
{
inconclusiveLogs.ForEach(c => _logs.Remove(c));
Assert.Inconclusive(GetLogsString(inconclusiveLogs));
var inconclusiveLogs = _logs.Where(l => l.Exception != null && l.Exception.GetType() == exception).ToList();
if (inconclusiveLogs.Any())
{
inconclusiveLogs.ForEach(c => _logs.Remove(c));
Assert.Inconclusive(GetLogsString(inconclusiveLogs));
}
}
}
public static void MarkInconclusive(string text)
{
var inconclusiveLogs = _logs.Where(l => l.FormattedMessage.ToLower().Contains(text.ToLower())).ToList();
if (inconclusiveLogs.Any())
lock (_logs)
{
inconclusiveLogs.ForEach(c => _logs.Remove(c));
Assert.Inconclusive(GetLogsString(inconclusiveLogs));
var inconclusiveLogs = _logs.Where(l => l.FormattedMessage.ToLower().Contains(text.ToLower())).ToList();
if (inconclusiveLogs.Any())
{
inconclusiveLogs.ForEach(c => _logs.Remove(c));
Assert.Inconclusive(GetLogsString(inconclusiveLogs));
}
}
}
private static void Expected(LogLevel level, int count)
{
var levelLogs = _logs.Where(l => l.Level == level).ToList();
if (levelLogs.Count != count)
lock (_logs)
{
var levelLogs = _logs.Where(l => l.Level == level).ToList();
if (levelLogs.Count != count)
{
var message = string.Format("{0} {1}(s) were expected but {2} were logged.\n\r{3}",
count, level, levelLogs.Count, GetLogsString(levelLogs));
var message = string.Format("{0} {1}(s) were expected but {2} were logged.\n\r{3}",
count, level, levelLogs.Count, GetLogsString(levelLogs));
message = "\n\r****************************************************************************************\n\r"
+ message +
"\n\r****************************************************************************************";
message = "\n\r****************************************************************************************\n\r"
+ message +
"\n\r****************************************************************************************";
Assert.Fail(message);
}
Assert.Fail(message);
}
levelLogs.ForEach(c => _logs.Remove(c));
levelLogs.ForEach(c => _logs.Remove(c));
}
}
private static void Ignore(LogLevel level)
{
var levelLogs = _logs.Where(l => l.Level == level).ToList();
levelLogs.ForEach(c => _logs.Remove(c));
lock (_logs)
{
var levelLogs = _logs.Where(l => l.Level == level).ToList();
levelLogs.ForEach(c => _logs.Remove(c));
}
}
}
}

@ -9,6 +9,7 @@ using NLog;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes;
using NzbDrone.Core.Configuration;
using RestSharp;
namespace NzbDrone.Test.Common
@ -30,13 +31,16 @@ namespace NzbDrone.Test.Common
public void Start()
{
AppData = Path.Combine(TestContext.CurrentContext.TestDirectory, "_intg_" + DateTime.Now.Ticks);
AppData = Path.Combine(TestContext.CurrentContext.TestDirectory, "_intg_" + TestBase.GetUID());
Directory.CreateDirectory(AppData);
GenerateConfigFile();
var lidarrConsoleExe = OsInfo.IsWindows ? "Lidarr.Console.exe" : "Lidarr.exe";
if (BuildInfo.IsDebug)
{
Start(Path.Combine(TestContext.CurrentContext.TestDirectory, "..\\..\\..\\..\\..\\_output\\Lidarr.Console.exe"));
Start(Path.Combine(TestContext.CurrentContext.TestDirectory, "..", "..", "..", "..", "..", "_output", "Lidarr.Console.exe"));
}
else
{
@ -52,8 +56,6 @@ namespace NzbDrone.Test.Common
Assert.Fail("Process has exited");
}
SetApiKey();
var request = new RestRequest("system/status");
request.AddHeader("Authorization", ApiKey);
request.AddHeader("X-Api-Key", ApiKey);
@ -74,13 +76,22 @@ namespace NzbDrone.Test.Common
public void KillAll()
{
if (_nzbDroneProcess != null)
try
{
if (_nzbDroneProcess != null)
{
_processProvider.Kill(_nzbDroneProcess.Id);
}
_processProvider.KillAll(ProcessProvider.LIDARR_CONSOLE_PROCESS_NAME);
_processProvider.KillAll(ProcessProvider.LIDARR_PROCESS_NAME);
}
catch (InvalidOperationException)
{
_processProvider.Kill(_nzbDroneProcess.Id);
// May happen if the process closes while being closed
}
_processProvider.KillAll(ProcessProvider.LIDARR_CONSOLE_PROCESS_NAME);
_processProvider.KillAll(ProcessProvider.LIDARR_PROCESS_NAME);
TestBase.DeleteTempFolder(AppData);
}
private void Start(string outputNzbdroneConsoleExe)
@ -100,33 +111,26 @@ namespace NzbDrone.Test.Common
}
}
private void SetApiKey()
private void GenerateConfigFile()
{
var configFile = Path.Combine(AppData, "config.xml");
var attempts = 0;
while (ApiKey == null && attempts < 50)
{
try
{
if (File.Exists(configFile))
{
var apiKeyElement = XDocument.Load(configFile)
.XPathSelectElement("Config/ApiKey");
if (apiKeyElement != null)
{
ApiKey = apiKeyElement.Value;
}
}
}
catch (XmlException ex)
{
Console.WriteLine("Error getting API Key from XML file: " + ex.Message, ex);
}
// Generate and set the api key so we don't have to poll the config file
var apiKey = Guid.NewGuid().ToString().Replace("-", "");
attempts++;
Thread.Sleep(1000);
}
var xDoc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement(ConfigFileProvider.CONFIG_ELEMENT_NAME,
new XElement(nameof(ConfigFileProvider.ApiKey), apiKey),
new XElement(nameof(ConfigFileProvider.AnalyticsEnabled), false)
)
);
var data = xDoc.ToString();
File.WriteAllText(configFile, data);
ApiKey = apiKey;
}
}
}

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using FluentAssertions;
@ -43,8 +44,8 @@ namespace NzbDrone.Test.Common
public abstract class TestBase : LoggingTest
{
private static readonly Random _random = new Random();
private static int _nextUid;
private AutoMoqer _mocker;
protected AutoMoqer Mocker
@ -84,7 +85,21 @@ namespace NzbDrone.Test.Common
}
}
protected string TempFolder { get; private set; }
private string _tempFolder;
protected string TempFolder
{
get
{
if (_tempFolder == null)
{
_tempFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, "_temp_" + GetUID());
Directory.CreateDirectory(_tempFolder);
}
return _tempFolder;
}
}
[SetUp]
public void TestBaseSetup()
@ -93,9 +108,7 @@ namespace NzbDrone.Test.Common
LogManager.ReconfigExistingLoggers();
TempFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, "_temp_" + DateTime.Now.Ticks);
Directory.CreateDirectory(TempFolder);
_tempFolder = null;
}
[TearDown]
@ -103,9 +116,25 @@ namespace NzbDrone.Test.Common
{
_mocker = null;
DeleteTempFolder(_tempFolder);
}
public static string GetUID()
{
return Process.GetCurrentProcess().Id + "_" + DateTime.Now.Ticks + "_" + Interlocked.Increment(ref _nextUid);
}
public static void DeleteTempFolder(string folder)
{
if (folder == null)
{
return;
}
try
{
var tempFolder = new DirectoryInfo(TempFolder);
var tempFolder = new DirectoryInfo(folder);
if (tempFolder.Exists)
{
foreach (var file in tempFolder.GetFiles("*", SearchOption.AllDirectories))

@ -16,7 +16,7 @@ namespace NzbDrone.Update.Test
[Test]
public void should_start_service_if_app_type_was_serivce()
{
const string targetFolder = "c:\\Lidarr\\";
string targetFolder = "c:\\Lidarr\\".AsOsAgnostic();
Subject.Start(AppType.Service, targetFolder);
@ -26,13 +26,14 @@ namespace NzbDrone.Update.Test
[Test]
public void should_start_console_if_app_type_was_service_but_start_failed_because_of_permissions()
{
const string targetFolder = "c:\\Lidarr\\";
string targetFolder = "c:\\Lidarr\\".AsOsAgnostic();
string targetProcess = "c:\\Lidarr\\Lidarr.Console.exe".AsOsAgnostic();
Mocker.GetMock<IServiceProvider>().Setup(c => c.Start(ServiceProvider.SERVICE_NAME)).Throws(new InvalidOperationException());
Subject.Start(AppType.Service, targetFolder);
Mocker.GetMock<IProcessProvider>().Verify(c => c.SpawnNewProcess("c:\\Lidarr\\Lidarr.Console.exe", "/" + StartupContext.NO_BROWSER, null, false), Times.Once());
Mocker.GetMock<IProcessProvider>().Verify(c => c.SpawnNewProcess(targetProcess, "/" + StartupContext.NO_BROWSER, null, false), Times.Once());
ExceptionVerification.ExpectedWarns(1);
}

@ -29,29 +29,7 @@ NUNIT_PARAMS="--workers=1"
if [ "$PLATFORM" = "Mac" ]; then
#set up environment
if [[ -x '/opt/local/bin/mono' ]]; then
# Macports and mono-supplied installer path
export PATH="/opt/local/bin:$PATH"
elif [[ -x '/usr/local/bin/mono' ]]; then
# Homebrew-supplied path to mono
export PATH="/usr/local/bin:$PATH"
fi
echo $TEST_DIR
export DYLD_FALLBACK_LIBRARY_PATH="$TEST_DIR"
if [ -e /Library/Frameworks/Mono.framework ]; then
MONO_FRAMEWORK_PATH=/Library/Frameworks/Mono.framework/Versions/Current
export PATH="$MONO_FRAMEWORK_PATH/bin:$PATH"
export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$MONO_FRAMEWORK_PATH/lib"
fi
if [[ -f '/opt/local/lib/libsqlite3.0.dylib' ]]; then
export DYLD_FALLBACK_LIBRARY_PATH="/opt/local/lib:$DYLD_FALLBACK_LIBRARY_PATH"
fi
export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$HOME/lib:/usr/local/lib:/lib:/usr/lib"
export DYLD_FALLBACK_LIBRARY_PATH="$TEST_DIR:/usr/local/lib:/lib:/usr/lib"
echo $LD_LIBRARY_PATH
echo $DYLD_LIBRARY_PATH
echo $DYLD_FALLBACK_LIBRARY_PATH

Loading…
Cancel
Save