Merge remote-tracking branch 'upstream/master' into schedules-direct

This commit is contained in:
Cody Robibero
2021-10-08 07:49:40 -06:00
452 changed files with 6467 additions and 4633 deletions

View File

@@ -32,10 +32,11 @@ namespace Jellyfin.Server.Implementations.Tests.Data
_sqliteItemRepository = _fixture.Create<SqliteItemRepository>();
}
public static IEnumerable<object[]> ItemImageInfoFromValueString_Valid_TestData()
public static TheoryData<string, ItemImageInfo> ItemImageInfoFromValueString_Valid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, ItemImageInfo>();
data.Add(
"/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN",
new ItemImageInfo
{
@@ -45,41 +46,33 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Width = 1920,
Height = 1080,
BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
}
};
});
yield return new object[]
{
data.Add(
"https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*0*0",
new ItemImageInfo
{
Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
Type = ImageType.Primary,
}
};
});
yield return new object[]
{
data.Add(
"https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary",
new ItemImageInfo
{
Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
Type = ImageType.Primary,
}
};
});
yield return new object[]
{
data.Add(
"https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*600",
new ItemImageInfo
{
Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
Type = ImageType.Primary,
}
};
});
yield return new object[]
{
data.Add(
"%MetadataPath%/library/68/68578562b96c80a7ebd530848801f645/poster.jpg*637264380567586027*Primary*600*336",
new ItemImageInfo
{
@@ -88,8 +81,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data
DateModified = new DateTime(637264380567586027, DateTimeKind.Utc),
Width = 600,
Height = 336
}
};
});
return data;
}
[Theory]
@@ -117,10 +111,10 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Assert.Null(_sqliteItemRepository.ItemImageInfoFromValueString(value));
}
public static IEnumerable<object[]> DeserializeImages_Valid_TestData()
public static TheoryData<string, ItemImageInfo[]> DeserializeImages_Valid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, ItemImageInfo[]>();
data.Add(
"/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN",
new ItemImageInfo[]
{
@@ -133,11 +127,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Height = 1080,
BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
}
}
};
});
yield return new object[]
{
data.Add(
"%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/poster.jpg*637261226720645297*Primary*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/logo.png*637261226720805297*Logo*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/landscape.jpg*637261226721285297*Thumb*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/backdrop.jpg*637261226721685297*Backdrop*0*0",
new ItemImageInfo[]
{
@@ -165,20 +157,19 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Type = ImageType.Backdrop,
DateModified = new DateTime(637261226721685297, DateTimeKind.Utc),
}
}
};
});
return data;
}
public static IEnumerable<object[]> DeserializeImages_ValidAndInvalid_TestData()
public static TheoryData<string, ItemImageInfo[]> DeserializeImages_ValidAndInvalid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, ItemImageInfo[]>();
data.Add(
string.Empty,
Array.Empty<ItemImageInfo>()
};
Array.Empty<ItemImageInfo>());
yield return new object[]
{
data.Add(
"/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN|test|1234||ss",
new ItemImageInfo[]
{
@@ -191,14 +182,13 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Height = 1080,
BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
}
}
};
});
yield return new object[]
{
data.Add(
"|",
Array.Empty<ItemImageInfo>()
};
Array.Empty<ItemImageInfo>());
return data;
}
[Theory]
@@ -242,30 +232,27 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Assert.Equal(expected, _sqliteItemRepository.SerializeImages(value));
}
public static IEnumerable<object[]> DeserializeProviderIds_Valid_TestData()
public static TheoryData<string, Dictionary<string, string>> DeserializeProviderIds_Valid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, Dictionary<string, string>>();
data.Add(
"Imdb=tt0119567",
new Dictionary<string, string>()
{
{ "Imdb", "tt0119567" },
}
};
});
yield return new object[]
{
data.Add(
"Imdb=tt0119567|Tmdb=330|TmdbCollection=328",
new Dictionary<string, string>()
{
{ "Imdb", "tt0119567" },
{ "Tmdb", "330" },
{ "TmdbCollection", "328" },
}
};
});
yield return new object[]
{
data.Add(
"MusicBrainzAlbum=9d363e43-f24f-4b39-bc5a-7ef305c677c7|MusicBrainzReleaseGroup=63eba062-847c-3b73-8b0f-6baf27bba6fa|AudioDbArtist=111352|AudioDbAlbum=2116560|MusicBrainzAlbumArtist=20244d07-534f-4eff-b4d4-930878889970",
new Dictionary<string, string>()
{
@@ -274,8 +261,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data
{ "AudioDbArtist", "111352" },
{ "AudioDbAlbum", "2116560" },
{ "MusicBrainzAlbumArtist", "20244d07-534f-4eff-b4d4-930878889970" },
}
};
});
return data;
}
[Theory]

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
<RootNamespace>Jellyfin.Server.Implementations.Tests</RootNamespace>

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Emby.Server.Implementations.LiveTv.EmbyTV;
using MediaBrowser.Controller.LiveTv;
using Xunit;
@@ -8,43 +7,36 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
{
public static class RecordingHelperTests
{
public static IEnumerable<object[]> GetRecordingName_Success_TestData()
public static TheoryData<string, TimerInfo> GetRecordingName_Success_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, TimerInfo>();
data.Add(
"The Incredibles 2020_04_20_21_06_00",
new TimerInfo
{
Name = "The Incredibles",
StartDate = new DateTime(2020, 4, 20, 21, 6, 0, DateTimeKind.Local),
IsMovie = true
}
};
});
yield return new object[]
{
data.Add(
"The Incredibles (2004)",
new TimerInfo
{
Name = "The Incredibles",
IsMovie = true,
ProductionYear = 2004
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory 2020_04_20_21_06_00",
new TimerInfo
{
Name = "The Big Bang Theory",
StartDate = new DateTime(2020, 4, 20, 21, 6, 0, DateTimeKind.Local),
IsProgramSeries = true,
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory S12E10",
new TimerInfo
{
@@ -52,11 +44,8 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
IsProgramSeries = true,
SeasonNumber = 12,
EpisodeNumber = 10
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory S12E10 The VCR Illumination",
new TimerInfo
{
@@ -65,22 +54,17 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
SeasonNumber = 12,
EpisodeNumber = 10,
EpisodeTitle = "The VCR Illumination"
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory 2018-12-06",
new TimerInfo
{
Name = "The Big Bang Theory",
IsProgramSeries = true,
OriginalAirDate = new DateTime(2018, 12, 6)
}
};
});
yield return new object[]
{
data.Add(
"The Big Bang Theory 2018-12-06 - The VCR Illumination",
new TimerInfo
{
@@ -88,11 +72,9 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
IsProgramSeries = true,
OriginalAirDate = new DateTime(2018, 12, 6),
EpisodeTitle = "The VCR Illumination"
}
};
});
yield return new object[]
{
data.Add(
"The Big Bang Theory 2018_12_06_21_06_00 - The VCR Illumination",
new TimerInfo
{
@@ -101,8 +83,9 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
IsProgramSeries = true,
OriginalAirDate = new DateTime(2018, 12, 6),
EpisodeTitle = "The VCR Illumination"
}
};
});
return data;
}
[Theory]

View File

@@ -1,17 +1,28 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.AutoMoq;
using Emby.Server.Implementations.QuickConnect;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Configuration;
using Moq;
using Xunit;
namespace Jellyfin.Server.Implementations.Tests.LiveTv
namespace Jellyfin.Server.Implementations.Tests.QuickConnect
{
public class QuickConnectManagerTests
{
private static readonly AuthorizationInfo _quickConnectAuthInfo = new AuthorizationInfo
{
Device = "Device",
DeviceId = "DeviceId",
Client = "Client",
Version = "1.0.0"
};
private readonly Fixture _fixture;
private readonly ServerConfiguration _config;
private readonly QuickConnectManager _quickConnectManager;
@@ -27,6 +38,12 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
{
ConfigureMembers = true
}).Inject(configManager.Object);
// User object contains circular references.
_fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => _fixture.Behaviors.Remove(b));
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
_quickConnectManager = _fixture.Create<QuickConnectManager>();
}
@@ -36,7 +53,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
[Fact]
public void TryConnect_QuickConnectUnavailable_ThrowsAuthenticationException()
=> Assert.Throws<AuthenticationException>(_quickConnectManager.TryConnect);
=> Assert.Throws<AuthenticationException>(() => _quickConnectManager.TryConnect(_quickConnectAuthInfo));
[Fact]
public void CheckRequestStatus_QuickConnectUnavailable_ThrowsAuthenticationException()
@@ -44,7 +61,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
[Fact]
public void AuthorizeRequest_QuickConnectUnavailable_ThrowsAuthenticationException()
=> Assert.Throws<AuthenticationException>(() => _quickConnectManager.AuthorizeRequest(Guid.Empty, string.Empty));
=> Assert.ThrowsAsync<AuthenticationException>(() => _quickConnectManager.AuthorizeRequest(Guid.Empty, string.Empty));
[Fact]
public void IsEnabled_QuickConnectAvailable_True()
@@ -57,17 +74,17 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
public void CheckRequestStatus_QuickConnectAvailable_Success()
{
_config.QuickConnectAvailable = true;
var res1 = _quickConnectManager.TryConnect();
var res1 = _quickConnectManager.TryConnect(_quickConnectAuthInfo);
var res2 = _quickConnectManager.CheckRequestStatus(res1.Secret);
Assert.Equal(res1, res2);
}
[Fact]
public void AuthorizeRequest_QuickConnectAvailable_Success()
public async Task AuthorizeRequest_QuickConnectAvailable_Success()
{
_config.QuickConnectAvailable = true;
var res = _quickConnectManager.TryConnect();
Assert.True(_quickConnectManager.AuthorizeRequest(Guid.Empty, res.Code));
var res = _quickConnectManager.TryConnect(_quickConnectAuthInfo);
Assert.True(await _quickConnectManager.AuthorizeRequest(Guid.Empty, res.Code));
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Emby.Server.Implementations.Sorting;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@@ -13,7 +11,7 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting
{
[Theory]
[ClassData(typeof(EpisodeBadData))]
public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem x, BaseItem y)
public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem? x, BaseItem? y)
{
var cmp = new AiredEpisodeOrderComparer();
Assert.Throws<ArgumentNullException>(() => cmp.Compare(x, y));
@@ -29,152 +27,138 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting
Assert.Equal(-expected, cmp.Compare(y, x));
}
private class EpisodeBadData : IEnumerable<object?[]>
private class EpisodeBadData : TheoryData<BaseItem?, BaseItem?>
{
public IEnumerator<object?[]> GetEnumerator()
public EpisodeBadData()
{
yield return new object?[] { null, new Episode() };
yield return new object?[] { new Episode(), null };
Add(null, new Episode());
Add(new Episode(), null);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
private class EpisodeTestData : IEnumerable<object?[]>
private class EpisodeTestData : TheoryData<BaseItem, BaseItem, int>
{
public IEnumerator<object?[]> GetEnumerator()
public EpisodeTestData()
{
yield return new object?[]
{
Add(
new Movie(),
new Movie(),
0
};
yield return new object?[]
{
0);
Add(
new Movie(),
new Episode(),
1
};
1);
// Good cases
yield return new object?[]
{
Add(
new Episode(),
new Episode(),
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 2, IndexNumber = 1 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
1
};
1);
// Good Specials
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 0, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
1);
// Specials to Episodes
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 2 },
1
};
yield return new object?[]
{
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 2 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 3, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 3, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 3 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
1
};
}
1);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
// Premiere Date
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 11, 0, 0, 0) },
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
-1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 11, 0, 0, 0) },
1);
}
}
}
}

View File

@@ -6,7 +6,9 @@ using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.AutoMoq;
using Emby.Server.Implementations.Archiving;
using Emby.Server.Implementations.Updates;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Updates;
using Moq;
using Moq.Protected;
@@ -40,7 +42,9 @@ namespace Jellyfin.Server.Implementations.Tests.Updates
_fixture.Customize(new AutoMoqCustomization
{
ConfigureMembers = true
}).Inject(http);
});
_fixture.Inject(http);
_fixture.Inject<IZipClient>(new ZipClient());
_installationManager = _fixture.Create<InstallationManager>();
}
@@ -78,5 +82,32 @@ namespace Jellyfin.Server.Implementations.Tests.Updates
packages = _installationManager.FilterPackages(packages, id: new Guid("a4df60c5-6ab4-412a-8f79-2cab93fb2bc5")).ToArray();
Assert.Single(packages);
}
[Fact]
public async Task InstallPackage_InvalidChecksum_ThrowsInvalidDataException()
{
var packageInfo = new InstallationInfo()
{
Name = "Test",
SourceUrl = "https://repo.jellyfin.org/releases/plugin/empty/empty.zip",
Checksum = "InvalidChecksum"
};
await Assert.ThrowsAsync<InvalidDataException>(() => _installationManager.InstallPackage(packageInfo, CancellationToken.None)).ConfigureAwait(false);
}
[Fact]
public async Task InstallPackage_Valid_Success()
{
var packageInfo = new InstallationInfo()
{
Name = "Test",
SourceUrl = "https://repo.jellyfin.org/releases/plugin/empty/empty.zip",
Checksum = "11b5b2f1a9ebc4f66d6ef19018543361"
};
var ex = await Record.ExceptionAsync(() => _installationManager.InstallPackage(packageInfo, CancellationToken.None)).ConfigureAwait(false);
Assert.Null(ex);
}
}
}