Merge pull request #28 from microsoft/caleteet-100-updates
Updates for release v1.0.0
16
CHANGELOG.md
|
@ -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
|
||||
|
|
24
package.json
|
@ -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,
|
||||
|
|
279
src/Constants.ts
|
@ -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"
|
||||
|
|