Browse Source

Fixes to language handling.

pull/479/head
Sebastian 7 years ago
parent
commit
597633a596
  1. 12
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/LanguageConfig.cs
  2. 27
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/LanguagesConfig.cs
  3. 67
      backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/LanguagesConfigTests.cs
  4. 15
      backend/tools/TestSuite/TestSuite.ApiTests/AppCreationTests.cs
  5. 114
      backend/tools/TestSuite/TestSuite.ApiTests/AppLanguagesTests.cs
  6. 12
      backend/tools/TestSuite/TestSuite.ApiTests/AppTests.cs
  7. 142
      backend/tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs
  8. 126
      backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs
  9. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleAudio_0.4mb.mp3
  10. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleGIFImage_40kbmb.gif
  11. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleJPGImage_50kbmb.jpg
  12. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SamplePNGImage_100kbmb.png
  13. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_1280x720_1mb.flv
  14. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_1280x720_1mb.mkv
  15. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_1280x720_1mb.mp4
  16. BIN
      backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_176x144_1mb.3gp
  17. 34
      backend/tools/TestSuite/TestSuite.ApiTests/LanguagesTests.cs
  18. 46
      backend/tools/TestSuite/TestSuite.ApiTests/PingTests.cs
  19. 24
      backend/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj
  20. 56
      backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs
  21. 26
      backend/tools/TestSuite/TestSuite.Shared/Fixtures/ClientFixture.cs
  22. 37
      backend/tools/TestSuite/TestSuite.Shared/Fixtures/ClientManagerFixture.cs
  23. 2
      backend/tools/TestSuite/TestSuite.Shared/Fixtures/ContentFixture.cs
  24. 3
      backend/tools/TestSuite/TestSuite.Shared/Fixtures/CreatedAppFixture.cs
  25. 31
      backend/tools/TestSuite/TestSuite.Shared/Model/TestClient.cs
  26. 4
      backend/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj
  27. 6
      backend/tools/TestSuite/TestSuite.sln

12
backend/src/Squidex.Domain.Apps.Core.Model/Apps/LanguageConfig.cs

@ -58,5 +58,17 @@ namespace Squidex.Domain.Apps.Core.Apps
this.language = language;
this.languageFallbacks = fallback ?? Array.Empty<Language>();
}
public LanguageConfig WithoutFallback(Language fallback)
{
Guard.NotNull(fallback);
if (languageFallbacks.Contains(fallback))
{
return new LanguageConfig(Language, IsOptional, LanguageFallbacks.Except(new[] { fallback }));
}
return this;
}
}
}

27
backend/src/Squidex.Domain.Apps.Core.Model/Apps/LanguagesConfig.cs

@ -89,19 +89,26 @@ namespace Squidex.Domain.Apps.Core.Apps
}
[Pure]
public LanguagesConfig MakeMaster(Language language)
public LanguagesConfig Set(Language language, bool isOptional = false, IEnumerable<Language>? fallback = null)
{
Guard.NotNull(language);
return Create(languages, languages[language]);
return Set(new LanguageConfig(language, isOptional, fallback));
}
[Pure]
public LanguagesConfig Set(Language language, bool isOptional = false, IEnumerable<Language>? fallback = null)
public LanguagesConfig MakeMaster(Language language)
{
Guard.NotNull(language);
return Set(new LanguageConfig(language, isOptional, fallback));
var newMaster = new LanguageConfig(languages[language].Language);
var newLanguages =
languages
.Without(language)
.With(language, newMaster);
return Create(newLanguages, newMaster);
}
[Pure]
@ -111,7 +118,10 @@ namespace Squidex.Domain.Apps.Core.Apps
var newLanguages = languages.With(config.Language, config);
var newMaster = Master?.Language == config.Language ? config : Master;
var newMaster =
Master.Language != config.Language ?
Master :
config;
return Create(newLanguages, newMaster!);
}
@ -122,12 +132,7 @@ namespace Squidex.Domain.Apps.Core.Apps
Guard.NotNull(language);
var newLanguages =
languages.Values.Where(x => x.Language != language)
.Select(config => new LanguageConfig(
config.Language,
config.IsOptional,
config.LanguageFallbacks.Except(new[] { language })))
.ToArrayDictionary(x => x.Language);
languages.Values.Where(x => x.Language != language).Select(x => x.WithoutFallback(language)).ToArrayDictionary(x => x.Language);
var newMaster =
newLanguages.Values.FirstOrDefault(x => x.Language == Master.Language) ??

67
backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/LanguagesConfigTests.cs

@ -14,15 +14,17 @@ using Squidex.Domain.Apps.Core.Apps;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Core.Model.Apps
{
public class LanguagesConfigTests
{
private readonly LanguagesConfig config_0 = LanguagesConfig.Build(Language.DE);
[Fact]
public void Should_create_initial_config_0()
{
var config_0 = LanguagesConfig.Build(Language.DE);
config_0.OfType<LanguageConfig>().ToList().Should().BeEquivalentTo(
new List<LanguageConfig>
{
@ -37,9 +39,9 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_create_initial_config_0_with_multiple_languages()
{
var config_0 = LanguagesConfig.Build(Language.DE, Language.EN, Language.IT);
var config = LanguagesConfig.Build(Language.DE, Language.EN, Language.IT);
config_0.OfType<LanguageConfig>().ToList().Should().BeEquivalentTo(
config.OfType<LanguageConfig>().ToList().Should().BeEquivalentTo(
new List<LanguageConfig>
{
new LanguageConfig(Language.DE),
@ -47,12 +49,12 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
new LanguageConfig(Language.IT)
});
config_0.TryGetConfig(Language.DE, out var master);
config.TryGetConfig(Language.DE, out var master);
Assert.Equal(Language.DE, config_0.Master.Language);
Assert.Equal(3, config_0.Count);
Assert.Equal(Language.DE, config.Master.Language);
Assert.Equal(3, config.Count);
Assert.Same(master, config_0.Master);
Assert.Same(master, config.Master);
}
[Fact]
@ -64,18 +66,17 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
new LanguageConfig(Language.EN),
new LanguageConfig(Language.IT)
};
var config_0 = LanguagesConfig.Build(configs);
var config = LanguagesConfig.Build(configs);
config_0.OfType<LanguageConfig>().ToList().Should().BeEquivalentTo(configs);
config.OfType<LanguageConfig>().ToList().Should().BeEquivalentTo(configs);
Assert.Equal(configs[0], config_0.Master);
Assert.Same(configs[0], config_0.Master);
Assert.Equal(configs[0], config.Master);
Assert.Same(configs[0], config.Master);
}
[Fact]
public void Should_add_language()
{
var config_0 = LanguagesConfig.Build(Language.DE);
var config_1 = config_0.Set(Language.IT);
config_1.OfType<LanguageConfig>().ToList().Should().BeEquivalentTo(
@ -92,36 +93,30 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_make_first_language_to_master()
{
var config_0 = LanguagesConfig.Build(Language.IT);
Assert.Equal(Language.IT, config_0.Master.Language);
Assert.Equal(Language.DE, config_0.Master.Language);
}
[Fact]
public void Should_not_throw_exception_if_language_to_add_already_exists()
{
var config_0 = LanguagesConfig.Build(Language.DE);
config_0.Set(Language.DE);
}
[Fact]
public void Should_make_master_language()
{
var config_0 = LanguagesConfig.Build(Language.DE);
var config_1 = config_0.Set(Language.UK);
var config_2 = config_1.Set(Language.IT);
var config_2 = config_1.Set(Language.IT, true, new[] { Language.UK });
var config_3 = config_2.MakeMaster(Language.IT);
Assert.Equal(Language.IT, config_3.Master.Language);
Assert.False(config_3.Master.IsOptional);
}
[Fact]
public void Should_return_same_languages_if_master_language_is_already_master()
{
var config_0 = LanguagesConfig.Build(Language.DE);
var config_1 = config_0.Set(Language.UK);
var config_2 = config_1.Set(Language.IT);
var config_3 = config_2.MakeMaster(Language.IT);
@ -133,24 +128,20 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_throw_exception_if_language_to_make_master_is_not_found()
{
var config_0 = LanguagesConfig.Build(Language.DE);
Assert.Throws<KeyNotFoundException>(() => config_0.MakeMaster(Language.EN));
}
[Fact]
public void Should_not_throw_exception_if_language_is_already_master_language()
{
var config_0 = LanguagesConfig.Build(Language.DE);
config_0.MakeMaster(Language.DE);
}
[Fact]
public void Should_remove_language()
{
var config_0 = LanguagesConfig.Build(Language.DE, Language.IT, Language.RU);
var config_1 = config_0.Remove(Language.IT);
var config = LanguagesConfig.Build(Language.DE, Language.IT, Language.RU);
var config_1 = config.Remove(Language.IT);
Assert.Same(config_1.Master, config_1.OfType<LanguageConfig>().FirstOrDefault(x => x.Language == Language.DE));
@ -165,12 +156,12 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_remove_fallbacks_when_removing_language()
{
var config_0 =
var config =
LanguagesConfig.Build(
new LanguageConfig(Language.DE),
new LanguageConfig(Language.IT, false, Language.RU, Language.IT),
new LanguageConfig(Language.RU, false, Language.DE, Language.IT));
var config_1 = config_0.Remove(Language.IT);
var config_1 = config.Remove(Language.IT);
config_1.OfType<LanguageConfig>().ToList().Should().BeEquivalentTo(
new List<LanguageConfig>
@ -181,9 +172,8 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
}
[Fact]
public void Should_do_nothing_if_language_to_remove_is_not_found()
public void Should_return_same_languages_if_language_to_remove_is_not_found()
{
var config_0 = LanguagesConfig.Build(Language.DE);
var config_1 = config_0.Remove(Language.EN);
Assert.Equal(config_0, config_1);
@ -192,15 +182,12 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_throw_exception_if_language_to_remove_is_master()
{
var config_0 = LanguagesConfig.Build(Language.DE);
Assert.Throws<InvalidOperationException>(() => config_0.Remove(Language.DE));
}
[Fact]
public void Should_update_language()
{
var config_0 = LanguagesConfig.Build(Language.DE);
var config_1 = config_0.Set(new LanguageConfig(Language.IT));
var config_2 = config_1.Set(new LanguageConfig(Language.IT, true, Language.DE));
@ -215,16 +202,12 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_throw_exception_if_fallback_language_is_invalid()
{
var config_0 = LanguagesConfig.Build(Language.DE);
Assert.Throws<InvalidOperationException>(() => config_0.Set(new LanguageConfig(Language.DE, false, Language.EN)));
}
[Fact]
public void Should_provide_enumerators()
{
var config_0 = LanguagesConfig.Build(Language.DE);
Assert.NotEmpty(config_0);
Assert.NotNull(((IEnumerable)config_0).GetEnumerator());
@ -234,8 +217,6 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_resolve_language_by_string()
{
var config_0 = LanguagesConfig.Build(Language.DE);
Assert.True(config_0.TryGetItem("de", out var item));
Assert.NotNull(item);
}
@ -243,8 +224,6 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
[Fact]
public void Should_not_resolve_language_fór_invalid_language()
{
var config_0 = LanguagesConfig.Build(Language.DE);
Assert.False(config_0.TryGetItem("invalid", out var item));
Assert.Null(item);
}

15
backend/tools/TestSuite/TestSuite.ApiTests/AppCreationTests.cs

@ -30,6 +30,7 @@ namespace TestSuite.ApiTests
{
var appName = Guid.NewGuid().ToString();
// STEP 1: Create app
var createRequest = new CreateAppDto { Name = appName };
var app = await _.Apps.PostAppAsync(createRequest);
@ -37,16 +38,22 @@ namespace TestSuite.ApiTests
// Should return create app with correct name.
Assert.Equal(appName, app.Name);
// STEP 2: Get all apps
var apps = await _.Apps.GetAppsAsync();
// Should provide new app when apps are queried.
Assert.Contains(apps, x => x.Name == appName);
// STEP 3: Check contributors
var contributors = await _.Apps.GetContributorsAsync(appName);
// Should not client itself as a contributor.
Assert.Empty(contributors.Items);
// STEP 4: Check clients
var clients = await _.Apps.GetClientsAsync(appName);
// Should create default client.
@ -58,7 +65,13 @@ namespace TestSuite.ApiTests
{
var appName = Guid.NewGuid().ToString();
await _.Apps.PostAppAsync(new CreateAppDto { Name = appName });
// STEP 1: Create app
var createRequest = new CreateAppDto { Name = appName };
await _.Apps.PostAppAsync(createRequest);
// STEP 2: Archive app
await _.Apps.DeleteAppAsync(appName);
var apps = await _.Apps.GetAppsAsync();

114
backend/tools/TestSuite/TestSuite.ApiTests/AppLanguagesTests.cs

@ -0,0 +1,114 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Squidex.ClientLibrary.Management;
using TestSuite.Fixtures;
using Xunit;
#pragma warning disable SA1300 // Element should begin with upper-case letter
#pragma warning disable SA1507 // Code should not contain multiple blank lines in a row
namespace TestSuite.ApiTests
{
public sealed class AppLanguagesTests : IClassFixture<ClientFixture>
{
public ClientFixture _ { get; }
public AppLanguagesTests(ClientFixture fixture)
{
_ = fixture;
}
[Fact]
public async Task Should_manage_languages()
{
var appName = Guid.NewGuid().ToString();
// STEP 1: Add app
var createRequest = new CreateAppDto { Name = appName };
await _.Apps.PostAppAsync(createRequest);
// STEP 2: Add languages
await _.Apps.PostLanguageAsync(appName, new AddLanguageDto { Language = "de" });
await _.Apps.PostLanguageAsync(appName, new AddLanguageDto { Language = "it" });
await _.Apps.PostLanguageAsync(appName, new AddLanguageDto { Language = "fr" });
var languages = await _.Apps.GetLanguagesAsync(appName);
var languageEN = languages.Items.First(x => x.Iso2Code == "en");
Assert.Equal(new string[] { "en", "de", "fr", "it" }, languages.Items.Select(x => x.Iso2Code).ToArray());
Assert.True(languageEN.IsMaster);
// STEP 3: Update language1
var updateRequest1 = new UpdateLanguageDto
{
Fallback = new string[]
{
"fr",
"it"
},
IsOptional = true
};
languages = await _.Apps.PutLanguageAsync(appName, "de", updateRequest1);
var languageDE = languages.Items.First(x => x.Iso2Code == "de");
Assert.Equal(new string[] { "fr", "it" }, languageDE.Fallback.ToArray());
Assert.True(languageDE.IsOptional);
// STEP 4: Update language2
var updateRequest2 = new UpdateLanguageDto
{
Fallback = new string[]
{
"fr",
"it"
}
};
languages = await _.Apps.PutLanguageAsync(appName, "en", updateRequest2);
languageEN = languages.Items.First(x => x.Iso2Code == "en");
Assert.Equal(new string[] { "fr", "it" }, updateRequest2.Fallback.ToArray());
// STEP 5: Change master language
var masterRequest = new UpdateLanguageDto { IsMaster = true };
languages = await _.Apps.PutLanguageAsync(appName, "de", masterRequest);
languageDE = languages.Items.First(x => x.Iso2Code == "de");
languageEN = languages.Items.First(x => x.Iso2Code == "en");
Assert.True(languageDE.IsMaster);
Assert.False(languageDE.IsOptional);
Assert.False(languageEN.IsMaster);
Assert.Empty(languageDE.Fallback);
Assert.Equal(new string[] { "de", "en", "fr", "it" }, languages.Items.Select(x => x.Iso2Code).ToArray());
// STEP 6: RemoveRequest
languages = await _.Apps.DeleteLanguageAsync(appName, "fr");
languageEN = languages.Items.First(x => x.Iso2Code == "en");
Assert.Equal(new string[] { "it" }, languageEN.Fallback.ToArray());
Assert.Equal(new string[] { "de", "en", "it" }, languages.Items.Select(x => x.Iso2Code).ToArray());
}
}
}

12
backend/tools/TestSuite/TestSuite.ApiTests/AppsTests.cs → backend/tools/TestSuite/TestSuite.ApiTests/AppTests.cs

@ -18,15 +18,23 @@ using Xunit;
namespace TestSuite.ApiTests
{
public sealed class AppsTests : IClassFixture<CreatedAppFixture>
public sealed class AppTests : IClassFixture<CreatedAppFixture>
{
public CreatedAppFixture _ { get; }
public AppsTests(CreatedAppFixture fixture)
public AppTests(CreatedAppFixture fixture)
{
_ = fixture;
}
[Fact]
public async Task Should_get_app()
{
var app = await _.Apps.GetAppAsync(_.AppName);
Assert.Equal(_.AppName, app.Name);
}
[Fact]
public async Task Should_manage_clients()
{

142
backend/tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs

@ -0,0 +1,142 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.ClientLibrary.Management;
using TestSuite.Fixtures;
using Xunit;
#pragma warning disable SA1300 // Element should begin with upper-case letter
#pragma warning disable SA1507 // Code should not contain multiple blank lines in a row
namespace TestSuite.ApiTests
{
public class AssetFormatTests : IClassFixture<AssetFixture>
{
public AssetFixture _ { get; }
public AssetFormatTests(AssetFixture fixture)
{
_ = fixture;
}
[Fact]
public async Task Should_upload_image_gif()
{
var asset = await _.UploadFileAsync("Assets/SampleGIFImage_40kbmb.gif", "image/gif");
// Should create metadata.
Assert.True(asset.IsImage);
Assert.Equal(312, asset.PixelHeight);
Assert.Equal(312, asset.PixelWidth);
Assert.Equal(312L, asset.Metadata["pixelHeight"]);
Assert.Equal(312L, asset.Metadata["pixelWidth"]);
Assert.Equal(AssetType.Image, asset.Type);
}
[Fact]
public async Task Should_upload_image_gif_without_extension()
{
var asset = await _.UploadFileAsync("Assets/SampleGIFImage_40kbmb.gif", "image/gif", Guid.NewGuid().ToString());
// Should create metadata.
Assert.True(asset.IsImage);
Assert.Equal(312, asset.PixelHeight);
Assert.Equal(312, asset.PixelWidth);
Assert.Equal(312L, asset.Metadata["pixelHeight"]);
Assert.Equal(312L, asset.Metadata["pixelWidth"]);
Assert.Equal(AssetType.Image, asset.Type);
}
[Fact]
public async Task Should_upload_image_png()
{
var asset = await _.UploadFileAsync("Assets/SamplePNGImage_100kbmb.png", "image/png");
// Should create metadata.
Assert.True(asset.IsImage);
Assert.Equal(170, asset.PixelHeight);
Assert.Equal(272, asset.PixelWidth);
Assert.Equal(170L, asset.Metadata["pixelHeight"]);
Assert.Equal(272L, asset.Metadata["pixelWidth"]);
Assert.Equal(AssetType.Image, asset.Type);
}
[Fact]
public async Task Should_upload_image_jpg()
{
var asset = await _.UploadFileAsync("Assets/SampleJPGImage_50kbmb.jpg", "image/jpg");
// Should create metadata.
Assert.True(asset.IsImage);
Assert.Equal(300, asset.PixelHeight);
Assert.Equal(300, asset.PixelWidth);
Assert.Equal(300L, asset.Metadata["pixelHeight"]);
Assert.Equal(300L, asset.Metadata["pixelWidth"]);
Assert.Equal(96L, asset.Metadata["imageQuality"]);
Assert.Equal(AssetType.Image, asset.Type);
}
[Fact]
public async Task Should_upload_audio_mp3()
{
var asset = await _.UploadFileAsync("Assets/SampleAudio_0.4mb.mp3", "audio/mp3");
// Should create metadata.
Assert.False(asset.IsImage);
Assert.Equal("00:00:28.2708750", asset.Metadata["duration"]);
Assert.Equal(128L, asset.Metadata["audioBitrate"]);
Assert.Equal(2L, asset.Metadata["audioChannels"]);
Assert.Equal(44100L, asset.Metadata["audioSampleRate"]);
Assert.Equal(AssetType.Audio, asset.Type);
}
[Fact]
public async Task Should_upload_video_mp4()
{
var asset = await _.UploadFileAsync("Assets/SampleVideo_1280x720_1mb.mp4", "audio/mp4");
// Should create metadata.
Assert.False(asset.IsImage);
Assert.Equal("00:00:05.3120000", asset.Metadata["duration"]);
Assert.Equal(384L, asset.Metadata["audioBitrate"]);
Assert.Equal(2L, asset.Metadata["audioChannels"]);
Assert.Equal(48000L, asset.Metadata["audioSampleRate"]);
Assert.Equal(1280L, asset.Metadata["videoWidth"]);
Assert.Equal(720L, asset.Metadata["videoHeight"]);
Assert.Equal(AssetType.Video, asset.Type);
}
[Fact]
public async Task Should_upload_video_mkv()
{
var asset = await _.UploadFileAsync("Assets/SampleVideo_1280x720_1mb.flv", "audio/webm");
// Should create metadata.
Assert.Equal(AssetType.Unknown, asset.Type);
}
[Fact]
public async Task Should_upload_video_flv()
{
var asset = await _.UploadFileAsync("Assets/SampleVideo_1280x720_1mb.flv", "audio/x-flv");
// Should create metadata.
Assert.Equal(AssetType.Unknown, asset.Type);
}
[Fact]
public async Task Should_upload_video_3gp()
{
var asset = await _.UploadFileAsync("Assets/SampleVideo_176x144_1mb.3gp", "audio/3gpp");
// Should create metadata.
Assert.Equal(AssetType.Unknown, asset.Type);
}
}
}

126
backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs

@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Squidex.ClientLibrary;
using Squidex.ClientLibrary.Management;
using TestSuite.Fixtures;
using Xunit;
@ -29,82 +28,19 @@ namespace TestSuite.ApiTests
_ = fixture;
}
[Fact]
public async Task Should_upload_image()
{
var fileName = $"{Guid.NewGuid()}.png";
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var file = new FileParameter(stream, fileName, "image/png");
var asset = await _.Assets.PostAssetAsync(_.AppName, file);
// Should create metadata.
Assert.True(asset.IsImage);
Assert.Equal(600, asset.PixelHeight);
Assert.Equal(600, asset.PixelWidth);
Assert.Equal(600L, asset.Metadata["pixelHeight"]);
Assert.Equal(600L, asset.Metadata["pixelWidth"]);
}
}
[Fact]
public async Task Should_upload_image_without_extension()
{
var fileName = $"{Guid.NewGuid()}.png";
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var file = new FileParameter(stream, fileName, "image/png");
var asset = await _.Assets.PostAssetAsync(_.AppName, file);
// Should create metadata.
Assert.True(asset.IsImage);
Assert.Equal(600, asset.PixelHeight);
Assert.Equal(600, asset.PixelWidth);
Assert.Equal(600L, asset.Metadata["pixelHeight"]);
Assert.Equal(600L, asset.Metadata["pixelWidth"]);
}
}
[Fact]
public async Task Should_replace_asset()
{
var fileName = $"{Guid.NewGuid()}.png";
AssetDto asset;
// STEP 1: Create asset
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var file = new FileParameter(stream, fileName, "image/png");
asset = await _.Assets.PostAssetAsync(_.AppName, file);
Assert.True(asset.IsImage);
Assert.Equal(600, asset.PixelHeight);
Assert.Equal(600, asset.PixelWidth);
}
var asset = await _.UploadFileAsync("Assets/logo-squared.png", "image/png");
// STEP 2: Reupload asset
using (var stream = new FileStream("Assets/logo-wide.png", FileMode.Open))
{
var file = new FileParameter(stream, fileName, "image/png");
asset = await _.Assets.PutAssetContentAsync(_.AppName, asset.Id.ToString(), file);
// Should update metadata.
Assert.True(asset.IsImage);
Assert.Equal(135, asset.PixelHeight);
Assert.Equal(600, asset.PixelWidth);
}
asset = await _.UploadFileAsync("Assets/logo-wide.png", asset);
using (var stream = new FileStream("Assets/logo-wide.png", FileMode.Open))
{
var downloaded = await DownloadAsync(asset);
var downloaded = await _.DownloadAsync(asset);
// Should dowload with correct size.
Assert.Equal(stream.Length, downloaded.Length);
@ -114,17 +50,8 @@ namespace TestSuite.ApiTests
[Fact]
public async Task Should_annote_asset()
{
var fileName = $"{Guid.NewGuid()}.png";
AssetDto asset;
// STEP 1: Create asset
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var file = new FileParameter(stream, fileName, "image/png");
asset = await _.Assets.PostAssetAsync(_.AppName, file);
}
var asset = await _.UploadFileAsync("Assets/logo-squared.png", "image/png");
// STEP 2: Annotate metadata.
@ -166,21 +93,14 @@ namespace TestSuite.ApiTests
{
var fileName = $"{Guid.NewGuid()}.png";
AssetDto asset;
// STEP 1: Create asset
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var file = new FileParameter(stream, fileName, "image/png");
asset = await _.Assets.PostAssetAsync(_.AppName, file);
}
var asset = await _.UploadFileAsync("Assets/logo-squared.png", "image/png");
// STEP 2: Download asset
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var downloaded = await DownloadAsync(asset);
var downloaded = await _.DownloadAsync(asset);
// Should dowload with correct size.
Assert.Equal(stream.Length, downloaded.Length);
@ -211,7 +131,7 @@ namespace TestSuite.ApiTests
// STEP 5: Download asset without key.
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var ex = await Assert.ThrowsAsync<HttpRequestException>(() => DownloadAsync(asset));
var ex = await Assert.ThrowsAsync<HttpRequestException>(() => _.DownloadAsync(asset));
// Should return 403 when not authenticated.
Assert.Contains("403", ex.Message);
@ -221,17 +141,8 @@ namespace TestSuite.ApiTests
[Fact]
public async Task Should_delete_asset()
{
var fileName = $"{Guid.NewGuid()}.png";
AssetDto asset;
// STEP 1: Create asset
using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open))
{
var file = new FileParameter(stream, fileName, "image/png");
asset = await _.Assets.PostAssetAsync(_.AppName, file);
}
var asset = await _.UploadFileAsync("Assets/logo-squared.png", "image/png");
// STEP 2: Delete asset
@ -242,26 +153,5 @@ namespace TestSuite.ApiTests
Assert.Equal(404, ex.StatusCode);
}
private async Task<MemoryStream> DownloadAsync(AssetDto asset)
{
var temp = new MemoryStream();
using (var client = new HttpClient())
{
var url = $"{_.ServerUrl}{asset._links["content"].Href}";
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
{
await stream.CopyToAsync(temp);
}
}
return temp;
}
}
}

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleAudio_0.4mb.mp3

Binary file not shown.

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleGIFImage_40kbmb.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleJPGImage_50kbmb.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SamplePNGImage_100kbmb.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_1280x720_1mb.flv

Binary file not shown.

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_1280x720_1mb.mkv

Binary file not shown.

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_1280x720_1mb.mp4

Binary file not shown.

BIN
backend/tools/TestSuite/TestSuite.ApiTests/Assets/SampleVideo_176x144_1mb.3gp

Binary file not shown.

34
backend/tools/TestSuite/TestSuite.ApiTests/LanguagesTests.cs

@ -0,0 +1,34 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading.Tasks;
using TestSuite.Fixtures;
using Xunit;
#pragma warning disable SA1300 // Element should begin with upper-case letter
#pragma warning disable SA1507 // Code should not contain multiple blank lines in a row
namespace TestSuite.ApiTests
{
public class LanguagesTests : IClassFixture<ClientFixture>
{
public ClientFixture _ { get; }
public LanguagesTests(ClientFixture fixture)
{
_ = fixture;
}
[Fact]
public async Task Should_provide_languages()
{
var languages = await _.Languages.GetLanguagesAsync();
Assert.True(languages.Count > 100);
}
}
}

46
backend/tools/TestSuite/TestSuite.ApiTests/PingTests.cs

@ -0,0 +1,46 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading.Tasks;
using TestSuite.Fixtures;
using Xunit;
#pragma warning disable SA1300 // Element should begin with upper-case letter
#pragma warning disable SA1507 // Code should not contain multiple blank lines in a row
namespace TestSuite.ApiTests
{
public class PingTests : IClassFixture<CreatedAppFixture>
{
public CreatedAppFixture _ { get; }
public PingTests(CreatedAppFixture fixture)
{
_ = fixture;
}
[Fact]
public async Task Should_ping_service()
{
await _.Ping.GetPingAsync();
}
[Fact]
public async Task Should_ping_app()
{
await _.Ping.GetAppPingAsync(_.AppName);
}
[Fact]
public async Task Should_get_info()
{
var infos = await _.Ping.GetInfoAsync();
Assert.NotNull(infos);
}
}
}

24
backend/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj

@ -32,5 +32,29 @@
<None Update="Assets\logo-wide.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleAudio_0.4mb.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleGIFImage_40kbmb.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleJPGImage_50kbmb.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SamplePNGImage_100kbmb.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleVideo_1280x720_1mb.flv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleVideo_1280x720_1mb.mkv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleVideo_1280x720_1mb.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleVideo_176x144_1mb.3gp">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

56
backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs

@ -5,6 +5,10 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Squidex.ClientLibrary.Management;
namespace TestSuite.Fixtures
@ -17,5 +21,57 @@ namespace TestSuite.Fixtures
{
Assets = ClientManager.CreateAssetsClient();
}
public async Task<MemoryStream> DownloadAsync(AssetDto asset)
{
var temp = new MemoryStream();
using (var client = new HttpClient())
{
var url = $"{ServerUrl}{asset._links["content"].Href}";
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
{
await stream.CopyToAsync(temp);
}
}
return temp;
}
public async Task<AssetDto> UploadFileAsync(string path, AssetDto asset, string fileName = null)
{
var fileInfo = new FileInfo(path);
using (var stream = fileInfo.OpenRead())
{
var upload = new FileParameter(stream, fileName ?? RandomName(fileInfo), asset.MimeType);
return await Assets.PutAssetContentAsync(AppName, asset.Id.ToString(), upload);
}
}
public async Task<AssetDto> UploadFileAsync(string path, string mimeType, string fileName = null)
{
var fileInfo = new FileInfo(path);
using (var stream = fileInfo.OpenRead())
{
var upload = new FileParameter(stream, fileName ?? RandomName(fileInfo), mimeType);
return await Assets.PostAssetAsync(AppName, upload);
}
}
private static string RandomName(FileInfo fileInfo)
{
var fileName = $"{Guid.NewGuid()}{fileInfo.Extension}";
return fileName;
}
}
}

26
backend/tools/TestSuite/TestSuite.Shared/Fixtures/ClientFixture.cs

@ -5,34 +5,22 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Squidex.ClientLibrary;
using Squidex.ClientLibrary.Management;
using TestSuite.Model;
namespace TestSuite.Fixtures
{
public class ClientFixture : IDisposable
public class ClientFixture : ClientManagerFixture
{
public SquidexClientManager ClientManager { get; }
public IAppsClient Apps => ClientManager.CreateAppsClient();
public IAppsClient Apps { get; }
public IBackupsClient Backups => ClientManager.CreateBackupsClient();
public IBackupsClient Backups { get; }
public ILanguagesClient Languages => ClientManager.CreateLanguagesClient();
public string ServerUrl { get; } = TestClient.ServerUrl;
public IPingClient Ping => ClientManager.CreatePingClient();
public ClientFixture()
{
ClientManager = TestClient.ClientManager;
public IRulesClient Rules => ClientManager.CreateRulesClient();
Apps = ClientManager.CreateAppsClient();
Backups = ClientManager.CreateBackupsClient();
}
public virtual void Dispose()
{
}
public ISchemasClient Schemas => ClientManager.CreateSchemasClient();
}
}

37
backend/tools/TestSuite/TestSuite.Shared/Fixtures/ClientManagerFixture.cs

@ -0,0 +1,37 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Squidex.ClientLibrary;
namespace TestSuite.Fixtures
{
public class ClientManagerFixture : IDisposable
{
public string ServerUrl { get; } = "http://localhost:5000";
public string ClientId { get; } = "root";
public string ClientSecret { get; } = "xeLd6jFxqbXJrfmNLlO2j1apagGGGSyZJhFnIuHp4I0=";
public string AppName { get; } = "integration-tests";
public SquidexClientManager ClientManager { get; }
public ClientManagerFixture()
{
ClientManager = new SquidexClientManager(ServerUrl, AppName, ClientId, ClientSecret)
{
ReadResponseAsString = true
};
}
public virtual void Dispose()
{
}
}
}

2
backend/tools/TestSuite/TestSuite.Shared/Fixtures/ContentFixture.cs

@ -38,7 +38,7 @@ namespace TestSuite.Fixtures
{
var schemas = ClientManager.CreateSchemasClient();
await schemas.PostSchemaAsync(TestClient.TestAppName, new CreateSchemaDto
await schemas.PostSchemaAsync(AppName, new CreateSchemaDto
{
Name = SchemaName,
Fields = new List<UpsertSchemaFieldDto>

3
backend/tools/TestSuite/TestSuite.Shared/Fixtures/CreatedAppFixture.cs

@ -7,14 +7,11 @@
using System.Threading.Tasks;
using Squidex.ClientLibrary.Management;
using TestSuite.Model;
namespace TestSuite.Fixtures
{
public class CreatedAppFixture : ClientFixture
{
public string AppName { get; } = TestClient.TestAppName;
public CreatedAppFixture()
{
Task.Run(async () =>

31
backend/tools/TestSuite/TestSuite.Shared/Model/TestClient.cs

@ -1,31 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.ClientLibrary;
namespace TestSuite.Model
{
internal static class TestClient
{
public const string ServerUrl = "http://localhost:5000";
public const string ClientId = "root";
public const string ClientSecret = "xeLd6jFxqbXJrfmNLlO2j1apagGGGSyZJhFnIuHp4I0=";
public const string TestAppName = "integration-tests";
public static readonly SquidexClientManager ClientManager =
new SquidexClientManager(
ServerUrl,
TestAppName,
ClientId,
ClientSecret)
{
ReadResponseAsString = true
};
}
}

4
backend/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj

@ -4,7 +4,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.ClientLibrary" Version="4.1.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.4.1" />
</ItemGroup>
@ -15,4 +14,7 @@
<ItemGroup>
<AdditionalFiles Include="..\..\..\stylecop.json" Link="stylecop.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\squidex-samples\csharp\Squidex.ClientLibrary\Squidex.ClientLibrary\Squidex.ClientLibrary.csproj" />
</ItemGroup>
</Project>

6
backend/tools/TestSuite/TestSuite.sln

@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSuite.ApiTests", "TestS
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSuite.LoadTests", "TestSuite.LoadTests\TestSuite.LoadTests.csproj", "{F37572D9-4880-40F4-B3CB-83F58A40CA48}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Squidex.ClientLibrary", "..\..\..\..\squidex-samples\csharp\Squidex.ClientLibrary\Squidex.ClientLibrary\Squidex.ClientLibrary.csproj", "{9AF5F7FD-3C82-4A4F-8494-739911E2BB6F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -27,6 +29,10 @@ Global
{F37572D9-4880-40F4-B3CB-83F58A40CA48}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F37572D9-4880-40F4-B3CB-83F58A40CA48}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F37572D9-4880-40F4-B3CB-83F58A40CA48}.Release|Any CPU.Build.0 = Release|Any CPU
{9AF5F7FD-3C82-4A4F-8494-739911E2BB6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9AF5F7FD-3C82-4A4F-8494-739911E2BB6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9AF5F7FD-3C82-4A4F-8494-739911E2BB6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9AF5F7FD-3C82-4A4F-8494-739911E2BB6F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

Loading…
Cancel
Save