Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sqlpackage path argument, dotnet tool sqlpackage #221

Merged
merged 19 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions __tests__/AzureSqlAction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jest.mock('fs');

describe('AzureSqlAction tests', () => {
afterEach(() => {
jest.restoreAllMocks();
jest.restoreAllMocks();
});

describe('validate sqlpackage calls for DacpacAction', () => {
Expand Down Expand Up @@ -190,7 +190,7 @@ describe('AzureSqlAction tests', () => {
* @param connectionString The custom connection string to be used for the test. If not specified, a default one using SQL login will be used.
* @returns An ActionInputs objects based on the given action type.
*/
function getInputs(actionType: ActionType, connectionString: string = ''): IActionInputs {
export function getInputs(actionType: ActionType, connectionString: string = ''): IActionInputs {

const defaultConnectionString = 'Server=testServer.database.windows.net;Initial Catalog=testDB;User Id=testUser;Password=placeholder';
const config = connectionString ? new SqlConnectionConfig(connectionString) : new SqlConnectionConfig(defaultConnectionString);
Expand Down
75 changes: 75 additions & 0 deletions __tests__/AzureSqlActionHelper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as fs from 'fs';
import * as semver from 'semver';
import AzureSqlActionHelper from "../src/AzureSqlActionHelper";
import AzureSqlAction, { IBuildAndPublishInputs, IDacpacActionInputs, ActionType, SqlPackageAction, IActionInputs } from "../src/AzureSqlAction";
import { getInputs } from './AzureSqlAction.test';

jest.mock('fs');

describe('AzureSqlActionHelper tests', () => {
afterEach(() => {
jest.restoreAllMocks();
});

const versions = [ // returned from sqlpackage, validated version expected
['162.3.563.1', '162.3.563'], // GA version
['162.4.101.0', '162.4.101'], // GA version
['162.3.562-preview', '162.3.562'], // preview version
['15.0.5164.1', '15.0.5164'] // old version
];

// checks parsing logic used from semver
describe('tests semver parsing for potential sqlpackage version values', () => {
it.each(versions)('should parse %s version correctly', (versionReturned, versionExpected) => {
let semverExpected = semver.coerce(versionExpected);
let semverTested = semver.coerce(versionReturned);

expect(semverTested).toEqual(semverExpected);
});
});

// checks sorting logic used from semver
describe('tests sorting of versions to select latest version', () => {
it('should select latest version', () => {
let versionArray: semver.SemVer[] = [];
versions.forEach(([versionReturned, versionExpected]) => {
versionArray.push(semver.coerce(versionReturned) ?? new semver.SemVer('0.0.0'));
});

let latestVersion = semver.rsort(versionArray)[0];
let latestVersionExpected = semver.coerce(versions[1][1]);

expect(latestVersion).toEqual(latestVersionExpected);
});
});


// // ensures the sqlpackagepath input overrides the version check
dzsquared marked this conversation as resolved.
Show resolved Hide resolved
describe('sqlpackagepath input options', () => {
const sqlpackagepaths = ['//custom/path/to/sqlpackage', 'c:/Program Files/Sqlpackage/sqlpackage'];
it.each(sqlpackagepaths)('should return sqlpackagepath if provided', async (path) => {
let inputs = getInputs(ActionType.DacpacAction) as IDacpacActionInputs;
inputs.sqlpackagePath = path;

let fileExistsSpy = jest.spyOn(fs, "existsSync");
fileExistsSpy.mockReturnValue(true);
let sqlpackagePath = await AzureSqlActionHelper.getSqlPackagePath(inputs);

expect(fileExistsSpy).toHaveBeenCalledWith(inputs.sqlpackagePath);
expect(sqlpackagePath).toEqual(path);
});

});

it('throws if SqlPackage.exe fails to be found at user-specified location', async () => {
let inputs = getInputs(ActionType.DacpacAction) as IDacpacActionInputs;
let action = new AzureSqlAction(inputs);

let getSqlPackagePathSpy = jest.spyOn(AzureSqlActionHelper, 'getSqlPackagePath').mockRejectedValue(1);

expect(await action.execute().catch(() => null)).rejects;
expect(getSqlPackagePathSpy).toHaveBeenCalledTimes(1);
});

});

2 changes: 1 addition & 1 deletion __tests__/FirewallManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('FirewallManager tests', () => {
});
});

it('does not add firewall rule if client has access to MySql server', async () => {
it('does not add firewall rule if client has access to SQL server', async () => {
let addFirewallRuleSpy = jest.spyOn(azureSqlResourceManager, 'addFirewallRule').mockResolvedValue({ name: 'FirewallRuleName' } as any);
let removeFirewallRuleSpy = jest.spyOn(azureSqlResourceManager, 'removeFirewallRule');
await firewallManager.addFirewallRule('');
Expand Down
52 changes: 49 additions & 3 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('main.ts tests', () => {

expect(detectIPAddressSpy).toHaveBeenCalled();
expect(getAuthorizerSpy).not.toHaveBeenCalled();
expect(getInputSpy).toHaveBeenCalledTimes(5);
expect(getInputSpy).toHaveBeenCalledTimes(6);
expect(resolveFilePathSpy).toHaveBeenCalled();
expect(addFirewallRuleSpy).not.toHaveBeenCalled();
expect(actionExecuteSpy).toHaveBeenCalled();
Expand Down Expand Up @@ -101,14 +101,60 @@ describe('main.ts tests', () => {

expect(detectIPAddressSpy).toHaveBeenCalled();
expect(getAuthorizerSpy).not.toHaveBeenCalled();
expect(getInputSpy).toHaveBeenCalledTimes(4);
expect(getInputSpy).toHaveBeenCalledTimes(5);
expect(resolveFilePathSpy).toHaveBeenCalled();
expect(addFirewallRuleSpy).not.toHaveBeenCalled();
expect(actionExecuteSpy).toHaveBeenCalled();
expect(removeFirewallRuleSpy).not.toHaveBeenCalled();
expect(setFailedSpy).not.toHaveBeenCalled();
})

it('gets inputs and executes dacpac action with optional sqlpackage path', async () => {
let resolveFilePathSpy = jest.spyOn(AzureSqlActionHelper, 'resolveFilePath').mockReturnValue('./TestDacpacPackage.dacpac');
let getInputSpy = jest.spyOn(core, 'getInput').mockImplementation((name, options) => {
switch(name) {
case 'connection-string': return 'Server=testServer.database.windows.net;Initial Catalog=testDB;User Id=testUser;Password=placeholder;';
case 'path': return './TestDacpacPackage.dacpac';
case 'action': return 'script';
case 'arguments': return '/p:FakeSqlpackageArgument';
case 'sqlpackage-path': return '/path/to/sqlpackage';
}

return '';
});

let getAuthorizerSpy = jest.spyOn(AuthorizerFactory, 'getAuthorizer');
let addFirewallRuleSpy = jest.spyOn(FirewallManager.prototype, 'addFirewallRule');
let actionExecuteSpy = jest.spyOn(AzureSqlAction.prototype, 'execute');
let removeFirewallRuleSpy = jest.spyOn(FirewallManager.prototype, 'removeFirewallRule');
let setFailedSpy = jest.spyOn(core, 'setFailed');
let detectIPAddressSpy = SqlUtils.detectIPAddress = jest.fn().mockImplementationOnce(() => {
return "";
});

await run();

expect(AzureSqlAction).toHaveBeenCalled();
expect(AzureSqlAction).toHaveBeenCalledWith(
expect.objectContaining({
actionType: ActionType.DacpacAction,
filePath: './TestDacpacPackage.dacpac',
sqlpackageAction: SqlPackageAction.Script,
additionalArguments: '/p:FakeSqlpackageArgument',
sqlpackagePath: '/path/to/sqlpackage'
} as IDacpacActionInputs)
);

expect(detectIPAddressSpy).toHaveBeenCalled();
expect(getAuthorizerSpy).not.toHaveBeenCalled();
expect(getInputSpy).toHaveBeenCalledTimes(5);
expect(resolveFilePathSpy).toHaveBeenCalled();
expect(addFirewallRuleSpy).not.toHaveBeenCalled();
expect(actionExecuteSpy).toHaveBeenCalled();
expect(removeFirewallRuleSpy).not.toHaveBeenCalled();
expect(setFailedSpy).not.toHaveBeenCalled();
})

it('gets inputs and executes sql action', async () => {
let resolveFilePathSpy = jest.spyOn(AzureSqlActionHelper, 'resolveFilePath').mockReturnValue('./TestSqlFile.sql');
let getInputSpy = jest.spyOn(core, 'getInput').mockImplementation((name, options) => {
Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ inputs:
arguments:
description: 'In case of .dacpac or .sqlproj file types, additional sqlpackage arguments that will be applied. In case of .sql file type, additional go-sqlcmd argument that will be applied.'
required: false
sqlpackage-path:
description: 'Specify a SqlPackage executable location to override the default locations.'
required: false
build-arguments:
description: 'In case of a .sqlproj file, additional arguments that will be applied to dotnet build when building the database project.'
required: false
Expand Down
2 changes: 1 addition & 1 deletion lib/main.js

Large diffs are not rendered by default.

Loading
Loading