Azurite
Install
npm install @testcontainers/azurite --save-dev
Examples
These examples use the following libraries:
Choose an image from the container registry and substitute IMAGE.
Upload/download a blob
1
2
3
4
5
6
7
8
9
10
11
12
13
14 await using container = await new AzuriteContainer ( IMAGE ). start ();
const connectionString = container . getConnectionString ();
const serviceClient = BlobServiceClient . fromConnectionString ( connectionString );
const containerClient = serviceClient . getContainerClient ( "test" );
await containerClient . createIfNotExists ();
const blobName = "hello.txt" ;
const content = "Hello world!" ;
await containerClient . uploadBlockBlob ( blobName , content , Buffer . byteLength ( content ));
const blobClient = containerClient . getBlockBlobClient ( blobName );
const downloadBuffer = await blobClient . downloadToBuffer ();
expect ( downloadBuffer . toString ()). toBe ( content );
Send/receive queue messages
1
2
3
4
5
6
7
8
9
10
11
12
13 await using container = await new AzuriteContainer ( IMAGE ). start ();
const connectionString = container . getConnectionString ();
const serviceClient = QueueServiceClient . fromConnectionString ( connectionString );
const queueName = "test-queue" ;
await serviceClient . createQueue ( queueName );
const messageText = "Hello world!" ;
const queueClient = serviceClient . getQueueClient ( queueName );
await queueClient . sendMessage ( messageText );
const messages = await queueClient . receiveMessages ();
expect ( messages . receivedMessageItems ). toMatchObject ([{ messageText }]);
Create/insert/fetch on a table
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 await using container = await new AzuriteContainer ( IMAGE ). start ();
const connectionString = container . getConnectionString ();
const tableName = "person" ;
const tableClient = TableClient . fromConnectionString ( connectionString , tableName , {
allowInsecureConnection : true ,
});
await tableClient . createTable ();
const entity : TableEntity < { name : string } > = {
partitionKey : "p1" ,
rowKey : "r1" ,
name : "John Doe" ,
};
await tableClient . createEntity ( entity );
const nextEntity = await tableClient . listEntities (). next ();
expect ( nextEntity . value ). toEqual ( expect . objectContaining ( entity ));
In memory persistence
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 await using container = await new AzuriteContainer ( IMAGE ). withInMemoryPersistence (). start ();
const blobName = "hello.txt" ;
{
const connectionString = container . getConnectionString ();
const serviceClient = BlobServiceClient . fromConnectionString ( connectionString );
const containerClient = serviceClient . getContainerClient ( "test" );
await containerClient . createIfNotExists ();
const content = "Hello world!" ;
await containerClient . uploadBlockBlob ( blobName , content , Buffer . byteLength ( content ));
const blobClient = containerClient . getBlockBlobClient ( blobName );
const blobExists = await blobClient . exists ();
expect ( blobExists ). toBeTruthy ();
}
await container . restart ();
{
const connectionString = container . getConnectionString ();
const serviceClient = BlobServiceClient . fromConnectionString ( connectionString );
const containerClient = serviceClient . getContainerClient ( "test" );
const blobClient = containerClient . getBlockBlobClient ( blobName );
const blobExistsAfterRestart = await blobClient . exists ();
expect ( blobExistsAfterRestart ). toBeFalsy ();
}
With credentials
const accountName = "test-account" ;
const accountKey = Buffer . from ( "test-key" ). toString ( "base64" );
await using container = await new AzuriteContainer ( IMAGE )
. withAccountName ( accountName )
. withAccountKey ( accountKey )
. start ();
const credentials = new StorageSharedKeyCredential ( accountName , accountKey );
const serviceClient = new BlobServiceClient ( container . getBlobEndpoint (), credentials );
With ports
1
2
3
4
5
6
7
8
9
10
11
12
13 const blobPort = 13000 ;
const queuePort = 14000 ;
const tablePort = 15000 ;
await using container = await new AzuriteContainer ( IMAGE )
. withBlobPort ({ container : 10001 , host : blobPort })
. withQueuePort ({ container : 10002 , host : queuePort })
. withTablePort ({ container : 10003 , host : tablePort })
. start ();
expect ( container . getBlobPort ()). toBe ( blobPort );
expect ( container . getQueuePort ()). toBe ( queuePort );
expect ( container . getTablePort ()). toBe ( tablePort );
With HTTPS (PEM certificate)
Code azurite-test-utils
1
2
3
4
5
6
7
8
9
10
11
12
13
14 await using container = await new AzuriteContainer ( IMAGE ). withSsl ( TEST_CERT , TEST_KEY ). start ();
const connectionString = container . getConnectionString ();
expect ( connectionString ). toContain ( "DefaultEndpointsProtocol=https" );
expect ( connectionString ). toContain ( "BlobEndpoint=https://" );
expect ( connectionString ). toContain ( "QueueEndpoint=https://" );
expect ( connectionString ). toContain ( "TableEndpoint=https://" );
const serviceClient = BlobServiceClient . fromConnectionString ( connectionString , getTlsPipelineOptions ( TEST_CERT ));
const containerClient = serviceClient . getContainerClient ( "test" );
await containerClient . createIfNotExists ();
const containerItem = await serviceClient . listContainers (). next ();
expect ( containerItem . value ? . name ). toBe ( "test" );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 type BlobClientPipelineOptions = NonNullable < Parameters < typeof BlobServiceClient . fromConnectionString > [ 1 ] > ;
type BlobClientPipelineOptionsWithTls = BlobClientPipelineOptions & { tlsOptions : { ca : string } };
const base64UrlEncode = ( value : string ) : string => Buffer . from ( value ). toString ( "base64url" );
const createJwtToken = ( payload : Record < string , string | number > ) : string => {
const header = { alg : "none" , typ : "JWT" };
return ` ${ base64UrlEncode ( JSON . stringify ( header )) } . ${ base64UrlEncode ( JSON . stringify ( payload )) } .` ;
};
export const getTlsPipelineOptions = ( ca : string ) : BlobClientPipelineOptionsWithTls => ({
tlsOptions : {
ca ,
},
});
export const createOAuthToken = ( audience : string ) : string => {
const now = Math . floor ( Date . now () / 1000 );
return createJwtToken ({
nbf : now - 60 ,
iat : now - 60 ,
exp : now + 3600 ,
iss : "https://sts.windows.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/" ,
aud : audience ,
scp : "user_impersonation" ,
oid : "23657296-5cd5-45b0-a809-d972a7f4dfe1" ,
tid : "dd0d0df1-06c3-436c-8034-4b9a153097ce" ,
});
};
export const createTokenCredential = ( token : string ) : TokenCredential => ({
getToken : async () => ({
token ,
expiresOnTimestamp : Date.now () + 3600 _000 ,
}),
});
With OAuth (basic)
Code azurite-test-utils
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 await using container = await new AzuriteContainer ( IMAGE ). withSsl ( TEST_CERT , TEST_KEY ). withOAuth (). start ();
const validServiceClient = new BlobServiceClient (
container . getBlobEndpoint (),
createTokenCredential ( createOAuthToken ( "https://storage.azure.com" )),
getTlsPipelineOptions ( TEST_CERT )
);
const validContainerClient = validServiceClient . getContainerClient ( `oauth-valid- ${ Date . now () } ` );
await validContainerClient . create ();
await validContainerClient . delete ();
const invalidServiceClient = new BlobServiceClient (
container . getBlobEndpoint (),
createTokenCredential ( createOAuthToken ( "https://invalidaccount.blob.core.windows.net" )),
getTlsPipelineOptions ( TEST_CERT )
);
const invalidContainerClient = invalidServiceClient . getContainerClient ( `oauth-invalid- ${ Date . now () } ` );
await expect ( invalidContainerClient . create ()). rejects . toThrow ( "Server failed to authenticate the request" );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 type BlobClientPipelineOptions = NonNullable < Parameters < typeof BlobServiceClient . fromConnectionString > [ 1 ] > ;
type BlobClientPipelineOptionsWithTls = BlobClientPipelineOptions & { tlsOptions : { ca : string } };
const base64UrlEncode = ( value : string ) : string => Buffer . from ( value ). toString ( "base64url" );
const createJwtToken = ( payload : Record < string , string | number > ) : string => {
const header = { alg : "none" , typ : "JWT" };
return ` ${ base64UrlEncode ( JSON . stringify ( header )) } . ${ base64UrlEncode ( JSON . stringify ( payload )) } .` ;
};
export const getTlsPipelineOptions = ( ca : string ) : BlobClientPipelineOptionsWithTls => ({
tlsOptions : {
ca ,
},
});
export const createOAuthToken = ( audience : string ) : string => {
const now = Math . floor ( Date . now () / 1000 );
return createJwtToken ({
nbf : now - 60 ,
iat : now - 60 ,
exp : now + 3600 ,
iss : "https://sts.windows.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/" ,
aud : audience ,
scp : "user_impersonation" ,
oid : "23657296-5cd5-45b0-a809-d972a7f4dfe1" ,
tid : "dd0d0df1-06c3-436c-8034-4b9a153097ce" ,
});
};
export const createTokenCredential = ( token : string ) : TokenCredential => ({
getToken : async () => ({
token ,
expiresOnTimestamp : Date.now () + 3600 _000 ,
}),
});