testcontainers-dotnet icon indicating copy to clipboard operation
testcontainers-dotnet copied to clipboard

feat(#421) Added AzuriteTestcontainer

Open vlaskal opened this issue 3 years ago • 1 comments

Hi @HofmeisterAn ,

I've created this draft PR with AzuriteTestcontainer. Currently there is only basic support of options. What is done:

  • Default image
  • Custom image
  • Host Blob port bind
  • Host Queue port bind
  • Host Table port bind
  • Connection string
  • Wait strategy
  • Default output consumer
  • onlyBlob
  • onlyQueue
  • onlyTable
  • azurite.blobHost
  • azurite.queueHost
  • azurite.tableHost
  • azurite.location
  • azurite.silent
  • azurite.debug
  • azurite.loose
  • azurite.skipApiVersionCheck
  • azurite.disableProductStyleUrl

What is not done:

  • azurite.containerBlobPort
  • azurite.containerQueuePort
  • azurite.containerTablePort
  • azurite.containerLocation
  • azurite.cert
  • azurite.key
  • azurite.pwd
  • azurite.oauth
  • Account name
  • Account Key

I need to also discuss how to fit it into current approach, which is inheritance from TestcontainerDatabaseConfiguration, TestcontainerDatabase and DatabaseFixture<TDockerContainer, TDatabaseConnection>. The main problem what I have is that I use just few prepared fields or properties and most of them are useless for Azurite. I look at eg. KafkaTestcontainer implementation and I have one suggestion: I think class HostedServiceContainer should be more generic. It means I would like to remove Username and Password proeprty and moved them to specific classes. In this case to TestcontainerDatabase also if it make sense to TestcontainerMessageBroker and leave only Port setup there. Then I can use eg. BlobPort for this default Port implementation. Same think applies to configuration classes HostedServiceConfiguration, TestcontainerDatabaseConfiguration and TestcontainerMessageBrokerConfiguration . Then I can inherit AzuriteTestcontainer directly from HostedServiceTestcontainer.

What do you think?

vlaskal avatar Aug 07 '22 09:08 vlaskal

Main options, switches and settings are implemented. I think more than 90% of use cases should be supported. I would wait if someone will request them. I will move this PR to ready state.

vlaskal avatar Aug 07 '22 20:08 vlaskal

  • I'd suggest to use a more common naming pattern (in. NET) for the boolean properties. Instead of Debug, DisableProductStyleUrl, SkipApiVersionCheck or RunTableOnly, I would use something like DebugEnabled, TableServiceEnabled, IsSilent, etc.

Original intention was to make it same as are command options and documentation. But you are right. I updated names as you suggested.

  • The WithPortBinding configuration looks static. Please use random assigned host ports (GetMappedPublicPort). We cannot rely on static port configurations. Ports may be already in use.

PortBindings is not static. It is same implementation as is used in other containers. Only there is not option to set port inside of container. HostPort value is by default 0 which means it will use random port and will be bind to static ContainerPort. Do you think ContainerPort should be also configurable? I tried to make them configurable as is done in other contianers.

vlaskal avatar Aug 15 '22 05:08 vlaskal

PortBindings is not static. It is same implementation as is used in other containers. Only there is not option to set port inside of container. HostPort value is by default 0 which means it will use random port and will be bind to static ContainerPort.

Ok, then maybe I understood something wrong. I'll take a look at it again (incl. the other classes). Thanks already!

HofmeisterAn avatar Aug 15 '22 14:08 HofmeisterAn

Very nice that you are working on this :D

Came looking because I did not get it working with Azurite and found this pr :)

Would this also work with the Azure SDK for .NET?

I have certifcates created as per their guide and am able to use the docker via

docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -v /absolute-path-on-my-machine/azurite:/workspace  mcr.microsoft.com/azure-storage/azurite azurite --blobHost 0.0.0.0  --queueHost 0.0.0.0 --tableHost 0.0.0.0 --oauth basic --cert /workspace/127.0.0.1.pem --key /workspace/127.0.0.1-key.pem

and consume via

var blobServiceClient = new BlobServiceClient(new Uri("https://127.0.0.1:10000/devstoreaccount1"), new DefaultAzureCredential());
        var containerName = "quickstartblobsbe2dbb6d-efe9-40e6-a8ad-303cffacb9eb";
        var containerClient = blobServiceClient.GetBlobContainerClient(containerName);
        await containerClient.CreateIfNotExistsAsync();

But I am having trouble with doing the same in TestContainers The following works (but without azure credential)

var testcontainersBuilder =
            new TestcontainersBuilder<TestcontainersContainer>()
                .WithImage(image)
                .WithPortBinding(10000)
                .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(10000));
        var testContainer = testcontainersBuilder.Build();
        await testContainer.StartAsync();

var connectionString = "UseDevelopmentStorage=true;"; 

I tried the following

var testcontainersBuilder =
            new TestcontainersBuilder<TestcontainersContainer>()
                .WithImage(image)
                .WithBindMount("/Users/maxhamulyak/Development/BlogTopics/AzureStorage/azurite", "/workspace")
                .WithCommand("azurite", "--blobHost 0.0.0.0", "--oauth basic", "--cert /workspace/127.0.0.1.pem", " -key /workspace/127.0.0.1-key.pem")
                .WithPortBinding(10000)
                .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(10000));

But that results in container is not running

Any hints how to enable DotnetTestcontainers with ssl and --oauth basic would be great.

Thanks Max

kaylumah avatar Aug 25 '22 19:08 kaylumah

Any hints how to enable DotnetTestcontainers with ssl and --oauth basic would be great.

In your example you are using " -key /workspace/127.0.0.1-key.pem" instead of --key .... Did you try something like: .WithCommand("azurite", "--blobHost", "0.0.0.0", "--oauth", "basic", "--cert", "/workspace/127.0.0.1.pem", "--key", "/workspace/127.0.0.1-key.pem")? What error do you get?

HofmeisterAn avatar Aug 26 '22 14:08 HofmeisterAn

Any hints how to enable DotnetTestcontainers with ssl and --oauth basic would be great.

In your example you are using " -key /workspace/127.0.0.1-key.pem" instead of --key .... Did you try something like: .WithCommand("azurite", "--blobHost", "0.0.0.0", "--oauth", "basic", "--cert", "/workspace/127.0.0.1.pem", "--key", "/workspace/127.0.0.1-key.pem")? What error do you get?

Ah you spotted my mistake :) I tried various syntax and apparently in the last one I forgot one dash before key.

var testcontainersBuilder =
            new TestcontainersBuilder<TestcontainersContainer>()
                .WithImage(image)
                .WithBindMount("/absolute-local-path/azurite", "/workspace")
                .WithCommand("azurite", "--blobHost", "0.0.0.0", "--oauth", "basic", "--cert", "/workspace/127.0.0.1.pem", "--key", "/workspace/127.0.0.1-key.pem")
                .WithPortBinding(10000)
                .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(10000));

        var testContainer = testcontainersBuilder.Build();
        await testContainer.StartAsync();
        

        var blobServiceClient = new BlobServiceClient(new Uri("https://127.0.0.1:10000/devstoreaccount1"), new DefaultAzureCredential());
        var containerName = "quickstartblobsbe2dbb6d-efe9-40e6-a8ad-303cffacb9eb";
        var containerClient = blobServiceClient.GetBlobContainerClient(containerName);
        await containerClient.CreateIfNotExistsAsync();
        
        var blobFileName = Guid.NewGuid().ToString();
        var blobClient1 = containerClient.GetBlobClient(blobFileName);
        await blobClient1.UploadAsync(BinaryData.FromString("Hello World!"));

        var blobClient2 = containerClient.GetBlobClient(blobFileName);
        using var ms = new MemoryStream();
        await blobClient2.DownloadToAsync(ms);
        ms.Close();
        var text = new UTF8Encoding().GetString(ms.ToArray());

Where /absolute-local-path/azurite contains the cert files created my mkcert

Thanks again Max

kaylumah avatar Aug 26 '22 17:08 kaylumah

@kaylumah is it working or do you still get an error?

HofmeisterAn avatar Aug 26 '22 17:08 HofmeisterAn

@kaylumah is it working or do you still get an error?

With the snippet I shared it is working, including SSL and OAUTH needed for the .NET Azure SDK see (https://github.com/Azure/Azurite#usage-with-azure-storage-sdks-or-tools)

kaylumah avatar Aug 26 '22 17:08 kaylumah

c03a7fd27bb5e1b515cee716ba4d54418b25d838, 596b14e74169d174529742da8bbadf01be4d1bd5 thanks for all of your help.

HofmeisterAn avatar Aug 27 '22 08:08 HofmeisterAn

c03a7fd, 596b14e thanks for all of your help.

Any time

vlaskal avatar Aug 27 '22 18:08 vlaskal

@kaylumah is it working or do you still get an error?

With the snippet I shared it is working, including SSL and OAUTH needed for the .NET Azure SDK see (https://github.com/Azure/Azurite#usage-with-azure-storage-sdks-or-tools)

@kaylumah Could you describe to me why do you need use SSL? I thought is not used to often and I would like to know if I should add support for it or it can wait. Thanks a lot

vlaskal avatar Aug 27 '22 18:08 vlaskal

@vlaskal see https://github.com/Azure/Azurite#azure-sdks if you want to use stuff like oauth authentication like AzureDefaultCredential you need the https. I believe its best practice as opposed to putting the shared access key in config

kaylumah avatar Aug 27 '22 18:08 kaylumah

@kaylumah thank you for pointing this to me. I will try to create anothe PR and add support gor this. Will this help you?

vlaskal avatar Aug 27 '22 19:08 vlaskal

@vlaskal yeah this will help me :)

Before I found your PR I was doing it like

var testcontainersBuilder =
            new TestcontainersBuilder<TestcontainersContainer>()
                .WithImage(image)
                .WithBindMount("/absolute-local-path/azurite", "/workspace")
                .WithCommand("azurite", "--blobHost", "0.0.0.0", "--oauth", "basic", "--cert", "/workspace/127.0.0.1.pem", "--key", "/workspace/127.0.0.1-key.pem")
                .WithPortBinding(10000)
                .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(10000));

Which does the trick, but doing it typed like you added in this PR would be a big step up

kaylumah avatar Aug 27 '22 19:08 kaylumah

OK, will work on next PR.

vlaskal avatar Aug 27 '22 19:08 vlaskal