diff --git a/samples/samples-js/ProductsTrigger/function.json b/samples/samples-js/ProductsTrigger/function.json index 3bc5a8141..e277c5e39 100644 --- a/samples/samples-js/ProductsTrigger/function.json +++ b/samples/samples-js/ProductsTrigger/function.json @@ -4,7 +4,7 @@ "name": "changes", "type": "sqlTrigger", "direction": "in", - "tableName": "Products", + "tableName": "dbo.Products", "connectionStringSetting": "SqlConnectionString" } ], diff --git a/samples/samples-powershell/ProductsTrigger/function.json b/samples/samples-powershell/ProductsTrigger/function.json index 3bc5a8141..e277c5e39 100644 --- a/samples/samples-powershell/ProductsTrigger/function.json +++ b/samples/samples-powershell/ProductsTrigger/function.json @@ -4,7 +4,7 @@ "name": "changes", "type": "sqlTrigger", "direction": "in", - "tableName": "Products", + "tableName": "dbo.Products", "connectionStringSetting": "SqlConnectionString" } ], diff --git a/samples/samples-python/ProductsTrigger/function.json b/samples/samples-python/ProductsTrigger/function.json index 3bc5a8141..e277c5e39 100644 --- a/samples/samples-python/ProductsTrigger/function.json +++ b/samples/samples-python/ProductsTrigger/function.json @@ -4,7 +4,7 @@ "name": "changes", "type": "sqlTrigger", "direction": "in", - "tableName": "Products", + "tableName": "dbo.Products", "connectionStringSetting": "SqlConnectionString" } ], diff --git a/test/Integration/SqlTriggerBindingIntegrationTestBase.cs b/test/Integration/SqlTriggerBindingIntegrationTestBase.cs index 20976db9b..f1db431f2 100644 --- a/test/Integration/SqlTriggerBindingIntegrationTestBase.cs +++ b/test/Integration/SqlTriggerBindingIntegrationTestBase.cs @@ -145,7 +145,7 @@ void MonitorOutputData(object sender, DataReceivedEventArgs e) /// Name of the user function that should cause error in trigger listener /// Whether the functions host should be launched from test folder /// Expected error message string - protected void StartFunctionHostAndWaitForError(string functionName, bool useTestFolder, string expectedErrorMessage) + protected void StartFunctionHostAndWaitForError(string functionName, SupportedLanguages lang, bool useTestFolder, string expectedErrorMessage) { string errorMessage = null; var tcs = new TaskCompletionSource(); @@ -165,7 +165,7 @@ void OutputHandler(object sender, DataReceivedEventArgs e) }; // All trigger integration tests are only using C# functions for testing at the moment. - this.StartFunctionHost(functionName, SupportedLanguages.CSharp, useTestFolder, OutputHandler); + this.StartFunctionHost(functionName, lang, useTestFolder, OutputHandler); // The functions host generally logs the error message within a second after starting up. const int BufferTimeForErrorInSeconds = 15; diff --git a/test/Integration/SqlTriggerBindingIntegrationTests.cs b/test/Integration/SqlTriggerBindingIntegrationTests.cs index e13f24227..0e6984ebe 100644 --- a/test/Integration/SqlTriggerBindingIntegrationTests.cs +++ b/test/Integration/SqlTriggerBindingIntegrationTests.cs @@ -78,8 +78,10 @@ await this.WaitForProductChanges( /// Verifies that manually setting the batch size using the original config var correctly changes the /// number of changes processed at once. /// - [Fact] - public async Task BatchSizeOverrideTriggerTest() + [Theory] + [SqlInlineData()] + [UnsupportedLanguages(SupportedLanguages.Java, SupportedLanguages.OutOfProc)] + public async Task BatchSizeOverrideTriggerTest(SupportedLanguages lang) { // Use enough items to require 4 batches to be processed but then // set the max batch size to the same value so they can all be processed in one @@ -97,7 +99,7 @@ public async Task BatchSizeOverrideTriggerTest() maxBatchSize.ToString()); this.StartFunctionHost( nameof(ProductsTriggerWithValidation), - SupportedLanguages.CSharp, + lang, useTestFolder: true, customOutputHandler: handler, environmentVariables: new Dictionary() { @@ -120,8 +122,10 @@ await this.WaitForProductChanges( /// /// Verifies that manually setting the max batch size correctly changes the number of changes processed at once /// - [Fact] - public async Task MaxBatchSizeOverrideTriggerTest() + [Theory] + [SqlInlineData()] + [UnsupportedLanguages(SupportedLanguages.Java, SupportedLanguages.OutOfProc)] + public async Task MaxBatchSizeOverrideTriggerTest(SupportedLanguages lang) { // Use enough items to require 4 batches to be processed but then // set the max batch size to the same value so they can all be processed in one @@ -139,7 +143,7 @@ public async Task MaxBatchSizeOverrideTriggerTest() maxBatchSize.ToString()); this.StartFunctionHost( nameof(ProductsTriggerWithValidation), - SupportedLanguages.CSharp, + lang, useTestFolder: true, customOutputHandler: handler, environmentVariables: new Dictionary() { @@ -203,13 +207,15 @@ await this.WaitForProductChanges( /// Verifies that if several changes have happened to the table row since last invocation, then a single net /// change for that row is passed to the user function. /// - [Fact] - public async Task MultiOperationTriggerTest() + [Theory] + [SqlInlineData()] + [UnsupportedLanguages(SupportedLanguages.Java)] + public async Task MultiOperationTriggerTest(SupportedLanguages lang) { int firstId = 1; int lastId = 5; this.SetChangeTrackingForTable("Products"); - this.StartFunctionHost(nameof(ProductsTrigger), SupportedLanguages.CSharp); + this.StartFunctionHost(nameof(ProductsTrigger), lang); // 1. Insert + multiple updates to a row are treated as single insert with latest row values. await this.WaitForProductChanges( @@ -408,15 +414,17 @@ public async Task MultiFunctionTriggerTest() /// /// Ensures correct functionality with user functions running across multiple functions host processes. /// - [Fact] - public async Task MultiHostTriggerTest() + [Theory] + [SqlInlineData()] + [UnsupportedLanguages(SupportedLanguages.Java)] + public async Task MultiHostTriggerTest(SupportedLanguages lang) { this.SetChangeTrackingForTable("Products"); // Prepare three function host processes. - this.StartFunctionHost(nameof(ProductsTrigger), SupportedLanguages.CSharp); - this.StartFunctionHost(nameof(ProductsTrigger), SupportedLanguages.CSharp); - this.StartFunctionHost(nameof(ProductsTrigger), SupportedLanguages.CSharp); + this.StartFunctionHost(nameof(ProductsTrigger), lang); + this.StartFunctionHost(nameof(ProductsTrigger), lang); + this.StartFunctionHost(nameof(ProductsTrigger), lang); int firstId = 1; int lastId = 90; @@ -463,6 +471,7 @@ public void TableNotPresentTriggerTest() { this.StartFunctionHostAndWaitForError( nameof(TableNotPresentTrigger), + SupportedLanguages.CSharp, true, "Could not find table: 'dbo.TableNotPresent'."); } @@ -475,6 +484,7 @@ public void PrimaryKeyNotCreatedTriggerTest() { this.StartFunctionHostAndWaitForError( nameof(PrimaryKeyNotPresentTrigger), + SupportedLanguages.CSharp, true, "Could not find primary key created in table: 'dbo.ProductsWithoutPrimaryKey'."); } @@ -488,6 +498,7 @@ public void ReservedPrimaryKeyColumnNamesTriggerTest() { this.StartFunctionHostAndWaitForError( nameof(ReservedPrimaryKeyColumnNamesTrigger), + SupportedLanguages.CSharp, true, "Found reserved column name(s): '_az_func_ChangeVersion', '_az_func_AttemptCount', '_az_func_LeaseExpirationTime' in table: 'dbo.ProductsWithReservedPrimaryKeyColumnNames'." + " Please rename them to be able to use trigger binding."); @@ -501,6 +512,7 @@ public void UnsupportedColumnTypesTriggerTest() { this.StartFunctionHostAndWaitForError( nameof(UnsupportedColumnTypesTrigger), + SupportedLanguages.CSharp, true, "Found column(s) with unsupported type(s): 'Location' (type: geography), 'Geometry' (type: geometry), 'Organization' (type: hierarchyid)" + " in table: 'dbo.ProductsWithUnsupportedColumnTypes'."); @@ -509,11 +521,14 @@ public void UnsupportedColumnTypesTriggerTest() /// /// Tests the error message when change tracking is not enabled on the user table. /// - [Fact] - public void ChangeTrackingNotEnabledTriggerTest() + [Theory] + [SqlInlineData()] + [UnsupportedLanguages(SupportedLanguages.Java)] + public void ChangeTrackingNotEnabledTriggerTest(SupportedLanguages lang) { this.StartFunctionHostAndWaitForError( nameof(ProductsTrigger), + lang, false, "Could not find change tracking enabled for table: 'dbo.Products'."); } @@ -541,14 +556,17 @@ public async void GetMetricsTest() /// /// Tests that when using an unsupported database the expected error is thrown /// - [Fact] - public void UnsupportedDatabaseThrows() + [Theory] + [SqlInlineData()] + [UnsupportedLanguages(SupportedLanguages.Java)] + public void UnsupportedDatabaseThrows(SupportedLanguages lang) { // Change database compat level to unsupported version this.ExecuteNonQuery($"ALTER DATABASE {this.DatabaseName} SET COMPATIBILITY_LEVEL = 120"); this.StartFunctionHostAndWaitForError( nameof(ProductsTrigger), + lang, false, "SQL bindings require a database compatibility level of 130 or higher to function. Current compatibility level = 120"); } diff --git a/test/Integration/test-js/ProductsTriggerWithValidation/function.json b/test/Integration/test-js/ProductsTriggerWithValidation/function.json new file mode 100644 index 000000000..e277c5e39 --- /dev/null +++ b/test/Integration/test-js/ProductsTriggerWithValidation/function.json @@ -0,0 +1,12 @@ +{ + "bindings": [ + { + "name": "changes", + "type": "sqlTrigger", + "direction": "in", + "tableName": "dbo.Products", + "connectionStringSetting": "SqlConnectionString" + } + ], + "disabled": false + } \ No newline at end of file diff --git a/test/Integration/test-js/ProductsTriggerWithValidation/index.js b/test/Integration/test-js/ProductsTriggerWithValidation/index.js new file mode 100644 index 000000000..4ed3d4fc9 --- /dev/null +++ b/test/Integration/test-js/ProductsTriggerWithValidation/index.js @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +module.exports = async function (context, changes) { + const expectedMaxBatchSize = process.env["TEST_EXPECTED_MAX_BATCH_SIZE"] + if (expectedMaxBatchSize && expectedMaxBatchSize != changes.length) { + throw new Error(`Invalid max batch size, got ${changes.length} changes but expected ${expectedMaxBatchSize}`) + } + context.log(`SQL Changes: ${JSON.stringify(changes)}`) +} \ No newline at end of file diff --git a/test/Integration/test-powershell/ProductsTriggerWithValidation/function.json b/test/Integration/test-powershell/ProductsTriggerWithValidation/function.json new file mode 100644 index 000000000..e277c5e39 --- /dev/null +++ b/test/Integration/test-powershell/ProductsTriggerWithValidation/function.json @@ -0,0 +1,12 @@ +{ + "bindings": [ + { + "name": "changes", + "type": "sqlTrigger", + "direction": "in", + "tableName": "dbo.Products", + "connectionStringSetting": "SqlConnectionString" + } + ], + "disabled": false + } \ No newline at end of file diff --git a/test/Integration/test-powershell/ProductsTriggerWithValidation/run.ps1 b/test/Integration/test-powershell/ProductsTriggerWithValidation/run.ps1 new file mode 100644 index 000000000..8ce36e8da --- /dev/null +++ b/test/Integration/test-powershell/ProductsTriggerWithValidation/run.ps1 @@ -0,0 +1,15 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. + +using namespace System.Net + +param($changes) + +$expectedMaxBatchSize = $env:TEST_EXPECTED_MAX_BATCH_SIZE +if ($expectedMaxBatchSize -and $expectedMaxBatchSize -ne $changes.Count) { + throw "Invalid max batch size, got $($changes.Count) changes but expected $expectedMaxBatchSize" +} + +$changesJson = $changes | ConvertTo-Json +$changesJson = $changesJson -replace [Environment]::NewLine,""; +Write-Host "SQL Changes: $changesJson" \ No newline at end of file diff --git a/test/Integration/test-python/ProductsTriggerWithValidation/__init__.py b/test/Integration/test-python/ProductsTriggerWithValidation/__init__.py new file mode 100644 index 000000000..fbfffcf2d --- /dev/null +++ b/test/Integration/test-python/ProductsTriggerWithValidation/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import json +import logging +import os + +def main(changes): + expectedMaxBatchSize = os.environ.get("TEST_EXPECTED_MAX_BATCH_SIZE") + length = len(json.loads(changes)) + if expectedMaxBatchSize and int(expectedMaxBatchSize) != length: + raise Exception("Invalid max batch size, got %d changes but expected %s" % (length, expectedMaxBatchSize)) + logging.info("SQL Changes: %s", changes) diff --git a/test/Integration/test-python/ProductsTriggerWithValidation/function.json b/test/Integration/test-python/ProductsTriggerWithValidation/function.json new file mode 100644 index 000000000..e277c5e39 --- /dev/null +++ b/test/Integration/test-python/ProductsTriggerWithValidation/function.json @@ -0,0 +1,12 @@ +{ + "bindings": [ + { + "name": "changes", + "type": "sqlTrigger", + "direction": "in", + "tableName": "dbo.Products", + "connectionStringSetting": "SqlConnectionString" + } + ], + "disabled": false + } \ No newline at end of file