@audius/sdk 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +38 -0
- package/.prettierrc.js +1 -0
- package/.python-version +1 -0
- package/Dockerfile +15 -0
- package/README.md +3 -0
- package/babel.config.js +3 -0
- package/data-contracts/ABIs/AdminUpgradeabilityProxy.json +132 -0
- package/data-contracts/ABIs/BaseAdminUpgradeabilityProxy.json +113 -0
- package/data-contracts/ABIs/BaseUpgradeabilityProxy.json +22 -0
- package/data-contracts/ABIs/DiscoveryProviderFactory.json +189 -0
- package/data-contracts/ABIs/DiscoveryProviderFactoryInterface.json +61 -0
- package/data-contracts/ABIs/DiscoveryProviderStorage.json +205 -0
- package/data-contracts/ABIs/DiscoveryProviderStorageInterface.json +65 -0
- package/data-contracts/ABIs/ECDSA.json +4 -0
- package/data-contracts/ABIs/IPLDBlacklistFactory.json +168 -0
- package/data-contracts/ABIs/Initializable.json +4 -0
- package/data-contracts/ABIs/Migrations.json +67 -0
- package/data-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
- package/data-contracts/ABIs/Ownable.json +79 -0
- package/data-contracts/ABIs/PlaylistFactory.json +669 -0
- package/data-contracts/ABIs/PlaylistFactoryInterface.json +42 -0
- package/data-contracts/ABIs/PlaylistStorage.json +250 -0
- package/data-contracts/ABIs/PlaylistStorageInterface.json +129 -0
- package/data-contracts/ABIs/Proxy.json +10 -0
- package/data-contracts/ABIs/Registry.json +240 -0
- package/data-contracts/ABIs/RegistryContract.json +102 -0
- package/data-contracts/ABIs/RegistryContractInterface.json +28 -0
- package/data-contracts/ABIs/RegistryInterface.json +66 -0
- package/data-contracts/ABIs/SigningLogic.json +43 -0
- package/data-contracts/ABIs/SigningLogicInitializable.json +46 -0
- package/data-contracts/ABIs/SocialFeatureFactory.json +460 -0
- package/data-contracts/ABIs/SocialFeatureStorage.json +225 -0
- package/data-contracts/ABIs/SocialFeatureStorageInterface.json +123 -0
- package/data-contracts/ABIs/TestContract.json +135 -0
- package/data-contracts/ABIs/TestContractInterface.json +19 -0
- package/data-contracts/ABIs/TestContractWithStorage.json +165 -0
- package/data-contracts/ABIs/TestContractWithStorageInterface.json +24 -0
- package/data-contracts/ABIs/TestStorage.json +144 -0
- package/data-contracts/ABIs/TestStorageInterface.json +42 -0
- package/data-contracts/ABIs/TestUserReplicaSetManager.json +432 -0
- package/data-contracts/ABIs/TrackFactory.json +391 -0
- package/data-contracts/ABIs/TrackFactoryInterface.json +73 -0
- package/data-contracts/ABIs/TrackStorage.json +223 -0
- package/data-contracts/ABIs/TrackStorageInterface.json +121 -0
- package/data-contracts/ABIs/UpgradeabilityProxy.json +37 -0
- package/data-contracts/ABIs/UserFactory.json +657 -0
- package/data-contracts/ABIs/UserFactoryInterface.json +65 -0
- package/data-contracts/ABIs/UserLibraryFactory.json +334 -0
- package/data-contracts/ABIs/UserReplicaSetManager.json +418 -0
- package/data-contracts/ABIs/UserStorage.json +233 -0
- package/data-contracts/ABIs/UserStorageInterface.json +93 -0
- package/data-contracts/signatureSchemas.ts +1236 -0
- package/dist/core.d.ts +446 -0
- package/dist/core.js +769 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +689 -0
- package/dist/index.js +72850 -0
- package/dist/index.js.map +1 -0
- package/eth-contracts/ABIs/Address.json +4 -0
- package/eth-contracts/ABIs/AudiusAdminUpgradeabilityProxy.json +105 -0
- package/eth-contracts/ABIs/AudiusClaimDistributor.json +4968 -0
- package/eth-contracts/ABIs/AudiusToken.json +724 -0
- package/eth-contracts/ABIs/BaseUpgradeabilityProxy.json +23 -0
- package/eth-contracts/ABIs/Checkpointing.json +4 -0
- package/eth-contracts/ABIs/ClaimsManager.json +539 -0
- package/eth-contracts/ABIs/Context.json +11 -0
- package/eth-contracts/ABIs/DelegateManager.json +989 -0
- package/eth-contracts/ABIs/DelegateManagerV2.json +1049 -0
- package/eth-contracts/ABIs/DelegateManagerV2Bad.json +1049 -0
- package/eth-contracts/ABIs/ERC20.json +252 -0
- package/eth-contracts/ABIs/ERC20Burnable.json +287 -0
- package/eth-contracts/ABIs/ERC20Detailed.json +270 -0
- package/eth-contracts/ABIs/ERC20Mintable.json +364 -0
- package/eth-contracts/ABIs/ERC20Pausable.json +397 -0
- package/eth-contracts/ABIs/EthRewardsManager.json +174 -0
- package/eth-contracts/ABIs/Governance.json +938 -0
- package/eth-contracts/ABIs/GovernanceUpgraded.json +953 -0
- package/eth-contracts/ABIs/GovernanceV2.json +938 -0
- package/eth-contracts/ABIs/IERC20.json +200 -0
- package/eth-contracts/ABIs/Initializable.json +4 -0
- package/eth-contracts/ABIs/InitializableV2.json +14 -0
- package/eth-contracts/ABIs/Migrations.json +71 -0
- package/eth-contracts/ABIs/MinterRole.json +91 -0
- package/eth-contracts/ABIs/MockAccount.json +62 -0
- package/eth-contracts/ABIs/MockDelegateManager.json +55 -0
- package/eth-contracts/ABIs/MockStakingCaller.json +259 -0
- package/eth-contracts/ABIs/MockWormhole.json +106 -0
- package/eth-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
- package/eth-contracts/ABIs/Ownable.json +93 -0
- package/eth-contracts/ABIs/Pausable.json +150 -0
- package/eth-contracts/ABIs/PauserRole.json +91 -0
- package/eth-contracts/ABIs/Proxy.json +10 -0
- package/eth-contracts/ABIs/Registry.json +288 -0
- package/eth-contracts/ABIs/Roles.json +4 -0
- package/eth-contracts/ABIs/SafeERC20.json +4 -0
- package/eth-contracts/ABIs/SafeMath.json +4 -0
- package/eth-contracts/ABIs/ServiceProviderFactory.json +1153 -0
- package/eth-contracts/ABIs/ServiceTypeManager.json +337 -0
- package/eth-contracts/ABIs/Staking.json +555 -0
- package/eth-contracts/ABIs/StakingUpgraded.json +570 -0
- package/eth-contracts/ABIs/TestContract.json +44 -0
- package/eth-contracts/ABIs/TrustedNotifierManager.json +265 -0
- package/eth-contracts/ABIs/Uint256Helpers.json +4 -0
- package/eth-contracts/ABIs/UpgradeabilityProxy.json +40 -0
- package/eth-contracts/ABIs/Wormhole.json +45 -0
- package/eth-contracts/ABIs/WormholeClient.json +155 -0
- package/examples/file.mp3 +0 -0
- package/examples/initAudiusLibs.js +86 -0
- package/examples/initializeVersions.js +95 -0
- package/examples/pic.jpg +0 -0
- package/initScripts/configureLocalDiscProv.js +167 -0
- package/initScripts/helpers/claim.js +43 -0
- package/initScripts/helpers/distributeTokens.js +24 -0
- package/initScripts/helpers/spRegistration.js +138 -0
- package/initScripts/helpers/utils.js +34 -0
- package/initScripts/helpers/version.js +93 -0
- package/initScripts/local.js +617 -0
- package/initScripts/mainnet.js +131 -0
- package/initScripts/manageProdRelayerWallets.js +191 -0
- package/package.json +125 -0
- package/rollup.config.js +164 -0
- package/scripts/AudiusClaimDistributor.json +4968 -0
- package/scripts/Wormhole.json +155 -0
- package/scripts/addCIDToIpldBlacklist.js +124 -0
- package/scripts/circleci-test.sh +53 -0
- package/scripts/communityRewards/transferCommunityRewardsToSolana.js +222 -0
- package/scripts/ipfs.sh +58 -0
- package/scripts/migrate_contracts.sh +25 -0
- package/scripts/reset.sh +65 -0
- package/scripts/test.sh +77 -0
- package/src/api/account.js +670 -0
- package/src/api/base.js +122 -0
- package/src/api/file.js +168 -0
- package/src/api/playlist.js +328 -0
- package/src/api/rewards.d.ts +4 -0
- package/src/api/rewards.js +682 -0
- package/src/api/serviceProvider.js +154 -0
- package/src/api/track.js +604 -0
- package/src/api/user.js +888 -0
- package/src/api/user.test.js +172 -0
- package/src/constants.ts +7 -0
- package/src/core.ts +3 -0
- package/src/index.js +6 -0
- package/src/libs.d.ts +3 -0
- package/src/libs.js +619 -0
- package/src/sanityChecks/addSecondaries.js +40 -0
- package/src/sanityChecks/assignReplicaSetIfNecessary.js +10 -0
- package/src/sanityChecks/index.d.ts +9 -0
- package/src/sanityChecks/index.js +31 -0
- package/src/sanityChecks/isCreator.js +73 -0
- package/src/sanityChecks/needsRecoveryEmail.js +20 -0
- package/src/sanityChecks/rolloverNodes.js +74 -0
- package/src/sanityChecks/sanitizeNodes.js +24 -0
- package/src/sanityChecks/syncNodes.js +28 -0
- package/src/sdk/constants.ts +10 -0
- package/src/sdk/index.ts +1 -0
- package/src/sdk/oauth/Oauth.ts +265 -0
- package/src/sdk/oauth/index.ts +1 -0
- package/src/sdk/sdk.ts +102 -0
- package/src/service-selection/ServiceSelection.test.ts +320 -0
- package/src/service-selection/ServiceSelection.ts +460 -0
- package/src/service-selection/constants.ts +14 -0
- package/src/service-selection/index.ts +1 -0
- package/src/services/ABIDecoder/AudiusABIDecoder.ts +71 -0
- package/src/services/ABIDecoder/index.ts +1 -0
- package/src/services/comstock/Comstock.ts +39 -0
- package/src/services/comstock/index.ts +1 -0
- package/src/services/contracts/ContractClient.ts +227 -0
- package/src/services/contracts/GovernedContractClient.ts +53 -0
- package/src/services/contracts/ProviderSelection.ts +42 -0
- package/src/services/creatorNode/CreatorNode.ts +1065 -0
- package/src/services/creatorNode/CreatorNodeSelection.test.ts +997 -0
- package/src/services/creatorNode/CreatorNodeSelection.ts +488 -0
- package/src/services/creatorNode/constants.ts +10 -0
- package/src/services/creatorNode/index.ts +2 -0
- package/src/services/dataContracts/AudiusContracts.ts +234 -0
- package/src/services/dataContracts/IPLDBlacklistFactoryClient.ts +73 -0
- package/src/services/dataContracts/PlaylistFactoryClient.ts +370 -0
- package/src/services/dataContracts/RegistryClient.ts +95 -0
- package/src/services/dataContracts/SocialFeatureFactoryClient.ts +196 -0
- package/src/services/dataContracts/TrackFactoryClient.ts +131 -0
- package/src/services/dataContracts/UserFactoryClient.ts +351 -0
- package/src/services/dataContracts/UserLibraryFactoryClient.ts +115 -0
- package/src/services/dataContracts/UserReplicaSetManagerClient.ts +206 -0
- package/src/services/dataContracts/index.ts +1 -0
- package/src/services/discoveryProvider/DiscoveryProvider.ts +1168 -0
- package/src/services/discoveryProvider/DiscoveryProviderSelection.test.ts +536 -0
- package/src/services/discoveryProvider/DiscoveryProviderSelection.ts +383 -0
- package/src/services/discoveryProvider/constants.ts +13 -0
- package/src/services/discoveryProvider/index.ts +1 -0
- package/src/services/discoveryProvider/requests.ts +629 -0
- package/src/services/ethContracts/AudiusTokenClient.ts +163 -0
- package/src/services/ethContracts/ClaimDistributionClient.ts +45 -0
- package/src/services/ethContracts/ClaimsManagerClient.ts +102 -0
- package/src/services/ethContracts/DelegateManagerClient.ts +480 -0
- package/src/services/ethContracts/EthContracts.ts +359 -0
- package/src/services/ethContracts/EthRewardsManagerClient.ts +33 -0
- package/src/services/ethContracts/GovernanceClient.ts +451 -0
- package/src/services/ethContracts/RegistryClient.ts +33 -0
- package/src/services/ethContracts/ServiceProviderFactoryClient.ts +691 -0
- package/src/services/ethContracts/ServiceTypeManagerClient.ts +112 -0
- package/src/services/ethContracts/StakingProxyClient.ts +97 -0
- package/src/services/ethContracts/TrustedNotifierManagerClient.ts +101 -0
- package/src/services/ethContracts/WormholeClient.ts +97 -0
- package/src/services/ethContracts/index.ts +1 -0
- package/src/services/ethWeb3Manager/EthWeb3Manager.ts +239 -0
- package/src/services/ethWeb3Manager/index.ts +1 -0
- package/src/services/hedgehog/Hedgehog.ts +96 -0
- package/src/services/hedgehog/index.ts +1 -0
- package/src/services/identity/IdentityService.ts +551 -0
- package/src/services/identity/index.ts +1 -0
- package/src/services/identity/requests.ts +65 -0
- package/src/services/schemaValidator/SchemaValidator.ts +105 -0
- package/src/services/schemaValidator/index.ts +1 -0
- package/src/services/schemaValidator/schemas/trackSchema.json +267 -0
- package/src/services/schemaValidator/schemas/userSchema.json +230 -0
- package/src/services/solanaAudiusData/errors.ts +20 -0
- package/src/services/solanaAudiusData/index.ts +1189 -0
- package/src/services/solanaWeb3Manager/errors.js +101 -0
- package/src/services/solanaWeb3Manager/index.d.ts +46 -0
- package/src/services/solanaWeb3Manager/index.js +655 -0
- package/src/services/solanaWeb3Manager/padBNToUint8Array.ts +7 -0
- package/src/services/solanaWeb3Manager/rewards.js +941 -0
- package/src/services/solanaWeb3Manager/rewardsAttester.ts +1093 -0
- package/src/services/solanaWeb3Manager/tokenAccount.js +149 -0
- package/src/services/solanaWeb3Manager/transactionHandler.js +345 -0
- package/src/services/solanaWeb3Manager/transfer.js +272 -0
- package/src/services/solanaWeb3Manager/userBank.js +160 -0
- package/src/services/solanaWeb3Manager/utils.d.ts +31 -0
- package/src/services/solanaWeb3Manager/utils.js +163 -0
- package/src/services/solanaWeb3Manager/wAudio.js +28 -0
- package/src/services/solanaWeb3Manager/wAudio.test.js +30 -0
- package/src/services/web3Manager/Web3Config.ts +14 -0
- package/src/services/web3Manager/Web3Manager.ts +360 -0
- package/src/services/web3Manager/XMLHttpRequest.ts +11 -0
- package/src/services/web3Manager/index.ts +2 -0
- package/src/services/wormhole/index.js +424 -0
- package/src/types.ts +8 -0
- package/src/userStateManager.ts +53 -0
- package/src/utils/apiSigning.ts +51 -0
- package/src/utils/captcha.ts +97 -0
- package/src/utils/estimateGas.ts +64 -0
- package/src/utils/fileHasher.ts +278 -0
- package/src/utils/importContractABI.d.ts +9 -0
- package/src/utils/importContractABI.js +19 -0
- package/src/utils/index.ts +11 -0
- package/src/utils/multiProvider.ts +72 -0
- package/src/utils/network.test.ts +127 -0
- package/src/utils/network.ts +308 -0
- package/src/utils/promiseFight.test.ts +87 -0
- package/src/utils/promiseFight.ts +36 -0
- package/src/utils/signatures.ts +139 -0
- package/src/utils/types.ts +34 -0
- package/src/utils/utils.test.ts +36 -0
- package/src/utils/utils.ts +235 -0
- package/src/utils/uuid.ts +14 -0
- package/src/web3.d.ts +9 -0
- package/src/web3.js +8 -0
- package/tests/assets/static_image.png +0 -0
- package/tests/assets/static_text.txt +1 -0
- package/tests/audiusTokenClientTest.js +37 -0
- package/tests/creatorNodeTest.js +19 -0
- package/tests/fileHasherTest.js +125 -0
- package/tests/governanceTest.js +382 -0
- package/tests/helpers.js +105 -0
- package/tests/index.js +14 -0
- package/tests/playlistClientTest.js +157 -0
- package/tests/providerSelectionTest.js +241 -0
- package/tests/registryClientTest.js +19 -0
- package/tests/rewardsAttesterTest.js +373 -0
- package/tests/serviceTypeManagerClientTest.js +33 -0
- package/tests/socialFeatureClientTest.js +79 -0
- package/tests/stakingTest.js +302 -0
- package/tests/trackClientTest.js +86 -0
- package/tests/userClientTest.js +121 -0
- package/tsconfig.json +10 -0
- package/types/@audius-hedgehog/index.d.ts +39 -0
- package/types/abi-decoder/index.d.ts +41 -0
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
import nock from 'nock'
|
|
2
|
+
import assert from 'assert'
|
|
3
|
+
import semver from 'semver'
|
|
4
|
+
|
|
5
|
+
import { CREATOR_NODE_SERVICE_NAME } from './constants'
|
|
6
|
+
import { CreatorNodeSelection } from './CreatorNodeSelection'
|
|
7
|
+
import type { EthContracts } from '../ethContracts'
|
|
8
|
+
|
|
9
|
+
const mockEthContracts = (
|
|
10
|
+
urls: string[],
|
|
11
|
+
currrentVersion: string,
|
|
12
|
+
previousVersions: string[] | null = null
|
|
13
|
+
): EthContracts =>
|
|
14
|
+
({
|
|
15
|
+
getCurrentVersion: async () => currrentVersion,
|
|
16
|
+
getNumberOfVersions: async () => 2,
|
|
17
|
+
getVersion: async (_: string, queryIndex: number) => {
|
|
18
|
+
if (previousVersions) {
|
|
19
|
+
return previousVersions[queryIndex] as string
|
|
20
|
+
}
|
|
21
|
+
return ['1.2.2', '1.2.3'][queryIndex] as string
|
|
22
|
+
},
|
|
23
|
+
getServiceProviderList: async () => urls.map((u) => ({ endpoint: u })),
|
|
24
|
+
hasSameMajorAndMinorVersion: (version1: string, version2: string) => {
|
|
25
|
+
return (
|
|
26
|
+
semver.major(version1) === semver.major(version2) &&
|
|
27
|
+
semver.minor(version1) === semver.minor(version2)
|
|
28
|
+
)
|
|
29
|
+
},
|
|
30
|
+
isInRegressedMode: () => {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
} as unknown as EthContracts)
|
|
34
|
+
|
|
35
|
+
const mockCreatorNode = {
|
|
36
|
+
getSyncStatus: async () => {
|
|
37
|
+
return {
|
|
38
|
+
isBehind: false,
|
|
39
|
+
isConfigured: true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
monitoringCallbacks: {}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Add fields as necessary
|
|
46
|
+
const defaultHealthCheckData = {
|
|
47
|
+
service: CREATOR_NODE_SERVICE_NAME,
|
|
48
|
+
version: '1.2.3',
|
|
49
|
+
healthy: true,
|
|
50
|
+
country: 'US',
|
|
51
|
+
latitude: '37.7749',
|
|
52
|
+
longitude: '-122.4194',
|
|
53
|
+
databaseConnections: 5,
|
|
54
|
+
totalMemory: 6237552640,
|
|
55
|
+
usedMemory: 6111436800,
|
|
56
|
+
storagePathSize: 62725623808,
|
|
57
|
+
storagePathUsed: 14723018752,
|
|
58
|
+
maxFileDescriptors: 524288,
|
|
59
|
+
allocatedFileDescriptors: 2912,
|
|
60
|
+
receivedBytesPerSec: 776.7638177541248,
|
|
61
|
+
transferredBytesPerSec: 39888.88888888889,
|
|
62
|
+
maxStorageUsedPercent: 95
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type HealthCheckData = { [K in keyof typeof defaultHealthCheckData]?: unknown }
|
|
66
|
+
|
|
67
|
+
describe('test CreatorNodeSelection', () => {
|
|
68
|
+
it('selects the fastest healthy service as primary and rest as secondaries', async () => {
|
|
69
|
+
const healthy = 'https://healthy.audius.co'
|
|
70
|
+
nock(healthy)
|
|
71
|
+
.get('/health_check/verbose')
|
|
72
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
73
|
+
|
|
74
|
+
const healthyButSlow = 'https://healthybutslow.audius.co'
|
|
75
|
+
nock(healthyButSlow)
|
|
76
|
+
.get('/health_check/verbose')
|
|
77
|
+
.delay(100)
|
|
78
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
79
|
+
|
|
80
|
+
const healthyButSlowest = 'https://healthybutslowest.audius.co'
|
|
81
|
+
nock(healthyButSlowest)
|
|
82
|
+
.get('/health_check/verbose')
|
|
83
|
+
.delay(200)
|
|
84
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
85
|
+
|
|
86
|
+
const cns = new CreatorNodeSelection({
|
|
87
|
+
creatorNode: mockCreatorNode,
|
|
88
|
+
numberOfNodes: 3,
|
|
89
|
+
ethContracts: mockEthContracts(
|
|
90
|
+
[healthy, healthyButSlow, healthyButSlowest],
|
|
91
|
+
'1.2.3'
|
|
92
|
+
),
|
|
93
|
+
whitelist: null,
|
|
94
|
+
blacklist: null
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
98
|
+
|
|
99
|
+
assert(primary === healthy)
|
|
100
|
+
assert(secondaries.length === 2)
|
|
101
|
+
assert(secondaries.includes(healthyButSlow))
|
|
102
|
+
assert(secondaries.includes(healthyButSlowest))
|
|
103
|
+
|
|
104
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
105
|
+
assert(returnedHealthyServices.size === 3)
|
|
106
|
+
const healthyServices = [healthy, healthyButSlow, healthyButSlowest]
|
|
107
|
+
healthyServices.map((service) =>
|
|
108
|
+
assert(returnedHealthyServices.has(service))
|
|
109
|
+
)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('Return nothing if whitelist is empty set', async function () {
|
|
113
|
+
const healthy = 'https://healthy.audius.co'
|
|
114
|
+
nock(healthy)
|
|
115
|
+
.get('/health_check/verbose')
|
|
116
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
117
|
+
|
|
118
|
+
const healthyButSlow = 'https://healthybutslow.audius.co'
|
|
119
|
+
nock(healthyButSlow)
|
|
120
|
+
.get('/health_check/verbose')
|
|
121
|
+
.delay(100)
|
|
122
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
123
|
+
|
|
124
|
+
const healthyButSlowest = 'https://healthybutslowest.audius.co'
|
|
125
|
+
nock(healthyButSlowest)
|
|
126
|
+
.get('/health_check/verbose')
|
|
127
|
+
.delay(200)
|
|
128
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
129
|
+
|
|
130
|
+
const cns = new CreatorNodeSelection({
|
|
131
|
+
creatorNode: mockCreatorNode,
|
|
132
|
+
numberOfNodes: 3,
|
|
133
|
+
ethContracts: mockEthContracts(
|
|
134
|
+
[healthy, healthyButSlow, healthyButSlowest],
|
|
135
|
+
'1.2.3'
|
|
136
|
+
),
|
|
137
|
+
whitelist: new Set([]),
|
|
138
|
+
blacklist: null
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
const { primary, secondaries, services } = await cns.select()
|
|
142
|
+
assert(primary === undefined)
|
|
143
|
+
assert(secondaries.length === 0)
|
|
144
|
+
|
|
145
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
146
|
+
assert(returnedHealthyServices.size === 0)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('select healthy nodes as the primary and secondary, and do not select unhealthy nodes', async () => {
|
|
150
|
+
const upToDate = 'https://upToDate.audius.co'
|
|
151
|
+
nock(upToDate)
|
|
152
|
+
.get('/health_check/verbose')
|
|
153
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
154
|
+
|
|
155
|
+
const behindMajor = 'https://behindMajor.audius.co'
|
|
156
|
+
nock(behindMajor)
|
|
157
|
+
.get('/health_check/verbose')
|
|
158
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '0.2.3' } })
|
|
159
|
+
|
|
160
|
+
const behindMinor = 'https://behindMinor.audius.co'
|
|
161
|
+
nock(behindMinor)
|
|
162
|
+
.get('/health_check/verbose')
|
|
163
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.0.3' } })
|
|
164
|
+
|
|
165
|
+
const behindPatch = 'https://behindPatch.audius.co'
|
|
166
|
+
nock(behindPatch)
|
|
167
|
+
.get('/health_check/verbose')
|
|
168
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.0' } })
|
|
169
|
+
|
|
170
|
+
const cns = new CreatorNodeSelection({
|
|
171
|
+
creatorNode: mockCreatorNode,
|
|
172
|
+
numberOfNodes: 3,
|
|
173
|
+
ethContracts: mockEthContracts(
|
|
174
|
+
[upToDate, behindMajor, behindMinor, behindPatch],
|
|
175
|
+
'1.2.3'
|
|
176
|
+
),
|
|
177
|
+
whitelist: null,
|
|
178
|
+
blacklist: null
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
182
|
+
|
|
183
|
+
assert(primary === upToDate)
|
|
184
|
+
assert(secondaries.length === 1)
|
|
185
|
+
assert(secondaries.includes(behindPatch))
|
|
186
|
+
|
|
187
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
188
|
+
assert(returnedHealthyServices.size === 2)
|
|
189
|
+
const healthyServices = [upToDate, behindPatch]
|
|
190
|
+
healthyServices.map((service) =>
|
|
191
|
+
assert(returnedHealthyServices.has(service))
|
|
192
|
+
)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('return nothing if no services are healthy', async () => {
|
|
196
|
+
const unhealthy1 = 'https://unhealthy1.audius.co'
|
|
197
|
+
nock(unhealthy1).get('/health_check/verbose').reply(500, {})
|
|
198
|
+
|
|
199
|
+
const unhealthy2 = 'https://unhealthy2.audius.co'
|
|
200
|
+
nock(unhealthy2).get('/health_check/verbose').delay(100).reply(500, {})
|
|
201
|
+
|
|
202
|
+
const unhealthy3 = 'https://unhealthy3.audius.co'
|
|
203
|
+
nock(unhealthy3).get('/health_check/verbose').delay(200).reply(500, {})
|
|
204
|
+
|
|
205
|
+
const unhealthy4 = 'https://unhealthy4.audius.co'
|
|
206
|
+
nock(unhealthy4).get('/health_check/verbose').delay(300).reply(500, {})
|
|
207
|
+
|
|
208
|
+
const unhealthy5 = 'https://unhealthy5.audius.co'
|
|
209
|
+
nock(unhealthy5).get('/health_check/verbose').delay(400).reply(500, {})
|
|
210
|
+
|
|
211
|
+
const cns = new CreatorNodeSelection({
|
|
212
|
+
creatorNode: mockCreatorNode,
|
|
213
|
+
numberOfNodes: 3,
|
|
214
|
+
ethContracts: mockEthContracts(
|
|
215
|
+
[unhealthy1, unhealthy2, unhealthy3, unhealthy4, unhealthy5],
|
|
216
|
+
'1.2.3'
|
|
217
|
+
),
|
|
218
|
+
whitelist: null,
|
|
219
|
+
blacklist: null
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
223
|
+
|
|
224
|
+
// All unhealthy are bad candidates so don't select anything
|
|
225
|
+
assert(primary === undefined)
|
|
226
|
+
assert(secondaries.length === 0)
|
|
227
|
+
|
|
228
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
229
|
+
assert(returnedHealthyServices.size === 0)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('selects the only healthy service among the services of different statuses', async () => {
|
|
233
|
+
// the cream of the crop -- up to date version, slow. you want this
|
|
234
|
+
const shouldBePrimary = 'https://shouldBePrimary.audius.co'
|
|
235
|
+
nock(shouldBePrimary)
|
|
236
|
+
.get('/health_check/verbose')
|
|
237
|
+
.delay(200)
|
|
238
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
239
|
+
|
|
240
|
+
// cold, overnight pizza -- behind by minor version, fast. nope
|
|
241
|
+
const unhealthy2 = 'https://unhealthy2.audius.co'
|
|
242
|
+
nock(unhealthy2)
|
|
243
|
+
.get('/health_check/verbose')
|
|
244
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.0.3' } })
|
|
245
|
+
|
|
246
|
+
// stale chips from 2 weeks ago -- behind by major version, kinda slow. still nope
|
|
247
|
+
const unhealthy3 = 'https://unhealthy3.audius.co'
|
|
248
|
+
nock(unhealthy3)
|
|
249
|
+
.get('/health_check/verbose')
|
|
250
|
+
.delay(100)
|
|
251
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '0.2.3' } })
|
|
252
|
+
|
|
253
|
+
// moldy canned beans -- not available/up at all. for sure nope
|
|
254
|
+
const unhealthy1 = 'https://unhealthy1.audius.co'
|
|
255
|
+
nock(unhealthy1).get('/health_check/verbose').reply(500, {})
|
|
256
|
+
|
|
257
|
+
// your house mate's leftovers from her team outing -- behind by patch, kinda slow. solid
|
|
258
|
+
const shouldBeSecondary = 'https://secondary.audius.co'
|
|
259
|
+
nock(shouldBeSecondary)
|
|
260
|
+
.get('/health_check/verbose')
|
|
261
|
+
.delay(100)
|
|
262
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.0' } })
|
|
263
|
+
|
|
264
|
+
const cns = new CreatorNodeSelection({
|
|
265
|
+
creatorNode: mockCreatorNode,
|
|
266
|
+
numberOfNodes: 3,
|
|
267
|
+
ethContracts: mockEthContracts(
|
|
268
|
+
[
|
|
269
|
+
unhealthy1,
|
|
270
|
+
shouldBePrimary,
|
|
271
|
+
unhealthy2,
|
|
272
|
+
unhealthy3,
|
|
273
|
+
shouldBeSecondary
|
|
274
|
+
],
|
|
275
|
+
'1.2.3'
|
|
276
|
+
),
|
|
277
|
+
whitelist: null,
|
|
278
|
+
blacklist: null
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
282
|
+
|
|
283
|
+
assert(primary === shouldBePrimary)
|
|
284
|
+
assert(secondaries.length === 1)
|
|
285
|
+
assert(secondaries.includes(shouldBeSecondary))
|
|
286
|
+
|
|
287
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
288
|
+
assert(returnedHealthyServices.size === 2)
|
|
289
|
+
const healthyServices = [shouldBePrimary, shouldBeSecondary]
|
|
290
|
+
healthyServices.map((service) =>
|
|
291
|
+
assert(returnedHealthyServices.has(service))
|
|
292
|
+
)
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* This test is to ensure that the proper number of services is selected.
|
|
297
|
+
* If numNodes = n, then (assuming all nodes are healthy):
|
|
298
|
+
* - 1 primary is selected
|
|
299
|
+
* - n-1 secondaries are selected
|
|
300
|
+
* - n services are returned
|
|
301
|
+
*/
|
|
302
|
+
it('selects numNodes - 1 number of secondaries (starting with numNodes=5->1)', async () => {
|
|
303
|
+
const contentNodes = []
|
|
304
|
+
const numNodes = 5
|
|
305
|
+
for (let i = 0; i < numNodes; i++) {
|
|
306
|
+
const healthyUrl = `https://healthy${i}.audius.co`
|
|
307
|
+
nock(healthyUrl)
|
|
308
|
+
.persist()
|
|
309
|
+
.get('/health_check/verbose')
|
|
310
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
311
|
+
contentNodes.push(healthyUrl)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
let cns
|
|
315
|
+
for (let i = 0; i < numNodes; i++) {
|
|
316
|
+
cns = new CreatorNodeSelection({
|
|
317
|
+
creatorNode: mockCreatorNode,
|
|
318
|
+
numberOfNodes: numNodes - i,
|
|
319
|
+
ethContracts: mockEthContracts(contentNodes, '1.2.3'),
|
|
320
|
+
whitelist: null,
|
|
321
|
+
blacklist: null
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
325
|
+
assert(primary)
|
|
326
|
+
assert(secondaries.length === numNodes - i - 1)
|
|
327
|
+
const returnedHealthyServices = Object.keys(services)
|
|
328
|
+
assert(returnedHealthyServices.length === numNodes)
|
|
329
|
+
}
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
it('selects 1 secondary if only 1 secondary is available', async () => {
|
|
333
|
+
const shouldBePrimary = 'https://shouldBePrimary.audius.co'
|
|
334
|
+
nock(shouldBePrimary)
|
|
335
|
+
.get('/health_check/verbose')
|
|
336
|
+
.delay(200)
|
|
337
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
338
|
+
|
|
339
|
+
const shouldBeSecondary = 'https://secondary.audius.co'
|
|
340
|
+
nock(shouldBeSecondary)
|
|
341
|
+
.get('/health_check/verbose')
|
|
342
|
+
.delay(100)
|
|
343
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.0' } })
|
|
344
|
+
|
|
345
|
+
const unhealthy = 'https://unhealthy.audius.co'
|
|
346
|
+
nock(unhealthy).get('/health_check/verbose').reply(500, {})
|
|
347
|
+
|
|
348
|
+
const cns = new CreatorNodeSelection({
|
|
349
|
+
creatorNode: mockCreatorNode,
|
|
350
|
+
numberOfNodes: 3,
|
|
351
|
+
ethContracts: mockEthContracts(
|
|
352
|
+
[unhealthy, shouldBePrimary, shouldBeSecondary],
|
|
353
|
+
'1.2.3'
|
|
354
|
+
),
|
|
355
|
+
whitelist: null,
|
|
356
|
+
blacklist: null
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
360
|
+
|
|
361
|
+
assert(primary === shouldBePrimary)
|
|
362
|
+
assert(secondaries.length === 1)
|
|
363
|
+
assert(secondaries.includes(shouldBeSecondary))
|
|
364
|
+
|
|
365
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
366
|
+
assert(returnedHealthyServices.size === 2)
|
|
367
|
+
const healthyServices = [shouldBePrimary, shouldBeSecondary]
|
|
368
|
+
healthyServices.map((service) =>
|
|
369
|
+
assert(returnedHealthyServices.has(service))
|
|
370
|
+
)
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
it('filters out nodes if over 95% of storage is used', async () => {
|
|
374
|
+
const shouldBePrimary = 'https://primary.audius.co'
|
|
375
|
+
nock(shouldBePrimary)
|
|
376
|
+
.get('/health_check/verbose')
|
|
377
|
+
.reply(200, {
|
|
378
|
+
data: {
|
|
379
|
+
...defaultHealthCheckData,
|
|
380
|
+
storagePathUsed: 30,
|
|
381
|
+
storagePathSize: 100
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
const shouldBeSecondary1 = 'https://secondary1.audius.co'
|
|
386
|
+
nock(shouldBeSecondary1)
|
|
387
|
+
.get('/health_check/verbose')
|
|
388
|
+
.reply(200, {
|
|
389
|
+
data: {
|
|
390
|
+
...defaultHealthCheckData,
|
|
391
|
+
version: '1.2.1',
|
|
392
|
+
storagePathUsed: 30,
|
|
393
|
+
storagePathSize: 100
|
|
394
|
+
}
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
const shouldBeSecondary2 = 'https://secondary2.audius.co'
|
|
398
|
+
nock(shouldBeSecondary2)
|
|
399
|
+
.get('/health_check/verbose')
|
|
400
|
+
.reply(200, {
|
|
401
|
+
data: {
|
|
402
|
+
...defaultHealthCheckData,
|
|
403
|
+
version: '1.2.0',
|
|
404
|
+
storagePathUsed: 30,
|
|
405
|
+
storagePathSize: 100
|
|
406
|
+
}
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
const used95PercentStorage = 'https://used95PercentStorage.audius.co'
|
|
410
|
+
nock(used95PercentStorage)
|
|
411
|
+
.get('/health_check/verbose')
|
|
412
|
+
.reply(200, {
|
|
413
|
+
data: {
|
|
414
|
+
...defaultHealthCheckData,
|
|
415
|
+
storagePathUsed: 95.354,
|
|
416
|
+
storagePathSize: 100
|
|
417
|
+
}
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
const used99PercentStorage = 'https://used99PercentStorage.audius.co'
|
|
421
|
+
nock(used99PercentStorage)
|
|
422
|
+
.get('/health_check/verbose')
|
|
423
|
+
.reply(200, {
|
|
424
|
+
data: {
|
|
425
|
+
...defaultHealthCheckData,
|
|
426
|
+
storagePathUsed: 99,
|
|
427
|
+
storagePathSize: 100
|
|
428
|
+
}
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
const cns = new CreatorNodeSelection({
|
|
432
|
+
creatorNode: mockCreatorNode,
|
|
433
|
+
numberOfNodes: 3,
|
|
434
|
+
ethContracts: mockEthContracts(
|
|
435
|
+
[
|
|
436
|
+
shouldBePrimary,
|
|
437
|
+
shouldBeSecondary1,
|
|
438
|
+
shouldBeSecondary2,
|
|
439
|
+
used95PercentStorage,
|
|
440
|
+
used99PercentStorage
|
|
441
|
+
],
|
|
442
|
+
'1.2.3'
|
|
443
|
+
),
|
|
444
|
+
whitelist: null,
|
|
445
|
+
blacklist: null
|
|
446
|
+
})
|
|
447
|
+
assert(cns.maxStorageUsedPercent === 95)
|
|
448
|
+
|
|
449
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
450
|
+
|
|
451
|
+
assert(cns.maxStorageUsedPercent === 95)
|
|
452
|
+
assert(primary === shouldBePrimary)
|
|
453
|
+
assert(secondaries.length === 2)
|
|
454
|
+
assert(secondaries.includes(shouldBeSecondary1))
|
|
455
|
+
assert(secondaries.includes(shouldBeSecondary2))
|
|
456
|
+
|
|
457
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
458
|
+
assert(returnedHealthyServices.size === 3)
|
|
459
|
+
const healthyServices = [
|
|
460
|
+
shouldBePrimary,
|
|
461
|
+
shouldBeSecondary1,
|
|
462
|
+
shouldBeSecondary2
|
|
463
|
+
]
|
|
464
|
+
healthyServices.map((service) =>
|
|
465
|
+
assert(returnedHealthyServices.has(service))
|
|
466
|
+
)
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
it('overrides with health check resp `maxStorageUsedPercent` even if it is passed into constructor', async () => {
|
|
470
|
+
const shouldBePrimary = 'https://primary.audius.co'
|
|
471
|
+
nock(shouldBePrimary)
|
|
472
|
+
.get('/health_check/verbose')
|
|
473
|
+
.reply(200, {
|
|
474
|
+
data: {
|
|
475
|
+
...defaultHealthCheckData,
|
|
476
|
+
storagePathUsed: 30,
|
|
477
|
+
storagePathSize: 100
|
|
478
|
+
}
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
const shouldBeSecondary1 = 'https://secondary1.audius.co'
|
|
482
|
+
nock(shouldBeSecondary1)
|
|
483
|
+
.get('/health_check/verbose')
|
|
484
|
+
.reply(200, {
|
|
485
|
+
data: {
|
|
486
|
+
...defaultHealthCheckData,
|
|
487
|
+
version: '1.2.2',
|
|
488
|
+
storagePathUsed: 30,
|
|
489
|
+
storagePathSize: 100
|
|
490
|
+
}
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
const shouldBeSecondary2 = 'https://secondary2.audius.co'
|
|
494
|
+
nock(shouldBeSecondary2)
|
|
495
|
+
.get('/health_check/verbose')
|
|
496
|
+
.reply(200, {
|
|
497
|
+
data: {
|
|
498
|
+
...defaultHealthCheckData,
|
|
499
|
+
version: '1.2.1',
|
|
500
|
+
storagePathUsed: 30,
|
|
501
|
+
storagePathSize: 100
|
|
502
|
+
}
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
const used50PercentStorage = 'https://used95PercentStorage.audius.co'
|
|
506
|
+
nock(used50PercentStorage)
|
|
507
|
+
.get('/health_check/verbose')
|
|
508
|
+
.reply(200, {
|
|
509
|
+
data: {
|
|
510
|
+
...defaultHealthCheckData,
|
|
511
|
+
version: '1.2.0',
|
|
512
|
+
storagePathUsed: 50,
|
|
513
|
+
storagePathSize: 100
|
|
514
|
+
}
|
|
515
|
+
})
|
|
516
|
+
|
|
517
|
+
const used70PercentStorage = 'https://used70PercentStorage.audius.co'
|
|
518
|
+
nock(used70PercentStorage)
|
|
519
|
+
.get('/health_check/verbose')
|
|
520
|
+
.reply(200, {
|
|
521
|
+
data: {
|
|
522
|
+
...defaultHealthCheckData,
|
|
523
|
+
version: '1.2.0',
|
|
524
|
+
storagePathUsed: 70.546,
|
|
525
|
+
storagePathSize: 100
|
|
526
|
+
}
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
const cns = new CreatorNodeSelection({
|
|
530
|
+
creatorNode: mockCreatorNode,
|
|
531
|
+
numberOfNodes: 3,
|
|
532
|
+
ethContracts: mockEthContracts(
|
|
533
|
+
[
|
|
534
|
+
shouldBePrimary,
|
|
535
|
+
shouldBeSecondary1,
|
|
536
|
+
shouldBeSecondary2,
|
|
537
|
+
used50PercentStorage,
|
|
538
|
+
used70PercentStorage
|
|
539
|
+
],
|
|
540
|
+
'1.2.3'
|
|
541
|
+
),
|
|
542
|
+
whitelist: null,
|
|
543
|
+
blacklist: null,
|
|
544
|
+
maxStorageUsedPercent: 50
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
assert(cns.maxStorageUsedPercent === 50)
|
|
548
|
+
|
|
549
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
550
|
+
|
|
551
|
+
// @ts-expect-error maxStorageUsedPercent actually does change after another select call
|
|
552
|
+
assert(cns.maxStorageUsedPercent === 95)
|
|
553
|
+
|
|
554
|
+
assert(primary === shouldBePrimary)
|
|
555
|
+
assert(secondaries.length === 2)
|
|
556
|
+
assert(secondaries.includes(shouldBeSecondary1))
|
|
557
|
+
assert(secondaries.includes(shouldBeSecondary2))
|
|
558
|
+
|
|
559
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
560
|
+
assert(returnedHealthyServices.size === 5)
|
|
561
|
+
const healthyServices = [
|
|
562
|
+
shouldBePrimary,
|
|
563
|
+
shouldBeSecondary1,
|
|
564
|
+
shouldBeSecondary2
|
|
565
|
+
]
|
|
566
|
+
healthyServices.map((service) =>
|
|
567
|
+
assert(returnedHealthyServices.has(service))
|
|
568
|
+
)
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
it('allows custom maxStorageUsedPercent as constructor param if `maxStorageUsedPercent` is not found in health check resp', async () => {
|
|
572
|
+
const healthCheckResponseWithNoMaxStorageUsedPercent: HealthCheckData = {
|
|
573
|
+
...defaultHealthCheckData
|
|
574
|
+
}
|
|
575
|
+
delete healthCheckResponseWithNoMaxStorageUsedPercent.maxStorageUsedPercent
|
|
576
|
+
|
|
577
|
+
const shouldBePrimary = 'https://primary.audius.co'
|
|
578
|
+
nock(shouldBePrimary)
|
|
579
|
+
.get('/health_check/verbose')
|
|
580
|
+
.reply(200, {
|
|
581
|
+
data: {
|
|
582
|
+
...healthCheckResponseWithNoMaxStorageUsedPercent,
|
|
583
|
+
storagePathUsed: 30,
|
|
584
|
+
storagePathSize: 100
|
|
585
|
+
}
|
|
586
|
+
})
|
|
587
|
+
|
|
588
|
+
const shouldBeSecondary1 = 'https://secondary1.audius.co'
|
|
589
|
+
nock(shouldBeSecondary1)
|
|
590
|
+
.get('/health_check/verbose')
|
|
591
|
+
.reply(200, {
|
|
592
|
+
data: {
|
|
593
|
+
...healthCheckResponseWithNoMaxStorageUsedPercent,
|
|
594
|
+
version: '1.2.1',
|
|
595
|
+
storagePathUsed: 30,
|
|
596
|
+
storagePathSize: 100
|
|
597
|
+
}
|
|
598
|
+
})
|
|
599
|
+
|
|
600
|
+
const shouldBeSecondary2 = 'https://secondary2.audius.co'
|
|
601
|
+
nock(shouldBeSecondary2)
|
|
602
|
+
.get('/health_check/verbose')
|
|
603
|
+
.reply(200, {
|
|
604
|
+
data: {
|
|
605
|
+
...healthCheckResponseWithNoMaxStorageUsedPercent,
|
|
606
|
+
version: '1.2.0',
|
|
607
|
+
storagePathUsed: 30,
|
|
608
|
+
storagePathSize: 100
|
|
609
|
+
}
|
|
610
|
+
})
|
|
611
|
+
|
|
612
|
+
const used50PercentStorage = 'https://used95PercentStorage.audius.co'
|
|
613
|
+
nock(used50PercentStorage)
|
|
614
|
+
.get('/health_check/verbose')
|
|
615
|
+
.reply(200, {
|
|
616
|
+
data: {
|
|
617
|
+
...healthCheckResponseWithNoMaxStorageUsedPercent,
|
|
618
|
+
storagePathUsed: 50,
|
|
619
|
+
storagePathSize: 100
|
|
620
|
+
}
|
|
621
|
+
})
|
|
622
|
+
|
|
623
|
+
const used70PercentStorage = 'https://used70PercentStorage.audius.co'
|
|
624
|
+
nock(used70PercentStorage)
|
|
625
|
+
.get('/health_check/verbose')
|
|
626
|
+
.reply(200, {
|
|
627
|
+
data: {
|
|
628
|
+
...healthCheckResponseWithNoMaxStorageUsedPercent,
|
|
629
|
+
storagePathUsed: 70.546,
|
|
630
|
+
storagePathSize: 100
|
|
631
|
+
}
|
|
632
|
+
})
|
|
633
|
+
|
|
634
|
+
const cns = new CreatorNodeSelection({
|
|
635
|
+
creatorNode: mockCreatorNode,
|
|
636
|
+
numberOfNodes: 3,
|
|
637
|
+
ethContracts: mockEthContracts(
|
|
638
|
+
[
|
|
639
|
+
shouldBePrimary,
|
|
640
|
+
shouldBeSecondary1,
|
|
641
|
+
shouldBeSecondary2,
|
|
642
|
+
used50PercentStorage,
|
|
643
|
+
used70PercentStorage
|
|
644
|
+
],
|
|
645
|
+
'1.2.3'
|
|
646
|
+
),
|
|
647
|
+
whitelist: null,
|
|
648
|
+
blacklist: null,
|
|
649
|
+
maxStorageUsedPercent: 50
|
|
650
|
+
})
|
|
651
|
+
|
|
652
|
+
assert(cns.maxStorageUsedPercent === 50)
|
|
653
|
+
|
|
654
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
655
|
+
|
|
656
|
+
assert(cns.maxStorageUsedPercent === 50)
|
|
657
|
+
assert(primary === shouldBePrimary)
|
|
658
|
+
assert(secondaries.length === 2)
|
|
659
|
+
assert(secondaries.includes(shouldBeSecondary1))
|
|
660
|
+
assert(secondaries.includes(shouldBeSecondary2))
|
|
661
|
+
|
|
662
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
663
|
+
assert(returnedHealthyServices.size === 3)
|
|
664
|
+
const healthyServices = [
|
|
665
|
+
shouldBePrimary,
|
|
666
|
+
shouldBeSecondary1,
|
|
667
|
+
shouldBeSecondary2
|
|
668
|
+
]
|
|
669
|
+
healthyServices.map((service) =>
|
|
670
|
+
assert(returnedHealthyServices.has(service))
|
|
671
|
+
)
|
|
672
|
+
})
|
|
673
|
+
|
|
674
|
+
it('allows Content Node to be selected if storage information is unavailable (undefined or null)', async () => {
|
|
675
|
+
const healthCheckDataWithNoStorageInfo: HealthCheckData = {
|
|
676
|
+
...defaultHealthCheckData
|
|
677
|
+
}
|
|
678
|
+
delete healthCheckDataWithNoStorageInfo.storagePathSize
|
|
679
|
+
healthCheckDataWithNoStorageInfo.storagePathUsed = null
|
|
680
|
+
|
|
681
|
+
const shouldBePrimary =
|
|
682
|
+
'https://missingStoragePathUsedAndStoragePathSize.audius.co'
|
|
683
|
+
nock(shouldBePrimary)
|
|
684
|
+
.get('/health_check/verbose')
|
|
685
|
+
.reply(200, { data: healthCheckDataWithNoStorageInfo })
|
|
686
|
+
|
|
687
|
+
const shouldBeSecondary1 = 'https://missingStoragePathUsed.audius.co'
|
|
688
|
+
nock(shouldBeSecondary1)
|
|
689
|
+
.get('/health_check/verbose')
|
|
690
|
+
.reply(200, {
|
|
691
|
+
data: {
|
|
692
|
+
...healthCheckDataWithNoStorageInfo,
|
|
693
|
+
version: '1.2.1',
|
|
694
|
+
storagePathSize: 100
|
|
695
|
+
}
|
|
696
|
+
})
|
|
697
|
+
|
|
698
|
+
const shouldBeSecondary2 = 'https://missingStoragePathSize.audius.co'
|
|
699
|
+
nock(shouldBeSecondary2)
|
|
700
|
+
.get('/health_check/verbose')
|
|
701
|
+
.reply(200, {
|
|
702
|
+
data: {
|
|
703
|
+
...healthCheckDataWithNoStorageInfo,
|
|
704
|
+
version: '1.2.0',
|
|
705
|
+
storagePathUsed: 30
|
|
706
|
+
}
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
const cns = new CreatorNodeSelection({
|
|
710
|
+
creatorNode: mockCreatorNode,
|
|
711
|
+
numberOfNodes: 3,
|
|
712
|
+
ethContracts: mockEthContracts(
|
|
713
|
+
[shouldBePrimary, shouldBeSecondary1, shouldBeSecondary2],
|
|
714
|
+
'1.2.3'
|
|
715
|
+
),
|
|
716
|
+
whitelist: null,
|
|
717
|
+
blacklist: null,
|
|
718
|
+
maxStorageUsedPercent: 50
|
|
719
|
+
})
|
|
720
|
+
|
|
721
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
722
|
+
|
|
723
|
+
assert(primary === shouldBePrimary)
|
|
724
|
+
assert(secondaries.length === 2)
|
|
725
|
+
assert(secondaries.includes(shouldBeSecondary1))
|
|
726
|
+
assert(secondaries.includes(shouldBeSecondary2))
|
|
727
|
+
|
|
728
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
729
|
+
assert(returnedHealthyServices.size === 3)
|
|
730
|
+
const healthyServices = [
|
|
731
|
+
shouldBePrimary,
|
|
732
|
+
shouldBeSecondary1,
|
|
733
|
+
shouldBeSecondary2
|
|
734
|
+
]
|
|
735
|
+
healthyServices.map((service) =>
|
|
736
|
+
assert(returnedHealthyServices.has(service))
|
|
737
|
+
)
|
|
738
|
+
})
|
|
739
|
+
|
|
740
|
+
it('does not always pick the same one with equivalency delta', async () => {
|
|
741
|
+
// Run this test a few times and make sure we eventually get something
|
|
742
|
+
// different
|
|
743
|
+
const primaries: string[] = []
|
|
744
|
+
for (let i = 0; i < 20; ++i) {
|
|
745
|
+
const one = 'https://one.audius.co'
|
|
746
|
+
nock(one)
|
|
747
|
+
.get('/health_check/verbose')
|
|
748
|
+
.delay(100)
|
|
749
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
750
|
+
|
|
751
|
+
const two = 'https://two.audius.co'
|
|
752
|
+
nock(two)
|
|
753
|
+
.get('/health_check/verbose')
|
|
754
|
+
.delay(200)
|
|
755
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
756
|
+
|
|
757
|
+
const cns = new CreatorNodeSelection({
|
|
758
|
+
creatorNode: mockCreatorNode,
|
|
759
|
+
numberOfNodes: 2,
|
|
760
|
+
ethContracts: mockEthContracts([one, two], '1.2.3'),
|
|
761
|
+
whitelist: null,
|
|
762
|
+
blacklist: null,
|
|
763
|
+
// Even though one and two take 100ms and 200ms respectively,
|
|
764
|
+
// we consider 200ms equivalent, so they should be randomly picked
|
|
765
|
+
equivalencyDelta: 200
|
|
766
|
+
})
|
|
767
|
+
|
|
768
|
+
const { primary } = await cns.select(true, false)
|
|
769
|
+
primaries.push(primary)
|
|
770
|
+
}
|
|
771
|
+
// Make sure there is some variance
|
|
772
|
+
assert(!primaries.every((val) => val === primaries[0]))
|
|
773
|
+
}).timeout(10000)
|
|
774
|
+
|
|
775
|
+
describe('Test preferHigherPatchForPrimary and preferHigherPatchForSecondaries', () => {
|
|
776
|
+
it('Selects highest version nodes when preferHigherPatchForPrimary and preferHigherPatchForSecondaries are enabled', async () => {
|
|
777
|
+
const aheadPatch = 'https://aheadPatch.audius.co'
|
|
778
|
+
nock(aheadPatch)
|
|
779
|
+
.get('/health_check/verbose')
|
|
780
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.6' } })
|
|
781
|
+
|
|
782
|
+
const aheadPatchButSlow = 'https://aheadPatchButSlow.audius.co'
|
|
783
|
+
nock(aheadPatchButSlow)
|
|
784
|
+
.get('/health_check/verbose')
|
|
785
|
+
.delay(100)
|
|
786
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.6' } })
|
|
787
|
+
|
|
788
|
+
const healthy = 'https://healthy.audius.co'
|
|
789
|
+
nock(healthy)
|
|
790
|
+
.get('/health_check/verbose')
|
|
791
|
+
.reply(200, { data: defaultHealthCheckData })
|
|
792
|
+
|
|
793
|
+
const cns = new CreatorNodeSelection({
|
|
794
|
+
creatorNode: mockCreatorNode,
|
|
795
|
+
numberOfNodes: 3,
|
|
796
|
+
ethContracts: mockEthContracts(
|
|
797
|
+
[healthy, aheadPatchButSlow, aheadPatch],
|
|
798
|
+
'1.2.3'
|
|
799
|
+
),
|
|
800
|
+
whitelist: null,
|
|
801
|
+
blacklist: null
|
|
802
|
+
// preferHigherPatchForPrimary and preferHigherPatchForSecondaries true by default
|
|
803
|
+
})
|
|
804
|
+
|
|
805
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
806
|
+
|
|
807
|
+
assert(primary === aheadPatch)
|
|
808
|
+
assert(secondaries.length === 2)
|
|
809
|
+
assert(secondaries[0] === aheadPatchButSlow)
|
|
810
|
+
assert(secondaries[1] === healthy)
|
|
811
|
+
|
|
812
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
813
|
+
assert(returnedHealthyServices.size === 3)
|
|
814
|
+
const healthyServices = [aheadPatch, aheadPatchButSlow, healthy]
|
|
815
|
+
healthyServices.map((service) =>
|
|
816
|
+
assert(returnedHealthyServices.has(service))
|
|
817
|
+
)
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
it('Selects highest version node for primary with preferHigherPatchForPrimary enabled and fastest node for secondaries with preferHigherPatchForSecondaries disabled', async () => {
|
|
821
|
+
const aheadPatch = 'https://aheadPatch.audius.co'
|
|
822
|
+
nock(aheadPatch)
|
|
823
|
+
.get('/health_check/verbose')
|
|
824
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.6' } })
|
|
825
|
+
|
|
826
|
+
const aheadPatchButSlow = 'https://aheadPatchButSlow.audius.co'
|
|
827
|
+
nock(aheadPatchButSlow)
|
|
828
|
+
.get('/health_check/verbose')
|
|
829
|
+
.delay(100)
|
|
830
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.6' } })
|
|
831
|
+
|
|
832
|
+
const healthyButBehindPatch = 'https://healthyButBehindPatch.audius.co'
|
|
833
|
+
nock(healthyButBehindPatch)
|
|
834
|
+
.get('/health_check/verbose')
|
|
835
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.0' } })
|
|
836
|
+
|
|
837
|
+
const healthy = 'https://healthy.audius.co'
|
|
838
|
+
nock(healthy)
|
|
839
|
+
.get('/health_check/verbose')
|
|
840
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.3' } })
|
|
841
|
+
|
|
842
|
+
const cns = new CreatorNodeSelection({
|
|
843
|
+
creatorNode: mockCreatorNode,
|
|
844
|
+
numberOfNodes: 3,
|
|
845
|
+
ethContracts: mockEthContracts(
|
|
846
|
+
[healthy, healthyButBehindPatch, aheadPatchButSlow, aheadPatch],
|
|
847
|
+
'1.2.3'
|
|
848
|
+
),
|
|
849
|
+
whitelist: null,
|
|
850
|
+
blacklist: null,
|
|
851
|
+
// preferHigherPatchForPrimary defaults to true
|
|
852
|
+
preferHigherPatchForSecondaries: false
|
|
853
|
+
})
|
|
854
|
+
|
|
855
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
856
|
+
|
|
857
|
+
assert(primary === aheadPatch)
|
|
858
|
+
assert(secondaries.length === 2)
|
|
859
|
+
assert(secondaries[0] === healthy)
|
|
860
|
+
assert(secondaries[1] === aheadPatchButSlow)
|
|
861
|
+
|
|
862
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
863
|
+
assert(returnedHealthyServices.size === 4)
|
|
864
|
+
const healthyServices = [
|
|
865
|
+
aheadPatch,
|
|
866
|
+
aheadPatchButSlow,
|
|
867
|
+
healthy,
|
|
868
|
+
healthyButBehindPatch
|
|
869
|
+
]
|
|
870
|
+
healthyServices.map((service) =>
|
|
871
|
+
assert(returnedHealthyServices.has(service))
|
|
872
|
+
)
|
|
873
|
+
})
|
|
874
|
+
|
|
875
|
+
it('Selects fastest node for primary with preferHigherPatchForPrimary disabled and highest version nodes for secondaries with preferHigherPatchForSecondaries enabled', async () => {
|
|
876
|
+
const higherPatchAndSlow = 'https://higherPatchAndSlow.audius.co'
|
|
877
|
+
nock(higherPatchAndSlow)
|
|
878
|
+
.get('/health_check/verbose')
|
|
879
|
+
.delay(50)
|
|
880
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.4' } })
|
|
881
|
+
|
|
882
|
+
const highestPatchAndSlowest = 'https://highestPatchAndSlowest.audius.co'
|
|
883
|
+
nock(highestPatchAndSlowest)
|
|
884
|
+
.get('/health_check/verbose')
|
|
885
|
+
.delay(100)
|
|
886
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.5' } })
|
|
887
|
+
|
|
888
|
+
const healthyAndBehindPatch = 'https://healthyAndBehindPatch.audius.co'
|
|
889
|
+
nock(healthyAndBehindPatch)
|
|
890
|
+
.get('/health_check/verbose')
|
|
891
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.2' } })
|
|
892
|
+
|
|
893
|
+
const healthy = 'https://healthy.audius.co'
|
|
894
|
+
nock(healthy)
|
|
895
|
+
.get('/health_check/verbose')
|
|
896
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.3' } })
|
|
897
|
+
|
|
898
|
+
const cns = new CreatorNodeSelection({
|
|
899
|
+
creatorNode: mockCreatorNode,
|
|
900
|
+
numberOfNodes: 3,
|
|
901
|
+
ethContracts: mockEthContracts(
|
|
902
|
+
[
|
|
903
|
+
healthy,
|
|
904
|
+
healthyAndBehindPatch,
|
|
905
|
+
higherPatchAndSlow,
|
|
906
|
+
highestPatchAndSlowest
|
|
907
|
+
],
|
|
908
|
+
'1.2.3'
|
|
909
|
+
),
|
|
910
|
+
whitelist: null,
|
|
911
|
+
blacklist: null,
|
|
912
|
+
preferHigherPatchForPrimary: false
|
|
913
|
+
// preferHigherPatchForSecondaries defaults to true
|
|
914
|
+
})
|
|
915
|
+
|
|
916
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
917
|
+
|
|
918
|
+
assert(primary === healthy)
|
|
919
|
+
assert(secondaries.length === 2)
|
|
920
|
+
assert(secondaries[0] === highestPatchAndSlowest)
|
|
921
|
+
assert(secondaries[1] === higherPatchAndSlow)
|
|
922
|
+
|
|
923
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
924
|
+
assert(returnedHealthyServices.size === 4)
|
|
925
|
+
const healthyServices = [
|
|
926
|
+
highestPatchAndSlowest,
|
|
927
|
+
higherPatchAndSlow,
|
|
928
|
+
healthy,
|
|
929
|
+
healthyAndBehindPatch
|
|
930
|
+
]
|
|
931
|
+
healthyServices.map((service) =>
|
|
932
|
+
assert(returnedHealthyServices.has(service))
|
|
933
|
+
)
|
|
934
|
+
})
|
|
935
|
+
|
|
936
|
+
it('Selects fastest nodes when preferHigherPatchForPrimary and preferHigherPatchForSecondaries are disabled', async () => {
|
|
937
|
+
const higherPatchAndSlow = 'https://higherPatchAndSlow.audius.co'
|
|
938
|
+
nock(higherPatchAndSlow)
|
|
939
|
+
.get('/health_check/verbose')
|
|
940
|
+
.delay(50)
|
|
941
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.4' } })
|
|
942
|
+
|
|
943
|
+
const highestPatchAndSlowest = 'https://highestPatchAndSlowest.audius.co'
|
|
944
|
+
nock(highestPatchAndSlowest)
|
|
945
|
+
.get('/health_check/verbose')
|
|
946
|
+
.delay(100)
|
|
947
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.5' } })
|
|
948
|
+
|
|
949
|
+
const healthyAndBehindPatch = 'https://healthyAndBehindPatch.audius.co'
|
|
950
|
+
nock(healthyAndBehindPatch)
|
|
951
|
+
.get('/health_check/verbose')
|
|
952
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.2' } })
|
|
953
|
+
|
|
954
|
+
const healthy = 'https://healthy.audius.co'
|
|
955
|
+
nock(healthy)
|
|
956
|
+
.get('/health_check/verbose')
|
|
957
|
+
.reply(200, { data: { ...defaultHealthCheckData, version: '1.2.3' } })
|
|
958
|
+
|
|
959
|
+
const cns = new CreatorNodeSelection({
|
|
960
|
+
creatorNode: mockCreatorNode,
|
|
961
|
+
numberOfNodes: 3,
|
|
962
|
+
ethContracts: mockEthContracts(
|
|
963
|
+
[
|
|
964
|
+
healthy,
|
|
965
|
+
healthyAndBehindPatch,
|
|
966
|
+
higherPatchAndSlow,
|
|
967
|
+
highestPatchAndSlowest
|
|
968
|
+
],
|
|
969
|
+
'1.2.3'
|
|
970
|
+
),
|
|
971
|
+
whitelist: null,
|
|
972
|
+
blacklist: null,
|
|
973
|
+
preferHigherPatchForPrimary: false,
|
|
974
|
+
preferHigherPatchForSecondaries: false
|
|
975
|
+
})
|
|
976
|
+
|
|
977
|
+
const { primary, secondaries, services } = await cns.select(true, false)
|
|
978
|
+
|
|
979
|
+
assert(primary === healthy)
|
|
980
|
+
assert(secondaries.length === 2)
|
|
981
|
+
assert(secondaries[0] === higherPatchAndSlow)
|
|
982
|
+
assert(secondaries[1] === highestPatchAndSlowest)
|
|
983
|
+
|
|
984
|
+
const returnedHealthyServices = new Set(Object.keys(services))
|
|
985
|
+
assert(returnedHealthyServices.size === 4)
|
|
986
|
+
const healthyServices = [
|
|
987
|
+
highestPatchAndSlowest,
|
|
988
|
+
higherPatchAndSlow,
|
|
989
|
+
healthy,
|
|
990
|
+
healthyAndBehindPatch
|
|
991
|
+
]
|
|
992
|
+
healthyServices.map((service) =>
|
|
993
|
+
assert(returnedHealthyServices.has(service))
|
|
994
|
+
)
|
|
995
|
+
})
|
|
996
|
+
})
|
|
997
|
+
})
|