diff --git a/.travis.yml b/.travis.yml index 3b830b24ba..00f03cf0c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,20 +10,29 @@ before_script: - npm run build script: - npm run test:cov - - npm run coveralls-report - npm install --global typedoc - - typedoc --out ts-docs src + - CURRENT_VERSION=$(npm run version --silent) + - typedoc --out "ts-docs/$CURRENT_VERSION" src - touch ./ts-docs/.nojekyll + - if [ "$TRAVIS_NODE_VERSION" = "8" ]; then npm run coveralls-report; fi deploy: - provider: pages skip_cleanup: true local_dir: ts-docs + keep_history: true github_token: $GITHUB_TOKEN on: branch: master + node_js: "8" - provider: script skip_cleanup: true script: /bin/sh travis/uploadArchives.sh on: branch: master node_js: "8" + - provider: script + skip_cleanup: true + script: /bin/sh travis/release.sh + on: + branch: $RELEASE_BRANCH + node_js: "8" diff --git a/src/infrastructure/BlockHttp.ts b/src/infrastructure/BlockHttp.ts index be209da207..7f56ab295f 100644 --- a/src/infrastructure/BlockHttp.ts +++ b/src/infrastructure/BlockHttp.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { from as observableFrom, Observable, throwError } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; +import { Observable } from 'rxjs'; import { BlockInfoDTO, BlockRoutesApi } from 'symbol-openapi-typescript-node-client'; import { PublicAccount } from '../model/account/PublicAccount'; import { BlockInfo } from '../model/blockchain/BlockInfo'; @@ -55,10 +54,7 @@ export class BlockHttp extends Http implements BlockRepository { * @returns Observable */ public getBlockByHeight(height: UInt64): Observable { - return observableFrom(this.blockRoutesApi.getBlockByHeight(height.toString())).pipe( - map(({body}) => this.toBlockInfo(body)), - catchError((error) => throwError(this.errorHandling(error))), - ); + return this.call(this.blockRoutesApi.getBlockByHeight(height.toString()), (body) => this.toBlockInfo(body)); } /** @@ -69,15 +65,12 @@ export class BlockHttp extends Http implements BlockRepository { */ public getBlockTransactions(height: UInt64, queryParams?: QueryParams): Observable { - return observableFrom( - this.blockRoutesApi.getBlockTransactions(height.toString(), - this.queryParams(queryParams).pageSize, - this.queryParams(queryParams).id, - this.queryParams(queryParams).ordering)) - .pipe(map(({body}) => body.map((transactionDTO) => { - return CreateTransactionFromDTO(transactionDTO); - })), - catchError((error) => throwError(this.errorHandling(error))), + return this.call(this.blockRoutesApi.getBlockTransactions(height.toString(), + this.queryParams(queryParams).pageSize, + this.queryParams(queryParams).id, + this.queryParams(queryParams).ordering), (body) => body.map((transactionDTO) => { + return CreateTransactionFromDTO(transactionDTO); + }), ); } @@ -88,11 +81,8 @@ export class BlockHttp extends Http implements BlockRepository { * @returns Observable */ public getBlocksByHeightWithLimit(height: UInt64, limit: number): Observable { - return observableFrom( - this.blockRoutesApi.getBlocksByHeightWithLimit(height.toString(), limit)).pipe( - map(({body}) => body.map((blockDTO) => this.toBlockInfo(blockDTO))), - catchError((error) => throwError(this.errorHandling(error))), - ); + return this.call(this.blockRoutesApi.getBlocksByHeightWithLimit(height.toString(), limit), (body) => + body.map((blockDTO) => this.toBlockInfo(blockDTO))); } /** @@ -138,12 +128,10 @@ export class BlockHttp extends Http implements BlockRepository { * @return Observable */ public getMerkleTransaction(height: UInt64, hash: string): Observable { - return observableFrom( - this.blockRoutesApi.getMerkleTransaction(height.toString(), hash)).pipe( - map(({body}) => new MerkleProofInfo( - body.merklePath!.map((payload) => new MerklePathItem(payload.position, payload.hash)), - )), - catchError((error) => throwError(this.errorHandling(error))), - ); + return this.call( + this.blockRoutesApi.getMerkleTransaction(height.toString(), hash), (body) => new MerkleProofInfo( + body.merklePath!.map((payload) => new MerklePathItem(payload.position, payload.hash)), + )); } + } diff --git a/test/infrastructure/BlockHttp.spec.ts b/test/infrastructure/BlockHttp.spec.ts new file mode 100644 index 0000000000..a0e8a8deef --- /dev/null +++ b/test/infrastructure/BlockHttp.spec.ts @@ -0,0 +1,170 @@ +/* + * 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 { + BlockDTO, + BlockInfoDTO, + BlockMetaDTO, + BlockRoutesApi, + MerklePathItemDTO, + MerkleProofInfoDTO, + NetworkTypeEnum, + PositionEnum, +} from 'symbol-openapi-typescript-node-client'; +import { instance, mock, reset, when } from 'ts-mockito'; +import { DtoMapping } from '../../src/core/utils/DtoMapping'; +import { BlockHttp } from '../../src/infrastructure/BlockHttp'; +import { BlockRepository } from '../../src/infrastructure/BlockRepository'; +import { BlockInfo } from '../../src/model/blockchain/BlockInfo'; +import { MerklePathItem } from '../../src/model/blockchain/MerklePathItem'; +import { Transaction } from '../../src/model/transaction/Transaction'; +import { UInt64 } from '../../src/model/UInt64'; + +describe('BlockHttp', () => { + + const blockDTO = new BlockDTO(); + blockDTO.version = 1; + blockDTO.network = NetworkTypeEnum.NUMBER_152; + blockDTO.beneficiaryPublicKey = 'a'; + blockDTO.difficulty = '2'; + blockDTO.feeMultiplier = 3; + blockDTO.height = '4'; + blockDTO.previousBlockHash = '5'; + blockDTO.type = 6; + blockDTO.signerPublicKey = '81E5E7AE49998802DABC816EC10158D3A7879702FF29084C2C992CD1289877A7'; + blockDTO.timestamp = '7'; + blockDTO.beneficiaryPublicKey = '81E5E7AE49998802DABC816EC10158D3A7879702FF29084C2C992CD1289877A8'; + + const blockMetaDTO = new BlockMetaDTO(); + blockMetaDTO.generationHash = 'abc'; + blockMetaDTO.hash = 'aHash'; + blockMetaDTO.numStatements = 10; + blockMetaDTO.numTransactions = 20; + blockMetaDTO.totalFee = '30'; + blockMetaDTO.stateHashSubCacheMerkleRoots = ['a', 'b', 'c']; + + const blockInfoDto = new BlockInfoDTO(); + blockInfoDto.block = blockDTO; + blockInfoDto.meta = blockMetaDTO; + + const url = 'http://someHost'; + const response: http.IncomingMessage = mock(); + const blockRoutesApi: BlockRoutesApi = mock(); + const blockRepository: BlockRepository = DtoMapping.assign(new BlockHttp(url), {blockRoutesApi: instance(blockRoutesApi)}); + + const transactionInfoDTO = { + meta: { + hash: '671653C94E2254F2A23EFEDB15D67C38332AED1FBD24B063C0A8E675582B6A96', + height: '18160', + id: '5A0069D83F17CF0001777E55', + index: 0, + merkleComponentHash: '81E5E7AE49998802DABC816EC10158D3A7879702FF29084C2C992CD1289877A7', + }, + transaction: { + deadline: '1000', + maxFee: '0', + signature: '939673209A13FF82397578D22CC96EB8516A6760C894D9B7535E3A1E0680' + + '07B9255CFA9A914C97142A7AE18533E381C846B69D2AE0D60D1DC8A55AD120E2B606', + signerPublicKey: '7681ED5023141D9CDCF184E5A7B60B7D466739918ED5DA30F7E71EA7B86EFF2D', + minApprovalDelta: 1, + minRemovalDelta: 1, + modifications: [ + { + cosignatoryPublicKey: '589B73FBC22063E9AE6FBAC67CB9C6EA865EF556E5' + + 'FB8B7310D45F77C1250B97', + modificationAction: 0, + }, + ], + type: 16725, + version: 1, + network: 144, + }, + }; + + before(() => { + reset(response); + reset(blockRoutesApi); + }); + + function assertBlockInfo(blockInfo: BlockInfo) { + expect(blockInfo).to.be.not.null; + expect(blockInfo.type).to.be.equals(blockInfoDto.block.type); + expect(blockInfo.previousBlockHash).to.be.equals(blockInfoDto.block.previousBlockHash); + expect(blockInfo.height.toString()).to.be.equals(blockInfoDto.block.height); + expect(blockInfo.feeMultiplier).to.be.equals(blockInfoDto.block.feeMultiplier); + expect(blockInfo.networkType).to.be.equals(blockInfoDto.block.network); + expect(blockInfo.version).to.be.equals(blockInfoDto.block.version); + expect(blockInfo.beneficiaryPublicKey!.publicKey).to.be.equals(blockInfoDto.block.beneficiaryPublicKey); + expect(blockInfo.difficulty.toString()).to.be.equals(blockInfoDto.block.difficulty); + expect(blockInfo.feeMultiplier).to.be.equals(blockInfoDto.block.feeMultiplier); + expect(blockInfo.signer!.publicKey).to.be.equals(blockInfoDto.block.signerPublicKey); + expect(blockInfo.signature).to.be.equals(blockInfoDto.block.signature); + + expect(blockInfo.generationHash).to.be.equals(blockInfoDto.meta.generationHash); + expect(blockInfo.hash).to.be.equals(blockInfoDto.meta.hash); + expect(blockInfo.numStatements).to.be.equals(blockInfoDto.meta.numStatements); + expect(blockInfo.numTransactions).to.be.equals(blockInfoDto.meta.numTransactions); + expect(blockInfo.totalFee.toString()).to.be.equals(blockInfoDto.meta.totalFee); + } + + function assertTransaction(transaction: Transaction) { + expect(transaction).to.be.not.null; + expect(transaction.type).to.be.equals(transactionInfoDTO.transaction.type); + expect(transaction.deadline.toString()).to.be.equals(transactionInfoDTO.transaction.deadline); + } + + it('getBlockInfo', async () => { + when(blockRoutesApi.getBlockByHeight('1')).thenReturn(Promise.resolve({response, body: blockInfoDto})); + const blockInfo = await blockRepository.getBlockByHeight(UInt64.fromUint(1)).toPromise(); + assertBlockInfo(blockInfo); + }); + + it('getBlocksByHeightWithLimit', async () => { + when(blockRoutesApi.getBlocksByHeightWithLimit('2', 10)).thenReturn(Promise.resolve({ + response, + body: [blockInfoDto], + })); + const blockInfos = await blockRepository.getBlocksByHeightWithLimit(UInt64.fromUint(2), 10).toPromise(); + assertBlockInfo(blockInfos[0]); + }); + + it('getBlockTransactions', async () => { + when(blockRoutesApi.getBlockTransactions('2', undefined, undefined, undefined)).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await blockRepository.getBlockTransactions(UInt64.fromUint(2)).toPromise(); + assertTransaction(transactions[0]); + }); + + it('getMerkleTransaction', async () => { + const merkleProofInfoDTO = new MerkleProofInfoDTO(); + const merklePathItemDTO = new MerklePathItemDTO(); + merklePathItemDTO.hash = 'bbb'; + merklePathItemDTO.position = PositionEnum.Left; + merkleProofInfoDTO.merklePath = [merklePathItemDTO]; + + when(blockRoutesApi.getMerkleTransaction('2', 'abc')).thenReturn(Promise.resolve({ + response, + body: merkleProofInfoDTO, + })); + const merkleProofInfo = await blockRepository.getMerkleTransaction(UInt64.fromUint(2), 'abc').toPromise(); + expect(merkleProofInfo).to.be.not.null; + expect(merkleProofInfo.merklePath).to.deep.equals([new MerklePathItem(PositionEnum.Left, 'bbb')]); + }); + +}); diff --git a/.npmrc.template b/travis/.npmrc similarity index 100% rename from .npmrc.template rename to travis/.npmrc diff --git a/travis/release.sh b/travis/release.sh new file mode 100644 index 0000000000..e099e17880 --- /dev/null +++ b/travis/release.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -e + +if [ "$TRAVIS_BRANCH" = "$RELEASE_BRANCH" ]; then + + REMOTE_NAME="origin" + POST_RELEASE_BRANCH="post-$RELEASE_BRANCH" + + git remote rm $REMOTE_NAME + + echo "Setting remote url https://github.com/${TRAVIS_REPO_SLUG}.git" + git remote add $REMOTE_NAME "https://${GRGIT_USER}@github.com/${TRAVIS_REPO_SLUG}.git" > /dev/null 2>&1 + + echo "Checking out $RELEASE_BRANCH as travis leaves the head detached." + git checkout $RELEASE_BRANCH + + CURRENT_VERSION=$(npm run version --silent) + + echo "Current Version" + cat "$CURRENT_VERSION" + echo "" + + echo "Testing git remote" + git branch -vv + echo "" + + echo "Creating tag v$CURRENT_VERSION" + git tag "v$CURRENT_VERSION" + echo "" + + cp travis/.npmrc $HOME/.npmrc + + echo "Releasing sdk artifacts" + npm publish + echo "" + + echo "Increasing sdk version" + npm version patch -m "Increasing version to %s" --git-tag-version false + + CURRENT_VERSION=$(npm run version --silent) + + echo "New Version" + cat "$CURRENT_VERSION" + echo "" + + echo "Pushing code to $REMOTE_NAME $POST_RELEASE_BRANCH" + git push --set-upstream $REMOTE_NAME $RELEASE_BRANCH:$POST_RELEASE_BRANCH + echo "Pushing tags to $REMOTE_NAME" + git push --tags $REMOTE_NAME +else + echo "Release is disabled" +fi diff --git a/travis/uploadArchives.sh b/travis/uploadArchives.sh index f4aec74a78..33159e61d9 100644 --- a/travis/uploadArchives.sh +++ b/travis/uploadArchives.sh @@ -5,7 +5,7 @@ CURRENT_VERSION=$(npm run version --silent) NEW_VERSION="$CURRENT_VERSION-alpha-$(date +%Y%m%d%H%M)" echo "Uploading npm package version $NEW_VERSION" -cp .npmrc.template $HOME/.npmrc +cp travis/.npmrc $HOME/.npmrc npm version "$NEW_VERSION" --commit-hooks false --git-tag-version false