-
Notifications
You must be signed in to change notification settings - Fork 29
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
feat(restConfiguration): Add restConfiguration entity #970
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
import * as catalogIndex from '@kaoto-next/camel-catalog/index.json'; | ||
import { RestConfiguration } from '@kaoto-next/camel-catalog/types'; | ||
import { restConfigurationSchema, restConfigurationStub } from '../../../stubs/rest-configuration'; | ||
import { ICamelProcessorDefinition } from '../../camel-processors-catalog'; | ||
import { EntityType } from '../../camel/entities'; | ||
import { CatalogKind } from '../../catalog-kind'; | ||
import { CamelCatalogService } from './camel-catalog.service'; | ||
import { CamelRestConfigurationVisualEntity } from './camel-rest-configuration-visual-entity'; | ||
|
||
describe('CamelRestConfigurationVisualEntity', () => { | ||
const REST_CONFIGURATION_ID_REGEXP = /^restConfiguration-[a-zA-Z0-9]{4}$/; | ||
let restConfigurationDef: { restConfiguration: RestConfiguration }; | ||
|
||
beforeAll(async () => { | ||
const entityCatalogMap = await import('@kaoto-next/camel-catalog/' + catalogIndex.catalogs.entities.file); | ||
CamelCatalogService.setCatalogKey( | ||
CatalogKind.Entity, | ||
entityCatalogMap as unknown as Record<string, ICamelProcessorDefinition>, | ||
); | ||
}); | ||
|
||
afterAll(() => { | ||
CamelCatalogService.clearCatalogs(); | ||
}); | ||
|
||
beforeEach(() => { | ||
restConfigurationDef = { | ||
restConfiguration: { | ||
...restConfigurationStub.restConfiguration, | ||
}, | ||
}; | ||
}); | ||
|
||
describe('isApplicable', () => { | ||
it.each([ | ||
[true, { restConfiguration: {} }], | ||
[true, { restConfiguration: { bindingMode: 'off' } }], | ||
[true, restConfigurationStub], | ||
[false, { from: { id: 'from-1234', steps: [] } }], | ||
[false, { restConfiguration: { bindingMode: 'off' }, anotherProperty: true }], | ||
])('should return %s for %s', (result, definition) => { | ||
expect(CamelRestConfigurationVisualEntity.isApplicable(definition)).toEqual(result); | ||
}); | ||
}); | ||
|
||
describe('constructor', () => { | ||
it('should set id to generated id', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.id).toMatch(REST_CONFIGURATION_ID_REGEXP); | ||
}); | ||
}); | ||
|
||
it('should return id', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.getId()).toMatch(REST_CONFIGURATION_ID_REGEXP); | ||
}); | ||
|
||
it('should set id', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
const newId = 'newId'; | ||
entity.setId(newId); | ||
|
||
expect(entity.getId()).toEqual(newId); | ||
}); | ||
|
||
it('should return node label', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.getNodeLabel()).toEqual('restConfiguration'); | ||
}); | ||
|
||
it('should return tooltip content', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.getTooltipContent()).toEqual('restConfiguration'); | ||
}); | ||
|
||
describe('getComponentSchema', () => { | ||
it('should return entity current definition', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.getComponentSchema().definition).toEqual(restConfigurationDef.restConfiguration); | ||
}); | ||
|
||
it.skip('should return schema from store', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.getComponentSchema().schema).toEqual(restConfigurationSchema); | ||
}); | ||
|
||
it('should return hardcoded schema title', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.getComponentSchema().title).toEqual('Rest Configuration'); | ||
}); | ||
}); | ||
|
||
describe('updateModel', () => { | ||
it('should update model', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
const path = 'restConfiguration.bindingMode'; | ||
const value = 'json'; | ||
|
||
entity.updateModel(path, value); | ||
|
||
expect(restConfigurationDef.restConfiguration.bindingMode).toEqual(value); | ||
}); | ||
|
||
it('should not update model if path is not defined', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
const value = 'json_xml'; | ||
|
||
entity.updateModel(undefined, value); | ||
|
||
expect(restConfigurationDef.restConfiguration.bindingMode).toEqual('off'); | ||
}); | ||
|
||
it('should reset the restConfiguration object if it is not defined', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
entity.updateModel('restConfiguration', {}); | ||
|
||
expect(restConfigurationDef.restConfiguration).toEqual({}); | ||
}); | ||
}); | ||
|
||
it('return no interactions', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.getNodeInteraction()).toEqual({ | ||
canHavePreviousStep: false, | ||
canHaveNextStep: false, | ||
canHaveChildren: false, | ||
canHaveSpecialChildren: false, | ||
canRemoveStep: false, | ||
canReplaceStep: false, | ||
}); | ||
}); | ||
|
||
/** Skip until https://github.com/KaotoIO/kaoto-next/issues/969 gets resolved */ | ||
describe.skip('getNodeValidationText', () => { | ||
it('should return undefined for valid definitions', () => { | ||
const entity = new CamelRestConfigurationVisualEntity({ | ||
restConfiguration: { | ||
...restConfigurationDef.restConfiguration, | ||
useXForwardHeaders: true, | ||
apiVendorExtension: true, | ||
skipBindingOnErrorCode: true, | ||
clientRequestValidation: true, | ||
enableCORS: true, | ||
enableNoContentResponse: true, | ||
inlineRoutes: true, | ||
}, | ||
}); | ||
|
||
expect(entity.getNodeValidationText()).toBeUndefined(); | ||
}); | ||
|
||
it('should not modify the original definition when validating', () => { | ||
const originalRestConfigurationDef: RestConfiguration = { ...restConfigurationDef.restConfiguration }; | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
entity.getNodeValidationText(); | ||
|
||
expect(restConfigurationDef.restConfiguration).toEqual(originalRestConfigurationDef); | ||
}); | ||
|
||
it('should return errors when there is an invalid property', () => { | ||
const invalidRestConfigurationDef: RestConfiguration = { | ||
...restConfigurationDef.restConfiguration, | ||
bindingMode: 'WildModeOn' as RestConfiguration['bindingMode'], | ||
}; | ||
const entity = new CamelRestConfigurationVisualEntity({ restConfiguration: invalidRestConfigurationDef }); | ||
|
||
expect(entity.getNodeValidationText()).toEqual(`'/useXForwardHeaders' must be boolean, | ||
'/apiVendorExtension' must be boolean, | ||
'/skipBindingOnErrorCode' must be boolean, | ||
'/clientRequestValidation' must be boolean, | ||
'/enableCORS' must be boolean, | ||
'/enableNoContentResponse' must be boolean, | ||
'/inlineRoutes' must be boolean`); | ||
}); | ||
}); | ||
Comment on lines
+142
to
+185
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to reenable this test, once #969 is fixed. |
||
|
||
describe('toVizNode', () => { | ||
it('should return visualization node', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
const vizNode = entity.toVizNode(); | ||
|
||
expect(vizNode.data).toEqual({ | ||
componentName: undefined, | ||
entity: { | ||
id: entity.getId(), | ||
restConfigurationDef, | ||
type: EntityType.RestConfiguration, | ||
}, | ||
icon: '', | ||
isGroup: true, | ||
path: 'restConfiguration', | ||
processorName: 'restConfiguration', | ||
}); | ||
}); | ||
}); | ||
|
||
it('should serialize the restConfiguration definition', () => { | ||
const entity = new CamelRestConfigurationVisualEntity(restConfigurationDef); | ||
|
||
expect(entity.toJSON()).toEqual(restConfigurationDef); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import { ProcessorDefinition, RestConfiguration } from '@kaoto-next/camel-catalog/types'; | ||
import Ajv, { ValidateFunction } from 'ajv-draft-04'; | ||
import addFormats from 'ajv-formats'; | ||
import { getCamelRandomId } from '../../../camel-utils/camel-random-id'; | ||
import { isDefined, setValue } from '../../../utils'; | ||
import { EntityType } from '../../camel/entities/base-entity'; | ||
import { CatalogKind } from '../../catalog-kind'; | ||
import { | ||
BaseVisualCamelEntity, | ||
IVisualizationNode, | ||
IVisualizationNodeData, | ||
NodeInteraction, | ||
VisualComponentSchema, | ||
} from '../base-visual-entity'; | ||
import { CamelCatalogService } from './camel-catalog.service'; | ||
import { CamelStepsService } from './support/camel-steps.service'; | ||
|
||
export class CamelRestConfigurationVisualEntity implements BaseVisualCamelEntity { | ||
id: string; | ||
readonly type = EntityType.RestConfiguration; | ||
private schemaValidator: ValidateFunction<RestConfiguration> | undefined; | ||
|
||
constructor(public restConfigurationDef: { restConfiguration: RestConfiguration }) { | ||
const id = getCamelRandomId('restConfiguration'); | ||
this.id = id; | ||
} | ||
|
||
static isApplicable(restConfigurationDef: unknown): restConfigurationDef is { restConfiguration: RestConfiguration } { | ||
if ( | ||
!isDefined(restConfigurationDef) || | ||
Array.isArray(restConfigurationDef) || | ||
typeof restConfigurationDef !== 'object' | ||
) { | ||
return false; | ||
} | ||
|
||
const objectKeys = Object.keys(restConfigurationDef!); | ||
|
||
return ( | ||
objectKeys.length === 1 && | ||
'restConfiguration' in restConfigurationDef! && | ||
typeof restConfigurationDef.restConfiguration === 'object' | ||
); | ||
} | ||
|
||
getId(): string { | ||
return this.id; | ||
} | ||
|
||
setId(id: string): void { | ||
this.id = id; | ||
} | ||
|
||
getNodeLabel(): string { | ||
return 'restConfiguration'; | ||
} | ||
|
||
getTooltipContent(): string { | ||
return 'restConfiguration'; | ||
} | ||
|
||
addStep(): void { | ||
return; | ||
} | ||
|
||
removeStep(): void { | ||
return; | ||
} | ||
|
||
getComponentSchema(): VisualComponentSchema { | ||
const schema = CamelCatalogService.getComponent(CatalogKind.Entity, 'restConfiguration'); | ||
|
||
return { | ||
definition: Object.assign({}, this.restConfigurationDef.restConfiguration), | ||
schema: schema?.propertiesSchema || {}, | ||
title: 'Rest Configuration', | ||
}; | ||
} | ||
|
||
updateModel(path: string | undefined, value: unknown): void { | ||
if (!path) return; | ||
|
||
setValue(this.restConfigurationDef, path, value); | ||
|
||
if (!isDefined(this.restConfigurationDef.restConfiguration)) { | ||
this.restConfigurationDef.restConfiguration = {}; | ||
} | ||
} | ||
|
||
getNodeInteraction(): NodeInteraction { | ||
return { | ||
canHavePreviousStep: false, | ||
canHaveNextStep: false, | ||
canHaveChildren: false, | ||
canHaveSpecialChildren: false, | ||
canRemoveStep: false, | ||
canReplaceStep: false, | ||
}; | ||
} | ||
|
||
getNodeValidationText(): string | undefined { | ||
const componentVisualSchema = this.getComponentSchema(); | ||
if (!componentVisualSchema) return undefined; | ||
|
||
if (!this.schemaValidator) { | ||
this.schemaValidator = this.getValidatorFunction(componentVisualSchema); | ||
} | ||
|
||
this.schemaValidator?.({ ...this.restConfigurationDef.restConfiguration }); | ||
|
||
return this.schemaValidator?.errors?.map((error) => `'${error.instancePath}' ${error.message}`).join(',\n'); | ||
} | ||
|
||
toVizNode(): IVisualizationNode<IVisualizationNodeData> { | ||
const restConfigurationGroupNode = CamelStepsService.getVizNodeFromProcessor( | ||
'restConfiguration', | ||
{ processorName: 'restConfiguration' as keyof ProcessorDefinition }, | ||
this.restConfigurationDef, | ||
); | ||
restConfigurationGroupNode.data.entity = this; | ||
restConfigurationGroupNode.data.isGroup = true; | ||
|
||
return restConfigurationGroupNode; | ||
} | ||
|
||
toJSON(): unknown { | ||
return this.restConfigurationDef; | ||
} | ||
|
||
private getValidatorFunction( | ||
componentVisualSchema: VisualComponentSchema, | ||
): ValidateFunction<RestConfiguration> | undefined { | ||
const ajv = new Ajv({ | ||
strict: false, | ||
allErrors: true, | ||
useDefaults: 'empty', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @igarashitm , I think you already saw this, but in any case, this |
||
}); | ||
addFormats(ajv); | ||
|
||
let schemaValidator: ValidateFunction<RestConfiguration> | undefined; | ||
try { | ||
schemaValidator = ajv.compile<RestConfiguration>(componentVisualSchema.schema); | ||
} catch (error) { | ||
console.error('Could not compile schema', error); | ||
} | ||
|
||
return schemaValidator; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to reenable this test, once #969 is fixed.