From 81d89c431b6a174587232d599851a3df5af4a6a7 Mon Sep 17 00:00:00 2001 From: Jeffrey Tang Date: Mon, 16 Dec 2024 13:36:59 -0600 Subject: [PATCH] Add test Signed-off-by: Jeffrey Tang --- .github/workflows/flow-gcs-test.yaml | 82 +++++++++++++++++++++ .github/workflows/script/gcs_test.sh | 42 +++++++++++ .github/workflows/script/helper.sh | 37 ++++++++++ .github/workflows/script/solo_smoke_test.sh | 37 +--------- examples/create-topic.js | 71 ++++++++++++++++-- 5 files changed, 228 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/flow-gcs-test.yaml create mode 100755 .github/workflows/script/gcs_test.sh create mode 100644 .github/workflows/script/helper.sh diff --git a/.github/workflows/flow-gcs-test.yaml b/.github/workflows/flow-gcs-test.yaml new file mode 100644 index 000000000..89bb0b002 --- /dev/null +++ b/.github/workflows/flow-gcs-test.yaml @@ -0,0 +1,82 @@ +## +# Copyright (C) 2023-2024 Hedera Hashgraph, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +name: "Test GCS as bucket storage" +# The purpose of this reusable workflow is to make sure task files are working as expected. + +on: + workflow_dispatch: + workflow_call: + pull_request: + types: + - opened + - reopened + - synchronize +secrets: + GCS_ACCESS_KEY: + description: "GCS Access Key" + GCS_SECRET_KEY: + description: "GCS Secret +defaults: + run: + shell: bash + +permissions: + contents: read + actions: read + +jobs: + example-task-file-test: + timeout-minutes: 20 + runs-on: solo-linux-large + steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Setup Node + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: 20 + cache: npm + + - name: Setup Kind + uses: helm/kind-action@0025e74a8c7512023d06dc019c617aa3cf561fde # v1.10.0 + with: + install_only: true + node_image: kindest/node:v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72 + version: v0.21.0 + kubectl_version: v1.28.6 + verbosity: 3 + wait: 120s + + - name: Install Dependencies + id: npm-deps + run: npm ci + + - name: Compile Project + run: npm run build + + - name: Run Example Task File Test + env: + GCS_ACCESS_KEY: ${{ secrets.GCS_ACCESS_KEY }} + GCS_SECRET_KEY: ${{ secrets.GCS_SECRET_KEY }} + run: | + .github/workflows/script/gcs_test.sh diff --git a/.github/workflows/script/gcs_test.sh b/.github/workflows/script/gcs_test.sh new file mode 100755 index 000000000..acee8662e --- /dev/null +++ b/.github/workflows/script/gcs_test.sh @@ -0,0 +1,42 @@ +#!/bin/bash +set -eo pipefail + +source .github/workflows/script/helper.sh + +if [ -z "${GCS_ACCESS_KEY}" ]; then + echo "GCS_ACCESS_KEY is not set. Exiting..." + exit 1 +fi + +if [ -z "${GCS_SECRET_KEY}" ]; then + echo "GCS_SECRET_KEY is not set. Exiting..." + exit 1 +fi + +echo "Generate GCS credentials to file gcs_values.yaml" +echo "cloud:" > gcs_values.yaml +echo " gcs:" >> gcs_values.yaml +echo " enabled: true" >> gcs_values.yaml +echo ' GCS_ACCESS_KEY: "'${GCS_ACCESS_KEY}'"' >> gcs_values.yaml +echo ' GCS_SECRET_KEY: "'${GCS_SECRET_KEY}'"' >> gcs_values.yaml + + +SOLO_CLUSTER_NAME=solo-e2e +SOLO_NAMESPACE=solo-e2e +SOLO_CLUSTER_SETUP_NAMESPACE=solo-setup + +kind create cluster -n "${SOLO_CLUSTER_NAME}" +solo init +solo cluster setup --chart-dir /Users/jeffrey/solo-charts/charts -s "${SOLO_CLUSTER_SETUP_NAMESPACE}" +solo node keys --gossip-keys --tls-keys -i node1,node2 +solo network deploy --chart-dir /Users/jeffrey/solo-charts/charts -i node1,node2 -n "${SOLO_NAMESPACE}" -f gcs_values.yaml +solo node setup -i node1,node2 -n "${SOLO_NAMESPACE}" +solo node start -i node1,node2 -n "${SOLO_NAMESPACE}" +solo mirror-node deploy --namespace "${SOLO_NAMESPACE}" + +kubectl port-forward -n "${SOLO_NAMESPACE}" svc/haproxy-node1-svc 50211:50211 > /dev/null 2>&1 & +kubectl port-forward -n "${SOLO_NAMESPACE}" svc/hedera-explorer 8080:80 > /dev/null 2>&1 & + +cd ..; create_test_account ; cd - + +node examples/create-topic.js diff --git a/.github/workflows/script/helper.sh b/.github/workflows/script/helper.sh new file mode 100644 index 000000000..ffed2745d --- /dev/null +++ b/.github/workflows/script/helper.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -eo pipefail + +function create_test_account () +{ + echo "Create test account with solo network" + cd solo + + # create new account and extract account id + npm run solo-test -- account create -n solo-e2e --hbar-amount 100 --generate-ecdsa-key --set-alias > test.log + export OPERATOR_ID=$(grep "accountId" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') + echo "OPERATOR_ID=${OPERATOR_ID}" + rm test.log + + # get private key of the account + npm run solo-test -- account get -n solo-e2e --account-id ${OPERATOR_ID} --private-key > test.log + export OPERATOR_KEY=$(grep "privateKey" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') + export CONTRACT_TEST_KEY_ONE=0x$(grep "privateKeyRaw" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') + echo "CONTRACT_TEST_KEY_ONE=${CONTRACT_TEST_KEY_ONE}" + rm test.log + + npm run solo-test -- account create -n solo-e2e --hbar-amount 100 --generate-ecdsa-key --set-alias > test.log + export SECOND_KEY=$(grep "accountId" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') + npm run solo-test -- account get -n solo-e2e --account-id ${SECOND_KEY} --private-key > test.log + export CONTRACT_TEST_KEY_TWO=0x$(grep "privateKeyRaw" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') + echo "CONTRACT_TEST_KEY_TWO=${CONTRACT_TEST_KEY_TWO}" + rm test.log + + export CONTRACT_TEST_KEYS=${CONTRACT_TEST_KEY_ONE},$'\n'${CONTRACT_TEST_KEY_TWO} + export HEDERA_NETWORK="local-node" + + echo "OPERATOR_KEY=${OPERATOR_KEY}" + echo "HEDERA_NETWORK=${HEDERA_NETWORK}" + echo "CONTRACT_TEST_KEYS=${CONTRACT_TEST_KEYS}" + + cd - +} diff --git a/.github/workflows/script/solo_smoke_test.sh b/.github/workflows/script/solo_smoke_test.sh index 8d0c12450..704ff89cd 100755 --- a/.github/workflows/script/solo_smoke_test.sh +++ b/.github/workflows/script/solo_smoke_test.sh @@ -9,7 +9,7 @@ set -eo pipefail # Then run smart contract test, and also javascript sdk sample test to interact with solo network # -function_name="" +source .github/workflows/script/helper.sh function enable_port_forward () { @@ -73,41 +73,6 @@ function start_contract_test () return $result } -function create_test_account () -{ - echo "Create test account with solo network" - cd solo - - # create new account and extract account id - npm run solo-test -- account create -n solo-e2e --hbar-amount 100 --generate-ecdsa-key --set-alias > test.log - export OPERATOR_ID=$(grep "accountId" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') - echo "OPERATOR_ID=${OPERATOR_ID}" - rm test.log - - # get private key of the account - npm run solo-test -- account get -n solo-e2e --account-id ${OPERATOR_ID} --private-key > test.log - export OPERATOR_KEY=$(grep "privateKey" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') - export CONTRACT_TEST_KEY_ONE=0x$(grep "privateKeyRaw" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') - echo "CONTRACT_TEST_KEY_ONE=${CONTRACT_TEST_KEY_ONE}" - rm test.log - - npm run solo-test -- account create -n solo-e2e --hbar-amount 100 --generate-ecdsa-key --set-alias > test.log - export SECOND_KEY=$(grep "accountId" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') - npm run solo-test -- account get -n solo-e2e --account-id ${SECOND_KEY} --private-key > test.log - export CONTRACT_TEST_KEY_TWO=0x$(grep "privateKeyRaw" test.log | awk '{print $2}' | sed 's/"//g'| sed 's/,//g') - echo "CONTRACT_TEST_KEY_TWO=${CONTRACT_TEST_KEY_TWO}" - rm test.log - - export CONTRACT_TEST_KEYS=${CONTRACT_TEST_KEY_ONE},$'\n'${CONTRACT_TEST_KEY_TWO} - export HEDERA_NETWORK="local-node" - - echo "OPERATOR_KEY=${OPERATOR_KEY}" - echo "HEDERA_NETWORK=${HEDERA_NETWORK}" - echo "CONTRACT_TEST_KEYS=${CONTRACT_TEST_KEYS}" - - cd - -} - function start_sdk_test () { cd solo diff --git a/examples/create-topic.js b/examples/create-topic.js index f44a957a3..25458446d 100644 --- a/examples/create-topic.js +++ b/examples/create-topic.js @@ -14,9 +14,18 @@ * limitations under the License. * */ -import {Wallet, LocalProvider, TopicCreateTransaction, TopicMessageSubmitTransaction} from '@hashgraph/sdk'; +import { + Wallet, + LocalProvider, + TopicCreateTransaction, + TopicMessageSubmitTransaction, + AccountCreateTransaction, + PrivateKey, + Hbar, +} from '@hashgraph/sdk'; import dotenv from 'dotenv'; +import http from 'http'; dotenv.config(); @@ -30,12 +39,11 @@ async function main() { const wallet = new Wallet(process.env.OPERATOR_ID, process.env.OPERATOR_KEY, provider); + const TEST_MESSAGE = 'Hello World'; try { - console.log('before create topic'); // create topic let transaction = await new TopicCreateTransaction().freezeWithSigner(wallet); transaction = await transaction.signWithSigner(wallet); - console.log('after sign transaction'); const createResponse = await transaction.executeWithSigner(wallet); const createReceipt = await createResponse.getReceiptWithSigner(wallet); @@ -44,7 +52,7 @@ async function main() { // send one message let topicMessageSubmitTransaction = await new TopicMessageSubmitTransaction({ topicId: createReceipt.topicId, - message: 'Hello World', + message: TEST_MESSAGE, }).freezeWithSigner(wallet); topicMessageSubmitTransaction = await topicMessageSubmitTransaction.signWithSigner(wallet); const sendResponse = await topicMessageSubmitTransaction.executeWithSigner(wallet); @@ -52,10 +60,63 @@ async function main() { const sendReceipt = await sendResponse.getReceiptWithSigner(wallet); console.log(`topic sequence number = ${sendReceipt.topicSequenceNumber.toString()}`); + + await new Promise(resolve => setTimeout(resolve, 1000)); + + // send a create account transaction to push record stream files to mirror node + const newKey = PrivateKey.generate(); + let accountCreateTransaction = await new AccountCreateTransaction() + .setInitialBalance(new Hbar(10)) + .setKey(newKey.publicKey) + .freezeWithSigner(wallet); + accountCreateTransaction = await accountCreateTransaction.signWithSigner(wallet); + const accountCreationResponse = await accountCreateTransaction.executeWithSigner(wallet); + const accountCreationReceipt = await accountCreationResponse.getReceiptWithSigner(wallet); + console.log(`account id = ${accountCreationReceipt.accountId.toString()}`); + + await new Promise(resolve => setTimeout(resolve, 1000)); + + // Check submit message result should success + const queryURL = `http://localhost:8080/api/v1/topics/${createReceipt.topicId}/messages`; + let received = false; + let receivedMessage = ''; + + // wait until the transaction reached consensus and retrievable from the mirror node API + let retry = 0; + while (!received && retry < 10) { + const req = http.request(queryURL, {method: 'GET', timeout: 100, headers: {Connection: 'close'}}, res => { + res.setEncoding('utf8'); + res.on('data', chunk => { + // convert chunk to json object + const obj = JSON.parse(chunk); + if (obj.messages.length === 0) { + console.log('No messages yet'); + } else { + // convert message from base64 to utf-8 + const base64 = obj.messages[0].message; + const buff = Buffer.from(base64, 'base64'); + receivedMessage = buff.toString('utf-8'); + console.log(`Received message: ${receivedMessage}`); + received = true; + } + }); + }); + req.on('error', e => { + console.log(`problem with request: ${e.message}`); + }); + req.end(); // make the request + // wait and try again + await new Promise(resolve => setTimeout(resolve, 1000)); + retry++; + } + if (receivedMessage === TEST_MESSAGE) { + console.log('Message received successfully'); + } else { + console.error('Message received but not match'); + } } catch (error) { console.error(error); } - provider.close(); }