diff --git a/crates/iota-graphql-e2e-tests/README.md b/crates/iota-graphql-e2e-tests/README.md index 4e0c24eee8a..a0001d1c739 100644 --- a/crates/iota-graphql-e2e-tests/README.md +++ b/crates/iota-graphql-e2e-tests/README.md @@ -1,6 +1,14 @@ End-to-end tests for GraphQL service, built on top of the transactional test runner. +# Testing through the transactional test runner + +This crate specifically tests GraphQL queries in an e2e manner against the Indexer database. +The tests are executed through the [transactional test runner](../iota-transactional-test-runner), mediated by the [test.rs](tests/tests.rs) module. + +Each test is defined in a `.move` file, which contains various statements that are executed in a transactional manner. +In addition to the `.move` file, there is a corresponding `.exp` file that contains the expected output of the transactional test. + # Local Set-up These tests require a running instance of the `postgres` service, with a diff --git a/crates/iota-graphql-e2e-tests/coverage/mutation/executeTransactionBlock.md b/crates/iota-graphql-e2e-tests/coverage/mutation/executeTransactionBlock.md new file mode 100644 index 00000000000..708215005ff --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/mutation/executeTransactionBlock.md @@ -0,0 +1,118 @@ +Query: `executeTransactionBlock` + +```graphql +mutation { + executeTransactionBlock(txBytes: $tx, signatures: $sigs) { + effects { + transactionBlock { + digest + } + status + lamportVersion + errors + dependencies { + edges { + node { + digest + bcs + } + } + } + gasEffects { + __typename + gasObject { + digest + storageRebate + bcs + } + gasSummary { + computationCost + computationCostBurned + storageCost + storageRebate + nonRefundableStorageFee + } + } + unchangedSharedObjects { + edges { + node { + __typename + } + } + } + objectChanges { + edges { + node { + idCreated + idDeleted + } + } + } + balanceChanges { + edges { + node { + amount + } + } + } + events { + edges { + node { + timestamp + } + } + } + timestamp + epoch { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + checkpoint { + previousCheckpointDigest + networkTotalTransactions + } + bcs + } + errors + } +} +``` + +tested by [crates/iota-graphql-rpc/tests/e2e_tests.rs](../../../iota-graphql-rpc/tests/e2e_tests.rs): + +```graphql +{ + executeTransactionBlock(txBytes: $tx, signatures: $sigs) { + effects { + transactionBlock { + digest + } + } + errors + } +} +``` + +tested by [crates/iota-graphql-rpc/tests/e2e_tests.rs](../../../iota-graphql-rpc/tests/e2e_tests.rs): + +```graphql +mutation { + executeTransactionBlock(txBytes: "{}", signatures: "{}") { + effects { + status + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/address.md b/crates/iota-graphql-e2e-tests/coverage/query/address.md new file mode 100644 index 00000000000..7cc2ff3aa0e --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/address.md @@ -0,0 +1,191 @@ +Query: `address` + +```graphql +{ + address(address: "0x1") { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/owned_objects.move](../../../iota-graphql-e2e-tests/tests/call/owned_objects.move): + +```graphql +//# run-graphql +{ + address(address: "0x42") { + objects { + edges { + node { + owner { + __typename + ... on AddressOwner { + owner { + address + } + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move](../../../iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move): + +```graphql +//# run-graphql +{ + address(address: "@{C}") { + transactionBlocks(last: 1) { + nodes { + effects { + balanceChanges { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + edges { + node { + amount + } + cursor + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/coins.move](../../../iota-graphql-e2e-tests/tests/consistency/coins.move): + +```graphql +//# run-graphql +{ + queryCoins: coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + owner { + ... on AddressOwner { + owner { + address + coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + contents { + json + } + } + } + } + } + } + } + contents { + json + } + } + } + } + addressCoinsA: address(address: "@{A}") { + coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + contents { + json + } + } + } + } + } + addressCoinsB: address(address: "@{B}") { + coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + contents { + json + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.move](../../../iota-graphql-e2e-tests/tests/consistency/staked_iota.move): + +```graphql +//# run-graphql +{ + address(address: "@{C}") { + stakedIotas { + edges { + cursor + node { + principal + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/availableRange.md b/crates/iota-graphql-e2e-tests/coverage/query/availableRange.md new file mode 100644 index 00000000000..5b76a865112 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/availableRange.md @@ -0,0 +1,43 @@ +Query: `availableRange` + +```graphql +{ + availableRange { + first { + digest + } + last { + digest + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/available_range/available_range.move](../../../iota-graphql-e2e-tests/tests/available_range/available_range.move): + +```graphql +//# run-graphql +{ + availableRange { + first { + digest + sequenceNumber + } + last { + digest + sequenceNumber + } + } + + first: checkpoint(id: { sequenceNumber: 0 } ) { + digest + sequenceNumber + } + + last: checkpoint { + digest + sequenceNumber + } +} +``` + diff --git a/crates/iota-graphql-e2e-tests/coverage/query/chainIdentifier.md b/crates/iota-graphql-e2e-tests/coverage/query/chainIdentifier.md new file mode 100644 index 00000000000..9dda9821f3e --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/chainIdentifier.md @@ -0,0 +1,16 @@ +Query: `chainIdentifier` + +```graphql +{ + chainIdentifier +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/epoch/chain_identifier.move](../../../iota-graphql-e2e-tests/tests/epoch/chain_identifier.move): + +```graphql +//# run-graphql +{ +chainIdentifier +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/checkpoint.md b/crates/iota-graphql-e2e-tests/coverage/query/checkpoint.md new file mode 100644 index 00000000000..278b5a5d8fc --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/checkpoint.md @@ -0,0 +1,69 @@ +Query: `checkpoint` + +```graphql +{ + checkpoint(id: null) { + digest + sequenceNumber + timestamp + validatorSignatures + previousCheckpointDigest + networkTotalTransactions + rollingGasSummary { + computationCost + computationCostBurned + storageCost + storageRebate + nonRefundableStorageFee + } + epoch { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/simple.move](../../../iota-graphql-e2e-tests/tests/call/simple.move): + +```graphql +//# run-graphql +{ + checkpoint { + sequenceNumber + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transactions/at_checkpoint.move](../../../iota-graphql-e2e-tests/tests/transactions/at_checkpoint.move): + +```graphql +//# run-graphql +{ # Via a checkpoint query + c0: checkpoint(id: { sequenceNumber: 0 }) { transactionBlocks { nodes { ...Tx } } } + c1: checkpoint(id: { sequenceNumber: 1 }) { transactionBlocks { nodes { ...Tx } } } + c2: checkpoint(id: { sequenceNumber: 2 }) { transactionBlocks { nodes { ...Tx } } } + c3: checkpoint(id: { sequenceNumber: 3 }) { transactionBlocks { nodes { ...Tx } } } + c4: checkpoint(id: { sequenceNumber: 4 }) { transactionBlocks { nodes { ...Tx } } } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/checkpoints.md b/crates/iota-graphql-e2e-tests/coverage/query/checkpoints.md new file mode 100644 index 00000000000..35e1d963e78 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/checkpoints.md @@ -0,0 +1,96 @@ +Query: `checkpoints` + +```graphql +{ + checkpoints(after: null, first: null, last: null, before: null) { + edges { + node { + digest + sequenceNumber + timestamp + validatorSignatures + previousCheckpointDigest + networkTotalTransactions + rollingGasSummary { + computationCost + computationCostBurned + storageCost + storageRebate + nonRefundableStorageFee + } + epoch { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/limits/output_node_estimation.move](../../../iota-graphql-e2e-tests/tests/limits/output_node_estimation.move): + +```graphql +//# run-graphql --show-usage +# build on previous example with nested connection +{ + checkpoints { # 1 + nodes { # 1 + transactionBlocks { # 20 + edges { # 20 + txns: node { # 400 + digest # 400 + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move](../../../iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move): + +```graphql +{ + checkpoints { + nodes { + sequenceNumber + transactionBlocks(filter: { signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects(last: 1) { + edges { + cursor + } + } + } + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/coinMetadata.md b/crates/iota-graphql-e2e-tests/coverage/query/coinMetadata.md new file mode 100644 index 00000000000..40324539394 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/coinMetadata.md @@ -0,0 +1,45 @@ +Query: `coinMetadata` + +```graphql +{ + coinMetadata(coinType: "@{test}::fake::FAKE") { + digest + storageRebate + bcs + decimals + name + symbol + description + iconUrl + supply + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/coin_metadata.move](../../../iota-graphql-e2e-tests/tests/call/coin_metadata.move): + +```graphql +//# run-graphql +{ + coinMetadata(coinType: "@{test}::fake::FAKE") { + decimals + name + symbol + description + iconUrl + supply + } +} + +//# run-graphql +{ + coinMetadata(coinType: "@{test}::fake::FAKE") { + decimals + name + symbol + description + iconUrl + supply + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/coins.md b/crates/iota-graphql-e2e-tests/coverage/query/coins.md new file mode 100644 index 00000000000..c1034e2a691 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/coins.md @@ -0,0 +1,156 @@ +Query: `type` + +```graphql +{ + coins(first: null, last: null, after: null) { + edges { + node { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + contents { + __typename + data + } + display { + value + error + } + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicFields { + edges { + node { + __typename + } + } + } + coinBalance + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/objects/coin.move](../../../iota-graphql-e2e-tests/tests/objects/coin.move): + +```graphql +//# run-graphql +fragment C on Coin { + coinBalance + contents { type { repr } } +} + +{ + iotaCoins: coins { + edges { + cursor + node { ...C } + } + } + + fakeCoins: coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { ...C } + } + } + + address(address: "@{A}") { + coins { + edges { + cursor + node { ...C } + } + } + + allBalances: balances { + edges { + cursor + node { + coinType { repr } + coinObjectCount + totalBalance + } + } + } + + firstBalance: balances(first: 1) { + edges { cursor } + } + + lastBalance: balances(last: 1) { + edges { cursor } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/dryRunTransactionBlock.md b/crates/iota-graphql-e2e-tests/coverage/query/dryRunTransactionBlock.md new file mode 100644 index 00000000000..c02bea1a742 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/dryRunTransactionBlock.md @@ -0,0 +1,90 @@ +Query: `dryRunTransactionBlock` + +```graphql +{ + dryRunTransactionBlock( + txBytes: "AAIAIC3Pg7fIBNN95RZluYu1Ll8icKxoO/oGYoEAfLP0szGAAAjoAwAAAAAAAAICAAEBAQABAQIAAAEAAA==" + txMeta: {} + ) { + transaction { + digest + sender { + address + } + gasInput { + gasSponsor { + address + } + gasPayment { + edges { + node { + digest + storageRebate + bcs + } + } + } + gasPrice + gasBudget + } + } + error + results { + mutatedReferences { + input { + __typename + ... on Input { + ix + } + ... on Result { + cmd + ix + } + } + type { + repr + } + bcs + } + returnValues { + type { + repr + signature + layout + abilities + } + bcs + } + } + } +} +``` + +tested by [crates/iota-graphql-rpc/tests/e2e_tests.rs](../../../iota-graphql-rpc/tests/e2e_tests.rs): + +```graphql +{ + dryRunTransactionBlock(txBytes: $tx, txMeta: {}) { + results { + mutatedReferences { + input { + __typename + } + } + } + transaction { + digest + sender { + address + } + gasInput { + gasSponsor { + address + } + gasPrice + } + } + error + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/epoch.md b/crates/iota-graphql-e2e-tests/coverage/query/epoch.md new file mode 100644 index 00000000000..cd5f8245498 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/epoch.md @@ -0,0 +1,107 @@ +Query: `epoch` + +```graphql +{ + epoch(id: 1) { + epochId + referenceGasPrice + validatorSet { + totalStake + pendingActiveValidatorsId + pendingActiveValidatorsSize + stakingPoolMappingsId + stakingPoolMappingsSize + inactivePoolsId + inactivePoolsSize + validatorCandidatesId + validatorCandidatesSize + } + startTimestamp + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + protocolConfigs { + __typename + } + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + checkpoints { + edges { + node { + previousCheckpointDigest + networkTotalTransactions + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/validator/validator.move](../../../iota-graphql-e2e-tests/tests/validator/validator.move): + +```graphql +{ + epoch(id: 1) { + validatorSet { + activeValidators { + nodes { + name + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move](../../../iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move): + +```graphql +//# run-graphql --cursors {"s":3,"c":4} {"s":7,"c":8} {"s":9,"c":10} +# View checkpoints before the last checkpoint in each epoch, from the perspective of the first +# checkpoint in the next epoch. +{ + checkpoint { + sequenceNumber + } + epoch_0: epoch(id: 0) { + epochId + checkpoints(before: "@{cursor_0}") { + nodes { + sequenceNumber + } + } + } + epoch_1: epoch(id: 1) { + epochId + checkpoints(before: "@{cursor_1}") { + nodes { + sequenceNumber + } + } + } + epoch_2: epoch(id: 2) { + epochId + checkpoints(before: "@{cursor_2}") { + nodes { + sequenceNumber + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/events.md b/crates/iota-graphql-e2e-tests/coverage/query/events.md new file mode 100644 index 00000000000..ea0100eb520 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/events.md @@ -0,0 +1,49 @@ +Query: `events` + +```graphql +{ + events(first: null, last: null, after: null, before: null, filter: null) { + edges { + node { + __typename + data + timestamp + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/event_connection/no_filter.move](../../../iota-graphql-e2e-tests/tests/event_connection/no_filter.move): + +```graphql +//# run-graphql +{ + events { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + nodes { + json + } + } +} + +//# run-graphql --cursors {"tx":2,"e":19,"c":1} +{ + events(after: "@{cursor_0}") { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + nodes { + json + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/latestPackage.md b/crates/iota-graphql-e2e-tests/coverage/query/latestPackage.md new file mode 100644 index 00000000000..f6ccf36ae32 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/latestPackage.md @@ -0,0 +1,232 @@ +Query: `latestPackage` + +```graphql +{ + latestPackage(address: "0x1") { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + packageVersions { + edges { + node { + digest + storageRebate + bcs + moduleBcs + } + } + } + latestPackage { + digest + storageRebate + bcs + moduleBcs + } + module(name: "address") { + bytes + disassembly + } + modules { + edges { + node { + name + package { + digest + storageRebate + bcs + moduleBcs + } + datatype(name: "Char") { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + datatypes { + edges { + node { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + } + } + __typename + fileFormatVersion + bytes + disassembly + } + } + } + linkage { + version + __typename + } + typeOrigins { + __typename + } + moduleBcs + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/packages/versioning.move](../../../iota-graphql-e2e-tests/tests/packages/versioning.move): + +```graphql +//# run-graphql +{ + latestPackage(address: "@{P0}") { + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + firstPackage: package(address: "@{P0}", version: 1) { + address + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + packages(first: 10) { + nodes { + address + version + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/object.md b/crates/iota-graphql-e2e-tests/coverage/query/object.md new file mode 100644 index 00000000000..62b2c246845 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/object.md @@ -0,0 +1,165 @@ +Query: `object` + +```graphql +{ + object(address: "0x1") { + address + objects { + edges { + node { + digest + } + } + } + balance { + coinType { + repr + signature + layout + abilities + } + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + } + } + } + coins { + edges { + node { + digest + } + } + } + stakedIotas { + edges { + node { + digest + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + name { + bcs + } + } + dynamicFields { + edges { + node { + name { + __typename + } + } + } + } + asMoveObject { + digest + } + asMovePackage { + digest + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/owned_objects.move](../../../iota-graphql-e2e-tests/tests/call/owned_objects.move): + +```graphql +//# run-graphql +{ + object(address: "0x42") { + objects { + edges { + node { + owner { + __typename + ... on AddressOwner { + owner { + address + } + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transactions/random.move](../../../iota-graphql-e2e-tests/tests/transactions/random.move): + +```graphql +//# run-graphql +{ + object(address: "0x8") { + address + version + asMoveObject { + contents { + type { repr } + json + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.move](../../../iota-graphql-e2e-tests/tests/call/dynamic_fields.move): + +```graphql +//# run-graphql +{ + object(address: "@{obj_2_0}") { + dynamicFields { + nodes { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveObject { + __typename + } + ... on MoveValue { + __typename + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/objects.md b/crates/iota-graphql-e2e-tests/coverage/query/objects.md new file mode 100644 index 00000000000..b48d531f62a --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/objects.md @@ -0,0 +1,187 @@ +Query: `objects` + +```graphql +{ + objects(first: null, last: null, after: null, filter: null) { + edges { + node { + address + objects { + edges { + node { + digest + } + } + } + balance { + coinType { + repr + signature + layout + abilities + } + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + } + } + } + coins { + edges { + node { + digest + } + } + } + stakedIotas { + edges { + node { + digest + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + name { + bcs + } + } + dynamicFields { + edges { + node { + name { + __typename + } + } + } + } + asMoveObject { + digest + } + asMovePackage { + digest + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.move](../../../iota-graphql-e2e-tests/tests/consistency/performance/many_objects.move): + +```graphql +//# run-graphql +{ + last_2: objects(last: 2, filter: {type: "@{Test}"}) { + nodes { + version + asMoveObject { + owner { + ... on AddressOwner { + owner { + address + } + } + } + contents { + json + type { + repr + } + } + } + } + } + last_4_objs_owned_by_A: address(address: "@{A}") { + objects(last: 4) { + nodes { + owner { + ... on AddressOwner { + owner { + address + } + } + } + contents { + json + type { + repr + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.move](../../../iota-graphql-e2e-tests/tests/consistency/objects_pagination.move): + +```graphql +//# run-graphql --cursors @{obj_6_0,2} +{ + before_obj_6_0_at_checkpoint_2: objects(filter: {type: "@{Test}"}, before: "@{cursor_0}") { + nodes { + version + asMoveObject { + contents { + type { + repr + } + json + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/coverage/query/objects.md](../../../iota-graphql-e2e-tests/coverage/query/objects.md): + +```graphql +//# run-graphql +{ + objects(filter: {type: "0x2::coin"}) { + edges { + node { + asMoveObject { + contents { + type { + repr + } + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/owner.md b/crates/iota-graphql-e2e-tests/coverage/query/owner.md new file mode 100644 index 00000000000..4c7236775b3 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/owner.md @@ -0,0 +1,156 @@ +Query: `owner` + +```graphql +{ + owner(address: "0x1", rootVersion: null) { + address + objects { + edges { + node { + address + } + } + } + balance { + coinType { + repr + signature + layout + abilities + } + coinObjectCount + totalBalance + } + coins { + edges { + node { + balance { + coinObjectCount + totalBalance + } + } + } + } + stakedIotas { + edges { + node { + digest + } + } + } + asAddress { + address + } + asObject { + digest + } + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicFields { + edges { + node { + __typename + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/owned_objects.move](../../../iota-graphql-e2e-tests/tests/call/owned_objects.move): + +```graphql +//# run-graphql +{ + owner(address: "0x42") { + objects { + edges { + node { + owner { + __typename + ... on AddressOwner { + owner { + address + } + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.move](../../../iota-graphql-e2e-tests/tests/call/dynamic_fields.move): + +```graphql +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicFields { + nodes { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveObject { + __typename + } + ... on MoveValue { + bcs + data + __typename + } + } + } + } + } +} + +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveValue { + __typename + bcs + data + } + } + } + } +} + +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicObjectField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { + value { + ... on MoveObject { + __typename + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/package.md b/crates/iota-graphql-e2e-tests/coverage/query/package.md new file mode 100644 index 00000000000..00d014d1da7 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/package.md @@ -0,0 +1,232 @@ +Query: `package` + +```graphql +{ + package(address: "0x1") { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + packageVersions { + edges { + node { + digest + storageRebate + bcs + moduleBcs + } + } + } + latestPackage { + digest + storageRebate + bcs + moduleBcs + } + module(name: "address") { + bytes + disassembly + } + modules { + edges { + node { + name + package { + digest + storageRebate + bcs + moduleBcs + } + datatype(name: "Char") { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + datatypes { + edges { + node { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + } + } + __typename + fileFormatVersion + bytes + disassembly + } + } + } + linkage { + version + __typename + } + typeOrigins { + __typename + } + moduleBcs + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/packages/versioning.move](../../../iota-graphql-e2e-tests/tests/packages/versioning.move): + +```graphql +//# run-graphql +{ + latestPackage(address: "@{P0}") { + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + firstPackage: package(address: "@{P0}", version: 1) { + address + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + packages(first: 10) { + nodes { + address + version + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/packages.md b/crates/iota-graphql-e2e-tests/coverage/query/packages.md new file mode 100644 index 00000000000..04d1dfbf6df --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/packages.md @@ -0,0 +1,230 @@ +Query: `package` + +```graphql +{ + packages(first: null, last: 5, after: null, filter: null) { + edges { + node { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + packageVersions { + edges { + node { + digest + storageRebate + bcs + moduleBcs + } + } + } + latestPackage { + digest + storageRebate + bcs + moduleBcs + } + module(name: "address") { + bytes + disassembly + } + modules { + edges { + node { + name + package { + digest + storageRebate + bcs + moduleBcs + } + datatype(name: "Char") { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + datatypes { + edges { + node { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + } + } + __typename + fileFormatVersion + bytes + disassembly + } + } + } + linkage { + version + __typename + } + typeOrigins { + __typename + } + moduleBcs + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/packages/versioning.move](../../../iota-graphql-e2e-tests/tests/packages/versioning.move): + +```graphql +//# run-graphql +{ # Querying packages with checkpoint bounds + before: packages(first: 10, filter: { beforeCheckpoint: 1 }) { + nodes { + address + version + previousTransactionBlock { + effects { checkpoint { sequenceNumber } } + } + } + } + + after: packages(first: 10, filter: { afterCheckpoint: 1 }) { + nodes { + address + version + previousTransactionBlock { + effects { checkpoint { sequenceNumber } } + } + } + } + + between: packages(first: 10, filter: { afterCheckpoint: 1, beforeCheckpoint: 3 }) { + nodes { + address + version + previousTransactionBlock { + effects { checkpoint { sequenceNumber } } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/protocolConfig.md b/crates/iota-graphql-e2e-tests/coverage/query/protocolConfig.md new file mode 100644 index 00000000000..876ae677796 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/protocolConfig.md @@ -0,0 +1,59 @@ +Query: `protocolConfig` + +```graphql +{ + protocolConfig(protocolVersion: 1) { + protocolVersion + featureFlags { + key + value + __typename + } + configs { + key + value + __typename + } + config(key: "address_from_bytes_cost_base") { + key + value + __typename + } + featureFlag(key: "bridge") { + key + value + __typename + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/epoch/protocol_configs.move](../../../iota-graphql-e2e-tests/tests/epoch/protocol_configs.move): + +```graphql +//# run-graphql +{ + protocolConfig { + protocolVersion + config(key: "max_move_identifier_len") { + value + } + featureFlag(key: "bridge") { + value + } + } +} + +//# run-graphql +{ + protocolConfig(protocolVersion: 1) { + protocolVersion + config(key: "max_move_identifier_len") { + value + } + featureFlag(key: "bridge") { + value + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/serviceConfig.md b/crates/iota-graphql-e2e-tests/coverage/query/serviceConfig.md new file mode 100644 index 00000000000..97960565217 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/serviceConfig.md @@ -0,0 +1,37 @@ +Query: `serviceConfig` + +```graphql +{ + serviceConfig { + isEnabled(feature:COINS) + availableVersions + enabledFeatures + maxQueryDepth + maxQueryNodes + maxOutputNodes + maxDbQueryCost + defaultPageSize + maxPageSize + mutationTimeoutMs + requestTimeoutMs + maxQueryPayloadSize + maxTypeArgumentDepth + maxTypeArgumentWidth + maxTypeNodes + maxMoveValueDepth + maxTransactionIds + maxScanLimit + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/simple.move](../../../iota-graphql-e2e-tests/tests/call/simple.move): + +```graphql +//# run-graphql +{ + serviceConfig { + availableVersions + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/transactionBlock.md b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlock.md new file mode 100644 index 00000000000..1273c8687c8 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlock.md @@ -0,0 +1,74 @@ +Query: `transactionBlock` + +```graphql +{ + transactionBlock(digest: "63X49x2QuuYNduExZWoJjfXut3s3WDWZ7Tr7nXJu32ZT") { + digest + sender { + address + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } + gasInput { + gasPrice + gasBudget + } + kind { + __typename + } + signatures + effects { + status + errors + timestamp + } + expiration { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + bcs + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/transactionBlocks.md b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlocks.md new file mode 100644 index 00000000000..3fff42b23aa --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlocks.md @@ -0,0 +1,175 @@ +Query: `transactionBlocks` + +```graphql +{ + transactionBlocks(first: null, last: null, after: null, scanLimit: null) { + edges { + node { + digest + sender { + address + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } + gasInput { + gasPrice + gasBudget + } + kind { + __typename + } + signatures + effects { + status + errors + timestamp + } + expiration { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + bcs + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/balances.move](../../../iota-graphql-e2e-tests/tests/consistency/balances.move): + +```graphql +//# run-graphql --cursors {"c":2,"t":1,"i":false} +# Emulating viewing transaction blocks at checkpoint 2. Fake coin balance should be 700. +{ + transactionBlocks(first: 1, after: "@{cursor_0}", filter: {signAddress: "@{A}"}) { + nodes { + sender { + fakeCoinBalance: balance(type: "@{P0}::fake::FAKE") { + totalBalance + } + allBalances: balances { + nodes { + coinType { + repr + } + coinObjectCount + totalBalance + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move](../../../iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move): + +```graphql +//# run-graphql +{ + transactionBlocks(first: 1) { + nodes { + effects { + objectChanges { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + edges { + cursor + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move](../../../iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move): + +```graphql +//# run-graphql --cursors {"t":5,"i":false,"c":6} +# Verify that with a cursor, we are locked into a view as if we were at the checkpoint stored in +# the cursor. Compare against `without_cursor`, which should show the latest state at the actual +# latest checkpoint. There should only be 1 transaction block in the `with_cursor` query, but +# multiple in the second +{ + checkpoint { + sequenceNumber + } + with_cursor: transactionBlocks(after: "@{cursor_0}", filter: {signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects { + edges { + cursor + } + } + } + } + } + } + without_cursor: transactionBlocks(filter: {signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects { + edges { + cursor + } + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/type.md b/crates/iota-graphql-e2e-tests/coverage/query/type.md new file mode 100644 index 00000000000..72155a597bf --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/type.md @@ -0,0 +1,28 @@ +Query: `type` + +```graphql +{ + type(type: "vector") { + repr + signature + layout + abilities + __typename + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/coverage/query/type.md](../../../iota-graphql-e2e-tests/coverage/query/type.md): + +```graphql +//# run-graphql +# Happy path -- primitive type with generic parameter + +{ + type(type: "vector") { + repr + signature + layout + } +} +``` diff --git a/crates/iota-graphql-rpc/README.md b/crates/iota-graphql-rpc/README.md index 55ee84500fb..c7dadc63929 100644 --- a/crates/iota-graphql-rpc/README.md +++ b/crates/iota-graphql-rpc/README.md @@ -125,6 +125,9 @@ To run it with the `iota start` subcommand, switch to the root directory of the ## Running tests +The crate provides test coverage for server functionality, covering client validation, query validation, reading and writing data, query limits, and health checks. +For query tests, please see the `iota-graphql-e2e-tests` crate. + To run the tests, a running postgres database is required. To do so, follow the [Indexer database setup](../iota-indexer/README.md#database-setup) to set up a database. @@ -136,3 +139,11 @@ cargo nextest run -p iota-graphql-rpc --features pg_integration --no-fail-fast - To check for compatibility with json-rpc `pnpm --filter @iota/graphql-transport test:e2e` + +## To re-generate the GraphQL schema after code changes + +In order to re-generate the GraphQL schema ([schema.graphql](schema.graphql)), run the following command: + +```sh +cargo run --bin iota-graphql-rpc generate-schema +```