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

Fix: Face issue when testing the VulcanSQL integration with Canner Enteprise #185

Merged
merged 2 commits into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
38 changes: 28 additions & 10 deletions packages/extension-store-canner/src/lib/canner/persistenceStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
PersistentStore,
TYPES,
VulcanExtensionId,
VulcanInternalExtension,
} from '@vulcan-sql/core';
import { inject } from 'inversify';
import * as oas3 from 'openapi3-ts';
Expand Down Expand Up @@ -37,7 +36,7 @@ interface WorkspaceArtifact {
* Used the string to identify the extension Id not by the enum "ArtifactBuilderProviderType".
* Because if we create another enum to extend the 'ArtifactBuilderProviderType', it seems unnecessary to give the new enum only has 'Canner' as its type."
* */
@VulcanInternalExtension()

@VulcanExtensionId('Canner')
export class CannerPersistenceStore extends PersistentStore {
private filePath: string;
Expand Down Expand Up @@ -70,14 +69,19 @@ export class CannerPersistenceStore extends PersistentStore {
});
// get the indicator files path of each workspaces
const files = await getIndicatorFilesOfWorkspaces(filesInfo);
this.logger.debug('Succeed to get the indicator files of each workspaces');
this.logger.debug(
`Succeed to get the indicator files of each workspaces: ${JSON.stringify(
files
)}`
);
// get the latest artifacts of each workspaces
const artifacts = await this.getLatestArtifactsOfWorkspaces(
storageService,
files
);
// merge the artifacts of each workspaces to one artifact
const artifact = await this.mergeArtifactsOfWorkspaces(artifacts);
this.logger.debug(`Succeed to merge the artifacts: ${artifact}`);
return Buffer.from(JSON.stringify(artifact), 'utf-8');
}

Expand All @@ -87,14 +91,16 @@ export class CannerPersistenceStore extends PersistentStore {
): Promise<WorkspaceArtifact[]> {
return await Promise.all(
// download latest artifact buffer content of each workspace by viewing the indicator.json of the each workspace
indicators.map(async ({ workspaceId, name }) => {
const buffer = await storageService.downObjectAsBuffer({ name });
indicators.map(async ({ workspaceId, name: indicatorPath }) => {
const buffer = await storageService.downObjectAsBuffer({
name: indicatorPath,
});
const indicator = JSON.parse(
buffer.toString('utf-8')
) as ArtifactIndicator;
const artifact = await this.getWorkspaceArtifact(
storageService,
workspaceId,
indicatorPath,
indicator
);
this.logger.debug('Succeed to download latest artifacts of workspaces');
Expand All @@ -108,11 +114,13 @@ export class CannerPersistenceStore extends PersistentStore {

private async getWorkspaceArtifact(
storageService: BaseStorageService,
workspaceId: string,
indicatorPath: string,
indicator: ArtifactIndicator
): Promise<BuiltInArtifact> {
const latestArtifactFolder = indicator[indicator.master];
const path = `${workspaceId}/vulcansql/${latestArtifactFolder}/result.json`;
const vulcanFolderPath = indicatorPath.replace('/indicator.json', '');
const path = `${vulcanFolderPath}/${latestArtifactFolder}/result.json`;
this.logger.debug(`Download the artifact from path: ${path}`);
// download from artifact path name
const buffer = await storageService.downObjectAsBuffer({
name: path,
Expand Down Expand Up @@ -150,11 +158,21 @@ export class CannerPersistenceStore extends PersistentStore {
if (artifact.specs['oas3']['paths'])
Object.entries(artifact.specs['oas3']['paths']).forEach(
([apiEndpoint, endpointInfo]) => {
// concat the workspace sql name prefix to original api endpoint
// ths api endpoint has the "/" prefix, so concat directly
// concat the workspace sql name prefix to original api endpoint, the "apiEndpoint" has the "/" prefix, so concat directly
const endpoint = `${workspaceSqlName}${apiEndpoint}`;
merged.specs['oas3']['paths'][endpoint] =
endpointInfo as oas3.PathItemObject;
// Add workspace sql name prefix to original operationId & summary
const { summary, operationId } = merged.specs['oas3']['paths'][
endpoint
]['get'] as oas3.OperationObject;
merged.specs['oas3']['paths'][endpoint]['get'] = {
...merged.specs['oas3']['paths'][endpoint]['get'],
// e.g: get/xxx => get/{workspaceSqlName}/xxx
operationId: `get/${workspaceSqlName}/${operationId?.slice(4)}`,
// e.g: /xxx => /{workspaceSqlName}/xxx
summary: `/${workspaceSqlName}${summary}`,
};
}
);
return merged;
Expand Down
14 changes: 8 additions & 6 deletions packages/extension-store-canner/src/lib/canner/profileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import {
Profile,
ProfileReader,
VulcanExtensionId,
VulcanInternalExtension,
ConfigurationError
ConfigurationError,
} from '@vulcan-sql/core';
import { CannerStoreConfig, getEnvConfig } from '../config';
import { createStorageService } from '../storageService';
Expand All @@ -19,7 +18,6 @@ export interface CannerProfileReaderOptions {
* Used the string to identify the extension Id not by the enum "LocalFileProfileReader".
* Because if we create another enum to extend the 'LocalFileProfileReader', it seems unnecessary to give the new enum only has 'Canner' as its type."
* */
@VulcanInternalExtension()
@VulcanExtensionId('Canner')
export class CannerProfileReader extends ProfileReader {
private envConfig: CannerStoreConfig = getEnvConfig();
Expand All @@ -38,7 +36,11 @@ export class CannerProfileReader extends ProfileReader {
});
// get the indicator files path of each workspaces
const files = await getIndicatorFilesOfWorkspaces(filesInfo);
this.logger.debug('Succeed to get the indicator files of each workspaces');
this.logger.debug(
`Succeed to get the indicator files of each workspaces: ${JSON.stringify(
files
)}`
);

// generate profiles from the indicator files of each workspaces
const { user, password, host, port } = this.envConfig.profile;
Expand All @@ -54,7 +56,7 @@ export class CannerProfileReader extends ProfileReader {
) as ArtifactIndicator;
const workspaceSqlName = indicator[workspaceId];
const profile = {
name: `profile-${workspaceSqlName}`,
name: `canner-${workspaceSqlName}`,
type: 'canner',
connection: {
user,
Expand All @@ -65,7 +67,7 @@ export class CannerProfileReader extends ProfileReader {
},
allow: '*',
} as Profile<Record<string, any>>;
this.logger.debug(`created ${profile.name}.`);
this.logger.debug(`created "${profile.name}".`);
return profile;
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '../lib/canner/persistenceStore';

describe('Test CannerPersistenceStore', () => {
const fakePath = 'fake-path';
// fake workspaceId
const fakeWorkspaces = {
// fake workspace id and sql name
Expand Down Expand Up @@ -41,21 +42,25 @@ describe('Test CannerPersistenceStore', () => {
};
const fakeStorageListedObjectsInfo = {
ws1: {
indicator: { name: `${fakeWorkspaces.ws1.id}/vulcansql/indicator.json` },
indicator: {
name: `${fakePath}/${fakeWorkspaces.ws1.id}/vulcansql/indicator.json`,
},
artifact: {
name: `${fakeWorkspaces.ws1.id}/vulcansql/${fakeWorkspaces.ws1.folders[1]}/result.json`,
name: `${fakePath}/${fakeWorkspaces.ws1.id}/vulcansql/${fakeWorkspaces.ws1.folders[1]}/result.json`,
},
others: [
{ name: `${fakeWorkspaces.ws1.id}/notebook` },
{ name: `${fakeWorkspaces.ws1.id}/notebook_output` },
{ name: `${fakePath}/${fakeWorkspaces.ws1.id}/notebook` },
{ name: `${fakePath}/${fakeWorkspaces.ws1.id}/notebook_output` },
],
},
ws2: {
indicator: { name: `${fakeWorkspaces.ws2.id}/vulcansql/indicator.json` },
indicator: {
name: `${fakePath}/${fakeWorkspaces.ws2.id}/vulcansql/indicator.json`,
},
artifact: {
name: `${fakeWorkspaces.ws2.id}/vulcansql/${fakeWorkspaces.ws2.folders[1]}/result.json`,
name: `${fakePath}/${fakeWorkspaces.ws2.id}/vulcansql/${fakeWorkspaces.ws2.folders[1]}/result.json`,
},
others: [{ name: `${fakeWorkspaces.ws2.id}/data` }],
others: [{ name: `${fakePath}/${fakeWorkspaces.ws2.id}/data` }],
},
};

Expand Down Expand Up @@ -128,8 +133,14 @@ describe('Test CannerPersistenceStore', () => {
.stub(storageServiceModule, 'createStorageService')
.resolves(stubStorageService);

const stubOption = sinon.stubInterface<ArtifactBuilderOptions>();
const store = new CannerPersistenceStore(stubOption, {}, 'Canner');
const store = new CannerPersistenceStore(
{
...sinon.stubInterface<ArtifactBuilderOptions>(),
filePath: fakePath,
},
{},
'Canner'
);

// Act, Assert
await expect(store.load()).rejects.toThrowError(
Expand All @@ -139,7 +150,6 @@ describe('Test CannerPersistenceStore', () => {

it('Should load successfully when "specs" field is "oas3" format ', async () => {
// Arrange

// test artifacts from each workspaces downloaded from storage
const artifacts = {
ws1: {
Expand All @@ -156,7 +166,12 @@ describe('Test CannerPersistenceStore', () => {
oas3: {
...sinon.stubInterface<oas3.OpenAPIObject>(),
paths: {
'/orders': {},
'/orders': {
get: {
operationId: 'get/orders',
summary: '/orders',
},
},
},
},
},
Expand All @@ -175,7 +190,12 @@ describe('Test CannerPersistenceStore', () => {
oas3: {
...sinon.stubInterface<oas3.OpenAPIObject>(),
paths: {
'/products/:id': {},
'/products/:id': {
get: {
operationId: 'get/products/:id',
summary: '/products/:id',
},
},
},
},
},
Expand Down Expand Up @@ -209,10 +229,19 @@ describe('Test CannerPersistenceStore', () => {
description: 'Data API for Canner Enterprise',
},
paths: {
[`${fakeWorkspaces.ws1.sqlName}/orders`]:
artifacts['ws1'].specs['oas3'].paths['/orders'],
[`${fakeWorkspaces.ws2.sqlName}/products/:id`]:
artifacts['ws2'].specs['oas3'].paths['/products/:id'],
[`${fakeWorkspaces.ws1.sqlName}/orders`]: {
get: {
operationId: `get/${fakeWorkspaces.ws1.sqlName}/orders`,
summary: `/${fakeWorkspaces.ws1.sqlName}/orders`,
},
},

[`${fakeWorkspaces.ws2.sqlName}/products/:id`]: {
get: {
operationId: `get/${fakeWorkspaces.ws2.sqlName}/products/:id`,
summary: `/${fakeWorkspaces.ws2.sqlName}/products/:id`,
},
},
},
},
},
Expand Down Expand Up @@ -251,8 +280,14 @@ describe('Test CannerPersistenceStore', () => {
.stub(storageServiceModule, 'createStorageService')
.resolves(stubStorageService);

const stubOption = sinon.stubInterface<ArtifactBuilderOptions>();
const store = new CannerPersistenceStore(stubOption, {}, 'Canner');
const store = new CannerPersistenceStore(
{
...sinon.stubInterface<ArtifactBuilderOptions>(),
filePath: fakePath,
},
{},
'Canner'
);

const mergedArtifact = JSON.parse((await store.load()).toString('utf-8'));
// Act, Assert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe('Test CannerProfileReader', () => {
};
const expected = [
{
name: `profile-${fakeWorkspaces.ws1.sqlName}`,
name: `canner-${fakeWorkspaces.ws1.sqlName}`,
type: 'canner',
connection: {
...connectionInfo,
Expand All @@ -131,7 +131,7 @@ describe('Test CannerProfileReader', () => {
allow: '*',
},
{
name: `profile-${fakeWorkspaces.ws2.sqlName}`,
name: `canner-${fakeWorkspaces.ws2.sqlName}`,
type: 'canner',
connection: {
...connectionInfo,
Expand Down
1 change: 1 addition & 0 deletions packages/serve/src/lib/evaluator/evaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class Evaluator {
);
continue;
}
logger.debug(`profile: ${profile.name}, allow: ${profile.allow}`);
this.profiles.set(profile.name, this.getConstraints(profile.allow));
}
}
Expand Down