Skip to content

Commit

Permalink
Merge pull request #1 from composable-com/dev
Browse files Browse the repository at this point in the history
dev to master
  • Loading branch information
f1729 authored Sep 25, 2023
2 parents 18cf899 + 7331b46 commit a17d82e
Show file tree
Hide file tree
Showing 25 changed files with 1,349 additions and 249 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ coverage
.DS_Store
.vscode
build/
.env
.env
.idea
55 changes: 17 additions & 38 deletions connect.yaml
Original file line number Diff line number Diff line change
@@ -1,41 +1,4 @@
deployAs:
- name: service
applicationType: service
endpoint: /service
scripts:
postDeploy: npm install && npm run build && npm run connector:post-deploy
preUndeploy: npm install && npm run build && npm run connector:pre-undeploy
configuration:
standardConfiguration:
- key: CTP_REGION
description: commercetools Composable Commerce API region
securedConfiguration:
- key: CTP_PROJECT_KEY
description: commercetools Composable Commerce project key
- key: CTP_CLIENT_ID
description: commercetools Composable Commerce client ID
- key: CTP_CLIENT_SECRET
description: commercetools Composable Commerce client secret
- key: CTP_SCOPE
description: commercetools Composable Commerce client scope
- name: job
applicationType: job
endpoint: /job
properties:
schedule: "*/5 * * * *"
configuration:
standardConfiguration:
- key: CTP_REGION
description: commercetools Composable Commerce API region
securedConfiguration:
- key: CTP_PROJECT_KEY
description: commercetools Composable Commerce project key
- key: CTP_CLIENT_ID
description: commercetools Composable Commerce client ID
- key: CTP_CLIENT_SECRET
description: commercetools Composable Commerce client secret
- key: CTP_SCOPE
description: commercetools Composable Commerce client scope
- name: event
applicationType: event
endpoint: /event
Expand All @@ -54,4 +17,20 @@ deployAs:
- key: CTP_CLIENT_SECRET
description: commercetools Composable Commerce client secret
- key: CTP_SCOPE
description: commercetools Composable Commerce client scope
description: commercetools Composable Commerce client scope
- key: FLUENT_CLIENT_ID
description: Fluent Retail client ID
- key: FLUENT_CLIENT_SECRET
description: Fluent Retail client secret
- key: FLUENT_USERNAME
description: Fluent Retail username
- key: FLUENT_PASSWORD
description: Fluent Retail password
- key: FLUENT_HOST
description: Fluent Retail host
- key: FLUENT_CATALOGUE_REF
description: Fluent Retail catalogue reference
- key: FLUENT_RETAILER_ID
description: Fluent Retail retailer ID
- key: FLUENT_CATALOG_LOCALE
description: Locale used in Commercetools in product names, descriptions, etc. (default en-US)
1 change: 1 addition & 0 deletions event/.prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"trailingComma": "es5",
"semi": false,
"singleQuote": true,
"parser": "typescript",
"printWidth": 80,
Expand Down
1 change: 1 addition & 0 deletions event/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"lint": "eslint . --ext .ts",
"prettier": "prettier --write '**/*.{js,ts}'",
"test": "jest --config jest.config.cjs",
"test:coverage": "jest --config jest.config.cjs --coverage --collectCoverageFrom='src/**/*.{ts,jxs}'",
"test:watch": "jest --watch",
"connector:post-deploy": "node build/connector/post-deploy.js",
"connector:pre-undeploy": "node build/connector/pre-undeploy.js"
Expand Down
36 changes: 36 additions & 0 deletions event/src/client/build.client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createClient } from './build.client';
import { ClientBuilder } from '@commercetools/sdk-client-v2';

jest.mock('@commercetools/sdk-client-v2', () => ({
ClientBuilder: jest.fn().mockImplementation(() => ({
withProjectKey: jest.fn().mockReturnThis(),
withClientCredentialsFlow: jest.fn().mockReturnThis(),
withHttpMiddleware: jest.fn().mockReturnThis(),
build: jest.fn(),
})),
}));

jest.mock('../middleware/auth.middleware', () => ({
authMiddlewareOptions: jest.fn(),
}));

jest.mock('../middleware/http.middleware', () => ({
httpMiddlewareOptions: jest.fn(),
}));

jest.mock('../utils/config.utils', () => ({
readConfiguration: jest.fn().mockReturnValue({
projectKey: 'test-project-key',
}),
}));

describe('createClient function', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should create a new Client with the correct configuration', () => {
createClient();
expect(ClientBuilder).toHaveBeenCalled();
});
});
23 changes: 23 additions & 0 deletions event/src/client/create.client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createApiRoot } from './create.client';

jest.mock('../utils/config.utils', () => ({
readConfiguration: jest.fn().mockReturnValue({
projectKey: 'test-project-key',
clientId: 'test-client-id',
clientSecret: 'test-client-secret',
scope: 'test-scope',
region: 'test-region'
}),
}));

describe('createApiRoot function', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should create an API root with the correct project key', () => {
const apiRoot = createApiRoot();

expect(apiRoot.apiClients).toBeDefined();
});
});
25 changes: 16 additions & 9 deletions event/src/connector/actions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { ByProjectKeyRequestBuilder } from '@commercetools/platform-sdk/dist/declarations/src/generated/client/by-project-key-request-builder';

const PRODUCT_PUBLISHED_SUBSCRIPTION_KEY =
'myconnector-productPublishedSubscription';
const MY_SUBSCRIPTION_KEY = 'ct-connect-fluent-subscription';

export async function createProductPublishedSubscription(
export async function createMySubscription(
apiRoot: ByProjectKeyRequestBuilder,
topicName: string,
projectId: string
Expand All @@ -14,7 +13,7 @@ export async function createProductPublishedSubscription(
.subscriptions()
.get({
queryArgs: {
where: `key = "${PRODUCT_PUBLISHED_SUBSCRIPTION_KEY}"`,
where: `key = "${MY_SUBSCRIPTION_KEY}"`,
},
})
.execute();
Expand All @@ -24,7 +23,7 @@ export async function createProductPublishedSubscription(

await apiRoot
.subscriptions()
.withKey({ key: PRODUCT_PUBLISHED_SUBSCRIPTION_KEY })
.withKey({ key: MY_SUBSCRIPTION_KEY })
.delete({
queryArgs: {
version: subscription.version,
Expand All @@ -37,24 +36,32 @@ export async function createProductPublishedSubscription(
.subscriptions()
.post({
body: {
key: PRODUCT_PUBLISHED_SUBSCRIPTION_KEY,
key: MY_SUBSCRIPTION_KEY,
destination: {
type: 'GoogleCloudPubSub',
topic: topicName,
projectId,
},
format: {
type: 'CloudEvents',
cloudEventsVersion: '1.0',
},
messages: [
{
resourceTypeId: 'product',
types: ['ProductPublished'],
},
{
resourceTypeId: 'order',
types: ['OrderCreated'],
}
],
},
})
.execute();
}

export async function deleteProductPublishedSubscription(
export async function deleteMySubscription(
apiRoot: ByProjectKeyRequestBuilder
): Promise<void> {
const {
Expand All @@ -63,7 +70,7 @@ export async function deleteProductPublishedSubscription(
.subscriptions()
.get({
queryArgs: {
where: `key = "${PRODUCT_PUBLISHED_SUBSCRIPTION_KEY}"`,
where: `key = "${MY_SUBSCRIPTION_KEY}"`,
},
})
.execute();
Expand All @@ -73,7 +80,7 @@ export async function deleteProductPublishedSubscription(

await apiRoot
.subscriptions()
.withKey({ key: PRODUCT_PUBLISHED_SUBSCRIPTION_KEY })
.withKey({ key: MY_SUBSCRIPTION_KEY })
.delete({
queryArgs: {
version: subscription.version,
Expand Down
57 changes: 57 additions & 0 deletions event/src/connector/post-deploy.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { assertError } from '../utils/assert.utils';
import * as postDeploy from './post-deploy';
import * as actions from './actions';

jest.mock('../utils/assert.utils', () => ({
assertError: jest.fn(),
}));

jest.mock('../utils/config.utils', () => ({
readConfiguration: jest.fn().mockReturnValue({
projectKey: 'test-project-key',
clientId: 'test-client-id',
clientSecret: 'test-client-secret',
scope: 'test-scope',
region: 'test-region'
}),
}));

jest
.spyOn(actions, 'createProductPublishedSubscription')
.mockReturnValue(Promise.resolve());

describe('run function', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should call postDeploy and handle errors gracefully', async () => {
const mockError = new Error('Test error');
const mockErrorMessage = `Post-deploy failed: ${mockError.message}`;
jest
.spyOn(actions, 'createProductPublishedSubscription')
.mockRejectedValueOnce(mockError);

const writeSpy = jest.spyOn(process.stderr, 'write');

await postDeploy.run();

expect(assertError).toHaveBeenCalledWith(mockError);
expect(writeSpy).toHaveBeenCalledWith(mockErrorMessage);
});

it('should not throw an error when postDeploy succeeds', async () => {
const mockError = new Error('Test error');
jest
.spyOn(postDeploy, 'run')
.mockImplementationOnce(() => Promise.resolve());
const writeSpy = jest.spyOn(process.stderr, 'write');
await postDeploy.run();
jest
.spyOn(actions, 'createProductPublishedSubscription')
.mockRejectedValueOnce(mockError);

expect(assertError).not.toHaveBeenCalled();
expect(writeSpy).not.toHaveBeenCalled();
});
});
15 changes: 6 additions & 9 deletions event/src/connector/post-deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,26 @@ dotenv.config();

import { createApiRoot } from '../client/create.client';
import { assertError, assertString } from '../utils/assert.utils';
import { createProductPublishedSubscription } from './actions';
import { createMySubscription } from './actions';

const CONNECT_GCP_TOPIC_NAME_KEY = 'CONNECT_GCP_TOPIC_NAME';
const CONNECT_GCP_PROJECT_ID_KEY = 'CONNECT_GCP_PROJECT_ID';

async function postDeploy(properties: Map<string, unknown>): Promise<void> {
const topicName = properties.get(CONNECT_GCP_TOPIC_NAME_KEY);
const projectId = properties.get(CONNECT_GCP_PROJECT_ID_KEY);

assertString(topicName, CONNECT_GCP_TOPIC_NAME_KEY);
assertString(projectId, CONNECT_GCP_PROJECT_ID_KEY);
const topicName = properties.get(CONNECT_GCP_TOPIC_NAME_KEY) as string;
const projectId = properties.get(CONNECT_GCP_PROJECT_ID_KEY) as string;

const apiRoot = createApiRoot();
await createProductPublishedSubscription(apiRoot, topicName, projectId);
await createMySubscription(apiRoot, topicName, projectId);
}

async function run(): Promise<void> {
export async function run(): Promise<void> {
try {
const properties = new Map(Object.entries(process.env));
await postDeploy(properties);
} catch (error) {
assertError(error);
process.stderr.write(`Post-deploy failed: ${error.message}\n`);
process.stderr.write(`Post-deploy failed: ${error.message}`);
process.exitCode = 1;
}
}
Expand Down
Loading

0 comments on commit a17d82e

Please sign in to comment.