Skip to content

Commit

Permalink
Merge 33c5a46 into e91e481
Browse files Browse the repository at this point in the history
  • Loading branch information
tbarlow12 committed May 24, 2019
2 parents e91e481 + 33c5a46 commit d782c01
Show file tree
Hide file tree
Showing 17 changed files with 589 additions and 278 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions src/index.test.ts

This file was deleted.

25 changes: 25 additions & 0 deletions src/plugins/apim/apimFunctionPlugin.test.ts
@@ -0,0 +1,25 @@
import { MockFactory } from "../../test/mockFactory";
import { invokeHook } from "../../test/utils";
import { AzureApimFunctionPlugin } from './apimFunctionPlugin';

jest.mock('../../services/apimService');
import { ApimService } from '../../services/apimService';

describe('APIM Function Plugin', () => {
it('calls deploy function', async () => {
const deployFunction = jest.fn();

ApimService.prototype.deployFunction = deployFunction;

const sls = MockFactory.createTestServerless();
sls.service.provider['apim'] = 'apim config'
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureApimFunctionPlugin(sls, options);

await invokeHook(plugin, 'after:deploy:function:deploy');

expect(sls.cli.log).toBeCalledWith('Starting APIM function deployment')
expect(deployFunction).toBeCalled();
expect(sls.cli.log).lastCalledWith('Finished APIM function deployment')
});
});
43 changes: 43 additions & 0 deletions src/plugins/apim/apimServicePlugin.test.ts
@@ -1,6 +1,11 @@
import Serverless from 'serverless';
import { MockFactory } from "../../test/mockFactory";
import { invokeHook } from "../../test/utils";
import { AzureApimServicePlugin } from './apimServicePlugin';

jest.mock('../../services/apimService');
import { ApimService } from '../../services/apimService';

describe('APIM Service Plugin', () => {
it('is defined', () => {
expect(AzureApimServicePlugin).toBeDefined();
Expand All @@ -16,4 +21,42 @@ describe('APIM Service Plugin', () => {

expect(plugin).not.toBeNull();
});

it('calls deploy API and deploy functions', async () => {
const deployApi = jest.fn();
const deployFunctions = jest.fn();

ApimService.prototype.deployApi = deployApi;
ApimService.prototype.deployFunctions = deployFunctions;

const sls = MockFactory.createTestServerless();
sls.service.provider['apim'] = 'apim config'
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureApimServicePlugin(sls, options);

await invokeHook(plugin, 'after:deploy:deploy');

expect(sls.cli.log).toBeCalledWith('Starting APIM service deployment')
expect(deployApi).toBeCalled();
expect(deployFunctions).toBeCalled();
expect(sls.cli.log).lastCalledWith('Finished APIM service deployment')
});

it('does not call deploy API or deploy functions when "apim" not included in config', async () => {
const deployApi = jest.fn();
const deployFunctions = jest.fn();

ApimService.prototype.deployApi = deployApi;
ApimService.prototype.deployFunctions = deployFunctions;

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureApimServicePlugin(sls, options);

await invokeHook(plugin, 'after:deploy:deploy');

expect(sls.cli.log).not.toBeCalled()
expect(deployApi).not.toBeCalled();
expect(deployFunctions).not.toBeCalled();
});
});
33 changes: 33 additions & 0 deletions src/plugins/deploy/azureDeployPlugin.test.ts
@@ -0,0 +1,33 @@
import { MockFactory } from "../../test/mockFactory";
import { invokeHook } from "../../test/utils";
import { AzureDeployPlugin } from "./azureDeployPlugin";

jest.mock("../../services/functionAppService");
import { FunctionAppService } from "../../services/functionAppService";

jest.mock("../../services/resourceService");
import { ResourceService } from "../../services/resourceService";

describe('Deploy plugin', () => {

it('calls deploy hook', async () => {
const deployResourceGroup = jest.fn();
const functionAppStub = "Function App Stub";
const deploy = jest.fn(() => Promise.resolve(functionAppStub));
const uploadFunctions = jest.fn();

ResourceService.prototype.deployResourceGroup = deployResourceGroup
FunctionAppService.prototype.deploy = deploy
FunctionAppService.prototype.uploadFunctions = uploadFunctions

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureDeployPlugin(sls, options);

await invokeHook(plugin, 'deploy:deploy');

expect(deployResourceGroup).toBeCalled();
expect(deploy).toBeCalled();
expect(uploadFunctions).toBeCalledWith(functionAppStub);
});
});
123 changes: 123 additions & 0 deletions src/plugins/login/loginPlugin.test.ts
@@ -0,0 +1,123 @@
import { MockFactory } from "../../test/mockFactory";
import { invokeHook } from "../../test/utils";
import { AzureLoginPlugin } from "./loginPlugin";
import { AzureLoginService } from "../../services/loginService";

describe('Login Plugin', () => {

const authResponse = MockFactory.createTestAuthResponse();

it('returns if azure credentials are set', async () => {
const interactiveLogin = jest.fn(() => Promise.resolve(authResponse));
const servicePrincipalLogin = jest.fn(() => Promise.resolve(authResponse));

AzureLoginService.interactiveLogin = interactiveLogin;
AzureLoginService.servicePrincipalLogin = servicePrincipalLogin;

const sls = MockFactory.createTestServerless();
sls.variables['azureCredentials'] = 'credentials';
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureLoginPlugin(sls, options);

await invokeHook(plugin, 'before:package:initialize');

expect(interactiveLogin).not.toBeCalled();
expect(servicePrincipalLogin).not.toBeCalled();
});

it('calls login if azure credentials are not set', async () => {
const interactiveLogin = jest.fn(() => Promise.resolve(authResponse));
const servicePrincipalLogin = jest.fn(() => Promise.resolve(authResponse));

AzureLoginService.interactiveLogin = interactiveLogin;
AzureLoginService.servicePrincipalLogin = servicePrincipalLogin;

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureLoginPlugin(sls, options);

await invokeHook(plugin, 'before:package:initialize');

expect(interactiveLogin).toBeCalled();
expect(servicePrincipalLogin).not.toBeCalled();
});

it('calls service principal login if environment variables are set', async () => {

process.env.azureSubId = 'azureSubId';
process.env.azureServicePrincipalClientId = 'azureServicePrincipalClientId';
process.env.azureServicePrincipalPassword = 'azureServicePrincipalPassword';
process.env.azureServicePrincipalTenantId = 'azureServicePrincipalTenantId';

const interactiveLogin = jest.fn(() => Promise.resolve(authResponse));
const servicePrincipalLogin = jest.fn(() => Promise.resolve(authResponse));

AzureLoginService.interactiveLogin = interactiveLogin;
AzureLoginService.servicePrincipalLogin = servicePrincipalLogin;

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureLoginPlugin(sls, options);
await invokeHook(plugin, 'before:package:initialize');
expect(servicePrincipalLogin).toBeCalledWith(
'azureServicePrincipalClientId',
'azureServicePrincipalPassword',
'azureServicePrincipalTenantId'
)
expect(interactiveLogin).not.toBeCalled();

expect(sls.variables['azureCredentials']).toEqual(authResponse.credentials);
expect(sls.variables['subscriptionId']).toEqual('azureSubId');
});

it('calls interactive login if environment variables are not set', async () => {
delete process.env.azureSubId;
delete process.env.azureServicePrincipalClientId;
delete process.env.azureServicePrincipalPassword;
delete process.env.azureServicePrincipalTenantId;

const interactiveLogin = jest.fn(() => Promise.resolve(authResponse));
const servicePrincipalLogin = jest.fn(() => Promise.resolve(authResponse));

AzureLoginService.interactiveLogin = interactiveLogin;
AzureLoginService.servicePrincipalLogin = servicePrincipalLogin;

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureLoginPlugin(sls, options);
await invokeHook(plugin, 'before:package:initialize');
expect(servicePrincipalLogin).not.toBeCalled();
expect(interactiveLogin).toBeCalled();

expect(sls.variables['azureCredentials']).toEqual(authResponse.credentials);
expect(sls.variables['subscriptionId']).toEqual('azureSubId');
});

it('logs an error from authentication', async () => {
process.env.azureSubId = 'azureSubId';
process.env.azureServicePrincipalClientId = 'azureServicePrincipalClientId';
process.env.azureServicePrincipalPassword = 'azureServicePrincipalPassword';
process.env.azureServicePrincipalTenantId = 'azureServicePrincipalTenantId';

const interactiveLogin = jest.fn(() => Promise.resolve(authResponse));
const errorMessage = 'This is my error message';
const servicePrincipalLogin = jest.fn(() => {
throw new Error(errorMessage);
});

AzureLoginService.interactiveLogin = interactiveLogin;
AzureLoginService.servicePrincipalLogin = servicePrincipalLogin;

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureLoginPlugin(sls, options);
await invokeHook(plugin, 'before:package:initialize');
expect(servicePrincipalLogin).toBeCalledWith(
'azureServicePrincipalClientId',
'azureServicePrincipalPassword',
'azureServicePrincipalTenantId'
)
expect(interactiveLogin).not.toBeCalled();
expect(sls.cli.log).lastCalledWith(`Error: ${errorMessage}`)
});
})
29 changes: 6 additions & 23 deletions src/plugins/login/loginPlugin.ts
@@ -1,7 +1,6 @@
import open from 'open';
import { interactiveLoginWithAuthResponse, loginWithServicePrincipalSecretWithAuthResponse } from '@azure/ms-rest-nodeauth';
import Serverless from 'serverless';
import AzureProvider from '../../provider/azureProvider';
import { AzureLoginService } from '../../services/loginService';

export class AzureLoginPlugin {
private provider: AzureProvider;
Expand All @@ -23,32 +22,16 @@ export class AzureLoginPlugin {

this.serverless.cli.log('Logging into Azure');

let authResult = null;

const subscriptionId = process.env.azureSubId;
const clientId = process.env.azureServicePrincipalClientId;
const secret = process.env.azureServicePrincipalPassword;
const tenantId = process.env.azureServicePrincipalTenantId;

try {
if (subscriptionId && clientId && secret && tenantId) {
authResult = await loginWithServicePrincipalSecretWithAuthResponse(clientId, secret, tenantId);
}
else {
await open('https://microsoft.com/devicelogin');
authResult = await interactiveLoginWithAuthResponse();
}

// TODO: This is temporary until the azure provider goes away
this.provider.credentials = authResult.credentials;

this.serverless.variables['azureAccessToken'] = authResult.credentials.tokenCache._entries[0].accessToken;
const authResult = await AzureLoginService.login();
this.serverless.variables['azureCredentials'] = authResult.credentials;
this.serverless.variables['subscriptionId'] = authResult.subscriptionId || subscriptionId;
// Use environment variable for sub ID or use the first subscription in the list (service principal can
// have access to more than one subscription)
this.serverless.variables['subscriptionId'] = process.env.azureSubId || authResult.subscriptions[0].id;
}
catch (e) {
this.serverless.cli.log('Error logging into azure');
this.serverless.cli.log(e);
this.serverless.cli.log(`${e}`);
}
}
}
31 changes: 31 additions & 0 deletions src/plugins/package/azurePackage.test.ts
@@ -0,0 +1,31 @@
import { MockFactory } from "../../test/mockFactory";
import { invokeHook } from "../../test/utils";
import { AzurePackage } from "./azurePackage"

jest.mock('../../shared/bindings');
import { BindingUtils } from '../../shared/bindings';
jest.mock('../../shared/utils');
import { Utils, FunctionMetadata } from '../../shared/utils';

describe('Azure Package Plugin', () => {
it('sets up provider configuration', async () => {
const metadata = 'metadata';
const functionName = 'function1';

const getFunctionMetaDataFn = jest.fn(() => metadata as any as FunctionMetadata);
const createEventsBindingsFn = jest.fn();

Utils.getFunctionMetaData = getFunctionMetaDataFn
BindingUtils.createEventsBindings = createEventsBindingsFn

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzurePackage(sls, options);

await invokeHook(plugin, 'package:setupProviderConfiguration');

expect(sls.cli.log).toBeCalledWith('Building Azure Events Hooks');
expect(getFunctionMetaDataFn).toBeCalledWith(functionName, sls);
expect(createEventsBindingsFn).toBeCalledWith(sls.config.servicePath, functionName, metadata);
});
});
8 changes: 4 additions & 4 deletions src/plugins/package/azurePackage.ts
@@ -1,8 +1,8 @@

import Serverless from 'serverless';
import AzureProvider from '../../provider/azureProvider';
import { createEventsBindings } from '../../shared/bindings';
import { getFunctionMetaData } from '../../shared/utils';
import { BindingUtils } from '../../shared/bindings';
import { Utils } from '../../shared/utils';

export class AzurePackage {
provider: AzureProvider
Expand All @@ -19,9 +19,9 @@ export class AzurePackage {

const createEventsPromises = this.serverless.service.getAllFunctions()
.map((functionName) => {
const metaData = getFunctionMetaData(functionName, this.serverless);
const metaData = Utils.getFunctionMetaData(functionName, this.serverless);

return createEventsBindings(this.serverless.config.servicePath, functionName, metaData);
return BindingUtils.createEventsBindings(this.serverless.config.servicePath, functionName, metaData);
});

return Promise.all(createEventsPromises);
Expand Down
26 changes: 26 additions & 0 deletions src/plugins/remove/azureRemove.test.ts
@@ -0,0 +1,26 @@
import { MockFactory } from "../../test/mockFactory";
import { invokeHook } from "../../test/utils";
import { AzureRemove } from "./azureRemove";

jest.mock("../../services/resourceService");
import { ResourceService } from "../../services/resourceService";

describe('Remove Plugin', () => {
it('calls remove hook', async () => {
const deleteDeployment = jest.fn();
const deleteResourceGroup = jest.fn();

ResourceService.prototype.deleteDeployment = deleteDeployment;
ResourceService.prototype.deleteResourceGroup = deleteResourceGroup;

const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureRemove(sls, options);

await invokeHook(plugin, 'remove:remove');

expect(deleteDeployment).toBeCalled();
expect(deleteResourceGroup).toBeCalled();
expect(sls.cli.log).toBeCalledWith('Service successfully removed');
});
});

0 comments on commit d782c01

Please sign in to comment.