Skip to content

Commit dbd7a64

Browse files
committed
tests: refactor file data source tests and add new tests
1 parent e518186 commit dbd7a64

File tree

6 files changed

+349
-317
lines changed

6 files changed

+349
-317
lines changed

tests/runner-tests/file-data-sources/abis/Contract.abi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
"internalType": "string",
88
"name": "testCommand",
99
"type": "string"
10+
},
11+
{
12+
"indexed": false,
13+
"internalType": "string",
14+
"name": "data",
15+
"type": "string"
1016
}
1117
],
1218
"name": "TestEvent",
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
type IpfsFile @entity {
1+
type FileEntity @entity {
22
id: ID!
33
content: String!
4+
foo: Foo @relation
45
}
56

6-
type IpfsFile1 @entity {
7+
type Foo @entity {
78
id: ID!
8-
content: String!
9+
ipfs: FileEntity @derivedFrom(field: "foo")
910
}
10-
11-
type SpawnTestEntity @entity {
12-
id: ID!
13-
content: String!
14-
context: String!
15-
}

tests/runner-tests/file-data-sources/src/mapping.ts

Lines changed: 122 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -4,130 +4,148 @@ import {
44
BigInt,
55
Bytes,
66
DataSourceContext,
7+
store,
8+
log,
79
} from "@graphprotocol/graph-ts";
810
import { TestEvent } from "../generated/Contract/Contract";
9-
import { IpfsFile, IpfsFile1, SpawnTestEntity } from "../generated/schema";
10-
11-
// CID of `file-data-sources/abis/Contract.abi` after being processed by graph-cli.
12-
const KNOWN_CID = "QmQ2REmceVtzawp7yrnxLQXgNNCtFHEnig6fL9aqE1kcWq";
13-
14-
export function handleBlock(block: ethereum.Block): void {
15-
let entity = new IpfsFile("onchain");
16-
entity.content = "onchain";
17-
entity.save();
18-
19-
// This will create the same data source twice, once at block 0 and another at block 2.
20-
// The creation at block 2 should be detected as a duplicate and therefore a noop.
21-
if (block.number == BigInt.fromI32(0) || block.number == BigInt.fromI32(2)) {
22-
dataSource.create("File", [KNOWN_CID]);
11+
import { FileEntity, Foo } from "../generated/schema";
12+
13+
const ONCHAIN_FROM_OFFCHAIN = "CREATE_ONCHAIN_DATASOURCE_FROM_OFFCHAIN_HANDLER";
14+
const CREATE_FILE = "CREATE_FILE";
15+
// const CREATE_FILE_FROM_HANDLE_FILE = "CREATE_FILE_FROM_HANDLE_FILE";
16+
const CREATE_UNDEFINED_ENTITY = "CREATE_UNDEFINED_ENTITY";
17+
const CREATE_CONFLICTING_ENTITY = "CREATE_CONFLICTING_ENTITY";
18+
const SPAWN_FDS_FROM_OFFCHAIN_HANDLER = "SPAWN_FDS_FROM_OFFCHAIN_HANDLER";
19+
const ACCESS_AND_UPDATE_OFFCHAIN_ENTITY_IN_ONCHAIN_HANDLER =
20+
"ACCESS_AND_UPDATE_OFFCHAIN_ENTITY_IN_ONCHAIN_HANDLER";
21+
const ACCESS_FILE_ENTITY_THROUGH_DERIVED_FIELD =
22+
"ACCESS_FILE_ENTITY_THROUGH_DERIVED_FIELD";
23+
24+
const CREATE_FOO = "CREATE_FOO";
25+
export function handleTestEvent(event: TestEvent): void {
26+
if (event.params.testCommand == CREATE_FILE) {
27+
dataSource.createWithContext(
28+
"File",
29+
[event.params.data],
30+
new DataSourceContext(),
31+
);
2332
}
2433

25-
if (block.number == BigInt.fromI32(1)) {
26-
let entity = IpfsFile.load("onchain")!;
27-
assert(entity.content == "onchain");
28-
29-
// The test assumes file data sources are processed in the block in which they are created.
30-
// So the ds created at block 0 will have been processed.
31-
//
32-
// Test that onchain data sources cannot read offchain data.
33-
assert(IpfsFile.load(KNOWN_CID) == null);
34+
if (event.params.testCommand == SPAWN_FDS_FROM_OFFCHAIN_HANDLER) {
35+
let comma_separated_hash = event.params.data;
36+
let hash1 = comma_separated_hash.split(",")[0];
37+
let hash2 = comma_separated_hash.split(",")[1];
38+
let context = new DataSourceContext();
39+
context.setString("command", SPAWN_FDS_FROM_OFFCHAIN_HANDLER);
40+
context.setString("hash", hash2);
3441

35-
// Test that using an invalid CID will be ignored
36-
dataSource.create("File", ["hi, I'm not valid"]);
42+
log.info(
43+
"Creating file data source from handleFile, command : {} ,hash1: {}, hash2: {}",
44+
[SPAWN_FDS_FROM_OFFCHAIN_HANDLER, hash1, hash2],
45+
);
46+
dataSource.createWithContext("File", [hash1], context);
3747
}
3848

39-
// This will invoke File1 data source with same CID, which will be used
40-
// to test whether same cid is triggered across different data source.
41-
if (block.number == BigInt.fromI32(3)) {
42-
// Test that onchain data sources cannot read offchain data (again, but this time more likely to hit the DB than the write queue).
43-
assert(IpfsFile.load(KNOWN_CID) == null);
44-
45-
dataSource.create("File1", [KNOWN_CID]);
49+
if (event.params.testCommand == ONCHAIN_FROM_OFFCHAIN) {
50+
let context = new DataSourceContext();
51+
context.setString("command", ONCHAIN_FROM_OFFCHAIN);
52+
context.setString("address", "0x0000000000000000000000000000000000000000");
53+
dataSource.createWithContext("File", [event.params.data], context);
4654
}
47-
}
4855

49-
export function handleTestEvent(event: TestEvent): void {
50-
let command = event.params.testCommand;
51-
52-
if (command == "createFile2") {
53-
// Will fail the subgraph when processed due to mismatch in the entity type and 'entities'.
54-
dataSource.create("File2", [KNOWN_CID]);
55-
} else if (command == "saveConflictingEntity") {
56-
// Will fail the subgraph because the same entity has been created in a file data source.
57-
let entity = new IpfsFile(KNOWN_CID);
58-
entity.content = "empty";
59-
entity.save();
60-
} else if (command == "createFile1") {
61-
// Will fail the subgraph with a conflict between two entities created by offchain data sources.
62-
let context = new DataSourceContext();
63-
context.setBytes("hash", event.block.hash);
64-
dataSource.createWithContext("File1", [KNOWN_CID], context);
65-
} else if (command == "spawnOffChainHandlerTest") {
66-
// Used to test the spawning of a file data source from another file data source handler.
67-
// `SpawnTestHandler` will spawn a file data source that will be handled by `spawnOffChainHandlerTest`,
68-
// which creates another file data source `OffChainDataSource`, which will be handled by `handleSpawnedTest`.
56+
if (event.params.testCommand == CREATE_UNDEFINED_ENTITY) {
57+
log.info("Creating undefined entity", []);
6958
let context = new DataSourceContext();
70-
context.setString("command", command);
71-
dataSource.createWithContext("SpawnTestHandler", [KNOWN_CID], context);
72-
} else if (command == "spawnOnChainHandlerTest") {
73-
// Used to test the failure of spawning of on-chain data source from a file data source handler.
74-
// `SpawnTestHandler` will spawn a file data source that will be handled by `spawnTestHandler`,
75-
// which creates an `OnChainDataSource`, which should fail since spawning onchain datasources
76-
// from offchain handlers is not allowed.
77-
let context = new DataSourceContext();
78-
context.setString("command", command);
79-
dataSource.createWithContext("SpawnTestHandler", [KNOWN_CID], context);
80-
} else {
81-
assert(false, "Unknown command: " + command);
59+
context.setString("command", CREATE_UNDEFINED_ENTITY);
60+
dataSource.createWithContext("File", [event.params.data], context);
8261
}
83-
}
8462

85-
export function handleFile(data: Bytes): void {
86-
// Test that offchain data sources cannot read onchain data.
87-
assert(IpfsFile.load("onchain") == null);
63+
if (event.params.testCommand == CREATE_CONFLICTING_ENTITY) {
64+
log.info("Creating conflicting entity", []);
65+
let entity = new FileEntity(event.params.data);
66+
entity.content = "content";
67+
entity.save();
68+
}
8869

8970
if (
90-
dataSource.stringParam() != "QmVkvoPGi9jvvuxsHDVJDgzPEzagBaWSZRYoRDzU244HjZ"
71+
event.params.testCommand ==
72+
ACCESS_AND_UPDATE_OFFCHAIN_ENTITY_IN_ONCHAIN_HANDLER
9173
) {
92-
// Test that an offchain data source cannot read from another offchain data source.
93-
assert(
94-
IpfsFile.load("QmVkvoPGi9jvvuxsHDVJDgzPEzagBaWSZRYoRDzU244HjZ") == null
95-
);
74+
let hash = event.params.data;
75+
log.info("Creating file data source from handleFile: {}", [hash]);
76+
let entity = FileEntity.load(event.params.data);
77+
if (entity == null) {
78+
log.info("Entity not found", []);
79+
} else {
80+
// This should never be logged if the entity was created in the offchain handler
81+
// Such entities are not accessible in onchain handlers and will return null on load
82+
log.info("Updating entity content", []);
83+
entity.content = "updated content";
84+
entity.save();
85+
}
9686
}
9787

98-
let entity = new IpfsFile(dataSource.stringParam());
99-
entity.content = data.toString();
100-
entity.save();
101-
102-
// Test that an offchain data source can load its own entities
103-
let loaded_entity = IpfsFile.load(dataSource.stringParam())!;
104-
assert(loaded_entity.content == entity.content);
105-
}
88+
if (event.params.testCommand == CREATE_FOO) {
89+
let entity = new Foo(event.params.data);
90+
entity.save();
91+
let context = new DataSourceContext();
92+
context.setString("command", CREATE_FOO);
93+
dataSource.createWithContext("File", [event.params.data], context);
94+
}
10695

107-
export function handleFile1(data: Bytes): void {
108-
let entity = new IpfsFile1(dataSource.stringParam());
109-
entity.content = data.toString();
110-
entity.save();
111-
}
96+
if (event.params.testCommand == ACCESS_FILE_ENTITY_THROUGH_DERIVED_FIELD) {
97+
let entity = Foo.load(event.params.data);
98+
if (entity == null) {
99+
log.info("Entity not found", []);
100+
} else {
101+
log.info("Accessing file entity through derived field", []);
102+
let fileEntity = entity.ipfs.load();
112103

113-
// Used to test spawning a file data source from another file data source handler.
114-
// This function spawns a file data source that will be handled by `handleSpawnedTest`.
115-
export function spawnTestHandler(data: Bytes): void {
116-
let context = new DataSourceContext();
117-
context.setString("file", "fromSpawnTestHandler");
118-
let command = dataSource.context().getString("command");
119-
if (command == "spawnOffChainHandlerTest") {
120-
dataSource.createWithContext("OffChainDataSource", [KNOWN_CID], context);
121-
} else if (command == "spawnOnChainHandlerTest") {
122-
dataSource.createWithContext("OnChainDataSource", [KNOWN_CID], context);
104+
assert(fileEntity.length == 0, "Expected exactly one file entity");
105+
}
123106
}
124107
}
125108

126-
// This is the handler for the data source spawned by `spawnOffChainHandlerTest`.
127-
export function handleSpawnedTest(data: Bytes): void {
128-
let entity = new SpawnTestEntity(dataSource.stringParam());
129-
let context = dataSource.context().getString("file");
130-
entity.content = data.toString();
131-
entity.context = context;
132-
entity.save();
109+
export function handleFile(data: Bytes): void {
110+
log.info("handleFile {}", [dataSource.stringParam()]);
111+
let context = dataSource.context();
112+
113+
if (context.isSet("command")) {
114+
let contextCommand = context.getString("command");
115+
116+
if (contextCommand == SPAWN_FDS_FROM_OFFCHAIN_HANDLER) {
117+
let hash = context.getString("hash");
118+
log.info("Creating file data source from handleFile: {}", [hash]);
119+
dataSource.createWithContext("File", [hash], new DataSourceContext());
120+
}
121+
122+
if (contextCommand == ONCHAIN_FROM_OFFCHAIN) {
123+
log.info("Creating onchain data source from offchain handler", []);
124+
let address = context.getString("address");
125+
dataSource.create("OnChainDataSource", [address]);
126+
}
127+
128+
if (contextCommand == CREATE_UNDEFINED_ENTITY) {
129+
log.info("Creating undefined entity", []);
130+
let entity = new Foo(dataSource.stringParam());
131+
entity.save();
132+
}
133+
134+
if (contextCommand == CREATE_FOO) {
135+
log.info("Creating FileEntity with relation to Foo", []);
136+
let entity = new FileEntity(dataSource.stringParam());
137+
entity.foo = dataSource.stringParam();
138+
entity.content = data.toString();
139+
entity.save();
140+
}
141+
} else {
142+
log.info("Creating FileEntity from handleFile: {} , content : {}", [
143+
dataSource.stringParam(),
144+
data.toString(),
145+
]);
146+
147+
let entity = new FileEntity(dataSource.stringParam());
148+
entity.content = data.toString();
149+
entity.save();
150+
}
133151
}

tests/runner-tests/file-data-sources/subgraph.yaml

Lines changed: 5 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@ dataSources:
1313
apiVersion: 0.0.7
1414
language: wasm/assemblyscript
1515
entities:
16-
- Gravatar
16+
- FileEntity
17+
- Foo
1718
abis:
1819
- name: Contract
1920
file: ./abis/Contract.abi
20-
blockHandlers:
21-
- handler: handleBlock
2221
eventHandlers:
23-
- event: TestEvent(string)
22+
- event: TestEvent(string,string)
2423
handler: handleTestEvent
2524
file: ./src/mapping.ts
2625
templates:
@@ -38,10 +37,8 @@ templates:
3837
abis:
3938
- name: Contract
4039
file: ./abis/Contract.abi
41-
blockHandlers:
42-
- handler: handleBlock
4340
eventHandlers:
44-
- event: TestEvent(string)
41+
- event: TestEvent(string,string)
4542
handler: handleTestEvent
4643
file: ./src/mapping.ts
4744
- kind: file/ipfs
@@ -51,61 +48,9 @@ templates:
5148
apiVersion: 0.0.7
5249
language: wasm/assemblyscript
5350
entities:
54-
- IpfsFile
51+
- FileEntity
5552
abis:
5653
- name: Contract
5754
file: ./abis/Contract.abi
5855
handler: handleFile
5956
file: ./src/mapping.ts
60-
- kind: file/ipfs
61-
name: File1
62-
mapping:
63-
kind: ethereum/events
64-
apiVersion: 0.0.7
65-
language: wasm/assemblyscript
66-
entities:
67-
- IpfsFile1
68-
abis:
69-
- name: Contract
70-
file: ./abis/Contract.abi
71-
handler: handleFile1
72-
file: ./src/mapping.ts
73-
- kind: file/ipfs
74-
name: File2
75-
mapping:
76-
kind: ethereum/events
77-
apiVersion: 0.0.7
78-
language: wasm/assemblyscript
79-
entities:
80-
- IpfsFile # will trigger an error, should be IpfsFile1
81-
abis:
82-
- name: Contract
83-
file: ./abis/Contract.abi
84-
handler: handleFile1
85-
file: ./src/mapping.ts
86-
- kind: file/ipfs
87-
name: SpawnTestHandler
88-
mapping:
89-
kind: ethereum/events
90-
apiVersion: 0.0.7
91-
language: wasm/assemblyscript
92-
entities:
93-
- SpawnTestEntity
94-
abis:
95-
- name: Contract
96-
file: ./abis/Contract.abi
97-
handler: spawnTestHandler
98-
file: ./src/mapping.ts
99-
- kind: file/ipfs
100-
name: OffChainDataSource
101-
mapping:
102-
kind: ethereum/events
103-
apiVersion: 0.0.7
104-
language: wasm/assemblyscript
105-
entities:
106-
- SpawnTestEntity
107-
abis:
108-
- name: Contract
109-
file: ./abis/Contract.abi
110-
handler: handleSpawnedTest
111-
file: ./src/mapping.ts

0 commit comments

Comments
 (0)