Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting metadata from plugin failed with error: invalid_grant #3098

Closed
markgoho opened this issue Jan 29, 2021 · 7 comments
Closed

Getting metadata from plugin failed with error: invalid_grant #3098

markgoho opened this issue Jan 29, 2021 · 7 comments
Assignees

Comments

@markgoho
Copy link

markgoho commented Jan 29, 2021

[REQUIRED] Environment info

firebase-tools: 9.2.2

Platform: Windows

[REQUIRED] Test case

Trying to test an HTTP onRequest function that writes to the emulated Firestore.

[REQUIRED] Steps to reproduce

index.ts

import * as functions from 'firebase-functions';

export const testFirestoreWrite = functions.https.onRequest(
  async (request, response) => {
    await (await import('./testWrite')).testWrite(request, response);
  },
);

testWrite.ts

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

admin.initializeApp();

export async function testWrite(
  request: functions.https.Request,
  response: functions.Response<unknown>,
) {
  const body = request.body;
  const { collection, docId, doc } = body;
  console.log({ collection, docId, doc });
  try {
    await admin.firestore().collection(collection).doc(docId).create(doc);
  } catch (e) {
    console.error(e);
  }
  response.send(body);
}

functions.spec.js

const { expect } = require('chai');
const test = require('firebase-functions-test')({
  projectId: process.env.GCLOUD_PROJECT,
});
const admin = require('firebase-admin');
const myFunctions = require('../lib/index');

describe('Unit tests', () => {
  after(() => {
    test.cleanup();
  });

  it('tests a firestore write', async () => {
    const req = {
      body: {
        collection: 'test-collection',
        docId: 'abc1234',
        doc: { name: 'Mark Goho' },
      },
    };

    const sendPromise = new Promise(resolve => {
      const res = {
        send: text => { resolve(text); },
      };
      myFunctions.testFirestoreWrite(req, res);
    });

    const body = await sendPromise;
    expect(body).to.eq(req.body);
  });
});

[REQUIRED] Expected behavior

Currently this test passes because the assertion evaluates to true, but I'd also expect the firestore write to succeed as well.

[REQUIRED] Actual behavior

  • I've started the emulator with cross-env GCLOUD_PROJECT=fakeproject firebase emulators:start --project=fakeproject --only=firestore,functions,auth
  • Functions directory is being watched with tsc watch
  • Tests are running with mocha functions.spec.js --exit

This is the error output (from the try/catch block above):

Error: 400 undefined: Getting metadata from plugin failed with error: invalid_grant
    at Object.callErrorFromStatus (C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\node_modules\@grpc\grpc-js\build\src\call.js:31:26)
    at Object.onReceiveStatus (C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\node_modules\@grpc\grpc-js\build\src\client.js:176:52)
    at Object.onReceiveStatus (C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\node_modules\@grpc\grpc-js\build\src\client-interceptors.js:334:141)
    at Object.onReceiveStatus (C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\node_modules\@grpc\grpc-js\build\src\client-interceptors.js:297:181)
    at C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\node_modules\@grpc\grpc-js\build\src\call-stream.js:130:78
    at processTicksAndRejections (internal/process/task_queues.js:79:11)
Caused by: Error
    at WriteBatch.commit (C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\node_modules\@google-cloud\firestore\build\src\write-batch.js:426:23)
    at DocumentReference.create (C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\node_modules\@google-cloud\firestore\build\src\reference.js:285:14)
    at Object.testWrite (C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\lib\testWrite.js:11:67)
    at C:\Users\Mark\Documents\IdeaCrew\active-branch-tracker\functions\lib\index.js:28:72 {
  code: '400',
  details: 'Getting metadata from plugin failed with error: invalid_grant',
  metadata: Metadata { internalRepr: Map {}, options: {} },
  note: 'Exception occurred in retry method that was not classified as transient'
}

Side Note

This would be a great quickstart testing example to include in https://github.com/firebase/quickstart-testing

UPDATE:

When running firebase emulators:exec 'npm run test' I am not getting these errors. I can't discern what the difference is when running emulators using this command vs. firebase emulators:start

@markgoho
Copy link
Author

markgoho commented Feb 1, 2021

Found an interesting thread on Reddit where a person wants to connect to prod but is getting this error. Is that what's happening here? Somehow my code is trying to reach out to the production Firestore?

@kmcnellis
Copy link
Member

When running your test with firebase emulators:exec, the cli is automatically setting some environment variables for you, corresponding to the hostname/port of each emulator. [source] The admin sdk in your function under test will look for those variables to correctly connect to the firestore emulator instead of production

However, since you are directly calling the functions code via mocha, those environment variables aren't set, and your code is connecting to production. The error is generally related to the gcloud cli (see firebase/firebase-functions#121), and should go away by talking to the emulators instead.

You can either run the test by using firebase emulators:exec, or by changing your test to make the request over the network (running firebase emulators:start outputs the address you'd need to call - mine is localhost:5001, for example)

@markgoho
Copy link
Author

markgoho commented Feb 2, 2021

changing your test to make the request over the network (running firebase emulators:start outputs the address you'd need to call - mine is localhost:5001, for example)

@kmcnellis can you point me to an example of this? I have no idea what changing your test to make the request over the network means

@kmcnellis
Copy link
Member

I mean by using the node http package, or something like axios. It's an HTTP onRequest function, so you can just do a GET or POST request to localhost:5001/testFirestoreWrite

@markgoho
Copy link
Author

markgoho commented Feb 2, 2021

Ah hah!

So this kind of makes sense. You're saying because the functions are exposed locally (localhost:number), I can tweak my tests to just use a node-based http library to just hit the endpoints, and then test the outcome of those functions.

Is this documented anywhere officially? I feel like the documentation around local testing (now that we have emulators) hasn't quite kept up with the speed of development (not a terrible problem!). Repos like the quickstart-testing are great, but we need more examples of how to perform these common actions with emulators.

@samtstern do you think that quickstart repo (the simple HTTP function) could be altered/added-to to show this strategy that @kmcnellis is suggesting? i.e. would that be the right place to document this approach?

@kmcnellis kmcnellis assigned samedson, samtstern and yuchenshi and unassigned samedson Feb 2, 2021
@kmcnellis kmcnellis reopened this Feb 2, 2021
@samtstern
Copy link
Contributor

For other people who get the invalid_grant issue and are trying to access production it may mean that your token is invalid for some reason and you need to log in again. Try running:

firebase login --reauth

and

gcloud auth application-default login

@samtstern
Copy link
Contributor

I opened firebase/quickstart-testing#97 to track improving the documentation! Closing this here as I don't think there's a CLI bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants