Files

229 lines
7.9 KiB
TypeScript

/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '../setup';
import { expect } from 'chai';
import { stub } from 'sinon';
import * as modularStorage from '@firebase/storage';
import { makeTestCompatStorage, fakeApp, fakeStorage } from '../utils';
import { FirebaseStorage, getStorage, StorageError } from '@firebase/storage';
import firebase from '@firebase/app-compat';
import { StorageServiceCompat } from '../../src/service';
import { FirebaseApp } from '@firebase/app-types';
const DEFAULT_HOST = 'firebasestorage.googleapis.com';
describe('Firebase Storage > Service', () => {
describe('useEmulator(host, port)', () => {
it('calls connectStorageEmulator() correctly', () => {
const connectStorageEmulatorStub = stub(
modularStorage,
'connectStorageEmulator'
).callsFake(() => {});
const service = makeTestCompatStorage(fakeApp, fakeStorage);
service.useEmulator('test.host.org', 1234);
expect(connectStorageEmulatorStub).to.have.been.calledWithExactly(
fakeStorage,
'test.host.org',
1234,
{}
);
});
});
describe('refFromURL', () => {
let service: StorageServiceCompat;
let testCompatApp: FirebaseApp;
let testModularStorage: FirebaseStorage;
before(() => {
testCompatApp = firebase.initializeApp({});
testModularStorage = getStorage(testCompatApp);
service = makeTestCompatStorage(testCompatApp, testModularStorage);
});
after(() => {
return testCompatApp.delete();
});
it('Works with gs:// URLs', () => {
const ref = service.refFromURL('gs://mybucket/child/path/image.png');
expect(ref.toString()).to.equal('gs://mybucket/child/path/image.png');
});
it('Works with http:// URLs', () => {
const ref = service.refFromURL(
`http://${DEFAULT_HOST}/v0/b/` +
'mybucket/o/child%2Fpath%2Fimage.png?downloadToken=hello'
);
expect(ref.toString()).to.equal('gs://mybucket/child/path/image.png');
});
it('Works with https:// URLs', () => {
const ref = service.refFromURL(
`https://${DEFAULT_HOST}/v0/b/` +
'mybucket/o/child%2Fpath%2Fimage.png?downloadToken=hello'
);
expect(ref.toString()).to.equal('gs://mybucket/child/path/image.png');
});
it('Works with storage.googleapis.com URLs', () => {
const ref = service.refFromURL(
`https://storage.googleapis.com/mybucket/path%20with%20space/image.png`
);
expect(ref.toString()).to.equal(
'gs://mybucket/path with space/image.png'
);
});
it('Works with storage.googleapis.com URLs with query params', () => {
const ref = service.refFromURL(
`https://storage.googleapis.com/mybucket/path%20with%20space/image.png?X-Goog-Algorithm=
GOOG4-RSA-SHA256`
);
expect(ref.toString()).to.equal(
'gs://mybucket/path with space/image.png'
);
});
it('Works with storage.cloud.google.com URLs', () => {
const ref = service.refFromURL(
`https://storage.cloud.google.com/mybucket/path%20with%20space/image.png`
);
expect(ref.toString()).to.equal(
'gs://mybucket/path with space/image.png'
);
});
it('Works with storage.cloud.google.com URLs and escaped slash', () => {
const ref = service.refFromURL(
`https://storage.cloud.google.com/mybucket/path%20with%20space%2Fimage.png`
);
expect(ref.toString()).to.equal(
'gs://mybucket/path with space/image.png'
);
});
});
describe('Argument verification', () => {
let service: StorageServiceCompat;
let testCompatApp: FirebaseApp;
let testModularStorage: FirebaseStorage;
before(() => {
testCompatApp = firebase.initializeApp({});
testModularStorage = getStorage(testCompatApp);
service = makeTestCompatStorage(testCompatApp, testModularStorage);
});
after(() => {
return testCompatApp.delete();
});
describe('ref', () => {
it('Throws on gs:// argument', () => {
expect(() => service.ref('gs://yo')).to.throw(
'storage/invalid-argument'
);
});
});
describe('refFromURL', () => {
it('Throws with a non-URL string arg', () => {
expect(() => {
service.refFromURL('child');
}).to.throw(
/expected a full URL but got a child path.*storage\/invalid-argument/i
);
});
it('Throws with an invalid URL arg', () => {
expect(() => {
service.refFromURL('notlegit://url');
}).to.throw('storage/invalid-argument');
});
});
describe('MaxUploadRetryTime', () => {
const modularStorage = {} as FirebaseStorage;
const service = makeTestCompatStorage(fakeApp, modularStorage);
it('reads from the modular instance', () => {
modularStorage.maxUploadRetryTime = 999;
expect(service.maxUploadRetryTime).to.equal(999);
});
it('sets value on the modular instance', () => {
service.setMaxUploadRetryTime(888);
expect(modularStorage.maxUploadRetryTime).to.equal(888);
});
});
describe('MaxOperationRetryTime', () => {
const modularStorage = {} as FirebaseStorage;
const service = makeTestCompatStorage(fakeApp, modularStorage);
it('reads from the modular instance', () => {
modularStorage.maxOperationRetryTime = 999;
expect(service.maxOperationRetryTime).to.equal(999);
});
it('sets value on the modular instance', () => {
service.setMaxOperationRetryTime(888);
expect(modularStorage.maxOperationRetryTime).to.equal(888);
});
});
});
describe('Deletion', () => {
let service: StorageServiceCompat;
let testCompatApp: FirebaseApp;
let testModularStorage: FirebaseStorage;
before(() => {
testCompatApp = firebase.initializeApp({});
testModularStorage = getStorage(testCompatApp);
service = makeTestCompatStorage(testCompatApp, testModularStorage);
});
after(() => {
return testCompatApp.delete();
});
it('In-flight requests are canceled when the service is deleted', async () => {
const ref = service.refFromURL('gs://mybucket/image.jpg');
const metadataPromise = ref.getMetadata();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
service._delegate._delete();
await expect(metadataPromise).to.be.rejectedWith('storage/app-deleted');
});
it('Requests fail when started after the service is deleted', async () => {
const ref = service.refFromURL('gs://mybucket/image.jpg');
// eslint-disable-next-line @typescript-eslint/no-floating-promises
service._delegate._delete();
await expect(ref.getMetadata()).to.be.rejectedWith('storage/app-deleted');
});
it('Running uploads fail when the service is deleted', () => {
const ref = service.refFromURL('gs://mybucket/image.jpg');
const toReturn = new Promise<void>((resolve, reject) => {
ref.put(new Uint8Array([97])).on(
'state_changed',
null,
(err: StorageError | Error) => {
expect((err as StorageError).code).to.equal('storage/app-deleted');
resolve();
},
() => {
reject('Upload completed, should have been canceled');
}
);
// eslint-disable-next-line @typescript-eslint/no-floating-promises
service._delegate._delete();
});
return toReturn;
});
});
});