Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
042dca2
fix(storage): standardize URL formatting and enhance transport retry
thiyaguk09 May 7, 2026
5f18f7e
fix(storage): resolve transport and retry issues (#8235)
thiyaguk09 Jun 23, 2026
288e31a
lint fix
thiyaguk09 Jun 23, 2026
fbedc7c
fix(storage): Invocation ID is not retained on multipart upload retri…
thiyaguk09 Jul 28, 2026
053428f
test: update resumable upload test mocks to use URL and Headers objects
thiyaguk09 Aug 27, 2026
9764d21
style: apply prettier formatting throughout the codebase to ensure co…
thiyaguk09 Aug 28, 2026
b20961b
refactor: improve type safety and remove any casts across storage tra…
thiyaguk09 Aug 28, 2026
d8b93e8
refactor: move upload initialization into the writing event pipeline …
thiyaguk09 Aug 28, 2026
8576398
test(storage): system tests for gaxios migration
thiyaguk09 Aug 28, 2026
4a73eb4
fix(storage): standardize URL formatting and enhance transport retry
thiyaguk09 May 7, 2026
320b5cc
fix(storage): resolve transport and retry issues (#8235)
thiyaguk09 Jun 23, 2026
c2710bf
lint fix
thiyaguk09 Jun 23, 2026
463e7f8
fix(storage): Invocation ID is not retained on multipart upload retri…
thiyaguk09 Jul 28, 2026
ca30b2e
test: update resumable upload test mocks to use URL and Headers objects
thiyaguk09 Aug 27, 2026
01e1f17
style: apply prettier formatting throughout the codebase to ensure co…
thiyaguk09 Aug 28, 2026
d104ded
refactor: improve type safety and remove any casts across storage tra…
thiyaguk09 Aug 28, 2026
b541179
refactor: move upload initialization into the writing event pipeline …
thiyaguk09 Aug 28, 2026
2e5eee3
Merge branch 'storage-gaxios-migration' into test/storage-system-gaxios
thiyaguk09 Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion handwritten/storage/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Changelog


[npm history][1]

[1]: https://www.npmjs.com/package/@google-cloud/storage?activeTab=versions
Expand Down
7 changes: 7 additions & 0 deletions handwritten/storage/SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Security Policy

To report a security issue, please use [g.co/vulnz](https://g.co/vulnz).

The Google Security Team will respond within 5 working days of your report on g.co/vulnz.

We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue.
116 changes: 86 additions & 30 deletions handwritten/storage/conformance-test/conformanceCommon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import * as jsonToNodeApiMapping from './test-data/retryInvocationMap.json';
import * as libraryMethods from './libraryMethods';
import {Bucket, File, HmacKey, Notification, Storage} from '../src/';
import * as libraryMethods from './libraryMethods.js';
import {
Bucket,
File,
GaxiosOptions,
GaxiosOptionsPrepared,
HmacKey,
Notification,
Storage,
} from '../src';
import * as crypto from 'crypto';
import * as assert from 'assert';
import {DecorateRequestOptions} from '../src/nodejs-common';
import fetch from 'node-fetch';

import {
StorageRequestOptions,
StorageTransport,
} from '../src/storage-transport.js';
interface RetryCase {
instructions: String[];
}
Expand Down Expand Up @@ -50,7 +60,7 @@ interface ConformanceTestResult {

type LibraryMethodsModuleType = typeof import('./libraryMethods');
const methodMap: Map<String, String[]> = new Map(
Object.entries(jsonToNodeApiMapping)
Object.entries({}), // TODO: replace with Object.entries(jsonToNodeApiMapping)
);

const DURATION_SECONDS = 600; // 10 mins.
Expand Down Expand Up @@ -82,79 +92,115 @@ export function executeScenario(testCase: RetryTestCase) {
let creationResult: {id: string};
let storage: Storage;
let hmacKey: HmacKey;
let storageTransport: StorageTransport;

describe(`${storageMethodString}`, async () => {
beforeEach(async () => {
storageTransport = new StorageTransport({
apiEndpoint: TESTBENCH_HOST,
authClient: undefined,
baseUrl: TESTBENCH_HOST,
packageJson: {name: 'test-package', version: '1.0.0'},
retryOptions: {
retryDelayMultiplier: RETRY_MULTIPLIER_FOR_CONFORMANCE_TESTS,
maxRetries: 3,
maxRetryDelay: 32,
totalTimeout: TIMEOUT_FOR_INDIVIDUAL_TEST,
},
scopes: [
'http://www.googleapis.com/auth/devstorage.full_control',
],
projectId: CONF_TEST_PROJECT_ID,
userAgent: 'retry-test',
useAuthWithCustomEndpoint: true,
customEndpoint: true,
timeout: DURATION_SECONDS,
});

storage = new Storage({
apiEndpoint: TESTBENCH_HOST,
projectId: CONF_TEST_PROJECT_ID,
retryOptions: {
retryDelayMultiplier: RETRY_MULTIPLIER_FOR_CONFORMANCE_TESTS,
},
});

creationResult = await createTestBenchRetryTest(
instructionSet.instructions,
jsonMethod?.name.toString()
jsonMethod?.name.toString(),
storageTransport,
);
if (storageMethodString.includes('InstancePrecondition')) {
bucket = await createBucketForTest(
storage,
testCase.preconditionProvided,
storageMethodString
storageMethodString,
);
file = await createFileForTest(
testCase.preconditionProvided,
storageMethodString,
bucket
bucket,
);
} else {
bucket = await createBucketForTest(
storage,
false,
storageMethodString
storageMethodString,
);
file = await createFileForTest(
false,
storageMethodString,
bucket
bucket,
);
}
notification = bucket.notification(`${TESTS_PREFIX}`);
notification = bucket.notification(TESTS_PREFIX);
await notification.create();

[hmacKey] = await storage.createHmacKey(
`${TESTS_PREFIX}@email.com`
`${TESTS_PREFIX}@email.com`,
);

storage.interceptors.push({
request: requestConfig => {
requestConfig.headers = requestConfig.headers || {};
Object.assign(requestConfig.headers, {
resolved: (
requestConfig: GaxiosOptionsPrepared,
): Promise<GaxiosOptionsPrepared> => {
const config = requestConfig as GaxiosOptions;
config.headers = config.headers || {};
Object.assign(config.headers, {
'x-retry-test-id': creationResult.id,
});
return requestConfig as DecorateRequestOptions;
return Promise.resolve(config as GaxiosOptionsPrepared);
},
rejected: error => {
return Promise.reject(error);
},
});
});

it(`${instructionNumber}`, async () => {
const methodParameters: libraryMethods.ConformanceTestOptions = {
storage: storage,
bucket: bucket,
file: file,
storageTransport: storageTransport,
notification: notification,
storage: storage,
hmacKey: hmacKey,
};
if (testCase.preconditionProvided) {
methodParameters.preconditionRequired = true;
}

if (testCase.expectSuccess) {
assert.ifError(await storageMethodObject(methodParameters));
} else {
await assert.rejects(storageMethodObject(methodParameters));
await assert.rejects(async () => {
await storageMethodObject(methodParameters);
}, undefined);
}

const testBenchResult = await getTestBenchRetryTest(
creationResult.id
creationResult.id,
storageTransport,
);
assert.strictEqual(testBenchResult.completed, true);
}).timeout(TIMEOUT_FOR_INDIVIDUAL_TEST);
Expand All @@ -167,7 +213,7 @@ export function executeScenario(testCase: RetryTestCase) {
async function createBucketForTest(
storage: Storage,
preconditionShouldBeOnInstance: boolean,
storageMethodString: String
storageMethodString: String,
) {
const name = generateName(storageMethodString, 'bucket');
const bucket = storage.bucket(name);
Expand All @@ -187,7 +233,7 @@ async function createBucketForTest(
async function createFileForTest(
preconditionShouldBeOnInstance: boolean,
storageMethodString: String,
bucket: Bucket
bucket: Bucket,
) {
const name = generateName(storageMethodString, 'file');
const file = bucket.file(name);
Expand All @@ -209,25 +255,35 @@ function generateName(storageMethodString: String, bucketOrFile: string) {

async function createTestBenchRetryTest(
instructions: String[],
methodName: string
methodName: string,
storageTransport: StorageTransport,
): Promise<ConformanceTestCreationResult> {
const requestBody = {instructions: {[methodName]: instructions}};
const response = await fetch(`${TESTBENCH_HOST}retry_test`, {

const requestOptions: StorageRequestOptions = {
method: 'POST',
url: 'retry_test',
body: JSON.stringify(requestBody),
headers: {'Content-Type': 'application/json'},
});
return response.json() as Promise<ConformanceTestCreationResult>;
};

const response = await storageTransport.makeRequest(requestOptions);
return response as unknown as ConformanceTestCreationResult;
}

async function getTestBenchRetryTest(
testId: string
testId: string,
storageTransport: StorageTransport,
): Promise<ConformanceTestResult> {
const response = await fetch(`${TESTBENCH_HOST}retry_test/${testId}`, {
const response = await storageTransport.makeRequest({
url: `retry_test/${testId}`,
method: 'GET',
retry: true,
headers: {
'x-retry-test-id': testId,
},
});

return response.json() as Promise<ConformanceTestResult>;
return response as unknown as ConformanceTestResult;
}

function shortUUID() {
Expand Down
2 changes: 1 addition & 1 deletion handwritten/storage/conformance-test/globalHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export async function mochaGlobalSetup(this: any) {
await getTestBenchDockerImage();
await runTestBenchDockerImage();
await new Promise(resolve =>
setTimeout(resolve, TIME_TO_WAIT_FOR_CONTAINER_READY)
setTimeout(resolve, TIME_TO_WAIT_FOR_CONTAINER_READY),
);
}

Expand Down
Loading
Loading