|
16 | 16 | // under the License. |
17 | 17 | package org.apache.cloudstack.tosca.parser; |
18 | 18 |
|
19 | | -import bsh.StringUtil; |
20 | 19 | import com.cloud.exception.InvalidParameterValueException; |
21 | 20 | import org.apache.cloudstack.tosca.functions.ToscaBooleanFunctions; |
22 | 21 | import org.apache.cloudstack.tosca.functions.ToscaFunction; |
23 | 22 | import org.apache.cloudstack.tosca.model.ToscaAttributeDefinition; |
| 23 | +import org.apache.cloudstack.tosca.model.ToscaCollectionType; |
24 | 24 | import org.apache.cloudstack.tosca.model.ToscaDataTypeDefinition; |
25 | 25 | import org.apache.cloudstack.tosca.model.ToscaInputDefinition; |
26 | 26 | import org.apache.cloudstack.tosca.model.ToscaNodeTemplate; |
@@ -71,16 +71,18 @@ private ToscaNodeType getVmNodeTypeForTests() { |
71 | 71 | ToscaPropertyDefinition sshKeyPairName = new ToscaPropertyDefinition("ssh-key-pair-name", "SSH key pair name.", ToscaTypeDefinition.ofPrimitive(ToscaPrimitiveType.STRING), false, null); |
72 | 72 |
|
73 | 73 | ToscaPropertyDefinition nameDataTypeProperty = new ToscaPropertyDefinition("name", "Name.", ToscaTypeDefinition.ofPrimitive(ToscaPrimitiveType.STRING), true, null); |
74 | | - ToscaPropertyDefinition valueDataTypeProperty = new ToscaPropertyDefinition("value", "Value.", ToscaTypeDefinition.ofPrimitive(ToscaPrimitiveType.STRING), true, null); |
75 | | - ToscaDataTypeDefinition detailsDataTypeDefinition = new ToscaDataTypeDefinition("NameValueMapping", Map.of(nameDataTypeProperty.getName(), nameDataTypeProperty, valueDataTypeProperty.getName(), valueDataTypeProperty)); |
76 | | - ToscaPropertyDefinition details = new ToscaPropertyDefinition("offering-details", "Offering details.", ToscaTypeDefinition.ofDataType(detailsDataTypeDefinition), false, null); |
| 74 | + ToscaPropertyDefinition valueDataTypeProperty = new ToscaPropertyDefinition("value", "Value.", ToscaTypeDefinition.ofPrimitive(ToscaPrimitiveType.STRING), false, null); |
| 75 | + ToscaDataTypeDefinition nameValueMappingDataType = new ToscaDataTypeDefinition("NameValueMapping", Map.of(nameDataTypeProperty.getName(), nameDataTypeProperty, valueDataTypeProperty.getName(), valueDataTypeProperty)); |
| 76 | + ToscaPropertyDefinition nameValueMappingList = new ToscaPropertyDefinition("name-value-mapping", "Name value mapping.", ToscaTypeDefinition.ofCollection(ToscaCollectionType.LIST, ToscaTypeDefinition.ofDataType(nameValueMappingDataType)), false, null); |
77 | 77 |
|
| 78 | + ToscaPropertyDefinition ipAddresses = new ToscaPropertyDefinition("ip-addresses", "IPs.", ToscaTypeDefinition.ofCollection(ToscaCollectionType.LIST, ToscaTypeDefinition.ofPrimitive(ToscaPrimitiveType.STRING)), false, null); |
| 79 | + ToscaPropertyDefinition details = new ToscaPropertyDefinition("offering-details", "Offering details.", ToscaTypeDefinition.ofCollection(ToscaCollectionType.MAP, ToscaTypeDefinition.ofPrimitive(ToscaPrimitiveType.STRING)), false, null); |
78 | 80 | ToscaAttributeDefinition uuid = new ToscaAttributeDefinition("uuid", "UUID of the system VM.", ToscaTypeDefinition.ofPrimitive(ToscaPrimitiveType.STRING)); |
79 | 81 |
|
80 | 82 | return new ToscaNodeType("Vm", |
81 | 83 | Map.of(type.getName(), type, vcpus.getName(), vcpus, startVm.getName(), startVm, |
82 | 84 | maxUsage.getName(), maxUsage, sshKeyPairId.getName(), sshKeyPairId, sshKeyPairName.getName(), sshKeyPairName, |
83 | | - details.getName(), details), |
| 85 | + nameValueMappingList.getName(), nameValueMappingList, ipAddresses.getName(), ipAddresses, details.getName(), details), |
84 | 86 | Map.of(uuid.getName(), uuid)); |
85 | 87 | } |
86 | 88 |
|
@@ -247,23 +249,6 @@ public void parseNodeTemplatesTestHandleMissingRequiredKeys() { |
247 | 249 | Mockito.verify(parsingContextMock, Mockito.times(1)).addErrors(Mockito.anyList(), Mockito.anyString()); |
248 | 250 | } |
249 | 251 |
|
250 | | -// |
251 | | -// instance: |
252 | | -// type: Vm |
253 | | -// properties: |
254 | | -// type: SSVM |
255 | | -// vcpus: 2 |
256 | | -// start-vm: false |
257 | | -// max-usage: 10.572 |
258 | | -// ssh-key-pair-id: { $get_attribute: [pair, uuid] } |
259 | | -// ssh-key-pair-name: { $get_property: [pair, name] } |
260 | | -// pair: |
261 | | -// type: SshPair |
262 | | -// properties: |
263 | | -// name: Pair |
264 | | -// public-key: { $get_input: key } |
265 | | - |
266 | | - |
267 | 252 | @Test |
268 | 253 | public void parseNodeTemplatesTestEnsureAllPropertyTypesAreParsedCorrectly() { |
269 | 254 | String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, start-vm: false, max-usage: 10.572, ssh-key-pair-id: {$get_attribute: [pair, uuid]}, ssh-key-pair-name: {$get_property: [pair, name]}}}, pair: {type: SshPair, properties: {name: Pair, public-key: {$get_input: public-key}}}}"; |
@@ -358,22 +343,113 @@ public void parseNodeTemplatesTestHandleHandleIncorrectGetAttributeAndGetPropert |
358 | 343 | Mockito.verify(parsingContextMock, Mockito.never()).addUnresolvedByGetAttribute(Mockito.any(), Mockito.any()); |
359 | 344 | } |
360 | 345 |
|
361 | | -// instance: |
362 | | -// type: Vm |
363 | | -// properties: |
364 | | -// type: SSVM |
365 | | -// vcpus: 2 |
366 | | -// start-vm: false |
367 | | -// max-usage: 10.572 |
368 | | -// ssh-key-pair-id: { $get_attribute: [pair, uuid] } |
369 | | -// ssh-key-pair-name: { $get_property: [pair, name] } |
370 | | -// requirements: |
371 | | -// - dependency: pair |
372 | | -// pair: |
373 | | -// type: SshPair |
374 | | -// properties: |
375 | | -// name: Pair |
376 | | -// public-key: { $get_input: key } |
| 346 | + @Test |
| 347 | + public void parseNodeTemplatesTestEnsureCollectionTypesAreParsedCorrectly() { |
| 348 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, offering-details: {memory: '1024', speed: '1000'}, ip-addresses: [10.0.0.2, 172.16.30.2]}}}"; |
| 349 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 350 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 351 | + |
| 352 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 353 | + Mockito.verify(parsingContextMock, Mockito.never()).addError(Mockito.anyString(), Mockito.anyString()); |
| 354 | + Mockito.verify(parsingContextMock, Mockito.never()).addErrors(Mockito.anyList(), Mockito.anyString()); |
| 355 | + |
| 356 | + Map<String, Object> details = ToscaYamlHelper.asMap(nodeTemplates.get("instance").getProperty("offering-details").getRawValue()); |
| 357 | + Assert.assertEquals(2, details.size()); |
| 358 | + Assert.assertTrue(details.containsKey("memory")); |
| 359 | + Assert.assertTrue(details.containsKey("speed")); |
| 360 | + |
| 361 | + List<?> ipAddresses = ToscaYamlHelper.asList(nodeTemplates.get("instance").getProperty("ip-addresses").getRawValue()); |
| 362 | + Assert.assertEquals(2, ipAddresses.size()); |
| 363 | + Assert.assertTrue(ipAddresses.contains("10.0.0.2")); |
| 364 | + Assert.assertTrue(ipAddresses.contains("172.16.30.2")); |
| 365 | + } |
| 366 | + |
| 367 | + @Test |
| 368 | + public void parseNodeTemplatesTestHandleIncorrectCollectionTypesValues() { |
| 369 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, offering-details: [10.0.0.2, 172.16.30.2], ip-addresses: {memory: '1024', speed: '1000'}}}}"; |
| 370 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 371 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 372 | + |
| 373 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 374 | + Mockito.verify(parsingContextMock, Mockito.times(2)).addError(Mockito.anyString(), Mockito.anyString()); |
| 375 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("offering-details")); |
| 376 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("ip-addresses")); |
| 377 | + } |
| 378 | + |
| 379 | + @Test |
| 380 | + public void parseNodeTemplatesTestHandleIncorrectEntrySchemaValues() { |
| 381 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, offering-details: {memory: 1024, speed: false}, ip-addresses: [{name: name, value: value}]}}}"; |
| 382 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 383 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 384 | + |
| 385 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 386 | + Mockito.verify(parsingContextMock, Mockito.times(2)).addError(Mockito.anyString(), Mockito.anyString()); |
| 387 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("offering-details")); |
| 388 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("ip-addresses")); |
| 389 | + } |
| 390 | + |
| 391 | + @Test |
| 392 | + public void parseNodeTemplatesTestEnsureDataTypesAreParsedCorrectly() { |
| 393 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, name-value-mapping: [{name: name1, value: value1}, {name: name2}]}}}"; |
| 394 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 395 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 396 | + |
| 397 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 398 | + Mockito.verify(parsingContextMock, Mockito.times(0)).addError(Mockito.anyString(), Mockito.anyString()); |
| 399 | + List<?> nameValues = ToscaYamlHelper.asList(nodeTemplates.get("instance").getProperty("name-value-mapping").getRawValue()); |
| 400 | + Map<String, Object> firstNameValue = ToscaYamlHelper.asMap(nameValues.get(0)); |
| 401 | + Map<String, Object> secondNameValue = ToscaYamlHelper.asMap(nameValues.get(1)); |
| 402 | + Assert.assertEquals(2, nameValues.size()); |
| 403 | + Assert.assertEquals(2, firstNameValue.size()); |
| 404 | + Assert.assertTrue(firstNameValue.containsKey("name")); |
| 405 | + Assert.assertTrue(firstNameValue.containsKey("value")); |
| 406 | + Assert.assertEquals(1, secondNameValue.size()); |
| 407 | + Assert.assertTrue(secondNameValue.containsKey("name")); |
| 408 | + } |
| 409 | + |
| 410 | + @Test |
| 411 | + public void parseNodeTemplatesTestHandleUnknownKeyInDataType() { |
| 412 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, name-value-mapping: [{name: name1, unknown-key: value1}]}}}"; |
| 413 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 414 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 415 | + |
| 416 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 417 | + Mockito.verify(parsingContextMock, Mockito.times(1)).addError(Mockito.anyString(), Mockito.anyString()); |
| 418 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("name-value-mapping")); |
| 419 | + } |
| 420 | + |
| 421 | + @Test |
| 422 | + public void parseNodeTemplatesTestHandleMissingRequiredKeyInDataType() { |
| 423 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, name-value-mapping: [{value: value2}]}}}"; |
| 424 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 425 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 426 | + |
| 427 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 428 | + Mockito.verify(parsingContextMock, Mockito.times(1)).addError(Mockito.anyString(), Mockito.anyString()); |
| 429 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("name-value-mapping")); |
| 430 | + } |
| 431 | + |
| 432 | + @Test |
| 433 | + public void parseNodeTemplatesTestHandleMismatchingPropertyTypesInDataType() { |
| 434 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, name-value-mapping: [{name: 100, value: false}]}}}"; |
| 435 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 436 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 437 | + |
| 438 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 439 | + Mockito.verify(parsingContextMock, Mockito.times(1)).addError(Mockito.anyString(), Mockito.anyString()); |
| 440 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("name-value-mapping")); |
| 441 | + } |
| 442 | + |
| 443 | + @Test |
| 444 | + public void parseNodeTemplatesTestHandleMismatchingTypesInDataType() { |
| 445 | + String serviceTemplateYaml = "{instance: {type: Vm, properties: {type: SSVM, vcpus: 2, name-value-mapping: [[firstitem]]}}}"; |
| 446 | + Map<String, Object> serviceTemplate = ToscaYamlHelper.asMap(ToscaYamlHelper.loadYaml(serviceTemplateYaml)); |
| 447 | + Mockito.when(parsingContextMock.getProfile()).thenReturn(getToscaProfileForTests()); |
| 448 | + |
| 449 | + Map<String, ToscaNodeTemplate> nodeTemplates = toscaServiceTemplateParserSpy.parseNodeTemplates(serviceTemplate, parsingContextMock); |
| 450 | + Mockito.verify(parsingContextMock, Mockito.times(1)).addError(Mockito.anyString(), Mockito.anyString()); |
| 451 | + Assert.assertNull(nodeTemplates.get("instance").getProperty("name-value-mapping")); |
| 452 | + } |
377 | 453 |
|
378 | 454 | @Test |
379 | 455 | public void parseNodeTemplatesTestEnsureRequirementsDependenciesAreAddedToTheParsingContext() { |
|
0 commit comments