Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Google Cloud Storage API (fake-gcs-server) module #1023

Merged
merged 29 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1c59633
GCS
KSemenenko Oct 13, 2023
92de687
fix build
KSemenenko Oct 13, 2023
25bf116
fix
KSemenenko Oct 13, 2023
4cbb43b
rename
KSemenenko Oct 13, 2023
5d90a8d
fix dotnet issue
KSemenenko Oct 14, 2023
7c471fa
fix build
KSemenenko Oct 14, 2023
f38592b
auto port fix + tests
KSemenenko Oct 15, 2023
606456d
Merge branch 'develop' into develop
KSemenenko Oct 15, 2023
3d9dc80
code syle
KSemenenko Oct 15, 2023
41ef904
fix using
KSemenenko Oct 15, 2023
f6bae77
fix build
KSemenenko Oct 15, 2023
bfd1e27
namespaces
KSemenenko Oct 15, 2023
164bb72
Merge branch 'develop' into develop
KSemenenko Oct 15, 2023
6b336a8
Update src/Testcontainers.FakeGCSServer/FakeGCSServerBuilder.cs
KSemenenko Oct 16, 2023
ccf38c9
Update tests/Testcontainers.FakeGCSServer.Tests/FakeGCSServerContaine…
KSemenenko Oct 16, 2023
bee9a02
Update tests/Testcontainers.FakeGCSServer.Tests/FakeGCSServerContaine…
KSemenenko Oct 16, 2023
37d1560
global using
KSemenenko Oct 16, 2023
40613da
Merge remote-tracking branch 'origin/develop' into develop
KSemenenko Oct 16, 2023
0c3dc7a
naming
KSemenenko Oct 16, 2023
99dc7a8
naming
KSemenenko Oct 16, 2023
cd1fb72
naming
KSemenenko Oct 16, 2023
2f009bc
Merge branch 'develop' into develop
KSemenenko Oct 16, 2023
4fea409
fix build
KSemenenko Oct 16, 2023
7b178aa
run tests one more time
KSemenenko Oct 16, 2023
978dec3
async test
KSemenenko Oct 16, 2023
0d62034
port 8080
KSemenenko Oct 16, 2023
e339e4a
fix: Remove traling slash (fixes NotFound)
HofmeisterAn Oct 17, 2023
b745326
chore: Rename test member
HofmeisterAn Oct 18, 2023
5bdc1d7
chore: Simplify shell script config
HofmeisterAn Oct 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Testcontainers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Tests", "tes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.WebDriver.Tests", "tests\Testcontainers.WebDriver.Tests\Testcontainers.WebDriver.Tests.csproj", "{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.FakeGCSServer", "src\Testcontainers.FakeGCSServer\Testcontainers.FakeGCSServer.csproj", "{FF86B509-2F9E-4269-ABC2-912B3339DE29}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.FakeGCSServer.Tests", "tests\Testcontainers.FakeGCSServer.Tests\Testcontainers.FakeGCSServer.Tests.csproj", "{9F27AA1B-C25D-400C-BCB0-6B0BF1A1DCEA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -436,6 +440,14 @@ Global
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.Build.0 = Release|Any CPU
{FF86B509-2F9E-4269-ABC2-912B3339DE29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF86B509-2F9E-4269-ABC2-912B3339DE29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF86B509-2F9E-4269-ABC2-912B3339DE29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF86B509-2F9E-4269-ABC2-912B3339DE29}.Release|Any CPU.Build.0 = Release|Any CPU
{9F27AA1B-C25D-400C-BCB0-6B0BF1A1DCEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F27AA1B-C25D-400C-BCB0-6B0BF1A1DCEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F27AA1B-C25D-400C-BCB0-6B0BF1A1DCEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F27AA1B-C25D-400C-BCB0-6B0BF1A1DCEA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{3F2E254F-C203-43FD-A078-DC3E2CBC0F9F} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
Expand Down Expand Up @@ -507,5 +519,7 @@ Global
{1A1983E6-5297-435F-B467-E8E1F11277D6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{27CDB869-A150-4593-958F-6F26E5391E7C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{FF86B509-2F9E-4269-ABC2-912B3339DE29} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
{9F27AA1B-C25D-400C-BCB0-6B0BF1A1DCEA} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions src/Testcontainers.FakeGCSServer/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root = true
81 changes: 81 additions & 0 deletions src/Testcontainers.FakeGCSServer/FakeGCSServerBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Text;
using System.Text.RegularExpressions;
KSemenenko marked this conversation as resolved.
Show resolved Hide resolved

namespace Testcontainers.FakeGCSServer;

/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
[PublicAPI]
public sealed class FakeGCSServerBuilder : ContainerBuilder<FakeGCSServerBuilder, FakeGCSServerContainer, FakeGCSServerConfiguration>
{
public const string FakeGCSServerImage = "fsouza/fake-gcs-server:1.47.5";
public const ushort FakeGCSServerPort = 4443;
public const string StartupScriptFilePath = "/testcontainers.sh";

/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerBuilder" /> class.
/// </summary>
public FakeGCSServerBuilder()
: this(new FakeGCSServerConfiguration())
{
DockerResourceConfiguration = Init().DockerResourceConfiguration;
}

/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerBuilder" /> class.
/// </summary>
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
private FakeGCSServerBuilder(FakeGCSServerConfiguration dockerResourceConfiguration)
: base(dockerResourceConfiguration)
{
DockerResourceConfiguration = dockerResourceConfiguration;
}

/// <inheritdoc />
protected override FakeGCSServerConfiguration DockerResourceConfiguration { get; }

/// <inheritdoc />
public override FakeGCSServerContainer Build()
{
Validate();
return new FakeGCSServerContainer(DockerResourceConfiguration, TestcontainersSettings.Logger);
}

/// <inheritdoc />
protected override FakeGCSServerBuilder Init()
{
return base.Init()
.WithImage(FakeGCSServerImage)
.WithPortBinding(FakeGCSServerPort, true)
.WithEntrypoint("/bin/sh", "-c")
.WithCommand($"while [ ! -f {StartupScriptFilePath} ]; do sleep 0.1; done; sh {StartupScriptFilePath}")
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged(new Regex("server started at.*", RegexOptions.IgnoreCase)))
.WithStartupCallback((container, ct) =>
{
const char lf = '\n';
var startupScript = new StringBuilder();
startupScript.Append("#!/bin/bash");
startupScript.Append(lf);
startupScript.Append($"fake-gcs-server -backend memory -scheme http -port {FakeGCSServerPort} -external-url \"http://localhost:{container.GetMappedPublicPort(FakeGCSServerPort)}\"");
KSemenenko marked this conversation as resolved.
Show resolved Hide resolved
startupScript.Append(lf);
return container.CopyAsync(Encoding.Default.GetBytes(startupScript.ToString()), StartupScriptFilePath, Unix.FileMode755, ct);
});
}

/// <inheritdoc />
protected override FakeGCSServerBuilder Clone(IContainerConfiguration resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new FakeGCSServerConfiguration(resourceConfiguration));
}

/// <inheritdoc />
protected override FakeGCSServerBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new FakeGCSServerConfiguration(resourceConfiguration));
}

/// <inheritdoc />
protected override FakeGCSServerBuilder Merge(FakeGCSServerConfiguration oldValue, FakeGCSServerConfiguration newValue)
{
return new FakeGCSServerBuilder(new FakeGCSServerConfiguration(oldValue, newValue));
}
}
53 changes: 53 additions & 0 deletions src/Testcontainers.FakeGCSServer/FakeGCSServerConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace Testcontainers.FakeGCSServer;

/// <inheritdoc cref="ContainerConfiguration" />
[PublicAPI]
public sealed class FakeGCSServerConfiguration : ContainerConfiguration
{
/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerConfiguration" /> class.
/// </summary>
public FakeGCSServerConfiguration()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public FakeGCSServerConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
: base(resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}

/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public FakeGCSServerConfiguration(IContainerConfiguration resourceConfiguration)
: base(resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}

/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public FakeGCSServerConfiguration(FakeGCSServerConfiguration resourceConfiguration)
: this(new FakeGCSServerConfiguration(), resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}

/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerConfiguration" /> class.
/// </summary>
/// <param name="oldValue">The old Docker resource configuration.</param>
/// <param name="newValue">The new Docker resource configuration.</param>
public FakeGCSServerConfiguration(FakeGCSServerConfiguration oldValue, FakeGCSServerConfiguration newValue)
: base(oldValue, newValue)
{
}
}
26 changes: 26 additions & 0 deletions src/Testcontainers.FakeGCSServer/FakeGCSServerContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace Testcontainers.FakeGCSServer;

/// <inheritdoc cref="DockerContainer" />
[PublicAPI]
public sealed class FakeGCSServerContainer : DockerContainer
{
/// <summary>
/// Initializes a new instance of the <see cref="FakeGCSServerContainer" /> class.
/// </summary>
/// <param name="configuration">The container configuration.</param>
/// <param name="logger">The logger.</param>
public FakeGCSServerContainer(FakeGCSServerConfiguration configuration, ILogger logger)
: base(configuration, logger)
{
}

/// <summary>
/// Gets the FakeGCSServer connection string.
/// </summary>
/// <returns>The FakeGCSServer connection string.</returns>
public string GetConnectionString()
{
var builder = new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(FakeGCSServerBuilder.FakeGCSServerPort), "storage/v1/");
return builder.ToString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)src/Testcontainers/Testcontainers.csproj"/>
</ItemGroup>
</Project>
8 changes: 8 additions & 0 deletions src/Testcontainers.FakeGCSServer/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
global using System;
global using System.Net;
global using Docker.DotNet.Models;
global using DotNet.Testcontainers.Builders;
global using DotNet.Testcontainers.Configurations;
global using DotNet.Testcontainers.Containers;
global using JetBrains.Annotations;
global using Microsoft.Extensions.Logging;
1 change: 1 addition & 0 deletions tests/Testcontainers.FakeGCSServer.Tests/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Text;
using System.IO;

namespace Testcontainers.FakeGCSServer;

public abstract class FakeGCSServerContainerTest : IAsyncLifetime
{
private readonly FakeGCSServerContainer _fakeGCSServerContainer = new FakeGCSServerBuilder().Build();

public Task InitializeAsync()
{
return _fakeGCSServerContainer.StartAsync();
}

public Task DisposeAsync()
{
return _fakeGCSServerContainer.DisposeAsync().AsTask();
}

public sealed class BlobService : FakeGCSServerContainerTest
{
[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task EstablishesConnection()
{
string testProject = "test-project";
string testBucket = "test-bucket";
string content = "Hello Google Storage";

// Give
var client = await new StorageClientBuilder
{
UnauthenticatedAccess = true,
BaseUri = _fakeGCSServerContainer.GetConnectionString()
}.BuildAsync();

// When
client.CreateBucket(testProject, testBucket);
client.UploadObject(testBucket, "hello.txt", "text/plain", new MemoryStream(Encoding.UTF8.GetBytes(content)));
var ms = new MemoryStream();
KSemenenko marked this conversation as resolved.
Show resolved Hide resolved
client.DownloadObject(testBucket, "hello.txt", ms);
var blobContent = Encoding.UTF8.GetString(ms.ToArray());

// Then
Assert.True(content == blobContent);
KSemenenko marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<IsPublishable>false</IsPublishable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2"/>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0"/>
<PackageReference Include="xunit" Version="2.5.0"/>
<PackageReference Include="Google.Api.Gax" Version="4.4.0" />
<PackageReference Include="Google.Api.Gax.Rest" Version="4.4.0" />
<PackageReference Include="Google.Apis.Storage.v1" Version="1.62.1.3190" />
<PackageReference Include="Google.Cloud.Storage.V1" Version="4.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Testcontainers.FakeGCSServer\Testcontainers.FakeGCSServer.csproj" />
<ProjectReference Include="$(SolutionDir)tests/Testcontainers.Commons/Testcontainers.Commons.csproj"/>
</ItemGroup>
</Project>
6 changes: 6 additions & 0 deletions tests/Testcontainers.FakeGCSServer.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
global using System.Threading.Tasks;
global using DotNet.Testcontainers.Commons;
global using System.Linq;
global using Google.Cloud.Storage.V1;
global using Testcontainers.FakeGCSServer;
global using Xunit;