Description
[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:
- Create a firebase project and install Mocha and rules-unit-testing along with SDK
- TestEnvironment:
a. host:"127.0.0.1"
b. port: - Create a testing folder and add a spec file for the test.
- in the test, create an unauthenticated context,
- 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:
-
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"
-
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)
})
})
})