UNPKG

@stordata/vsphere-soapify

Version:

A NodeJS abstraction layer for the vSphere SOAP API

763 lines (634 loc) 21.5 kB
'use strict'; const { expect } = require('chai'), Parser = require('./parser'), Client = require('./client'), sdk = require('./sdk'); describe('The Parser class', function() { let parser, client; beforeEach(function() { client = new Client('https://url/sdk'); parser = new Parser(client); }); describe('The parse method', function() { describe('xsd:string', function() { it('should default to parsing a string', function() { expect(parser.parse('abcd')).to.equal('abcd'); }); it('should parse a string', function() { expect(parser.parse('abcd', 'xsd:string')).to.equal('abcd'); }); it('should parse undefined as undefined', function() { expect(parser.parse(undefined, 'xsd:string')).to.equal(undefined); }); }); describe('xsd:boolean', function() { it('should parse "true" as true for "xsd:boolean" type', function() { expect(parser.parse('true', 'xsd:boolean')).to.equal(true); }); it('should parse true as true for "xsd:boolean" type', function() { expect(parser.parse(true, 'xsd:boolean')).to.equal(true); }); it('should parse false as false for "xsd:boolean" type', function() { expect(parser.parse(false, 'xsd:boolean')).to.equal(false); }); it('should parse "false" as false for "xsd:boolean" type', function() { expect(parser.parse('false', 'xsd:boolean')).to.equal(false); }); it('should parse a random string as true for "xsd:boolean" type', function() { expect(parser.parse('notABoolean', 'xsd:boolean')).to.equal(false); }); it('should parse "" as false for "xsd:boolean" type', function() { expect(parser.parse('', 'xsd:boolean')).to.equal(false); }); it('should parse undefined as an undefined', function() { expect(parser.parse(undefined, 'xsd:boolean')).to.equal(undefined); }); }); describe('xsd:byte, xsd:short, xsd:int, xsd:long', function() { ['byte', 'short', 'int', 'long'].forEach((type) => { ['123', '-45', '67.89'].forEach((value) => { it(`should parse "${value}" as ${value} for "xsd:${type}" type`, function() { expect(parser.parse(value, `xsd:${type}`)).to.equal(Number(value)); }); it(`should parse ${value} as ${value} for "xsd:${type}" type`, function() { expect(parser.parse(Number(value), `xsd:${type}`)).to.equal(Number(value)); }); }); it(`should parse an invalid number as NaN for "xsd:${type}" type`, function() { expect(parser.parse('notANumber', `xsd:${type}`)).to.deep.equal(NaN); }); it('should parse undefined as undefined', function() { expect(parser.parse(undefined, `xsd:${type}`)).to.equal(undefined); }); }); }); describe('xsd:dateTime', function() { it('should parse a valid XML date and time as a Date for "xsd:dateTime" type', function() { expect(parser.parse('2019-01-01T12:34:45.678Z', 'xsd:dateTime')).to.equalTime(new Date(2019, 0, 1, 12, 34, 45, 678)); }); it('should parse a Date as a Date for "xsd:dateTime" type', function() { expect(parser.parse(new Date(2019, 0, 1, 12, 34, 45, 678), 'xsd:dateTime')).to.equalTime(new Date(2019, 0, 1, 12, 34, 45, 678)); }); it('should parse a valid XML date as a Date for "xsd:dateTime" type', function() { expect(parser.parse('2019-01-01', 'xsd:dateTime')).to.equalTime(new Date(2019, 0, 1)); }); it('should parse undefined as undefined', function() { expect(parser.parse(undefined, 'xsd:dateTime')).to.equal(undefined); }); }); describe('ArrayOfString', function() { it('should parse an array of strings', function() { expect(parser.parse({ string: ['str1', 'str2'] }, 'ArrayOfString')).to.deep.equal(['str1', 'str2']); }); it('should parse a JS array too', function() { expect(parser.parse(['str1', 'str2'], 'ArrayOfString')).to.deep.equal(['str1', 'str2']); }); }); describe('ArrayOfBoolean', function() { it('should parse an array of booleans', function() { expect(parser.parse({ boolean: ['true', 'false'] }, 'ArrayOfBoolean')).to.deep.equal([true, false]); }); it('should parse a JS array too', function() { expect(parser.parse(['true', 'false'], 'ArrayOfBoolean')).to.deep.equal([true, false]); }); }); ['Short', 'Int', 'Long'].forEach((type) => { describe(`ArrayOf${type}`, function() { it(`should parse an array of ${type} values`, function() { expect(parser.parse({ [type.toLowerCase()]: ['123', '12.34', '-42'] }, `ArrayOf${type}`)).to.deep.equal([123, 12.34, -42]); }); }); }); describe('ArrayOfKeyAnyValue', function() { it('should parse an array of KeyAnyValue to an object, parsing values according to their type', function() { expect(parser.parse([{ key: 'a', value: { attributes: { 'xsi:type': 'xsd:int' }, $value: '1' } }, { key: 'b', value: { attributes: { 'xsi:type': 'xsd:string' }, $value: 'str1' } }, { key: 'c', value: { attributes: { 'xsi:type': 'xsd:boolean' }, $value: 'true' } }], 'ArrayOfKeyAnyValue')).to.deep.equal({ a: 1, b: 'str1', c: true }); }); it('should parse a raw XML object too', function() { expect(parser.parse({ attributes: { 'xsi:type': 'ArrayOfKeyAnyValue' }, KeyAnyValue: [{ key: 'a', value: { attributes: { 'xsi:type': 'xsd:int' }, $value: '1' } }, { key: 'b', value: { attributes: { 'xsi:type': 'xsd:string' }, $value: 'str1' } }, { key: 'c', value: { attributes: { 'xsi:type': 'xsd:boolean' }, $value: 'true' } }] }, 'ArrayOfKeyAnyValue')).to.deep.equal({ a: 1, b: 'str1', c: true }); }); }); describe('ArrayOfOptionValue', function() { it('should parse an array of OptionValue to an object, parsing values according to their type', function() { expect(parser.parse([{ key: 'a', value: { attributes: { 'xsi:type': 'xsd:int' }, $value: '1' } }, { key: 'b', value: { attributes: { 'xsi:type': 'xsd:string' }, $value: 'str1' } }, { key: 'c', value: { attributes: { 'xsi:type': 'xsd:boolean' }, $value: 'true' } }], 'ArrayOfOptionValue')).to.deep.equal({ a: 1, b: 'str1', c: true }); }); it('should parse a raw XML object too', function() { expect(parser.parse({ attributes: { 'xsi:type': 'ArrayOfOptionValue' }, OptionValue: [{ key: 'a', value: { attributes: { 'xsi:type': 'xsd:int' }, $value: '1' } }, { key: 'b', value: { attributes: { 'xsi:type': 'xsd:string' }, $value: 'str1' } }, { key: 'c', value: { attributes: { 'xsi:type': 'xsd:boolean' }, $value: 'true' } }] }, 'ArrayOfOptionValue')).to.deep.equal({ a: 1, b: 'str1', c: true }); }); }); describe('ArrayOfObjectContent', function() { it('should parse an array of managed objets', function() { const parsed = parser.parse([{ obj: { attributes: { type: 'HostSystem' }, $value: 'myId' }, propSet: [{ name: 'name', val: { attributes: { 'xsi:type': 'xsd:string' }, $value: 'myName' } }] }], 'ArrayOfObjectContent'); expect(parsed).to.have.length(1); expect(parsed[0]).to.be.a.instanceOf(sdk.managed.HostSystem); expect(parsed[0]).to.deep.equal({ name: 'myName', ref: 'myId' }); }); }); describe('ManagedObjectReference', function() { it('should parse a managed objet', function() { const parsed = parser.parse({ attributes: { type: 'HostSystem' }, $value: 'myId' }, 'ManagedObjectReference'); expect(parsed).to.be.a.instanceOf(sdk.managed.HostSystem); expect(parsed).to.deep.equal({ ref: 'myId' }); }); it('should parse a ManagedEntity when object is unknown', function() { const parsed = parser.parse({ attributes: { type: 'UnknownCustomManagedObject' }, $value: 'myId' }, 'ManagedObjectReference'); expect(parsed.constructor.name).to.equal(sdk.managed.ManagedEntity.name); expect(parsed).to.deep.equal({ ref: 'myId' }); }); it('should parse a ManagedEntity when no type is defined', function() { const parsed = parser.parse({ $value: 'myId' }, 'ManagedObjectReference'); expect(parsed.constructor.name).to.equal(sdk.managed.ManagedEntity.name); expect(parsed).to.deep.equal({ ref: 'myId' }); }); }); describe('ArrayOfManagedObjectReference', function() { it('should parse an array of ManagedObjectReference', function() { const parsed = parser.parse({ 'xsi:type': 'ArrayOfManagedObjectReference', ManagedObjectReference: [{ attributes: { type: 'HostSystem' }, $value: 'myId' }, { attributes: { type: 'Datastore' }, $value: 'myId_2' }] }, 'ArrayOfManagedObjectReference'); expect(parsed).to.have.length(2); expect(parsed[0]).to.be.a.instanceOf(sdk.managed.HostSystem); expect(parsed[0]).to.deep.equal({ ref: 'myId' }); expect(parsed[1]).to.be.a.instanceOf(sdk.managed.Datastore); expect(parsed[1]).to.deep.equal({ ref: 'myId_2' }); }); it('should support an empty array', function() { const parsed = parser.parse({ 'xsi:type': 'ArrayOfManagedObjectReference', ManagedObjectReference: [] }, 'ArrayOfManagedObjectReference'); expect(parsed).to.have.length(0); }); it('should support a single object (i.e.: not an array)', function() { const parsed = parser.parse({ attributes: { 'xsi:type': 'ArrayOfManagedObjectReference' }, ManagedObjectReference: { attributes: { type: 'Datastore' }, $value: '/tmp/govcsim-DC0-LocalDS_0-813051446@folder-5' } }, 'ArrayOfManagedObjectReference'); expect(parsed).to.deep.equal([{ ref: '/tmp/govcsim-DC0-LocalDS_0-813051446@folder-5' }]); }); }); it('should return an empty array when ArrayOf value does not contain the values', function() { expect(parser.parse({}, 'ArrayOfUnknownCustomType')).to.deep.equal([]); }); it('should return undefined when ArrayOf value is undefined', function() { expect(parser.parse(undefined, 'ArrayOfUnknownCustomType')).to.deep.equal(undefined); }); describe('ComplexType', function() { it('should return a complex type instance', function() { const parsed = parser.parse({ key: 'myAlarm1', acknowledged: true }, 'AlarmState'); expect(parsed).to.be.an.instanceof(sdk.data.AlarmState); expect(parsed).to.deep.equal({ acknowledged: true, key: 'myAlarm1' }); }); it('should support passing the actual type directly', function() { const parsed = parser.parse({ key: 'myAlarm1', acknowledged: true }, sdk.data.AlarmState); expect(parsed).to.be.an.instanceof(sdk.data.AlarmState); expect(parsed).to.deep.equal({ acknowledged: true, key: 'myAlarm1' }); }); }); describe('ArrayOfComplexType', function() { it('should return an array of complex type instances', function() { expect(parser.parse([{ key: 'myAlarm1', acknowledged: true }, { key: 'myAlarm2', acknowledged: true }], 'ArrayOfAlarmState')).to.deep.equal([ { acknowledged: true, key: 'myAlarm1' }, { acknowledged: true, key: 'myAlarm2' } ]); }); }); describe('With raw XML objects', function() { describe('xsd:string', function() { it('should parse a xsd:string object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'xsd:string' }, $value: '1' })).to.equal('1'); }); it('should parse a xsd:string object when string is empty', function() { expect(parser.parse({ attributes: { 'xsi:type': 'xsd:string' }, $value: '' })).to.equal(''); }); }); it('should parse a xsd:boolean object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'xsd:boolean' }, $value: 'true' })).to.equal(true); }); it('should parse a xsd:short object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'xsd:short' }, $value: '1' })).to.equal(1); }); it('should parse a xsd:int object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'xsd:int' }, $value: '1.23' })).to.equal(1.23); }); it('should parse a xsd:long object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'xsd:long' }, $value: '-1' })).to.equal(-1); }); it('should parse a xsd:dateTime object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'xsd:dateTime' }, $value: '2019-01-01T12:34:45.678Z' })).to.equalTime(new Date(2019, 0, 1, 12, 34, 45, 678)); }); it('should parse a ArrayOfString object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'ArrayOfString' }, string: ['str1', 'str2'] })).to.deep.equal(['str1', 'str2']); }); it('should parse a ArrayOfBoolean object', function() { expect(parser.parse({ attributes: { 'xsi:type': 'ArrayOfBoolean' }, boolean: ['true', 'false'] })).to.deep.equal([true, false]); }); ['Short', 'Int', 'Long'].forEach((type) => { it(`should parse a ArrayOf${type} object`, function() { expect(parser.parse({ attributes: { 'xsi:type': `ArrayOf${type}` }, [type.toLowerCase()]: ['123', '12.34', '-42'] })).to.deep.equal([123, 12.34, -42]); }); }); it('should parse a complex type, if it is mapped in the library', function() { const parsed = parser.parse({ attributes: { 'xsi:type': sdk.data.HostHardwareSummary.name }, cpuMhz: '2048', cpuModel: 'Xeon E5-2640v2', memorySize: '409600', numCpuCores: '20', model: 'R820', numCpuPkgs: '2', numCpuThreads: '40', numHBAs: '2', numNics: '3', uuid: '123456-0000-0000-123456', vendor: 'Dell' }); expect(parsed).to.be.a.instanceOf(sdk.data.HostHardwareSummary); expect(parsed).to.deep.equal({ cpuMhz: 2048, cpuModel: 'Xeon E5-2640v2', memorySize: 409600, model: 'R820', numCpuCores: 20, numCpuPkgs: 2, numCpuThreads: 40, numHBAs: 2, numNics: 3, uuid: '123456-0000-0000-123456', vendor: 'Dell' }); }); it('should support "XMLSchema-instance" namespace too', function() { const parsed = parser.parse({ attributes: { 'XMLSchema-instance:type': sdk.data.HostHardwareSummary.name }, cpuMhz: '2048', cpuModel: 'Xeon E5-2640v2' }); expect(parsed).to.be.a.instanceOf(sdk.data.HostHardwareSummary); expect(parsed).to.deep.equal({ cpuMhz: 2048, cpuModel: 'Xeon E5-2640v2' }); }); describe('ComplexType', function() { it('should return a complex type when the actual type is mapped', function() { const parsed = parser.parse({ attributes: { 'xsi:type': 'ClusterComputeResourceSummary' }, effectiveCpu: '123' }, 'ComputeResourceSummary'); expect(parsed).to.be.an.instanceof(sdk.data.ClusterComputeResourceSummary); expect(parsed).to.deep.equal({ effectiveCpu: 123 }); }); it('should return a complex type of the default type when the actual type is mapped', function() { const parsed = parser.parse({ attributes: { 'xsi:type': 'AnotherUnmappedComputeResourceSummary' }, effectiveCpu: '123' }, 'ComputeResourceSummary'); expect(parsed).to.be.an.instanceof(sdk.data.ComputeResourceSummary); expect(parsed).to.deep.equal({ effectiveCpu: 123 }); }); }); describe('ArrayOfComplexType', function() { it('should return an array of complex type instances', function() { expect(parser.parse({ attributes: { 'xsi:type': 'ArrayOfAlarmState' }, AlarmState: [{ key: 'myAlarm1', acknowledged: true }, { key: 'myAlarm2', acknowledged: false }] }, 'ArrayOfAlarmState')).to.deep.equal([ { acknowledged: true, key: 'myAlarm1' }, { acknowledged: false, key: 'myAlarm2' } ]); }); it('should return an empty array when there is no instances', function() { expect(parser.parse({ attributes: { 'xsi:type': 'ArrayOfAlarmState' }, AlarmState: [] }, 'ArrayOfAlarmState')).to.deep.equal([]); }); it('should return an empty array when instances attribute does not exist', function() { expect(parser.parse({ attributes: { 'xsi:type': 'ArrayOfAlarmState' } }, 'ArrayOfAlarmState')).to.deep.equal([]); }); it('should return undefined when undefined is given', function() { expect(parser.parse(undefined, 'ArrayOfAlarmState')).to.equal(undefined); }); }); describe('Enum', function() { it('should parse an enum value as a String', function() { expect(parser.parse('running', 'VirtualMachinePowerState')).to.equal('running'); }); it('should parse an enum XML object as a String', function() { expect(parser.parse({ attributes: { 'xsi:type': 'VirtualMachinePowerState' }, $value: 'running' }, 'VirtualMachinePowerState')).to.equal('running'); }); }); }); it('should return the object unparsed when everything failed and there is no default type', function() { expect(parser.parse({ attributes: { 'xsi:type': 'UnmappedObject' }, a: 1 })).to.deep.equal({ attributes: { 'xsi:type': 'UnmappedObject' }, a: 1 }); }); it('should return the object unparsed when everything failed, including the default type', function() { expect(parser.parse({ attributes: { 'xsi:type': 'UnmappedObject' }, a: 1 }, 'AnotherUnmappedDefaultType')).to.deep.equal({ attributes: { 'xsi:type': 'UnmappedObject' }, a: 1 }); }); }); });