Skip to content
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
128 changes: 56 additions & 72 deletions src/infrastructure/MosaicHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* limitations under the License.
*/

import { from as observableFrom, Observable, throwError } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { MosaicRoutesApi } from 'symbol-openapi-typescript-node-client';
import { Observable, throwError } from 'rxjs';
import { catchError, mergeMap } from 'rxjs/operators';
import { MosaicRoutesApi, MosaicIds, AccountIds, MosaicInfoDTO, MosaicDTO } from 'symbol-openapi-typescript-node-client';
import { Address } from '../model/account/Address';
import { PublicAccount } from '../model/account/PublicAccount';
import { MosaicFlags } from '../model/mosaic/MosaicFlags';
Expand Down Expand Up @@ -63,21 +63,9 @@ export class MosaicHttp extends Http implements MosaicRepository {
*/
public getMosaic(mosaicId: MosaicId): Observable<MosaicInfo> {
return this.networkTypeObservable.pipe(
mergeMap((networkType) => observableFrom(
this.mosaicRoutesApi.getMosaic(mosaicId.toHex())).pipe(
map(({body}) => new MosaicInfo(
new MosaicId(body.mosaic.id),
UInt64.fromNumericString(body.mosaic.supply),
UInt64.fromNumericString(body.mosaic.startHeight),
PublicAccount.createFromPublicKey(body.mosaic.ownerPublicKey, networkType),
body.mosaic.revision,
new MosaicFlags(body.mosaic.flags),
body.mosaic.divisibility,
UInt64.fromNumericString(body.mosaic.duration),
)),
catchError((error) => throwError(this.errorHandling(error))),
)),
);
mergeMap((networkType) =>
this.call(this.mosaicRoutesApi.getMosaic(mosaicId.toHex()), (body) => this.toMosaicInfo(body, networkType))),
);
}

/**
Expand All @@ -86,27 +74,11 @@ export class MosaicHttp extends Http implements MosaicRepository {
* @returns Observable<MosaicInfo[]>
*/
public getMosaics(mosaicIds: MosaicId[]): Observable<MosaicInfo[]> {
const mosaicIdsBody = {
mosaicIds: mosaicIds.map((id) => id.toHex()),
};
const ids = new MosaicIds();
ids.mosaicIds = mosaicIds.map((id) => id.toHex());
return this.networkTypeObservable.pipe(
mergeMap((networkType) => observableFrom(
this.mosaicRoutesApi.getMosaics(mosaicIdsBody)).pipe(
map(({body}) => body.map((mosaicInfoDTO) => {
return new MosaicInfo(
new MosaicId(mosaicInfoDTO.mosaic.id),
UInt64.fromNumericString(mosaicInfoDTO.mosaic.supply),
UInt64.fromNumericString(mosaicInfoDTO.mosaic.startHeight),
PublicAccount.createFromPublicKey(mosaicInfoDTO.mosaic.ownerPublicKey, networkType),
mosaicInfoDTO.mosaic.revision,
new MosaicFlags(mosaicInfoDTO.mosaic.flags),
mosaicInfoDTO.mosaic.divisibility,
UInt64.fromNumericString(mosaicInfoDTO.mosaic.duration),
);
})),
catchError((error) => throwError(this.errorHandling(error))),
),
),
mergeMap((networkType) =>
this.call(this.mosaicRoutesApi.getMosaics(ids), (body) => body.map((b) => this.toMosaicInfo(b, networkType)))),
);
}

Expand All @@ -117,20 +89,9 @@ export class MosaicHttp extends Http implements MosaicRepository {
*/
public getMosaicsFromAccount(address: Address): Observable<MosaicInfo[]> {
return this.networkTypeObservable.pipe(
mergeMap((networkType) => observableFrom(
this.mosaicRoutesApi.getMosaicsFromAccount(address.plain())).pipe(
map(({body}) => body.mosaics.map((mosaicInfo) =>
new MosaicInfo(
new MosaicId(mosaicInfo.id),
UInt64.fromNumericString(mosaicInfo.supply),
UInt64.fromNumericString(mosaicInfo.startHeight),
PublicAccount.createFromPublicKey(mosaicInfo.ownerPublicKey, networkType),
mosaicInfo.revision,
new MosaicFlags(mosaicInfo.flags),
mosaicInfo.divisibility,
UInt64.fromNumericString(mosaicInfo.duration)))),
catchError((error) => throwError(this.errorHandling(error))),
)),
mergeMap((networkType) =>
this.call(this.mosaicRoutesApi.getMosaicsFromAccount(address.plain()),
(body) => body.mosaics.map((b) => this.toMosaicInfoFromMosaicDto(b, networkType)))),
);
}

Expand All @@ -140,27 +101,50 @@ export class MosaicHttp extends Http implements MosaicRepository {
* @param addresses Array of addresses
*/
public getMosaicsFromAccounts(addresses: Address[]): Observable<MosaicInfo[]> {
const accountIdsBody = {
addresses: addresses.map((address) => address.plain()),
};
const accountIds = new AccountIds();
accountIds.addresses = addresses.map((address) => address.plain());
return this.networkTypeObservable.pipe(
mergeMap((networkType) => observableFrom(
this.mosaicRoutesApi.getMosaicsFromAccounts(accountIdsBody)).pipe(
map(({body}) => body.mosaics.map((mosaicInfoDTO) => {
return new MosaicInfo(
new MosaicId(mosaicInfoDTO.id),
UInt64.fromNumericString(mosaicInfoDTO.supply),
UInt64.fromNumericString(mosaicInfoDTO.startHeight),
PublicAccount.createFromPublicKey(mosaicInfoDTO.ownerPublicKey, networkType),
mosaicInfoDTO.revision,
new MosaicFlags(mosaicInfoDTO.flags),
mosaicInfoDTO.divisibility,
UInt64.fromNumericString(mosaicInfoDTO.duration),
);
})),
catchError((error) => throwError(this.errorHandling(error))),
),
),
mergeMap((networkType) =>
this.call(this.mosaicRoutesApi.getMosaicsFromAccounts(accountIds),
(body) => body.mosaics.map((b) => this.toMosaicInfoFromMosaicDto(b, networkType)))),
);
}

/**
* Maps MosaicInfoDTO to MosaicInfo
*
* @param mosaicInfo the dto object.
* @returns the model object
*/
private toMosaicInfo(mosaicInfo: MosaicInfoDTO, networkType: NetworkType): MosaicInfo {
return new MosaicInfo(
new MosaicId(mosaicInfo.mosaic.id),
UInt64.fromNumericString(mosaicInfo.mosaic.supply),
UInt64.fromNumericString(mosaicInfo.mosaic.startHeight),
PublicAccount.createFromPublicKey(mosaicInfo.mosaic.ownerPublicKey, networkType),
mosaicInfo.mosaic.revision,
new MosaicFlags(mosaicInfo.mosaic.flags),
mosaicInfo.mosaic.divisibility,
UInt64.fromNumericString(mosaicInfo.mosaic.duration),
);
}

/**
* Maps MosaicDTO to MosaicInfo
*
* @param mosaicInfo the dto object.
* @returns the model object
*/
private toMosaicInfoFromMosaicDto(mosaicInfo: MosaicDTO, networkType: NetworkType): MosaicInfo {
return new MosaicInfo(
new MosaicId(mosaicInfo.id),
UInt64.fromNumericString(mosaicInfo.supply),
UInt64.fromNumericString(mosaicInfo.startHeight),
PublicAccount.createFromPublicKey(mosaicInfo.ownerPublicKey, networkType),
mosaicInfo.revision,
new MosaicFlags(mosaicInfo.flags),
mosaicInfo.divisibility,
UInt64.fromNumericString(mosaicInfo.duration),
);
}
}
143 changes: 143 additions & 0 deletions test/infrastructure/MosaicHttp.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Copyright 2020 NEM
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect } from 'chai';
import * as http from 'http';
import {
Mosaic,
MosaicRoutesApi,
MosaicInfoDTO,
MosaicDTO,
MosaicsInfoDTO,
MosaicIds,
} from 'symbol-openapi-typescript-node-client';
import { instance, mock, reset, when, deepEqual } from 'ts-mockito';
import { DtoMapping } from '../../src/core/utils/DtoMapping';
import { MosaicRepository } from '../../src/infrastructure/MosaicRepository';
import { MosaicHttp } from '../../src/infrastructure/MosaicHttp';
import { NetworkType } from '../../src/model/network/NetworkType';
import { MosaicId } from '../../src/model/mosaic/MosaicId';
import { MosaicInfo } from '../../src/model/mosaic/MosaicInfo';
import { PublicAccount } from '../../src/model/account/PublicAccount';
import { AccountIds } from 'symbol-openapi-typescript-node-client';
import { assert } from 'chai';

describe('MosaicHttp', () => {

const publicAccount =
PublicAccount.createFromPublicKey('9801508C58666C746F471538E43002B85B1CD542F9874B2861183919BA8787B6', NetworkType.MIJIN_TEST);
const address = publicAccount.address;
const mosaicId = new MosaicId('941299B2B7E1291C');
const mosaic = new Mosaic();
mosaic.amount = '777';
mosaic.id = mosaicId.toHex();

const mosaicDto = new MosaicDTO();
mosaicDto.divisibility = 6;
mosaicDto.duration = '10';
mosaicDto.flags = 1;
mosaicDto.id = mosaicId.toHex();
mosaicDto.ownerAddress = address.encoded();
mosaicDto.ownerPublicKey = publicAccount.publicKey;
mosaicDto.revision = 0;
mosaicDto.startHeight = '1';
mosaicDto.supply = '100';

const mosaicInfoDto = new MosaicInfoDTO();
const mosaicsInfoDto = new MosaicsInfoDTO();
mosaicInfoDto.mosaic = mosaicDto;
mosaicsInfoDto.mosaics = [mosaicDto];

const url = 'http://someHost';
const response: http.IncomingMessage = mock();
const mosaicRoutesApi: MosaicRoutesApi = mock();
const mosaicRepository: MosaicRepository = DtoMapping.assign(new MosaicHttp(url, NetworkType.MIJIN_TEST),
{mosaicRoutesApi: instance(mosaicRoutesApi)});

before(() => {
reset(response);
reset(mosaicRoutesApi);
});

function assertMosaicInfo(mosaicInfo: MosaicInfo) {
expect(mosaicInfo).to.be.not.null;
expect(mosaicInfo.divisibility).to.be.equals(6);
expect(mosaicInfo.duration.toString()).to.be.equals(mosaicDto.duration);
expect(mosaicInfo.flags.getValue()).to.be.equals(mosaicDto.flags);
expect(mosaicInfo.height.toString()).to.be.equals(mosaicDto.startHeight);
expect(mosaicInfo.supply.toString()).to.be.equals(mosaicDto.supply);
expect(mosaicInfo.owner.publicKey).to.be.equals(mosaicDto.ownerPublicKey);
expect(mosaicInfo.owner.address.encoded()).to.be.equals(mosaicDto.ownerAddress);
expect(mosaicInfo.revision).to.be.equals(mosaicDto.revision);
expect(mosaicInfo.id.toHex()).to.be.equals(mosaicId.toHex());
}

it('getMosaic', async () => {
when(mosaicRoutesApi.getMosaic(mosaicId.toHex())).thenReturn(Promise.resolve({response, body: mosaicInfoDto}));
const mosaicInfo = await mosaicRepository.getMosaic(mosaicId).toPromise();
assertMosaicInfo(mosaicInfo);
});

it('getMosaics', async () => {
const mosaicIds = new MosaicIds();
mosaicIds.mosaicIds = [mosaicId.toHex()];
when(mosaicRoutesApi.getMosaics(deepEqual(mosaicIds))).thenReturn(Promise.resolve({response, body: [mosaicInfoDto]}));
const mosaicInfos = await mosaicRepository.getMosaics([mosaicId]).toPromise();
assertMosaicInfo(mosaicInfos[0]);
});

it('getMosaicsFromAccount', async () => {
when(mosaicRoutesApi.getMosaicsFromAccount(address.plain())).thenReturn(Promise.resolve({response, body: mosaicsInfoDto}));
const mosaicsInfo = await mosaicRepository.getMosaicsFromAccount(address).toPromise();
assertMosaicInfo(mosaicsInfo[0]);
});

it('getMosaicsFromAccounts', async () => {
const accountIds = new AccountIds();
accountIds.addresses = [address.plain()];
when(mosaicRoutesApi.getMosaicsFromAccounts(deepEqual(accountIds)))
.thenReturn(Promise.resolve({response, body: mosaicsInfoDto}));
const mosaicsInfo = await mosaicRepository.getMosaicsFromAccounts([address]).toPromise();
assertMosaicInfo(mosaicsInfo[0]);
});

it('getMosaic - Error', async () => {
when(mosaicRoutesApi.getMosaic(mosaicId.toHex())).thenThrow(new Error('Mocked Error'));
await mosaicRepository.getMosaic(mosaicId).toPromise().catch((error) =>
expect(error).not.to.be.undefined);
});

it('getMosaics - Error', async () => {
const mosaicIds = new MosaicIds();
mosaicIds.mosaicIds = [mosaicId.toHex()];
when(mosaicRoutesApi.getMosaics(deepEqual(mosaicIds))).thenThrow(new Error('Mocked Error'));
await mosaicRepository.getMosaics([mosaicId]).toPromise().catch((error) =>
expect(error).not.to.be.undefined);
});

it('getMosaicsFromAccount - Error', async () => {
when(mosaicRoutesApi.getMosaicsFromAccount(address.plain())).thenThrow(new Error('Mocked Error'));
await mosaicRepository.getMosaicsFromAccount(address).toPromise().catch((error) =>
expect(error).not.to.be.undefined);
});

it('getMosaicsFromAccounts - Error', async () => {
const accountIds = new AccountIds();
accountIds.addresses = [address.plain()];
when(mosaicRoutesApi.getMosaicsFromAccounts(deepEqual(accountIds))).thenThrow(new Error('Mocked Error'));
await mosaicRepository.getMosaicsFromAccounts([address]).toPromise().catch((error) =>
expect(error).not.to.be.undefined);
});
});
Loading