Skip to content

Commit

Permalink
Merge 17434b5 into 94bc2b4
Browse files Browse the repository at this point in the history
  • Loading branch information
samtstern committed Nov 15, 2019
2 parents 94bc2b4 + 17434b5 commit ceffb84
Show file tree
Hide file tree
Showing 29 changed files with 970 additions and 228 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
@@ -1,5 +1,7 @@
* Fixes a bug where the Cloud Functions emulator ignored the "host" configuration (#1722).
* Fixes a bug where the Cloud Functions emulator accepted requests to too many paths (#1773).
* Fixes a bug where the Functions emulator ignored the "host" configuration (#1722)
* Fixes a bug where the Functions emulator accepted requests to too many paths (#1773)
* Modifies `firebase ext:update` to not perform update if the extension is already up to date.
* Print Firebase Console links for Extensions after operations.
* Updated Firebase Extensions registry address.
* Adds the `firebase init emulators` command.
* Adds a Cloud Pub/Sub Emulator (#1748).
424 changes: 292 additions & 132 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -62,6 +62,7 @@
]
},
"dependencies": {
"@google-cloud/pubsub": "^1.1.5",
"JSONStream": "^1.2.1",
"archiver": "^3.0.0",
"body-parser": "^1.19.0",
Expand Down Expand Up @@ -101,6 +102,7 @@
"tcp-port-used": "^1.0.1",
"tmp": "0.0.33",
"universal-analytics": "^0.4.16",
"unzipper": "^0.10.5",
"update-notifier": "^2.5.0",
"uuid": "^3.0.0",
"winston": "^1.0.1"
Expand Down Expand Up @@ -132,6 +134,7 @@
"@types/tar": "^4.0.0",
"@types/tcp-port-used": "^1.0.0",
"@types/tmp": "^0.1.0",
"@types/unzipper": "^0.10.0",
"@types/uuid": "^3.4.4",
"@types/winston": "^2.4.4",
"@typescript-eslint/eslint-plugin": "^2.3.0",
Expand Down
12 changes: 8 additions & 4 deletions scripts/set-default-credentials.sh
Expand Up @@ -9,10 +9,14 @@ if [ "${TRAVIS}" != "true" ]; then
export TRAVIS_REPO_SLUG="firebase/firebase-tools"
fi

GOOGLE_APPLICATION_CREDENTIALS="${CWD}/scripts/creds-private.json"
if [ "${TRAVIS_REPO_SLUG}" == "firebase/firebase-tools" ]; then
GOOGLE_APPLICATION_CREDENTIALS="${CWD}/scripts/creds-public.json"
if [[ -z $LOCAL ]]; then
GOOGLE_APPLICATION_CREDENTIALS="${CWD}/scripts/creds-private.json"
if [ "${TRAVIS_REPO_SLUG}" == "firebase/firebase-tools" ]; then
GOOGLE_APPLICATION_CREDENTIALS="${CWD}/scripts/creds-public.json"
fi
export GOOGLE_APPLICATION_CREDENTIALS
else
echo "Not setting GOOGLE_APPLICATION_CREDENTIALS because LOCAL=${LOCAL}"
fi
export GOOGLE_APPLICATION_CREDENTIALS

echo "Application Default Credentials: ${GOOGLE_APPLICATION_CREDENTIALS}"
5 changes: 2 additions & 3 deletions scripts/test-triggers-end-to-end.sh
@@ -1,4 +1,6 @@
#!/bin/bash
# To run this command locally:
# LOCAL=true FBTOOLS_TARGET_PROJECT={{YOUR_PROJECT}} ./scripts/test-triggers-end-to-end.sh
set -xe
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

Expand All @@ -12,9 +14,6 @@ then
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
1 change: 1 addition & 0 deletions scripts/triggers-end-to-end-tests/.gitignore
Expand Up @@ -7,6 +7,7 @@ yarn-error.log*
firebase-debug.log*
database-debug.log*
firestore-debug.log*
pubsub-debug.log*

# Firebase cache
.firebase/
Expand Down
3 changes: 3 additions & 0 deletions scripts/triggers-end-to-end-tests/firebase.json
Expand Up @@ -13,6 +13,9 @@
},
"functions": {
"port": 9002
},
"pubsub": {
"port": 8085
}
}
}
19 changes: 19 additions & 0 deletions scripts/triggers-end-to-end-tests/functions/index.js
@@ -1,12 +1,14 @@
const admin = require("firebase-admin");
const functions = require("firebase-functions");
const { PubSub } = require("@google-cloud/pubsub");

/*
* 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 ==========";
const PUBSUB_FUNCTION_LOG = "========== PUBSUB FUNCTION ==========";

/*
* We install onWrite triggers for START_DOCUMENT_NAME in both the firestore and
Expand All @@ -17,6 +19,9 @@ const FIRESTORE_FUNCTION_LOG = "========== FIRESTORE FUNCTION ==========";
const START_DOCUMENT_NAME = "test/start";
const END_DOCUMENT_NAME = "test/done";

const PUBSUB_TOPIC = "test-topic";

const pubsub = new PubSub();
admin.initializeApp();

exports.deleteFromFirestore = functions.https.onRequest(async (req, res) => {
Expand Down Expand Up @@ -51,6 +56,13 @@ exports.writeToRtdb = functions.https.onRequest(async (req, res) => {
});
});

exports.writeToPubsub = functions.https.onRequest(async (req, res) => {
const msg = await pubsub.topic(PUBSUB_TOPIC).publishJSON({ foo: "bar" }, { attr: "val" });
console.log("PubSub Emulator Host", process.env.PUBSUB_EMULATOR_HOST);
console.log("Wrote PubSub Message", msg);
res.json({ published: "ok" });
});

exports.firestoreReaction = functions.firestore
.document(START_DOCUMENT_NAME)
.onWrite(async (/* change, ctx */) => {
Expand Down Expand Up @@ -86,3 +98,10 @@ exports.rtdbReaction = functions.database

return true;
});

exports.pubsubReaction = functions.pubsub.topic(PUBSUB_TOPIC).onPublish((msg /* , ctx */) => {
console.log(PUBSUB_FUNCTION_LOG);
console.log("Message", JSON.stringify(msg.json));
console.log("Attributes", JSON.stringify(msg.attributes));
return true;
});
3 changes: 2 additions & 1 deletion scripts/triggers-end-to-end-tests/functions/package.json
Expand Up @@ -12,8 +12,9 @@
"node": "8"
},
"dependencies": {
"@google-cloud/pubsub": "^1.1.5",
"firebase-admin": "^8.0.0",
"firebase-functions": "^3.1.0"
"firebase-functions": "^3.3.0"
},
"devDependencies": {
"firebase-functions-test": "^0.1.6"
Expand Down
110 changes: 86 additions & 24 deletions scripts/triggers-end-to-end-tests/run.spec.js
Expand Up @@ -24,6 +24,7 @@ const FIREBASE_PROJECT_ZONE = "us-central1";
*/
const RTDB_FUNCTION_LOG = "========== RTDB FUNCTION ==========";
const FIRESTORE_FUNCTION_LOG = "========== FIRESTORE FUNCTION ==========";
const PUBSUB_FUNCTION_LOG = "========== PUBSUB FUNCTION ==========";

/*
* Various delays that are needed because this test spawns
Expand Down Expand Up @@ -52,8 +53,12 @@ function TriggerEndToEndTest(config) {
this.functions_emulator_host = "localhost";
this.functions_emulator_port = config.emulators.functions.port;

this.pubsub_emulator_host = "localhost";
this.pubsub_emulator_port = config.emulators.pubsub.port;

this.rtdb_trigger_count = 0;
this.firestore_trigger_count = 0;
this.pubsub_trigger_count = 0;

this.rtdb_from_firestore = false;
this.firestore_from_rtdb = false;
Expand All @@ -77,14 +82,20 @@ TriggerEndToEndTest.prototype.success = function success() {
);
};

TriggerEndToEndTest.prototype.startEmulators = function startEmulators() {
TriggerEndToEndTest.prototype.startEmulators = function startEmulators(additionalArgs) {
var self = this;
self.emulators_process = subprocess.spawn("node", [
const args = [
PROJECT_ROOT + "/lib/bin/firebase.js",
"emulators:start",
"--project",
FIREBASE_PROJECT,
]);
];

if (additionalArgs) {
args.push(...additionalArgs);
}

self.emulators_process = subprocess.spawn("node", args);

self.emulators_process.stdout.on("data", function(data) {
process.stdout.write("[emulators stdout] " + data);
Expand All @@ -94,6 +105,9 @@ TriggerEndToEndTest.prototype.startEmulators = function startEmulators() {
if (data.indexOf(FIRESTORE_FUNCTION_LOG) > -1) {
self.firestore_trigger_count++;
}
if (data.indexOf(PUBSUB_FUNCTION_LOG) > -1) {
self.pubsub_trigger_count++;
}
});

self.emulators_process.stderr.on("data", function(data) {
Expand All @@ -112,12 +126,10 @@ TriggerEndToEndTest.prototype.stopEmulators = function stopEmulators(done) {
this.emulators_process.kill("SIGINT");
};

TriggerEndToEndTest.prototype.writeToRtdb = function writeToRtdb(done) {
TriggerEndToEndTest.prototype.invokeHttpFunction = function invokeHttpFunction(name, done) {
var url =
"http://localhost:" +
[this.functions_emulator_port, FIREBASE_PROJECT, FIREBASE_PROJECT_ZONE, "writeToRtdb"].join(
"/"
);
[this.functions_emulator_port, FIREBASE_PROJECT, FIREBASE_PROJECT_ZONE, name].join("/");

const req = request.get(url);

Expand All @@ -130,24 +142,16 @@ TriggerEndToEndTest.prototype.writeToRtdb = function writeToRtdb(done) {
});
};

TriggerEndToEndTest.prototype.writeToFirestore = function writeToFirestore(done) {
var url =
"http://localhost:" +
[
this.functions_emulator_port,
FIREBASE_PROJECT,
FIREBASE_PROJECT_ZONE,
"writeToFirestore",
].join("/");
TriggerEndToEndTest.prototype.writeToRtdb = function writeToRtdb(done) {
return this.invokeHttpFunction("writeToRtdb", done);
};

const req = request.get(url);
TriggerEndToEndTest.prototype.writeToFirestore = function writeToFirestore(done) {
return this.invokeHttpFunction("writeToFirestore", done);
};

req.once("response", function(response) {
done(null, response);
});
req.once("error", function(err) {
done(err);
});
TriggerEndToEndTest.prototype.writeToPubsub = function writeToPubsub(done) {
return this.invokeHttpFunction("writeToPubsub", done);
};

function readConfig(done) {
Expand Down Expand Up @@ -189,7 +193,7 @@ describe("database and firestore emulator function triggers", function() {
});
},
function(done) {
test.startEmulators();
test.startEmulators(["--only", "functions,database,firestore"]);
/*
* Give some time for the emulator subprocesses to start up.
*/
Expand Down Expand Up @@ -287,6 +291,15 @@ describe("database and firestore emulator function triggers", function() {
);
});

after(function(done) {
this.timeout(EMULATORS_SHUTDOWN_DELAY_MS);
if (test) {
test.stopEmulators(done);
return;
}
done();
});

it("should write to the database emulator", function(done) {
this.timeout(EMULATOR_TEST_TIMEOUT);

Expand Down Expand Up @@ -325,6 +338,40 @@ describe("database and firestore emulator function triggers", function() {
expect(test.success()).to.equal(true);
done();
});
});

describe("pubsub emulator function triggers", function() {
var test;

before(function(done) {
this.timeout(TEST_SETUP_TIMEOUT);

expect(FIREBASE_PROJECT).to.not.be.an("undefined");
expect(FIREBASE_PROJECT).to.not.be.null;

async.series(
[
function(done) {
readConfig(function(err, config) {
if (err) {
done(new Error("error reading firebase.json: " + err));
return;
}
test = new TriggerEndToEndTest(config);
done();
});
},
function(done) {
test.startEmulators(["--only", "functions,pubsub"]);
/*
* Give some time for the emulator subprocesses to start up.
*/
setTimeout(done, EMULATORS_STARTUP_DELAY_MS);
},
],
done
);
});

after(function(done) {
this.timeout(EMULATORS_SHUTDOWN_DELAY_MS);
Expand All @@ -334,4 +381,19 @@ describe("database and firestore emulator function triggers", function() {
}
done();
});

it("should write to the pubsub emulator", function(done) {
this.timeout(EMULATOR_TEST_TIMEOUT);

test.writeToPubsub(function(err, response) {
expect(err).to.be.null;
expect(response.statusCode).to.equal(200);
setTimeout(done, EMULATORS_WRITE_DELAY_MS);
});
});

it("should have have triggered cloud functions", function(done) {
expect(test.pubsub_trigger_count).to.equal(1);
done();
});
});
1 change: 1 addition & 0 deletions src/commands/index.js
Expand Up @@ -79,6 +79,7 @@ module.exports = function(client) {
client.setup.emulators = {};
client.setup.emulators.database = loadCommand("setup-emulators-database");
client.setup.emulators.firestore = loadCommand("setup-emulators-firestore");
client.setup.emulators.pubsub = loadCommand("setup-emulators-pubsub");
client.setup.web = loadCommand("setup-web");
client.target = loadCommand("target");
client.target.apply = loadCommand("target-apply");
Expand Down
5 changes: 5 additions & 0 deletions src/commands/init.js
Expand Up @@ -95,6 +95,11 @@ module.exports = new Command("init [feature]")
name: "Storage: Deploy Cloud Storage security rules",
checked: false,
},
{
value: "emulators",
name: "Emulators: Set up local emulators for Firebase features",
checked: false,
},
];

var next;
Expand Down
10 changes: 10 additions & 0 deletions src/commands/setup-emulators-pubsub.ts
@@ -0,0 +1,10 @@
import { Command } from "../command";
const downloadEmulator = require("../emulator/download");

const EMULATOR_NAME = "pubsub";

module.exports = new Command(`setup:emulators:${EMULATOR_NAME}`)
.description(`downloads the ${EMULATOR_NAME} emulator`)
.action(() => {
return downloadEmulator(EMULATOR_NAME);
});
4 changes: 4 additions & 0 deletions src/emulator/constants.ts
Expand Up @@ -7,6 +7,7 @@ const DEFAULT_PORTS: { [s in Emulators]: number } = {
functions: 5001,
firestore: 8080,
database: 9000,
pubsub: 8085,
};

const DEFAULT_HOST = "localhost";
Expand All @@ -16,13 +17,16 @@ export class Constants {

static SERVICE_FIRESTORE = "firestore.googleapis.com";
static SERVICE_REALTIME_DATABASE = "firebaseio.com";
static SERVICE_PUBSUB = "pubsub.googleapis.com";

static getServiceName(service: string): string {
switch (service) {
case this.SERVICE_FIRESTORE:
return "firestore";
case this.SERVICE_REALTIME_DATABASE:
return "database";
case this.SERVICE_PUBSUB:
return "pubsub";
default:
return service;
}
Expand Down

0 comments on commit ceffb84

Please sign in to comment.