Skip to content

Commit 70f219a

Browse files
authored
Test the resulting git trees to ensure correct changes have persisted (#10)
* Test the resulting git tree hashes after mutation * Test the file hashes in tests To support deeper tests for the cases where the tree hash will be unstable, test the hash of the file contents instead, and also do this for places where we also test the tree hash.
1 parent 8cbf997 commit 70f219a

File tree

3 files changed

+210
-30
lines changed

3 files changed

+210
-30
lines changed

src/core.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export const commitFilesFromBase64 = async ({
142142
input: {
143143
refId: info.targetBranch.id,
144144
oid: baseOid,
145+
force: true,
145146
},
146147
});
147148

src/github/graphql/queries.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import type {
99
CreateRefMutationVariables,
1010
DeleteRefMutation,
1111
DeleteRefMutationVariables,
12+
GetRefTreeQuery,
13+
GetRefTreeQueryVariables,
1214
GetRepositoryMetadataQuery,
1315
GetRepositoryMetadataQueryVariables,
1416
UpdateRefMutation,
@@ -83,6 +85,31 @@ const CREATE_COMMIT_ON_BRANCH = /* GraphQL */ `
8385
}
8486
`;
8587

88+
/** For tests only */
89+
const GET_REF_TREE = /* GraphQL */ `
90+
query getRefTree(
91+
$owner: String!
92+
$name: String!
93+
$ref: String!
94+
$path: String!
95+
) {
96+
repository(owner: $owner, name: $name) {
97+
ref(qualifiedName: $ref) {
98+
target {
99+
... on Commit {
100+
tree {
101+
oid
102+
}
103+
file(path: $path) {
104+
oid
105+
}
106+
}
107+
}
108+
}
109+
}
110+
}
111+
`;
112+
86113
export const getRepositoryMetadata = async (
87114
o: GitHubClient,
88115
v: GetRepositoryMetadataQueryVariables,
@@ -117,3 +144,8 @@ export const createCommitOnBranchQuery = async (
117144
v: CreateCommitOnBranchMutationVariables,
118145
): Promise<CreateCommitOnBranchMutation> =>
119146
o.graphql<CreateCommitOnBranchMutation>(CREATE_COMMIT_ON_BRANCH, v);
147+
148+
export const getRefTreeQuery = async (
149+
o: GitHubClient,
150+
v: GetRefTreeQueryVariables,
151+
): Promise<GetRefTreeQuery> => o.graphql<GetRefTreeQuery>(GET_REF_TREE, v);

src/test/integration/node.test.ts

Lines changed: 177 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,88 @@ import { commitFilesFromBuffers } from "../../node.js";
55
import { deleteBranches } from "./util.js";
66
import {
77
createRefMutation,
8+
getRefTreeQuery,
89
getRepositoryMetadata,
910
} from "../../github/graphql/queries.js";
1011

1112
const octokit = getOctokit(ENV.GITHUB_TOKEN);
1213

1314
const TEST_BRANCH_PREFIX = `${ROOT_TEST_BRANCH_PREFIX}-node`;
1415

16+
const TEST_TARGET_COMMIT = "fce2760017eab6d85388ed5cfdfac171559d80b3";
17+
/**
18+
* For tests, important that this commit is not an ancestor of TEST_TARGET_COMMIT,
19+
* to ensure that non-fast-forward pushes are tested
20+
*/
21+
const TEST_TARGET_COMMIT_2 = "7ba8473f02849de3b5449b25fc83c5245d338d94";
22+
const TEST_TARGET_TREE_2 = "95c9ea756f3686614dcdc1c42f7f654b684cdac2";
23+
24+
const BASIC_FILE_CHANGES_PATH = "foo.txt";
25+
const BASIC_FILE_CHANGES_OID = "0e23339619d605319ec4b49a0ac9dd94598eff8e";
26+
const BASIC_FILE_CONTENTS = {
27+
message: {
28+
headline: "Test commit",
29+
body: "This is a test commit",
30+
},
31+
fileChanges: {
32+
additions: [
33+
{
34+
path: BASIC_FILE_CHANGES_PATH,
35+
contents: Buffer.alloc(1024, "Hello, world!"),
36+
},
37+
],
38+
},
39+
log,
40+
};
41+
42+
const TEST_TARGET_TREE_WITH_BASIC_CHANGES =
43+
"a3431c9b42b71115c52bc6fbf9da3682cf0ed5e8";
44+
1545
describe("node", () => {
1646
const branches: string[] = [];
1747

1848
// Set timeout to 1 minute
1949
jest.setTimeout(60 * 1000);
2050

21-
const contents = Buffer.alloc(1024, "Hello, world!");
22-
const BASIC_FILE_CONTENTS = {
23-
message: {
24-
headline: "Test commit",
25-
body: "This is a test commit",
26-
},
27-
fileChanges: {
28-
additions: [
29-
{
30-
path: `foo.txt`,
31-
contents,
32-
},
33-
],
34-
},
35-
log,
36-
};
37-
3851
let repositoryId: string;
3952

53+
const expectBranchHasTree = async ({
54+
branch,
55+
treeOid,
56+
file,
57+
}: {
58+
branch: string;
59+
treeOid?: string;
60+
file?: {
61+
path: string;
62+
oid: string;
63+
};
64+
}) => {
65+
const ref = (
66+
await getRefTreeQuery(octokit, {
67+
owner: REPO.owner,
68+
name: REPO.repository,
69+
ref: `refs/heads/${branch}`,
70+
path: file?.path ?? "package.json",
71+
})
72+
).repository?.ref?.target;
73+
74+
if (!ref) {
75+
throw new Error("Unexpected missing ref");
76+
}
77+
78+
if ("tree" in ref) {
79+
if (treeOid) {
80+
expect(ref.tree.oid).toEqual(treeOid);
81+
}
82+
if (file) {
83+
expect(ref.file?.oid).toEqual(file.oid);
84+
}
85+
} else {
86+
throw new Error("Expected ref to have a tree");
87+
}
88+
};
89+
4090
beforeAll(async () => {
4191
const response = await getRepositoryMetadata(octokit, {
4292
owner: REPO.owner,
@@ -53,12 +103,26 @@ describe("node", () => {
53103
describe("commitFilesFromBuffers", () => {
54104
describe("can commit single file of various sizes", () => {
55105
const SIZES_BYTES = {
56-
"1KiB": 1024,
57-
"1MiB": 1024 * 1024,
58-
"10MiB": 1024 * 1024 * 10,
106+
"1KiB": {
107+
sizeBytes: 1024,
108+
treeOid: "547dfe4079b53c3b45a6717ac1ed6d98512f0a1c",
109+
fileOid: "0e23339619d605319ec4b49a0ac9dd94598eff8e",
110+
},
111+
"1MiB": {
112+
sizeBytes: 1024 * 1024,
113+
treeOid: "a6dca57388cf08de146bcc01a2113b218d6c2858",
114+
fileOid: "a1d7fed1b4a8de1b665dc4f604015b2d87ef978f",
115+
},
116+
"10MiB": {
117+
sizeBytes: 1024 * 1024 * 10,
118+
treeOid: "c4788256a2c1e3ea4267cff0502a656d992248ec",
119+
fileOid: "e36e74edbb6d3fc181ef584a50f8ee55585d27cc",
120+
},
59121
};
60122

61-
for (const [sizeName, sizeBytes] of Object.entries(SIZES_BYTES)) {
123+
for (const [sizeName, { sizeBytes, treeOid, fileOid }] of Object.entries(
124+
SIZES_BYTES,
125+
)) {
62126
it(`Can commit a ${sizeName}`, async () => {
63127
const branch = `${TEST_BRANCH_PREFIX}-${sizeName}`;
64128
branches.push(branch);
@@ -69,7 +133,7 @@ describe("node", () => {
69133
...REPO,
70134
branch,
71135
base: {
72-
branch: "main",
136+
commit: TEST_TARGET_COMMIT,
73137
},
74138
message: {
75139
headline: "Test commit",
@@ -85,10 +149,43 @@ describe("node", () => {
85149
},
86150
log,
87151
});
152+
153+
await expectBranchHasTree({
154+
branch,
155+
treeOid,
156+
file: {
157+
path: `${sizeName}.txt`,
158+
oid: fileOid,
159+
},
160+
});
88161
});
89162
}
90163
});
91164

165+
it("can commit using branch as a base", async () => {
166+
const branch = `${TEST_BRANCH_PREFIX}-branch-base`;
167+
branches.push(branch);
168+
169+
await commitFilesFromBuffers({
170+
octokit,
171+
...REPO,
172+
branch,
173+
base: {
174+
branch: "main",
175+
},
176+
...BASIC_FILE_CONTENTS,
177+
});
178+
179+
// Don't test tree for this one as it will change over time / be unstable
180+
await expectBranchHasTree({
181+
branch,
182+
file: {
183+
path: BASIC_FILE_CHANGES_PATH,
184+
oid: BASIC_FILE_CHANGES_OID,
185+
},
186+
});
187+
});
188+
92189
it("can commit using tag as a base", async () => {
93190
const branch = `${TEST_BRANCH_PREFIX}-tag-base`;
94191
branches.push(branch);
@@ -102,6 +199,15 @@ describe("node", () => {
102199
},
103200
...BASIC_FILE_CONTENTS,
104201
});
202+
203+
// Don't test tree for this one as it will change over time / be unstable
204+
await expectBranchHasTree({
205+
branch,
206+
file: {
207+
path: BASIC_FILE_CHANGES_PATH,
208+
oid: BASIC_FILE_CHANGES_OID,
209+
},
210+
});
105211
});
106212

107213
it("can commit using commit as a base", async () => {
@@ -113,10 +219,19 @@ describe("node", () => {
113219
...REPO,
114220
branch,
115221
base: {
116-
commit: "fce2760017eab6d85388ed5cfdfac171559d80b3",
222+
commit: TEST_TARGET_COMMIT,
117223
},
118224
...BASIC_FILE_CONTENTS,
119225
});
226+
227+
await expectBranchHasTree({
228+
branch,
229+
treeOid: TEST_TARGET_TREE_WITH_BASIC_CHANGES,
230+
file: {
231+
path: BASIC_FILE_CHANGES_PATH,
232+
oid: BASIC_FILE_CHANGES_OID,
233+
},
234+
});
120235
});
121236

122237
describe("existing branches", () => {
@@ -129,7 +244,7 @@ describe("node", () => {
129244
input: {
130245
repositoryId,
131246
name: `refs/heads/${branch}`,
132-
oid: "31ded45f25a07726e02fd111d4c230718b49fa2a",
247+
oid: TEST_TARGET_COMMIT_2,
133248
},
134249
});
135250

@@ -138,11 +253,20 @@ describe("node", () => {
138253
...REPO,
139254
branch,
140255
base: {
141-
commit: "fce2760017eab6d85388ed5cfdfac171559d80b3",
256+
commit: TEST_TARGET_COMMIT,
142257
},
143258
...BASIC_FILE_CONTENTS,
144259
force: true,
145260
});
261+
262+
await expectBranchHasTree({
263+
branch,
264+
treeOid: TEST_TARGET_TREE_WITH_BASIC_CHANGES,
265+
file: {
266+
path: BASIC_FILE_CHANGES_PATH,
267+
oid: BASIC_FILE_CHANGES_OID,
268+
},
269+
});
146270
});
147271

148272
it("cannot commit to existing branch when force is false", async () => {
@@ -154,7 +278,7 @@ describe("node", () => {
154278
input: {
155279
repositoryId,
156280
name: `refs/heads/${branch}`,
157-
oid: "31ded45f25a07726e02fd111d4c230718b49fa2a",
281+
oid: TEST_TARGET_COMMIT_2,
158282
},
159283
});
160284

@@ -164,13 +288,18 @@ describe("node", () => {
164288
...REPO,
165289
branch,
166290
base: {
167-
commit: "fce2760017eab6d85388ed5cfdfac171559d80b3",
291+
commit: TEST_TARGET_COMMIT,
168292
},
169293
...BASIC_FILE_CONTENTS,
170294
}),
171295
).rejects.toThrow(
172296
`Branch ${branch} exists already and does not match base`,
173297
);
298+
299+
await expectBranchHasTree({
300+
branch,
301+
treeOid: TEST_TARGET_TREE_2,
302+
});
174303
});
175304

176305
it("can commit to existing branch when force is false and target matches base", async () => {
@@ -182,7 +311,7 @@ describe("node", () => {
182311
input: {
183312
repositoryId,
184313
name: `refs/heads/${branch}`,
185-
oid: "31ded45f25a07726e02fd111d4c230718b49fa2a",
314+
oid: TEST_TARGET_COMMIT,
186315
},
187316
});
188317

@@ -191,10 +320,19 @@ describe("node", () => {
191320
...REPO,
192321
branch,
193322
base: {
194-
commit: "31ded45f25a07726e02fd111d4c230718b49fa2a",
323+
commit: TEST_TARGET_COMMIT,
195324
},
196325
...BASIC_FILE_CONTENTS,
197326
});
327+
328+
await expectBranchHasTree({
329+
branch,
330+
treeOid: TEST_TARGET_TREE_WITH_BASIC_CHANGES,
331+
file: {
332+
path: BASIC_FILE_CHANGES_PATH,
333+
oid: BASIC_FILE_CHANGES_OID,
334+
},
335+
});
198336
});
199337

200338
it("can commit to same branch as base", async () => {
@@ -206,7 +344,7 @@ describe("node", () => {
206344
input: {
207345
repositoryId,
208346
name: `refs/heads/${branch}`,
209-
oid: "31ded45f25a07726e02fd111d4c230718b49fa2a",
347+
oid: TEST_TARGET_COMMIT,
210348
},
211349
});
212350

@@ -219,6 +357,15 @@ describe("node", () => {
219357
},
220358
...BASIC_FILE_CONTENTS,
221359
});
360+
361+
await expectBranchHasTree({
362+
branch,
363+
treeOid: TEST_TARGET_TREE_WITH_BASIC_CHANGES,
364+
file: {
365+
path: BASIC_FILE_CHANGES_PATH,
366+
oid: BASIC_FILE_CHANGES_OID,
367+
},
368+
});
222369
});
223370
});
224371
});

0 commit comments

Comments
 (0)