From 0ed85254dd6dd6853d169fa82b340c48871a730a Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 22 Jan 2023 12:30:26 +0100 Subject: [PATCH 01/17] Create README.md Example of unit testing for one or more SQL Server objects using tSQLt, Docker, and GitHub Actions --- .../unit-testing/tsqlt-docker/README.md | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/README.md diff --git a/samples/containers/unit-testing/tsqlt-docker/README.md b/samples/containers/unit-testing/tsqlt-docker/README.md new file mode 100644 index 00000000..751f50c7 --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/README.md @@ -0,0 +1,80 @@ + +![](./media/solutions-microsoft-logo-small.png) + +# Sample name + +Briefly describe what the sample does. Describe the benefit of running this sample. + + + +![Alt text](/media/image-name.png "") + + +### Contents + +[About this sample](#about-this-sample)
+[Before you begin](#before-you-begin)
+[Run this sample](#run-this-sample)
+[Sample details](#sample-details)
+[Disclaimers](#disclaimers)
+[Related links](#related-links)
+ + + + +## About this sample + + +- **Applies to:** SQL Server 2016 (or higher), Azure SQL Database, Azure SQL Data Warehouse, Parallel Data Warehouse +- **Key features:** +- **Workload:** +- **Programming Language:** +- **Authors:** +- **Update history:** + + + +## Before you begin + +To run this sample, you need the following prerequisites. + +**Software prerequisites:** + + +1. SQL Server 2016 (or higher) or an Azure SQL Database +2. Visual Studio 2015 (or higher) with the latest SSDT installed + +**Azure prerequisites:** + + +1. Permission to create an Azure SQL Database + + + +## Run this sample + + + +1. From Visual Studio, open the **sample.sln** file from the root directory. + +2. In Visual Studio Build menu, select **Build Solution** (or Press F6). + +3. Step 3 ... + + + +## Sample details + +Describe sample details + + + +## Disclaimers +The code included in this sample is not intended to be ... + + + +## Related Links + + +For more information, see these articles: From 867dac3e825355a97b5515230fcedbb4377c75c8 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sat, 28 Jan 2023 08:34:45 +0100 Subject: [PATCH 02/17] Add the description of the sample Changed the section: Sample name, Contents, About this sample, Before you begin, Run this sample --- .../unit-testing/tsqlt-docker/README.md | 197 +++++++++++++++--- 1 file changed, 170 insertions(+), 27 deletions(-) diff --git a/samples/containers/unit-testing/tsqlt-docker/README.md b/samples/containers/unit-testing/tsqlt-docker/README.md index 751f50c7..d7fa2000 100644 --- a/samples/containers/unit-testing/tsqlt-docker/README.md +++ b/samples/containers/unit-testing/tsqlt-docker/README.md @@ -1,14 +1,9 @@ -![](./media/solutions-microsoft-logo-small.png) +![](https://github.com/microsoft/sql-server-samples/blob/master/media/solutions-microsoft-logo-small.png) -# Sample name - -Briefly describe what the sample does. Describe the benefit of running this sample. - - - -![Alt text](/media/image-name.png "") +# SQL Server unit testing with tSQLt, Docker, and GitHub Actions! +This sample describes how to automate the testing for one or more SQL Server objects using tSQLt, Docker, and GitHub Actions! ### Contents @@ -19,47 +14,195 @@ Briefly describe what the sample does. Describe the benefit of running this samp [Disclaimers](#disclaimers)
[Related links](#related-links)
- ## About this sample - -- **Applies to:** SQL Server 2016 (or higher), Azure SQL Database, Azure SQL Data Warehouse, Parallel Data Warehouse -- **Key features:** -- **Workload:** -- **Programming Language:** -- **Authors:** -- **Update history:** +- **Applies to:** SQL Server 2016 (or higher) +- **Key features:** Run SQL Server in Docker containers +- **Workload:** Unit tests executed on [AdventureWorks2017](https://github.com/Microsoft/sql-server-samples/releases/tag/adventureworks) +- **Programming Language:** T-SQL, YAML +- **Authors:** [Sergio Govoni](https://www.linkedin.com/in/sgovoni/) ## Before you begin -To run this sample, you need the following prerequisites. +To run this example, the following basic concepts are required. + +[tSQLt](https://tsqlt.org/) is a unit testing framework for SQL Server. It provides the APIs to create and execute test cases, as well as integrates them with continuous integration servers. The power of the tSQLt framework has been described in my article [The tSQLt framework and the execution of a test](https://segovoni.medium.com/unit-testing-the-tsqlt-framework-and-the-execution-of-a-test-e4d135c3e343). + +[Docker](https://www.docker.com/) is one of the most popular systems for running applications in isolable, minimal and easily deployable environments called containers. Since SQL Server 2017, the SQL Server Engine can run in a Docker container, a typical usage of running SQL Server in a Docker container concerns the automation of software tests. + +[GitHub Actions](https://github.com/features/actions/) is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline. You can create workflows that build and test every pull request to your repository, or deploy merged pull requests to production. GitHub provides Linux, Windows, and macOS virtual machines to run your workflows, or you can host your own self-hosted runners in your own data center or cloud infrastructure such as Microsoft Azure. **Software prerequisites:** - -1. SQL Server 2016 (or higher) or an Azure SQL Database -2. Visual Studio 2015 (or higher) with the latest SSDT installed +1. GitHub account. If you don't already have a GitHub account, you can get one for free [here](https://github.com/signup)! +2. GitHub sample repository -**Azure prerequisites:** + - -1. Permission to create an Azure SQL Database +## Case history + +The AdventureWorks2017 database contains the Production.Product table that stores products managed and sold by the fake company Adventure Works LTD. + +The trigger we have wrote is to prevent the insertion of new products with values less than 10 as a “safety stock”. The Company wishes to always have a warehouse stock of no less than 10 units for each product. The safety stock level is a very important value for the automatic procedures: it allows to re-order materials. The creation of new purchase orders and production orders are based on the safety stock level. To make our trigger simple, it will only respond to the OnInsert event, for INSERT commands. ## Run this sample - + -1. From Visual Studio, open the **sample.sln** file from the root directory. +The implementation of the trigger and related unit tests has been done. -2. In Visual Studio Build menu, select **Build Solution** (or Press F6). +The challenge is to automate the execution of the tests at each commit on the main branch of the repository. GitHub Actions is our CI/CD platform, it supports the use of Docker containers and it is intimately integrated into GitHub, the source control that manages our source code. -3. Step 3 ... +**Create your first workflow** + +Let's go ahead with the creation of a workflow: an automated and configurable process that will execute one or more jobs. + +Workflows are defined with a YAML file stored in the same repository which holds the source code. The workflows will be triggered when an event occurs in the repository. Anyway, a workflow can also be activated manually or according to a defined schedule. Follow [these instructions](https://docs.github.com/en/actions/quickstart) to create your first workflow. + +A sample YAML file that implements the test automation workflow is available here, the fundamental steps are: + +1. Definition of activation events +2. Creating a Docker container from a SQL Server image on Linux +3. AdventureWorks2017 database recovery +4. Installation of the tSQLt framework +5. Creating the database objects to be tested (SUT) +6. Creation and execution unit tests + +**1. Definition of activation events** + +The definition of the activation events is typically done at the beginning of the YAML script with a code snippet similar to the one shown below. The workflow is activated when push or pull request events occur on the “master” branch. The “workflow_dispatch” specification allows you to run the workflow manually from the actions tab. + +``` +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "master" branch + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: +``` + +**2. Creating a Docker container from a SQL Server image on Linux** + +Creating a Docker container from a SQL Server image on Linux can be done by requesting the sqlserver service accompanied by the path to the Docker image you want to use. + +The official images provided by Microsoft for SQL Server on Linux are available [here](https://hub.docker.com/_/microsoft-mssql-server). + +We will not use an official image downloaded from the Microsoft registry. We will use a Docker image of SQL Server with the AdventureWorks database installed, this image is published by [chriseaton](https://hub.docker.com/u/chriseaton), you can find it at this [link](https://hub.docker.com/r/chriseaton/adventureworks). + +The following YAML code snippet sets up the SQL Server service. + +``` +jobs: + windows-auth-tsqlt: + name: Installting tSQLt with SQL Auth + # The type of runner that the job will run on + runs-on: ubuntu-latest + + services: + sqlserver: + image: chriseaton/adventureworks:latest + ports: + - 1433:1433 + env: + ACCEPT_EULA: Y + SA_PASSWORD: 3uuiCaKxfbForrK +``` + +In order to reference the newly created Docker container it is important to save its identifier in an environment variable. + +The following snippet of YAML code sets the ENV_CONTAINER_ID variable with the ID of the container created. + +``` +- name: Set environment variable ENV_CONTAINER_ID + run: echo "ENV_CONTAINER_ID=$(docker ps --all --filter status=running --no-trunc --format "{{.ID}}")" >> $GITHUB_ENV +``` + +**3. AdventureWorks2017 database recovery** + +The AdventureWorks2017 database recovery can be performed using the following docker exec command. + +``` +- name: Restore AdventureWorks2017 + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -Q "RESTORE DATABASE [AdventureWorks2017] FROM DISK = '/adventureworks.bak' WITH MOVE 'AdventureWorks2017' TO '/var/opt/mssql/data/AdventureWorks.mdf', MOVE 'AdventureWorks2017_log' TO '/var/opt/mssql/data/AdventureWorks_log.ldf'" +``` + +**4. Installation of the tSQLt framework** + +The installation of the latest version of tSQLt framework in the AdventureWorks2017 database is done using the GitHub Actions tSQLt Installer published by [lowlydba](https://github.com/lowlydba), you can find more details [here](https://github.com/lowlydba/tsqlt-installer) and on the [GitHub Actions marketplace](https://github.com/marketplace/actions/tsqlt-installer). + +The snippet of YAML code used for the installation of the tSQLt framework in the AdventureWorks2017 database is the following. + +``` +steps: + - uses: actions/checkout@v2 + - name: Install tSQLt with SQL auth on AdventureWorks2017 + uses: lowlydba/tsqlt-installer@v1 + with: + sql-instance: localhost + database: AdventureWorks2017 + version: latest + user: sa + password: 3uuiCaKxfbForrK +``` + +**5. Creating the database objects to be tested (SUT)** + +The test environment is ready, we have a SQL Server instance on Linux inside a Docker container; the AdventureWorks2017 database has been restored and it is ready for use. + +Let's go ahead with the creation of the trigger and the stored procedure (that manages errors), they represent our [System Under Test (SUT)](https://en.wikipedia.org/wiki/System_under_test). + +The TR_Product_SafetyStockLevel trigger creation script and the usp_Raiserror_SafetyStockLevel stored procedure creation script are saved in the source directory of this sample. + +Triggers and stored procedures are created in the AdventureWorks2017 database attached to the SQL Server instance, the YAML code snippet that performs this operation is the following. + +``` +- name: Create sp usp_Raiserror_SafetyStockLevel + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/usp-raiserror-safetystocklevel.sql +- name: Create TR_Product_SafetyStockLevel + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/tr_product_safetystocklevel.sql +``` + +**6. Creation and execution of test units** + +The last phase of this workflow is represented by the creation and execution of the unit tests. + +The test class and the unit tests creation scripts are contained in the unit-test subfolder of this sample. + +Let's go ahead with the creation of the test class dedicated to the TR_Product_SafetyStockLevel trigger, we called it UnitTestTRProductSafetyStockLevel. + +The following docker exec command, that uses sqlcmd, executes the TSQL commands contained in the test-class-trproductsafetystocklevel.sql script. + +``` +- name: Create test class UnitTestTRProductSafetyStockLevel + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-class-trproductsafetystocklevel.sql +``` + +Let's go ahead with the creation and execution of the unit tests. Each .sql file of the "test case" family contains the TSQL commands for creating and running the related unit test. Each store procedure tests one and only one test case. + +The following snippet of YAML code creates and runs the test units. + +``` +- name: Create and run test case try to insert one wrong row + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-one-wrong-row.sql +- name: Create and run test case try to insert one right row + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-one-right-row.sql +- name: Create and run test case try to insert multiple rows + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-multiple-rows.sql +- name: Create and run test case try to insert multiple rows ordered + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-multiple-rows-ordered.sql +``` + +The YAML script for our workflow is complete, you can find it here. From 99b243d597e0fc547bcd935c1d82bb1d26642744 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sat, 28 Jan 2023 17:24:28 +0100 Subject: [PATCH 03/17] Modify "run this sample" section for step by step instructions --- .../unit-testing/tsqlt-docker/README.md | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/samples/containers/unit-testing/tsqlt-docker/README.md b/samples/containers/unit-testing/tsqlt-docker/README.md index d7fa2000..451a2864 100644 --- a/samples/containers/unit-testing/tsqlt-docker/README.md +++ b/samples/containers/unit-testing/tsqlt-docker/README.md @@ -55,15 +55,24 @@ The trigger we have wrote is to prevent the insertion of new products with value -The implementation of the trigger and related unit tests has been done. +1. If you don't already have one, [sign up for a new GitHub account](https://docs.github.com/get-started/signing-up-for-github/signing-up-for-a-new-github-account) +2. Create your sample repository on GitHub, if you've never done it, you can find the guide [here](https://docs.github.com/get-started/quickstart/create-a-repo) +3. Create a `.github/workflows` directory in your GitHub repository if this directory does not already exist +4. Copy the `automated-tests.yml` inside the directory `.github/workflows` you created in the previous step. The `automated-tests.yml` describes the process that will execute one or more jobs +5. Create the `source` and `unit-test` directories in the root of your sample repository +6. Copy all the files located in the source and unit-test directories to their respective directories in your repository +7. View and run the workflow as described [here](https://docs.github.com/actions/quickstart) +8. Have fun with the solution details outlined below + +**The challenge** + +The implementation of the trigger and related unit tests has been done, all files are ready in your repository! The challenge is to automate the execution of the tests at each commit on the main branch of the repository. GitHub Actions is our CI/CD platform, it supports the use of Docker containers and it is intimately integrated into GitHub, the source control that manages our source code. **Create your first workflow** -Let's go ahead with the creation of a workflow: an automated and configurable process that will execute one or more jobs. - -Workflows are defined with a YAML file stored in the same repository which holds the source code. The workflows will be triggered when an event occurs in the repository. Anyway, a workflow can also be activated manually or according to a defined schedule. Follow [these instructions](https://docs.github.com/en/actions/quickstart) to create your first workflow. +Workflows are defined with a YAML file stored in the same repository which holds the source code. The workflows will be triggered when an event occurs in the repository. Anyway, a workflow can also be activated manually or according to a defined schedule. A sample YAML file that implements the test automation workflow is available here, the fundamental steps are: @@ -208,12 +217,15 @@ The YAML script for our workflow is complete, you can find it here. ## Sample details -Describe sample details +Unit tests developed for a SQL Server solution are not just meant to verify that requirements have been met once, prior to release; the real game changer is represented by the possibility of repeating the checks during the development of new code and during the bug fixing process. + +The repeatability of the tests provides the ability to automate them, an essential condition for integrating automatic tests within a Continuous Integration platform. In this article we described how to automate the testing of SQL Server objects using tSQLt, Docker and GitHub Actions! ## Disclaimers -The code included in this sample is not intended to be ... + +The code included in this sample is not intended to be a set of best practices on how to build scalable enterprise grade unit testing or CI/CD system. This is beyond the scope of this quick start sample. @@ -221,3 +233,7 @@ The code included in this sample is not intended to be ... For more information, see these articles: + +- [Unit testing: What it is and why it is important for T-SQL code!](https://medium.com/@segovoni/unit-testing-what-it-is-and-why-it-is-important-for-t-sql-code-7e9df7ca8bfe) +- [Unit testing: The tSQLt framework and the execution of a test!](https://segovoni.medium.com/unit-testing-the-tsqlt-framework-and-the-execution-of-a-test-e4d135c3e343) +- [Unit testing: How to write your first unit test for T-SQL code](https://segovoni.medium.com/unit-testing-how-to-write-your-first-unit-test-for-t-sql-code-3bc1533acbbc) From 6447eff9af5155c553fbf11a49f225607673d723 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sat, 28 Jan 2023 18:46:05 +0100 Subject: [PATCH 04/17] Changed software prerequisites and step by step instructions --- .../containers/unit-testing/tsqlt-docker/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/containers/unit-testing/tsqlt-docker/README.md b/samples/containers/unit-testing/tsqlt-docker/README.md index 451a2864..17e73a99 100644 --- a/samples/containers/unit-testing/tsqlt-docker/README.md +++ b/samples/containers/unit-testing/tsqlt-docker/README.md @@ -9,6 +9,7 @@ This sample describes how to automate the testing for one or more SQL Server obj [About this sample](#about-this-sample)
[Before you begin](#before-you-begin)
+[Case history](#case-history)
[Run this sample](#run-this-sample)
[Sample details](#sample-details)
[Disclaimers](#disclaimers)
@@ -38,8 +39,7 @@ To run this example, the following basic concepts are required. **Software prerequisites:** -1. GitHub account. If you don't already have a GitHub account, you can get one for free [here](https://github.com/signup)! -2. GitHub sample repository +1. A GitHub account. If you don't already have a GitHub account, you can get one for free [here](https://github.com/signup)! @@ -55,10 +55,10 @@ The trigger we have wrote is to prevent the insertion of new products with value -1. If you don't already have one, [sign up for a new GitHub account](https://docs.github.com/get-started/signing-up-for-github/signing-up-for-a-new-github-account) +1. [Sign in](https://github.com/login) to GitHub. If you don't already have an account, [sign up for a new GitHub account](https://docs.github.com/get-started/signing-up-for-github/signing-up-for-a-new-github-account) 2. Create your sample repository on GitHub, if you've never done it, you can find the guide [here](https://docs.github.com/get-started/quickstart/create-a-repo) 3. Create a `.github/workflows` directory in your GitHub repository if this directory does not already exist -4. Copy the `automated-tests.yml` inside the directory `.github/workflows` you created in the previous step. The `automated-tests.yml` describes the process that will execute one or more jobs +4. Copy the automated-tests.yml inside the directory `.github/workflows` you created in the previous step. The `automated-tests.yml` describes the process that will execute one or more jobs 5. Create the `source` and `unit-test` directories in the root of your sample repository 6. Copy all the files located in the source and unit-test directories to their respective directories in your repository 7. View and run the workflow as described [here](https://docs.github.com/actions/quickstart) @@ -70,11 +70,11 @@ The implementation of the trigger and related unit tests has been done, all file The challenge is to automate the execution of the tests at each commit on the main branch of the repository. GitHub Actions is our CI/CD platform, it supports the use of Docker containers and it is intimately integrated into GitHub, the source control that manages our source code. -**Create your first workflow** +**Understand and manage your first workflow** Workflows are defined with a YAML file stored in the same repository which holds the source code. The workflows will be triggered when an event occurs in the repository. Anyway, a workflow can also be activated manually or according to a defined schedule. -A sample YAML file that implements the test automation workflow is available here, the fundamental steps are: +A sample YAML file that implements the test automation workflow is already in your sample repository, the fundamental steps of the process are: 1. Definition of activation events 2. Creating a Docker container from a SQL Server image on Linux From b9bea4b64634ea1118fe47ddde2e56e81791af5e Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sat, 28 Jan 2023 19:42:53 +0100 Subject: [PATCH 05/17] Add YAML file for unit testing workflow --- .../.github/workflows/automated-tests.yml | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml diff --git a/samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml b/samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml new file mode 100644 index 00000000..7d85e68b --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml @@ -0,0 +1,99 @@ +# This workflow installs tSQLt and runs the test units + +name: tSQLt installer and unit testing runner + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "master" branch + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + windows-auth-tsqlt: + name: Installting tSQLt with SQL Auth + # The type of runner that the job will run on + runs-on: ubuntu-latest + + services: + sqlserver: + image: chriseaton/adventureworks:latest + ports: + - 1433:1433 + env: + ACCEPT_EULA: Y + SA_PASSWORD: 3uuiCaKxfbForrK + + steps: + - uses: actions/checkout@v2 + + - name: Install tSQLt with SQL auth on tempdb + uses: lowlydba/tsqlt-installer@v1 + with: + sql-instance: localhost + database: tempdb + version: latest + user: sa + password: 3uuiCaKxfbForrK + + #- name: Get the containers list unformatted + # run: docker ps + + #- name: Get the containers list formatted + # run: docker ps --all --filter status=running --no-trunc --format "{{.ID}}" + + #- name: Set the container ID + # run: echo '::set-output name=CONTAINER_ID::$(docker ps --all --filter status=running --no-trunc --format "{{.ID}}")' + # id: ContainerID + + #- name: Get container ID + # run: echo "The container ID is ${{ steps.ContainerID.outputs.CONTAINER_ID }}" + + - name: Set environment variable ENV_CONTAINER_ID + run: echo "ENV_CONTAINER_ID=$(docker ps --all --filter status=running --no-trunc --format "{{.ID}}")" >> $GITHUB_ENV + + - name: Test environment variable ENV_CONTAINER_ID + run: echo $ENV_CONTAINER_ID + + #- name: Print environment variables + # run: env + + - name: Restore AdventureWorks2017 + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -Q "RESTORE DATABASE [AdventureWorks2017] FROM DISK = '/adventureworks.bak' WITH MOVE 'AdventureWorks2017' TO '/var/opt/mssql/data/AdventureWorks.mdf', MOVE 'AdventureWorks2017_log' TO '/var/opt/mssql/data/AdventureWorks_log.ldf'" + + - name: Get the database list + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -Q "SELECT Name FROM sys.databases" + + - name: Install tSQLt with SQL auth on AdventureWorks2017 + uses: lowlydba/tsqlt-installer@v1 + with: + sql-instance: localhost + database: AdventureWorks2017 + version: latest + user: sa + password: 3uuiCaKxfbForrK + + - name: Create sp usp_Raiserror_SafetyStockLevel + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/usp-raiserror-safetystocklevel.sql + + - name: Create system under test (SUT) TR_Product_SafetyStockLevel + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/tr_product_safetystocklevel.sql + + - name: Create test class UnitTestTRProductSafetyStockLevel + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-class-trproductsafetystocklevel.sql + + - name: Create and run test case try to insert one wrong row + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-one-wrong-row.sql + + - name: Create and run test case try to insert one right row + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-one-right-row.sql + + - name: Create and run test case try to insert multiple rows + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-multiple-rows.sql + + - name: Create and run test case try to insert multiple rows ordered + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-multiple-rows-ordered.sql From 283ffc10b5e582c544c4f55930bffc637393bddd Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sat, 28 Jan 2023 19:47:06 +0100 Subject: [PATCH 06/17] Create TSQL script for trigger TR_Product_SafetyStockLevel --- .../source/tr_product_safetystocklevel.sql | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/source/tr_product_safetystocklevel.sql diff --git a/samples/containers/unit-testing/tsqlt-docker/source/tr_product_safetystocklevel.sql b/samples/containers/unit-testing/tsqlt-docker/source/tr_product_safetystocklevel.sql new file mode 100644 index 00000000..e2de4776 --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/source/tr_product_safetystocklevel.sql @@ -0,0 +1,33 @@ +------------------------------------------------------------------------- +-- Demo: SQL Server CI/CD - +-- - +-- Script: Create trigger TR_Product_SafetyStockLevel - +-- Author: Sergio Govoni - +-- Notes: -- - +------------------------------------------------------------------------- + +USE [AdventureWorks2017]; +GO + +CREATE OR ALTER TRIGGER Production.TR_Product_SafetyStockLevel + ON Production.Product +AFTER INSERT AS +BEGIN + /* + Avoid to insert products with safety stock level lower than 10! + */ + DECLARE @SafetyStockLevel SMALLINT; + + SELECT + @SafetyStockLevel = SafetyStockLevel + FROM + inserted; + + IF (@SafetyStockLevel < 10) + BEGIN + -- Error!! + EXEC Production.usp_Raiserror_SafetyStockLevel + @Message = 'Safety stock level cannot be lower than 10!'; + END; +END; +GO From dfbd4c83a6ce31f01e83ed897d9a7e2911c07c6f Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sat, 28 Jan 2023 19:52:34 +0100 Subject: [PATCH 07/17] Create TSQL script for stored procedure usp_Raiserror_SafetyStockLevel --- .../source/usp-raiserror-safetystocklevel.sql | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/source/usp-raiserror-safetystocklevel.sql diff --git a/samples/containers/unit-testing/tsqlt-docker/source/usp-raiserror-safetystocklevel.sql b/samples/containers/unit-testing/tsqlt-docker/source/usp-raiserror-safetystocklevel.sql new file mode 100644 index 00000000..797fbe73 --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/source/usp-raiserror-safetystocklevel.sql @@ -0,0 +1,35 @@ +------------------------------------------------------------------------- +-- Demo: SQL Server CI/CD - +-- - +-- Script: Create stored procedure usp_Raiserror_SafetyStockLevel - +-- Author: Sergio Govoni - +-- Notes: -- - +------------------------------------------------------------------------- + +USE [AdventureWorks2017]; +GO + +/* +DECLARE @user AS SYSNAME; +SELECT + @user = QUOTENAME(SL.Name) +FROM + master..sysdatabases AS SD +INNER JOIN + master..syslogins AS SL ON SD.SID = SL.SID +WHERE + SD.Name = DB_NAME(); +EXEC('EXEC sp_changedbowner ' + @user); +GO +*/ + +CREATE OR ALTER PROCEDURE Production.usp_Raiserror_SafetyStockLevel +( + @Message NVARCHAR(256) +) +AS +BEGIN + ROLLBACK; + RAISERROR(@Message, 16, 1); +END; +GO From 85b126770941c242a1c6fe9d3261c2469fdce063 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 15:15:51 +0100 Subject: [PATCH 08/17] Create TSQL script for new test class --- .../test-class-trproductsafetystocklevel.sql | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/unit-test/test-class-trproductsafetystocklevel.sql diff --git a/samples/containers/unit-testing/tsqlt-docker/unit-test/test-class-trproductsafetystocklevel.sql b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-class-trproductsafetystocklevel.sql new file mode 100644 index 00000000..1a7eb28c --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-class-trproductsafetystocklevel.sql @@ -0,0 +1,15 @@ +------------------------------------------------------------------------- +-- Demo: SQL Server CI/CD - +-- - +-- Script: Create new test class UnitTestTRProductSafetyStockLevel - +-- Author: Sergio Govoni - +-- Notes: -- - +------------------------------------------------------------------------- + +USE [AdventureWorks2017]; +GO + +-- Create new test class +-- The test class collects test cases for this class +EXEC tSQLt.NewTestClass 'UnitTestTRProductSafetyStockLevel'; +GO From da6191dfebacde952322e9fc03de3df5309d9b80 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 15:18:05 +0100 Subject: [PATCH 09/17] Create TSQL script for test case: one wrong row --- .../test-case-try-to-insert-one-wrong-row.sql | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-wrong-row.sql diff --git a/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-wrong-row.sql b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-wrong-row.sql new file mode 100644 index 00000000..026dcf73 --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-wrong-row.sql @@ -0,0 +1,66 @@ +------------------------------------------------------------------------- +-- Demo: SQL Server CI/CD - +-- - +-- Script: Test case: try to insert one wrong row - +-- Author: Sergio Govoni - +-- Notes: -- - +------------------------------------------------------------------------- + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE OR ALTER PROCEDURE UnitTestTRProductSafetyStockLevel.[test try to insert one wrong row] +AS +BEGIN + /* + Arrange: + Spy the procedure Production.usp_Raiserror_SafetyStockLevel + */ + EXEC tSQLt.SpyProcedure 'Production.usp_Raiserror_SafetyStockLevel'; + + /* + Act: + Try to insert one wrong rows with SafetyStockLevel lower than 10 + */ + INSERT INTO Production.Product + ( + [Name] + ,ProductNumber + ,MakeFlag + ,FinishedGoodsFlag + ,SafetyStockLevel + ,ReorderPoint + ,StandardCost + ,ListPrice + ,DaysToManufacture + ,SellStartDate + ,rowguid + ,ModifiedDate + ) + VALUES + ( + N'Carbon Bar 1' + ,N'CB-0001' + ,0 + ,0 + ,9 /* SafetyStockLevel */ + ,750 + ,0.0000 + ,78.0000 + ,0 + ,GETDATE() + ,NEWID() + ,GETDATE() + ); + + /* + Assert + */ + IF NOT EXISTS (SELECT _id_ FROM Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog) + EXEC tSQLt.Fail + @Message0 = 'Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog is empty! usp_Raiserror_SafetyStockLevel has not been called!'; +END; +GO + +EXEC tSQLt.Run 'UnitTestTRProductSafetyStockLevel.[test try to insert one wrong row]'; +GO From bef416701a3a6ffd22ce4c1b09c1d973b76e5f68 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 15:19:17 +0100 Subject: [PATCH 10/17] Create TSQL script for test case: one right row --- .../test-case-try-to-insert-one-right-row.sql | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-right-row.sql diff --git a/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-right-row.sql b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-right-row.sql new file mode 100644 index 00000000..57aaacc5 --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-one-right-row.sql @@ -0,0 +1,66 @@ +------------------------------------------------------------------------- +-- Demo: SQL Server CI/CD - +-- - +-- Script: Test case: try to insert one right row - +-- Author: Sergio Govoni - +-- Notes: -- - +------------------------------------------------------------------------- + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE OR ALTER PROCEDURE UnitTestTRProductSafetyStockLevel.[test try to insert one right row] +AS +BEGIN + /* + Arrange: + Spy the procedure Production.usp_Raiserror_SafetyStockLevel + */ + EXEC tSQLt.SpyProcedure 'Production.usp_Raiserror_SafetyStockLevel'; + + /* + Act: + Try to insert one right row with SafetyStockLevel lower than 10 + */ + INSERT INTO Production.Product + ( + [Name] + ,ProductNumber + ,MakeFlag + ,FinishedGoodsFlag + ,SafetyStockLevel + ,ReorderPoint + ,StandardCost + ,ListPrice + ,DaysToManufacture + ,SellStartDate + ,rowguid + ,ModifiedDate + ) + VALUES + ( + N'Carbon Bar 1' + ,N'CB-0001' + ,0 + ,0 + ,20 /* SafetyStockLevel */ + ,750 + ,0.0000 + ,78.0000 + ,0 + ,GETDATE() + ,NEWID() + ,GETDATE() + ); + + /* + Assert + */ + IF EXISTS (SELECT _id_ FROM Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog) + EXEC tSQLt.Fail + @Message0 = 'Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog is not empty!'; +END; +GO + +EXEC tSQLt.Run 'UnitTestTRProductSafetyStockLevel.[test try to insert one right row]'; +GO From bedb9da7f6a909122bf146ffe77265c568ade7c8 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 15:20:47 +0100 Subject: [PATCH 11/17] Create TSQL script for test case: multiple rows --- .../test-case-try-to-insert-multiple-rows.sql | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows.sql diff --git a/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows.sql b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows.sql new file mode 100644 index 00000000..cf1e7246 --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows.sql @@ -0,0 +1,82 @@ +------------------------------------------------------------------------- +-- Demo: SQL Server CI/CD - +-- - +-- Script: Test case: try to insert multiple rows - +-- Author: Sergio Govoni - +-- Notes: -- - +------------------------------------------------------------------------- + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE OR ALTER PROCEDURE UnitTestTRProductSafetyStockLevel.[test try to insert multiple rows] +AS +BEGIN + /* + Arrange: + Spy the procedure Production.usp_raiserror_safety_stock_level + */ + EXEC tSQLt.SpyProcedure 'Production.usp_Raiserror_SafetyStockLevel'; + + /* + Act: + Try to insert multiple rows + The first product has a wrong value for SafetyStockLevel column, + whereas the value in second one is right + */ + INSERT INTO Production.Product + ( + [Name] + ,ProductNumber + ,MakeFlag + ,FinishedGoodsFlag + ,SafetyStockLevel + ,ReorderPoint + ,StandardCost + ,ListPrice + ,DaysToManufacture + ,SellStartDate + ,rowguid + ,ModifiedDate + ) + VALUES + ( + N'Carbon Bar 1' + ,N'CB-0001' + ,0 + ,0 + ,9 /* SafetyStockLevel */ + ,750 + ,0.0000 + ,78.0000 + ,0 + ,GETDATE() + ,NEWID() + ,GETDATE() + ), + ( + N'Carbon Bar 3' + ,N'CB-0003' + ,0 + ,0 + ,15 /* SafetyStockLevel */ + ,750 + ,0.0000 + ,78.0000 + ,0 + ,GETDATE() + ,NEWID() + ,GETDATE() + ); + + /* + Assert + */ + IF NOT EXISTS (SELECT _id_ FROM Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog) + EXEC tSQLt.Fail + @Message0 = 'Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog is empty! usp_Raiserror_SafetyStockLevel has not been called!'; +END; +GO + +EXEC tSQLt.Run 'UnitTestTRProductSafetyStockLevel.[test try to insert multiple rows]'; +GO From e6c0dd9864be1b1b1fc03f9356ef9badbbcd046f Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 15:22:57 +0100 Subject: [PATCH 12/17] Create TSQL script for test case: multiple ordered rows --- ...se-try-to-insert-multiple-rows-ordered.sql | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows-ordered.sql diff --git a/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows-ordered.sql b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows-ordered.sql new file mode 100644 index 00000000..dea70109 --- /dev/null +++ b/samples/containers/unit-testing/tsqlt-docker/unit-test/test-case-try-to-insert-multiple-rows-ordered.sql @@ -0,0 +1,85 @@ +------------------------------------------------------------------------- +-- Demo: SQL Server CI/CD - +-- - +-- Script: Test case: try to insert multiple rows ordered - +-- Author: Sergio Govoni - +-- Notes: -- - +------------------------------------------------------------------------- + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE OR ALTER PROCEDURE UnitTestTRProductSafetyStockLevel.[test try to insert multiple rows ordered] +AS +BEGIN + /* + Arrange: + Spy the procedure Production.usp_Raiserror_SafetyStockLevel + */ + EXEC tSQLt.SpyProcedure 'Production.usp_Raiserror_SafetyStockLevel'; + + /* + Act: + Try to insert multiple rows + The first product has a right value for SafetyStockLevel column, + whereas the value in second one is wrong + */ + INSERT INTO Production.Product + ( + [Name] + ,ProductNumber + ,MakeFlag + ,FinishedGoodsFlag + ,SafetyStockLevel + ,ReorderPoint + ,StandardCost + ,ListPrice + ,DaysToManufacture + ,SellStartDate + ,rowguid + ,ModifiedDate + ) + VALUES + ( + N'Carbon Bar 1' + ,N'CB-0001' + ,0 + ,0 + ,15 /* SafetyStockLevel */ + ,750 + ,0.0000 + ,78.0000 + ,0 + ,GETDATE() + ,NEWID() + ,GETDATE() + ), + ( + N'Carbon Bar 3' + ,N'CB-0003' + ,0 + ,0 + ,3 /* SafetyStockLevel */ + ,750 + ,0.0000 + ,78.0000 + ,0 + ,GETDATE() + ,NEWID() + ,GETDATE() + ); + + /* + Assert + */ + IF NOT EXISTS (SELECT _id_ FROM Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog) + EXEC tSQLt.Fail + @Message0 = 'Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog is empty! usp_Raiserror_SafetyStockLevel has not been called!'; + + -- Optimized assert command, to be evaluated + --EXEC tSQLt.AssertEmptyTable @TableName = 'Production.usp_Raiserror_SafetyStockLevel_SpyProcedureLog'; +END; +GO + +EXEC tSQLt.Run 'UnitTestTRProductSafetyStockLevel.[test try to insert multiple rows ordered]'; +GO From 1283532366bb9d58df87c235b15f447c88fe1df8 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 15:38:18 +0100 Subject: [PATCH 13/17] Rename tr_product_safetystocklevel --- ...oduct_safetystocklevel.sql => tr-product-safetystocklevel.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename samples/containers/unit-testing/tsqlt-docker/source/{tr_product_safetystocklevel.sql => tr-product-safetystocklevel.sql} (100%) diff --git a/samples/containers/unit-testing/tsqlt-docker/source/tr_product_safetystocklevel.sql b/samples/containers/unit-testing/tsqlt-docker/source/tr-product-safetystocklevel.sql similarity index 100% rename from samples/containers/unit-testing/tsqlt-docker/source/tr_product_safetystocklevel.sql rename to samples/containers/unit-testing/tsqlt-docker/source/tr-product-safetystocklevel.sql From b764ae78b3ff1edabccd48f431b9c730d1556067 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 15:43:24 +0100 Subject: [PATCH 14/17] Adjusted the name of the renamed TSQL script --- .../tsqlt-docker/.github/workflows/automated-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml b/samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml index 7d85e68b..79c7411b 100644 --- a/samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml +++ b/samples/containers/unit-testing/tsqlt-docker/.github/workflows/automated-tests.yml @@ -81,7 +81,7 @@ jobs: run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/usp-raiserror-safetystocklevel.sql - name: Create system under test (SUT) TR_Product_SafetyStockLevel - run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/tr_product_safetystocklevel.sql + run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/tr-product-safetystocklevel.sql - name: Create test class UnitTestTRProductSafetyStockLevel run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-class-trproductsafetystocklevel.sql From 9f72c1036bb21f1556899c6c1bab02a3e4650e61 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 16:20:02 +0100 Subject: [PATCH 15/17] Add links to resources used in the sample Changed database name from AdventureWorks2017 to AdventureWorks in descriptions --- .../unit-testing/tsqlt-docker/README.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/samples/containers/unit-testing/tsqlt-docker/README.md b/samples/containers/unit-testing/tsqlt-docker/README.md index 17e73a99..c9b5be0e 100644 --- a/samples/containers/unit-testing/tsqlt-docker/README.md +++ b/samples/containers/unit-testing/tsqlt-docker/README.md @@ -21,9 +21,9 @@ This sample describes how to automate the testing for one or more SQL Server obj - **Applies to:** SQL Server 2016 (or higher) - **Key features:** Run SQL Server in Docker containers -- **Workload:** Unit tests executed on [AdventureWorks2017](https://github.com/Microsoft/sql-server-samples/releases/tag/adventureworks) +- **Workload:** Unit tests executed on [AdventureWorks](https://github.com/Microsoft/sql-server-samples/releases/tag/adventureworks) - **Programming Language:** T-SQL, YAML -- **Authors:** [Sergio Govoni](https://www.linkedin.com/in/sgovoni/) +- **Authors:** [Sergio Govoni](https://www.linkedin.com/in/sgovoni/) | [Microsoft MVP Profile](https://mvp.microsoft.com/it-it/PublicProfile/4029181?fullName=Sergio%20Govoni) | [Blog](https://segovoni.medium.com/) | [GitHub](https://github.com/segovoni) | [Twitter](https://twitter.com/segovoni) @@ -45,7 +45,7 @@ To run this example, the following basic concepts are required. ## Case history -The AdventureWorks2017 database contains the Production.Product table that stores products managed and sold by the fake company Adventure Works LTD. +The AdventureWorks database contains the Production.Product table that stores products managed and sold by the fake company Adventure Works LTD. The trigger we have wrote is to prevent the insertion of new products with values less than 10 as a “safety stock”. The Company wishes to always have a warehouse stock of no less than 10 units for each product. The safety stock level is a very important value for the automatic procedures: it allows to re-order materials. The creation of new purchase orders and production orders are based on the safety stock level. To make our trigger simple, it will only respond to the OnInsert event, for INSERT commands. @@ -58,9 +58,9 @@ The trigger we have wrote is to prevent the insertion of new products with value 1. [Sign in](https://github.com/login) to GitHub. If you don't already have an account, [sign up for a new GitHub account](https://docs.github.com/get-started/signing-up-for-github/signing-up-for-a-new-github-account) 2. Create your sample repository on GitHub, if you've never done it, you can find the guide [here](https://docs.github.com/get-started/quickstart/create-a-repo) 3. Create a `.github/workflows` directory in your GitHub repository if this directory does not already exist -4. Copy the automated-tests.yml inside the directory `.github/workflows` you created in the previous step. The `automated-tests.yml` describes the process that will execute one or more jobs +4. Copy the [automated-tests.yml](https://github.com/microsoft/sql-server-samples/tree/master/samples/containers/unit-testing/tsqlt-docker/.github/workflows) inside the directory `.github/workflows` you created in the previous step in your repository. The `automated-tests.yml` describes the process that will execute one or more jobs 5. Create the `source` and `unit-test` directories in the root of your sample repository -6. Copy all the files located in the source and unit-test directories to their respective directories in your repository +6. Copy all the files located in the [source](https://github.com/microsoft/sql-server-samples/tree/master/samples/containers/unit-testing/tsqlt-docker/source) and [unit-test](https://github.com/microsoft/sql-server-samples/tree/master/samples/containers/unit-testing/tsqlt-docker/unit-test) directories to their respective directories in your repository 7. View and run the workflow as described [here](https://docs.github.com/actions/quickstart) 8. Have fun with the solution details outlined below @@ -78,7 +78,7 @@ A sample YAML file that implements the test automation workflow is already in yo 1. Definition of activation events 2. Creating a Docker container from a SQL Server image on Linux -3. AdventureWorks2017 database recovery +3. AdventureWorks database recovery 4. Installation of the tSQLt framework 5. Creating the database objects to be tested (SUT) 6. Creation and execution unit tests @@ -136,20 +136,20 @@ The following snippet of YAML code sets the ENV_CONTAINER_ID variable with the I run: echo "ENV_CONTAINER_ID=$(docker ps --all --filter status=running --no-trunc --format "{{.ID}}")" >> $GITHUB_ENV ``` -**3. AdventureWorks2017 database recovery** +**3. AdventureWorks database recovery** -The AdventureWorks2017 database recovery can be performed using the following docker exec command. +The AdventureWorks database recovery can be performed using the following docker exec command. ``` -- name: Restore AdventureWorks2017 +- name: Restore AdventureWorks run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -Q "RESTORE DATABASE [AdventureWorks2017] FROM DISK = '/adventureworks.bak' WITH MOVE 'AdventureWorks2017' TO '/var/opt/mssql/data/AdventureWorks.mdf', MOVE 'AdventureWorks2017_log' TO '/var/opt/mssql/data/AdventureWorks_log.ldf'" ``` **4. Installation of the tSQLt framework** -The installation of the latest version of tSQLt framework in the AdventureWorks2017 database is done using the GitHub Actions tSQLt Installer published by [lowlydba](https://github.com/lowlydba), you can find more details [here](https://github.com/lowlydba/tsqlt-installer) and on the [GitHub Actions marketplace](https://github.com/marketplace/actions/tsqlt-installer). +The installation of the latest version of tSQLt framework in the AdventureWorks database is done using the GitHub Actions tSQLt Installer published by [lowlydba](https://github.com/lowlydba), you can find more details [here](https://github.com/lowlydba/tsqlt-installer) and on the [GitHub Actions marketplace](https://github.com/marketplace/actions/tsqlt-installer). -The snippet of YAML code used for the installation of the tSQLt framework in the AdventureWorks2017 database is the following. +The snippet of YAML code used for the installation of the tSQLt framework in the AdventureWorks database is the following. ``` steps: @@ -166,13 +166,13 @@ steps: **5. Creating the database objects to be tested (SUT)** -The test environment is ready, we have a SQL Server instance on Linux inside a Docker container; the AdventureWorks2017 database has been restored and it is ready for use. +The test environment is ready, we have a SQL Server instance on Linux inside a Docker container; the AdventureWorks database has been restored and it is ready for use. Let's go ahead with the creation of the trigger and the stored procedure (that manages errors), they represent our [System Under Test (SUT)](https://en.wikipedia.org/wiki/System_under_test). The TR_Product_SafetyStockLevel trigger creation script and the usp_Raiserror_SafetyStockLevel stored procedure creation script are saved in the source directory of this sample. -Triggers and stored procedures are created in the AdventureWorks2017 database attached to the SQL Server instance, the YAML code snippet that performs this operation is the following. +Triggers and stored procedures are created in the AdventureWorks database attached to the SQL Server instance, the YAML code snippet that performs this operation is the following. ``` - name: Create sp usp_Raiserror_SafetyStockLevel From 72cf44b9e89af0aa022a650c3257c5024f4004c6 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Sun, 29 Jan 2023 16:30:36 +0100 Subject: [PATCH 16/17] Add unit testing/tsqlt-docker section --- samples/containers/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/samples/containers/README.md b/samples/containers/README.md index aa37b09f..958c9f10 100644 --- a/samples/containers/README.md +++ b/samples/containers/README.md @@ -1,3 +1,7 @@ __[replication](replication/)__ -Example of SQL Server Replication in containers. This demo uses docker-compose to start two SQL Server containers; one that acts as the publisher and distributor, and the other as the subscriber in a push snapshot configuration. \ No newline at end of file +Example of SQL Server Replication in containers. This demo uses docker-compose to start two SQL Server containers; one that acts as the publisher and distributor, and the other as the subscriber in a push snapshot configuration. + +__[unit testing/tsqlt-docker](unit-testing/tsqlt-docker/)__ + +Example describes how to automate the testing for one or more SQL Server objects using tSQLt, Docker, and GitHub Actions. From 7b0497287dcaddeb8ded78fa82b3a28da9c57e51 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Wed, 1 Feb 2023 18:08:19 +0100 Subject: [PATCH 17/17] Add inline code quote --- .../containers/unit-testing/tsqlt-docker/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/containers/unit-testing/tsqlt-docker/README.md b/samples/containers/unit-testing/tsqlt-docker/README.md index c9b5be0e..abb0263f 100644 --- a/samples/containers/unit-testing/tsqlt-docker/README.md +++ b/samples/containers/unit-testing/tsqlt-docker/README.md @@ -45,9 +45,9 @@ To run this example, the following basic concepts are required. ## Case history -The AdventureWorks database contains the Production.Product table that stores products managed and sold by the fake company Adventure Works LTD. +The AdventureWorks database contains the `Production.Product` table that stores products managed and sold by the fake company Adventure Works LTD. -The trigger we have wrote is to prevent the insertion of new products with values less than 10 as a “safety stock”. The Company wishes to always have a warehouse stock of no less than 10 units for each product. The safety stock level is a very important value for the automatic procedures: it allows to re-order materials. The creation of new purchase orders and production orders are based on the safety stock level. To make our trigger simple, it will only respond to the OnInsert event, for INSERT commands. +The trigger we have wrote is to prevent the insertion of new products with values less than 10 as a “safety stock”. The Company wishes to always have a warehouse stock of no less than 10 units for each product. The safety stock level is a very important value for the automatic procedures: it allows to re-order materials. The creation of new purchase orders and production orders are based on the safety stock level. To make our trigger simple, it will only respond to the `OnInsert` event, for `INSERT` commands. @@ -85,7 +85,7 @@ A sample YAML file that implements the test automation workflow is already in yo **1. Definition of activation events** -The definition of the activation events is typically done at the beginning of the YAML script with a code snippet similar to the one shown below. The workflow is activated when push or pull request events occur on the “master” branch. The “workflow_dispatch” specification allows you to run the workflow manually from the actions tab. +The definition of the activation events is typically done at the beginning of the YAML script with a code snippet similar to the one shown below. The workflow is activated when push or pull request events occur on the `master` branch. The `workflow_dispatch` specification allows you to run the workflow manually from the actions tab. ``` # Controls when the workflow will run @@ -102,7 +102,7 @@ on: **2. Creating a Docker container from a SQL Server image on Linux** -Creating a Docker container from a SQL Server image on Linux can be done by requesting the sqlserver service accompanied by the path to the Docker image you want to use. +Creating a Docker container from a SQL Server image on Linux can be done by requesting the `sqlserver service` accompanied by the path to the Docker image you want to use. The official images provided by Microsoft for SQL Server on Linux are available [here](https://hub.docker.com/_/microsoft-mssql-server). @@ -129,7 +129,7 @@ jobs: In order to reference the newly created Docker container it is important to save its identifier in an environment variable. -The following snippet of YAML code sets the ENV_CONTAINER_ID variable with the ID of the container created. +The following snippet of YAML code sets the `ENV_CONTAINER_ID` variable with the ID of the container created. ``` - name: Set environment variable ENV_CONTAINER_ID @@ -196,7 +196,7 @@ The following docker exec command, that uses sqlcmd, executes the TSQL commands run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-class-trproductsafetystocklevel.sql ``` -Let's go ahead with the creation and execution of the unit tests. Each .sql file of the "test case" family contains the TSQL commands for creating and running the related unit test. Each store procedure tests one and only one test case. +Let's go ahead with the creation and execution of the unit tests. Each .sql file of the test case family contains the TSQL commands for creating and running the related unit test. Each store procedure tests one and only one test case. The following snippet of YAML code creates and runs the test units.