Merge pull request #28 from microsoft/caleteet-100-updates

Updates for release v1.0.0
This commit is contained in:
Chris Segura 2020-01-31 11:20:17 -08:00 коммит произвёл GitHub
Родитель dc12c4f832 7a0439d359
Коммит 549a3afcae
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
86 изменённых файлов: 4017 добавлений и 4052 удалений

Просмотреть файл

@ -2,6 +2,22 @@
All notable changes to the "azure blockchain" extension will be documented in this file.
## 0.1.14
### Enhancements
- Added UI to handle required parameters for OpenZeppelin contract deployment.
- Added Blockchain Data Manager to the core view for connecting to existing instances.
### Fixes
- Cleanup of obfuscation for build directory path.
- Merge of public PR for url checker to include basic auth.
### Internal Improvements
- Refactoring custom build directory code.
## 0.1.13
### Enhancements

Просмотреть файл

@ -3,9 +3,9 @@
"displayName": "Azure Blockchain Development Kit for Ethereum",
"description": "Develop, deploy debug and manage your Azure Blockchain Service solution",
"publisher": "AzBlockchain",
"preview": true,
"preview": false,
"icon": "images/blockchain-service-logo.png",
"version": "0.1.13",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-azure-blockchain-ethereum"
@ -57,6 +57,7 @@
"onCommand:azureBlockchainService.signInToInfuraAccount",
"onCommand:azureBlockchainService.signOutOfInfuraAccount",
"onCommand:azureBlockchainService.generateToken",
"onCommand:azureBlockchainService.openAtAzurePortal",
"onDebug"
],
"contributes": {
@ -204,6 +205,11 @@
"command": "azureBlockchainService.generateToken",
"title": "Generate token",
"category": "Azure Blockchain"
},
{
"command": "azureBlockchainService.openAtAzurePortal",
"title": "Open at Azure Portal",
"category": "Azure Blockchain"
}
],
"breakpoints": [
@ -275,6 +281,10 @@
{
"when": "false",
"command": "openZeppelin.addCategory"
},
{
"when": "false",
"command": "azureBlockchainService.openAtAzurePortal"
}
],
"view/title": [
@ -326,6 +336,16 @@
"command": "azureBlockchainService.copyRPCEndpointAddress",
"when": "view == AzureBlockchain && viewItem == localnetwork",
"group": "azureBlockchain-0@0"
},
{
"command": "azureBlockchainService.openAtAzurePortal",
"when": "view == AzureBlockchain && viewItem == input",
"group": "azureBlockchain-0@0"
},
{
"command": "azureBlockchainService.openAtAzurePortal",
"when": "view == AzureBlockchain && viewItem == output",
"group": "azureBlockchain-0@0"
}
],
"explorer/context": [

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 18 18" enable-background="new 0 0 50 50" xml:space="preserve">
<polygon points="13.77 4.58 13.77 10.73 8.49 13.83 8.49 7.66 13.77 4.58" fill="#773adc"/>
<polygon points="13.77 4.58 8.49 7.67 3.2 4.58 8.49 1.49 13.77 4.58" fill="#b796f9"/>
<polygon points="8.49 7.67 8.49 13.83 3.2 10.73 3.2 4.58 8.49 7.67" fill="#a67af4"/>
<path d="M11.15,7.69c.7-.4,1.26-.08,1.26.72a2.77,2.77,0,0,1-1.25,2.17c-.7.4-1.26.08-1.26-.72A2.77,2.77,0,0,1,11.15,7.69Z" fill="#552f99"/>
<path d="M14.66,9.83H11.51a.63.63,0,0,1,0-1.26h3.15a2.06,2.06,0,0,0,2-2.13,2.06,2.06,0,0,0-2-2.14h0a.63.63,0,0,1,0-1.26h0a3.31,3.31,0,0,1,3.22,3.4A3.31,3.31,0,0,1,14.66,9.83Z" fill="#50e6ff"/>
<path d="M11.94,13.87,9.51,11.44a.13.13,0,0,0-.2,0v1.87h-6a2.06,2.06,0,0,1-2-2.14A2.07,2.07,0,0,1,3.2,9.06V7.8A3.33,3.33,0,0,0,.12,11.19a3.32,3.32,0,0,0,3.22,3.4h6v1.86a.13.13,0,0,0,.2,0L11.94,14A.11.11,0,0,0,11.94,13.87Z" fill="#32bedd"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 18 18" enable-background="new 0 0 50 50" xml:space="preserve">
<defs>
<linearGradient id="a13e5b14-541b-41c4-969c-51486fce6d08" x1="8.94" y1="18.11" x2="8.91" y2="13.59" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#32bedd"/>
<stop offset="0.36" stop-color="#34c1e0"/>
<stop offset="0.63" stop-color="#3ccbe8"/>
<stop offset="0.88" stop-color="#48dbf6"/>
<stop offset="1" stop-color="#50e6ff"/>
</linearGradient>
</defs>
<g>
<g>
<polygon points="15.43 3.76 15.43 11.24 9 15 9 7.51 15.43 3.76" fill="#773adc"/>
<polygon points="15.43 3.76 9 7.52 2.57 3.76 9 0 15.43 3.76" fill="#b796f9"/>
<polygon points="9 7.52 9 15 2.57 11.24 2.57 3.76 9 7.52" fill="#a67af4"/>
</g>
<path d="M11.89,9,9.06,6.12a.15.15,0,0,0-.21,0L6,9a.14.14,0,0,0,.11.24H7.78a.15.15,0,0,1,.15.15V12a.15.15,0,0,0,.14.15H9.83A.15.15,0,0,0,10,12V9.35a.15.15,0,0,1,.14-.15h1.67A.14.14,0,0,0,11.89,9Z" fill="#fff"/>
<g>
<rect x="5.41" y="11.81" width="7.02" height="6.19" rx="0.37" fill="url(#a13e5b14-541b-41c4-969c-51486fce6d08)"/>
<path d="M8.1,16.3,6.69,14.89l1.38-1.38a.1.1,0,0,0,0-.14l-.22-.22a.12.12,0,0,0-.14,0l-1.6,1.6a.22.22,0,0,0,0,.22.18.18,0,0,0,0,.07l1.62,1.62a.1.1,0,0,0,.14,0l.22-.22A.1.1,0,0,0,8.1,16.3Z" fill="#fff"/>
<path d="M12,14.75l-1.59-1.6a.12.12,0,0,0-.14,0l-.22.22a.1.1,0,0,0,0,.14l1.37,1.38L10,16.3a.1.1,0,0,0,0,.14l.22.22a.1.1,0,0,0,.14,0L12,15A.16.16,0,0,0,12,15,.2.2,0,0,0,12,14.75Z" fill="#fff"/>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 15 15" enable-background="new 0 0 50 50" xml:space="preserve">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/>
<path class="icon-vs-out" d="M16 14H0V2h16v12z" id="outline" style="display: none;"/>
<path class="icon-vs-bg" d="M1 3v10h14V3H1zm13 9H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6v8z" id="iconBg"/>
<path class="icon-vs-fg" d="M14 4v8H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6zM6.057 5.367L5.35 4.66 2 8.01l3.35 3.338.707-.707-2.139-2.146L8 8.501v-1l-4.064-.005 2.121-2.129z" id="iconFg" style="display: none;"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 15 15" enable-background="new 0 0 50 50" xml:space="preserve" style="transform:rotateY(-180deg)">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/>
<path class="icon-vs-out" d="M16 14H0V2h16v12z" id="outline" style="display: none;"/>
<path class="icon-vs-bg" d="M1 3v10h14V3H1zm13 9H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6v8z" id="iconBg"/>
<path class="icon-vs-fg" d="M14 4v8H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6zM6.057 5.367L5.35 4.66 2 8.01l3.35 3.338.707-.707-2.139-2.146L8 8.501v-1l-4.064-.005 2.121-2.129z" id="iconFg" style="display: none;"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
<g>
<path class="msportalfx-svg-c19" fill="#0072c6" d="M 3.167 13 h 22.667 v 4 H 3.167 Z m 5 10 h 25.667 v 4 H 8.167 Z m -5 10 h 22.667 v 4 H 3.167 Z"/>
<circle class="msportalfx-svg-c13" fill="#b8d432" cx="4" cy="35" r="3.9"/>
<ellipse class="msportalfx-svg-c13" fill="#b8d432" transform="rotate(-45.001 4 15)" cx="4" cy="15" rx="3.9" ry="3.9"/>
<ellipse class="msportalfx-svg-c15" fill="#59b4d9" transform="rotate(-45.001 9 25)" cx="9" cy="25" rx="3.9" ry="3.9"/>
<path class="msportalfx-svg-c19" fill="#0072c6" d="M 24 20 V 10 l 8 5 Z m 0 20 V 30 l 8 5 Z m 8 -10 V 20 l 8 5 Z m 17.2 8.6 h -4.8 c -0.5 0 -0.8 0.3 -0.8 0.8 v 4 H 7 V 50 h 42.2 c 0.5 0 0.8 -0.3 0.8 -0.8 v -9.8 c 0 -0.5 -0.3 -0.8 -0.8 -0.8 Z M 49.281 0 H 7 v 6.7 h 36.381 v 4.2 c 0 0.5 0.3 0.8 1 0.8 h 4.8 c 0.5 0 0.8 -0.3 0.8 -0.8 V 0.9 c 0.1 -0.6 -0.2 -0.9 -0.7 -0.9 Z"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 18 18" enable-background="new 0 0 50 50" xml:space="preserve">
<polygon points="13.77 4.58 13.77 10.73 8.49 13.83 8.49 7.66 13.77 4.58" fill="#773adc"/>
<polygon points="13.77 4.58 8.49 7.67 3.2 4.58 8.49 1.49 13.77 4.58" fill="#b796f9"/>
<polygon points="8.49 7.67 8.49 13.83 3.2 10.73 3.2 4.58 8.49 7.67" fill="#a67af4"/>
<path d="M11.15,7.69c.7-.4,1.26-.08,1.26.72a2.77,2.77,0,0,1-1.25,2.17c-.7.4-1.26.08-1.26-.72A2.77,2.77,0,0,1,11.15,7.69Z" fill="#552f99"/>
<path d="M14.66,9.83H11.51a.63.63,0,0,1,0-1.26h3.15a2.06,2.06,0,0,0,2-2.13,2.06,2.06,0,0,0-2-2.14h0a.63.63,0,0,1,0-1.26h0a3.31,3.31,0,0,1,3.22,3.4A3.31,3.31,0,0,1,14.66,9.83Z" fill="#50e6ff"/>
<path d="M11.94,13.87,9.51,11.44a.13.13,0,0,0-.2,0v1.87h-6a2.06,2.06,0,0,1-2-2.14A2.07,2.07,0,0,1,3.2,9.06V7.8A3.33,3.33,0,0,0,.12,11.19a3.32,3.32,0,0,0,3.22,3.4h6v1.86a.13.13,0,0,0,.2,0L11.94,14A.11.11,0,0,0,11.94,13.87Z" fill="#32bedd"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 18 18" enable-background="new 0 0 50 50" xml:space="preserve">
<defs>
<linearGradient id="a13e5b14-541b-41c4-969c-51486fce6d08" x1="8.94" y1="18.11" x2="8.91" y2="13.59" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#32bedd"/>
<stop offset="0.36" stop-color="#34c1e0"/>
<stop offset="0.63" stop-color="#3ccbe8"/>
<stop offset="0.88" stop-color="#48dbf6"/>
<stop offset="1" stop-color="#50e6ff"/>
</linearGradient>
</defs>
<g>
<g>
<polygon points="15.43 3.76 15.43 11.24 9 15 9 7.51 15.43 3.76" fill="#773adc"/>
<polygon points="15.43 3.76 9 7.52 2.57 3.76 9 0 15.43 3.76" fill="#b796f9"/>
<polygon points="9 7.52 9 15 2.57 11.24 2.57 3.76 9 7.52" fill="#a67af4"/>
</g>
<path d="M11.89,9,9.06,6.12a.15.15,0,0,0-.21,0L6,9a.14.14,0,0,0,.11.24H7.78a.15.15,0,0,1,.15.15V12a.15.15,0,0,0,.14.15H9.83A.15.15,0,0,0,10,12V9.35a.15.15,0,0,1,.14-.15h1.67A.14.14,0,0,0,11.89,9Z" fill="#fff"/>
<g>
<rect x="5.41" y="11.81" width="7.02" height="6.19" rx="0.37" fill="url(#a13e5b14-541b-41c4-969c-51486fce6d08)"/>
<path d="M8.1,16.3,6.69,14.89l1.38-1.38a.1.1,0,0,0,0-.14l-.22-.22a.12.12,0,0,0-.14,0l-1.6,1.6a.22.22,0,0,0,0,.22.18.18,0,0,0,0,.07l1.62,1.62a.1.1,0,0,0,.14,0l.22-.22A.1.1,0,0,0,8.1,16.3Z" fill="#fff"/>
<path d="M12,14.75l-1.59-1.6a.12.12,0,0,0-.14,0l-.22.22a.1.1,0,0,0,0,.14l1.37,1.38L10,16.3a.1.1,0,0,0,0,.14l.22.22a.1.1,0,0,0,.14,0L12,15A.16.16,0,0,0,12,15,.2.2,0,0,0,12,14.75Z" fill="#fff"/>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 15 15" enable-background="new 0 0 50 50" xml:space="preserve">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#2b282e}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/>
<path class="icon-vs-out" d="M16 14H0V2h16v12z" id="outline" style="display: none;"/>
<path class="icon-vs-bg" d="M1 3v10h14V3H1zm13 9H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6v8z" id="iconBg"/>
<path class="icon-vs-fg" d="M14 4v8H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6zM6.057 5.367L5.35 4.66 2 8.01l3.35 3.338.707-.707-2.139-2.146L8 8.501v-1l-4.064-.005 2.121-2.129z" id="iconFg" style="display: none;"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 15 15" enable-background="new 0 0 50 50" xml:space="preserve" style="transform:rotateY(-180deg)">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#2b282e}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/>
<path class="icon-vs-out" d="M16 14H0V2h16v12z" id="outline" style="display: none;"/>
<path class="icon-vs-bg" d="M1 3v10h14V3H1zm13 9H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6v8z" id="iconBg"/>
<path class="icon-vs-fg" d="M14 4v8H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6zM6.057 5.367L5.35 4.66 2 8.01l3.35 3.338.707-.707-2.139-2.146L8 8.501v-1l-4.064-.005 2.121-2.129z" id="iconFg" style="display: none;"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
<g>
<path class="msportalfx-svg-c19" fill="#0072c6" d="M 3.167 13 h 22.667 v 4 H 3.167 Z m 5 10 h 25.667 v 4 H 8.167 Z m -5 10 h 22.667 v 4 H 3.167 Z"/>
<circle class="msportalfx-svg-c13" fill="#b8d432" cx="4" cy="35" r="3.9"/>
<ellipse class="msportalfx-svg-c13" fill="#b8d432" transform="rotate(-45.001 4 15)" cx="4" cy="15" rx="3.9" ry="3.9"/>
<ellipse class="msportalfx-svg-c15" fill="#59b4d9" transform="rotate(-45.001 9 25)" cx="9" cy="25" rx="3.9" ry="3.9"/>
<path class="msportalfx-svg-c19" fill="#0072c6" d="M 24 20 V 10 l 8 5 Z m 0 20 V 30 l 8 5 Z m 8 -10 V 20 l 8 5 Z m 17.2 8.6 h -4.8 c -0.5 0 -0.8 0.3 -0.8 0.8 v 4 H 7 V 50 h 42.2 c 0.5 0 0.8 -0.3 0.8 -0.8 v -9.8 c 0 -0.5 -0.3 -0.8 -0.8 -0.8 Z M 49.281 0 H 7 v 6.7 h 36.381 v 4.2 c 0 0.5 0.3 0.8 1 0.8 h 4.8 c 0.5 0 0.8 -0.3 0.8 -0.8 V 0.9 c 0.1 -0.6 -0.2 -0.9 -0.7 -0.9 Z"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -9,16 +9,20 @@ import { Constants } from '../Constants';
import { vscodeEnvironment } from '../helpers';
import { Output } from '../Output';
import { Telemetry } from '../TelemetryClient';
import { BlockchainDataManagerResource } from './Operations/BlockchainDataManagerResource';
import { ConsortiumResource } from './Operations/ConsortiumResource';
import { MemberResource } from './Operations/MemberResource';
import { SkuResource } from './Operations/SkuResources';
import { TransactionNodeResource } from './Operations/TransactionNodeResource';
const { preview20180601, preview20190601 } = Constants.azureApiVersions;
export class AzureBlockchainServiceClient extends AzureServiceClient {
public memberResource: MemberResource;
public transactionNodeResource: TransactionNodeResource;
public consortiumResource: ConsortiumResource;
public skuResource: SkuResource;
public bdmResource: BlockchainDataManagerResource;
constructor(
credentials: ServiceClientCredentials | UserTokenCredentials,
@ -26,7 +30,6 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
public readonly resourceGroup: string,
public readonly location: string,
public readonly baseUri: string,
public readonly apiVersion: string,
public readonly options: AzureServiceClientOptions,
) {
super(credentials, options);
@ -49,10 +52,11 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
this.transactionNodeResource = new TransactionNodeResource(this);
this.consortiumResource = new ConsortiumResource(this);
this.skuResource = new SkuResource(this);
this.bdmResource = new BlockchainDataManagerResource(this);
}
public async createConsortium(memberName: string, body: string): Promise<void> {
const url = this.getUrl(memberName, true, true);
const url = this.getUrl(memberName, preview20180601, true, true);
const urlDetailsOfConsortium = url.slice(url.indexOf('subscriptions'), url.lastIndexOf(memberName)) + memberName;
const httpRequest = this.getHttpRequest(url, 'PUT', body);
@ -78,8 +82,40 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
});
}
public getBlockchainDataManagers(callback: (error: Error | null, result?: any) => void): Promise<void> {
const url = this.getUrl('watchers', preview20190601, true, false);
const httpRequest = this.getHttpRequest(url, 'GET');
return this.sendRequestToAzure(httpRequest, callback);
}
public getBlockchainDataManagerApplications(bdmName: string, callback: (error: Error | null, result?: any) => void)
: Promise<void> {
const url =
this.getUrl(`watchers/${bdmName}/artifacts`, preview20190601, true, false);
const httpRequest = this.getHttpRequest(url, 'GET');
return this.sendRequestToAzure(httpRequest, callback);
}
public getBlockchainDataManagerInputs(bdmName: string, callback: (error: Error | null, result?: any) => void)
: Promise<void> {
const url = this.getUrl(`watchers/${bdmName}/inputs`, preview20190601, true, false);
const httpRequest = this.getHttpRequest(url, 'GET');
return this.sendRequestToAzure(httpRequest, callback);
}
public getBlockchainDataManagerOutputs(bdmName: string, callback: (error: Error | null, result?: any) => void)
: Promise<void> {
const url = this.getUrl(`watchers/${bdmName}/outputs`, preview20190601, true, false);
const httpRequest = this.getHttpRequest(url, 'GET');
return this.sendRequestToAzure(httpRequest, callback);
}
public getMembers(memberName: string, callback: (error: Error | null, result?: any) => void): Promise<void> {
const url = this.getUrl(`${memberName}/ConsortiumMembers`, true, true);
const url = this.getUrl(`${memberName}/ConsortiumMembers`, preview20180601, true, true);
const httpRequest = this.getHttpRequest(url, 'GET');
@ -87,7 +123,7 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
}
public getConsortia(callback: (error: Error | null, result?: any) => void): Promise<void> {
const url = this.getUrl('', true, true);
const url = this.getUrl('', preview20180601, true, true);
const httpRequest = this.getHttpRequest(url, 'GET');
@ -95,7 +131,7 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
}
public getTransactionNodes(memberName: string, callback: (error: Error | null, result?: any) => void): Promise<void> {
const url = this.getUrl(`${memberName}/transactionNodes`, true, true);
const url = this.getUrl(`${memberName}/transactionNodes`, preview20180601, true, true);
const httpRequest = this.getHttpRequest(url, 'GET');
@ -111,7 +147,7 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
? `${memberName}/listApikeys`
: `${memberName}/transactionNodes/${nodeName}/listApikeys`;
const url = this.getUrl(mainPartOfUrl, true, true);
const url = this.getUrl(mainPartOfUrl, preview20180601, true, true);
const httpRequest = this.getHttpRequest(url, 'POST');
@ -119,7 +155,7 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
}
public getSkus(callback: (error: Error | null, result?: any) => void): Promise<void> {
const url = this.getUrl('skus');
const url = this.getUrl('skus', preview20180601);
const httpRequest = this.getHttpRequest(url, 'GET');
@ -180,7 +216,7 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
nameAvailable: boolean,
reason: string,
}> {
const url = this.getUrl(`locations/${this.location}/checkNameAvailability`);
const url = this.getUrl(`locations/${this.location}/checkNameAvailability`, preview20180601);
const request = this.getHttpRequest(
url,
@ -202,12 +238,16 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
});
}
private getUrl(mainPartOfUrl: string, useResourceGroup: boolean = false, useBlockchainMembers: boolean = false)
private getUrl(
mainPartOfUrl: string,
apiVersion: string,
useResourceGroup: boolean = false,
useBlockchainMembers: boolean = false)
: string {
const resourceGroup = useResourceGroup ? `resourceGroups/${this.resourceGroup}/` : '';
const blockchainMember = useBlockchainMembers ? 'blockchainMembers/' : '';
return `${this.baseUri}/subscriptions/${this.subscriptionId}/${resourceGroup}` +
`providers/Microsoft.Blockchain/${blockchainMember}${mainPartOfUrl}?api-version=${this.apiVersion}`;
`providers/Microsoft.Blockchain/${blockchainMember}${mainPartOfUrl}?api-version=${apiVersion}`;
}
}

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export interface IAzureBlockchainDataManagerApplicationDto {
id: string;
name: string;
properties: {
artifactType: string;
content: {
abiFileUrl: string;
bytecodeFileUrl: string;
queryTargetTypes: string[];
};
state: string;
provisioningState: string;
createdTime: string;
lastUpdatedTime: string;
};
type: string;
}

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { ISkuDto } from '..';
export interface IAzureBlockchainDataManagerDto {
id: string;
location: string;
name: string;
properties: {
createdTime: string;
lastUpdatedTime: string;
provisioningState: string;
sku: ISkuDto;
state: string;
uniqueId: string;
};
tags: {};
type: string;
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export interface IAzureBlockchainDataManagerInputDto {
id: string;
name: string;
properties: {
inputType: string;
dataSource: {
resourceId: string;
};
};
type: string;
}

Просмотреть файл

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export interface IAzureBlockchainDataManagerOutputDto {
id: string;
name: string;
properties: {
outputType: string;
dataSource: {
resourceId: string;
};
state: string;
createdTime: string;
lastUpdatedTime: string;
};
type: string;
}

Просмотреть файл

@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import {
IAzureBlockchainDataManagerApplicationDto,
IAzureBlockchainDataManagerDto,
IAzureBlockchainDataManagerInputDto,
IAzureBlockchainDataManagerOutputDto,
} from '..';
import { AzureBlockchainServiceClient } from '../AzureBlockchainServiceClient';
export class BlockchainDataManagerResource {
constructor(public readonly client: AzureBlockchainServiceClient) {}
public async getListBlockchainDataManager(): Promise<IAzureBlockchainDataManagerDto[]> {
return new Promise((resolve, reject) => {
return this.client.getBlockchainDataManagers((error: Error | null, result?: any) => {
if (error) {
reject(error);
} else {
resolve(Object.assign([], result.value));
}
});
});
}
public async getListBlockchainDataManagerApplication(bdmName: string)
: Promise<IAzureBlockchainDataManagerApplicationDto[]> {
return new Promise((resolve, reject) => {
return this.client.getBlockchainDataManagerApplications(bdmName, (error: Error | null, result?: any) => {
if (error) {
reject(error);
} else {
resolve(Object.assign([], result.value));
}
});
});
}
public async getListBlockchainDataManagerInput(bdmName: string)
: Promise<IAzureBlockchainDataManagerInputDto[]> {
return new Promise((resolve, reject) => {
return this.client.getBlockchainDataManagerInputs(bdmName, (error: Error | null, result?: any) => {
if (error) {
reject(error);
} else {
resolve(Object.assign([], result.value));
}
});
});
}
public async getListBlockchainDataManagerOutput(bdmName: string)
: Promise<IAzureBlockchainDataManagerOutputDto[]> {
return new Promise((resolve, reject) => {
return this.client.getBlockchainDataManagerOutputs(bdmName, (error: Error | null, result?: any) => {
if (error) {
reject(error);
} else {
resolve(Object.assign([], result.value));
}
});
});
}
}

Просмотреть файл

@ -2,6 +2,10 @@
// Licensed under the MIT license.
import { AzureBlockchainServiceClient } from './AzureBlockchainServiceClient';
import { IAzureBlockchainDataManagerApplicationDto } from './AzureDto/BlockchainDataManagerApplicationDto';
import { IAzureBlockchainDataManagerDto } from './AzureDto/BlockchainDataManagerDto';
import { IAzureBlockchainDataManagerInputDto } from './AzureDto/BlockchainDataManagerInputDto';
import { IAzureBlockchainDataManagerOutputDto } from './AzureDto/BlockchainDataManagerOutputDto';
import { IAzureConsortiumDto } from './AzureDto/ConsortiumDto';
import { IAzureConsortiumMemberDto } from './AzureDto/ConsortiumMemberDto';
import { IAzureMemberDto } from './AzureDto/MemberDto';
@ -14,6 +18,10 @@ import { SkuResource } from './Operations/SkuResources';
export {
AzureBlockchainServiceClient,
IAzureBlockchainDataManagerApplicationDto,
IAzureBlockchainDataManagerDto,
IAzureBlockchainDataManagerInputDto,
IAzureBlockchainDataManagerOutputDto,
IAzureConsortiumDto,
IAzureConsortiumMemberDto,
IAzureMemberDto,

Просмотреть файл

@ -170,8 +170,8 @@ export class Constants {
};
public static confirmationDialogResult = {
no: 'no',
yes: 'yes',
no: 'No',
yes: 'Yes',
};
public static mnemonicConstants = {
@ -203,7 +203,116 @@ export class Constants {
valueOrDefault: Constants.getMessageValueOrDefault,
};
public static treeItemData = {
group: {
azure: {
member: {
contextValue: 'member',
iconPath: { dark: '', light: '' },
},
},
bdm: {
input: {
contextValue: 'inputGroup',
iconPath: { dark: '', light: '' },
label: 'Inputs',
},
output: {
contextValue: 'outputGroup',
iconPath: { dark: '', light: '' },
label: 'Outputs',
},
},
},
network: {
azure: {
contextValue: 'network',
iconPath: { dark: '', light: '' },
},
bdm: {
application: {
contextValue: 'bdmApplication',
iconPath: { dark: '', light: '' },
},
input: {
contextValue: 'input',
iconPath: { dark: '', light: '' },
},
output: {
contextValue: 'output',
iconPath: { dark: '', light: '' },
},
},
default: {
contextValue: 'network',
iconPath: { dark: '', light: '' },
},
infura: {
contextValue: 'network',
iconPath: { dark: '', light: '' },
},
local: {
contextValue: 'localnetwork',
iconPath: { dark: '', light: '' },
},
},
project: {
azure: {
contextValue: 'project',
iconPath: { dark: '', light: '' },
},
bdm: {
contextValue: 'project',
iconPath: { dark: '', light: '' },
},
default: {
contextValue: 'project',
iconPath: { dark: '', light: '' },
},
infura: {
contextValue: 'project',
iconPath: { dark: '', light: '' },
},
local: {
contextValue: 'localproject',
iconPath: { dark: '', light: '' },
},
},
service: {
azure: {
contextValue: 'service',
iconPath: { dark: '', light: '' },
label: 'Azure Blockchain Service',
prefix: 'abs',
},
bdm: {
contextValue: 'service',
iconPath: { dark: '', light: '' },
label: 'Blockchain Data Manager',
prefix: 'bdm',
},
default: {
contextValue: 'service',
iconPath: { dark: '', light: '' },
label: 'Default Service',
},
infura: {
contextValue: 'service',
iconPath: { dark: '', light: '' },
label: 'Infura Service',
prefix: 'inf',
},
local: {
contextValue: 'service',
iconPath: { dark: '', light: '' },
label: 'Local Service',
prefix: 'loc',
},
},
};
public static validationRegexps = {
array: /^\[.*\]$/g,
forbiddenChars: {
dotAtTheEnd: /^(?=.*[.]$).*$/g,
networkName: /[^0-9a-z]/g,
@ -217,6 +326,7 @@ export class Constants {
isUrl: /^(?:http(s)?:\/\/)?[\w:@.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=]+$/igm,
lowerCaseLetter: /(?=.*[a-z]).*/g,
moduleExportsTemplate: /{(.*)}$/g,
onlyNumber: /^(-\d+|\d+)$/g,
// tslint:disable-next-line: max-line-length
port: /^([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/,
specialChars: {
@ -224,6 +334,14 @@ export class Constants {
password: /[!@$^&()+=?\/<>|[\]{}_:.\\~]/g,
resourceGroupName: /[-\w.()]/g,
},
types: {
simpleArray: /\w+\[\]/g,
simpleMapping: /^\[.+\]$/g,
solidityAddress: /^(0x)[a-zA-Z0-9]{40}$/g,
solidityInt: /^int\d+$/g,
solidityInteger: /u*int\d*/g,
solidityUint: /^uint\d+$/g,
},
upperCaseLetter: /(?=.*[A-Z]).*/g,
};
@ -232,6 +350,9 @@ export class Constants {
};
public static validationMessages = {
arrayElementsShouldBeValid: (elementsType: string) => {
return `Array elements should have valid value of type ${elementsType}`;
},
forbiddenChars: {
dotAtTheEnd: "Input value must not have '.' at the end.",
networkName: 'Invalid name. Name can contain only lowercase letters and numbers.',
@ -266,8 +387,18 @@ export class Constants {
projectIdAlreadyExists: 'Network with project ID already exists.',
resourceGroupAlreadyExists: Constants.getMessageResourceGroupAlreadyExist,
unresolvedSymbols: Constants.getMessageInputHasUnresolvedSymbols,
valueCanSafelyStoreUpToBits: (pow: string) => {
return `Value can only safely store up to ${pow} bits`;
},
valueCannotBeEmpty: 'Value cannot be empty.',
valueShouldBeArray: 'Value should be the array and enclosed in \[ \]',
valueShouldBeBool: 'Value should be true or false.',
valueShouldBeNumber: 'Value should be a number.',
valueShouldBeNumberOrEmpty: 'Value should be a number or empty.',
valueShouldBePositiveAndCanSafelyStoreUpToBits: (pow: string) => {
return `Value should be positive and can only safely store up to ${pow} bits`;
},
valueShouldBeSolidityAddress: 'Value should be the correct solidity address.',
};
public static placeholders = {
@ -277,6 +408,7 @@ export class Constants {
generateMnemonic: 'Generate mnemonic',
pasteMnemonic: 'Paste mnemonic',
resourceGroupName: 'Resource Group Name',
selectBlockchainDataManagerInstance: 'Select Blockchain Data Manager instance',
selectConsortium: 'Select consortium',
selectDeployDestination: 'Select deploy destination',
selectDestination: 'Select destination',
@ -294,76 +426,6 @@ export class Constants {
setupMnemonic: 'Setup mnemonic',
};
public static treeItemData = {
member: {
azure: {
contextValue: 'member',
iconPath: { dark: '', light: ''},
},
},
network: {
azure: {
contextValue: 'network',
iconPath: { dark: '', light: ''},
},
default: {
contextValue: 'network',
iconPath: { dark: '', light: ''},
},
infura: {
contextValue: 'network',
iconPath: { dark: '', light: ''},
},
local: {
contextValue: 'localnetwork',
iconPath: { dark: '', light: ''},
},
},
project: {
azure: {
contextValue: 'project',
iconPath: { dark: '', light: ''},
},
default: {
contextValue: 'project',
iconPath: { dark: '', light: ''},
},
infura: {
contextValue: 'project',
iconPath: { dark: '', light: ''},
},
local: {
contextValue: 'localproject',
iconPath: { dark: '', light: ''},
},
},
service: {
azure: {
contextValue: 'service',
iconPath: { dark: '', light: ''},
label: 'Azure Blockchain Service',
prefix: 'abs',
},
default: {
contextValue: 'service',
iconPath: { dark: '', light: ''},
label: 'Default Service',
},
infura: {
contextValue: 'service',
iconPath: { dark: '', light: ''},
label: 'Infura Service',
prefix: 'inf',
},
local: {
contextValue: 'service',
iconPath: { dark: '', light: ''},
label: 'Local Service',
prefix: 'loc',
},
},
};
// More information see here
// https://ethereum.stackexchange.com/questions/17051/how-to-select-a-network-id-or-is-there-a-list-of-network-ids
public static infuraEndpointsIds: { [key: string]: number } = {
@ -444,7 +506,7 @@ export class Constants {
AstIsEmpty: 'enums could not be extracted, current AST is empty',
BuildContractsBeforeGenerating: 'Please build contracts before generating',
BuildContractsDirIsEmpty: Constants.getMessageContractsBuildDirectoryIsEmpty,
BuildContractsDirIsNotExist: Constants.getMessageContractsBuildDirectoryIsNotExist,
BuildContractsDirDoesNotExist: Constants.getMessageContractsBuildDirectoryDoesNotExist,
CompiledContractIsMissing: 'Compiled contract is missing for solidity file.',
DirectoryIsNotEmpty: 'Directory is not empty. Open another one?',
ErrorWhileExecutingCommand: 'Error while executing command: ',
@ -543,19 +605,32 @@ export class Constants {
public static azureApps = {
AzureFunction: { label: 'Azure Function', serviceType: 2, outputDir: 'generatedAzureFunction' },
FlowApp: { label: 'Flow App', serviceType: 0, outputDir: 'generatedFlowApp' },
LogicApp: { label: 'Logic App', serviceType: 1, outputDir: 'generatedLogicApp'},
LogicApp: { label: 'Logic App', serviceType: 1, outputDir: 'generatedLogicApp' },
};
public static azureApiVersions = {
preview20180601: '2018-06-01-preview',
preview20190601: '2019-06-01-preview',
};
public static azureResourceExplorer = {
contentType: 'application/json',
portalBasUri: 'https://portal.azure.com/#@microsoft.onmicrosoft.com',
portalBasUri: 'https://ms.portal.azure.com/#@microsoft.onmicrosoft.com',
portalBladeUri: 'https://ms.portal.azure.com/#blade/ManagedLedgerExtension/TransactionNodeMenuBlade',
providerName: 'Microsoft.Blockchain',
requestAcceptLanguage: 'en-US',
requestApiVersion: '2018-06-01-preview',
requestBaseUri: 'https://management.azure.com',
resourceType: 'blockchainMembers',
};
public static solidityTypes = {
address: 'address',
bool: 'bool',
int: 'int',
string: 'string',
uint: 'uint',
};
public static firstOZVersion = '2.3.0';
public static allOpenZeppelinVersions = ['2.3.0', '2.4.0'];
public static ozVersionUserSettingsKey = 'azureBlockchainService.openZeppelin.version';
@ -563,6 +638,9 @@ export class Constants {
public static openZeppelin = {
cancelButtonTitle: 'Cancel',
contractsUpgradeIsFailed: 'Upgrade of OpenZeppelin contracts has failed',
contactParameterInformation(contractName: string, parameterName: string, parameterType: string) {
return `Contract: ${contractName}. Parameter: ${parameterName}: ${parameterType}`;
},
descriptionDownloadingFailed: 'Description downloading failed',
downloadingContractsFromOpenZeppelin: 'Downloading contracts from OpenZeppelin',
exploreDownloadedContractsInfo: 'Explore more information about the contracts downloaded',
@ -574,8 +652,10 @@ export class Constants {
replaceButtonTitle: 'Replace',
retryButtonTitle: 'Retry',
retryDownloading: 'Retry downloading',
saveSpecifiedParameters: 'Not all contract parameters were defined. Do you want to save the progress?',
selectCategoryForDownloading: 'Select category for downloading',
skipButtonTitle: 'Skip files',
specifyContractParameters: 'Some contracts have parameters required for deploy. Do you want to specify them?',
upgradeOpenZeppelin: 'Upgrading OpenZeppelin',
hashCalculationFailed(errorMessage: string): string {
return `Error while calculating file hash. Message: ${errorMessage}`;
@ -588,8 +668,8 @@ export class Constants {
},
alreadyExisted(existing: IOZAsset[]): string {
return `OpenZeppelin: (${existing.length}) files already exist on disk: `
+ existing.slice(0, 3).map((contract) => contract.name).join(' ')
+ (existing.length > 3 ? '...' : '');
+ existing.slice(0, 3).map((contract) => contract.name).join(' ')
+ (existing.length > 3 ? '...' : '');
},
invalidHashMessage(contractPath: string): string {
return `${contractPath} - invalid hash`;
@ -608,7 +688,7 @@ export class Constants {
},
invalidVersionDialog(version: string, location: string, lastVersion: string) {
return `There is invalid OpenZeppelin version (${version}) in ${location}. ` +
`Do you want to use the latest one (${lastVersion})?`;
`Do you want to use the latest one (${lastVersion})?`;
},
};
@ -623,11 +703,21 @@ export class Constants {
this.infuraFileResponse.path = context.asAbsolutePath(path.join('resources', 'codeFlowResult', 'index.html'));
this.infuraFileResponse.css = context.asAbsolutePath(path.join('resources', 'codeFlowResult', 'main.css'));
this.treeItemData.member.azure.iconPath = {
this.treeItemData.group.azure.member.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'ABS-member.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'ABS-member.svg')),
};
this.treeItemData.group.bdm.input.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'BlockchainDataManagerGroupInput.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'BlockchainDataManagerGroupInput.svg')),
};
this.treeItemData.group.bdm.output.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'BlockchainDataManagerGroupOutput.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'BlockchainDataManagerGroupOutput.svg')),
};
this.treeItemData.network.default.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'EthereumNetwork.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'EthereumNetwork.svg')),
@ -638,6 +728,21 @@ export class Constants {
light: context.asAbsolutePath(path.join('resources/light', 'ABNetwork.svg')),
};
this.treeItemData.network.bdm.application.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'BlockchainDataManagerApplication.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'BlockchainDataManagerApplication.svg')),
};
this.treeItemData.network.bdm.input.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'ABNetwork.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'ABNetwork.svg')),
};
this.treeItemData.network.bdm.output.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'BlockchainDataManagerOutput.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'BlockchainDataManagerOutput.svg')),
};
this.treeItemData.network.infura.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'EthereumNetwork.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'EthereumNetwork.svg')),
@ -653,6 +758,11 @@ export class Constants {
light: context.asAbsolutePath(path.join('resources/light', 'ABS-consortium.svg')),
};
this.treeItemData.project.bdm.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'BlockchainDataManager-service_and_project.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'BlockchainDataManager-service_and_project.svg')),
};
this.treeItemData.project.infura.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'InfuraProject.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'InfuraProject.svg')),
@ -668,6 +778,11 @@ export class Constants {
light: context.asAbsolutePath(path.join('resources/light', 'ABS-service.svg')),
};
this.treeItemData.service.bdm.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'BlockchainDataManager-service_and_project.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'BlockchainDataManager-service_and_project.svg')),
};
this.treeItemData.service.infura.iconPath = {
dark: context.asAbsolutePath(path.join('resources/dark', 'InfuraService.svg')),
light: context.asAbsolutePath(path.join('resources/light', 'InfuraService.svg')),
@ -697,8 +812,8 @@ export class Constants {
return `Contracts build directory "${buildDirPath}" is empty.`;
}
private static getMessageContractsBuildDirectoryIsNotExist(buildDirPath: string): string {
return `Contracts build directory "${buildDirPath}" is not exist.`;
private static getMessageContractsBuildDirectoryDoesNotExist(buildDirPath: string): string {
return `Contracts build directory "${buildDirPath}" does not exist.`;
}
private static getMessageNetworkAlreadyExist(networkName: string): string {

Просмотреть файл

@ -81,10 +81,10 @@ export class LogicAppGenerator {
const files: string[] = [];
if (!fs.pathExistsSync(buildDir)) {
Telemetry.sendException(new Error(Constants.errorMessageStrings.BuildContractsDirIsNotExist(
Telemetry.sendException(new Error(Constants.errorMessageStrings.BuildContractsDirDoesNotExist(
Telemetry.obfuscate(buildDir),
)));
throw new Error(Constants.errorMessageStrings.BuildContractsDirIsNotExist(buildDir));
throw new Error(Constants.errorMessageStrings.BuildContractsDirDoesNotExist(buildDir));
}
if (filePath) {

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { ItemType } from '../../ItemType';
import { BlockchainDataManagerInputAndOutput } from '../../TreeItems/BlockchainDataManager/BlockchainDataManagerInputAndOutput';
import { ItemCreator } from '../ItemCreator';
export class BlockchainDataManagerInputAndOutputItemCreator extends ItemCreator {
protected getRequiredFields(): Array<{ fieldName: string, type: string }> {
const requiredFields = super.getRequiredFields();
requiredFields.push(...[
{ fieldName: 'label', type: 'string' },
]);
return requiredFields;
}
protected getAdditionalConstructorArguments(obj: { [key: string]: any }): any[] {
return [
...super.getAdditionalConstructorArguments(obj),
obj.label,
obj.itemType,
];
}
protected createFromObject(
label: string,
itemType: ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP | ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT_GROUP,
): BlockchainDataManagerInputAndOutput {
return new BlockchainDataManagerInputAndOutput(itemType, label);
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { ItemType } from '../../ItemType';
import { BlockchainDataManagerNetworkNode } from '../../TreeItems';
import { NetworkNodeItemCreator } from '../NetworkNodeItemCreator';
export class BlockchainDataManagerNetworkNodeItemCreator extends NetworkNodeItemCreator {
protected getRequiredFields(): Array<{ fieldName: string, type: string }> {
const requiredFields = super.getRequiredFields();
requiredFields.push(...[
{ fieldName: 'subscriptionId', type: 'string' },
{ fieldName: 'resourceGroup', type: 'string' },
]);
return requiredFields;
}
protected getAdditionalConstructorArguments(obj: { [key: string]: any }): any[] {
return [
...super.getAdditionalConstructorArguments(obj),
obj.subscriptionId,
obj.resourceGroup,
obj.itemType,
];
}
protected createFromObject(
label: string,
url: string,
networkId: string,
subscriptionId: string,
resourceGroup: string,
itemType: ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION |
ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT |
ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT,
): BlockchainDataManagerNetworkNode {
return new BlockchainDataManagerNetworkNode(label, networkId, subscriptionId, resourceGroup, itemType, url);
}
}

Просмотреть файл

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { BlockchainDataManagerProject } from '../../TreeItems';
import { ItemCreator } from '../ItemCreator';
export class BlockchainDataManagerProjectItemCreator extends ItemCreator {
protected getRequiredFields(): Array<{ fieldName: string, type: string }> {
const requiredFields = super.getRequiredFields();
requiredFields.push(...[
{ fieldName: 'label', type: 'string' },
{ fieldName: 'subscriptionId', type: 'string' },
{ fieldName: 'resourceGroup', type: 'string' },
]);
return requiredFields;
}
protected getAdditionalConstructorArguments(obj: { [key: string]: any }): any[] {
return [
obj.label,
obj.subscriptionId,
obj.resourceGroup,
];
}
protected createFromObject(
label: string,
subscriptionId: string,
resourceGroup: string,
): BlockchainDataManagerProject {
return new BlockchainDataManagerProject(label, subscriptionId, resourceGroup);
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { BlockchainDataManagerService } from '../../TreeItems';
import { ItemCreator } from '../ItemCreator';
export class BlockchainDataManagerServiceItemCreator extends ItemCreator {
protected createFromObject(): BlockchainDataManagerService {
return new BlockchainDataManagerService();
}
}

Просмотреть файл

@ -4,6 +4,10 @@
export * from './AzureBlockchainNetworkNodeItemCreator';
export * from './AzureBlockchainProjectItemCreator';
export * from './AzureBlockchainServiceItemCreator';
export * from './BlockchainDataManager/BlockchainDataManagerNetworkNodeItemCreator';
export * from './BlockchainDataManager/BlockchainDataManagerProjectItemCreator';
export * from './BlockchainDataManager/BlockchainDataManagerServiceItemCreator';
export * from './BlockchainDataManager/BlockchainDataManagerInputAndOutputItemCreator';
export * from './CommandItemCreator';
export * from './InfuraNetworkNodeItemCreator';
export * from './InfuraProjectItemCreator';

Просмотреть файл

@ -21,4 +21,12 @@ export enum ItemType {
INFURA_SERVICE = 40,
INFURA_PROJECT = 41,
INFURA_NETWORK_NODE = 42,
BLOCKCHAIN_DATA_MANAGER_SERVICE = 50,
BLOCKCHAIN_DATA_MANAGER_PROJECT = 51,
BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP = 52,
BLOCKCHAIN_DATA_MANAGER_INPUT = 53,
BLOCKCHAIN_DATA_MANAGER_OUTPUT_GROUP = 54,
BLOCKCHAIN_DATA_MANAGER_OUTPUT = 55,
BLOCKCHAIN_DATA_MANAGER_APPLICATION = 56,
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { QuickPickItem } from 'vscode';
export class BlockchainDataManagerInstanceItem implements QuickPickItem {
public readonly bdmName: string;
public readonly uniqueId: string;
public readonly resourceGroup: string;
public readonly subscriptionId: string;
public readonly label: string;
constructor(bdmName: string, subscriptionId: string, resourceGroup: string, uniqueId: string) {
this.bdmName = bdmName;
this.subscriptionId = subscriptionId;
this.resourceGroup = resourceGroup;
this.uniqueId = uniqueId;
this.label = bdmName;
}
}

Просмотреть файл

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export * from './BlockchainDataManagerInstanceItem';
export * from './ConsortiumItem';
export * from './InfuraProjectItem';
export * from './LocationItem';

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Constants } from '../../../Constants';
import { ItemType } from '../../ItemType';
import { ExtensionItemData } from '../ExtensionItem';
import { Group } from '../Group';
const { input, output } = Constants.treeItemData.group.bdm;
export class BlockchainDataManagerInputAndOutput extends Group {
constructor(
itemType: ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP | ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT_GROUP,
label: string,
) {
const data: ExtensionItemData = itemType === ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP ? input : output;
super(itemType, label, data);
}
}

Просмотреть файл

@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Constants } from '../../../Constants';
import { ItemType } from '../../ItemType';
import { ExtensionItemData } from '../ExtensionItem';
import { NetworkNode } from '../NetworkNode';
const { application, input, output } = Constants.treeItemData.network.bdm;
export class BlockchainDataManagerNetworkNode extends NetworkNode {
public readonly subscriptionId: string;
public readonly resourceGroup: string;
constructor(
label: string,
networkId: number | string,
subscriptionId: string,
resourceGroup: string,
itemType: ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION |
ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT |
ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT,
url: string,
) {
const data: ExtensionItemData =
itemType === ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION ? application :
itemType === ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT ? input : output;
super(
itemType,
label,
data,
url,
networkId,
);
this.subscriptionId = subscriptionId;
this.resourceGroup = resourceGroup;
}
public toJSON(): { [key: string]: any } {
const obj = super.toJSON();
obj.subscriptionId = this.subscriptionId;
obj.resourceGroup = this.resourceGroup;
return obj;
}
protected async getGasPrice(): Promise<number | undefined> {
return 0;
}
protected async getGasLimit(): Promise<number | undefined> {
return 0;
}
protected defaultProtocol(): string {
return Constants.networkProtocols.http;
}
}

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Constants } from '../../../Constants';
import { IDeployDestination } from '../../IDeployDestination';
import { ItemType } from '../../ItemType';
import { Project } from '../Project';
export class BlockchainDataManagerProject extends Project {
public readonly subscriptionId: string;
public readonly resourceGroup: string;
constructor(label: string, subscriptionId: string, resourceGroup: string) {
super(
ItemType.BLOCKCHAIN_DATA_MANAGER_PROJECT,
label,
Constants.treeItemData.project.bdm,
);
this.subscriptionId = subscriptionId;
this.resourceGroup = resourceGroup;
}
public toJSON(): { [p: string]: any } {
const obj = super.toJSON();
obj.subscriptionId = this.subscriptionId;
obj.resourceGroup = this.resourceGroup;
return obj;
}
public getDeployDestinations(): Promise<IDeployDestination[]> {
throw new Error('Method not implemented.');
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Constants } from '../../../Constants';
import { ItemType } from '../../ItemType';
import { Service } from '../Service';
export class BlockchainDataManagerService extends Service {
constructor() {
super(
ItemType.BLOCKCHAIN_DATA_MANAGER_SERVICE,
Constants.treeItemData.service.bdm.label,
Constants.treeItemData.service.bdm,
);
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { ItemType } from '../ItemType';
import { ExtensionItem, ExtensionItemData } from './ExtensionItem';
export type GroupTypes =
ItemType.MEMBER |
ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP |
ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT_GROUP;
export abstract class Group extends ExtensionItem {
protected constructor(itemType: GroupTypes, label: string, data: ExtensionItemData) {
super(itemType, label, data);
}
}

Просмотреть файл

@ -3,10 +3,10 @@
import { Constants } from '../../Constants';
import { ItemType } from '../ItemType';
import { ExtensionItem } from './ExtensionItem';
import { Group } from './Group';
export class Member extends ExtensionItem {
export class Member extends Group {
constructor(label: string) {
super(ItemType.MEMBER, label, Constants.treeItemData.member.azure);
super(ItemType.MEMBER, label, Constants.treeItemData.group.azure.member);
}
}

Просмотреть файл

@ -17,7 +17,10 @@ const protocolRegExp = new RegExp('^(' +
export type NetworkNodeTypes =
ItemType.AZURE_BLOCKCHAIN_NETWORK_NODE |
ItemType.LOCAL_NETWORK_NODE |
ItemType.INFURA_NETWORK_NODE;
ItemType.INFURA_NETWORK_NODE |
ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION |
ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT |
ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT;
export abstract class NetworkNode extends ExtensionItem {
public readonly networkId: number | string;

Просмотреть файл

@ -6,7 +6,11 @@ import { ItemType } from '../ItemType';
import { ExtensionItem, ExtensionItemData } from './ExtensionItem';
import { NetworkNode } from './NetworkNode';
export type ProjectTypes = ItemType.AZURE_BLOCKCHAIN_PROJECT | ItemType.LOCAL_PROJECT | ItemType.INFURA_PROJECT;
export type ProjectTypes =
ItemType.AZURE_BLOCKCHAIN_PROJECT |
ItemType.LOCAL_PROJECT |
ItemType.INFURA_PROJECT |
ItemType.BLOCKCHAIN_DATA_MANAGER_PROJECT;
export abstract class Project extends ExtensionItem {
protected constructor(itemType: ProjectTypes, label: string, data: ExtensionItemData) {

Просмотреть файл

@ -8,6 +8,7 @@ export type ServiceTypes =
ItemType.AZURE_BLOCKCHAIN_SERVICE |
ItemType.LOCAL_SERVICE |
ItemType.INFURA_SERVICE |
ItemType.BLOCKCHAIN_DATA_MANAGER_SERVICE |
ItemType.COMMAND;
export abstract class Service extends ExtensionItem {

Просмотреть файл

@ -4,8 +4,13 @@
export * from './AzureBlockchainNetworkNode';
export * from './AzureBlockchainProject';
export * from './AzureBlockchainService';
export * from './BlockchainDataManager/BlockchainDataManagerNetworkNode';
export * from './BlockchainDataManager/BlockchainDataManagerProject';
export * from './BlockchainDataManager/BlockchainDataManagerService';
export * from './BlockchainDataManager/BlockchainDataManagerInputAndOutput';
export * from './Command';
export * from './ExtensionItem';
export * from './Group';
export * from './IExtensionItem';
export * from './InfuraNetworkNode';
export * from './InfuraProject';

Просмотреть файл

@ -10,6 +10,10 @@ import {
AzureBlockchainNetworkNodeItemCreator,
AzureBlockchainProjectItemCreator,
AzureBlockchainServiceItemCreator,
BlockchainDataManagerInputAndOutputItemCreator,
BlockchainDataManagerNetworkNodeItemCreator,
BlockchainDataManagerProjectItemCreator,
BlockchainDataManagerServiceItemCreator,
CommandItemCreator,
InfuraNetworkNodeItemCreator,
InfuraProjectItemCreator,
@ -29,13 +33,24 @@ ItemFactory.register(ItemType.NULLABLE, new NullableItemCreator());
ItemFactory.register(ItemType.AZURE_BLOCKCHAIN_SERVICE, new AzureBlockchainServiceItemCreator());
ItemFactory.register(ItemType.LOCAL_SERVICE, new LocalServiceItemCreator());
ItemFactory.register(ItemType.INFURA_SERVICE, new InfuraServiceItemCreator());
ItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_SERVICE, new BlockchainDataManagerServiceItemCreator());
ItemFactory.register(ItemType.AZURE_BLOCKCHAIN_PROJECT, new AzureBlockchainProjectItemCreator());
ItemFactory.register(ItemType.LOCAL_PROJECT, new LocalProjectItemCreator());
ItemFactory.register(ItemType.INFURA_PROJECT, new InfuraProjectItemCreator());
ItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_PROJECT, new BlockchainDataManagerProjectItemCreator());
ItemFactory.register(ItemType.AZURE_BLOCKCHAIN_NETWORK_NODE, new AzureBlockchainNetworkNodeItemCreator());
ItemFactory.register(ItemType.LOCAL_NETWORK_NODE, new LocalNetworkNodeItemCreator());
ItemFactory.register(ItemType.INFURA_NETWORK_NODE, new InfuraNetworkNodeItemCreator());
ItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION, new BlockchainDataManagerNetworkNodeItemCreator());
ItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT, new BlockchainDataManagerNetworkNodeItemCreator());
ItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT, new BlockchainDataManagerNetworkNodeItemCreator());
ItemFactory.register(ItemType.MEMBER, new MemberItemCreator());
ItemFactory.register(
ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP,
new BlockchainDataManagerInputAndOutputItemCreator());
ItemFactory.register(
ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT_GROUP,
new BlockchainDataManagerInputAndOutputItemCreator());

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Group } from '../Models/TreeItems/Group';
import { ExtensionView } from './ExtensionView';
export class GroupView extends ExtensionView<Group> {
constructor(groupItem: Group) {
super(groupItem);
}
}

Просмотреть файл

@ -1,11 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Member } from '../Models/TreeItems/Member';
import { ExtensionView } from './ExtensionView';
export class MemberView extends ExtensionView<Member> {
constructor(memberItem: Member) {
super(memberItem);
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Group } from '../../Models/TreeItems';
import { GroupView } from '../GroupView';
import { ViewCreator } from './ViewCreator';
export class GroupViewCreator extends ViewCreator {
public create(groupItem: Group): GroupView {
return new GroupView(groupItem);
}
}

Просмотреть файл

@ -1,12 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Member } from '../../Models/TreeItems';
import { MemberView } from '../MemberView';
import { ViewCreator } from './ViewCreator';
export class MemberViewCreator extends ViewCreator {
public create(memberItem: Member): MemberView {
return new MemberView(memberItem);
}
}

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export * from './MemberViewCreator';
export * from './GroupViewCreator';
export * from './NetworkNodeViewCreator';
export * from './NullableViewCreator';
export * from './ProjectViewCreator';

Просмотреть файл

@ -3,7 +3,7 @@
export * from './ExtensionView';
export * from './IExtensionView';
export * from './MemberView';
export * from './GroupView';
export * from './NetworkNodeView';
export * from './NullableView';
export * from './ProjectView';
@ -12,7 +12,7 @@ export * from './ViewItemFactory';
import { ItemType } from '../Models';
import {
MemberViewCreator,
GroupViewCreator,
NetworkNodeViewCreator,
NullableViewCreator,
ProjectViewCreator,
@ -26,13 +26,20 @@ ViewItemFactory.register(ItemType.NULLABLE, new NullableViewCreator());
ViewItemFactory.register(ItemType.AZURE_BLOCKCHAIN_SERVICE, new ServiceViewCreator());
ViewItemFactory.register(ItemType.LOCAL_SERVICE, new ServiceViewCreator());
ViewItemFactory.register(ItemType.INFURA_SERVICE, new ServiceViewCreator());
ViewItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_SERVICE, new ServiceViewCreator());
ViewItemFactory.register(ItemType.AZURE_BLOCKCHAIN_PROJECT, new ProjectViewCreator());
ViewItemFactory.register(ItemType.LOCAL_PROJECT, new ProjectViewCreator());
ViewItemFactory.register(ItemType.INFURA_PROJECT, new ProjectViewCreator());
ViewItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_PROJECT, new ProjectViewCreator());
ViewItemFactory.register(ItemType.AZURE_BLOCKCHAIN_NETWORK_NODE, new NetworkNodeViewCreator());
ViewItemFactory.register(ItemType.LOCAL_NETWORK_NODE, new NetworkNodeViewCreator());
ViewItemFactory.register(ItemType.INFURA_NETWORK_NODE, new NetworkNodeViewCreator());
ViewItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION, new NetworkNodeViewCreator());
ViewItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT, new NetworkNodeViewCreator());
ViewItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT, new NetworkNodeViewCreator());
ViewItemFactory.register(ItemType.MEMBER, new MemberViewCreator());
ViewItemFactory.register(ItemType.MEMBER, new GroupViewCreator());
ViewItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP, new GroupViewCreator());
ViewItemFactory.register(ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT_GROUP, new GroupViewCreator());

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import open = require('open');
import * as open from 'open';
import { ProgressLocation, window } from 'vscode';
import { Constants } from '../Constants';
import { openZeppelinHelper, showQuickPick } from '../helpers';
@ -36,11 +36,16 @@ export namespace OpenZeppelinCommands {
const downloadedAssets
= await downloadOZFiles(baseUrl, assetsStatuses.existing, assetsStatuses.missing, fullAssetWithDependencies);
await OpenZeppelinService.updateProjectJsonAsync(manifest.getVersion(), category, downloadedAssets);
const mergedAssets = await OpenZeppelinService.mergeAssetsWithExisting(downloadedAssets);
await OpenZeppelinService.updateProjectJsonAsync(manifest.getVersion(), category, mergedAssets);
openDocumentationUrl(manifest.getCategoryApiDocumentationUrl(category));
Telemetry.sendEvent('OpenZeppelinCommands.addCategory.generateMigrations');
await openZeppelinHelper.defineContractRequiredParameters();
await OpenZeppelinMigrationsService.generateMigrations(await OpenZeppelinService.getAllDownloadedAssetsAsync());
}
}

Просмотреть файл

@ -1,12 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as open from 'open';
import { Constants } from '../Constants';
import { showQuickPick } from '../helpers';
import { ItemType } from '../Models';
import {
AzureBlockchainProject,
AzureBlockchainService,
BlockchainDataManagerProject,
BlockchainDataManagerService,
InfuraProject,
InfuraService,
LocalProject,
@ -15,10 +18,15 @@ import {
Service,
ServiceTypes,
} from '../Models/TreeItems';
import { ConsortiumResourceExplorer, InfuraResourceExplorer, LocalResourceExplorer } from '../resourceExplorers';
import {
BlockchainDataManagerResourceExplorer,
ConsortiumResourceExplorer,
InfuraResourceExplorer,
LocalResourceExplorer,
} from '../resourceExplorers';
import { GanacheService, TreeManager } from '../services';
import { Telemetry } from '../TelemetryClient';
import { ProjectView } from '../ViewItems';
import { NetworkNodeView, ProjectView } from '../ViewItems';
interface IServiceDestination {
cmd: (service: Service) => Promise<Project>;
@ -71,6 +79,11 @@ export namespace ServiceCommands {
itemType: ItemType.INFURA_SERVICE,
label: Constants.treeItemData.service.infura.label,
},
{
cmd: connectBlockchainDataManagerProject,
itemType: ItemType.BLOCKCHAIN_DATA_MANAGER_SERVICE,
label: Constants.treeItemData.service.bdm.label,
},
];
const project = await execute(serviceDestinations);
@ -93,6 +106,10 @@ export namespace ServiceCommands {
await TreeManager.removeItem(viewItem.extensionItem);
Telemetry.sendEvent('ServiceCommands.disconnectProject.commandFinished');
}
export function openAtAzurePortal(viewItem: NetworkNodeView): void {
open(viewItem.extensionItem.url.href);
}
}
async function execute(serviceDestinations: IServiceDestination[]): Promise<Project> {
@ -180,3 +197,16 @@ async function getExistingPorts(service: LocalService): Promise<number[]> {
const localProjects = service.getChildren() as LocalProject[];
return localProjects.map((item) => item.port);
}
// ------------ BLOCKCHAIN DATA MANAGER ------------ //
async function connectBlockchainDataManagerProject(service: BlockchainDataManagerService)
: Promise<BlockchainDataManagerProject> {
const bdmResourceExplorer = new BlockchainDataManagerResourceExplorer();
return bdmResourceExplorer.selectProject(await getExistingBlockchainDataManager(service));
}
async function getExistingBlockchainDataManager(service: BlockchainDataManagerService): Promise<string[]> {
const bdmProjects = service.getChildren() as BlockchainDataManagerProject[];
return bdmProjects.map((item) => item.label);
}

Просмотреть файл

@ -22,7 +22,7 @@ import {
} from '../helpers';
import { IDeployDestination, ItemType } from '../Models';
import { NetworkForContractItem } from '../Models/QuickPickItems/NetworkForContractItem';
import { LocalService } from '../Models/TreeItems';
import { AzureBlockchainProject, InfuraProject, LocalProject, LocalService } from '../Models/TreeItems';
import { Project } from '../Models/TreeItems';
import { Output } from '../Output';
import {
@ -76,6 +76,8 @@ export namespace TruffleCommands {
export async function deployContracts(): Promise<void> {
Telemetry.sendEvent('TruffleCommands.deployContracts.commandStarted');
await checkOpenZeppelinIfUsed();
const truffleConfigsUri = TruffleConfiguration.getTruffleConfigUri();
const defaultDeployDestinations = getDefaultDeployDestinations(truffleConfigsUri);
const truffleDeployDestinations = await getTruffleDeployDestinations(truffleConfigsUri);
@ -101,7 +103,6 @@ export namespace TruffleCommands {
{ url: Telemetry.obfuscate(command.description || '') },
);
await checkOpenZeppelinIfUsed();
await command.cmd();
Telemetry.sendEvent('TruffleCommands.deployContracts.commandFinished');
@ -228,6 +229,7 @@ async function checkOpenZeppelinIfUsed(): Promise<void> {
}
await validateOpenZeppelinContracts();
await openZeppelinHelper.defineContractRequiredParameters();
}
}
@ -279,7 +281,9 @@ async function validateOpenZeppelinContracts(): Promise<void> {
const errorMsg = Constants.validationMessages.openZeppelinFilesAreInvalid(invalidContractsPaths);
const error = new Error(errorMsg);
window.showErrorMessage(errorMsg);
Telemetry.sendException(error);
const obfuscatedPaths = invalidContractsPaths.map((invalidContractsPath) =>
Telemetry.obfuscate(invalidContractsPath));
Telemetry.sendException(new Error(Constants.validationMessages.openZeppelinFilesAreInvalid(obfuscatedPaths)));
throw error;
}
}
@ -336,7 +340,12 @@ async function getProjectDeployDestinationItems(projects: Project[], truffleConf
: Promise<IDeployDestinationItem[]> {
const destinations: IDeployDestination[] = [];
for (const project of projects) {
const filteredProjects = projects.filter((project) =>
project instanceof AzureBlockchainProject ||
project instanceof InfuraProject ||
project instanceof LocalProject);
for (const project of filteredProjects) {
const projectDestinations = await project.getDeployDestinations();
destinations.push(...projectDestinations);
}
@ -361,8 +370,7 @@ async function getTruffleDeployFunction(
port?: number)
: Promise<() => Promise<void>> {
const treeProjectNames = await getTreeProjectNames();
if (port !== undefined &&
(treeProjectNames.includes(name) || name === Constants.localhostName)) {
if (port !== undefined && (treeProjectNames.includes(name) || name === Constants.localhostName)) {
Telemetry.sendEvent('TruffleCommands.getTruffleDeployFunction.returnDeployToLocalGanache');
return deployToLocalGanache.bind(undefined, name, truffleConfigPath, port);
}

Просмотреть файл

@ -28,7 +28,7 @@ import {
TreeService,
} from './services';
import { Telemetry } from './TelemetryClient';
import { ProjectView } from './ViewItems';
import { NetworkNodeView, ProjectView } from './ViewItems';
import { DebuggerConfiguration } from './debugAdapter/configuration/debuggerConfiguration';
@ -117,6 +117,8 @@ export async function activate(context: ExtensionContext) {
async (viewItem: ProjectView) => {
await tryExecute(() => ServiceCommands.disconnectProject(viewItem));
});
const openAtAzurePortal = commands.registerCommand('azureBlockchainService.openAtAzurePortal',
async (viewItem: NetworkNodeView) => ServiceCommands.openAtAzurePortal(viewItem));
//#endregion
//#region Infura commands
@ -131,8 +133,8 @@ export async function activate(context: ExtensionContext) {
async () => {
await tryExecute(() => InfuraCommands.showProjectsFromAccount());
});
//#endregion
//#region contract commands
const showSmartContractPage = commands.registerCommand(
'azureBlockchainService.showSmartContractPage',
@ -209,6 +211,7 @@ export async function activate(context: ExtensionContext) {
signOutOfInfuraAccount,
showProjectsFromInfuraAccount,
openZeppelinAddCategory,
openAtAzurePortal,
];
context.subscriptions.push(...subscriptions);

Просмотреть файл

@ -0,0 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export const bigIntMath = {
// eval required because babel translate ** to Math.pow
// tslint:disable-next-line:no-eval
pow: (value: BigInt, pow: number) => BigInt(eval(`BigInt(${value}) ** BigInt(${pow})`)),
};

Просмотреть файл

@ -1,8 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
const maxLength = 4095;
const truffleConfig = require(process.argv[2]);
const path = require('path');
try {
const hdwalletNodeModulePath = path.join(process.cwd(), 'node_modules', 'truffle-hdwallet-provider');
require(hdwalletNodeModulePath);
require.cache[require.resolve(hdwalletNodeModulePath)].exports = function HDWallet(...args) {
this.mnemonic = args[0];
this.url = args[1];
};
} catch (err) {
// ignore
}
const truffleConfig = require(path.join(process.cwd(), 'truffle-config.js'));
const getCircularReplacer = () => {
const seen = new WeakSet();
@ -15,7 +27,11 @@ const getCircularReplacer = () => {
}
if (typeof v === 'function') {
return v.toString();
if (k !== 'provider') {
return v.toString();
}
return v.call(truffleConfig);
}
return v;
@ -24,16 +40,4 @@ const getCircularReplacer = () => {
let message = JSON.stringify(truffleConfig, getCircularReplacer());
if (message.length > maxLength) {
for (let i = 0; i < message.length; i++) {
const index = Math.min(maxLength, message.length);
const str = message.substr(0, index);
message = message.substr(index);
process.send({ command: 'truffleConfig', batch: { index: i, done: message.length === 0, message: str} });
}
} else {
process.send({ command: 'truffleConfig', message: message });
}
setTimeout(() => process.exit(), 1000);
process.send({ command: 'truffleConfig', message: message }, () => process.exit());

Просмотреть файл

@ -2,13 +2,15 @@
// Licensed under the MIT license.
import { ProgressLocation, window } from 'vscode';
import { showConfirmDialogToUpdateOpenZeppelin, userSettings } from '.';
import { showConfirmationDialog, showInputBox, userSettings } from '.';
import { Constants } from '../Constants';
import { OpenZeppelinService } from '../services';
import { CancellationEvent } from '../Models';
import { OpenZeppelinMigrationsService, OpenZeppelinProjectJsonService, OpenZeppelinService } from '../services';
import { CurrentOpenZeppelinVersionLocation, InvalidOpenZeppelinVersionException } from '../services/openZeppelin/InvalidOpenZeppelinVersionException';
import { IOZMetadata } from '../services/openZeppelin/models';
import { IOZAsset, IOZMetadata } from '../services/openZeppelin/models';
import { OpenZeppelinManifest } from '../services/openZeppelin/OpenZeppelinManifest';
import { Telemetry } from '../TelemetryClient';
import { validateSolidityType } from '../validators/solidityTypeValidation';
export async function createManifestAsync(version: string): Promise<OpenZeppelinManifest> {
const metadata = await getManifestMetadata(version);
@ -49,7 +51,7 @@ export async function shouldUpgradeOpenZeppelinAsync(): Promise<boolean> {
const currentVersion = await tryGetCurrentOpenZeppelinVersionAsync();
const latestVersion = await OpenZeppelinService.getLatestOpenZeppelinVersionAsync();
return currentVersion !== latestVersion && await showConfirmDialogToUpdateOpenZeppelin();
return currentVersion !== latestVersion && await showConfirmationDialog(Constants.openZeppelin.newVersionAvailable);
}
export async function upgradeOpenZeppelinUserSettingsAsync() {
@ -68,10 +70,98 @@ export async function upgradeOpenZeppelinContractsAsync()
const latestVersion = await OpenZeppelinService.getLatestOpenZeppelinVersionAsync();
const manifest = await createManifestAsync(latestVersion);
return OpenZeppelinService.updateOpenZeppelinContractsAsync(manifest);
await OpenZeppelinService.updateOpenZeppelinContractsAsync(manifest);
await OpenZeppelinMigrationsService.generateMigrations(await OpenZeppelinService.getAllDownloadedAssetsAsync());
});
}
export async function defineContractRequiredParameters(): Promise<void> {
const assetsWithNotSpecifiedRequiredParameters = await getAssetsWithNotSpecifiedRequiredParameters();
if (assetsWithNotSpecifiedRequiredParameters.length === 0) {
return;
}
if (await showConfirmationDialog(Constants.openZeppelin.specifyContractParameters)) {
await setContractParameters(assetsWithNotSpecifiedRequiredParameters);
}
await OpenZeppelinMigrationsService.generateMigrations(await OpenZeppelinService.getAllDownloadedAssetsAsync());
}
function getManifestMetadata(version: string): IOZMetadata {
return require(`../services/openZeppelin/manifest-${version}.json`) as IOZMetadata;
}
async function setContractParameters(assets: IOZAsset[]): Promise<void> {
const projectMetadata = await OpenZeppelinProjectJsonService.getProjectJson();
try {
for (const asset of assets) {
for (const [contractName, contractParameters] of Object.entries(asset.requiredParameters!)) {
for (const parameter of contractParameters) {
if (!parameter.value) {
parameter.value = await showInputBox({
ignoreFocusOut: true,
prompt: Constants.openZeppelin.contactParameterInformation(
contractName,
parameter.name,
parameter.type,
),
validateInput: (v) => validateSolidityType(v, parameter.type),
});
}
}
}
}
await OpenZeppelinProjectJsonService.addAssetsToProjectJsonAsync(
assets,
projectMetadata);
await OpenZeppelinProjectJsonService.storeProjectJsonAsync(projectMetadata);
} catch (error) {
if (await showConfirmationDialog(Constants.openZeppelin.saveSpecifiedParameters)) {
await OpenZeppelinProjectJsonService.addAssetsToProjectJsonAsync(
assets,
projectMetadata);
await OpenZeppelinProjectJsonService.storeProjectJsonAsync(projectMetadata);
}
if (error instanceof CancellationEvent) {
return;
} else {
throw error;
}
}
}
async function getAssetsWithNotSpecifiedRequiredParameters() {
const currentOZVersion = await tryGetCurrentOpenZeppelinVersionAsync();
const manifest = await createManifestAsync(currentOZVersion);
const manifestAssets = manifest.getAssets();
const currentAssets = await OpenZeppelinService.getAllDownloadedAssetsAsync();
return currentAssets.reduce((assets, asset) => {
const manifestAsset = manifestAssets.find((assetFromManifest) => assetFromManifest.id === asset.id);
if (manifestAsset && !!manifestAsset.requiredParameters) {
if (!!asset.requiredParameters) {
for (const [contractName, contractParameters] of Object.entries(asset.requiredParameters)) {
const manifestContractParameters = manifestAsset.requiredParameters[contractName];
if (manifestContractParameters) {
for (const parameter of contractParameters) {
if (parameter.value === undefined) {
const param = manifestContractParameters.find((manifestContractParameter) =>
manifestContractParameter.name === parameter.name &&
manifestContractParameter.type === parameter.type);
if (param) {
assets.push(asset);
return assets;
}
}
}
}
}
} else {
assets.push(JSON.parse(JSON.stringify(manifestAsset)));
}
}
return assets;
}, [] as IOZAsset[]);
}

Просмотреть файл

@ -276,10 +276,8 @@ export namespace TruffleConfiguration {
async function getTruffleMetadata(): Promise<IConfiguration> {
const truffleConfigTemplatePath = path.join(__dirname, 'checkTruffleConfigTemplate.js');
const truffleConfigPath =
path.relative(path.dirname(truffleConfigTemplatePath), path.join(getWorkspaceRoot()!, 'truffle-config.js'));
const result = await tryExecuteCommandInFork(getWorkspaceRoot()!, truffleConfigTemplatePath, truffleConfigPath);
const result = await tryExecuteCommandInFork(getWorkspaceRoot()!, truffleConfigTemplatePath);
const truffleConfigObject = result.messages!.find((message) => message.command === 'truffleConfig');
if (!truffleConfigObject || !truffleConfigObject.message) {
@ -512,9 +510,17 @@ export namespace TruffleConfiguration {
const { contracts_directory, contracts_build_directory, migrations_directory }
= Constants.truffleConfigDefaultDirectory;
truffleConfig.contracts_directory = truffleConfig.contracts_directory || contracts_directory;
truffleConfig.contracts_build_directory = truffleConfig.contracts_build_directory || contracts_build_directory;
truffleConfig.migrations_directory = truffleConfig.migrations_directory || migrations_directory;
if (!truffleConfig.hasOwnProperty('contracts_directory')) {
truffleConfig.contracts_directory = contracts_directory;
}
if (!truffleConfig.hasOwnProperty('contracts_build_directory')) {
truffleConfig.contracts_build_directory = contracts_build_directory;
}
if (!truffleConfig.hasOwnProperty('migrations_directory')) {
truffleConfig.migrations_directory = migrations_directory;
}
const arrayNetwork: INetwork[] = [];

Просмотреть файл

@ -55,7 +55,7 @@ export async function showConfirmPaidOperationDialog() {
validateInput: DialogResultValidator.validateConfirmationResult,
});
if (answer.toLowerCase() !== Constants.confirmationDialogResult.yes) {
if (answer.toLowerCase() !== Constants.confirmationDialogResult.yes.toLowerCase()) {
Telemetry.sendEvent(
'userInteraction.showConfirmPaidOperationDialog.userCancellation',
{ prompt: Constants.placeholders.confirmPaidOperation });
@ -117,11 +117,12 @@ export async function saveTextInFile(
return file.fsPath;
}
export async function showConfirmDialogToUpdateOpenZeppelin(): Promise<boolean> {
export async function showConfirmationDialog(message: string): Promise<boolean> {
const answer = await window.showInformationMessage(
Constants.openZeppelin.newVersionAvailable,
message,
Constants.confirmationDialogResult.yes,
Constants.confirmationDialogResult.no);
Constants.confirmationDialogResult.no,
);
return answer === Constants.confirmationDialogResult.yes;
}

Просмотреть файл

@ -0,0 +1,211 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { QuickPickItem } from 'vscode';
import { AzureBlockchainServiceClient, IAzureBlockchainDataManagerDto } from '../ARMBlockchain';
import { Constants } from '../Constants';
import { showQuickPick } from '../helpers';
import { ItemType } from '../Models/ItemType';
import { BlockchainDataManagerInstanceItem, ResourceGroupItem, SubscriptionItem } from '../Models/QuickPickItems';
import { BlockchainDataManagerInputAndOutput, BlockchainDataManagerNetworkNode, BlockchainDataManagerProject } from '../Models/TreeItems';
import { Telemetry } from '../TelemetryClient';
import { AzureResourceExplorer } from './AzureResourceExplorer';
export class BlockchainDataManagerResourceExplorer extends AzureResourceExplorer {
public async selectProject(existingProjects: string[] = []): Promise<BlockchainDataManagerProject> {
Telemetry.sendEvent('BlockchainDataManagerResourceExplorer.selectProject');
await this.waitForLogin();
const subscriptionItem = await this.getOrSelectSubscriptionItem();
const resourceGroupItem = await this.getOrCreateResourceGroupItem(subscriptionItem);
const azureClient = await this.getAzureClient(subscriptionItem, resourceGroupItem);
const pick = await showQuickPick(
this.getBlockchainDataManagerInstanceItems(azureClient, subscriptionItem, resourceGroupItem, existingProjects),
{ placeHolder: Constants.placeholders.selectBlockchainDataManagerInstance, ignoreFocusOut: true },
);
if (pick instanceof BlockchainDataManagerInstanceItem) {
Telemetry.sendEvent('BlockchainDataManagerResourceExplorer.selectProject.selectBlockchainDataManagerProject');
return this.getBlockchainDataManagerInstance(pick, azureClient);
} else {
Telemetry.sendEvent('BlockchainDataManagerResourceExplorer.selectProject.createBlockchainDataManagerProject');
// TODO: implement createBlockchainDataManagerInstance
return Promise.resolve({} as BlockchainDataManagerProject);
}
}
private async getBlockchainDataManagerInstanceItems(
azureClient: AzureBlockchainServiceClient,
subscriptionItem: SubscriptionItem,
resourceGroupItem: ResourceGroupItem,
excludedItems: string[] = [])
: Promise<QuickPickItem[]> {
const items: QuickPickItem[] = [];
// TODO: add logic for create BlockchainDataManager project
const bdmItems =
await this.loadBlockchainDataManagerInstanceItem(azureClient, subscriptionItem, resourceGroupItem, excludedItems);
items.push(...bdmItems);
return items;
}
private async loadBlockchainDataManagerInstanceItem(
azureClient: AzureBlockchainServiceClient,
subscriptionItem: SubscriptionItem,
resourceGroupItem: ResourceGroupItem,
excludedItems: string[] = [])
: Promise<BlockchainDataManagerInstanceItem[]> {
const bdmItems: IAzureBlockchainDataManagerDto[] = await azureClient.bdmResource.getListBlockchainDataManager();
return bdmItems
.filter((item) => !excludedItems.includes(item.name))
.map((item) => new BlockchainDataManagerInstanceItem(
item.name,
subscriptionItem.subscriptionId,
resourceGroupItem.label,
item.properties.uniqueId,
))
.sort((a, b) => a.label.localeCompare(b.label));
}
private async getBlockchainDataManagerInstance(
bdmInstanceItem: BlockchainDataManagerInstanceItem,
azureClient: AzureBlockchainServiceClient)
: Promise<BlockchainDataManagerProject> {
const { bdmName, subscriptionId, resourceGroup } = bdmInstanceItem;
const bdmProject = new BlockchainDataManagerProject(bdmName, subscriptionId, resourceGroup);
const bdmApplications = await this.getBlockchainDataManagerApplications(bdmInstanceItem, azureClient);
const bdmInputs = await this.getBlockchainDataManagerInputs(bdmInstanceItem, azureClient);
const bdmOutputs = await this.getBlockchainDataManagerOutputs(bdmInstanceItem, azureClient);
bdmProject.setChildren([...bdmApplications, bdmInputs, bdmOutputs]);
return bdmProject;
}
private async getBlockchainDataManagerApplications(
bdmInstanceItem: BlockchainDataManagerInstanceItem,
azureClient: AzureBlockchainServiceClient)
: Promise<BlockchainDataManagerNetworkNode[]> {
const { bdmName, subscriptionId, resourceGroup } = bdmInstanceItem;
const listBDMApplication = await azureClient.bdmResource.getListBlockchainDataManagerApplication(bdmName);
return listBDMApplication.map((applicaion) => {
const indexRemovingRoute = applicaion.id.lastIndexOf('/artifacts');
const url = `${Constants.azureResourceExplorer.portalBasUri}/resource${applicaion.id.slice(0, indexRemovingRoute)}/blockchainapplications`;
return new BlockchainDataManagerNetworkNode(
applicaion.name,
'*',
subscriptionId,
resourceGroup,
ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION,
url);
});
}
private async getBlockchainDataManagerInputs(
bdmInstanceItem: BlockchainDataManagerInstanceItem,
azureClient: AzureBlockchainServiceClient)
: Promise<BlockchainDataManagerInputAndOutput> {
const { bdmName, subscriptionId, resourceGroup } = bdmInstanceItem;
const listBDMInput = await azureClient.bdmResource.getListBlockchainDataManagerInput(bdmName);
const bdmInputs = listBDMInput.map((input) => {
return new BlockchainDataManagerNetworkNode(
input.name,
'*',
subscriptionId,
resourceGroup,
ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT,
this.getInputUrl(input.properties.dataSource.resourceId));
});
const inputs = new BlockchainDataManagerInputAndOutput(
ItemType.BLOCKCHAIN_DATA_MANAGER_INPUT_GROUP,
Constants.treeItemData.group.bdm.input.label,
);
inputs.setChildren(bdmInputs);
return inputs;
}
private async getBlockchainDataManagerOutputs(
bdmInstanceItem: BlockchainDataManagerInstanceItem,
azureClient: AzureBlockchainServiceClient)
: Promise<BlockchainDataManagerInputAndOutput> {
const { bdmName, subscriptionId, resourceGroup } = bdmInstanceItem;
const listBDMOutput = await azureClient.bdmResource.getListBlockchainDataManagerOutput(bdmName);
const bdmOutputs = listBDMOutput.map((output) => {
const indexRemovingRoute = output.id.lastIndexOf('/outputs');
const url = `${Constants.azureResourceExplorer.portalBasUri}/resource${output.id.slice(0, indexRemovingRoute)}/outboundconnections`;
return new BlockchainDataManagerNetworkNode(
output.name,
'*',
subscriptionId,
resourceGroup,
ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT,
url);
});
const outputs = new BlockchainDataManagerInputAndOutput(
ItemType.BLOCKCHAIN_DATA_MANAGER_OUTPUT_GROUP,
Constants.treeItemData.group.bdm.output.label,
);
outputs.setChildren(bdmOutputs);
return outputs;
}
private getInputUrl(url: string): string {
const firstMark = 'blockchainMembers/';
const defaultInputTransactionNode = 'transaction-node';
const nodeName = 'nodeName';
const idxOfMemberAndTransactionNode = url.lastIndexOf(firstMark) + firstMark.length;
const relativeInternalPath = url.substring(0, idxOfMemberAndTransactionNode).split('/').join('%2F');
let memberAndTransactionNode = url.substring(idxOfMemberAndTransactionNode)
.replace('transactionNodes', nodeName);
if (memberAndTransactionNode.includes(defaultInputTransactionNode)) {
const memberName = memberAndTransactionNode.substring(0, memberAndTransactionNode.indexOf('/' + nodeName));
memberAndTransactionNode = memberAndTransactionNode.replace(defaultInputTransactionNode, memberName);
}
return `${Constants.azureResourceExplorer.portalBladeUri}/overview/memberResourceId/` +
relativeInternalPath + memberAndTransactionNode;
}
private async getAzureClient(subscriptionItem: SubscriptionItem, resourceGroupItem: ResourceGroupItem)
: Promise<AzureBlockchainServiceClient> {
return new AzureBlockchainServiceClient(
subscriptionItem.session.credentials,
subscriptionItem.subscriptionId,
resourceGroupItem.label,
resourceGroupItem.description,
Constants.azureResourceExplorer.requestBaseUri,
{
acceptLanguage: Constants.azureResourceExplorer.requestAcceptLanguage,
filters: [],
generateClientRequestId: true,
longRunningOperationRetryTimeout: 30,
noRetryPolicy: false,
requestOptions: {
customHeaders: {},
},
rpRegistrationRetryTimeout: 30,
},
);
}
}

Просмотреть файл

@ -87,7 +87,6 @@ export class ConsortiumResourceExplorer extends AzureResourceExplorer {
resourceGroupItem.label,
resourceGroupItem.description,
Constants.azureResourceExplorer.requestBaseUri,
Constants.azureResourceExplorer.requestApiVersion,
{
acceptLanguage: Constants.azureResourceExplorer.requestAcceptLanguage,
filters: [],

Просмотреть файл

@ -2,6 +2,7 @@
// Licensed under the MIT license.
export * from './AzureResourceExplorer';
export * from './BlockchainDataManagerResourceExplorer';
export * from './ConsortiumResourceExplorer';
export * from './InfuraResourceExplorer';
export * from './LocalResourceExplorer';

Просмотреть файл

@ -6,6 +6,7 @@ import * as path from 'path';
import { HttpService } from '..';
import { Constants } from '../../Constants';
import { getWorkspaceRoot, TruffleConfiguration } from '../../helpers';
import { Telemetry } from '../../TelemetryClient';
import { Contract } from './Contract';
export namespace ContractService {
@ -68,7 +69,7 @@ export namespace ContractService {
const buildDir = await getPathDirectory('contracts_build_directory');
if (!fs.pathExistsSync(buildDir)) {
throw new Error(Constants.errorMessageStrings.BuildContractsDirIsNotExist(buildDir));
throw new Error(Constants.errorMessageStrings.BuildContractsDirDoesNotExist(Telemetry.obfuscate(buildDir)));
}
return fs.readdirSync(buildDir)

Просмотреть файл

@ -15,3 +15,4 @@ export * from './tree/TreeService';
export * from './openZeppelin/OpenZeppelinService';
export * from './openZeppelin/OpenZeppelinMigrationsService';
export * from './infuraService/InfuraServiceClient';
export * from './openZeppelin/OpenZeppelinProjectJsonService';

Просмотреть файл

@ -54,7 +54,10 @@ function generateContractDeployerSection(items: IOZAsset[]): string {
const contractNames = OpenZeppelinService.getContractsNamesFromAsset(asset);
return deployerSections
.concat(contractNames.map((contract) => ` deployer.deploy(${contract});`));
.concat(contractNames.map((contract) => {
const contractParameters = OpenZeppelinService.getContractParametersFromAsset(asset, contract);
return ` deployer.deploy(${[contract, ...contractParameters].join(', ')});`;
}));
}, [])
.join('\n');
}

Просмотреть файл

@ -62,28 +62,19 @@ export namespace OpenZeppelinProjectJsonService {
export async function addAssetsToProjectJsonAsync(
downloadedAssets: IOZAsset[],
makePersist: boolean = true,
updatingProjectMetadata?: IProjectMetadata,
overWrite: boolean = false)
projectMetadata: IProjectMetadata)
: Promise<IProjectMetadata> {
const projectMetadata = updatingProjectMetadata || await getProjectJson();
const newStored: IOZAsset[] = [];
newStored.push(...downloadedAssets);
if (!overWrite) {
projectMetadata.openZeppelin.assets.forEach((storedAsset) => {
if (!downloadedAssets.some((downloaded) => downloaded.id === storedAsset.id)) {
newStored.push(storedAsset);
}
});
}
projectMetadata.openZeppelin.assets.forEach((storedAsset) => {
if (!downloadedAssets.some((downloaded) => downloaded.id === storedAsset.id)) {
newStored.push(storedAsset);
}
});
projectMetadata.openZeppelin.assets = newStored;
if (makePersist) {
await storeProjectJsonAsync(projectMetadata);
}
return projectMetadata;
}

Просмотреть файл

@ -119,7 +119,7 @@ export namespace OpenZeppelinService {
updatedProjectJson = await OpenZeppelinProjectJsonService
.addCategoryToProjectJsonAsync(category, false, updatedProjectJson);
updatedProjectJson = await OpenZeppelinProjectJsonService
.addAssetsToProjectJsonAsync(assets, false, updatedProjectJson);
.addAssetsToProjectJsonAsync(assets, updatedProjectJson);
return OpenZeppelinProjectJsonService.storeProjectJsonAsync(updatedProjectJson);
}
@ -139,6 +139,30 @@ export namespace OpenZeppelinService {
return [];
}
export function getContractParametersFromAsset(asset: IOZAsset, contractName: string): string[] {
if (asset.requiredParameters) {
const parameters = asset.requiredParameters[contractName];
if (parameters) {
return parameters.reduce((arr: string[], param) => {
if (param.value) {
if (param.type === 'string') {
arr.push(`"${param.value}"`);
} else if (param.type.match(Constants.validationRegexps.types.simpleArray)) {
arr.push(getArrayParameterValue(param.value, param.type));
} else {
arr.push(param.value);
}
}
return arr;
}, []);
}
}
return [];
}
export function getContractNameByAssetName(asset: IOZAsset): string {
return path.parse(asset.name).name;
}
@ -205,7 +229,8 @@ export namespace OpenZeppelinService {
}
try {
await createNewProjectJsonAsync(newManifest.getVersion(), newAssets, tempNewOzFolder);
const mergedAssets = await mergeAssetsWithExisting(newAssets);
await createNewProjectJsonAsync(newManifest.getVersion(), mergedAssets, tempNewOzFolder);
} catch {
throwOpenZeppelinUpgradeException(userTmpFolderPath);
}
@ -225,6 +250,38 @@ export namespace OpenZeppelinService {
Telemetry.sendEvent('OpenZeppelinService.updateOpenZeppelinContractsAsync.finished');
}
export async function getAssetsWithParameters(): Promise<IOZAsset[]> {
const currentAssets = await getAllDownloadedAssetsAsync();
return currentAssets.filter((asset) => !!asset.requiredParameters);
}
export async function mergeAssetsWithExisting(currentAssets: IOZAsset[]): Promise<IOZAsset[]> {
const assetsWithParameters = await OpenZeppelinService.getAssetsWithParameters();
return currentAssets.map((asset) => {
if (asset.requiredParameters) {
const assetWithParameters = assetsWithParameters.find((element) => element.id === asset.id);
if (assetWithParameters && assetWithParameters.requiredParameters) {
for (const [currentContractName, currentContractParameters] of Object.entries(asset.requiredParameters)) {
const existedContractParameters = assetWithParameters.requiredParameters[currentContractName];
if (existedContractParameters) {
for (const parameter of currentContractParameters) {
const param = existedContractParameters.find((existedContractParameter) =>
existedContractParameter.name === parameter.name &&
existedContractParameter.type === parameter.type);
if (param) {
parameter.value = param.value;
}
}
}
}
}
}
return asset;
});
}
}
function getOzContractsFromProjectMetadata(
@ -285,7 +342,7 @@ async function moveProjectJsonAsync(nonUserProjectFolder: string, folderIsDestin
async function createNewProjectJsonAsync(version: string, assets: IOZAsset[], folder: string): Promise<void> {
let projectJson = OpenZeppelinProjectJsonService.getProjectJson();
projectJson = await OpenZeppelinProjectJsonService.addVersionToProjectJsonAsync(version, false, projectJson);
projectJson = await OpenZeppelinProjectJsonService.addAssetsToProjectJsonAsync(assets, false, projectJson, true);
projectJson = await OpenZeppelinProjectJsonService.addAssetsToProjectJsonAsync(assets, projectJson);
const newPath = path.join(folder, OpenZeppelinProjectJsonService.getProjectJsonFileName());
return OpenZeppelinProjectJsonService.storeProjectJsonAsync(projectJson, newPath);
@ -325,3 +382,13 @@ async function downloadNewVersionOfAssetsAsync(
return { isDownloadSucceed: true, newAssets };
}
function getArrayParameterValue(value: string, type: string): string {
if (type !== 'string[]') {
return value;
}
const elements = value.slice(1, value.length - 1).split(',');
const values = elements?.map((element) => `"${element.trim()}"`);
return `[${values?.join(', ')}]`;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -24,6 +24,13 @@ export interface IOZAsset {
type?: OZAssetType;
contracts?: string[];
dependencies: string[];
requiredParameters?: { [key: string]: IOZContractParameter[] };
}
export interface IOZContractParameter {
name: string;
type: string;
value?: string;
}
export interface IProjectMetadata {

Просмотреть файл

@ -6,6 +6,7 @@ import { Constants } from '../../Constants';
import { ItemFactory } from '../../Models';
import {
AzureBlockchainService,
BlockchainDataManagerService,
Command,
IExtensionItem,
InfuraService,
@ -101,7 +102,12 @@ class ExtensionTreeManager {
infuraService = new InfuraService();
}
return [ azureBlockchainService, infuraService, localService];
let bdmService = items.find((item) => item instanceof BlockchainDataManagerService);
if (!bdmService) {
bdmService = new BlockchainDataManagerService();
}
return [ azureBlockchainService, infuraService, localService, bdmService];
}
}

Просмотреть файл

@ -0,0 +1,85 @@
import { Constants } from '../../Constants';
import { bigIntMath } from '../../helpers/bigIntMath';
export function validateSolidityType(value: string, type: string): string | undefined {
if (type.match(Constants.validationRegexps.types.simpleMapping)) {
// Mapping type
return;
}
if (type.match(Constants.validationRegexps.types.simpleArray)) {
return validateSimpleArray(value, type.split('[]')[0]);
}
return validateElementaryType(value, type);
}
function validateElementaryType(value: string, type: string): string | undefined {
if (type.match(Constants.validationRegexps.types.solidityInteger)) {
return validateNumber(value, type);
}
switch (type) {
case Constants.solidityTypes.string:
return;
case Constants.solidityTypes.bool:
return value === 'true' || value === 'false' ? undefined : Constants.validationMessages.valueShouldBeBool;
case Constants.solidityTypes.address:
return value.match(Constants.validationRegexps.types.solidityAddress) ?
undefined :
Constants.validationMessages.valueShouldBeSolidityAddress;
default:
// TODO: validate other types
return;
}
}
function validateNumber(value: string, type: string): string | undefined {
if (!value.match(Constants.validationRegexps.onlyNumber)) {
return Constants.validationMessages.valueShouldBeNumber;
}
if (type.match(Constants.validationRegexps.types.solidityUint)) {
const pow = type.split(Constants.solidityTypes.uint)[1];
const maxUint = bigIntMath.pow(BigInt(2), parseInt(pow, 10)) - BigInt(1);
const valueAsNumber = BigInt(parseInt(value, 10));
if (valueAsNumber < BigInt(0) || valueAsNumber > maxUint) {
return Constants.validationMessages.valueShouldBePositiveAndCanSafelyStoreUpToBits(pow);
}
}
if (type.match(Constants.validationRegexps.types.solidityInt)) {
const pow = type.split(Constants.solidityTypes.int)[1];
const maxInt = bigIntMath.pow(BigInt(2), parseInt(pow, 10) - 1) - BigInt(1);
const minInt = -maxInt;
const valueAsNumber = BigInt(parseInt(value, 10));
if (valueAsNumber < minInt || valueAsNumber > maxInt) {
return Constants.validationMessages.valueCanSafelyStoreUpToBits(pow);
}
}
return;
}
function validateSimpleArray(value: string, elementsType: string): string | undefined {
if (!value.match(Constants.validationRegexps.array)) {
return Constants.validationMessages.valueShouldBeArray;
}
const values = value.slice(1, value.length - 1).split(',');
if (values.length === 0 ||
(values.length === 1 && values[0] === '')) {
return;
}
const invalidValues = values.filter((element) => {
const result = validateSolidityType(element.trim(), elementsType);
return !!result;
});
if (invalidValues.length > 0) {
return Constants.validationMessages.arrayElementsShouldBeValid(elementsType);
}
return;
}

Просмотреть файл

@ -15,7 +15,7 @@ export class IsConfirmationValue implements IRule {
}
public validate(value: string): string | null {
const isConfirmationValue = this.yesNoOptions.includes(value.toLowerCase());
const isConfirmationValue = this.yesNoOptions.map((option) => option.toLowerCase()).includes(value.toLowerCase());
return isConfirmationValue ? null : Constants.validationMessages.invalidConfirmationResult;
}
}

Просмотреть файл

@ -0,0 +1,198 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as assert from 'assert';
import { ServiceClientCredentials } from 'ms-rest';
import * as sinon from 'sinon';
import * as uuid from 'uuid';
import * as vscode from 'vscode';
import { AzureBlockchainServiceClient } from '../src/ARMBlockchain';
describe('Integration tests for AzureBlockchainServiceClient', () => {
let credentials: ServiceClientCredentials;
let subscriptionId: string;
let resourceGroup: string;
let baseUri: string;
let memberName: string;
let bdmName: string;
let transactionNode: string;
const azureBlockchainServiceClient = require('../src/ARMBlockchain/AzureBlockchainServiceClient');
const defaultResponseBody = '{ "message": "default response body" }';
let callbackFunction: (error: Error | null, result?: any) => void;
const incorrectResponseBody = uuid.v4();
let windowMock: sinon.SinonMock;
let showErrorMessageMock: sinon.SinonExpectation;
let pipelineMock: sinon.SinonStub<any[], any> | sinon.SinonStub<unknown[], {}>;
let serviceClient: AzureBlockchainServiceClient;
let callbackFunctionSpy: any;
before(() => {
credentials = {
signRequest: () => undefined,
};
callbackFunction = (_error: Error | null, _result?: any) => undefined;
});
beforeEach(() => {
subscriptionId = uuid.v4();
resourceGroup = uuid.v4();
baseUri = uuid.v4();
memberName = uuid.v4();
bdmName = uuid.v4();
transactionNode = uuid.v4();
sinon.stub(azureBlockchainServiceClient.__proto__, 'constructor');
windowMock = sinon.mock(vscode.window);
showErrorMessageMock = windowMock.expects('showErrorMessage');
const specialOptions = {
acceptLanguage: uuid.v4(),
generateClientRequestId: true,
};
serviceClient = new azureBlockchainServiceClient.AzureBlockchainServiceClient(
credentials,
subscriptionId,
resourceGroup,
baseUri,
specialOptions,
);
// @ts-ignore
pipelineMock = sinon.stub(serviceClient, 'pipeline');
callbackFunctionSpy = sinon.spy(callbackFunction);
});
afterEach(() => {
sinon.restore();
});
function assertRequestFailed(error: any, callbackSpy: sinon.SinonSpy<[Error | null, any?], void>): void {
assert.strictEqual(pipelineMock.calledOnce, true, 'pipeline should called once');
assert.strictEqual(
showErrorMessageMock.calledOnceWithExactly(error.message),
true,
'showErrorMessage should called once with correct arguments');
assert.strictEqual(
callbackSpy.calledOnceWithExactly(error as Error),
true,
'callbackFunction should called once with correct arguments');
}
function assertResponseNotSuccess(
callbackSpy: sinon.SinonSpy<[Error | null, any?], void>,
pipelineCallbackSpy: sinon.SinonSpy)
: void {
assert.strictEqual(pipelineMock.calledOnce, true, 'pipeline should called once');
assert.strictEqual(showErrorMessageMock.notCalled, true, 'showErrorMessage should not called');
assert.strictEqual(callbackSpy.calledOnce, true, 'callbackFunction should called once');
assert.strictEqual(
callbackSpy.args[0][0] instanceof Error,
true,
'callbackFunction should called with correct arguments');
assert.strictEqual(pipelineCallbackSpy.calledOnce, true, 'pipelineCallback should called once');
assert.strictEqual(
pipelineCallbackSpy.args[0][0],
null,
'callback function should called with correct arguments');
}
function assertResponseSuccess(
callbackSpy: sinon.SinonSpy<[Error | null, any?], void>,
pipelineCallbackSpy: sinon.SinonSpy,
parsedResult: any)
: void {
assert.strictEqual(pipelineMock.calledOnce, true, 'pipeline should called once');
assert.strictEqual(showErrorMessageMock.notCalled, true, 'showErrorMessage should not called');
assert.strictEqual(
callbackSpy.calledOnceWithExactly(null, parsedResult),
true,
'callbackFunction should called once with correct arguments');
assert.strictEqual(pipelineCallbackSpy.calledOnce, true, 'pipelineCallback should called once');
assert.strictEqual(
pipelineCallbackSpy.args[0][0],
null,
'callback function should called with correct arguments');
}
const listOfMethod = [
{ callback: async () => await serviceClient.getMembers('consortiumName', callbackFunctionSpy),
methodName: 'getMembers' },
{ callback: async () => await serviceClient.getTransactionNodes(memberName, callbackFunctionSpy),
methodName: 'getTransactionNodes' },
{ callback: async () =>
await serviceClient.getTransactionNodeAccessKeys(memberName, transactionNode, callbackFunctionSpy),
methodName: 'getTransactionNodeAccessKeys' },
{ callback: async () => await serviceClient.getSkus(callbackFunctionSpy),
methodName: 'getSkus' },
{ callback: async () => await serviceClient.getConsortia(callbackFunctionSpy),
methodName: 'getConsortia' },
{ callback: async () => await serviceClient.getBlockchainDataManagers(callbackFunctionSpy),
methodName: 'getBlockchainDataManagers' },
{ callback: async () => await serviceClient.getBlockchainDataManagerApplications(bdmName, callbackFunctionSpy),
methodName: 'getBlockchainDataManagerApplications' },
];
listOfMethod.forEach((method) => {
describe(method.methodName, () => {
it('shows error when request failed.', async () => {
// Arrange
const response = sinon.stub();
const error = { message: uuid.v4() };
pipelineMock.callsFake((...args: any[]): {} => {
return args[1](error, response, defaultResponseBody);
});
// Act
await method.callback();
// Assert
assertRequestFailed(error, callbackFunctionSpy);
});
describe('throws error when response is not success.', () => {
const responseData = [
[400, defaultResponseBody],
[103, defaultResponseBody],
[530, defaultResponseBody],
[200, incorrectResponseBody]];
responseData.forEach(async (response) => {
it(`response status code is ${response[0]} and response body is ${JSON.stringify(response[1])}.`,
async () => {
// Arrange
const res = {statusCode: response[0]};
let pipelineCallbackSpy: any;
pipelineMock.callsFake((...args: any[]): {} => {
pipelineCallbackSpy = sinon.spy(args[1]);
return pipelineCallbackSpy(null, res, response[1]);
});
// Act
await method.callback();
// Assert
assertResponseNotSuccess(callbackFunctionSpy, pipelineCallbackSpy);
});
});
});
it('does not throw error when response is success.', async () => {
// Arrange
const res = {statusCode: 200};
const parsedResult = JSON.parse(defaultResponseBody);
let pipelineCallbackSpy: any;
pipelineMock.callsFake((...args: any[]): {} => {
pipelineCallbackSpy = sinon.spy(args[1]);
return pipelineCallbackSpy(null, res, defaultResponseBody);
});
// Act
await method.callback();
// Assert
assertResponseSuccess(callbackFunctionSpy, pipelineCallbackSpy, parsedResult);
});
});
});
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -5,7 +5,7 @@ import * as assert from 'assert';
import rewire = require('rewire');
describe('TreeManager tests', () => {
const numberOfElements = 3;
const numberOfElements = 4;
it(`fillDefaultTypes should return array with ${numberOfElements} elements`, async () => {
// Arrange
const treeManagerRewire = rewire('../src/services/tree/TreeManager');

Просмотреть файл

@ -1,72 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as assert from 'assert';
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import { TruffleCommands } from '../../src/commands/TruffleCommands';
import { Constants } from '../../src/Constants';
describe('TruffleCommands', () => {
describe('Integration test', () => {
describe('Success path', () => {
const fileUri = {
fsPath: path.join(__dirname, 'testData', 'TestContract.json'),
} as vscode.Uri;
const testJson = fs.readFileSync(fileUri.fsPath, null);
const testJsonString = JSON.parse(testJson.toString());
it('writeBytecodeToBuffer should write correct bytecode to clipboard', async () => {
// Arrange
const testBytecode = testJsonString[Constants.contractProperties.bytecode];
// Act
await TruffleCommands.writeBytecodeToBuffer(fileUri);
// Assert
assert.strictEqual(
await vscode.env.clipboard.readText(),
testBytecode,
'clipboard should store correct bytecode');
});
it('writeAbiToBuffer should write correct aby to clipboard', async () => {
// Arrange
const testAbi = JSON.stringify(testJsonString[Constants.contractProperties.abi]);
// Act
await TruffleCommands.writeAbiToBuffer(fileUri);
// Assert
assert.strictEqual(
await vscode.env.clipboard.readText(),
testAbi,
'clipboard should store correct aby');
});
});
describe('Invalid cases', () => {
const fileUri = {
fsPath: path.join(__dirname, 'WriteToBuffer.test.ts'),
} as vscode.Uri;
it('writeBytecodeToBuffer throw error when uri is not JSON file', async () => {
// Act and assert
await assert.rejects(
TruffleCommands.writeBytecodeToBuffer(fileUri),
Error,
Constants.errorMessageStrings.InvalidContract);
});
it('writeAbiToBuffer throw error when uri is not JSON file', async () => {
// Act and assert
await assert.rejects(
TruffleCommands.writeAbiToBuffer(fileUri),
Error,
Constants.errorMessageStrings.InvalidContract);
});
});
});
});

Просмотреть файл

@ -13,12 +13,18 @@ import { Constants } from '../../src/Constants';
import * as helpers from '../../src/helpers';
import { openZeppelinHelper, TruffleConfiguration } from '../../src/helpers';
import * as commands from '../../src/helpers/command';
import { CancellationEvent } from '../../src/Models';
import { CancellationEvent, ItemType } from '../../src/Models';
import {
AzureBlockchainNetworkNode,
AzureBlockchainProject,
AzureBlockchainService,
BlockchainDataManagerNetworkNode,
BlockchainDataManagerProject,
BlockchainDataManagerService,
IExtensionItem,
InfuraNetworkNode,
InfuraProject,
InfuraService,
LocalNetworkNode,
LocalProject,
LocalService,
@ -26,7 +32,7 @@ import {
Service,
} from '../../src/Models/TreeItems';
import { ConsortiumResourceExplorer } from '../../src/resourceExplorers';
import { GanacheService, MnemonicRepository, TreeManager } from '../../src/services';
import { GanacheService, MnemonicRepository, OpenZeppelinMigrationsService, TreeManager } from '../../src/services';
import { OpenZeppelinService } from '../../src/services';
import { OZContractValidated } from '../../src/services/openZeppelin/models';
import { TestConstants } from '../TestConstants';
@ -82,6 +88,8 @@ describe('TruffleCommands', () => {
beforeEach(async () => {
sinon.stub(helpers.openZeppelinHelper, 'tryGetCurrentOpenZeppelinVersionAsync');
sinon.stub(helpers.openZeppelinHelper, 'defineContractRequiredParameters');
sinon.stub(OpenZeppelinMigrationsService, 'generateMigrations');
getWorkspaceRootMock = sinon.stub(helpers, 'getWorkspaceRoot');
requiredMock = sinon.mock(helpers.required);
@ -564,6 +572,28 @@ describe('TruffleCommands', () => {
'installTruffleHdWalletProvider should not be called');
});
it('Blockchain Data Manager should be ignored in deploy destination list', async () => {
// Arrange
let isBDMExist = false;
const { local } = TestConstants.consortiumTestNames;
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.returns(uuid.v4());
const networkNodeName = getDeployName(service.local.prefix, local, local);
showQuickPickMock.onCall(0).callsFake((items: any) => {
isBDMExist = items.some((item: any) => item.detail === Constants.treeItemData.service.bdm.label);
return items.find((item: any) => item.label === networkNodeName);
});
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(isBDMExist, false, 'deploy destination list should not have Blockchain Data Manager');
});
describe('validating openZeppelin contracts before deploy', () => {
beforeEach(() => {
checkAppsSilentMock.resolves(true);
@ -637,6 +667,8 @@ async function createTestServicesItems(): Promise<Service[]> {
const azureBlockchainService = new AzureBlockchainService();
const localService = new LocalService();
const infuraService = new InfuraService();
const bdmService = new BlockchainDataManagerService();
const azureBlockchainProject = new AzureBlockchainProject(
azureNames.consortium,
@ -657,10 +689,26 @@ async function createTestServicesItems(): Promise<Service[]> {
const localNetworkNode = new LocalNetworkNode(defaultLabel, defaultUrl, '*');
localProject.addChild(localNetworkNode);
const infuraProject = new InfuraProject(uuid.v4(), uuid.v4());
const infuraNetworkNode = new InfuraNetworkNode(uuid.v4(), uuid.v4(), uuid.v4());
infuraProject.addChild(infuraNetworkNode);
const bdmProject = new BlockchainDataManagerProject(uuid.v4(), uuid.v4(), uuid.v4());
const bdmNetworkNode = new BlockchainDataManagerNetworkNode(
uuid.v4(),
'*',
uuid.v4(),
uuid.v4(),
ItemType.BLOCKCHAIN_DATA_MANAGER_APPLICATION,
uuid.v4());
bdmProject.addChild(bdmNetworkNode);
azureBlockchainService.addChild(azureBlockchainProject);
localService.addChild(localProject);
infuraService.addChild(infuraProject);
bdmService.addChild(bdmProject);
services.push(azureBlockchainService, localService);
services.push(azureBlockchainService, localService, infuraService, bdmService);
return services;
}

Просмотреть файл

@ -1,671 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as assert from 'assert';
import * as fs from 'fs';
import * as path from 'path';
import * as sinon from 'sinon';
import uuid = require('uuid');
import * as vscode from 'vscode';
import { TruffleCommands } from '../../src/commands';
import { Constants } from '../../src/Constants';
import * as helpers from '../../src/helpers';
import { TruffleConfiguration } from '../../src/helpers';
import * as commands from '../../src/helpers/command';
import * as workspace from '../../src/helpers/workspace';
import { CancellationEvent } from '../../src/Models';
import {
AzureBlockchainNetworkNode,
AzureBlockchainProject,
AzureBlockchainService,
IExtensionItem,
LocalNetworkNode,
LocalProject,
LocalService,
Member,
Service,
} from '../../src/Models/TreeItems';
import { ConsortiumResourceExplorer } from '../../src/resourceExplorers';
import { GanacheService, MnemonicRepository, TreeManager } from '../../src/services';
import { OpenZeppelinService, OZContractValidated } from '../../src/services/openZeppelin/OpenZeppelinService';
import { TestConstants } from '../TestConstants';
import { AzureAccountHelper } from '../testHelpers/AzureAccountHelper';
const { service } = Constants.treeItemData;
describe('TruffleCommands', () => {
describe('Integration test', async () => {
describe('deployContracts', () => {
let requiredMock: sinon.SinonMock;
let checkAppsSilentMock: sinon.SinonExpectation;
let installTruffleMock: sinon.SinonExpectation;
let isHdWalletProviderRequiredMock: sinon.SinonExpectation;
let checkHdWalletProviderVersionMock: sinon.SinonExpectation;
let installTruffleHdWalletProviderMock: sinon.SinonExpectation;
let getWorkspaceRootMock: any;
let windowMock: sinon.SinonMock;
let showQuickPickMock: any;
let showInputBoxMock: any;
let showSaveDialogMock: sinon.SinonExpectation;
let showInformationMessageMock: any;
let ganacheServiceMock: sinon.SinonMock;
let startGanacheServerMock: sinon.SinonExpectation;
let getItemsMock: sinon.SinonStub<[], IExtensionItem[]>;
let loadStateMock: sinon.SinonStub<[], IExtensionItem[]>;
let servicesItems: Service[];
let truffleConfigSetNetworkMock: any;
let truffleConfigGetNetworkMock: any;
let truffleConfigGenerateMnemonicMock: any;
let commandContextMock: sinon.SinonMock;
let executeCommandMock: sinon.SinonExpectation;
let mnemonicRepositoryMock: sinon.SinonMock;
let getMnemonicMock: sinon.SinonStub<any[], any>;
let getAllMnemonicPathsMock: sinon.SinonStub<any[], any>;
let saveMnemonicPathMock: sinon.SinonExpectation;
let writeFileSyncMock: any;
let getAccessKeysMock: any;
let getExtensionMock: any;
let openZeppelinValidateContractsMock: any;
beforeEach(async () => {
getWorkspaceRootMock = sinon.stub(workspace, 'getWorkspaceRoot');
requiredMock = sinon.mock(helpers.required);
checkAppsSilentMock = requiredMock.expects('checkAppsSilent');
installTruffleMock = requiredMock.expects('installTruffle');
isHdWalletProviderRequiredMock = requiredMock.expects('isHdWalletProviderRequired');
checkHdWalletProviderVersionMock = requiredMock.expects('checkHdWalletProviderVersion');
installTruffleHdWalletProviderMock = requiredMock.expects('installTruffleHdWalletProvider');
isHdWalletProviderRequiredMock.returns(false);
checkHdWalletProviderVersionMock.returns(false);
windowMock = sinon.mock(vscode.window);
showQuickPickMock = sinon.stub(vscode.window, 'showQuickPick');
showInputBoxMock = sinon.stub(vscode.window, 'showInputBox');
showSaveDialogMock = windowMock.expects('showSaveDialog');
sinon.stub(vscode.window, 'showErrorMessage');
showInformationMessageMock = sinon.stub(vscode.window, 'showInformationMessage');
ganacheServiceMock = sinon.mock(GanacheService);
startGanacheServerMock = ganacheServiceMock.expects('startGanacheServer');
getItemsMock = sinon.stub(TreeManager, 'getItems');
loadStateMock = sinon.stub(TreeManager, 'loadState');
servicesItems = await createTestServicesItems();
getItemsMock.returns(servicesItems);
loadStateMock.returns(servicesItems);
truffleConfigSetNetworkMock = sinon.stub(TruffleConfiguration.TruffleConfig.prototype, 'setNetworks');
truffleConfigGetNetworkMock = sinon.stub(TruffleConfiguration.TruffleConfig.prototype, 'getNetworks');
truffleConfigGetNetworkMock.returns(getTestTruffleNetworks());
truffleConfigGenerateMnemonicMock = sinon.stub(TruffleConfiguration, 'generateMnemonic');
truffleConfigGenerateMnemonicMock.returns(TestConstants.testMnemonic);
commandContextMock = sinon.mock(commands);
executeCommandMock = commandContextMock.expects('executeCommand');
mnemonicRepositoryMock = sinon.mock(MnemonicRepository);
getMnemonicMock = mnemonicRepositoryMock.expects('getMnemonic').returns(TestConstants.testMnemonic);
getAllMnemonicPathsMock = mnemonicRepositoryMock.expects('getAllMnemonicPaths').returns([] as string []);
saveMnemonicPathMock = mnemonicRepositoryMock.expects('saveMnemonicPath');
writeFileSyncMock = sinon.stub(fs, 'writeFileSync');
getAccessKeysMock = sinon.stub(ConsortiumResourceExplorer.prototype, 'getAccessKeys');
getExtensionMock = sinon.stub(vscode.extensions, 'getExtension').returns(AzureAccountHelper.mockExtension);
const openZeppelinServiceMock = sinon.mock(OpenZeppelinService);
openZeppelinValidateContractsMock = openZeppelinServiceMock.expects('validateContracts')
.resolves([]);
});
afterEach(() => {
sinon.restore();
});
it('should throw exception when config file not found', async () => {
// Arrange
getWorkspaceRootMock.returns(__dirname);
executeCommandMock.returns(uuid.v4());
// Act and assert
await assert.rejects(TruffleCommands.deployContracts(),
Error,
Constants.errorMessageStrings.TruffleConfigIsNotExist);
});
it('should throw cancellationEvent when showQuickPick return undefined', async () => {
// Arrange
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.returns(uuid.v4());
showQuickPickMock.returns(undefined);
// Act and assert
await assert.rejects(TruffleCommands.deployContracts(), CancellationEvent);
});
it('should install TruffleHdWalletProvider when it required', async () => {
// Arrange
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
isHdWalletProviderRequiredMock.returns(true);
checkHdWalletProviderVersionMock.returns(false);
executeCommandMock.returns(uuid.v4());
showInformationMessageMock.returns(Constants.informationMessage.installButton);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === TestConstants.servicesNames.development);
});
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, true, 'startGanacheServer should be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, false, 'truffleConfig.setNetwork should not be called');
assert.strictEqual(
isHdWalletProviderRequiredMock.calledOnce,
true,
'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
true,
'checkHdWalletProviderVersion should be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
true,
'installTruffleHdWalletProvider should be called');
});
it('should not install TruffleHdWalletProvider when it version correct', async () => {
// Arrange
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
isHdWalletProviderRequiredMock.returns(true);
checkHdWalletProviderVersionMock.returns(true);
executeCommandMock.returns(uuid.v4());
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === TestConstants.servicesNames.development);
});
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, true, 'startGanacheServer should be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, false, 'truffleConfig.setNetwork should not be called');
assert.strictEqual(isHdWalletProviderRequiredMock.calledOnce, true, 'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
true,
'checkHdWalletProviderVersion should be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to development should complete successfully', async () => {
// Arrange
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.returns(uuid.v4());
isHdWalletProviderRequiredMock.returns(false);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === TestConstants.servicesNames.development);
});
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, true, 'startGanacheServer should be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, false, 'truffleConfig.setNetwork should not be called');
assert.strictEqual(isHdWalletProviderRequiredMock.calledOnce, true, 'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to development should throw exception when there is an error on command execution', async () => {
// Arrange
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.throws(TestConstants.testError);
showQuickPickMock.callsFake((items: any) => {
return items.find((item: any) => item.label === TestConstants.servicesNames.development);
});
// Act and assert
await assert.rejects(TruffleCommands.deployContracts(), Error);
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, true, 'startGanacheServer should be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, false, 'truffleConfig.setNetwork should not be called');
assert.strictEqual(isHdWalletProviderRequiredMock.calledOnce, true, 'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to network should complete successfully', async () => {
// Arrange
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.returns(uuid.v4());
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === TestConstants.servicesNames.testNetwork);
});
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, false, 'startGanacheServer should not be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, false, 'truffleConfig.setNetwork should not be called');
assert.strictEqual(isHdWalletProviderRequiredMock.calledOnce, true, 'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to network should throw exception when there is an error on command execution', async () => {
// Arrange
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.throws(TestConstants.testError);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === TestConstants.servicesNames.testNetwork);
});
// Act and assert
await assert.rejects(TruffleCommands.deployContracts());
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, false, 'startGanacheServer should not be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, false, 'truffleConfig.setNetwork should not be called');
assert.strictEqual(isHdWalletProviderRequiredMock.calledOnce, true, 'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to local network should complete successfully', async () => {
// Arrange
const { local } = TestConstants.consortiumTestNames;
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.returns(uuid.v4());
const networkNodeName = getDeployName(service.local.prefix, local, local);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === networkNodeName);
});
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, true, 'startGanacheServer should be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, true, 'truffleConfig.setNetwork should be called');
assert.strictEqual(
isHdWalletProviderRequiredMock.calledOnce,
true,
'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to local network should throw exception when there is an error on command execution', async () => {
// Arrange
const { local } = TestConstants.consortiumTestNames;
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.throws(TestConstants.testError);
const networkNodeName = getDeployName(service.local.prefix, local, local);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === networkNodeName);
});
// Act and assert
await assert.rejects(TruffleCommands.deployContracts());
assert.strictEqual(showQuickPickMock.calledOnce, true, 'showQuickPick should be called once');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, true, 'startGanacheServer should be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, true, 'truffleConfig.setNetwork should be called');
assert.strictEqual(
isHdWalletProviderRequiredMock.calledOnce,
true,
'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to AzureBlockchainService should generate mnemonic and complete successfully', async () => {
// Arrange
const { consortium, member, transactionNode } = azureNames;
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.returns(uuid.v4());
getAccessKeysMock.returns(uuid.v4());
const networkNodeName = getDeployName(service.azure.prefix, consortium, transactionNode, [member]);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === networkNodeName);
});
showQuickPickMock.onCall(1).callsFake((items: any) => {
return items.find((item: any) => item.label === Constants.placeholders.generateMnemonic);
});
showSaveDialogMock.returns(uuid.v4());
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(showQuickPickMock.called, true, 'showQuickPick should be called');
assert.strictEqual(showQuickPickMock.callCount, 2, 'showQuickPick should be called twice');
assert.strictEqual(getAccessKeysMock.called, true, 'getAccessKeys should be called');
assert.strictEqual(showInputBoxMock.called, false, 'showInputBox should not be called');
assert.strictEqual(getMnemonicMock.called, false, 'getMnemonic should not be called');
assert.strictEqual(getAllMnemonicPathsMock.called, true, 'getAllMnemonicPaths should be called');
assert.strictEqual(saveMnemonicPathMock.called, true, 'saveMnemonicPath should be called');
assert.strictEqual(writeFileSyncMock.called, true, 'writeFileSync should be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, false, 'startGanacheServer should not be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, true, 'truffleConfig.setNetwork should be called');
assert.strictEqual(getExtensionMock.called, true, 'getExtension should be called');
assert.strictEqual(
isHdWalletProviderRequiredMock.calledOnce,
true,
'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
it('to AzureBlockchainService should complete successfully when user paste mnemonic', async () => {
// Arrange
const { consortium, member, transactionNode } = azureNames;
checkAppsSilentMock.returns(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
executeCommandMock.returns(uuid.v4());
getAccessKeysMock.returns(uuid.v4());
const networkNodeName = getDeployName(service.azure.prefix, consortium, transactionNode, [member]);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === networkNodeName);
});
showQuickPickMock.onCall(1).callsFake((items: any) => {
return items.find((item: any) => item.label === Constants.placeholders.pasteMnemonic);
});
showInputBoxMock.onCall(0).returns(TestConstants.testMnemonic);
showSaveDialogMock.returns(uuid.v4());
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(showQuickPickMock.called, true, 'showQuickPick should be called');
assert.strictEqual(showQuickPickMock.callCount, 2, 'showQuickPick should be called twice');
assert.strictEqual(getAccessKeysMock.called, true, 'getAccessKeys should be called');
assert.strictEqual(showInputBoxMock.calledOnce, true, 'showInputBox should be called once');
assert.strictEqual(getMnemonicMock.called, false, 'getMnemonic should not be called');
assert.strictEqual(getAllMnemonicPathsMock.called, true, 'getAllMnemonicPaths should be called');
assert.strictEqual(saveMnemonicPathMock.called, true, 'saveMnemonicPath should be called');
assert.strictEqual(writeFileSyncMock.called, true, 'writeFileSync should be called');
assert.strictEqual(checkAppsSilentMock.calledOnce, true, 'checkAppsSilent should be called once');
assert.strictEqual(installTruffleMock.called, false, 'installTruffle should not be called');
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
assert.strictEqual(startGanacheServerMock.called, false, 'startGanacheServer should not be called');
assert.strictEqual(truffleConfigSetNetworkMock.called, true, 'truffleConfig.setNetwork should be called');
assert.strictEqual(getExtensionMock.called, true, 'getExtension should be called');
assert.strictEqual(
isHdWalletProviderRequiredMock.calledOnce,
true,
'isHdWalletProviderRequired should be called');
assert.strictEqual(
checkHdWalletProviderVersionMock.calledOnce,
false,
'checkHdWalletProviderVersion should not be called');
assert.strictEqual(
installTruffleHdWalletProviderMock.calledOnce,
false,
'installTruffleHdWalletProvider should not be called');
});
describe('validating openZeppelin contracts before deploy', () => {
beforeEach(() => {
checkAppsSilentMock.resolves(true);
getWorkspaceRootMock.returns(path.join(__dirname, TestConstants.truffleCommandTestDataFolder));
showInputBoxMock.returns(Constants.confirmationDialogResult.yes);
executeCommandMock.returns(uuid.v4());
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === TestConstants.servicesNames.testNetwork);
});
});
afterEach(() => {
sinon.restore();
});
it('should pass when openZeppelin contracts are valid', async () => {
// Arrange
openZeppelinValidateContractsMock.resolves([ new OZContractValidated('1', true, true) ]);
// Act
await TruffleCommands.deployContracts();
// Assert
assert.strictEqual(executeCommandMock.called, true, 'executeCommand should be called');
});
it('should throw error when downloaded openZeppelin contract has invalid hash', async () => {
// Arrange
openZeppelinValidateContractsMock.resolves([ new OZContractValidated('1', true, false) ]);
// Act and Assert
await assert.rejects(TruffleCommands.deployContracts(), Error);
});
it('should throw error when downloaded openZeppelin contract doesn\'t exist on the disk', async () => {
// Arrange
openZeppelinValidateContractsMock.resolves([ new OZContractValidated('1', false) ]);
// Act and Assert
await assert.rejects(TruffleCommands.deployContracts(), Error);
});
it('should throw error when any downloaded openZeppelin contract is invalid', async () => {
// Arrange
openZeppelinValidateContractsMock.resolves([
new OZContractValidated('1', true, false),
new OZContractValidated('2', true, true),
]);
// Act and Assert
await assert.rejects(TruffleCommands.deployContracts(), Error);
});
});
});
});
});
const azureNames = {
consortium: uuid.v4(),
member: uuid.v4(),
transactionNode: TestConstants.servicesNames.testConsortium,
};
async function createTestServicesItems(): Promise<Service[]> {
const services: Service[] = [];
const azureBlockchainService = new AzureBlockchainService();
const localService = new LocalService();
const azureBlockchainProject = new AzureBlockchainProject(
azureNames.consortium,
uuid.v4(),
uuid.v4(),
[azureNames.member],
);
const member = new Member(azureNames.member);
const transactionNode
= new AzureBlockchainNetworkNode(azureNames.transactionNode, uuid.v4(), '*', '', '', azureNames.member);
member.addChild(transactionNode);
azureBlockchainProject.addChild(member);
const defaultPort = 8545;
const defaultLabel = TestConstants.consortiumTestNames.local;
const localProject = new LocalProject(defaultLabel, defaultPort);
const defaultUrl = `${Constants.networkProtocols.http}${Constants.localhost}:${defaultPort}`;
const localNetworkNode = new LocalNetworkNode(defaultLabel, defaultUrl, '*');
localProject.addChild(localNetworkNode);
azureBlockchainService.addChild(azureBlockchainProject);
localService.addChild(localProject);
services.push(azureBlockchainService, localService);
return services;
}
function getTestTruffleNetworks(): TruffleConfiguration.INetwork[] {
const networks: TruffleConfiguration.INetwork[] = [];
networks.push({
name: TestConstants.servicesNames.development,
options: {
host: '127.0.0.1',
network_id: '*',
port: 8545,
},
},
{
name: TestConstants.servicesNames.testNetwork,
options: {
gas: 4712388,
gasPrice: 100000000000,
network_id: 2,
},
});
return networks;
}
function getDeployName(prefix: string, projectName: string, nodeName: string, args?: string[]): string {
if (args) {
return [prefix, projectName, ...args, nodeName].join('_');
}
return [prefix, projectName, nodeName].join('_');
}

Просмотреть файл

@ -171,4 +171,70 @@ describe('Commands helper', () => {
return undefined;
});
});
describe('tryExecuteCommandInFork', () => {
const modulePath = 'some_path';
const messageData = { command: 'truffleConfig', message: "{ result: 'some message data' }" };
let childProcessMock: sinon.SinonMock;
let processMock: cp.ChildProcess;
beforeEach(() => {
processMock = new events.EventEmitter() as cp.ChildProcess;
processMock.stdout = new events.EventEmitter() as stream.Readable;
processMock.stderr = new events.EventEmitter() as stream.Readable;
processMock.stdin = new stream.Writable();
childProcessMock = sinon.mock(cp);
});
afterEach(() => {
sinon.restore();
});
it('tryExecuteCommandInFork should return correct result', async () => {
// Arrange
const forkMock = childProcessMock.expects('fork').returns(processMock);
// Act
const commandResultPromise = outputCommandHelper.tryExecuteCommandInFork('workingDirectory', modulePath, '');
await new Promise<void>(async (resolve) => {
setTimeout(async () => {
await processMock.emit('message', messageData);
await processMock.emit('exit', 0);
resolve();
}, 500);
});
const commandResult = await commandResultPromise;
// Assert
assert.strictEqual(
commandResult.messages && commandResult.messages[0],
messageData,
'commandResult.messages should be equal to test data');
assert.strictEqual(forkMock.calledOnce, true, 'fork should called once');
});
it('tryExecuteCommandInFork should rejected on error', async () => {
// Arrange
sinon.replace(cp, 'fork', () => { throw new Error(); });
// Act
const action = async () => {
return await outputCommandHelper.tryExecuteCommandInFork('workingDirectory', modulePath, '');
};
await new Promise<void>(async (resolve) => {
setTimeout(async () => {
await processMock.emit('message', messageData);
await processMock.emit('exit', 0);
resolve();
}, 500);
});
// Assert
await assert.rejects(action);
});
});
});

Просмотреть файл

@ -1,335 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as assert from 'assert';
import * as path from 'path';
import rewire = require('rewire');
import * as sinon from 'sinon';
import uuid = require('uuid');
import {
CancellationToken,
MessageItem,
MessageOptions,
Progress,
ProgressOptions,
QuickPickItem,
QuickPickOptions,
window,
} from 'vscode';
import { Constants } from '../../src/Constants';
import { TruffleConfiguration } from '../../src/helpers/truffleConfig';
import * as workspace from '../../src/helpers/workspace';
import { CancellationEvent } from '../../src/Models';
import {
IDownloadingResult,
IOZAsset,
IOZContractCategory,
OpenZeppelinMigrationsService,
OpenZeppelinService,
OZAssetType,
PromiseState,
} from '../../src/services';
describe('OpenZeppelinCommands tests', () => {
let testCategories: IOZContractCategory[];
let getCategoriesStub: sinon.SinonStub<[], IOZContractCategory[]>;
let collectAssetsWithDependenciesStub: sinon.SinonStub<[(string[] | undefined)?], IOZAsset[]>;
let downloadFilesStub: sinon.SinonStub<[IOZAsset[], (boolean | undefined)?], Promise<IDownloadingResult[]>>;
let addAssetsToProjectJsonStub: sinon.SinonStub<[IOZAsset[]], Promise<void>>;
let getAssetsStatusStub: sinon.SinonStub<any>;
let generateMigrationsStub: sinon.SinonStub<[IOZAsset[]], Promise<void>>;
let getCategoryApiDocumentationUrlStub: sinon.SinonStub<any>;
let withProgressStub: sinon.SinonStub<[ProgressOptions,
(progress: Progress<any>, token: CancellationToken) => any], any>;
let showQuickPickStub: sinon.SinonStub<
[QuickPickItem[] | Thenable<QuickPickItem[]>, (QuickPickOptions | undefined)?, (CancellationToken | undefined)?],
any>;
let showInformationMessageStub: sinon.SinonStub<[string, MessageOptions, ...MessageItem[]], any>;
let showErrorMessageStub: sinon.SinonStub<[string, MessageOptions, ...MessageItem[]], any>;
let selectedCategory: IOZContractCategory;
let testAssets: IOZAsset[];
let openZeppelinCommands: { addCategory: () => Promise<void> };
let openStub: sinon.SinonStub<any[], any>;
beforeEach(() => {
const numberOfCategory = 2;
testCategories = getTestCategories();
selectedCategory = testCategories[numberOfCategory];
testAssets = getTestAssetsWithDependencies(selectedCategory.assets);
const getWorkspaceRootMock = sinon.stub(workspace, 'getWorkspaceRoot');
getWorkspaceRootMock.returns(path.join(__filename, '../../TruffleCommandsTests/testData'));
sinon.stub(TruffleConfiguration.TruffleConfig.prototype, 'getConfiguration')
.returns({ contracts_directory: uuid.v4() } as TruffleConfiguration.IConfiguration);
addAssetsToProjectJsonStub = sinon.stub(OpenZeppelinService, 'addAssetsToProjectJson');
getCategoriesStub = sinon.stub(OpenZeppelinService, 'getCategories')
.returns(testCategories);
collectAssetsWithDependenciesStub = sinon.stub(OpenZeppelinService, 'collectAssetsWithDependencies')
.returns(testAssets);
getAssetsStatusStub = sinon.stub(OpenZeppelinService, 'getAssetsStatus');
downloadFilesStub = sinon.stub(OpenZeppelinService, 'downloadFiles');
generateMigrationsStub = sinon.stub(OpenZeppelinMigrationsService, 'generateMigrations');
getCategoryApiDocumentationUrlStub = sinon.stub(OpenZeppelinService, 'getCategoryApiDocumentationUrl')
.returns('testUrl');
getAssetsStatusStub.returns({ existing: [], missing: testAssets });
showQuickPickStub = sinon.stub(window, 'showQuickPick');
showInformationMessageStub = sinon.stub(window, 'showInformationMessage');
showErrorMessageStub = sinon.stub(window, 'showErrorMessage');
withProgressStub = sinon.stub(window, 'withProgress');
withProgressStub.callsFake(async (...args: any[]) => {
return args[1]();
});
showQuickPickStub.callsFake(async (...args: any[]) => {
return args[0].find((arg: any) => arg.label === selectedCategory.name);
});
const testDownloadingResult: IDownloadingResult[] = [];
testAssets.forEach((asset) => {
testDownloadingResult.push({
asset,
state: PromiseState.fulfilled,
});
});
downloadFilesStub.resolves(testDownloadingResult);
openStub = sinon.stub().resolves();
const openZeppelinCommandsRewire = rewire('../../src/commands/OpenZeppelinCommands');
openZeppelinCommandsRewire.__set__('open', openStub);
openZeppelinCommands = openZeppelinCommandsRewire.__get__('OpenZeppelinCommands');
});
afterEach(() => {
sinon.restore();
});
it('should complete basic pipeline', async () => {
// Arrange
const wereDownloadedMessage = Constants.openZeppelin.wereDownloaded(selectedCategory.assets.length);
showInformationMessageStub.onCall(1).returns(Constants.openZeppelin.moreDetailsButtonTitle);
// Act
await openZeppelinCommands.addCategory();
// Assert
assert.strictEqual(getCategoriesStub.called, true, 'getCategories should be called.');
assert.strictEqual(showQuickPickStub.calledOnce, true, 'showQuickPick should called once.');
assert.deepStrictEqual(
showQuickPickStub.args[0][1],
{
ignoreFocusOut: true,
placeHolder: Constants.openZeppelin.selectCategoryForDownloading,
},
'selectCategory should ask for category.',
);
assert.strictEqual(collectAssetsWithDependenciesStub.calledOnce, true, 'collectAssetsWithDependencies should called once.');
assert.deepStrictEqual(
collectAssetsWithDependenciesStub.args[0][0],
selectedCategory.assets,
'collectAssetsWithDependencies should called once with asserts from selected category.',
);
assert.strictEqual(downloadFilesStub.calledOnce, true, 'downloadFiles should be called');
assert.strictEqual(addAssetsToProjectJsonStub.called, true, 'addAssetsToProjectJson should be called');
assert.strictEqual(showInformationMessageStub.calledTwice, true, 'showInformationMessage should be called twice');
assert.strictEqual(
showInformationMessageStub.args[0][0],
wereDownloadedMessage,
'should be displayed message with number of downloaded items',
);
assert.strictEqual(
showInformationMessageStub.args[1][0],
Constants.openZeppelin.exploreDownloadedContractsInfo,
'should be displayed message with information about downloaded category',
);
assert.strictEqual(
getCategoryApiDocumentationUrlStub.calledOnce,
true,
'getCategoryApiDocumentationUrl should be called',
);
assert.strictEqual(generateMigrationsStub.called, true, 'generateMigrations should be called');
});
it('should downloads selected category', async () => {
// Act
await openZeppelinCommands.addCategory();
// Assert
assert.strictEqual(downloadFilesStub.args[0][0], testAssets, 'downloadFiles should called for selected asset');
});
it('throws cancellation event when user don`t select category', async () => {
// Arrange
const notExistingCategoryName = 'notExistingCategoryName';
showQuickPickStub.callsFake(async (...args: any[]) => {
return args[0].find((arg: any) => arg.label === notExistingCategoryName);
});
// Act and Assert
await assert.rejects(
async () => await openZeppelinCommands.addCategory(),
CancellationEvent,
'addCategory should throw cancellation event.');
assert.strictEqual(getCategoriesStub.calledOnce, true, 'getCategories should called once.');
assert.strictEqual(showQuickPickStub.calledOnce, true, 'showQuickPick should called once.');
assert.strictEqual(
collectAssetsWithDependenciesStub.notCalled,
true,
'collectAssetsWithDependencies should not called.');
assert.strictEqual(withProgressStub.notCalled, true, 'withProgress should not called.');
});
it('should ask for overwrite existing files and overwrite on positive answer', async () => {
// Arrange
const existingAsset = testAssets.slice(3, 4);
const missingAsset = testAssets.slice(0, 3);
getAssetsStatusStub
.returns({
existing: existingAsset,
missing: missingAsset,
});
showInformationMessageStub.onCall(0).returns(Constants.openZeppelin.replaceButtonTitle);
// Act
await openZeppelinCommands.addCategory();
// Assert
assert.strictEqual(showInformationMessageStub.calledThrice, true, 'showQuickPick should called three times');
assert.strictEqual(
showInformationMessageStub.args[0][0],
Constants.openZeppelin.alreadyExisted(existingAsset),
'alreadyExisted message should displayed once.',
);
assert.strictEqual(downloadFilesStub.args[0][1], true, 'downloading should be called with overwrite flag');
assert.strictEqual(downloadFilesStub.args[0][0].length, testAssets.length, 'downloading full asset of items');
});
it('should ask for overwrite existed files and skip files on negative answer', async () => {
// Arrange
const existingAsset = testAssets.slice(3, 4);
const missingAsset = testAssets.slice(0, 3);
getAssetsStatusStub
.returns({
existing: existingAsset,
missing: missingAsset,
});
showInformationMessageStub.onCall(0).returns(Constants.openZeppelin.skipButtonTitle);
// Act
await openZeppelinCommands.addCategory();
// Assert
assert.strictEqual(showInformationMessageStub.calledThrice, true, 'showQuickPick should called three times.');
assert.strictEqual(
showInformationMessageStub.args[0][0],
Constants.openZeppelin.alreadyExisted(existingAsset),
'showQuickPick should called once.',
);
assert.strictEqual(downloadFilesStub.args[0][1], false, 'downloading should be called without overwrite flag');
assert.strictEqual(downloadFilesStub.args[0][0].length, missingAsset.length, 'downloading only missing assets');
});
it('should show error message if some files failed on downloading and allow to retry', async () => {
// Arrange
const rejectedAssets = [
{ asset: {} as IOZAsset, state: PromiseState.rejected },
{ asset: {} as IOZAsset, state: PromiseState.rejected },
];
downloadFilesStub.resolves([
{ asset: {} as IOZAsset, state: PromiseState.fulfilled },
...rejectedAssets,
]);
showErrorMessageStub
.onCall(0).returns(Constants.openZeppelin.retryButtonTitle)
.onCall(1).returns(Constants.openZeppelin.cancelButtonTitle);
// Act
await openZeppelinCommands.addCategory();
// Assert
assert.strictEqual(
showErrorMessageStub.args[0][0],
Constants.openZeppelin.wereNotDownloaded(rejectedAssets.length),
'showErrorMessageStub should called with exact message',
);
assert.strictEqual(downloadFilesStub.calledTwice, true, 'downloadFiles should be retried');
});
it('should open documentation for chosen category after downloading', async () => {
// Arrange
const testDocumentationUrl = 'testUrl';
getCategoryApiDocumentationUrlStub.returns(testDocumentationUrl);
generateMigrationsStub.resolves();
showInformationMessageStub.onCall(1).returns(Constants.openZeppelin.moreDetailsButtonTitle);
// Act
await openZeppelinCommands.addCategory();
// Assert
assert.strictEqual(getCategoryApiDocumentationUrlStub.calledWithMatch(selectedCategory), true,
'getCategoryApiDocumentationUrl should be called with chosen category');
assert.strictEqual(openStub.calledWith(testDocumentationUrl), true,
`open should be called with ${testDocumentationUrl}`);
assert.strictEqual(openStub.calledAfter(downloadFilesStub), true, 'open should be called after downloadFiles');
});
it('should not ask and open category documentation if it doesn\'t exist', async () => {
// Arrange
getCategoryApiDocumentationUrlStub.returns(undefined);
generateMigrationsStub.resolves();
// Act
await openZeppelinCommands.addCategory();
// Assert
assert.strictEqual(
showInformationMessageStub.calledWith(Constants.openZeppelin.exploreDownloadedContractsInfo),
false,
'showInformationMessageStub should not be called with explore contracts info message');
assert.strictEqual(openStub.called, false, 'open should not be called');
});
});
function getTestCategories(): IOZContractCategory[] {
const testCategories: IOZContractCategory[] = [{
assets: [uuid.v4()],
id: uuid.v4(),
name: uuid.v4(),
},
{
assets: [uuid.v4(), uuid.v4()],
id: uuid.v4(),
name: uuid.v4(),
},
{
assets: [uuid.v4(), uuid.v4(), uuid.v4(), uuid.v4()],
id: uuid.v4(),
name: uuid.v4(),
}];
return testCategories;
}
function getTestAssetsWithDependencies(assets: string[]): IOZAsset[] {
const assetsWithDependencies: IOZAsset[] = [];
assets.forEach((asset) => {
assetsWithDependencies.push({
dependencies: [uuid.v4()],
hash: uuid.v4(),
id: asset,
name: uuid.v4(),
type: OZAssetType.contract,
});
});
return assetsWithDependencies;
}

Просмотреть файл

@ -8,10 +8,11 @@ import * as uuid from 'uuid';
import * as vscode from 'vscode';
import { Constants } from '../../../src/Constants';
import { ItemType } from '../../../src/Models';
import { AzureBlockchainProject, AzureBlockchainService, Project, Service, ServiceTypes } from '../../../src/Models/TreeItems';
import { ConsortiumResourceExplorer } from '../../../src/resourceExplorers';
import { AzureBlockchainProject, AzureBlockchainService, BlockchainDataManagerProject, InfuraProject, Project } from '../../../src/Models/TreeItems';
import { BlockchainDataManagerResourceExplorer, ConsortiumResourceExplorer, InfuraResourceExplorer } from '../../../src/resourceExplorers';
import { GanacheService, TreeManager } from '../../../src/services';
import { AzureAccountHelper } from '../../testHelpers/AzureAccountHelper';
const { project } = Constants.treeItemData;
describe('Service Commands', () => {
let defaultConsortiumName: string;
@ -42,12 +43,12 @@ describe('Service Commands', () => {
describe('connectProject returns project', () => {
let selectedDestination: any;
let getItemStub: sinon.SinonStub<[ServiceTypes], Service>;
let addChildStub: sinon.SinonStub<any, any>;
let showQuickPickMock: sinon.SinonStub<any[], any>;
let showInputBoxMock: sinon.SinonExpectation;
let selectConsortiumMock: any;
let startGanacheServerStub: any;
let selectProjectMock: any;
beforeEach(() => {
vscodeWindowMock = sinon.mock(vscode.window);
@ -60,7 +61,7 @@ describe('Service Commands', () => {
sinon.stub(GanacheService, 'getPortStatus')
.resolves(GanacheService.PortStatus.FREE);
getItemStub = sinon.stub(TreeManager, 'getItem')
sinon.stub(TreeManager, 'getItem')
.callsFake(() => {
const azureBlockchainService = new AzureBlockchainService();
addChildStub = sinon.stub(azureBlockchainService, 'addChild');
@ -76,13 +77,10 @@ describe('Service Commands', () => {
[defaultMemberName],
)),
);
sinon.stub(vscode.extensions, 'getExtension').returns(AzureAccountHelper.mockExtension);
});
afterEach(() => {
startGanacheServerStub.restore();
selectConsortiumMock.restore();
getItemStub.restore();
vscodeWindowMock.restore();
sinon.restore();
});
@ -130,7 +128,7 @@ describe('Service Commands', () => {
assertAfterEachTest(
result,
ItemType.LOCAL_PROJECT,
Constants.treeItemData.project.local.contextValue,
project.local.contextValue,
expectedLabel,
);
assert.strictEqual(showInputBoxMock.called, true, 'showInputBox should be called');
@ -142,9 +140,6 @@ describe('Service Commands', () => {
it('for Azure Blockchain Service destination.', async () => {
// Arrange
const getExtensionMock = sinon.stub(vscode.extensions, 'getExtension')
.returns(AzureAccountHelper.mockExtension);
showQuickPickMock.callsFake(async (...args: any[]) => {
const destination = args[0].find((x: any) => x.itemType === ItemType.AZURE_BLOCKCHAIN_SERVICE);
selectedDestination = destination;
@ -160,16 +155,69 @@ describe('Service Commands', () => {
assertAfterEachTest(
result,
ItemType.AZURE_BLOCKCHAIN_PROJECT,
Constants.treeItemData.project.default.contextValue,
project.azure.contextValue,
defaultConsortiumName,
);
assert.strictEqual(startGanacheServerStub.notCalled, true, 'startGanacheServer command should not be called');
assert.strictEqual(
selectConsortiumMock.calledOnce,
true,
'selectProject should be called once');
assert.strictEqual(selectConsortiumMock.calledOnce, true, 'selectProject should be called once');
});
getExtensionMock.restore();
it('for Infura Service destination.', async () => {
// Arrange
const label = uuid.v4.toString();
selectProjectMock = sinon.stub(InfuraResourceExplorer.prototype, 'selectProject');
const infuraProject = new InfuraProject(label, uuid.v4());
selectProjectMock.returns(infuraProject);
showQuickPickMock.callsFake(async (...args: any[]) => {
const destination = args[0].find((x: any) => x.itemType === ItemType.INFURA_SERVICE);
selectedDestination = destination;
selectedDestination.cmd = sinon.spy(destination.cmd);
return selectedDestination;
});
// Act
const result = await serviceCommandsRewire.ServiceCommands.connectProject();
// Assert
assertAfterEachTest(
result,
ItemType.INFURA_PROJECT,
project.infura.contextValue,
label,
);
assert.strictEqual(startGanacheServerStub.notCalled, true, 'startGanacheServer command should not be called');
assert.strictEqual(selectProjectMock.calledOnce, true, 'selectProject should be called once');
});
it('for Blockchain Data Manager Service destination.', async () => {
// Arrange
const label = uuid.v4.toString();
selectProjectMock = sinon.stub(BlockchainDataManagerResourceExplorer.prototype, 'selectProject');
const bdmProject = new BlockchainDataManagerProject(label, uuid.v4(), uuid.v4());
selectProjectMock.returns(bdmProject);
showQuickPickMock.callsFake(async (...args: any[]) => {
const destination = args[0].find((x: any) => x.itemType === ItemType.BLOCKCHAIN_DATA_MANAGER_SERVICE);
selectedDestination = destination;
selectedDestination.cmd = sinon.spy(destination.cmd);
return selectedDestination;
});
// Act
const result = await serviceCommandsRewire.ServiceCommands.connectProject();
// Assert
assertAfterEachTest(
result,
ItemType.BLOCKCHAIN_DATA_MANAGER_PROJECT,
project.bdm.contextValue,
label,
);
assert.strictEqual(startGanacheServerStub.notCalled, true, 'startGanacheServer command should not be called');
assert.strictEqual(selectProjectMock.calledOnce, true, 'selectProject should be called once');
});
});
});

Просмотреть файл

@ -11,12 +11,16 @@ import { ItemType } from '../../../src/Models';
import {
AzureBlockchainProject,
AzureBlockchainService,
BlockchainDataManagerProject,
BlockchainDataManagerService,
IExtensionItem,
InfuraProject,
InfuraService,
LocalService,
Project,
Service,
} from '../../../src/Models/TreeItems';
import { ConsortiumResourceExplorer } from '../../../src/resourceExplorers';
import { BlockchainDataManagerResourceExplorer, ConsortiumResourceExplorer, InfuraResourceExplorer } from '../../../src/resourceExplorers';
import { GanacheService, TreeManager } from '../../../src/services';
import { AzureAccountHelper } from '../../testHelpers/AzureAccountHelper';
import { getRandomInt } from '../../testHelpers/Random';
@ -34,13 +38,18 @@ describe('Service Commands', () => {
let startGanacheServerMock: sinon.SinonExpectation;
let selectConsortiumMock: any;
let getExtensionMock: any;
let selectProjectMock: any;
let azureGroup: Service;
let localGroup: Service;
let infuraGroup: Service;
let bdmGroup: Service;
function initializeNetworks() {
azureGroup = new AzureBlockchainService();
localGroup = new LocalService();
infuraGroup = new InfuraService();
bdmGroup = new BlockchainDataManagerService();
}
function createTestServiceItems() {
@ -136,9 +145,58 @@ describe('Service Commands', () => {
assertAfterEachTest(
result,
ItemType.AZURE_BLOCKCHAIN_PROJECT,
project.default.contextValue,
project.azure.contextValue,
consortiumName.toString());
});
it('for Infura Service destination.', async () => {
// Arrange
const label = uuid.v4.toString();
getItemMock.returns(infuraGroup);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === service.infura.label);
});
selectProjectMock = sinon.stub(InfuraResourceExplorer.prototype, 'selectProject');
const infuraProject = new InfuraProject(label, uuid.v4());
selectProjectMock.returns(infuraProject);
// Act
const result = await ServiceCommands.connectProject();
// Assert
assert.strictEqual(selectProjectMock.calledOnce, true);
assertAfterEachTest(
result,
ItemType.INFURA_PROJECT,
project.infura.contextValue,
label.toString());
});
it('for Blockchain Data Manager Service destination.', async () => {
// Arrange
const label = uuid.v4.toString();
getItemMock.returns(bdmGroup);
showQuickPickMock.onCall(0).callsFake((items: any) => {
return items.find((item: any) => item.label === service.bdm.label);
});
selectProjectMock = sinon.stub(BlockchainDataManagerResourceExplorer.prototype, 'selectProject');
const bdmProject = new BlockchainDataManagerProject(label, uuid.v4(), uuid.v4());
selectProjectMock.returns(bdmProject);
// Act
const result = await ServiceCommands.connectProject();
// Assert
assert.strictEqual(getExtensionMock.calledOnce, true);
assert.strictEqual(selectProjectMock.calledOnce, true);
assertAfterEachTest(
result,
ItemType.BLOCKCHAIN_DATA_MANAGER_PROJECT,
project.bdm.contextValue,
label.toString());
});
});
describe('connectProject should rejects', () => {

Просмотреть файл

@ -1,67 +0,0 @@
import * as assert from 'assert';
import * as helpers from '../../src/debugAdapter/helpers';
describe('helpers unit tests', () => {
it('groupBy should return correct result', () => {
const keyValue1 = '1';
const keyValue2 = '2';
const elA = { a: keyValue1, b: 1 };
const elB = { a: keyValue1, b: 2 };
const elC = { a: keyValue2, b: 3 };
const arrayMock = [ elA, elB, elC ];
const groups = helpers.groupBy(arrayMock, 'a');
assert.strictEqual(Object.keys(groups).length, 2, 'groups should be 2');
assert.strictEqual(Object.keys(groups).includes(keyValue1), true, `groups should contain key ${keyValue1}`);
assert.strictEqual(Object.keys(groups).includes(keyValue2), true, `groups should contain key ${keyValue2}`);
assert.strictEqual(groups[keyValue1][0], elA, 'group 1 should contain elA');
assert.strictEqual(groups[keyValue1][1], elB, 'group 1 should contain elB');
assert.strictEqual(groups[keyValue2][0], elC, 'group 2 should contain elC');
});
getTestCasesForSortFilePaths().forEach((testCase) => {
sortFilePathTest(testCase.input, testCase.output);
});
function sortFilePathTest(input: string[], output: string[]) {
it('sortFilePaths should return correct result', () => {
const result = helpers.sortFilePaths(input);
output.forEach((element, index) => {
assert.strictEqual(result[index], element, `${index}-th element should equal ${element}`);
});
});
}
function getTestCasesForSortFilePaths() {
return [
{
input: [
'A:\\B\\C\\b.ext',
'A:/B/C/D/a.ext',
'A:/B/C/a.ext',
],
output: [
'A:/B/C/a.ext',
'A:\\B\\C\\b.ext',
'A:/B/C/D/a.ext',
],
},
{
input: [
'A:/B/C/E/a.ext',
'A:/B/C/b.ext',
'A:/B/C/E/F/a.ext',
'A:\\B\\C\\a.ext',
'A:\\B\\C\\D\\A\\B\\b.ext',
],
output: [
'A:\\B\\C\\a.ext',
'A:/B/C/b.ext',
'A:\\B\\C\\D\\A\\B\\b.ext',
'A:/B/C/E/a.ext',
'A:/B/C/E/F/a.ext',
],
},
];
}
});

Просмотреть файл

@ -37,7 +37,7 @@ describe('OpenZeppelinHelper', () => {
it('shouldUpgradeOpenZeppelinAsync should return true if current and latest versions differ and confirm dialog is true', async () => {
sinon.stub(OpenZeppelinService, 'getCurrentOpenZeppelinVersionAsync').resolves('current');
sinon.stub(OpenZeppelinService, 'getLatestOpenZeppelinVersionAsync').resolves('latest');
sinon.stub(helpers, 'showConfirmDialogToUpdateOpenZeppelin').resolves(true);
sinon.stub(helpers, 'showConfirmationDialog').resolves(true);
const openZeppelinHelperRewire = rewire('../src/helpers/openZeppelinHelper');

Просмотреть файл

@ -1,744 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as assert from 'assert';
import rewire = require('rewire');
import * as sinon from 'sinon';
import uuid = require('uuid');
import * as vscode from 'vscode';
import { RequiredApps } from '../src/Constants';
import * as commands from '../src/helpers/command';
import * as workspace from '../src/helpers/workspace';
import { TestConstants } from './TestConstants';
const nodeValidVersion: commands.ICommandResult = {
cmdOutput: 'v11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const npmValidVersion: commands.ICommandResult = {
cmdOutput: '7.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const gitValidVersion: commands.ICommandResult = {
cmdOutput: ' 3.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const pythonValidVersion: commands.ICommandResult = {
cmdOutput: ' 2.9.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const truffleValidVersion: commands.ICommandResult = {
cmdOutput: 'truffle@5.5.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const ganacheValidVersion: commands.ICommandResult = {
cmdOutput: 'ganache-cli@6.5.0',
cmdOutputIncludingStderr: '',
code: 0,
};
describe('Required helper', () => {
describe('Unit test', () => {
let tryExecuteCommandMock: any;
let getWorkspaceRootMock: any;
let requiredRewire: any;
let showErrorMessageMock: any;
let executeVSCommandMock: any;
let executeCommandMock: any;
beforeEach(() => {
requiredRewire = rewire('../src/helpers/required');
tryExecuteCommandMock = sinon.stub(commands, 'tryExecuteCommand');
getWorkspaceRootMock = sinon.stub(workspace, 'getWorkspaceRoot');
showErrorMessageMock = sinon.stub(vscode.window, 'showErrorMessage');
executeVSCommandMock = sinon.stub(vscode.commands, 'executeCommand');
executeCommandMock = sinon.stub(commands, 'executeCommand');
});
afterEach(() => {
sinon.restore();
});
describe('getNodeVersion', () => {
it('should return empty string when tryExecuteCommand throw an error', async () => {
// Arrange
tryExecuteCommandMock.throws(TestConstants.testError);
// Act
const result = await requiredRewire.required.getNodeVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return empty string when tryExecuteCommand return not zero code', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: 'v11.0.0',
cmdOutputIncludingStderr: '',
code: 1,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getNodeVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return version', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: 'v11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getNodeVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
});
describe('getNpmVersion', () => {
it('should return empty string when tryExecuteCommand throw an error', async () => {
// Arrange
tryExecuteCommandMock.throws(TestConstants.testError);
// Act
const result = await requiredRewire.required.getNpmVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return empty string when tryExecuteCommand return not zero code', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: 'v11.0.0',
cmdOutputIncludingStderr: '',
code: 1,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getNpmVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return version', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: 'v11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getNpmVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
});
describe('getGitVersion', () => {
it('should return empty string when tryExecuteCommand throw an error', async () => {
// Arrange
tryExecuteCommandMock.throws(TestConstants.testError);
// Act
const result = await requiredRewire.required.getGitVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return empty string when tryExecuteCommand returns not zero code', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: ' 11.0.0',
cmdOutputIncludingStderr: '',
code: 1,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getGitVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return version', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: ' 11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getGitVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
});
describe('getPythonVersion', () => {
it('should return empty string when tryExecuteCommand throws an error', async () => {
// Arrange
tryExecuteCommandMock.throws(TestConstants.testError);
// Act
const result = await requiredRewire.required.getPythonVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return empty string when tryExecuteCommand returns not zero code', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: ' 11.0.0',
cmdOutputIncludingStderr: '',
code: 1,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getPythonVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
it('should return version', async () => {
// Arrange
const executionResult: commands.ICommandResult = {
cmdOutput: ' 11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getPythonVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
});
});
describe('getTruffleVersion', () => {
it('should return local version', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
const executionResult: commands.ICommandResult = {
cmdOutput: 'truffle@11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getTruffleVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
it('should return global version', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
const executionResult1: commands.ICommandResult = {
cmdOutput: '',
cmdOutputIncludingStderr: '',
code: 0,
};
const executionResult2: commands.ICommandResult = {
cmdOutput: 'Truffle v11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.onCall(0).returns(executionResult1);
tryExecuteCommandMock.onCall(1).returns(executionResult2);
// Act
const result = await requiredRewire.required.getTruffleVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.callCount, 2, 'tryExecuteCommand should be called twice');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
it('should throw an error when tryExecuteCommand throws an error on first call', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
tryExecuteCommandMock.onCall(0).throws(TestConstants.testError);
// Act and assert
await assert.rejects(requiredRewire.required.getTruffleVersion(), Error, TestConstants.testError);
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
it('should return empty string when tryExecuteCommand throws an error on second call', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
const executionResult1: commands.ICommandResult = {
cmdOutput: '',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.onCall(0).returns(executionResult1);
tryExecuteCommandMock.onCall(1).throws(TestConstants.testError);
// Act
const result = await requiredRewire.required.getTruffleVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.callCount, 2, 'tryExecuteCommand should be called twice');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
});
describe('getGanacheVersion', () => {
it('should return local version', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
const executionResult: commands.ICommandResult = {
cmdOutput: 'ganache-cli@11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.returns(executionResult);
// Act
const result = await requiredRewire.required.getGanacheVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
it('should return global version', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
const executionResult1: commands.ICommandResult = {
cmdOutput: '',
cmdOutputIncludingStderr: '',
code: 0,
};
const executionResult2: commands.ICommandResult = {
cmdOutput: 'v11.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.onCall(0).returns(executionResult1);
tryExecuteCommandMock.onCall(1).returns(executionResult2);
// Act
const result = await requiredRewire.required.getGanacheVersion();
// Assert
assert.strictEqual(result, '11.0.0', 'returned result should be defined');
assert.strictEqual(tryExecuteCommandMock.callCount, 2, 'tryExecuteCommand should be called twice');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
it('should throw an error when tryExecuteCommand throw an error on first call', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
tryExecuteCommandMock.onCall(0).throws(TestConstants.testError);
// Act and assert
await assert.rejects(requiredRewire.required.getGanacheVersion(), Error, TestConstants.testError);
assert.strictEqual(tryExecuteCommandMock.calledOnce, true, 'tryExecuteCommand should be called once');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
it('should return empty string when tryExecuteCommand throw an error on second call', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
const executionResult1: commands.ICommandResult = {
cmdOutput: '',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.onCall(0).returns(executionResult1);
tryExecuteCommandMock.onCall(1).throws(TestConstants.testError);
// Act
const result = await requiredRewire.required.getGanacheVersion();
// Assert
assert.strictEqual(result, '', 'returned result should be empty');
assert.strictEqual(tryExecuteCommandMock.callCount, 2, 'tryExecuteCommand should be called twice');
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, 'getWorkspaceRoot should be called once');
});
});
describe('isValid', () => {
const isValidCases = [
{
maxVersion: undefined,
minVersion: 'v6.0.0',
result: true,
version: 'v11.0.0',
},
{
maxVersion: 'v12.0.0',
minVersion: 'v6.0.0',
result: true,
version: 'v11.0.0',
},
{
maxVersion: 'v12.0.0',
minVersion: 'v6.0.0',
result: false,
version: 'v5.0.0',
},
{
maxVersion: 'v12.0.0',
minVersion: 'v6.0.0',
result: false,
version: 'v13.0.0',
},
];
isValidCases.forEach((element, index) => {
it(`should return correct result ${index + 1}`, () => {
// Act
const result = requiredRewire.required.isValid(element.version, element.minVersion, element.maxVersion);
// Assert
assert.strictEqual(result, element.result, 'returned result should be defined');
});
});
});
describe('getAllVersions', () => {
it('should return object with applications version', async () => {
// Arrange
tryExecuteCommandMock.onCall(0).returns(nodeValidVersion);
tryExecuteCommandMock.onCall(1).returns(npmValidVersion);
tryExecuteCommandMock.onCall(2).returns(gitValidVersion);
tryExecuteCommandMock.onCall(3).returns(pythonValidVersion);
tryExecuteCommandMock.onCall(4).returns(truffleValidVersion);
tryExecuteCommandMock.onCall(5).returns(ganacheValidVersion);
// Act
const result = await requiredRewire.required.getAllVersions();
// Assert
assert.strictEqual(result.length, 6, 'returned result should have length 6');
assert.strictEqual(tryExecuteCommandMock.callCount, 6, 'tryExecuteCommand should be called 6 times');
});
});
describe('checkAppsSilent', () => {
it('should return true when all versions are valid', async () => {
// Arrange
tryExecuteCommandMock.onCall(0).returns(nodeValidVersion);
tryExecuteCommandMock.onCall(1).returns(npmValidVersion);
tryExecuteCommandMock.onCall(2).returns(gitValidVersion);
tryExecuteCommandMock.onCall(3).returns(pythonValidVersion);
tryExecuteCommandMock.onCall(4).returns(truffleValidVersion);
tryExecuteCommandMock.onCall(5).returns(ganacheValidVersion);
// Act
const result = await requiredRewire.required.checkAppsSilent(
RequiredApps.node,
RequiredApps.npm,
RequiredApps.git,
RequiredApps.python,
);
// Assert
assert.strictEqual(result, true, 'returned result should be true');
assert.strictEqual(tryExecuteCommandMock.callCount, 4, 'tryExecuteCommand should be called 4 times');
});
it('should return false when there are invalid versions', async () => {
// Arrange
const executionResultGit: commands.ICommandResult = {
cmdOutput: ' 1.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const executionResultPython: commands.ICommandResult = {
cmdOutput: ' 2.5.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.onCall(0).returns(nodeValidVersion);
tryExecuteCommandMock.onCall(1).returns(npmValidVersion);
tryExecuteCommandMock.onCall(2).returns(executionResultGit);
tryExecuteCommandMock.onCall(3).returns(executionResultPython);
tryExecuteCommandMock.onCall(4).returns(truffleValidVersion);
tryExecuteCommandMock.onCall(5).returns(ganacheValidVersion);
// Act
const result = await requiredRewire.required.checkAppsSilent(
RequiredApps.node,
RequiredApps.npm,
RequiredApps.git,
RequiredApps.python,
);
// Assert
assert.strictEqual(result, false, 'returned result should be false');
assert.strictEqual(tryExecuteCommandMock.callCount, 4, 'tryExecuteCommand should be called 4 times');
});
});
describe('checkApps', () => {
it('should return true when all versions are valid', async () => {
// Arrange
tryExecuteCommandMock.onCall(0).returns(nodeValidVersion);
tryExecuteCommandMock.onCall(1).returns(npmValidVersion);
tryExecuteCommandMock.onCall(2).returns(gitValidVersion);
tryExecuteCommandMock.onCall(3).returns(pythonValidVersion);
tryExecuteCommandMock.onCall(4).returns(truffleValidVersion);
tryExecuteCommandMock.onCall(5).returns(ganacheValidVersion);
// Act
const result = await requiredRewire.required.checkApps(
RequiredApps.node,
RequiredApps.npm,
RequiredApps.git,
RequiredApps.python,
);
// Assert
assert.strictEqual(result, true, 'returned result should be true');
assert.strictEqual(tryExecuteCommandMock.callCount, 4, 'tryExecuteCommand should be called 4 times');
assert.strictEqual(showErrorMessageMock.called, false, 'showErrorMessage shouldn\'t be called');
assert.strictEqual(executeVSCommandMock.called, false, 'executeVSCommand shouldn\'t be called');
});
it('should return false when there are invalid versions', async () => {
// Arrange
const executionResultGit: commands.ICommandResult = {
cmdOutput: ' 1.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const executionResultPython: commands.ICommandResult = {
cmdOutput: ' 2.5.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.onCall(0).returns(nodeValidVersion);
tryExecuteCommandMock.onCall(1).returns(npmValidVersion);
tryExecuteCommandMock.onCall(2).returns(executionResultGit);
tryExecuteCommandMock.onCall(3).returns(executionResultPython);
tryExecuteCommandMock.onCall(4).returns(truffleValidVersion);
tryExecuteCommandMock.onCall(5).returns(ganacheValidVersion);
// Act
const result = await requiredRewire.required.checkApps(
RequiredApps.node,
RequiredApps.npm,
RequiredApps.git,
RequiredApps.python,
);
// Assert
assert.strictEqual(result, false, 'returned result should be false');
assert.strictEqual(tryExecuteCommandMock.callCount, 4, 'tryExecuteCommand should be called 4 times');
assert.strictEqual(showErrorMessageMock.called, true, 'showErrorMessage should be called');
assert.strictEqual(executeVSCommandMock.called, true, 'executeVSCommand should be called');
});
});
describe('checkRequiredApps', () => {
it('should return true when all versions are valid', async () => {
// Arrange
tryExecuteCommandMock.onCall(0).returns(nodeValidVersion);
tryExecuteCommandMock.onCall(1).returns(npmValidVersion);
tryExecuteCommandMock.onCall(2).returns(gitValidVersion);
tryExecuteCommandMock.onCall(3).returns(pythonValidVersion);
tryExecuteCommandMock.onCall(4).returns(truffleValidVersion);
tryExecuteCommandMock.onCall(5).returns(ganacheValidVersion);
// Act
const result = await requiredRewire.required.checkRequiredApps();
// Assert
assert.strictEqual(result, true, 'returned result should be true');
assert.strictEqual(tryExecuteCommandMock.callCount, 3, 'tryExecuteCommand should be called 3 times');
assert.strictEqual(showErrorMessageMock.called, false, 'showErrorMessage shouldn\'t be called');
assert.strictEqual(executeVSCommandMock.called, false, 'executeVSCommand shouldn\'t be called');
});
it('should return false when there are invalid versions', async () => {
// Arrange
const executionResultGit: commands.ICommandResult = {
cmdOutput: ' 1.0.0',
cmdOutputIncludingStderr: '',
code: 0,
};
const executionResultPython: commands.ICommandResult = {
cmdOutput: ' 2.5.0',
cmdOutputIncludingStderr: '',
code: 0,
};
tryExecuteCommandMock.onCall(0).returns(nodeValidVersion);
tryExecuteCommandMock.onCall(1).returns(npmValidVersion);
tryExecuteCommandMock.onCall(2).returns(executionResultGit);
tryExecuteCommandMock.onCall(3).returns(executionResultPython);
tryExecuteCommandMock.onCall(4).returns(truffleValidVersion);
tryExecuteCommandMock.onCall(5).returns(ganacheValidVersion);
// Act
const result = await requiredRewire.required.checkRequiredApps();
// Assert
assert.strictEqual(result, false, 'returned result should be false');
assert.strictEqual(tryExecuteCommandMock.callCount, 3, 'tryExecuteCommand should be called 3 times');
assert.strictEqual(showErrorMessageMock.called, true, 'showErrorMessageMock should be called');
assert.strictEqual(executeVSCommandMock.called, true, 'executeVSCommand should be called');
});
});
describe('installNpm', () => {
it('should install npm', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
executeCommandMock.returns(uuid.v4());
tryExecuteCommandMock.returns(npmValidVersion);
// Act
await requiredRewire.required.installNpm();
// Assert
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.calledOnce, true, 'executeCommand should be called once');
assert.strictEqual(tryExecuteCommandMock.called, true, 'tryExecuteCommand should be called');
});
it('should catch errors', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
executeCommandMock.throws(TestConstants.testError);
tryExecuteCommandMock.returns(npmValidVersion);
// Act
await requiredRewire.required.installNpm();
// Assert
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.calledOnce, true, 'executeCommand should be called once');
assert.strictEqual(tryExecuteCommandMock.called, true, 'tryExecuteCommand should be called');
});
});
describe('installTruffle', () => {
it('should install truffle', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
executeCommandMock.returns(uuid.v4());
tryExecuteCommandMock.returns(truffleValidVersion);
// Act
await requiredRewire.required.installTruffle();
// Assert
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.calledOnce, true, 'executeCommand should be called once');
assert.strictEqual(tryExecuteCommandMock.called, true, 'tryExecuteCommand should be called');
});
it('should catch errors', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
executeCommandMock.throws(TestConstants.testError);
tryExecuteCommandMock.returns(truffleValidVersion);
// Act
await requiredRewire.required.installTruffle();
// Assert
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.calledOnce, true, 'executeCommand should be called once');
assert.strictEqual(tryExecuteCommandMock.called, true, 'tryExecuteCommand should be called');
});
});
describe('installGanache', () => {
it('should install ganache-cli', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
executeCommandMock.returns(uuid.v4());
tryExecuteCommandMock.returns(ganacheValidVersion);
// Act
await requiredRewire.required.installGanache();
// Assert
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.calledOnce, true, 'executeCommand should be called once');
assert.strictEqual(tryExecuteCommandMock.called, true, 'tryExecuteCommand should be called');
});
it('should catch errors', async () => {
// Arrange
getWorkspaceRootMock.returns(uuid.v4());
executeCommandMock.throws(TestConstants.testError);
tryExecuteCommandMock.returns(ganacheValidVersion);
// Act
await requiredRewire.required.installGanache();
// Assert
assert.strictEqual(getWorkspaceRootMock.called, true, 'getWorkspaceRoot should be called');
assert.strictEqual(executeCommandMock.calledOnce, true, 'executeCommand should be called once');
assert.strictEqual(tryExecuteCommandMock.called, true, 'tryExecuteCommand should be called');
});
});
});
});

Просмотреть файл

@ -1,106 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as fs from 'fs-extra';
import * as path from 'path';
export const referenceMnemonic = 'some menmonic some menmonic some menmonic some menmonic some menmonic some menmonic';
export const referenceCfgContent = 'const HDWalletProvider = require("truffle-hdwallet-provider");'
+ 'module.exports = {'
+ ' networks: {'
+ ' development: {'
+ ' host: "127.0.0.1",'
+ ' port: 8545,'
+ ' network_id: "*"'
+ ' },'
+ ' "localhost:123": {'
+ ' from: "string",'
+ ' gas: 2,'
+ ' gasPrice: 3,'
+ ' host: "127.0.0.1",'
+ ' network_id: "*",'
+ ' port: 123,'
+ ' provider: new HDWalletProvider('
+ ' fs.readFileSync("path", "encoding"),'
+ ' "url"),'
+ ' skipDryRun: true,'
+ ' timeoutBlocks: 4,'
+ ' websockets: false,'
+ ' }'
+ ' },'
+ ' mocha: {},'
+ ' compilers: {'
+ ' solc: {}'
+ ' }'
+ '};';
export const referenceCfgContentWithDirectories = 'const HDWalletProvider = require("truffle-hdwallet-provider");'
+ 'module.exports = {'
+ ' contracts_build_directory: "build",'
+ ' contracts_directory: "test_contracts",'
+ ' migrations_directory: "test_migrations",'
+ ' networks: {'
+ ' development: {'
+ ' host: "127.0.0.1",'
+ ' port: 8545,'
+ ' network_id: "*"'
+ ' },'
+ ' "localhost:123": {'
+ ' from: "string",'
+ ' gas: 2,'
+ ' gasPrice: 3,'
+ ' host: "127.0.0.1",'
+ ' network_id: "*",'
+ ' port: 123,'
+ ' provider: new HDWalletProvider('
+ ' fs.readFileSync("path", "encoding"),'
+ ' "url"),'
+ ' skipDryRun: true,'
+ ' timeoutBlocks: 4,'
+ ' websockets: false,'
+ ' }'
+ ' },'
+ ' mocha: {},'
+ ' compilers: {'
+ ' solc: {}'
+ ' }'
+ '};';
export const referenceConfiguration = {
contracts_build_directory: 'build\\contracts',
contracts_directory: 'contracts',
migrations_directory: 'migrations',
networks: [
{
name: 'development',
options: {
host: '127.0.0.1',
network_id: '*',
port: 8545,
},
},
{
name: 'localhost:123',
options: {
from: 'string',
gas: 2,
gasPrice: 3,
host: '127.0.0.1',
network_id: '*',
port: 123,
provider: {
mnemonic: referenceMnemonic,
raw: 'new HDWalletProvider(fs.readFileSync(\"path\", \"encoding\"), \"url\")',
url: 'url',
},
skipDryRun: true,
timeoutBlocks: 4,
websockets: false,
},
},
],
};
const referenceAstPath = path.join(__dirname, 'referenceAstObject.json');
export const referenceAstObject = JSON.parse(fs.readFileSync(referenceAstPath, 'utf-8').toString());

Просмотреть файл

@ -1,286 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as assert from 'assert';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as sinon from 'sinon';
import { TruffleConfiguration } from '../src/helpers';
import * as workspace from '../src/helpers/workspace';
import * as testData from './testData/truffleConfigTestdata';
describe('TruffleConfiguration helper', () => {
afterEach(() => {
sinon.restore();
});
it('generateMnemonic should return correct sequence',
async () => {
// Act
const result = TruffleConfiguration.generateMnemonic();
// Assert
// 11 spaces + 12 words, 1 word = at least 1 char
assert.strictEqual(result.length > 23, true, 'result length should be greater than 23');
assert.strictEqual(result.split(' ').length, 12, 'number of words should be equal to 12');
});
it('getTruffleConfigUri returns correct value and check path for existence',
async () => {
// Arrange
const referencePath = path.normalize('w:/temp/truffle-config.js');
sinon.stub(workspace, 'getWorkspaceRoot').returns(path.normalize('w:/temp'));
const pathExistsStub = sinon.stub(fs, 'pathExistsSync').returns(true);
// Act
const result = TruffleConfiguration.getTruffleConfigUri();
// Assert
assert.strictEqual(result, referencePath, 'result should be correct uri');
assert.strictEqual(pathExistsStub.calledOnce, true, 'pathExists should called once');
});
it('getTruffleConfigUri throw an exception if path is not existed',
async () => {
// Arrange
sinon.stub(workspace, 'getWorkspaceRoot').returns('');
sinon.stub(fs, 'pathExistsSync').returns(false);
// Act and Assert
assert.throws(TruffleConfiguration.getTruffleConfigUri);
});
});
describe('class TruffleConfig', () => {
const configPathStub = path.normalize('w:/temp/truffle-config.js');
let readFileStub: sinon.SinonStub<any, any>;
let writeFileStub: sinon.SinonStub<any, any>;
before(() => {
readFileStub = sinon.stub(fs, 'readFileSync');
writeFileStub = sinon.stub(fs, 'writeFileSync');
readFileStub.withArgs(configPathStub).returns(testData.referenceCfgContent);
readFileStub.withArgs('path').returns(testData.referenceMnemonic);
readFileStub.withArgs('path', 'encoding').returns(testData.referenceMnemonic);
});
after(() => {
sinon.restore();
});
afterEach(() => {
sinon.resetHistory();
});
it('getAST should load correct AST',
async () => {
// Arrange
// Act
const result = (new TruffleConfiguration.TruffleConfig(configPathStub)).getAST();
// Assert
assert.deepEqual(result, testData.referenceAstObject, 'result should be equal to expected result');
assert.strictEqual(readFileStub.callCount > 0, true, 'readFile should called more then 0 times');
assert.strictEqual(
readFileStub.getCall(0).args[0],
configPathStub,
'readFile should called with correct arguments');
});
it('writeAST should write ast content to file',
async () => {
// Arrange
// Act
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
truffleConfig.getAST();
truffleConfig.writeAST();
// Assert
assert.strictEqual(writeFileStub.callCount > 0, true, 'writeFile should called more then 0 times');
assert.strictEqual(
writeFileStub.getCall(0).args[0],
configPathStub,
'writeFile should called with correct arguments');
assert.strictEqual(// 60 - first line, to avoid EOL differences
writeFileStub.getCall(0).args[1].substring(0, 60),
testData.referenceCfgContent.substring(0, 60),
'writeFile should called with correct arguments',
);
});
it('getNetworks should returns correct networks',
async () => {
// Arrange
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
// Act
const result = truffleConfig.getNetworks();
// Assert
assert.deepStrictEqual(
result[0],
testData.referenceConfiguration.networks[0],
'result first item should be equal to expected network');
assert.deepStrictEqual(
result[1],
testData.referenceConfiguration.networks[1],
'result second item should be equal to expected network');
});
it('setNetworks should add a network item',
async () => {
// Arrange
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
const newNetwork = {
name: 'newNetworkName',
options: {
network_id: 'ntwrk',
},
};
// Act
const resultBefore = truffleConfig.getNetworks();
truffleConfig.setNetworks(newNetwork);
const resultAfter = truffleConfig.getNetworks();
// Assert
assert.strictEqual(resultBefore.length, 2, 'before execution should be 2 networks');
assert.strictEqual(resultAfter.length, 3, 'after execution should be 2 networks');
assert.deepStrictEqual(resultAfter[2], newNetwork, 'last network should be equal to test network');
});
it('setNetworks should threw an exception if network already existed',
async () => {
// Arrange
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
const newNetwork = {
name: 'development',
options: {
network_id: 'ntwrk',
},
};
const action = () => {
truffleConfig.setNetworks(newNetwork);
};
// Act and Assert
assert.throws(action);
});
it('importFs should add correct import line',
async () => {
// Arrange
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
// Act
truffleConfig.importPackage('fs', 'fs');
// Assert
const configContent = writeFileStub.getCall(0).args[1];
assert.strictEqual(
configContent.includes('fs = require(\'fs\');'),
true,
'configContent should include test string');
});
});
describe('getConfiguration() in class TruffleConfig', () => {
const configPathStub = path.normalize('w:/temp/truffle-config.js');
let readFileStub: sinon.SinonStub<any, any>;
beforeEach(() => {
readFileStub = sinon.stub(fs, 'readFileSync');
readFileStub.withArgs('path').returns(testData.referenceMnemonic);
readFileStub.withArgs('path, encoding').returns(testData.referenceMnemonic);
});
afterEach(() => {
sinon.restore();
});
it('getConfiguration returns default configuration',
async () => {
// Arrange
readFileStub.returns('');
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
// Act
const result = truffleConfig.getConfiguration();
// Assert
assert.strictEqual(
result.contracts_build_directory,
path.normalize('build/contracts'),
'result should contain contracts build directory');
assert.strictEqual(
result.contracts_directory,
'contracts',
'result should contain contracts directory');
assert.strictEqual(
result.migrations_directory,
'migrations',
'result should contain migration build directory');
assert.deepStrictEqual(result.networks, undefined, 'result.networks should be undefined');
});
it('getConfiguration returns configuration without required fields',
async () => {
// Arrange
readFileStub.returns(testData.referenceCfgContent);
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
// Act
const result = truffleConfig.getConfiguration();
// Assert
assert.strictEqual(
result.contracts_build_directory,
path.normalize('build/contracts'),
'result should contain contracts build directory');
assert.strictEqual(
result.contracts_directory,
'contracts',
'result should contain contracts directory');
assert.strictEqual(
result.migrations_directory,
'migrations',
'result should contain migration build directory');
assert.deepStrictEqual(
result.networks,
testData.referenceConfiguration.networks,
'result.networks should be equal to test networks');
});
it('getConfiguration returns configuration with required fields',
async () => {
// Arrange
readFileStub.returns(testData.referenceCfgContentWithDirectories);
const truffleConfig = new TruffleConfiguration.TruffleConfig(configPathStub);
// Act
const result = truffleConfig.getConfiguration();
// Assert
assert.strictEqual(
result.contracts_build_directory,
'build',
'result should contain contracts build directory');
assert.strictEqual(
result.contracts_directory,
'test_contracts',
'result should contain contracts test_contracts directory');
assert.strictEqual(
result.migrations_directory,
'test_migrations',
'result should contain contracts test_migrations directory');
assert.deepStrictEqual(
result.networks,
testData.referenceConfiguration.networks,
'result.networks should be equal to test networks');
});
});

Просмотреть файл

@ -1,214 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as assert from 'assert';
import * as fs from 'fs';
import * as sinon from 'sinon';
import { InputBoxOptions, QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
import { Constants } from '../src/Constants';
import * as userInteraction from '../src/helpers/userInteraction';
import { CancellationEvent } from '../src/Models';
interface ITestItems extends QuickPickItem {
id: number;
label: string;
description: string;
testProperty: string;
}
describe('User interaction test', () => {
let windowMock: sinon.SinonMock;
beforeEach(() => {
windowMock = sinon.mock(window);
});
afterEach(() => {
sinon.restore();
});
it('showInputBox should return a value', async () => {
// Arrange
const option: InputBoxOptions = {};
windowMock.expects('showInputBox').withArgs(option).returns('test');
// Act
const result = await userInteraction.showInputBox(option);
// Assert
assert.strictEqual(result, 'test');
});
it('showInputBox should throw cancellation event', async () => {
// Arrange
const option: InputBoxOptions = {};
windowMock.expects('showInputBox').withArgs(option).returns(undefined);
// Act and assert
await assert.rejects(userInteraction.showInputBox(option), CancellationEvent);
});
it('showQuickPick should return a value', async () => {
// Arrange
const option: QuickPickOptions = {};
const items: QuickPickItem[] = [
{
description: 'test 1',
label: 'test 1',
},
{
description: 'test 2',
label: 'test 2',
},
];
windowMock.expects('showQuickPick').withArgs(items, option).returns(items[1]);
// Act
const result = await userInteraction.showQuickPick(items, option);
// Assert
assert.deepStrictEqual(result, items[1]);
});
it('showQuickPick with custom items should return a value', async () => {
// Arrange
const option: QuickPickOptions = {};
const items: ITestItems[] = [
{
description: 'test 1',
id: 1,
label: 'test 1',
testProperty: 'test 1',
},
{
description: 'test 2',
id: 2,
label: 'test 2',
testProperty: 'test 2',
},
];
windowMock.expects('showQuickPick').withArgs(items, option).returns(items[1]);
// Act
const result = await userInteraction.showQuickPick(items, option);
// Assert
assert.deepStrictEqual(result, items[1]);
});
it('showQuickPick should throw cancellation event', async () => {
// Arrange
const option: QuickPickOptions = {};
const items: QuickPickItem[] = [
{
description: 'test 1',
label: 'test 1',
},
{
description: 'test 2',
label: 'test 2',
},
];
windowMock.expects('showQuickPick').withArgs(items, option).returns(undefined);
// Act and assert
await assert.rejects(userInteraction.showQuickPick(items, option), CancellationEvent);
});
it('showConfirmPaidOperationDialog should throw cancellation event if answer not yes', async () => {
// Arrange
const answer = 'test';
windowMock.expects('showInputBox').returns(answer);
// Act and assert
await assert.rejects(userInteraction.showConfirmPaidOperationDialog(), CancellationEvent);
});
it('showConfirmPaidOperationDialog should throw cancellation event if answer undefined', async () => {
// Arrange
windowMock.expects('showInputBox').returns(undefined);
// Act and assert
await assert.rejects(userInteraction.showConfirmPaidOperationDialog(), CancellationEvent);
});
it('showConfirmPaidOperationDialog should not throw cancellation event if answer yes', async () => {
// Arrange
const answer = Constants.confirmationDialogResult.yes;
windowMock.expects('showInputBox').returns(answer);
// Act and assert
await userInteraction.showConfirmPaidOperationDialog();
});
it('showOpenFolderDialog should return a folder path', async () => {
// Arrange
const folderPath = 'test/test';
const uris: Uri[] = [{ fsPath: folderPath} as Uri];
windowMock.expects('showOpenDialog').returns(uris);
// Act
const result = await userInteraction.showOpenFolderDialog();
// Assert
assert.deepStrictEqual(result, folderPath);
});
it('showOpenFolderDialog should return path of first folder', async () => {
// Arrange
const folderPath1 = 'test/test';
const folderPath2 = 'test2/test2';
const uris: Uri[] = [{ fsPath: folderPath1}, { fsPath: folderPath2}] as Uri[];
windowMock.expects('showOpenDialog').returns(uris);
// Act
const result = await userInteraction.showOpenFolderDialog();
// Assert
assert.strictEqual(result, folderPath1);
});
it('showOpenFolderDialog should throw cancellation event if dialog canceled', async () => {
// Arrange
windowMock.expects('showOpenDialog').returns(undefined);
// Act and assert
await assert.rejects(userInteraction.showOpenFolderDialog(), CancellationEvent);
});
it('saveTextInFile should return file path', async () => {
// Arrange
const fsMock = sinon.mock(fs);
const filePath = 'filePath';
const text = 'test text';
windowMock.expects('showSaveDialog').returns({ fsPath: filePath} as Uri);
fsMock.expects('writeFileSync');
// Act
const result = await userInteraction.saveTextInFile(text, filePath);
// Assert
assert.strictEqual(result, filePath);
});
it('saveTextInFile should throw cancellation event if dialog canceled', async () => {
// Arrange
const filePath = 'filePath';
const text = 'test text';
windowMock.expects('showSaveDialog').returns(undefined);
// Act and assert
await assert.rejects(userInteraction.saveTextInFile(text, filePath), CancellationEvent);
});
});

Просмотреть файл

@ -40,7 +40,8 @@
"linterOptions": {
"exclude": [
"node_modules/**",
"src/**/*.d.ts"
"src/**/*.d.ts",
"src/helpers/checkTruffleConfigTemplate.js"
]
},
"defaultSeverity": "warning"