diff --git a/README.md b/README.md index 29fe86f..35fa1f3 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,26 @@ The following NuGet packages have been published: | [CommunityToolkit.Datasync.Server.NSwag] | ![NSwag Library Version][vs-nswag] | ![NSwag Library Downloads][ds-nswag] | | [CommunityToolkit.Datasync.Server.Swashbuckle] | ![Swashbuckle Library Version][vs-swashbuckle] | ![Swashbuckle Library Downloads][ds-swashbuckle] | +## Running Live Tests + +The test suite for the library includes "live tests" against real servers that are not normally run. To run those tests, you will need access to an +Azure account (you can sign up for one for free): + +1. Install the [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd) +2. Run `azd up` in a command line. + +This script will create several resources. The cost of running those resources is approximately $40/month (US dollars). However, you will only have +to run the services for less than an hour, so the cost of testing the library should be minimal. The process will create a `.runsettings` file in the +tests directory which you can use to enable the live testing. + +Live testing can be run using the Visual Studio Test Explorer or via `dotnet test`. + +Once you have completed running the tests, you can remove the created services using `azd down`. This will also remove the `.runsettings` file so that +live tests are not attempted any more. + +> **NOTE**: The `.runsettings` file contains secrets. It should not be checked in. We have added this file to the `.gitignore` to ensure that it is +> not checked into public GitHub repositories. + ## 🌍 Roadmap Read what we [plan for next iterations](https://github.com/CommunityToolkit/Datasync/milestones), and feel free to ask questions. diff --git a/azure.yaml b/azure.yaml new file mode 100644 index 0000000..9a17799 --- /dev/null +++ b/azure.yaml @@ -0,0 +1,37 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json + +## +## This AZD template will create all the resources necessary to +## test the Community Toolkit/Datasync libraries, plus deploy an +## app service (on free tier) that talks to the AzSQL service +## for the TODO Sample Service +## + +name: communitytoolkit-datasync-test-services + +hooks: + postprovision: + posix: + interactive: true + shell: sh + run: ./infra/scripts/write-runsettings.sh + windows: + interactive: true + shell: pwsh + run: ./infra/scripts/write-runsettings.ps1 + + predown: + posix: + interactive: true + shell: sh + run: ./infra/scripts/remove-runsettings.sh + windows: + interactive: true + shell: pwsh + run: ./infra/scripts/remove-runsettings.ps1 + +services: + todoservice: + language: csharp + project: ./samples/datasync-server/src/Sample.Datasync.Server + host: appservice diff --git a/infra/main.bicep b/infra/main.bicep new file mode 100644 index 0000000..a5ce550 --- /dev/null +++ b/infra/main.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +@minLength(1) +@maxLength(64) +@description('Name of the the environment which is used to generate a short unique hash used in all resources.') +param environmentName string + +@minLength(1) +@description('Primary location for all resources') +param location string + +@description('Id of the user or app to assign application roles') +param principalId string = '' + +@description('Optional - the SQL Server administrator password. If not provided, the username will be \'appadmin\'.') +param sqlAdminUsername string = 'appadmin' + +@secure() +@description('Optional - SQL Server administrator password. If not provided, a random password will be generated.') +param sqlAdminPassword string = newGuid() + +/*********************************************************************************/ + +var resourceToken = toLower(uniqueString(subscription().id, environmentName, location)) +var tags = { 'azd-env-name': environmentName } + +/*********************************************************************************/ + +resource rg 'Microsoft.Resources/resourceGroups@2024-07-01' = { + name: 'rg-${environmentName}' + location: location + tags: tags +} + +module resources './resources.bicep' = { + name: 'resources' + scope: rg + params: { + location: location + tags: tags + principalId: principalId + resourceToken: resourceToken + serviceName: 'todoservice' + sqlAdminUsername: sqlAdminUsername + sqlAdminPassword: sqlAdminPassword + } +} + +/*********************************************************************************/ + +output AZSQL_CONNECTION_STRING string = resources.outputs.AZSQL_CONNECTIONSTRING +output PGSQL_CONNECTION_STRING string = resources.outputs.PGSQL_CONNECTIONSTRING +output COSMOS_CONNECTION_STRING string = resources.outputs.COSMOS_CONNECTIONSTRING +output SERVICE_ENDPOINT string = resources.outputs.SERVICE_ENDPOINT diff --git a/infra/main.parameters.json b/infra/main.parameters.json new file mode 100644 index 0000000..7d7d8f9 --- /dev/null +++ b/infra/main.parameters.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "environmentName": { + "value": "${AZURE_ENV_NAME}" + }, + "location": { + "value": "${AZURE_LOCATION}" + }, + "principalId": { + "value": "${AZURE_PRINCIPAL_ID}" + }, + "sqlAdminUsername": { + "value": "appadmin" + }, + "sqlAdminPassword": { + "value": "$(secretOrRandomPassword)" + } + } +} \ No newline at end of file diff --git a/infra/modules/appservice.bicep b/infra/modules/appservice.bicep new file mode 100644 index 0000000..d899c53 --- /dev/null +++ b/infra/modules/appservice.bicep @@ -0,0 +1,104 @@ +targetScope = 'resourceGroup' + +@minLength(1) +@description('The name of the App Service Plan resource') +param appServicePlanName string + +@minLength(1) +@description('The name of the App Service resource') +param appServiceName string + +@minLength(1) +@description('The name of the test database to create') +param databaseName string = 'tododb' + +@minLength(1) +@description('Primary location for all resources') +param location string = resourceGroup().location + +@description('The name of the deployment in azure.yaml') +param serviceName string = 'todoservice' + +@description('The name of the SQL Server to create.') +param sqlServerName string + +@description('Optional - the SQL Server administrator password. If not provided, the username will be \'appadmin\'.') +param sqlAdminUsername string = 'appadmin' + +@secure() +@description('Optional - SQL Server administrator password. If not provided, a random password will be generated.') +param sqlAdminPassword string = newGuid() + +@description('The list of tags to apply to all resources.') +param tags object = {} + +/*********************************************************************************/ + +resource azsql_server 'Microsoft.Sql/servers@2024-05-01-preview' existing = { + name: sqlServerName +} + +resource sqldb 'Microsoft.Sql/servers/databases@2024-05-01-preview' = { + name: databaseName + parent: azsql_server + location: location + tags: tags + sku: { + name: 'Basic' + } + properties: { + collation: 'SQL_Latin1_General_CP1_CI_AS' + maxSizeBytes: 1073741824 + } +} + +resource appsvc_plan 'Microsoft.Web/serverfarms@2024-04-01' = { + name: appServicePlanName + location: location + tags: tags + sku: { + name: 'B1' + capacity: 1 + } +} + +resource app_service 'Microsoft.Web/sites@2024-04-01' = { + name: appServiceName + location: location + tags: union(tags, { + 'azd-service-name': serviceName + 'hidden-related:${appsvc_plan.id}': 'empty' + }) + properties: { + httpsOnly: true + serverFarmId: appsvc_plan.id + siteConfig: { + ftpsState: 'Disabled' + minTlsVersion: '1.2' + } + } + + resource configLogs 'config' = { + name: 'logs' + properties: { + applicationLogs: { fileSystem: { level: 'Verbose' } } + detailedErrorMessages: { enabled: true } + failedRequestsTracing: { enabled: true } + httpLogs: { fileSystem: { retentionInMb: 35, retentionInDays: 3, enabled: true } } + } + } + + resource connectionStrings 'config' = { + name: 'connectionstrings' + properties: { + DefaultConnection: { + value: 'Data Source=tcp:${azsql_server.properties.fullyQualifiedDomainName},1433;Initial Catalog=${sqldb.name};User Id=${sqlAdminUsername};Password=${sqlAdminPassword};' + type: 'SQLAzure' + } + } + } +} + +/*********************************************************************************/ + +output SERVICE_ENDPOINT string = 'https://${app_service.properties.defaultHostName}' diff --git a/infra/modules/azuresql.bicep b/infra/modules/azuresql.bicep new file mode 100644 index 0000000..e145ab1 --- /dev/null +++ b/infra/modules/azuresql.bicep @@ -0,0 +1,78 @@ +targetScope = 'resourceGroup' + +@description('The list of firewall rules to install') +param firewallRules FirewallRule[] = [ + { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' } +] + +@minLength(1) +@description('The name of the test database to create') +param databaseName string = 'unittests' + +@minLength(1) +@description('Primary location for all resources') +param location string = resourceGroup().location + +@description('The name of the SQL Server to create.') +param sqlServerName string + +@description('Optional - the SQL Server administrator password. If not provided, the username will be \'appadmin\'.') +param sqlAdminUsername string = 'appadmin' + +@secure() +@description('Optional - SQL Server administrator password. If not provided, a random password will be generated.') +param sqlAdminPassword string = newGuid() + +@description('The list of tags to apply to all resources.') +param tags object = {} + +/*********************************************************************************/ + +resource azsql_server 'Microsoft.Sql/servers@2024-05-01-preview' = { + name: sqlServerName + location: location + tags: tags + properties: { + version: '12.0' + minimalTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + administratorLogin: sqlAdminUsername + administratorLoginPassword: sqlAdminPassword + } + + resource fw 'firewallRules' = [ + for fwRule in firewallRules: { + name: '${fwRule.startIpAddress}-${fwRule.endIpAddress}' + properties: { + startIpAddress: fwRule.startIpAddress + endIpAddress: fwRule.endIpAddress + } + } + ] +} + +resource azsql_database 'Microsoft.Sql/servers/databases@2024-05-01-preview' = { + name: databaseName + parent: azsql_server + location: location + tags: tags + sku: { + name: 'Basic' + tier: 'Basic' + } + properties: { + collation: 'SQL_Latin1_General_CP1_CI_AS' + } +} + +/*********************************************************************************/ + +#disable-next-line outputs-should-not-contain-secrets +output AZSQL_CONNECTIONSTRING string = 'Data Source=tcp:${azsql_server.properties.fullyQualifiedDomainName},1433;Initial Catalog=${azsql_database.name};User Id=${azsql_server.properties.administratorLogin}@${azsql_server.properties.fullyQualifiedDomainName};Password=${sqlAdminPassword};Encrypt=True;TrustServerCertificate=False' + +/*********************************************************************************/ + +type FirewallRule = { + startIpAddress: string + endIpAddress: string +} diff --git a/infra/modules/cosmos.bicep b/infra/modules/cosmos.bicep new file mode 100644 index 0000000..a4704da --- /dev/null +++ b/infra/modules/cosmos.bicep @@ -0,0 +1,91 @@ +targetScope = 'resourceGroup' + +@minLength(1) +@description('The name of the test container to create') +param containerName string = 'Movies' + +@minLength(1) +@description('The name of the test database to create') +param databaseName string = 'unittests' + +@minLength(1) +@description('Primary location for all resources') +param location string = resourceGroup().location + +@description('The name of the SQL Server to create.') +param serverName string + +@description('The list of tags to apply to all resources.') +param tags object = {} + +/*********************************************************************************/ + +resource cosmos_account 'Microsoft.DocumentDB/databaseAccounts@2024-02-15-preview' = { + name: serverName + location: location + tags: tags + kind: 'GlobalDocumentDB' + properties: { + consistencyPolicy: { + defaultConsistencyLevel: 'Session' + } + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + disableKeyBasedMetadataWriteAccess: true + } +} + +resource cosmos_database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2024-02-15-preview' = { + name: databaseName + parent: cosmos_account + properties: { + resource: { + id: databaseName + } + } +} + +resource cosmos_container 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2023-09-15' = { + name: containerName + parent: cosmos_database + properties: { + resource: { + id: containerName + partitionKey: { + paths: ['/id'] + kind: 'Hash' + } + indexingPolicy: { + indexingMode: 'consistent' + includedPaths: [ + { path: '/*' } + ] + excludedPaths: [ + { path: '/_etag/?' } + ] + compositeIndexes: [ + [ + { path: '/UpdatedAt', order: 'ascending' } + { path: '/Id', order: 'ascending' } + ] + ] + } + defaultTtl: 86400 + } + options: { + throughput: 400 + } + } +} + +/*********************************************************************************/ + +#disable-next-line outputs-should-not-contain-secrets +output COSMOS_CONNECTIONSTRING string = cosmos_account.listConnectionStrings().connectionStrings[0].connectionString diff --git a/infra/modules/postgresql.bicep b/infra/modules/postgresql.bicep new file mode 100644 index 0000000..eb1ab6a --- /dev/null +++ b/infra/modules/postgresql.bicep @@ -0,0 +1,89 @@ +targetScope = 'resourceGroup' + +@description('The list of firewall rules to install') +param firewallRules FirewallRule[] = [ + { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' } +] + +@minLength(1) +@description('The name of the test database to create') +param databaseName string = 'unittests' + +@minLength(1) +@description('Primary location for all resources') +param location string = resourceGroup().location + +@description('The name of the SQL Server to create.') +param sqlServerName string + +@description('Optional - the SQL Server administrator password. If not provided, the username will be \'appadmin\'.') +param sqlAdminUsername string = 'appadmin' + +@secure() +@description('Optional - SQL Server administrator password. If not provided, a random password will be generated.') +param sqlAdminPassword string = newGuid() + +@description('The list of tags to apply to all resources.') +param tags object = {} + +/*********************************************************************************/ + +resource pgsql_server 'Microsoft.DBforPostgreSQL/flexibleServers@2023-06-01-preview' = { + name: sqlServerName + location: location + tags: tags + sku: { + name: 'Standard_B1ms' + tier: 'Burstable' + } + properties: { + administratorLogin: sqlAdminUsername + administratorLoginPassword: sqlAdminPassword + createMode: 'Default' + authConfig: { + activeDirectoryAuth: 'Disabled' + passwordAuth: 'Enabled' + } + backup: { + backupRetentionDays: 7 + geoRedundantBackup: 'Disabled' + } + highAvailability: { + mode: 'Disabled' + } + storage: { + storageSizeGB: 32 + autoGrow: 'Disabled' + } + version: '15' + } + + resource fw 'firewallRules' = [ for (fwRule, idx) in firewallRules : { + name: 'fw${idx}' + properties: { + startIpAddress: fwRule.startIpAddress + endIpAddress: fwRule.endIpAddress + } + }] +} + +resource pgsql_database 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2023-03-01-preview' = { + name: databaseName + parent: pgsql_server + properties: { + charset: 'UTF8' + collation: 'en_US.utf8' + } +} + +/*********************************************************************************/ + +#disable-next-line outputs-should-not-contain-secrets +output PGSQL_CONNECTIONSTRING string = 'Host=${pgsql_server.properties.fullyQualifiedDomainName};Database=${pgsql_database.name};Username=${pgsql_server.properties.administratorLogin};Password=${sqlAdminPassword}' + +/*********************************************************************************/ + +type FirewallRule = { + startIpAddress: string + endIpAddress: string +} diff --git a/infra/resources.bicep b/infra/resources.bicep new file mode 100644 index 0000000..ce72f1d --- /dev/null +++ b/infra/resources.bicep @@ -0,0 +1,114 @@ +targetScope = 'resourceGroup' + +@minLength(1) +@description('Primary location for all resources') +param location string + +@description('The IP address of the place running the tests') +param clientIpAddress string? + +@description('Id of the user or app to assign application roles') +#disable-next-line no-unused-params +param principalId string = '' + +@description('The resource token to use in constructing all service names') +param resourceToken string + +@description('The service name (in azure.yaml) to use for code deployment') +param serviceName string = 'todoservice' + +@description('Optional - the SQL Server administrator password. If not provided, the username will be \'appadmin\'.') +param sqlAdminUsername string = 'appadmin' + +@secure() +@description('Optional - SQL Server administrator password. If not provided, a random password will be generated.') +param sqlAdminPassword string = newGuid() + +@description('The list of tags to apply to all resources.') +param tags object = {} + +/*********************************************************************************/ + +var appServicePlanName = 'asp-${resourceToken}' +var appServiceName = 'web-${resourceToken}' +var azsqlServerName = 'sql-${resourceToken}' +var cosmosServerName = 'cosmos-${resourceToken}' +var pgsqlServerName = 'pgsql-${resourceToken}' + +var testDatabaseName = 'unittests' +var cosmosContainerName = 'Movies' + +var clientIpFirewallRules = clientIpAddress != null + ? [ + { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' } + { + endIpAddress: parseCidr('${clientIpAddress!}/32').lastUsable + startIpAddress: parseCidr('${clientIpAddress!}/32').firstUsable + } + ] + : [ + { endIpAddress: '255.255.255.255', startIpAddress: '0.0.0.0' } + ] + +/*********************************************************************************/ + +module azuresql './modules/azuresql.bicep' = { + name: 'azsql-deployment-${resourceToken}' + params: { + location: location + tags: tags + databaseName: testDatabaseName + firewallRules: clientIpFirewallRules + sqlServerName: azsqlServerName + sqlAdminUsername: sqlAdminUsername + sqlAdminPassword: sqlAdminPassword + } +} + +module pgsql './modules/postgresql.bicep' = { + name: 'pgsql-deployment-${resourceToken}' + params: { + location: location + tags: tags + databaseName: testDatabaseName + firewallRules: clientIpFirewallRules + sqlServerName: pgsqlServerName + sqlAdminUsername: sqlAdminUsername + sqlAdminPassword: sqlAdminPassword + } +} + +module cosmos './modules/cosmos.bicep' = { + name: 'cosmos-deployment-${resourceToken}' + params: { + location: location + tags: tags + databaseName: testDatabaseName + containerName: cosmosContainerName + serverName: cosmosServerName + } +} + +module app_service './modules/appservice.bicep' = { + name: 'appsvc-deployment-${resourceToken}' + params: { + location: location + tags: tags + serviceName: serviceName + sqlServerName: azsqlServerName + appServicePlanName: appServicePlanName + appServiceName: appServiceName + sqlAdminUsername: sqlAdminUsername + sqlAdminPassword: sqlAdminPassword + } + dependsOn: [ + azuresql + ] +} + +/*********************************************************************************/ + +output AZSQL_CONNECTIONSTRING string = azuresql.outputs.AZSQL_CONNECTIONSTRING +output PGSQL_CONNECTIONSTRING string = pgsql.outputs.PGSQL_CONNECTIONSTRING +output COSMOS_CONNECTIONSTRING string = cosmos.outputs.COSMOS_CONNECTIONSTRING +output SERVICE_ENDPOINT string = app_service.outputs.SERVICE_ENDPOINT diff --git a/infra/scripts/remove-runsettings.ps1 b/infra/scripts/remove-runsettings.ps1 new file mode 100644 index 0000000..1544150 --- /dev/null +++ b/infra/scripts/remove-runsettings.ps1 @@ -0,0 +1,12 @@ +<# +.SYNOPSIS + This scripts writes a suitable runsettings file for the tests so that + the tests use the appropriate services for live testing. +#> +$outputFile = "tests\.runsettings" + +if (Test-Path $outputFile) { + Remove-Item -Path $outputFile +} else { + Write-Output "File $($outputFile) does not exist." +} diff --git a/infra/scripts/write-runsettings.ps1 b/infra/scripts/write-runsettings.ps1 new file mode 100644 index 0000000..a10aa6a --- /dev/null +++ b/infra/scripts/write-runsettings.ps1 @@ -0,0 +1,23 @@ +<# +.SYNOPSIS + This scripts writes a suitable runsettings file for the tests so that + the tests use the appropriate services for live testing. +#> +$outputs = (azd env get-values --output json | ConvertFrom-Json) +$outputFile = "tests\.runsettings" + +$fileContents = @" + + + + + $($outputs.AZSQL_CONNECTION_STRING) + $($outputs.COSMOS_CONNECTION_STRING) + $($outputs.PGSQL_CONNECTION_STRING) + true + + + +"@ + +$fileContents | Out-File -FilePath $outputFile diff --git a/tests/infra/README.md b/tests/infra/README.md deleted file mode 100644 index 0acf6d6..0000000 --- a/tests/infra/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# Test Infrastructure - -Some of the tests in this repository rely on Azure Infrastructure so that they can run against a real -database service. The files within this folder are the 'Infrastructure as Code' necessary to create -the database services that are required and output the appropriate connection strings. - -## Deployment Instructions - -First, login to Azure with the Azure CLI and set a subscription: - -```bash -$ az login -$ az account set --subscription -``` - -Then create a resource group with a good name and location; with bash: - -```bash -$ export RG=datasync-testing -$ az group create -l westus3 -n $RG -$ az deployment group create -n "d-$RG" -g $RG --template-file ./infra/main.bicep -``` - -Or, with PowerShell: - -```powershell -> $env:RG="datasync-testing" -> az group create -l westus3 -n $env:RG -> az deployment group create -n "d-$($env:RG)" -g $env:RG --template-file .\infra\main.bicep -``` - -Replace the definition of `RG` with a unique name. This will ensure all the resources are unique -and that your tests will run to completion properly. It takes approximately 15-20 minutes to provision -the resources. The following resources are created: - -* Azure SQL Server and Database (Basic SKU - $4.90 per month) -* Azure Cosmos Database (Standard SKU - $0.88 per month) -* Azure DB for PostgreSQL flexible server (Burstable B1ms SKU - $12.99 per month) - -We recommend spinning up the databases for testing as needed, then removing them again. You only need to -run live tests when changing the repository code. - -## Running live tests - -The deployment returns some output which you can read as follows; with bash: - -```bash -$ az deployment group show -n "d-$RG" -g $RG --query properties.outputs -``` - -Or with PowerShell: - -```powershell -> az deployment group show -n "d-$($env:RG)" -g $env:RG --query properties.outputs -``` - -Create a `.runsettings` file in the `tests` directory (or the top level repository directory): - -```xml - - - - - {{connection string}} - {{connection string}} - {{connection string}} - - - -``` - -Replace the connection strings with the appropriate value from the deployment outputs. - -> You can also turn on logging by setting the `ENABLE_SQL_LOGGING` environment variable to `true`. - -You can either run the tests from the Visual Studio Test Explorer or run `dotnet test`. - -## Shutting down the test resources - -Delete the resource group containing the resources; with bash: - -```bash -$ az group delete -n $RG -``` - -Or with PowerShell: - -```powershell -> az group delete -n $env:RG -``` diff --git a/tests/infra/databases/azure-sql.bicep b/tests/infra/databases/azure-sql.bicep deleted file mode 100644 index 7aa7406..0000000 --- a/tests/infra/databases/azure-sql.bicep +++ /dev/null @@ -1,60 +0,0 @@ -targetScope = 'resourceGroup' - -@description('The IP address of the place running the tests') -param clientIpAddress string? - -@description('The name of the database to create') -param databaseName string = 'unittests' - -@minLength(1) -@description('Primary location for all resources') -param location string - -@description('The administrator username for the databases') -param administratorUsername string - -@secure() -@description('The administrator password for the databases') -param administratorPassword string - -var resourceToken = toLower(uniqueString(subscription().id, resourceGroup().name, location)) - -var clientIpFirewallRules = clientIpAddress != null ? [ - { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' } - { endIpAddress: parseCidr('${clientIpAddress!}/32').lastUsable, startIpAddress: parseCidr('${clientIpAddress!}/32').firstUsable } -] : [ - { endIpAddress: '255.255.255.255', startIpAddress: '0.0.0.0' } -] - -resource server 'Microsoft.Sql/servers@2023-08-01-preview' = { - name: 'azsql-${resourceToken}' - location: location - properties: { - administratorLogin: administratorUsername - administratorLoginPassword: administratorPassword - } - - resource fw 'firewallRules' = [ for fwRule in clientIpFirewallRules : { - name: '${fwRule.startIpAddress}-${fwRule.endIpAddress}' - properties: { - startIpAddress: fwRule.startIpAddress - endIpAddress: fwRule.endIpAddress - } - }] -} - -resource database 'Microsoft.Sql/servers/databases@2023-08-01-preview' = { - name: databaseName - parent: server - location: location - sku: { - name: 'Basic' - tier: 'Basic' - } - properties: { - collation: 'SQL_Latin1_General_CP1_CI_AS' - } -} - -#disable-next-line outputs-should-not-contain-secrets -output connectionString string = 'Data Source=tcp:${server.properties.fullyQualifiedDomainName},1433;Initial Catalog=${database.name};User Id=${administratorUsername}@${server.properties.fullyQualifiedDomainName};Password=${administratorPassword};Encrypt=True;TrustServerCertificate=False' diff --git a/tests/infra/databases/cosmos.bicep b/tests/infra/databases/cosmos.bicep deleted file mode 100644 index c244d0b..0000000 --- a/tests/infra/databases/cosmos.bicep +++ /dev/null @@ -1,92 +0,0 @@ -targetScope = 'resourceGroup' - -@description('The IP address of the place running the tests') -#disable-next-line no-unused-params -param clientIpAddress string? - -@description('The name of the database to create') -param databaseName string = 'unittests' - -@minLength(1) -@description('Primary location for all resources') -param location string - -@description('The administrator username for the database') -#disable-next-line no-unused-params -param administratorUsername string? - -@secure() -@description('The administrator password for the database') -#disable-next-line no-unused-params -param administratorPassword string? - -var containerName = 'Movies' -var resourceToken = toLower(uniqueString(subscription().id, resourceGroup().name, location)) - -resource account 'Microsoft.DocumentDB/databaseAccounts@2024-02-15-preview' = { - name: 'cosmos-${resourceToken}' - location: location - kind: 'GlobalDocumentDB' - properties: { - consistencyPolicy: { - defaultConsistencyLevel: 'Session' - } - locations: [ - { - locationName: location - failoverPriority: 0 - isZoneRedundant: false - } - ] - databaseAccountOfferType: 'Standard' - enableAutomaticFailover: false - disableKeyBasedMetadataWriteAccess: true - } -} - -resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2024-02-15-preview' = { - name: databaseName - parent: account - properties: { - resource: { - id: databaseName - } - } -} - -resource container 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2023-09-15' = { - name: containerName - parent: database - properties: { - resource: { - id: containerName - partitionKey: { - paths: [ '/id' ] - kind: 'Hash' - } - indexingPolicy: { - indexingMode: 'consistent' - includedPaths: [ - { path: '/*' } - ] - excludedPaths: [ - { path: '/_etag/?' } - ] - compositeIndexes: [ - [ - { path: '/UpdatedAt', order: 'ascending' } - { path: '/Id', order: 'ascending' } - ] - ] - } - defaultTtl: 86400 - } - options: { - throughput: 400 - } - } -} - - -#disable-next-line outputs-should-not-contain-secrets -output connectionString string = account.listConnectionStrings().connectionStrings[0].connectionString diff --git a/tests/infra/databases/postgresql.bicep b/tests/infra/databases/postgresql.bicep deleted file mode 100644 index 9fddf28..0000000 --- a/tests/infra/databases/postgresql.bicep +++ /dev/null @@ -1,77 +0,0 @@ -targetScope = 'resourceGroup' - -@description('The IP address of the place running the tests') -param clientIpAddress string? - -@description('The name of the database to create') -param databaseName string = 'unittests' - -@minLength(1) -@description('Primary location for all resources') -param location string - -@description('The administrator username for the database') -param administratorUsername string - -@secure() -@description('The administrator password for the database') -param administratorPassword string - -var resourceToken = toLower(uniqueString(subscription().id, resourceGroup().name, location)) -var clientIpFirewallRules = clientIpAddress != null ? [ - { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' } - { endIpAddress: parseCidr('${clientIpAddress!}/32').lastUsable, startIpAddress: parseCidr('${clientIpAddress!}/32').firstUsable } -] : [ - { endIpAddress: '255.255.255.255', startIpAddress: '0.0.0.0' } -] - - -resource server 'Microsoft.DBforPostgreSQL/flexibleServers@2023-06-01-preview' = { - name: 'pgserver-${resourceToken}' - location: location - sku: { - name: 'Standard_B1ms' - tier: 'Burstable' - } - properties: { - administratorLogin: administratorUsername - administratorLoginPassword: administratorPassword - createMode: 'Default' - authConfig: { - activeDirectoryAuth: 'Disabled' - passwordAuth: 'Enabled' - } - backup: { - backupRetentionDays: 7 - geoRedundantBackup: 'Disabled' - } - highAvailability: { - mode: 'Disabled' - } - storage: { - storageSizeGB: 32 - autoGrow: 'Disabled' - } - version: '15' - } - - resource fw 'firewallRules' = [ for (fwRule, idx) in clientIpFirewallRules : { - name: 'fw${idx}' - properties: { - startIpAddress: fwRule.startIpAddress - endIpAddress: fwRule.endIpAddress - } - }] -} - -resource database 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2023-03-01-preview' = { - name: databaseName - parent: server - properties: { - charset: 'UTF8' - collation: 'en_US.utf8' - } -} - -#disable-next-line outputs-should-not-contain-secrets -output connectionString string = 'Host=${server.properties.fullyQualifiedDomainName};Database=${database.name};Username=${administratorUsername};Password=${administratorPassword}' diff --git a/tests/infra/main.bicep b/tests/infra/main.bicep deleted file mode 100644 index a95537c..0000000 --- a/tests/infra/main.bicep +++ /dev/null @@ -1,59 +0,0 @@ -targetScope = 'resourceGroup' - -@description('The IP address of the place running the tests') -param clientIpAddress string? - -@minLength(1) -@description('Primary location for all resources') -param location string = resourceGroup().location - -@description('The administrator username for the databases') -param administratorUsername string = 'testadmin' - -@secure() -@description('The administrator password for the databases') -param administratorPassword string = newGuid() - -var resourceToken = toLower(uniqueString(subscription().id, resourceGroup().name, location)) - -// Azure SQL -module azuresql './databases/azure-sql.bicep' = { - name: 'deploy-azuresql-${resourceToken}' - params: { - administratorUsername: administratorUsername - administratorPassword: administratorPassword - clientIpAddress: clientIpAddress - location: location - } -} - -#disable-next-line outputs-should-not-contain-secrets -output AZSQL_CONNECTIONSTRING string = azuresql.outputs.connectionString - -// PostgreSQL -module postgresql './databases/postgresql.bicep' = { - name: 'deploy-postgresql-${resourceToken}' - params: { - administratorUsername: administratorUsername - administratorPassword: administratorPassword - clientIpAddress: clientIpAddress - location: location - } -} - -#disable-next-line outputs-should-not-contain-secrets -output PGSQL_CONNECTIONSTRING string = postgresql.outputs.connectionString - -// Cosmos -module cosmos './databases/cosmos.bicep' = { - name: 'deploy-cosmos-${resourceToken}' - params: { - administratorUsername: administratorUsername - administratorPassword: administratorPassword - clientIpAddress: clientIpAddress - location: location - } -} - -#disable-next-line outputs-should-not-contain-secrets -output COSMOS_CONNECTIONSTRING string = cosmos.outputs.connectionString