Skip to content

Commit

Permalink
Merge branch 'tc-poller' of github.com:firebase/firebase-tools into t…
Browse files Browse the repository at this point in the history
…c-poller
  • Loading branch information
TrCaM committed Jun 24, 2019
2 parents 9a81804 + 0907f95 commit fa22f42
Show file tree
Hide file tree
Showing 13 changed files with 639 additions and 5 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ jobs:
before_script: ./scripts/decrypt-app-credentials.sh
script: ./scripts/test-hosting.sh
after_script: skip
- stage: emulator triggers end to end test
if: repo == head_repo OR type == push
node_js: "8"
before_script: skip
script: ./scripts/test-triggers-end-to-end.sh
after_script: skip
cache:
directories:
- node_modules
3 changes: 2 additions & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* Fixes a bug where the functions emulator did not work with `firebase-functions` versions `3.x.x`.
* Make the Functions emulator automatically point to the RTDB emulator when running.
* Make the Functions emulator automatically point to the RTDB emulator when running.
* Fixes issue where the functions runtime would not always exit on success (#1346).
18 changes: 18 additions & 0 deletions scripts/test-triggers-end-to-end.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

set -xe

FIREBASE_CLI="./lib/bin/firebase.js"

if ! [ -x $FIREBASE_CLI ];
then
echo "marking $FIREBASE_CLI user/group executable"
chmod ug+x $FIREBASE_CLI
fi;

$FIREBASE_CLI setup:emulators:firestore
$FIREBASE_CLI setup:emulators:database

cd ./scripts/triggers-end-to-end-tests

npm install && npm test
5 changes: 5 additions & 0 deletions scripts/triggers-end-to-end-tests/.firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projects": {
"default": "fir-tools-testing"
}
}
67 changes: 67 additions & 0 deletions scripts/triggers-end-to-end-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
firebase-debug.log*
database-debug.log*
firestore-debug.log*

# Firebase cache
.firebase/

# Firebase config

# Uncomment this if you'd like others to create their own Firebase project.
# For a team working on the same Firebase project(s), it is recommended to leave
# it commented so all members can deploy to the same project(s) in .firebaserc.
# .firebaserc

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
86 changes: 86 additions & 0 deletions scripts/triggers-end-to-end-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# End-to-end Tests for Emulator Function Triggers

This test exercises support for Realtime Database function triggers as
introduced in the following PRs:

- https://github.com/firebase/firebase-tools/pull/1347
- https://github.com/firebase/firebase-tools/pull/1411

# Running Instructions

Install dependencies:
```
cd firebase-tools/scripts/triggers-end-to-end-tests && npm install
```

Run the test:
```
$ cd firebase-tools/scripts/triggers-end-to-end-tests && npm test
```

This end-to-end test uses the mocha testing framework.

## Verification

The test spins up a functions, database, and firestore emulator to verify the
following:

1. The functions emulator (firebase-tools >= v7.0.0) can register
[triggers](https://firebase.google.com/docs/functions/database-events)
with database emulators (>= v4.0.0).
2. The database emulator (>= v4.0.0) can invoke functions served by a local
functions emulator instance.
3. Functions served by the functions emulator may be defined to operate on a
local database emulator instance using the
[node.js admin SDK](https://github.com/firebase/firebase-admin-node) (and are
configured to do so by default).
4. Local functions triggered by a database emulator event may operate on a local
firestore emulator instance using the node.js admin SDK.
5. Local functions triggered by a firestore emulator event may operate on both local
database emulators (>= v4.0.0) and the invoking firestore emulator using the
node.js admin SDK.

At a high level, this test verifies the use of cloud functions as a
bidirectional communication channel between the database emulator and Firestore.

## Implementation

To verify (2), the test installs the following http function:

```javascript
exports.writeToRtdb = functions.https.onRequest(async (req, res) => {
const ref = admin.database().ref(START_DOCUMENT_NAME);
await ref.set({ start: (new Date().toISOString()) });
ref.once('value', (snap) => {
res.json({ data: snap });
});
});
```

This function performs a document write that triggers the following realtime
database function:

```javascript
exports.rtdbReaction = functions.database.ref(START_DOCUMENT_NAME).onWrite(async (change, ctx) => {
console.log(RTDB_FUNCTION_LOG);

const ref = admin.database().ref(END_DOCUMENT_NAME + "_from_database");
await ref.set({ done: (new Date().toISOString()) });

const firestoreref = admin.firestore().doc(END_DOCUMENT_NAME + "_from_database");
await firestoreref.set({ done: (new Date().toISOString()) });

return true;
});
```
The driver program for the end-to-end test has spawned the functions emulator as
a subprocess and searches for the presence of `RTDB_FUNCTION_LOG` in the process
to confirm (2).

In addition to printing a marker, the above database function also uses the
admin SDK to write "completion markers" back to the realtime database and
firestore emulators and a local firestore emulator. The test uses the presence of
these markers is checked by the driver program to confirm (3) and (4).

(5) is confirmed using analogous http and firestore-triggered functions. For
brevity, they are not reproduced here.
18 changes: 18 additions & 0 deletions scripts/triggers-end-to-end-tests/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"database": {},
"firestore": {
"rules": "firestore.rules"
},
"functions": {},
"emulators": {
"database": {
"port": 9000
},
"firestore": {
"port": 9001
},
"functions": {
"port": 9002
}
}
}
3 changes: 3 additions & 0 deletions scripts/triggers-end-to-end-tests/functions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
.eslintrc
package-lock.json
78 changes: 78 additions & 0 deletions scripts/triggers-end-to-end-tests/functions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const admin = require("firebase-admin");
const functions = require("firebase-functions");

/*
* Log snippets that the driver program above checks for. Be sure to update
* ../test.js if you plan on changing these.
*/
const RTDB_FUNCTION_LOG = '========== RTDB FUNCTION ==========';
const FIRESTORE_FUNCTION_LOG = '========== FIRESTORE FUNCTION ==========';

/*
* We install onWrite triggers for START_DOCUMENT_NAME in both the firestore and
* database emulators. From each respective onWrite trigger, we write a document
* to both the firestore and database emulators. This exercises the
* bidirectional communication between cloud functions and each emulator.
*/
const START_DOCUMENT_NAME = "test/start";
const END_DOCUMENT_NAME = "test/done";

admin.initializeApp();

exports.deleteFromFirestore = functions.https.onRequest(async (req, res) => {
await admin.firestore().doc(START_DOCUMENT_NAME).delete();
res.json({ deleted: true });
});

exports.deleteFromRtdb = functions.https.onRequest(async (req, res) => {
await admin.database().ref(START_DOCUMENT_NAME).remove();
res.json({ deleted: true });
});

exports.writeToFirestore = functions.https.onRequest(async (req, res) => {
const ref = admin.firestore().doc(START_DOCUMENT_NAME);
await ref.set({ start: (new Date().toISOString()) });
ref.get().then((snap) => {
res.json({ data: snap.data() });
});
});

exports.writeToRtdb = functions.https.onRequest(async (req, res) => {
const ref = admin.database().ref(START_DOCUMENT_NAME);
await ref.set({ start: (new Date().toISOString()) });
ref.once('value', (snap) => {
res.json({ data: snap });
});
});

exports.firestoreReaction = functions.firestore.document(START_DOCUMENT_NAME).onWrite(async (change, ctx) => {
console.log(FIRESTORE_FUNCTION_LOG);
/*
* Write back a completion timestamp to the firestore emulator. The test
* driver program checks for this by querying the firestore emulator
* directly.
*/
const ref = admin.firestore().doc(END_DOCUMENT_NAME + "_from_firestore");
await ref.set({ done: (new Date().toISOString()) });

/*
* Write a completion marker to the firestore emulator. This exercise
* cross-emulator communication.
*/
const dbref = admin.database().ref(END_DOCUMENT_NAME + "_from_firestore");
await dbref.set({ done: (new Date().toISOString()) });

return true;
});

exports.rtdbReaction = functions.database.ref(START_DOCUMENT_NAME).onWrite(async (change, ctx) => {
console.log(RTDB_FUNCTION_LOG);

const ref = admin.database().ref(END_DOCUMENT_NAME + "_from_database");
await ref.set({ done: (new Date().toISOString()) });

const firestoreref = admin.firestore().doc(END_DOCUMENT_NAME + "_from_database");
await firestoreref.set({ done: (new Date().toISOString()) });

return true;
});
22 changes: 22 additions & 0 deletions scripts/triggers-end-to-end-tests/functions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase serve --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "8"
},
"dependencies": {
"firebase-admin": "^8.0.0",
"firebase-functions": "^3.0.0"
},
"devDependencies": {
"firebase-functions-test": "^0.1.6"
},
"private": true
}
16 changes: 16 additions & 0 deletions scripts/triggers-end-to-end-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "triggers-end-to-end-tests",
"version": "1.0.0",
"description": "End-to-end tests for emulator cloud function triggers",
"main": "run.spec.js",
"scripts": {
"test": "./node_modules/mocha/bin/mocha run.spec.js --reporter spec --exit"
},
"dependencies": {
"async": "^3.0.1",
"grpc": "^1.21.0",
"mocha": "^5.0.5"
},
"author": "",
"license": "ISC"
}
Loading

0 comments on commit fa22f42

Please sign in to comment.