Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration test #7

Merged
merged 14 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Integration

on:
push:
branches:
- main
tags:
- '*'
pull_request:
branches:
- main

jobs:
build:
runs-on: minafoundation-default-runners

steps:
- name: 📥 Checkout
uses: actions/checkout@v3

- name: 📥 Update Git Submodules
run: |
git submodule init
git submodule update

- name: 📦 Install Nix
uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable

- name: 🤌 Get Minimina
uses: MinaFoundation/install-minimina-action@v1
with:
stream: stable

- name: 🛠️ Build Docker
env:
IMAGE_NAME: uptime-service-backend
TAG: integration-test
run: nix-shell --run "make docker"

- name: 🧪 Run Integration Tests
env:
UPTIME_SERVICE_SECRET: ${{ secrets.UPTIME_SERVICE_SECRET }}
Smorci marked this conversation as resolved.
Show resolved Hide resolved
run: nix-shell --run "make integration-test"
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
bazel-*
user.bazelrc

# direnv config
.envrc

# make stuff
result/

Expand All @@ -20,3 +23,7 @@ result/

# Dependency directories (remove the comment below to include it)
# vendor/

app_config.json
aws_creds.json
minasheets.json
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ tidy:
test:
GO=$(GO) ./scripts/build.sh test

integration-test:
GO=$(GO) ./scripts/build.sh integration-test

docker:
./scripts/build.sh $@
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Uptime Service Backend

[![Build](https://github.com/MinaFoundation/uptime-service-backend/actions/workflows/build.yml/badge.svg)](https://github.com/MinaFoundation/uptime-service-backend/actions/workflows/build.yml)
[![Integration](https://github.com/MinaFoundation/uptime-service-backend/actions/workflows/integration.yml/badge.svg)](https://github.com/MinaFoundation/uptime-service-backend/actions/workflows/integration.yml)

As part of delegation program, nodes are to upload some proof of their activity. These proofs are to be accumulated and utilized for scoring. This service provides the nodes with a way to submit their data for score calculation.

Expand Down
8 changes: 7 additions & 1 deletion scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ case "$1" in
cd src/delegation_backend
LD_LIBRARY_PATH="$OUT" $GO test
;;
integration-test)
cd src/integration_tests
$GO test -v
;;
docker)
if [[ "$TAG" == "" ]]; then
echo "Specify TAG env variable."
exit 1
fi
docker build -t "673156464838.dkr.ecr.us-west-2.amazonaws.com/block-producers-uptime:$TAG" -f dockerfiles/Dockerfile-delegation-backend .
# set image name to 673156464838.dkr.ecr.us-west-2.amazonaws.com/block-producers-uptime if IMAGE_NAME is not set
IMAGE_NAME=${IMAGE_NAME:-673156464838.dkr.ecr.us-west-2.amazonaws.com/block-producers-uptime}
docker build -t "$IMAGE_NAME:$TAG" -f dockerfiles/Dockerfile-delegation-backend .
;;
"")
cd src/cmd/delegation_backend
Expand Down
2 changes: 1 addition & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ in
{
devEnv = stdenv.mkDerivation {
name = "dev";
buildInputs = [ stdenv go_1_18 glibc minaSigner ];
buildInputs = [ stdenv go_1_19 glibc minaSigner ];
shellHook = ''
export LIB_MINA_SIGNER=${minaSigner}/lib/libmina_signer.so
return
Expand Down
3 changes: 2 additions & 1 deletion src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module block_producers_uptime
go 1.18

require (
github.com/aws/aws-sdk-go v1.45.0
github.com/aws/aws-sdk-go v1.45.28
github.com/aws/aws-sdk-go-v2 v1.21.0
github.com/aws/aws-sdk-go-v2/config v1.18.37
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5
Expand Down Expand Up @@ -37,6 +37,7 @@ require (
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions src/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBA
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aws/aws-sdk-go v1.45.0 h1:qoVOQHuLacxJMO71T49KeE70zm+Tk3vtrl7XO4VUPZc=
github.com/aws/aws-sdk-go v1.45.0/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.45.28 h1:p2ATcaK6ffSw4yZ2UAGzgRyRXwKyOJY6ZCiKqj5miJE=
github.com/aws/aws-sdk-go v1.45.28/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc=
github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0=
Expand Down Expand Up @@ -124,6 +126,7 @@ github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOL
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
Expand Down
168 changes: 168 additions & 0 deletions src/integration_tests/aws_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package integration_tests

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)

type AWSCreds struct {
AccessKeyID string `json:"access_key_id"`
SecretAccessKey string `json:"secret_access_key"`
}

type AppConfig struct {
NetworkName string `json:"network_name"`
AWS struct {
AccountID string `json:"account_id"`
Region string `json:"region"`
} `json:"aws"`
}

func getAWSCreds() AWSCreds {
credsBytes, err := ioutil.ReadFile(AWS_CREDS_FILE)
if err != nil {
log.Fatalf("Failed to read aws_creds.json: %v", err)
}

var creds AWSCreds
if err := json.Unmarshal(credsBytes, &creds); err != nil {
log.Fatalf("Failed to parse aws_creds.json: %v", err)
}

return creds
}

func getAppConfig() AppConfig {
appConfigBytes, err := ioutil.ReadFile(APP_CONFIG_FILE)
if err != nil {
log.Fatalf("Failed to read app_config.json: %v", err)
}

var config AppConfig
if err := json.Unmarshal(appConfigBytes, &config); err != nil {
log.Fatalf("Failed to parse app_config.json: %v", err)
}

return config
}

func getAWSBucketName(config AppConfig) string {
return config.AWS.AccountID + "-" + BUCKET_NAME_SUFFIX
}

func getAWSIntegrationTestFolder(config AppConfig) string {
return strings.Trim(config.NetworkName, "/") + "/"
}

func getS3Service(creds AWSCreds, config AppConfig) *s3.S3 {
accessKeyID := creds.AccessKeyID
secretAccessKey := creds.SecretAccessKey
region := config.AWS.Region

sess, err := session.NewSession(&aws.Config{
Region: aws.String(region),
Credentials: credentials.NewStaticCredentials(accessKeyID, secretAccessKey, ""),
})
if err != nil {
log.Fatalf("Failed to create AWS session: %v", err)
}

return s3.New(sess)
}

func emptyIntegrationTestFolder(creds AWSCreds, config AppConfig) error {
log.Printf("Emptying AWS S3 integration_test folder")

bucketName := getAWSBucketName(config)
folderPrefix := getAWSIntegrationTestFolder(config)
svc := getS3Service(creds, config)

// List objects with the specified prefix
listObjectsInput := &s3.ListObjectsV2Input{
Bucket: aws.String(bucketName),
Prefix: aws.String(folderPrefix),
}
objects, err := svc.ListObjectsV2(listObjectsInput)
if err != nil {
return err
}

// Delete each object with the specified prefix
for _, object := range objects.Contents {
if *object.Key == folderPrefix {
// Skip the folder itself
continue
}
deleteObjectInput := &s3.DeleteObjectInput{
Bucket: aws.String(bucketName),
Key: object.Key,
}
_, err := svc.DeleteObject(deleteObjectInput)
if err != nil {
return err
}
}

return nil
}

func waitUntilS3BucketHasBlocksAndSubmissions(creds AWSCreds, config AppConfig) error {
log.Printf("Waiting for blocks and submissions to appear in the S3 bucket")

bucketName := getAWSBucketName(config)
folderPrefix := getAWSIntegrationTestFolder(config)
svc := getS3Service(creds, config)

hasBlocks := false
hasSubmissionsForToday := false
currentDate := time.Now().Format("2006-01-02") // YYYY-MM-DD format

timeout := time.After(TIMEOUT_IN_S * time.Second)
tick := time.Tick(5 * time.Second)

for {
select {
case <-timeout:
return fmt.Errorf("Timeout reached while waiting for S3 bucket contents")
case <-tick:
// List objects with the specified prefix
listObjectsInput := &s3.ListObjectsV2Input{
Bucket: aws.String(bucketName),
Prefix: aws.String(folderPrefix),
}
objects, err := svc.ListObjectsV2(listObjectsInput)
if err != nil {
return err
}

// Reset the checks
hasBlocks = false
hasSubmissionsForToday = false

// Check the objects
for _, object := range objects.Contents {
key := *object.Key
if strings.HasPrefix(key, folderPrefix+"blocks/") && strings.HasSuffix(key, ".dat") {
hasBlocks = true
}
if strings.HasPrefix(key, folderPrefix+"submissions/"+currentDate+"/") && strings.HasSuffix(key, ".json") {
hasSubmissionsForToday = true
}
}

// If both blocks and submissions for today are found, return
if hasBlocks && hasSubmissionsForToday {
return nil
}
}
}
}
Loading