Conteúdo


Fundamentos básicos do Hyperledger Composer, Parte 2

Refine e implemente sua rede de blockchain

Instale ferramentas de desenvolvimento e testes de unidade e implemente sua rede na IBM Cloud

Comments

Conteúdos da série:

Esse conteúdo é a parte # de # na série: Fundamentos básicos do Hyperledger Composer, Parte 2

Fique ligado em conteúdos adicionais dessa série.

Esse conteúdo é parte da série:Fundamentos básicos do Hyperledger Composer, Parte 2

Fique ligado em conteúdos adicionais dessa série.

Este tutorial é uma continuação da Parte 1, na qual você aprendeu como modelar e testar uma rede de negócios simples em uma versão local do Hyperledger Composer Playground. Agora vamos nos aprofundar no Hyperledger Composer e, enfim, importar o modelo de rede para o playground on-line na IBM Cloud.

Primeiro é necessário instalar algumas ferramentas do desenvolvedor. O vídeo neste tutorial orientará a instalação. Em seguida, você fará mudanças na rede de amostra Mercadorias Perecíveis com a qual você trabalhou na Parte 1. Especificamente, você vai modelar um sensor de GPS de IoT no contêiner de envio incluindo leituras do GPS no ativo de envio e vai modificar o contrato inteligente (chaincode) para enviar um alerta quando o envio atingir sua porta de destino.

Você também aprenderá como testar a unidade das redes de blockchain usando uma ferramenta de Desenvolvimento Orientado por Comportamento (BDD) chamada Cucumber. Você usará um arquivo do recurso Cucumber para testar a lógica do contrato inteligente.

Finalmente, você importará o modelo para o playground online hospedado na IBM Cloud, no qual poderá interagir com ele e enviará transações por meio da interface com o usuário do playground, como você fez na Parte 1. Como o playground online está na IBM Cloud, não é necessária uma instalação para usá-lo.

Pré-requisitos

Além desses poucos pré-requisitos, a próxima seção percorrerá as ferramentas do desenvolvedor que precisam ser instaladas.

1

Configurar seu ambiente

No momento da escrita desse artigo, o Composer é suportado apenas no Ubuntu Linux e no MacOS, mas o suporte do Windows está a caminho.

Para a maioria das ferramentas que precisam ser instaladas, as instruções de instalação do Ubuntu Linux e do MacOS são praticamente as mesmas, mas eu vou apontar algumas diferenças à medida em que avançarmos. (Para saber como configurar o computador, assista ao vídeo.)

1a

Instale o Node.js

A maneira mais fácil de instalar o Node.js é usar o NVM, que significa Node Version Manager. Como o nome demonstra, o NVM é usado para gerenciar a versão do Node que é instalada no computador. Para instalar o NVM, siga as instruções que correspondem à sua plataforma.

Instale o NVM no Ubuntu Linux

A equipe do Hyperledger Composer oferece um script para instalar o NVM. Para instalar o NVM, execute o seguinte:

                curl -O https://hyperledger.github.io/composer/prereqs-ubuntu.sh
                chmod u+x prereqs-ubuntu.sh
                ./prereqs-ubuntu.sh

Será solicitado que você insira sua senha (assegure-se de que você seja um sudoer no sistema). Para obter mais informações, visite Instalando e desenvolvendo com o Hyperledger Composer.

Quando o script for concluído, estará tudo pronto para instalar o Node.js. Passe para a seção "Use o NVM para instalar o Node.js" agora.

Instale o NVM no MacOS

O MacOS oferece sua própria versão de várias ferramentas de linha de comandos populares como o Git, o Make e o SVN. Para ver se as ferramentas de linha de comando xcode estão instaladas, abra uma janela do terminal, digite gite pressione Enter.

Figura 1. Se esta mensagem for exibida, será necessário instalar as ferramentas de linha de comandos
If you see this message, you need to install the                     command-line tools
If you see this message, you need to install the command-line tools

Se aparecer uma mensagem semelhante à da Figura 1, clique no botão Instalar para instalar as ferramentas de linha de comandos. A instalação demora menos de cinco minutos.

Execute este comando do terminal:

                curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash

Observação: verifique o leia-me no repositório NVM do GitHub para assegurar-se de que você esteja instalando a versão mais recente (0.33.6 no momento da composição deste artigo).

O script faz mudanças nas configurações do Bash shell, portanto, é necessário sair da janela do terminal e abrir uma nova para carregar as novas configurações.

Para verificar se o NVM está instalado corretamente, execute o comando nvm --version na janela do terminal. A saída será semelhante a esta:

                $ nvm --version
                0.33.6

Agora você está pronto para instalar o Node.js usando o NVM.

Use o nvm para instalar o Node.js

Para instalar o Node.js, acesse a linha de comando (Ubuntu) ou abra uma janela do terminal (MacOS) para executar o comando nvm install --lts para instalar a versão LTS do Node.js:

nvm install --lts

A saída será semelhante a esta:

                $ nvm install --lts
                Installing latest LTS version.
                Downloading and installing node v8.9.0...
                Downloading https://nodejs.org/dist/v8.9.0/node-v8.9.0-darwin-x64.tar.gz...
                ######################################################################## 100.0%
                Computing checksum with shasum -a 256
                Checksums matched!
                .
                .
                (MAIS RESULTADOS A PARTIR DO COMPILADOR)
                .
                .
                Usando agora o nó v8.9.0 (npm v5.5.1)

A instalação pode demorar alguns minutos enquanto o código é compilado para sua plataforma (esse é o caso para o MacOS, pelo menos), portanto, seja paciente.

Finalmente, verifique se o Node.js foi instalado:

                $ node -v
                v8.9.0

Nesse caso, eu instalei o Node.js 8.9.0, que é a versão mais recente do LTS no momento em que esse artigo foi escrito.

1b

Instale a interface da linha de comandos (CLI) do Composer

Use a interface da linha de comandos (CLI) para criar, implementar e atualizar redes de negócios e executar outras funções relacionadas a redes de blockchain.

Para instalar a CLI do Composer, acesse a linha de comando (Ubuntu) ou abra uma janela do terminal (MacOS) e insira este comando:

                npm install -g composer-cli

NPM significa Node Package Manager e foi instalado quando o NVM instalou o Node.js. Normalmente, quando um pacote do Node.js é instalado por meio do NPM, ele fica disponível somente na árvore de diretórios em que foi instalado. A especificação da opção -g solicita que o NPM instale o pacote globalmente, disponibilizando-o para qualquer projeto Node.js no computador.

Verifique se a composer-cli foi instalada corretamente. Execute o comando composer -v na linha de comando (Ubuntu) ou na janela do terminal (MacOS), e o número da versão como saída:

                $ composer -v
                v0.15.0
1c

Instale o VSCode

VSCode é um editor de software livre da Microsoft. O código-fonte é disponibilizado gratuitamente para download no repositório VSCode do GitHub da Microsoft.

Não é necessário instalar o VSCode para fazer o desenvolvimento do Hyperledger Composer, mas é recomendado pela equipe do Composer e, além disso, o VSCode é muito bom. Existe uma extensão do Hyperledger Composer para o VSCode, que pode ser instalada e ativada facilmente. Ela oferece uma integração perfeita com o Git, juntamente com o destaque da sintaxe para arquivos de modelo de rede de negócios do Composer.

Instale o VSCode no Ubuntu Linux

Para instalar no Ubuntu (ou em outro Linux baseado em Debian), escolha uma destas opções:

  • .deb— Pacote Debian
  • .rpm—RPM Package Manager (originalmente chamado de Red Hat Package Manager)
  • .tar.gz— Tarball

Escolha seu método preferido e siga as instruções de instalação detalhadas no website do VSCode.

Instale o VSCode no MacOS

Para instalar no MacOS, clique no botão Download para Mac e um arquivo zip contendo o aplicativo VSCode será transferido por download para o Mac. Consulte o website do VSCode para obter instruções detalhadas de como instalar e executar o VSCode.

1d

Instale a extensão do Hyperledger Composer

Para aproveitar ao máximo o destaque da sintaxe ao editar arquivos do Hyperledger Composer, instale a extensão do Composer para VSCode. Inicie o VSCode e clique no ícone de Extensões à esquerda da interface com o usuário (ou pressione Cmd + X no Mac) para abrir o editor de Extensões.

Digite Hyperledger no campo de procura e a extensão do Hyperledger Composer será exibida na lista logo abaixo do campo Procurar, como mostra a Figura 2. Clique no botão Instalar e, quando a instalação for concluída, reinicie o VSCode para ativar a extensão.

Figura 2. Mercado de extensão do VSCode
VSCode Extension Marketplace
VSCode Extension Marketplace

Agora, sempre que você usar o VSCode para editar um arquivo de projeto do Hyperledger Composer, sua sintaxe será destacada automaticamente. A Figura 3 mostra o arquivo de modelo perishable.cto aberto na janela do editor VSCode. Observe o destaque da sintaxe das palavras-chave namespace e enum.

Figura 3. Rede Mercadorias Perecíveis no VSCode
VSCode Extension Marketplace
VSCode Extension Marketplace

Vídeo: configure seu ambiente

Este vídeo mostra como configurar seu ambiente.

2

Comece a desenvolver

Agora que você já tem as ferramentas, chegou a hora de fazê-las trabalhar. Você vai clonar o repositório perishable-network do GitHub que eu forneci e, em seguida, criará o código e fará o teste de unidade usando as ferramentas Node.js recém-instaladas.

Escolha um local no computador para trabalhar com o Hyperledger Composer e os modelos de rede. Por exemplo, eu uso o ~/HyperledgerComposer como meu diretório raiz do Composer e configurei uma variável de ambiente no Bash shell que estou usando:

$ export COMPOSER_ROOT=~/HyperledgerComposer

Para que este tutorial seja confiável quanto ao local, vou chamar esse diretório de $COMPOSER_ROOT. Quando aparecer $COMPOSER_ROOT nos próximos exemplos, o termo estará se referindo ao local que você escolheu. Eu sugiro configurar o $COMPOSER_ROOT para o local, como eu fiz acima.

Acesse uma linha de comando (Ubuntu) ou abra uma janela do terminal (MacOS), navegue para o diretório $COMPOSER_ROOT e insira este comando: git clone https://github.com/makotogo/developerWorks.git conforme mostrado abaixo.

                $ cd $COMPOSER_ROOT
                $ pwd
                /Users/sperry/HyperledgerComposer
                $ git clone https://github.com/makotogo/developerWorks.git
                Cloning into 'developerWorks'...
                remote: Counting objects: 364, done.
                remote: Compressing objects: 100% (45/45), done.
                remote: Total 364 (delta 33), reused 78 (delta 25), pack-reused 277
                Receiving objects: 100% (364/364), 146.69 KiB | 754.00 KiB/s, done.
                Resolving deltas: 100% (162/162), done.

Agora você tem o código. Este é o momento de compilá-lo e testá-lo.

Use o gerenciador de pacote (NPM) do Node.js para executar uma compilação e, em seguida, execute os testes de unidade que eu forneci. Execute estes comandos:

                cd $COMPOSER_ROOT/developerWorks/perishable-network
                npm install && npm test

Aqui está o que acontece: primeiro você navega para o diretório no qual o código perishable-network reside. Em seguida, executa npm install, que configura o ambiente local do Node.js (ou seja, local para o perishable-network). Em seguida, executa npm test, que executa os testes de unidade que fazem parte do projeto (consulte package.json).

Aparecerá muitas saídas, mas a última será como esta, indicando que os testes foram bem-sucedidos:

                    .
                    .
                  Perishable Shipping Network
                    #shipment
                Adding temperature 4.5 to shipment SHIP_001
                Received at: Wed Nov 01 2017 10:58:12 GMT-0500 (CDT)
                Contract arrivalDateTime: Thu Nov 02 2017 10:58:12 GMT-0500 (CDT)
                Lowest temp reading: 4.5
                Highest temp reading: 4.5
                Payout: 2500
                Grower: farmer@email.com new balance: 2500
                Importer: supermarket@email.com new balance: -2500
                      ✓ should receive base price for a shipment within temperature range (90ms)
                Adding temperature 1 to shipment SHIP_001
                Received at: Wed Nov 01 2017 10:58:12 GMT-0500 (CDT)
                Contract arrivalDateTime: Thu Nov 02 2017 10:58:12 GMT-0500 (CDT)
                Lowest temp reading: 1
                Highest temp reading: 4.5
                Min temp penalty: 0.2
                Payout: 1500
                Grower: farmer@email.com new balance: 4000
                Importer: supermarket@email.com new balance: -4000
                      ✓ should apply penalty for min temperature violation (81ms)
                Adding temperature 11 to shipment SHIP_001
                Received at: Wed Nov 01 2017 10:58:12 GMT-0500 (CDT)
                Contract arrivalDateTime: Thu Nov 02 2017 10:58:12 GMT-0500 (CDT)
                Lowest temp reading: 1
                Highest temp reading: 11
                Min temp penalty: 0.2
                Max temp penalty: 0.30000000000000004
                Payout: 999.9999999999998
                Grower: farmer@email.com new balance: 5000
                Importer: supermarket@email.com new balance: -5000
                      ✓ should apply penalty for max temperature violation (74ms)
                
                  3 passing (1s)
3

Refine a rede de negócios Mercadorias Perecíveis

A rede Mercadorias Perecíveis modela uma rede de negócios que inclui: um Grower, um Shipper e um Importer. As especificações estão descritas no README.md . O acordo entre os vários participantes desta rede é modelado usando a linguagem de modelagem CTO e aplicado pelo chaincode (contrato inteligente) escrito em JavaScript.

No exercício teórico desta seção, um sensor de GPS de IoT foi incluído nos contêineres de carga para fornecer o local de envio. Foi solicitado que você incluísse as leituras obtidas por este sensor no modelo de rede e enviasse um evento quando o envio atingisse seu destino.

Para incluir o sensor de GPS no modelo de rede, será necessário fazer mudanças no modelo de negócios e escrever testes de unidade adicionais. Em vez de escrever os testes de unidade no Mocha, vou mostrar como escrever usando uma ferramenta chamada Cucumber, que tem uma sintaxe mais compreensível e é tão eficiente quanto o Mocha.

3a

Modifique a definição de rede

Após fazer as mudanças nesta seção colando o código que forneci, sua solução deverá ser semelhante à que está no developerWorks/iot-perishable-network . Fique à vontade para usar este modelo como referência.

Para incluir o sensor de GPS, será necessário fazer algumas mudanças no modelo. Inicie o VSCode e abra o diretório raiz da rede Mercadorias Perecíveis ($COMPOSER_ROOT)/developerWorks/perishable-network). Abra o modelo de arquivo chamado perishable.cto, localizado no models .

Inclua uma nova variável enum para representar os principais locais no compasso logo abaixo de enum ShipmentStatus:

                /**
                 * Directions of the compass
                 */
                enum CompassDirection {
                  o N
                  o S
                  o E
                  o W
                }

As direções são N para o norte, S para sul e assim por diante. É importante restringir os dados inseridos para um conjunto de coordenadas de GPS e esta enum é usada para restringir os valores que podem ser inseridos no modelo e assegurar que eles sejam válidos.

Sempre que uma leitura de GPS for feita, ela será registrada no blockchain como uma transação, o que significa que será necessário incluir uma transação no modelo para ela. Logo abaixo da transação TemperatureReading, inclua uma nova transação GpsReading:

Lista 1. Transação para manipular o registro das leituras do GPS no blockchain
                /**
                 * A GPS reading for a shipment. E.g. received from a device
                 * within a shipping container
                 */
                transaction GpsReading extends ShipmentTransaction {
                  o String readingTime
                  o String readingDate
                  o String latitude
                  o CompassDirection latitudeDir
                  o String longitude
                  o CompassDirection longitudeDir
                }

Uma leitura de GPS requer vários parâmetros, incluindo quando a leitura foi obtida, juntamente com a latitude e a longitude. Essas informações são fornecidas como parâmetros para a transação.

Em seguida, para que a transação armazene a leitura de GPS no blockchain, as informações precisam fazer parte de um ativo de blockchain. Como uma leitura de GPS obtida do contêiner de envio, conceitualmente, faz parte de um envio, é natural incluir as leituras no ativo Shipment (como a TemperatureReadings internas). Inclua a linha destacada (linha 7) abaixo no ativo Shipment:

                asset Shipment identified by shipmentId {
                  o String shipmentId
                  o ProductType type
                  o ShipmentStatus status
                  o Long unitCount
                  o TemperatureReading[] temperatureReadings optional
                  o GpsReading[] gpsReadings optional
                  --> Contract contract
                }

Finalmente, inclua dois eventos no modelo: um quando um limite de temperatura for violado e outro quando o envio do contêiner atingir sua porta de destino:

Lista 2. Novos eventos - quando a temperatura no contêiner exceder a tolerância contratual e quando o envio do contêiner chegar na porta
                /**
                 * Um evento - quando a temperatura ultrapassa
os limites acordados */
                event TemperatureThresholdEvent {
                  o String message
                  o Double temperature
                  --> Shipment shipment
                }

                /**
                 * Um evento - quando o envio chega na porta */
                event ShipmentInPortEvent {
                  o String message
                  --> Shipment shipment
                }
3b

Inclua o chaincode

Você já modelou o sensor de GPS e a transação para incluir leituras de GPS no modelo. Agora, é necessário gravar o chaincode Javascript que manipula a atualização do blockchain. Abra lib/logic.js. Será necessário fazer várias mudanças neste arquivo.

Primeiro, inclua o código na função temperatureReading, que manipula a transação TemperatureReading. Substitua o corpo inteiro do método por este que está abaixo (as linhas que serão incluídas estão destacadas apenas para referência):

                function temperatureReading(temperatureReading) {
                
                    var shipment = temperatureReading.shipment;
                    var NS = "org.acme.shipping.perishable";
                    var contract = shipment.contract;
                    var factory = getFactory();
                
                    console.log('Adding temperature ' + temperatureReading.centigrade + ' to shipment ' + shipment.$identifier);
                
                    if (shipment.temperatureReadings) {
                        shipment.temperatureReadings.push(temperatureReading);
                    } else {
                        shipment.temperatureReadings = [temperatureReading];
                    }
                
                    if (temperatureReading.centigrade < contract.minTemperature ||
                        temperatureReading.centigrade > contract.maxTemperature) {
                        var temperatureEvent = factory.newEvent(NS, 'TemperatureThresholdEvent');
                        temperatureEvent.shipment = shipment;
                        temperatureEvent.temperature = temperatureReading.centigrade;
                        temperatureEvent.message = 'Temperature threshold violated! Emitting TemperatureEvent for shipment: ' + shipment.$identifier;
                        emit(temperatureEvent);
                    }
                
                    return getAssetRegistry(NS + '.Shipment')
                        .then(function (shipmentRegistry) {
                            // inclua a leitura de temperatura
no shipmentRegistry.update(shipment) do retorno do envio;
                        });
                }

Esse código verifica a leitura da temperatura atual em relação às estipulações contratuais e, se os limites de temperatura mínimo ou máximo foram atingidos, um evento TemperatureThresholdEvent será emitido.

Em seguida, inclua uma nova função para manipular a transação GpsReading.
Observação: é importante que você também inclua o bloco de comentários. Ele contém duas anotações importantes (@param e @transaction) que serão necessárias.

                /**
                 * A GPS reading has been received for a shipment
                 * @param {org.acme.shipping.perishable.GpsReading} gpsReading - the GpsReading transaction
                 * @transaction
                 */
                function gpsReading(gpsReading) {
                
                    var factory = getFactory();
                    var NS = "org.acme.shipping.perishable";
                    var shipment = gpsReading.shipment;
                    var PORT_OF_NEW_YORK = '/LAT:40.6840N/LONG:74.0062W';
                    
                    var latLong = '/LAT:' + gpsReading.latitude + gpsReading.latitudeDir + '/LONG:' +
                        gpsReading.longitude + gpsReading.longitudeDir;
                    
                    if (shipment.gpsReadings) {
                        shipment.gpsReadings.push(gpsReading);
                    } else {
                        shipment.gpsReadings = [gpsReading];
                    }
                
                    if (latLong == PORT_OF_NEW_YORK) {
                        var shipmentInPortEvent = factory.newEvent(NS, 'ShipmentInPortEvent');
                        shipmentInPortEvent.shipment = shipment;
                        var message = 'Shipment has reached the destination port of ' + PORT_OF_NEW_YORK;
                        shipmentInPortEvent.message = message;
                        emit(shipmentInPortEvent);
                    }
                
                    return getAssetRegistry(NS + '.Shipment')
                    .then(function (shipmentRegistry) {
                        // inclua a leitura de temperatura no
shipmentRegistry.update(shipment) do retorno do envio;
                        });
                }

O chaincode da transação armazena esta leitura de GPS na array de GpsReadings no ativo Shipment. Em seguida, ele verifica se essa leitura de GPS corresponde à porta de destino e, se corresponder, emite um ShipmentInPort . Finalmente, o blockchain é atualizado com o estado atual do Shipment.

3c

Inclua testes do recurso Cucumber

Vamos resumir. Você já incluiu uma transação no modelo e dois novos eventos. Agora, chegou a hora de realizar o teste de unidade das mudanças para assegurar-se de que elas funcionam. A equipe do Hyperledger Composer recomenda usar o Cucumber para realizar o teste de unidade dos modelos de negócios do Composer.

Crie um novo arquivo na pasta features chamado iot-perishable.feature e abra-o no VSCode. Vou explicar rapidamente cada uma das seções que precisam ser incluídas. Na seção "Teste de unidade com o Cucumber", vou explicar o Cucumber com mais detalhes. Mas antes, vamos fazer alguma coisa funcionar.

Primeiro, informe o Cucumber sobre o recurso que deseja testar, juntamente com as informações de quaisquer configurações que precisem ser realizadas antes de cada teste de unidade. Inclua o código a seguir no iot-perishable.feature vazio.

Lista 3. Recurso do Cucumber e informações
                Feature: IoT Perishable Network
                
                    Background:
                        Given I have deployed the business network definition ..
                        And I have added the following participants
                        """
                        [
                        {"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":0},
                        {"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":0},
                        {"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
                        ]
                        """
                        And I have added the following asset of type org.acme.shipping.perishable.Contract
                            | contractId | grower           | shipper               | importer           | arrivalDateTime  | unitPrice | minTemperature | maxTemperature | minPenaltyFactor | maxPenaltyFactor |
                            | CON_001    | grower@email.com | supermarket@email.com | supermarket@email.com | 10/26/2018 00:00 | 0.5       | 2              | 10             | 0.2              | 0.1              | 
                        
                        And I have added the following asset of type org.acme.shipping.perishable.Shipment
                            | shipmentId | type    | status     | unitCount | contract |
                            | SHIP_001   | BANANAS | IN_TRANSIT | 5000      | CON_001  |
                        When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
                            | shipment | centigrade |
                            | SHIP_001 | 4          |
                            | SHIP_001 | 5          |
                            | SHIP_001 | 10         |

Agora, é necessário incluir alguns testes de unidade, chamados Cenários. Inclua o Cenário abaixo logo após o bloco de informações no iot-perishable.feature .

Lista 4. Cenário: quando o intervalo de temperatura está dentro dos limites acordados
        Cenário: quando o intervalo de temperatura está entre limites pré-acordados
            Quando eu envio a seguinte transação do tipo org.acme.shipping.perishable.ShipmentReceived
                | shipment |
                | SHIP_001 |

            Portanto, terei os seguintes participantes
            """
            [
            {"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":2500},
            {"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-2500},
            {"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
            ]
            """

Este cenário assegura que o Grower receba a quantia completa quando a temperatura no contêiner de carga estiver dentro dos limites acordados.

Agora, inclua um cenário no qual o limite mínimo de temperatura igual a 2 graus Celsius é violado em 2 graus.

Lista 5. Cenário: quando o limite baixo/mínimo de temperatura é violado em 2 graus C
                Scenario: When the low/min temperature threshold is breached by 2 degrees C
                    Given I submit the following transaction of type org.acme.shipping.perishable.TemperatureReading
                        | shipment | centigrade |
                        | SHIP_001 | 0          |
            
                    When I submit the following transaction of type org.acme.shipping.perishable.ShipmentReceived
                        | shipment |
                        | SHIP_001 |
                    
                    Then I should have the following participants
                    """
                    [
                    {"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":500},
                    {"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-500},
                    {"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
                    ]
                    """

Nesse Cenário, a temperatura mínima cai para zero graus Celsius e o Grower é penalizado para cada grau Celsius abaixo do limite.

Agora, inclua um cenário no qual o limite máximo de temperatura é excedido em 2 graus Celsius.

Lista 6. Cenário: quando o limite alto/máximo de temperatura é violado em 2 graus
                Scenario: When the hi/max temperature threshold is breached by 2 degrees C
                    Given I submit the following transaction of type org.acme.shipping.perishable.TemperatureReading
                        | shipment | centigrade |
                        | SHIP_001 | 12          |
            
                    When I submit the following transaction of type org.acme.shipping.perishable.ShipmentReceived
                        | shipment |
                        | SHIP_001 |
                    
                    Then I should have the following participants
                    """
                    [
                    {"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":1500},
                    {"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-1500},
                    {"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
                    ]
                    """

Nesse Cenário, a temperatura máxima sobe acima de 10 graus Celsius e o Grower é penalizado para cada grau Celsius acima do limite.

Finalmente, inclua três cenários (dois TemperatureThresholdEvents e um ShipmentInPortEvent) no modelo como é mostrado na Listagem 2.

Lista 7. Cenário: eventos
                Scenario: Test TemperatureThresholdEvent is emitted when the min temperature threshold is violated
                    When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
                        | shipment | centigrade |
                        | SHIP_001 | 0          |
                    
                    Then I should have received the following event of type org.acme.shipping.perishable.TemperatureThresholdEvent
                        | message                                                                          | temperature | shipment |
                        | Temperature threshold violated! Emitting TemperatureEvent for shipment: SHIP_001 | 0           | SHIP_001 |
                
            
                Scenario: Test TemperatureThresholdEvent is emitted when the max temperature threshold is violated
                    When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
                        | shipment | centigrade |
                        | SHIP_001 | 11         |
                    
                    Then I should have received the following event of type org.acme.shipping.perishable.TemperatureThresholdEvent
                        | message                                                                          | temperature | shipment |
                        | Temperature threshold violated! Emitting TemperatureEvent for shipment: SHIP_001 | 11          | SHIP_001 |
                
            
                Scenario: Test ShipmentInPortEvent is emitted when GpsReading indicates arrival at destination port
                    When I submit the following transaction of type org.acme.shipping.perishable.GpsReading
                        | shipment | readingTime | readingDate | latitude | latitudeDir | longitude | longitudeDir |
                        | SHIP_001 | 120000      | 20171025    | 40.6840  | N           | 74.0062   | W            |
            
                    Then I should have received the following event of type org.acme.shipping.perishable.ShipmentInPortEvent
                        | message                                                                           | shipment |
                        | Shipment has reached the destination port of /LAT:40.6840N/LONG:74.0062W | SHIP_001 |

Finalmente, é necessário modificar o package.json para que ele fique semelhante ao que está abaixo. Eu destaquei as linhas que precisam ser modificadas (linha 18) e incluídas (linhas 41 e 42).

                {
                  "engines": {
                    "composer": "^0.15.0"
                  },
                  "name": "perishable-network",
                  "version": "0.1.11",
                  "description": "Shipping Perishable Goods Business Network",
                  "networkImage": "https://github.com/makotogo/developerWorks/perishable-network/networkimage.svg",
                  "networkImageanimated": "https://github.com/makotogo/developerWorks/perishable-network/networkimageanimated.svg",
                  "scripts": {
                    "prepublish": "mkdirp ./dist && composer archive create  --sourceType dir --sourceName . -a ./dist/perishable-network.bna",
                    "pretest": "npm run lint",
                    "lint": "eslint .",
                    "postlint": "npm run licchk",
                    "licchk": "license-check",
                    "postlicchk": "npm run doc",
                    "doc": "jsdoc --pedantic --recurse -c jsdoc.json",
                    "test": "mocha -t 0 --recursive && cucumber-js",
                    "deploy": "./scripts/deploy.sh"
                  },
                  "repository": {
                    "type": "git",
                    "url": "https://github.com/makotogo/developerWorks.git"
                  },
                  "keywords": [
                    "shipping",
                    "goods",
                    "perishable",
                    "composer",
                    "composer-network",
                    "iot"
                  ],
                  "author": "Hyperledger Composer",
                  "license": "Apache-2.0",
                  "devDependencies": {
                    "browserfs": "^1.2.0",
                    "chai": "^3.5.0",
                    "composer-admin": "^0.14.0-0",
                    "composer-cli": "^0.14.0-0",
                    "composer-client": "^0.14.0-0",
                    "composer-connector-embedded": "^0.14.0-0",
                    "composer-cucumber-steps": "^0.14.0-0",
                    "cucumber": "^2.2.0",
                    "eslint": "^3.6.1",
                    "istanbul": "^0.4.5",
                    "jsdoc": "^3.4.1",
                    "license-check": "^1.1.5",
                    "mkdirp": "^0.5.1",
                    "mocha": "^3.2.0",
                    "moment": "^2.17.1"
                  },
                  "license-check-config": {
                    "src": [
                      "**/*.js",
                      "!./coverage/**/*",
                      "!./node_modules/**/*",
                      "!./out/**/*",
                      "!./scripts/**/*"
                    ],
                    "path": "header.txt",
                    "blocking": true,
                    "logInfo": false,
                    "logError": true
                  }
                }

Observe que você incluiu dois módulos novos do Node (linhas 41 e 42 acima) no package.json. Para instalá-los, acesse a linha de comando (Ubuntu) ou abra uma janela do terminal (MacOS) e execute o npm install .

3d

Execute os testes de unidade

Agora, realize os testes de unidade executando npm test na linha de comando. Uma saída grande será emitida, mas desta vez, além dos testes do Mocha, você verá um bloco de saída para cada cenário do recurso Cucumber. Os testes do recurso Cucumber começam como este (estou mostrando apenas o primeiro por motivo de espaço).

                Feature: IoT Perishable Network
                
                  Scenario: When the temperature range is within the agreed-upon boundaries
                  ✔ Given I have deployed the business network definition ..
                  ✔ And I have added the following participants
                      """
                      [
                      {"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":0},
                      {"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":0},
                      {"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
                      ]
                      """
                  ✔ And I have added the following asset of type org.acme.shipping.perishable.Contract
                      | contractId | grower           | shipper               | importer              | arrivalDateTime  | unitPrice | minTemperature | maxTemperature | minPenaltyFactor | maxPenaltyFactor |
                      | CON_001    | grower@email.com | supermarket@email.com | supermarket@email.com | 10/26/2018 00:00 | 0.5       | 2              | 10             | 0.2              | 0.1              |
                  ✔ And I have added the following asset of type org.acme.shipping.perishable.Shipment
                      | shipmentId | type    | status     | unitCount | contract |
                      | SHIP_001   | BANANAS | IN_TRANSIT | 5000      | CON_001  |
                  ✔ When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
                      | shipment | centigrade |
                      | SHIP_001 | 4          |
                      | SHIP_001 | 5          |
                      | SHIP_001 | 10         |
                  ✔ When I submit the following transaction of type org.acme.shipping.perishable.ShipmentReceived
                      | shipment |
                      | SHIP_001 |
                  ✔ Then I should have the following participants
                      """
                      [
                      {"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":2500},
                      {"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-2500},
                      {"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
                      ]
                      """

As últimas linhas da saída são como estas, indicando que os testes de unidade foram aprovados.

                    .
                    .
                  ✔ And I have added the following asset of type org.acme.shipping.perishable.Shipment
                      | shipmentId | type    | status     | unitCount | contract |
                      | SHIP_001   | BANANAS | IN_TRANSIT | 5000      | CON_001  |
                  ✔ When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
                      | shipment | centigrade |
                      | SHIP_001 | 4          |
                      | SHIP_001 | 5          |
                      | SHIP_001 | 10         |
                  ✔ When I submit the following transaction of type org.acme.shipping.perishable.GpsReading
                      | shipment | readingTime | readingDate | latitude | latitudeDir | longitude | longitudeDir |
                      | SHIP_001 | 120000      | 20171025    | 40.6840  | N           | 74.0062   | W            |
                  ✔ Then I should have received the following event of type org.acme.shipping.perishable.ShipmentInPortEvent
                      | message                                                                  | shipment |
                      | Shipment has reached the destination port of /LAT:40.6840N/LONG:74.0062W | SHIP_001 |
                
                6 scenarios (6 passed)
                44 steps (44 passed)
                0m02.788s
                $

Uma análise mais detalhada de um teste de unidade com o Cucumber

Ok, eu sei que passei um conteúdo muito grande na seção anterior. Portanto, permita-me explicar com mais detalhes, começando com uma visão geral do Cucumber.

Visão geral do Cucumber

O Cucumber é uma ferramenta de teste de unidade projetada para Desenvolvimento Orientado por Comportamento (BDD), um estilo de desenvolvimento relacionado ao desenvolvimento orientado a testes (TDD), só que mais concentrado no comportamento do aplicativo, em vez de apenas na funcionalidade correta do código. É uma diferença sutil, mas importante.

Os cenários de teste do Cucumber são escritos em uma linguagem chamada Gherkin. Você já a viu na seção anterior. A sintaxe é muito simples:

                Feature : The application feature I want to test
                  Background:
                    Given some pre-condition that applies to each test
                
                  Scenario: The test I want to run
                      Given something
                      And some other thing
                      When I do XYZ
                      Then ABC is the expected outcome

Uma definição de etapa é uma parte pequena do código que vincula um padrão em texto em linguagem simples do Gherkin ao código real que executa o teste. Você é responsável por escrever as definições de etapa, caso contrário, os testes não serão executados.

Quando o Cucumber encontrar uma das palavras-chave a seguir: Quando, Given, Then, Eou But, ele procurará uma definição de etapa para associar ao texto após a palavra-chave. Aliás, o Cucumber não faz distinção entre palavras-chave, elas são apenas etapas para o Cucumber. Em outras palavras, para o Cucumber, When ABC e Given ABC significam "localizar e executar uma etapa com o padrão ABC".

Por exemplo, quando o Cucumber encontra Given I have added the following participants, ele procura uma etapa cujo padrão corresponda a I have added the following e, caso encontre, ele o executa. Caso contrário, você deverá fornecê-lo.

A boa notícia é que a equipe do Hyperledger Composer já forneceu as etapas para a maioria dos tipos de uso comuns da API do cliente do Composer. Isso significa que é possível escrever testes do Cucumber na linguagem Gherkin como os que você já viu, sem escrever nenhum código sozinho! O código está contido na biblioteca JavaScript composer-cucumber-steps que você incluiu no package.json na seção anterior.

Trabalhando com o Cucumber

Portanto, vamos percorrer um dos cenários. Vou descrever o que o Cucumber faz e mostrar o código Javascript real que é executado nas etapas do módulo composer-cucumber-steps do Node.js.

Consulte a Listagem 8. Neste cenário, existem três palavras-chave:

  • Given I submit the following transaction of type org.acme.shipping.perishable.TemperatureReading
  • Quando I submit the following transaction of type org.acme.shipping.perishable.ShipmentReceived
  • Then I should have the following participants

O Cucumber não faz distinção entre as três palavras-chave (elas são apenas etapas), mas os padrões que seguem as palavras-chave devem corresponder a uma (e somente a uma) etapa. Caso contrário, o teste não será executado porque não existe um código para executá-lo.

Na primeira instância, o Cucumber procura um padrão (ou seja, uma expressão regular) que corresponda a "I submit the following transaction of type org.acme.shipping.perishable.TemperatureReading" e encontra um. A função JavaScript que é executada quando a execução desta etapa é semelhante a esta:

Lista 8. composer-cucumber-steps/lib/transactionsteps.js
                'use strict';
                
                module.exports = function () {
                
                    this.When(/^I submit the following transactions? of type ([.\w]+)\.(\w+)$/, function (namespace, name, table) {
                        return this.composer.submitTransactions(namespace, name, table);
                    });
                
                    this.When(/^I submit the following transactions?$/, function (docString) {
                        return this.composer.submitTransactions(null, null, docString);
                    });
                
                };

Espere. Onde está a função this.Given()? Todas as funções mostradas acima começam com this.When. Como o Cucumber sabe que deve chamar uma das funções acima quando o Gherkin contém Given? Lembre-se, o Cucumber não distingue as palavras-chave de etapa (Given, When, And e assim por diante). Ele somente corresponde ao padrão. Na verdade, se você codificar uma definição de etapa do Cucumber com o mesmo padrão para Given e When, o Cucumber relatará um erro de definição de etapa duplicada!

O padrão a ser correspondido é a expressão regular entre os caracteres / entre parênteses, incluindo os grupos de captura (([.\w]+)\.(\w+)), que são usados para analisar os argumentos passados para a função que é chamada: namespace (org.acme.shipping.perishable), name (TemperatureReading) e mesa (vou falar mais sobre o argumento de tabela em breve).

O código que é executado para a etapa que corresponde ao padrão "I should have the following participants" corresponde a este código:

                'use strict';
                
                module.exports = function () {
                
                    this.Given(/^I have added the following participants? of type ([.\w]+)\.(\w+)$/, function (namespace, name, table) {
                        return this.composer.addParticipants(namespace, name, table);
                    });
                
                    this.Given(/^I have added the following participants?$/, function (docString) {
                        return this.composer.addParticipants(null, null, docString);
                    });
                
                    this.When(/^I add the following participants? of type ([.\w]+)\.(\w+)$/, function (namespace, name, table) {
                        return this.composer.addParticipants(namespace, name, table);
                    });
                
                    this.When(/^I add the following participants?$/, function (docString) {
                        return this.composer.addParticipants(null, null, docString);
                    });
                
                    this.When(/^I update the following participants? of type ([.\w]+)\.(\w+)$/, function (namespace, name, table) {
                        return this.composer.updateParticipants(namespace, name, table);
                    });
                
                    this.When(/^I update the following participants?$/, function (docString) {
                        return this.composer.updateParticipants(null, null, docString);
                    });
                
                    this.When(/^I remove the following participants? of type ([.\w]+)\.(\w+)$/, function (namespace, name, table) {
                        return this.composer.removeParticipants(namespace, name, table);
                    });
                
                    this.When(/^I remove the following participants?$/, function (docString) {
                        return this.composer.removeParticipants(null, null, docString);
                    });
                
                    this.Then(/^I should have the following participants? of type ([.\w]+)\.(\w+)$/, function (namespace, name, table) {
                        return this.composer.testParticipants(namespace, name, table);
                    });
                
                    this.Then(/^I should have the following participants?$/, function (docString) {
                        return this.composer.testParticipants(null, null, docString);
                    });
                
                    this.Then(/^I should not have the following participants? of type ([.\w]+)\.(\w+)$/, function (namespace, name, table) {
                        return this.composer.testNoParticipants(namespace, name, table);
                    });
                
                    this.Then(/^I should not have the following participants?$/, function (docString) {
                        return this.composer.testNoParticipants(null, null, docString);
                    });
                
                };

Como você pode ver, o código para as etapas relacionadas aos Participantes manipula muito mais do que apenas "I should have", como é o caso de "I remove", "I add" e muito mais.

Objetos complexos em Gherkin

Você deve ter notado que houve duas maneiras de representar objetos do modelo de rede Mercadorias Perecíveis nos exemplos do Gherkin. Primeiro, como esta:

                | contractId | grower           | shipper               | importer              | arrivalDateTime  | unitPrice | minTemperature | maxTemperature | minPenaltyFactor | maxPenaltyFactor |
                | CON_001    | grower@email.com | supermarket@email.com | supermarket@email.com | 10/26/2018 00:00 | 0.5       | 2              | 10             | 0.2              | 0.1              |

Segundo, como esta:

                """
                [
                {"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":1500},
                {"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-1500}
                ]
                """

O primeiro tipo de representação de objeto é chamado de tabela de dados e é uma tupla delimitada por barra vertical, na qual a primeira linha contém os nomes de propriedade, seguida por uma ou mais linhas que contêm os valores de propriedade. A tabela de dados não suporta objetos aninhados. Ao usar uma tabela de dados para representar objetos, é necessário informar à etapa o tipo de objeto seguinte. O objeto neste exemplo é um org.acme.shipping.perishable.Contract e ele foi especificado na mesma linha que a etapa (consulte Listagem 2). Use uma tabela de dados quando os objetos não contiverem outros objetos necessários do modelo (um objeto opcional pode ser omitido).

O segundo tipo usa um docstring, que é uma representação JSON do objeto e suporta objetos aninhados (por exemplo, observe o objeto Endereço aninhado). Ao usar o docstring, não é necessário especificar o tipo de objeto na etapa porque isso deve ser feito como parte do docstring (consulte Listagem 5).

Use a sintaxe do docstring quando um objeto que você estiver tentando representar contiver um objeto aninhado necessário ou quando você desejar fornecer valores de dados para um objeto opcional aninhado.

4

Implemente a rede modificada na IBM Cloud

Agora que você já modificou a rede e realizou o teste de unidade, chegou a hora de carregá-la no playground on-line e interagir com ela na IBM Cloud em https://composer-playground.mybluemix.net/.

Em Parte 1, eu mostrei como trabalhar com o playground para definir uma rede usando o modelo padrão de Mercadorias Perecíveis, instanciar o modelo e enviar transações para o blockchain na memória. Nesta seção, você vai usar o arquivo Business Network Archive (BNA) da rede Mercadorias Perecíveis criado pela compilação (ou seja, o npm install) para implementar a rede usando o recurso de importação do playground. Mas primeiro é necessário fazer algumas mudanças no código e, em seguida, executar uma compilação para criar o arquivo BNA.

4a

Faça algumas mudanças no código

Assegure-se de que o modelo de rede Mercadorias Perecíveis que você refinou anteriormente neste tutorial esteja aberta no VSCode. Agora abra lib/logic.js na janela do editor. Inclua uma mensagem de log do console na função temperatureReading() como é mostrado na linha 22:

Lista 9. logic.js —temperatureReading()
                function temperatureReading(temperatureReading) {
                
                    var shipment = temperatureReading.shipment;
                    var NS = 'org.acme.shipping.perishable';
                    var contract = shipment.contract;
                    var factory = getFactory();
                
                    console.log('Adding temperature ' + temperatureReading.centigrade + ' to shipment ' + shipment.$identifier);
                
                    if (shipment.temperatureReadings) {
                        shipment.temperatureReadings.push(temperatureReading);
                    } else {
                        shipment.temperatureReadings = [temperatureReading];
                    }
                
                    if (temperatureReading.centigrade < contract.minTemperature ||
                        temperatureReading.centigrade > contract.maxTemperature) {
                        var temperatureEvent = factory.newEvent(NS, 'TemperatureThresholdEvent');
                        temperatureEvent.shipment = shipment;
                        temperatureEvent.temperature = temperatureReading.centigrade;
                        temperatureEvent.message = 'Temperature threshold violated! Emitting TemperatureEvent for shipment: ' + shipment.$identifier;
                        console.log(message);
                        emit(temperatureEvent);
                    }

Agora localize a função gpsReading() e inclua uma mensagem de log do console como é mostrado na linha 22:

                function gpsReading(gpsReading) {
                    
                       var factory = getFactory();
                       var NS = "org.acme.shipping.perishable";
                       var shipment = gpsReading.shipment;
                       var PORT_OF_NEW_YORK = '/LAT:40.6840N/LONG:74.0062W';
                        
                       var latLong = '/LAT:' + gpsReading.latitude + gpsReading.latitudeDir + '/LONG:' +
                           gpsReading.longitude + gpsReading.longitudeDir;
                        
                       if (shipment.gpsReadings) {
                           shipment.gpsReadings.push(gpsReading);
                       } else {
                           shipment.gpsReadings = [gpsReading];
                       }
                    
                       if (latLong == PORT_OF_NEW_YORK) {
                           var shipmentInPortEvent = factory.newEvent(NS, 'ShipmentInPortEvent');
                           shipmentInPortEvent.shipment = shipment;
                           var message = 'Shipment has reached the destination port of ' + PORT_OF_NEW_YORK;
                           shipmentInPortEvent.message = message;
                           console.log(message);
                           emit(shipmentInPortEvent);
                       }
                    
                       return getAssetRegistry(NS + '.Shipment')
                       .then(function (shipmentRegistry) {
                           // add the temp reading to the shipment
                           return shipmentRegistry.update(shipment);
                       });
                   }

Agora, quando você executar as transações TemperatureReading e GpsReading e elas emitirem eventos, elas serão exibidas no console do JavaScript.

4b

Crie o Business Network Archive

Acesse a linha de comando (Ubuntu) ou abra uma janela do terminal (MacOS), navegue para o diretório perishable-network, que está localizado no diretório $COMPOSER_ROOT , e execute uma construção para criar o arquivo BNA executando npm install na linha de comando. Será exibida uma saída como esta:

                $ cd $COMPOSER_ROOT
                $ pwd
                /Users/sperry/HyperledgerComposer
                $ cd developerWorks/perishable-network/
                $ npm install
                
                > perishable-network@0.1.11 prepublish /Users/sperry/HyperledgerComposer/developerWorks/perishable-network
                > mkdirp ./dist && composer archive create  --sourceType dir --sourceName . -a ./dist/perishable-network.bna
                
                Creating Business Network Archive
                
                
                Looking for package.json of Business Network Definition
                	Input directory: /Users/sperry/HyperledgerComposer/developerWorks/perishable-network
                
                Found:
                	Description: Shipping Perishable Goods Business Network
                	Name: perishable-network
                	Identifier: perishable-network@0.1.11
                
                Written Business Network Definition Archive file to 
                	Output file: ./dist/perishable-network.bna
                
                Command succeeded
4c

Importe o modelo no playground on-line na IBM Cloud

Agora acesse o playground on-line na IBM Cloud: https://composer-playground.mybluemix.net/. Agora, a tela de boas-vindas já conhecida será exibida:

Figura 4. Tela de boas-vindas do playground na IBM Cloud
IBM Cloud Composer Online Playground Welcome screen
IBM Cloud Composer Online Playground Welcome screen

Se a tela de boas-vindas não for exibida, limpe o armazenamento local do navegador. No Chrome, por exemplo, em Configurações > Avançado > Configurações de conteúdo > Cookies > Todos os cookies e os dados do site > host local, clique no ícone de lixeira para remover o armazenamento local. Se você estiver usando um navegador diferente, siga as instruções específicas desse navegador e exclua todo o armazenamento local.

Clique no botão Executar blockchain para começar. Quando a visualização Minhas redes de negócios for exibida, clique em Implementar uma rede de negócios.

Figura 5. Minhas redes de negócios
IBM Cloud Composer Online Playground - My Business Networks
IBM Cloud Composer Online Playground - My Business Networks

Na próxima tela, clique em Soltar aqui para fazer upload ou procurar. Um diálogo de Arquivo é aberto. Navegue para o diretório $COMPOSER_ROOT/developerWorks/perishable-network/dist , localize o arquivo chamado perishable-network.bnae clique em Abra.

Figura 6. Implemente a nova rede de negócios
IBM Cloud Composer Online Playground - Deploy new business network
IBM Cloud Composer Online Playground - Deploy new business network

O título do ladrilho em que você acabou de clicar muda para perishable-network. Clique no botão Implementar para implementar o modelo.

Figura 7. Implemente a nova rede de negócios
IBM Cloud Composer Online Playground - Deploy new business network
IBM Cloud Composer Online Playground - Deploy new business network

Agora o modelo está implementado no playground on-line na IBM Cloud.

4d

Interaja com o modelo

A interação com o modelo será semelhante à da Parte 1 desta série. Na verdade, o playground on-line é uma versão na IBM Cloud do playground local usado na Parte 1, portanto, não será necessário repetir a interação com o modelo. Revise a Parte 1 caso precise se lembrar.

Na seção intitulada "Refine a rede de negócios Mercadorias Perecíveis", você executou testes de unidade para verificar se o código no novo modelo funciona. Agora, você vai interagir com o modelo usando o playground on-line para testar essas mesmas transações e verificá-las usando o console do JavaScript. Clique em Conectar agora na placa Administração para começar.

Primeiro, instancie o modelo clicando na guia Teste abaixo da barra de endereço no navegador. Clique no botão Enviar transação, selecione a transação SetupDemo e clique em Enviar.

Agora abra o console do JavaScript. A maneira de fazer isso depende do navegador. Se você estiver usando o Chrome, selecione Visualizar > Devenvolvedor > console do JavaScript.

Em seguida, envie uma transação TemperatureReading para Shipment SHIP_001 de 11 graus C, que está acima do limite máximo de temperatura e acionará um TemperatureThresholdEvent, como é mostrado na Figura 8.

Figura 8. Enviar TemperatureReading transação
IBM Cloud Composer Online Playground - Submit TemperatureReading                     transaction
IBM Cloud Composer Online Playground - Submit TemperatureReading transaction

A seguinte mensagem será exibida (juntamente com muitas outras, portanto, procure com atenção) no console do JavaScript: Temperature threshold violated! Emitting TemperatureEvent for shipment: SHIP_001. Isso indica que o evento foi emitido corretamente (apesar de que já temos essa informação porque já executamos o teste de unidade do Cucumber, não é mesmo?).

Agora, envie uma transação GpsReading para Shipment SHIP_001 com os parâmetros a seguir, como é mostrado na Figura 9.

  • readingTime = 171000
  • readingDate = 20171031
  • latitude = 40.6840
  • latitudeDir = N
  • longitude = 74.0062
  • longitudeDir = W
Figura 9. Enviar GpsReading transação
IBM Cloud Composer Online Playground - Submit GpsReading                     transaction
IBM Cloud Composer Online Playground - Submit GpsReading transaction

A seguinte mensagem deverá ser exibida no console do Javascript: Shipment has reached the destination port of /LAT:40.6840N/LONG:74.0062W.

Parabéns! Você tem um modelo funcional em execução na IBM Cloud.

Conclusão da Parte 2

Neste tutorial, você configurou as ferramentas para o desenvolvimento do Hyperledger Composer local no computador. Você modificou a rede Mercadorias Perecíveis, incluiu uma nova transação e dois novos eventos e, em seguida, realizou o teste de unidade desses eventos com o Cucumber.

Em seguida, você construiu um arquivo Business Network Archive (BNA) do Composer por meio da rede Mercadorias Perecíveis modificada e implementou e testou esse arquivo no playground on-line hospedado na IBM Cloud.

Fique ligado na Parte 3, na qual você instalará mais ferramentas para realmente aproveitar todo o potencial do Hyperledger Composer gerando uma interface REST. Você vai instalar e executar o Hyperledger Fabric no computador e gerar uma GUI que poderá ser usada para interagir com a rede Mercadorias Perecíveis em execução no computador exatamente da mesma maneira que o faria em um servidor de produção. Não haverá mais playground na Parte 3!


Recursos para download


Temas relacionados


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Internet of Things, Cloud computing
ArticleID=1057957
ArticleTitle=Fundamentos básicos do Hyperledger Composer, Parte 2: Refine e implemente sua rede de blockchain
publish-date=02082018