-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(test): setup github workflow to monitor process state
- Loading branch information
dtfiedler
committed
Aug 27, 2024
1 parent
9e3d25c
commit 64b1d88
Showing
13 changed files
with
291 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# run on a cron every hour and call yarn monitor | ||
|
||
name: Montior IO Process | ||
|
||
on: | ||
push: | ||
workflow_dispatch: | ||
schedule: | ||
- cron: '0 * * * *' # Run every hour | ||
|
||
jobs: | ||
monitor: | ||
permissions: | ||
contents: read | ||
actions: read | ||
strategy: | ||
matrix: | ||
network: [testnet, devnet] | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup Node.js | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version-file: '.nvmrc' | ||
cache: 'yarn' | ||
|
||
- name: Setup | ||
run: yarn | ||
|
||
- name: Monitor | ||
run: yarn monitor | tee results.txt | ||
continue-on-error: true | ||
id: monitor | ||
env: | ||
IO_PROCESS_ID: ${{ matrix.network == 'testnet' && 'agYcCFJtrMG6cqMuZfskIkFTGvUPddICmtQSBIoPdiA' || 'GaQrvEMKBpkjofgnBi_B3IgIDmY_XYelVLB6GcRGrHc' }} | ||
|
||
- name: Create test output | ||
id: test-outputs | ||
run: | | ||
TEST_RESULTS=$(cat results.txt) | ||
echo "TEST_RESULTS<<EOF" >> $GITHUB_ENV | ||
echo "$TEST_RESULTS" >> $GITHUB_ENV | ||
echo "EOF" >> $GITHUB_ENV | ||
- name: Notify Failure | ||
if: failure() | ||
uses: 8398a7/action-slack@v3 | ||
with: | ||
status: ${{ job.status }} | ||
text: 'IO Process Observation Failed!' | ||
custom_payload: | | ||
{ | ||
text: "IO Process Observation Failed", | ||
attachments: [{ | ||
fallback: 'IO Process Observation Failed', | ||
color: 'danger', | ||
title: 'Test Results', | ||
text: 'The IO Process Observation test has failed.', | ||
fields: [{ | ||
title: 'Network', | ||
value: '${{ matrix.network }}', | ||
short: true | ||
}, | ||
{ | ||
title: 'Process ID', | ||
value: '${{ matrix.network == 'testnet' && 'agYcCFJtrMG6cqMuZfskIkFTGvUPddICmtQSBIoPdiA' || 'GaQrvEMKBpkjofgnBi_B3IgIDmY_XYelVLB6GcRGrHc' }}', | ||
short: true | ||
}, | ||
{ | ||
title: 'Error Details', | ||
value: '${{ steps.monitor.outputs.stderr }}', | ||
short: false | ||
}], | ||
}] | ||
} | ||
env: | ||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} | ||
|
||
# on sucess send a slack message | ||
- name: Notify Success | ||
if: success() | ||
uses: rtCamp/action-slack-notify@v2 | ||
env: | ||
SLACK_COLOR: ${{ job.status }} | ||
SLACK_TITLE: IO Process Observation Success! | ||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} | ||
SLACK_CUSTOM_PAYLOAD: | | ||
{ | ||
"text": "IO Process Observation Success!", | ||
"attachments": [{ | ||
"fallback": "IO Process Observation Success!", | ||
"color": "good", | ||
"title": "Test Results", | ||
"text": "The IO Process Observation test has succeeded.", | ||
"fields": [{ | ||
"title": "Network", | ||
"value": "${{ matrix.network }}", | ||
"short": true | ||
}, | ||
{ | ||
"title": "Process ID", | ||
"value": "${{ matrix.network == 'testnet' && 'agYcCFJtrMG6cqMuZfskIkFTGvUPddICmtQSBIoPdiA' || 'GaQrvEMKBpkjofgnBi_B3IgIDmY_XYelVLB6GcRGrHc' }}", | ||
"short": true | ||
}, | ||
{ | ||
"title": "Test Output", | ||
"value": "```\n${{ env.TEST_RESULTS }}\n```", | ||
"short": false | ||
} | ||
] | ||
}] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { IO_DEVNET_PROCESS_ID, IO, IO_TESTNET_PROCESS_ID } from '@ar.io/sdk'; | ||
import { strict as assert } from 'node:assert'; | ||
import { describe, it } from 'node:test'; | ||
|
||
const io = IO.init({ | ||
processId: process.env.IO_PROCESS_ID || IO_TESTNET_PROCESS_ID, | ||
}); | ||
|
||
describe('distribution totals', () => { | ||
it('should always have correct eligible rewards for the current epoch (within 10 mIO)', async () => { | ||
const { distributions: currentEpochDistributions } = | ||
await io.getCurrentEpoch(); | ||
|
||
// TODO: for now pass if distributions are empty | ||
if (Object.keys(currentEpochDistributions).length === 0) { | ||
return; | ||
} | ||
|
||
// add up all the eligible operators and delegates | ||
const assignedRewards = Object.values( | ||
currentEpochDistributions.rewards.eligible, | ||
).reduce((acc, curr) => { | ||
const delegateRewards = Object.values(curr.delegateRewards).reduce( | ||
(d, c) => d + c, | ||
0, | ||
); | ||
return acc + curr.operatorReward + delegateRewards; | ||
}, 0); | ||
|
||
// handle any rounding errors | ||
const roundingError = | ||
assignedRewards - currentEpochDistributions.totalEligibleRewards; | ||
// assert total eligible rewards rounding is less than 10 | ||
assert( | ||
roundingError < 10, | ||
`Rounding for eligible distributions is too large: ${roundingError}`, | ||
); | ||
}); | ||
}); | ||
|
||
describe('token supply', () => { | ||
it('should always be 1 billion IO', async () => { | ||
const totalSupply = await io.getTokenSupply(); | ||
assert( | ||
totalSupply === 1000000000 * 1000000, | ||
`Total supply is not 1 billion IO: ${totalSupply}`, | ||
); | ||
}); | ||
}); | ||
|
||
// TODO: arns - ensure no invalid arns names | ||
|
||
describe('gateway registry', () => { | ||
it('should only have valid gateways', async () => { | ||
let cursor = ''; | ||
do { | ||
const { items: gateways, nextCursor } = await io.getGateways({ | ||
cursor, | ||
}); | ||
for (const gateway of gateways) { | ||
assert(gateway.operatorStake >= 50_000_000_000); | ||
} | ||
cursor = nextCursor; | ||
} while (cursor !== undefined); | ||
}); | ||
}); | ||
|
||
// Gateway registry - ensure no invalid gateways | ||
describe('arns names', () => { | ||
const twoWeeks = 2 * 7 * 24 * 60 * 60 * 1000; | ||
it('should not have any arns records older than two weeks', async () => { | ||
let cursor = ''; | ||
do { | ||
const { items: arns, nextCursor } = await io.getArNSRecords({ | ||
cursor, | ||
}); | ||
for (const arn of arns) { | ||
assert(arn.processId, `ARNs name '${arn.name}' has no processId`); | ||
assert(arn.type, `ARNs name '${arn.name}' has no type`); | ||
assert( | ||
arn.startTimestamp, | ||
`ARNs name '${arn.name}' has no start timestamp`, | ||
); | ||
assert( | ||
arn.purchasePrice >= 0, | ||
`ARNs name '${arn.name}' has no purchase price`, | ||
); | ||
assert( | ||
arn.undernameLimit >= 10, | ||
`ARNs name '${arn.name}' has no undername limit`, | ||
); | ||
if (arns.type === 'lease') { | ||
assert( | ||
arn.endTimestamp, | ||
`ARNs name '${arn.name}' has no end timestamp`, | ||
); | ||
assert( | ||
arn.endTimestamp > Date.now() - twoWeeks, | ||
`ARNs name '${arn.name}' is older than two weeks`, | ||
); | ||
} | ||
// if permabuy, assert no endTimestamp | ||
if (arn.type === 'permabuy') { | ||
assert( | ||
!arn.endTimestamp, | ||
`ARNs name '${arn.name}' has an end timestamp`, | ||
); | ||
} | ||
} | ||
cursor = nextCursor; | ||
} while (cursor !== undefined); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.