Discourse: scope mirror tests as being "mode 1" (#1463)

This is to prepare for mode 2 being tested side-by-side.

The normalizeMode1Topics function enforces bumpedMs is not
updated for mode 1 tests.

Additionally describe "update semantics" is redundant,
as the mirror has no other function than update.
This commit is contained in:
Robin van Boven 2019-12-02 20:24:49 +01:00 committed by GitHub
parent 3ceb4fb7fa
commit c521acc145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 152 additions and 143 deletions

View File

@ -169,6 +169,14 @@ class MockFetcher implements Discourse {
} }
} }
function normalizeMode1Topics(topics: Topic[]): Topic[] {
return topics.map((topic) => ({
...topic,
// Mode 1 didn't support bumpMs handling.
bumpedMs: topic.timestampMs,
}));
}
describe("plugins/discourse/mirror", () => { describe("plugins/discourse/mirror", () => {
function spyWarn(): JestMockFn<[string], void> { function spyWarn(): JestMockFn<[string], void> {
return ((console.warn: any): JestMockFn<any, void>); return ((console.warn: any): JestMockFn<any, void>);
@ -201,79 +209,79 @@ describe("plugins/discourse/mirror", () => {
return {fetcher, mirror, reporter, url, repo}; return {fetcher, mirror, reporter, url, repo};
}; };
it("mirrors topics from the fetcher", async () => { describe("mirror mode 1", () => {
const {mirror, fetcher, reporter, repo} = example(); it("mirrors topics from the fetcher", async () => {
fetcher.addPost(2, null); const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(3, null); fetcher.addPost(2, null);
const topic2 = fetcher._topic(2); fetcher.addPost(3, null);
const topic3 = fetcher._topic(3); const topic2 = fetcher._topic(2);
await mirror.update(reporter); const topic3 = fetcher._topic(3);
expect(repo.topics()).toEqual([topic2, topic3]); await mirror.update(reporter);
}); expect(repo.topics()).toEqual(normalizeMode1Topics([topic2, topic3]));
});
it("mirrors posts from the fetcher", async () => { it("mirrors posts from the fetcher", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter, repo} = example();
const p1 = fetcher.addPost(2, null); const p1 = fetcher.addPost(2, null);
const p2 = fetcher.addPost(3, null); const p2 = fetcher.addPost(3, null);
const p3 = fetcher.addPost(3, 1); const p3 = fetcher.addPost(3, 1);
await mirror.update(reporter); await mirror.update(reporter);
const posts = [fetcher._post(p1), fetcher._post(p2), fetcher._post(p3)]; const posts = [fetcher._post(p1), fetcher._post(p2), fetcher._post(p3)];
expect(repo.posts()).toEqual(posts); expect(repo.posts()).toEqual(posts);
}); });
it("provides usernames for all active users", async () => { it("provides usernames for all active users", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(2, null, "alpha"); fetcher.addPost(2, null, "alpha");
fetcher.addPost(3, null, "beta"); fetcher.addPost(3, null, "beta");
fetcher.addPost(3, 1, "alpha"); fetcher.addPost(3, 1, "alpha");
await mirror.update(reporter); await mirror.update(reporter);
// credbot appears because it is the nominal author of all topics // credbot appears because it is the nominal author of all topics
expect( expect(
repo repo
.users() .users()
.slice() .slice()
.sort() .sort()
).toEqual(["alpha", "beta", "credbot"]); ).toEqual(["alpha", "beta", "credbot"]);
}); });
function expectLikesSorted(as, bs) { function expectLikesSorted(as, bs) {
const s = (ls) => const s = (ls) =>
sortBy( sortBy(
ls, ls,
(x) => x.username, (x) => x.username,
(x) => x.postId (x) => x.postId
); );
expect(s(as)).toEqual(s(bs)); expect(s(as)).toEqual(s(bs));
} }
it("provides all the likes by users that have posted", async () => { it("provides all the likes by users that have posted", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(1, null, "alpha"); fetcher.addPost(1, null, "alpha");
fetcher.addPost(2, null, "alpha"); fetcher.addPost(2, null, "alpha");
fetcher.addPost(3, null, "beta"); fetcher.addPost(3, null, "beta");
const l1 = fetcher.addLike("beta", 1, 5); const l1 = fetcher.addLike("beta", 1, 5);
const l2 = fetcher.addLike("beta", 2, 6); const l2 = fetcher.addLike("beta", 2, 6);
const l3 = fetcher.addLike("beta", 3, 7); const l3 = fetcher.addLike("beta", 3, 7);
const l4 = fetcher.addLike("alpha", 1, 8); const l4 = fetcher.addLike("alpha", 1, 8);
await mirror.update(reporter); await mirror.update(reporter);
expectLikesSorted(repo.likes(), [l1, l2, l3, l4]); expectLikesSorted(repo.likes(), [l1, l2, l3, l4]);
const l5 = fetcher.addLike("alpha", 2, 9); const l5 = fetcher.addLike("alpha", 2, 9);
fetcher.addPost(4, null, "credbot"); fetcher.addPost(4, null, "credbot");
const l6 = fetcher.addLike("credbot", 2, 10); const l6 = fetcher.addLike("credbot", 2, 10);
const l7 = fetcher.addLike("beta", 4, 11); const l7 = fetcher.addLike("beta", 4, 11);
await mirror.update(reporter); await mirror.update(reporter);
expectLikesSorted(repo.likes(), [l1, l2, l3, l4, l5, l6, l7]); expectLikesSorted(repo.likes(), [l1, l2, l3, l4, l5, l6, l7]);
}); });
it("doesn't find likes of users that never posted", async () => { it("doesn't find likes of users that never posted", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(1, null); fetcher.addPost(1, null);
fetcher.addLike("nope", 1, 1); fetcher.addLike("nope", 1, 1);
await mirror.update(reporter); await mirror.update(reporter);
expect(repo.likes()).toEqual([]); expect(repo.likes()).toEqual([]);
}); });
describe("update semantics", () => {
it("only fetches new topics on `update`", async () => { it("only fetches new topics on `update`", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(1, null); fetcher.addPost(1, null);
@ -420,7 +428,7 @@ describe("plugins/discourse/mirror", () => {
// Force the fetcher not to return topic 2 // Force the fetcher not to return topic 2
fetcher._latestTopicId--; fetcher._latestTopicId--;
await mirror.update(reporter); await mirror.update(reporter);
const topics = [fetcher._topic(1)]; const topics = normalizeMode1Topics([fetcher._topic(1)]);
expect(repo.topics()).toEqual(topics); expect(repo.topics()).toEqual(topics);
const posts = [fetcher._post(pid1)]; const posts = [fetcher._post(pid1)];
expect(repo.posts()).toEqual(posts); expect(repo.posts()).toEqual(posts);
@ -443,7 +451,7 @@ describe("plugins/discourse/mirror", () => {
// Force the fetcher not to return topic 2 // Force the fetcher not to return topic 2
fetcher._latestTopicId--; fetcher._latestTopicId--;
await mirror.update(reporter); await mirror.update(reporter);
const topics = [fetcher._topic(1)]; const topics = normalizeMode1Topics([fetcher._topic(1)]);
expect(repo.topics()).toEqual(topics); expect(repo.topics()).toEqual(topics);
const posts = [pid1, pid3].map((x) => fetcher._post(x)); const posts = [pid1, pid3].map((x) => fetcher._post(x));
expect(repo.posts()).toEqual(posts); expect(repo.posts()).toEqual(posts);
@ -461,7 +469,8 @@ describe("plugins/discourse/mirror", () => {
const badLike = {username: "credbot", postId: 37, timestampMs: 0}; const badLike = {username: "credbot", postId: 37, timestampMs: 0};
fetcher._likes.push(badLike); fetcher._likes.push(badLike);
await mirror.update(reporter); await mirror.update(reporter);
expect(repo.topics()).toEqual([fetcher._topic(1)]); const topics = normalizeMode1Topics([fetcher._topic(1)]);
expect(repo.topics()).toEqual(topics);
expect(repo.posts()).toEqual([fetcher._post(pid)]); expect(repo.posts()).toEqual([fetcher._post(pid)]);
expect(repo.likes()).toEqual([]); expect(repo.likes()).toEqual([]);
expect(console.warn).toHaveBeenCalledWith( expect(console.warn).toHaveBeenCalledWith(
@ -471,92 +480,92 @@ describe("plugins/discourse/mirror", () => {
expect(console.warn).toHaveBeenCalledTimes(1); expect(console.warn).toHaveBeenCalledTimes(1);
spyWarn().mockReset(); spyWarn().mockReset();
}); });
});
it("warns if a user's likes are missing", async () => { it("warns if a user's likes are missing", async () => {
const {mirror, fetcher, reporter, repo} = example();
const pid = fetcher.addPost(1, null, "credbot");
(fetcher: any).likesByUser = async () => null;
await mirror.update(reporter);
expect(repo.topics()).toEqual([fetcher._topic(1)]);
expect(repo.posts()).toEqual([fetcher._post(pid)]);
expect(repo.likes()).toEqual([]);
});
it("inserts other likes if one user's likes are missing", async () => {
const {mirror, fetcher, reporter, repo} = example();
const p1 = fetcher.addPost(1, null, "credbot");
const p2 = fetcher.addPost(1, 1, "otheruser");
const l1 = fetcher.addLike("otheruser", 1, 123);
const _likesByUser = fetcher.likesByUser.bind(fetcher);
(fetcher: any).likesByUser = async (
targetUsername: string,
offset: number
) => {
if (targetUsername == "credbot") return null;
return await _likesByUser(targetUsername, offset);
};
await mirror.update(reporter);
expect(repo.topics()).toEqual([fetcher._topic(1)]);
expect(repo.posts()).toEqual([fetcher._post(p1), fetcher._post(p2)]);
expect(repo.likes()).toEqual([l1]);
});
it("sends the right tasks to the TaskReporter", async () => {
const {mirror, fetcher, reporter} = example();
fetcher.addPost(1, null, "credbot");
await mirror.update(reporter);
expect(reporter.activeTasks()).toEqual([]);
expect(reporter.entries()).toEqual([
{type: "START", taskId: "discourse"},
{type: "START", taskId: "discourse/topics"},
{type: "FINISH", taskId: "discourse/topics"},
{type: "START", taskId: "discourse/posts"},
{type: "FINISH", taskId: "discourse/posts"},
{type: "START", taskId: "discourse/likes"},
{type: "FINISH", taskId: "discourse/likes"},
{type: "FINISH", taskId: "discourse"},
]);
});
describe("findPostInTopic", () => {
it("works for the first post in a topic", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter, repo} = example();
const id = fetcher.addPost(5, null); const pid = fetcher.addPost(1, null, "credbot");
const post = NullUtil.get(fetcher._post(id)); (fetcher: any).likesByUser = async () => null;
expect(post.topicId).toEqual(5);
expect(post.indexWithinTopic).toEqual(1);
await mirror.update(reporter); await mirror.update(reporter);
expect(repo.findPostInTopic(5, 1)).toEqual(id); expect(repo.topics()).toEqual(normalizeMode1Topics([fetcher._topic(1)]));
expect(repo.posts()).toEqual([fetcher._post(pid)]);
expect(repo.likes()).toEqual([]);
}); });
it("works for the second post in a topic", async () => { it("inserts other likes if one user's likes are missing", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(1, null); const p1 = fetcher.addPost(1, null, "credbot");
const id = fetcher.addPost(1, 1); const p2 = fetcher.addPost(1, 1, "otheruser");
const post = NullUtil.get(fetcher._post(id)); const l1 = fetcher.addLike("otheruser", 1, 123);
expect(post.indexWithinTopic).toEqual(2); const _likesByUser = fetcher.likesByUser.bind(fetcher);
(fetcher: any).likesByUser = async (
targetUsername: string,
offset: number
) => {
if (targetUsername == "credbot") return null;
return await _likesByUser(targetUsername, offset);
};
await mirror.update(reporter); await mirror.update(reporter);
expect(repo.findPostInTopic(1, 2)).toEqual(id); expect(repo.topics()).toEqual(normalizeMode1Topics([fetcher._topic(1)]));
expect(repo.posts()).toEqual([fetcher._post(p1), fetcher._post(p2)]);
expect(repo.likes()).toEqual([l1]);
}); });
it("returns undefined for a post with too high an index", async () => { it("sends the right tasks to the TaskReporter", async () => {
const {mirror, fetcher, reporter, repo} = example(); const {mirror, fetcher, reporter} = example();
fetcher.addPost(1, null); fetcher.addPost(1, null, "credbot");
await mirror.update(reporter); await mirror.update(reporter);
expect(repo.findPostInTopic(1, 2)).toBe(undefined); expect(reporter.activeTasks()).toEqual([]);
expect(reporter.entries()).toEqual([
{type: "START", taskId: "discourse"},
{type: "START", taskId: "discourse/topics"},
{type: "FINISH", taskId: "discourse/topics"},
{type: "START", taskId: "discourse/posts"},
{type: "FINISH", taskId: "discourse/posts"},
{type: "START", taskId: "discourse/likes"},
{type: "FINISH", taskId: "discourse/likes"},
{type: "FINISH", taskId: "discourse"},
]);
}); });
it("returns undefined for topic that doesnt exist", async () => { describe("findPostInTopic", () => {
const {mirror, fetcher, reporter, repo} = example(); it("works for the first post in a topic", async () => {
fetcher.addPost(1, null); const {mirror, fetcher, reporter, repo} = example();
await mirror.update(reporter); const id = fetcher.addPost(5, null);
expect(repo.findPostInTopic(2, 1)).toBe(undefined); const post = NullUtil.get(fetcher._post(id));
}); expect(post.topicId).toEqual(5);
expect(post.indexWithinTopic).toEqual(1);
await mirror.update(reporter);
expect(repo.findPostInTopic(5, 1)).toEqual(id);
});
it("returns undefined for a mirror that never updated", async () => { it("works for the second post in a topic", async () => {
const {repo} = example(); const {mirror, fetcher, reporter, repo} = example();
expect(repo.findPostInTopic(1, 1)).toBe(undefined); fetcher.addPost(1, null);
const id = fetcher.addPost(1, 1);
const post = NullUtil.get(fetcher._post(id));
expect(post.indexWithinTopic).toEqual(2);
await mirror.update(reporter);
expect(repo.findPostInTopic(1, 2)).toEqual(id);
});
it("returns undefined for a post with too high an index", async () => {
const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(1, null);
await mirror.update(reporter);
expect(repo.findPostInTopic(1, 2)).toBe(undefined);
});
it("returns undefined for topic that doesnt exist", async () => {
const {mirror, fetcher, reporter, repo} = example();
fetcher.addPost(1, null);
await mirror.update(reporter);
expect(repo.findPostInTopic(2, 1)).toBe(undefined);
});
it("returns undefined for a mirror that never updated", async () => {
const {repo} = example();
expect(repo.findPostInTopic(1, 1)).toBe(undefined);
});
}); });
}); });
}); });