Skip to content

Commit 33abc1d

Browse files
authored
Copy latest sql dll to extension bundle in pipeline (#395)
* cp sql dll to extension bundle * remove quotes + add windows condition * fix path * add bin to path + add linux * use source folder * use preview path * add overwrite and ignore mkdir errors * fix target folder path * remove ignoreMakeDirErrors * add wait for case sensitivity test * use one task * set cache timeout to 0 * fix target path * pr comments + add timeout var linux * set cache to 0 for one test
1 parent 44f8c11 commit 33abc1d

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

builds/azure-pipelines/template-steps-build-test.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ steps:
3232
displayName: 'Set npm installation path for Windows'
3333
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
3434

35+
- bash: echo "##vso[task.setvariable variable=azureFunctionsExtensionBundlePath]$(func GetExtensionBundlePath)"
36+
displayName: 'Set Azure Functions extension bundle path'
37+
workingDirectory: $(Build.SourcesDirectory)/samples/samples-js
38+
3539
- task: DockerInstaller@0
3640
displayName: Docker Installer
3741
inputs:
@@ -67,6 +71,14 @@ steps:
6771
projects: '${{ parameters.solution }}'
6872
arguments: '--configuration ${{ parameters.configuration }} -p:GeneratePackageOnBuild=false -p:Version=${{ parameters.binariesVersion }}'
6973

74+
- task: CopyFiles@2
75+
displayName: 'Copy Sql extension dll to Azure Functions extension bundle'
76+
inputs:
77+
sourceFolder: $(Build.SourcesDirectory)/src/bin/${{ parameters.configuration }}/netstandard2.0
78+
contents: Microsoft.Azure.WebJobs.Extensions.Sql.dll
79+
targetFolder: $(azureFunctionsExtensionBundlePath)/bin
80+
overWrite: true
81+
7082
- script: |
7183
npm install
7284
npm run lint

src/SqlAsyncCollector.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Globalization;
56
using System.Collections.Generic;
67
using System.Data;
78
using System.Linq;
@@ -58,6 +59,8 @@ internal class SqlAsyncCollector<T> : IAsyncCollector<T>, IDisposable
5859

5960
private const string Collation = "Collation";
6061

62+
private const int AZ_FUNC_TABLE_INFO_CACHE_TIMEOUT_MINUTES = 10;
63+
6164
private readonly IConfiguration _configuration;
6265
private readonly SqlAttribute _attribute;
6366
private readonly ILogger _logger;
@@ -171,15 +174,29 @@ private async Task UpsertRowsAsync(IEnumerable<T> rows, SqlAttribute attribute,
171174
ObjectCache cachedTables = MemoryCache.Default;
172175
var tableInfo = cachedTables[cacheKey] as TableInformation;
173176

177+
int timeout = AZ_FUNC_TABLE_INFO_CACHE_TIMEOUT_MINUTES;
178+
string timeoutEnvVar = Environment.GetEnvironmentVariable("AZ_FUNC_TABLE_INFO_CACHE_TIMEOUT_MINUTES");
179+
if (!string.IsNullOrEmpty(timeoutEnvVar))
180+
{
181+
if (int.TryParse(timeoutEnvVar, NumberStyles.Integer, CultureInfo.InvariantCulture, out timeout))
182+
{
183+
this._logger.LogDebugWithThreadId($"Overriding default table info cache timeout with new value {timeout}");
184+
}
185+
else
186+
{
187+
timeout = AZ_FUNC_TABLE_INFO_CACHE_TIMEOUT_MINUTES;
188+
}
189+
}
190+
174191
if (tableInfo == null)
175192
{
176193
TelemetryInstance.TrackEvent(TelemetryEventName.TableInfoCacheMiss, props);
177194
// set the columnNames for supporting T as JObject since it doesn't have columns in the member info.
178195
tableInfo = await TableInformation.RetrieveTableInformationAsync(connection, fullTableName, this._logger, GetColumnNamesFromItem(rows.First()));
179196
var policy = new CacheItemPolicy
180197
{
181-
// Re-look up the primary key(s) after 10 minutes (they should not change very often!)
182-
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(10)
198+
// Re-look up the primary key(s) after timeout (default timeout is 10 minutes)
199+
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(timeout)
183200
};
184201

185202
cachedTables.Set(cacheKey, tableInfo, policy);

test/Integration/IntegrationTestBase.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ protected void StartAzurite()
176176
/// - The functionName is different than its route.<br/>
177177
/// - You can start multiple functions by passing in a space-separated list of function names.<br/>
178178
/// </remarks>
179-
protected void StartFunctionHost(string functionName, SupportedLanguages language, bool useTestFolder = false, DataReceivedEventHandler customOutputHandler = null)
179+
protected void StartFunctionHost(string functionName, SupportedLanguages language, bool useTestFolder = false, DataReceivedEventHandler customOutputHandler = null, Dictionary<string, string> environmentVariables = null)
180180
{
181181
string workingDirectory = language == SupportedLanguages.CSharp && useTestFolder ? GetPathToBin() : Path.Combine(GetPathToBin(), "SqlExtensionSamples", Enum.GetName(typeof(SupportedLanguages), language));
182182
if (!Directory.Exists(workingDirectory))
@@ -196,6 +196,14 @@ protected void StartFunctionHost(string functionName, SupportedLanguages languag
196196
UseShellExecute = false
197197
};
198198

199+
if (environmentVariables != null)
200+
{
201+
foreach (KeyValuePair<string, string> variable in environmentVariables)
202+
{
203+
startInfo.EnvironmentVariables[variable.Key] = variable.Value;
204+
}
205+
}
206+
199207
// Always disable telemetry during test runs
200208
startInfo.EnvironmentVariables[TelemetryOptoutEnvVar] = "1";
201209

test/Integration/SqlOutputBindingIntegrationTests.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,15 @@ public void AddProductWithIdentity_MissingPrimaryColumn(SupportedLanguages lang)
352352
[SqlInlineData()]
353353
public void AddProductCaseSensitiveTest(SupportedLanguages lang)
354354
{
355-
this.StartFunctionHost(nameof(AddProductParams), lang);
355+
// Set table info cache timeout to 0 minutes so that new collation gets picked up
356+
var environmentVariables = new Dictionary<string, string>()
357+
{
358+
{ "AZ_FUNC_TABLE_INFO_CACHE_TIMEOUT_MINUTES", "0" }
359+
};
360+
this.StartFunctionHost(nameof(AddProductParams), lang, false, null, environmentVariables);
356361

357362
// Change database collation to case sensitive
358-
this.ExecuteNonQuery($"ALTER DATABASE {this.DatabaseName} COLLATE Latin1_General_CS_AS");
363+
this.ExecuteNonQuery($"ALTER DATABASE {this.DatabaseName} SET Single_User WITH ROLLBACK IMMEDIATE; ALTER DATABASE {this.DatabaseName} COLLATE Latin1_General_CS_AS; ALTER DATABASE {this.DatabaseName} SET Multi_User;");
359364

360365
var query = new Dictionary<string, string>()
361366
{
@@ -369,7 +374,7 @@ public void AddProductCaseSensitiveTest(SupportedLanguages lang)
369374
Assert.Throws<AggregateException>(() => this.SendOutputGetRequest("addproduct-params", query).Wait());
370375

371376
// Change database collation back to case insensitive
372-
this.ExecuteNonQuery($"ALTER DATABASE {this.DatabaseName} COLLATE Latin1_General_CI_AS");
377+
this.ExecuteNonQuery($"ALTER DATABASE {this.DatabaseName} SET Single_User WITH ROLLBACK IMMEDIATE; ALTER DATABASE {this.DatabaseName} COLLATE Latin1_General_CI_AS; ALTER DATABASE {this.DatabaseName} SET Multi_User;");
373378

374379
this.SendOutputGetRequest("addproduct-params", query).Wait();
375380

0 commit comments

Comments
 (0)