Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.

Commit

Permalink
Add integration test for full deal flow, fix retrieval bugs (#118)
Browse files Browse the repository at this point in the history
# Goals

Write an integration test that verifies data is actually sent into
singularity and deals are proposed to boost. Test retrieval including:
- Test the retrieval process from both the datasource and Filecoin.
- Verify the correct functioning of the read seeker.
- Test the HTTP endpoint for file retrieval.
- Verify Lassie integration and CAR file retrieval.

fixes #103

# Implementation

- Various bug fixes already shipped and merged to singularity discovered
in testing
- Move most execution of devnet integration test out of github action
into a Makefile. See `integration/test/README.md` for more information.
This enables running tests and devnets locally with ease
- Switch from SINGULARITY_TAG to SINGULARITY_REF, removing the
automatically inserted colon. This allows us to run from direct SHA tags
as needed. It also means the code will run is no ref is specified, as
opposed to before where it would fail if no SINGULARITY_TAG was present
- Fix bug with go-routine execution of singularity preparation
introduced in cleanup data PR
- Fix bug with blob descriptors when local file is deleted
- Fix bug where local data was deleted before the deal status was
published or active
- Add several hook scripts to enable acceptance of boost deals (such as
pricing deals to zero)
- Various configuration fixes to make dealmaking in test run smoothly
- Integration test that now does a MUCH more full cycle -- pushes,
retrieves, waits for full storage on filecoin, then retrieves with
Lassie

# For discussion

- I had to add a custom entrypoint boost in order to properly configure
boost to advertise booster-http. We should probably upstream this.

- There is a bug fix for singularity that should get in before we merge
this.

---------

Co-authored-by: Masih H. Derkani <[email protected]>
Co-authored-by: Elijah <[email protected]>
  • Loading branch information
3 people authored Oct 5, 2023
1 parent d3eb162 commit f870783
Show file tree
Hide file tree
Showing 17 changed files with 363 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# The version of singularity you will use to make deals. Generally, this should not change
SINGULARITY_TAG=v0.4.1
SINGULARITY_REF=:v0.4.1

# Comma seperated list of storage providers motion should make storage deals with
# You must set this value to contain at least one storage provider for motion to
Expand Down
47 changes: 4 additions & 43 deletions .github/workflows/devnet-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
build:
name: Boost Devnet
runs-on: ubuntu-latest
runs-on: ubuntu-latest-4-cores
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -30,49 +30,10 @@ jobs:
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Run Boost Devnet from pre-built images
- name: Run Motion Integration Tests
run: |
cd integration/test/devnet
docker compose up -d
- name: Await Lotus full node startup
run: |
cd integration/test/devnet
docker compose exec lotus lotus wait-api --timeout=20m
- name: Set up Motion Wallet and API endpoints
run: |
cd integration/test/devnet
# Setup Lotus API token
export `docker compose exec lotus lotus auth api-info --perm=admin`
IFS=: read -r token path <<< "${FULLNODE_API_INFO}"
echo "LOTUS_TOKEN=${token}" >> $GITHUB_ENV
# Setup Motion Wallet
MOTION_WALLET_ADDR=`docker compose exec lotus lotus wallet new`
MOTION_WALLET_KEY=`docker compose exec lotus lotus wallet export ${MOTION_WALLET_ADDR}`
LOTUS_WALLET_DEFAULT_ADDR=`docker compose exec lotus lotus wallet default`
docker compose exec lotus lotus send --from=${LOTUS_WALLET_DEFAULT_ADDR} ${MOTION_WALLET_ADDR} 10
echo "MOTION_WALLET_ADDR=${MOTION_WALLET_ADDR}" >> $GITHUB_ENV
echo "MOTION_WALLET_KEY=${MOTION_WALLET_KEY}" >> $GITHUB_ENV
echo "MOTION_STORAGE_PROVIDERS=t01000" >> $GITHUB_ENV
echo "MOTION_API_ENDPOINT=http://localhost:40080" >> $GITHUB_ENV
echo "SINGULARITY_API_ENDPOINT=http://localhost:9091" >> $GITHUB_ENV
- name: Run Motionlarity
run: |
cd integration/test/motionlarity
docker compose up -d
- name: Wait until motion is running
uses: nick-fields/retry@v2
with:
timeout_seconds: 5
max_attempts: 10
retry_on: error
command: |
cd integration/test/motionlarity
docker compose ps --services --filter "status=running" | grep motion
- name: Run Motion integration tests
env:
MOTION_INTEGRATION_TEST: 'true'
run: go test ./integration/test -v
cd integration/test
make test
- name: Start S3 Connector
run: |
cd integration/test/s3-connector
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
/.env.local
integration/test/devnet/data
motion
integration/test/motionlarity/.env.local
integration/test/motionlarity/.up
integration/test/devnet/.up
integration/test/devnet/.boostready
14 changes: 6 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ services:
- 5432:5432

singularity_admin_init:
image: ghcr.io/data-preservation-programs/singularity:${SINGULARITY_TAG}
image: ghcr.io/data-preservation-programs/singularity${SINGULARITY_REF}
command: admin init
volumes:
- motion-singularity-volume:/usr/src/app/storage
ports:
- 9090:9090
environment:
DATABASE_CONNECTION_STRING: postgres://${SINGULARITY_DB_USER:-postgres}:${SINGULARITY_DB_PASSWORD:-postgres}@db:5432/${SINGULARITY_DB_NAME:-singularity}
LOTUS_TEST:
Expand All @@ -35,7 +33,7 @@ services:
condition: service_healthy

singularity_api:
image: ghcr.io/data-preservation-programs/singularity:${SINGULARITY_TAG}
image: ghcr.io/data-preservation-programs/singularity${SINGULARITY_REF}
command: run api --bind :9090
volumes:
- motion-singularity-volume:/usr/src/app/storage
Expand All @@ -51,7 +49,7 @@ services:
condition: service_completed_successfully

singularity_dataset_worker:
image: ghcr.io/data-preservation-programs/singularity:${SINGULARITY_TAG}
image: ghcr.io/data-preservation-programs/singularity${SINGULARITY_REF}
volumes:
- motion-singularity-volume:/usr/src/app/storage
command: run dataset-worker
Expand All @@ -65,7 +63,7 @@ services:
condition: service_completed_successfully

singularity_deal_pusher:
image: ghcr.io/data-preservation-programs/singularity:${SINGULARITY_TAG}
image: ghcr.io/data-preservation-programs/singularity${SINGULARITY_REF}
volumes:
- motion-singularity-volume:/usr/src/app/storage
command: run deal-pusher
Expand All @@ -79,7 +77,7 @@ services:
condition: service_completed_successfully

singularity_deal_tracker:
image: ghcr.io/data-preservation-programs/singularity:${SINGULARITY_TAG}
image: ghcr.io/data-preservation-programs/singularity${SINGULARITY_REF}
volumes:
- motion-singularity-volume:/usr/src/app/storage
command: run deal-tracker
Expand All @@ -93,7 +91,7 @@ services:
condition: service_completed_successfully

singularity_content_provider:
image: ghcr.io/data-preservation-programs/singularity:${SINGULARITY_TAG}
image: ghcr.io/data-preservation-programs/singularity${SINGULARITY_REF}
command: run content-provider --http-bind :7778
volumes:
- motion-singularity-volume:/usr/src/app/storage
Expand Down
3 changes: 3 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
Expand Down Expand Up @@ -1255,6 +1256,8 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7V
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ=
go.dedis.ch/kyber/v3 v3.0.9 h1:i0ZbOQocHUjfFasBiUql5zVeC7u/vahFd96DFA8UOWk=
go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
Expand Down
10 changes: 6 additions & 4 deletions integration/singularity/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,10 @@ func (s *SingularityStore) Describe(ctx context.Context, id blob.ID) (*blob.Desc
if err != nil {
return nil, err
}
descriptor, err := s.local.Describe(ctx, decoded)
if err != nil {
return nil, err
descriptor := &blob.Descriptor{
ID: id,
Size: uint64(getFileRes.Payload.Size),
ModificationTime: time.Unix(0, getFileRes.Payload.LastModifiedNano),
}
getFileDealsRes, err := s.singularityClient.File.GetFileDeals(&file.GetFileDealsParams{
Context: ctx,
Expand Down Expand Up @@ -545,7 +546,7 @@ binIteration:
for _, sp := range s.storageProviders {
var foundDealForSP bool
for _, deal := range getFileDealsRes.Payload {
if deal.Provider == sp.String() {
if deal.Provider == sp.String() && (deal.State == models.ModelDealStatePublished || deal.State == models.ModelDealStateActive) {
foundDealForSP = true
break
}
Expand All @@ -560,6 +561,7 @@ binIteration:

// If deals have been made for all SPs, the local bin file can be
// deleted
logger.Infof("deleting local copy for deal %s, file %s", id, binFileName)
binsToDelete = append(binsToDelete, binFileName)
}

Expand Down
47 changes: 47 additions & 0 deletions integration/test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.PHONY: devnet/up devnet/down motionlarity/up motionlarity/down test

./devnet/.up:
echo "Run Boost Devnet from pre-built images"
rm -rf ./devnet/data && docker compose -f ./devnet/docker-compose.yaml up -d
echo "Await Lotus full node startup"
docker compose -f ./devnet/docker-compose.yaml exec lotus lotus wait-api --timeout=20m
echo "Await Lotus-miner full node startup"
docker compose -f ./devnet/docker-compose.yaml exec lotus-miner lotus-miner wait-api --timeout=20m
touch ./devnet/.up

devnet/up: ./devnet/.up

./devnet/.boostready: ./devnet/.up
./boost-setup.sh
touch ./devnet/.boostready

./motionlarity/.env.local: ./devnet/.up
echo "Set up Motion Wallet and API endpoints"
cat ./motionlarity/.env > ./motionlarity/.env.local
echo "" >> ./motionlarity/.env.local
./integration-setup.sh ./motionlarity/.env.local

motionlarity/setup: ./motionlarity/.env.local ./devnet/.boostready

devnet/down: motionlarity/down
docker compose -f ./devnet/docker-compose.yaml down && sleep 2 && rm -rf ./devnet/data
rm ./devnet/.up || true

./motionlarity/.up: ./motionlarity/.env.local ./devnet/.boostready
./buildsingularity.sh
echo "Run Motionlarity"
docker compose -f ./motionlarity/docker-compose.yaml --env-file ./motionlarity/.env.local up -d
./waitmotion.sh
touch ./motionlarity/.up

motionlarity/up: ./motionlarity/.up

motionlarity/down:
docker compose -f ./motionlarity/docker-compose.yaml down --rmi=all --volumes
rm ./motionlarity/.up || true
rm ./motionlarity/.env.local || true
rm ./devnet/.boostready || true

test: motionlarity/up
echo "Run Motion integration tests"
MOTION_INTEGRATION_TEST='true' go test . -v --count=1
23 changes: 23 additions & 0 deletions integration/test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Motion Devnet Integration Test Suite

This integration allows you to spin up a complete devnet including Lotus, Boost, Singularity, and Motion, in order to test round trip deal flow. It includes an integration test that covers all steps of a motion deal workflow, including storing to a filecoin provider and retrieving data back via trustless HTTP retrieval.

It's intended both as an integration test to run in CI, and a platform for developers to spin up test nets so they can try out new Motion features they are working on.

### Command reference

All devnets are spun up with `make`. Key commands:

- `make devnet/up` - will spin up a boost / lotus devnet
- `make motionlarity/up` - will spin up motion and singularity pre-configured to make deals with a lotus/boost devnet. if a lotus / boost devnet is not already spun up, this will spin one up
- `make test` - this will run the integration test on top of the motion/singularity/boost/lotus devnets. It will spin up all required networks that are not already running
- `make motionalirity/down` -- this will shut down motion and singularity processes
- `make devnet/down` -- this will shut down the boost/lotus devnet. If singularity and motion processes running, it will shut them down as well

### Using local singularity

Motion processes that are spun up with this test suite automatically use the code that is in the local repository on the current branch.

However, Singularity processes are by default spun up with a remote image. If you want to spin up Singularity using a local code repository as the base, you'll want to specify `SINGULARITY_LOCAL_DOCKERFILE` as the path to your local singularity repo. For example, if you store your go repositories on the traditional go src folder hierarchy, you can use:

`SINGULARITY_LOCAL_DOCKERFILE=../../../../data-preservation-programs/singularity make motionlarity/up`
7 changes: 7 additions & 0 deletions integration/test/boost-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

echo "setup boost pricing"
for i in {1..10}
do
curl -X POST -d '{"operationName":"AppStorageAskUpdateMutation","variables":{"update":{"Price":"0", "VerifiedPrice": 0}},"query":"mutation AppStorageAskUpdateMutation($update: StorageAskUpdate!) {\n storageAskUpdate(update: $update)\n}\n"}' http://localhost:8080/graphql/query && break || sleep 5
done
8 changes: 8 additions & 0 deletions integration/test/buildsingularity.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

if [ -n "$SINGULARITY_LOCAL_DOCKERFILE" ]
then
echo "Building singularity from local source"
source ./motionlarity/.env
docker build -t ghcr.io/data-preservation-programs/singularity${SINGULARITY_REF} ${SINGULARITY_LOCAL_DOCKERFILE}
fi
4 changes: 4 additions & 0 deletions integration/test/devnet/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ services:

boost:
container_name: boost
platform: linux/amd64
image: ${BOOST_IMAGE}
init: true
ports:
Expand All @@ -81,8 +82,10 @@ services:
- ./data/lotus:/var/lib/lotus:ro
- ./data/lotus-miner:/var/lib/lotus-miner:ro
- ./data/sample:/app/public:rw
- ./entrypoints/boost:/app:rw

booster-http:
platform: linux/amd64
container_name: booster-http
image: ${BOOSTER_HTTP_IMAGE}
init: true
Expand All @@ -101,6 +104,7 @@ services:
- ./data/lotus-miner:/var/lib/lotus-miner:ro

booster-bitswap:
platform: linux/amd64
container_name: booster-bitswap
image: ${BOOSTER_BITSWAP_IMAGE}
init: true
Expand Down
87 changes: 87 additions & 0 deletions integration/test/devnet/entrypoints/boost/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
set -e

echo Wait for lotus is ready ...
lotus wait-api
echo Wait for lotus-miner is ready ...
lotus-miner wait-api
echo BOOST_PATH=$BOOST_PATH
export DEFAULT_WALLET=`lotus wallet default`
export FULLNODE_API_INFO=`lotus auth api-info --perm=admin | cut -f2 -d=`
export MINER_API_INFO=`lotus-miner auth api-info --perm=admin | cut -f2 -d=`

if [ ! -f $BOOST_PATH/.init.boost ]; then
echo Init wallets ...
export COLLAT_WALLET=`lotus wallet new bls`
export PUBMSG_WALLET=`lotus wallet new bls`
export CLIENT_WALLET=`lotus wallet new bls`
echo MINER_API_INFO=$MINER_API_INFO
echo FULLNODE_API_INFO=$FULLNODE_API_INFO
echo PUBMSG_WALLET=$PUBMSG_WALLET
echo COLLAT_WALLET=$COLLAT_WALLET

lotus send --from $DEFAULT_WALLET $COLLAT_WALLET 10
lotus send --from $DEFAULT_WALLET $PUBMSG_WALLET 10
lotus send --from $DEFAULT_WALLET $CLIENT_WALLET 10
lotus wallet market add --from $DEFAULT_WALLET --address $CLIENT_WALLET 5
lotus wallet market add --address $COLLAT_WALLET 5

until lotus-miner actor control set --really-do-it ${PUBMSG_WALLET}; do echo Waiting for storage miner API ready ...; sleep 1; done

echo Init boost on first run ...

boostd -vv --boost-repo $BOOST_PATH init --api-sealer=$MINER_API_INFO \
--api-sector-index=$MINER_API_INFO \
--wallet-publish-storage-deals=$PUBMSG_WALLET \
--wallet-deal-collateral=$COLLAT_WALLET \
--max-staging-deals-bytes=2000000000

# echo exit code: $?

echo Setting port in boost config...
sed 's|ip4/0.0.0.0/tcp/0|ip4/0.0.0.0/tcp/50000|g' $BOOST_PATH/config.toml > $BOOST_PATH/config.toml.tmp; cp $BOOST_PATH/config.toml.tmp $BOOST_PATH/config.toml; rm $BOOST_PATH/config.toml.tmp
sed 's|127.0.0.1|0.0.0.0|g' $BOOST_PATH/config.toml > $BOOST_PATH/config.toml.tmp; cp $BOOST_PATH/config.toml.tmp $BOOST_PATH/config.toml; rm $BOOST_PATH/config.toml.tmp

echo Done
touch $BOOST_PATH/.init.boost
fi

# TODO(anteva): fixme: hack as boostd fails to start without this dir
mkdir -p /var/lib/boost/deal-staging

if [ ! -f $BOOST_PATH/.register.boost ]; then
echo Temporary starting boost to get maddr...

boostd -vv run &> $BOOST_PATH/boostd.log &
BOOST_PID=`echo $!`
echo Got boost PID = $BOOST_PID

until cat $BOOST_PATH/boostd.log | grep maddr; do echo "Waiting for boost..."; sleep 1; done
echo Looks like boost started and initialized...

echo Registering to lotus-miner...
MADDR=`cat $BOOST_PATH/boostd.log | grep maddr | cut -f3 -d"{" | cut -f1 -d:`
echo Got maddr=${MADDR}

lotus-miner actor set-peer-id ${MADDR}
lotus-miner actor set-addrs /dns/boost/tcp/50000
echo Registered

touch $BOOST_PATH/.register.boost
echo Try to stop boost...
kill -15 $BOOST_PID || kill -9 $BOOST_PID
rm -f $BOOST_PATH/boostd.log
echo Super. DONE! Boostd is now configured and will be started soon
fi

## Override config options
echo Updating config values
sed 's|ServiceApiInfo = ""|ServiceApiInfo = "ws://localhost:8042"|g' $BOOST_PATH/config.toml > $BOOST_PATH/config.toml.tmp; cp $BOOST_PATH/config.toml.tmp $BOOST_PATH/config.toml; rm $BOOST_PATH/config.toml.tmp
sed 's|ExpectedSealDuration = "24h0m0s"|ExpectedSealDuration = "0h0m10s"|g' $BOOST_PATH/config.toml > $BOOST_PATH/config.toml.tmp; cp $BOOST_PATH/config.toml.tmp $BOOST_PATH/config.toml; rm $BOOST_PATH/config.toml.tmp

echo Setting HTTP addr
sed 's|HTTPRetrievalMultiaddr = ""|HTTPRetrievalMultiaddr = "/dns4/booster-http/tcp/7777/http"|g' $BOOST_PATH/config.toml > $BOOST_PATH/config.toml.tmp; cp $BOOST_PATH/config.toml.tmp $BOOST_PATH/config.toml; rm $BOOST_PATH/config.toml.tmp

echo Starting LID service and boost in dev mode...
trap 'kill %1' SIGINT
exec boostd-data run leveldb --addr=0.0.0.0:8042 & boostd -vv run --nosync=true
Loading

0 comments on commit f870783

Please sign in to comment.