-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This also refactors out the initialization code from the 2 tests. It took a while to figure out the right configuration so Jest would not pick up two versions of firebase-admin dependency since it also exists in the parent node_modules.
- Loading branch information
Showing
7 changed files
with
122 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,94 @@ | ||
import initializeFFT from "firebase-functions-test"; | ||
import { | ||
clearFirestoreData, | ||
} from "firebase-functions-test/lib/providers/firestore"; | ||
import {initializeApp} from "firebase-admin/app"; | ||
// import {getFirestore} from "firebase-admin/firestore"; | ||
import {getFirestore, Timestamp} from "firebase-admin/firestore"; | ||
import {getDatabase} from "firebase-admin/database"; | ||
import * as logger from "firebase-functions/logger"; | ||
import {initialize, projectConfig} from "./initialize"; | ||
import {runAtMidnight} from "../src/at-midnight"; | ||
|
||
process.env["FIRESTORE_EMULATOR_HOST"]="127.0.0.1:8088"; | ||
const projectConfig = {projectId: "demo-test"}; | ||
const fft = initializeFFT(projectConfig); | ||
jest.mock("firebase-functions/logger"); | ||
|
||
// When the function is running in the cloud initializeApp is called by index.ts | ||
// Here we are importing the function's module directly so we can call | ||
// initializeApp ourselves. This is beneficial since initializeApp needs to | ||
// be called after initializeFFT above. | ||
initializeApp(); | ||
const {cleanup} = initialize(); | ||
|
||
// type CollectionRef = admin.firestore.CollectionReference< | ||
// admin.firestore.DocumentData, admin.firestore.DocumentData | ||
// >; | ||
const HOUR = 1000 * 60 * 60; | ||
|
||
async function writeFirestoreRoot(lastLaunchMillis = 0) { | ||
const newRoot = getFirestore() | ||
.collection("qa") | ||
.doc(); | ||
|
||
await newRoot.set({ | ||
lastLaunchTime: Timestamp.fromMillis(lastLaunchMillis), | ||
}); | ||
|
||
// Add some sub docs to make sure they are deleted | ||
await newRoot.collection("users").doc().set({ | ||
uid: "test-user", | ||
}); | ||
|
||
return newRoot; | ||
} | ||
|
||
async function writeDatabaseRoot(rootId: string) { | ||
getDatabase().ref("qa").child(rootId).set({someField: "firebase realtime database"}); | ||
} | ||
|
||
// In other tests we use firebase-functions-test to wrap the function. | ||
// In this case it would look like: | ||
// const wrapped = fft.wrap(atMidnight); | ||
// However the wrapper doesn't support onSchedule: | ||
// - The Typescript types don't allow it | ||
// - at run time it doesn't pass the right event: | ||
// https://github.com/firebase/firebase-functions-test/issues/210 | ||
// So instead the code is separated from the onSchedule and called directly. | ||
|
||
describe("atMidnight", () => { | ||
beforeEach(async () => { | ||
await clearFirestoreData(projectConfig); | ||
await getDatabase().ref().set(null); | ||
}); | ||
|
||
test("clean up firestore roots", async () => { | ||
// The wrapper doesn't support onSchedule. The Typescript types don't allow it | ||
// and at run time it doesn't pass the right event: | ||
// https://github.com/firebase/firebase-functions-test/issues/210 | ||
// const wrapped = fft.wrap(atMidnight); | ||
test("clean up firestore roots with no database roots", async () => { | ||
await writeFirestoreRoot(); | ||
await runAtMidnight(); | ||
|
||
const roots = await getFirestore().collection("qa").get(); | ||
expect(roots.size).toBe(0); | ||
expect(logger.info) | ||
.toHaveBeenCalledWith("Found 1 roots to delete"); | ||
}); | ||
|
||
test("clean up firestore root and database root", async () => { | ||
const firestoreRoot = await writeFirestoreRoot(); | ||
await writeDatabaseRoot(firestoreRoot.id); | ||
|
||
await runAtMidnight(); | ||
|
||
const fsRoots = await getFirestore().collection("qa").get(); | ||
expect(fsRoots.size).toBe(0); | ||
const dbRoots = await getDatabase().ref("qa").get(); | ||
expect(dbRoots.val()).toEqual(null); | ||
expect(logger.info) | ||
.toHaveBeenCalledWith("Found 1 roots to delete"); | ||
}); | ||
|
||
test("only clean up firestore roots older than 6 hours", async () => { | ||
await writeFirestoreRoot(Date.now() - HOUR); | ||
await writeFirestoreRoot(Date.now() - 2*HOUR); | ||
await writeFirestoreRoot(Date.now() - 5*HOUR); | ||
await writeFirestoreRoot(Date.now() - 8*HOUR); | ||
await writeFirestoreRoot(Date.now() - 24*HOUR); | ||
|
||
await runAtMidnight(); | ||
|
||
const roots = await getFirestore().collection("qa").get(); | ||
expect(roots.size).toBe(3); | ||
expect(logger.info) | ||
.toHaveBeenCalledWith("Found 2 roots to delete"); | ||
}); | ||
|
||
afterAll(() => { | ||
fft.cleanup(); | ||
afterAll(async () => { | ||
await cleanup(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import {deleteApp, initializeApp} from "firebase-admin/app"; | ||
import initializeFFT from "firebase-functions-test"; | ||
|
||
export const projectConfig = { | ||
projectId: "demo-test", | ||
// This URL doesn't have to be valid, it just has to a non empty string | ||
// The actual database host will be picked up from | ||
// FIREBASE_DATABASE_EMULATOR_HOST | ||
// This is defined in jest.config.js | ||
databaseURL: "https://not-a-project.firebaseio.com", | ||
}; | ||
|
||
export function initialize() { | ||
const fft = initializeFFT(projectConfig); | ||
|
||
// When the function is running in the cloud initializeApp is called by index.ts | ||
// In our tests we import the function's module directly so we can call | ||
// initializeApp ourselves. This is beneficial since initializeApp needs to | ||
// be called after initializeFFT above. | ||
const fbApp = initializeApp(); | ||
|
||
const cleanup = async () => { | ||
fft.cleanup(); | ||
// Deleting the Firebase app is necessary for the Jest tests to exit when they | ||
// are complete. FFT creates a testApp which it deletes in cleanup(), but | ||
// we are not using this testApp. | ||
await deleteApp(fbApp); | ||
}; | ||
return {fft, fbApp, cleanup}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters