Skip to content

rules-unit-testing, storage uploadBytes and uploadString never resolve #6530

Open
@kris-kolve-jumio

Description

@kris-kolve-jumio

[REQUIRED] Describe your environment

  • Operating System version: macOS v12.4
  • Browser version: Chrom 104.0.5112.79 (not relevant testing in vsCode with mocha)
  • Firebase SDK version: 9.9.2
  • Firebase tools version: 2.0.4
  • Mocha version:10.0.0
  • Firebase-tools version: 11.6.0
  • Firebase Product: rules-unit-testing; storage

[REQUIRED] Describe the problem

uploadBytes and uploadString storage functions do not resolve when using the @firebase/rules-unit-testing library. This causes the test to timeout even at 20+seconds.

This occurs with authenticatedContext, and unauthenticated contexts.

It is also worth noting that, getBytes, and getDownloadURL, resolve as expected.

I get the same results using Mocha and Jest. I have even tried the v8 SDK with the same results.

I did not have the upload issue when using the Admin SDK with the emulators. I have not tried it yet in my app but suspect it will work as desired.

Steps to reproduce:

  1. Create a firebase project and install Mocha and rules-unit-testing along with SDK
  2. TestEnvironment:
    a. host:"127.0.0.1"
    b. port:
  3. Create a testing folder and add a spec file for the test.
  4. in the test, create an unauthenticated context,
  5. attempt to upload using uploadBytes.

Result: upload promise will never resolve.

Expected Result: upload promise resolves well within a second and the test will fail (assuming the rules prevent uploads from unauthenticated users.

If I do not set the hub host to "127.0.0.1" I will get an ECCONREFUSED ::1:4400. Also interesting and possibly related:

  1. Setting the hub:{host:"127.0.0.1", port:4400} does not make storage discoverable and also does not throw an ECCONREFUSED ::1. However, it does make it so the getBytes test ends up throwing a "FirebaseError: Firebase Storage: Max retry time for operation exceeded"

  2. Setting the storage:{host:"127.0.0.1", port:9199} seems to make the storage discoverable. getBytes will resolve but uploadBytes will never resolve... I wonder if the host configuration is not propagating to post commands sent to the emulators? IDK.

Relevant Code:

storage.rules -

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {

      function canRead(){
        return request.auth != null &&
          request.auth.token.email != null &&
          request.auth.token.email_verified ;
      }
      allow read: if canRead(); //ONLY ALLOW AUTHENTICATED USERS TO READ DATA
      allow write: if false; // Never allow writing
    }
  }
}

Note: it is necessary to add type:'module' in the package file so that imports work.

index.spec.js - TEST FILE

import * as fbTesting from "@firebase/rules-unit-testing"
import http from 'http'
import {readFileSync, createWriteStream} from 'fs'
// import firebase from 'firebase'
import assert from 'assert'
import { ref as storRef, deleteObject, uploadString, listAll, uploadBytes, getBytes } from "firebase/storage";
import 'mocha'

const {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment,
} = fbTesting

const host = '127.0.0.1'
const port = 9199

/** 
   * @type {fbTesting.RulesTestEnvironment}
   */
let testEnv;

before(async ()=>{
  testEnv = await initializeTestEnvironment({
    projectId: 'demo-data-visualization',
    hub:{host, port:4400},
    storage:{ host,port:9199},
    
  })
  console.log("test Environment Created", testEnv.projectId, testEnv.emulators)
})

after("Cleaning up", async ()=>{
  await testEnv.cleanup()
})

describe("Testing the Storage Security Rules", function() {
  this.timeout(20000)

  describe("An Un-Authenticated user,", ()=>{

    /** @type {fbTesting.storage.Storage} */
    let alice
    before("Creating Unauth User",async ()=>{
      testEnv.clearStorage()
      const context = testEnv.unauthenticatedContext()
      alice = context.storage();
      // console.log(alice)
    })

    it("Can NOT read from storage", async ()=>{
      // console.log(alice)
      // THIS TEST WORKS
      const ref = storRef(alice, 'data.json')
      const blob = getBytes(ref)
      await assertFails(blob)
    })

    it("Can NOT upload a file", async ()=>{

      //THIS TEST TIMES OUT IN 20 seconds
      const ref = storRef(alice, 'data/test.json')
      const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21]);
      const upload = uploadBytes(ref, bytes, {contentType:'application/octet-stream'})
      await assertFails(upload)
    })
  })

})

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions