Skip to main content

MinIO

The sandwich-contexts-minio package provides contexts for introducing MinIO S3-compatible object storage servers in your tests. MinIO can be launched either as a raw binary or via a container system.

The MinIO server is introduced as a generic TestS3Server, which gives you the flexibility to easily swap out different S3-compatible storage systems in your tests.

Starting MinIO servers

Via Nix-provided binary

The simplest approach uses Nix to obtain the MinIO binary automatically:

https://github.com/codedownio/sandwich/blob/master/demos/demo-minio/app/Main.hs
spec :: TopSpec
spec = describe "Introducing MinIO" $
introduceNixContext nixpkgsReleaseDefault $
introduceMinIOViaNix defaultMinIOContextOptions $ do
it "prints the MinIO server info" $ do
server <- getContext testS3Server
info [i|Got S3 server: #{server}|]

Via container

You can also run MinIO in a container using Docker or Podman:

https://github.com/codedownio/sandwich/blob/master/demos/demo-minio/app/Main.hs
spec :: TopSpec
spec = describe "Introducing MinIO" $
introduceMinIOViaContainer defaultMinIOContextOptions defaultContainerOptions $ do
it "prints the MinIO server info" $ do
server <- getContext testS3Server
info [i|Got S3 server: #{server}|]

Via existing binary

If you already have a MinIO binary available in your environment:

spec :: TopSpec
spec = describe "MinIO with existing binary" $
introduceBinaryViaEnvironment @"minio" $
introduceMinIOViaBinary defaultMinIOContextOptions $ do
it "uses the MinIO server" $ do
server <- getContext testS3Server
info [i|Got S3 server: #{server}|]

Configuration options

The MinIOContextOptions type allows you to customize the MinIO server setup:

data MinIOContextOptions = MinIOContextOptions {
minioContextBucket :: Maybe Text -- Default bucket to create
, minioContextLabels :: Map Text Text -- Container labels (for container mode)
, minioContextStartupTimeout :: Int -- Startup timeout in microseconds
}

Default options:

  • Bucket: "bucket1"
  • Labels: mempty
  • Startup timeout: 60 seconds

Working with the TestS3Server

Once you have a MinIO server running, you can access its configuration through the TestS3Server context:

it "connects to MinIO server" $ do
server <- getContext testS3Server

-- Access server details
info [i|MinIO endpoint: #{testS3ServerEndpoint server}|]
info [i|Access key: #{testS3ServerAccessKeyId server}|]
info [i|Secret key: #{testS3ServerSecretAccessKey server}|]
info [i|Bucket: #{testS3ServerBucket server}|]

Default credentials

MinIO servers started by this library use the default MinIO credentials:

  • Access Key ID: minioadmin
  • Secret Access Key: minioadmin

Integration examples

Working with buckets and objects

We provide support for generating a ConnectInfo for use with the minio-hs package.

import Network.Minio

it "performs S3 operations" $ do
server <- getContext testS3Server
let connectInfo = testS3ServerConnectInfo server

liftIO $ runMinio connectInfo $ do
-- List buckets
buckets <- listBuckets
info [i|Available buckets: #{buckets}|]

-- Upload an object (if bucket exists)
whenJust (testS3ServerBucket server) $ \bucket -> do
let objectName = "test-file.txt"
let content = "Hello, MinIO!"

putObject bucket objectName content [] []
info [i|Uploaded object #{objectName} to bucket #{bucket}|]

-- Download the object back
result <- getObject bucket objectName
downloadedContent <- loadBytes result
info [i|Downloaded content: #{downloadedContent}|]

Using with HTTP clients

Since MinIO provides an HTTP API, you can also interact with it using standard HTTP libraries:

import Network.HTTP.Simple

it "makes HTTP requests to MinIO" $ do
server <- getContext testS3Server
let endpoint = testS3ServerEndpoint server

-- Make a request to the health endpoint
request <- parseRequest $ toString $ endpoint <> "/minio/health/live"
response <- httpLBS request

getResponseStatusCode response `shouldBe` 200
info [i|MinIO health check passed|]

Container mode specifics

When using container mode, additional considerations apply:

Container options

You can customize container behavior using ContainerOptions:

customContainerOptions :: ContainerOptions
customContainerOptions = defaultContainerOptions {
containerOptionsSystem = ContainerSystemDocker
, containerOptionsName = Just "my-minio-server"
}

spec :: TopSpec
spec = introduceMinIOViaContainer defaultMinIOContextOptions customContainerOptions $ do
-- Your tests here

Port mapping

The library automatically handles port mapping, finding an available local port and mapping it to MinIO's internal port (9000). The testS3ServerEndpoint function will give you the correct local address to connect to.

Bracket-style functions

For more control over server lifecycle, you can use the bracket-style functions:

import Control.Monad.IO.Unlift

it "uses bracket-style MinIO" $ do
withMinIOViaBinary "/path/to/minio" defaultMinIOContextOptions $ \server -> do
-- Server is running here
let endpoint = testS3ServerEndpoint server
info [i|Server available at: #{endpoint}|]

These functions are useful when you need to start multiple MinIO servers or when integrating with other resource management patterns.