Skip to content

Test#2647

Open
jainakanksha-msft wants to merge 10 commits into
mainfrom
akkuSFI
Open

Test#2647
jainakanksha-msft wants to merge 10 commits into
mainfrom
akkuSFI

Conversation

@jainakanksha-msft
Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings May 21, 2026 10:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes Azurite’s dependencies (notably Azure SDK packages) and updates the codebase/tests to align with newer SDK typings and runtime behaviors (headers access, credential access, typed-array handling, and generated swagger defaults).

Changes:

  • Upgrades core dependencies (e.g., @azure/ms-rest-js, @azure/storage-blob, @azure/storage-queue, axios, tedious) and adjusts tests accordingly.
  • Refactors multiple tests and runtime helpers to use Uint8Array-based buffers and updated SDK option/property names (e.g., visibilityTimeout, _response.headers.get(...), client.credential).
  • Updates generated swagger/artifacts to remove the default value for x-ms-blob-sequence-number and tightens Express query handling in generated request adapters.

Reviewed changes

Copilot reviewed 30 out of 39 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/testutils.ts Formats file creation loops; comments out overrideRequest helper.
tests/table/apis/table.entity.rest.test.ts Adds non-null assertions for etag headers.
tests/table/apis/table.batch.errorhandling.test.ts Removes RestError import and loosens error typing; minor formatting.
tests/simpleTokenCredential.ts Switches TokenCredential-related imports to @azure/identity.
tests/queue/queueSas.test.ts Uses (serviceClient as any).credential instead of pipeline factory introspection.
tests/queue/queueCorsRequest.test.ts Asserts CORS headers via _response.headers.get(...) rather than response-shape properties.
tests/queue/oauth.test.ts Updates error detail property casing and cleans up formatting.
tests/queue/apis/messages.test.ts Renames visibilitytimeout to visibilityTimeout; adjusts timing for an expiration test.
tests/linuxbinary.test.ts Comments out the entire linux binary test file.
tests/blob/sas.test.ts Uses client.credential; updates hard-coded expected SAS strings.
tests/blob/oauth.test.ts Updates error detail property casing.
tests/blob/fsStore.test.ts Changes chunk buffering from Buffer[] to Uint8Array[].
tests/blob/blockblob.highlevel.test.ts Updates buffer comparisons and abort logic for upload stream test.
tests/blob/blobCorsRequest.test.ts Mirrors queue CORS assertion changes using _response.headers.get(...).
tests/blob/apis/service.test.ts Updates expected error detail property casing; uses client.credential.
tests/blob/apis/blockblob.test.ts Simplifies MD5 typed-array construction.
tests/blob/apis/blobbatch.test.ts Uses client.credential for batch SAS signing.
tests/blob/apis/blob.test.ts Removes node/browser branch for MD5 header; normalizes to Uint8Array.
swagger/blob.md Notes removal of default for blob sequence number header parameter.
swagger/blob-storage-2021-10-04.json Removes "default": 0 from BlobSequenceNumber parameter.
src/table/generated/utils/xml.ts Adjusts xml2js parse callback typing; removes builder options.
src/table/generated/ExpressRequestAdapter.ts Ensures getQuery() only returns strings.
src/queue/utils/utils.ts Adjusts xml2js parse callback typing.
src/queue/generated/utils/xml.ts Adjusts xml2js parse callback typing; removes builder options.
src/queue/generated/ExpressRequestAdapter.ts Ensures getQuery() only returns strings.
src/common/utils/utils.ts Normalizes HMAC/MD5 helpers to return/accept Uint8Array.
src/blob/persistence/SqlBlobMetadataStore.ts Formatting tweaks; normalizes restored byte arrays to Uint8Array.
src/blob/persistence/LokiBlobMetadataStore.ts Changes persisted-byte-array restore logic (Buffer/Uint8Array handling).
src/blob/main.ts Minor formatting cleanup.
src/blob/handlers/SubResponseTextBodyStream.ts Reformats class; changes end() typing to return this.
src/blob/handlers/BlobBatchSubResponse.ts Minor formatting updates.
src/blob/handlers/BlobBatchHandler.ts Changes stream-to-buffer copy to use Uint8Array conversion.
src/blob/handlers/AppendBlobHandler.ts Normalizes contentMD5 to Uint8Array.
src/blob/generated/utils/xml.ts Adjusts xml2js parse callback typing; removes builder options.
src/blob/generated/ExpressRequestAdapter.ts Ensures getQuery() only returns strings.
src/blob/generated/artifacts/parameters.ts Removes defaultValue: 0 for blob sequence number header.
src/blob/authentication/BlobSharedKeyAuthenticator.ts Formatting changes plus string-to-sign line reordering.
package.json Upgrades dependencies; removes azure-storage; adds @azure/identity.
Comments suppressed due to low confidence (1)

src/blob/persistence/LokiBlobMetadataStore.ts:3121

  • restoreUint8Array no longer handles the JSON-serialized Buffer shape ({ type: "Buffer", data: [...] }). Existing Loki DB files created by earlier versions can contain this shape, so this change can break loading persisted metadata after upgrade. Consider keeping backward-compatible handling for obj.type === "Buffer" (using obj.data) in addition to the Buffer instance case.
  private restoreUint8Array(obj: any): Uint8Array | undefined {
    if (typeof obj !== "object") {
      return undefined;
    }

    if (obj instanceof Buffer) {
      return new Uint8Array(obj);
    }

    const length = Object.keys(obj).length;
    const arr = Buffer.allocUnsafe(length);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/testutils.ts Outdated
Comment on lines +206 to +217
// headers: { [key: string]: string };
// } = { headers: {} },
// service: StorageServiceClient
// ) {
Comment thread package.json
@@ -73,7 +73,6 @@
"@typescript-eslint/eslint-plugin": "^5.54.1",
"@typescript-eslint/parser": "^5.54.1",
"autorest": "^3.6.0",
Comment on lines 80 to +81
this.getHeaderValueToSign(req, HeaderConstants.CONTENT_LANGUAGE),
this.getHeaderValueToSign(req, HeaderConstants.CONTENT_ENCODING),
Comment thread tests/blob/sas.test.ts
Comment on lines 123 to +142
@@ -140,7 +139,7 @@ describe("Shared Access Signature (SAS) authentication", () => {
storageSharedKeyCredential as StorageSharedKeyCredential
).toString();

assert.equal(sas, "sv=2016-05-31&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T13%3A31%3A48Z&se=2022-04-17T13%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=3tOzYrzhkaX48zalU5WlyEJg%2B7Tj4RzY4jBo9mCi8AM%3D");
assert.equal(sas, "sv=2016-05-31&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T06%3A31%3A48Z&se=2022-04-17T06%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=bTjnB%2ByT4DkYQcmMfpedew72%2FKdvTMuz29uatYuWYME%3D");
Comment thread tests/linuxbinary.test.ts Outdated
Comment on lines +1 to +5
// // run "EXE Mocha TS File - Loki" in VS Code to run this test
// import * as assert from 'assert';
// import { execFile } from 'child_process';
// import find from 'find-process';

Comment on lines 21 to +23
if (chunk) this.bodyText += (chunk! as any).toString();
this.subResponse.end();
return this;
Comment on lines +162 to +163
assert.strictEqual(
(err as any).statusCode,
Comment on lines 532 to +548
@@ -544,6 +544,8 @@ describe("Messages APIs test", () => {
assert.ok(eResult.nextVisibleOn);
assert.ok(eResult.version);

await sleep(1000);

Copilot AI review requested due to automatic review settings May 27, 2026 08:04
Comment on lines +292 to +298
export function generateTableSasToken({
accountName,
accountKey,
tableName,
permissions,
expiry
}: {
Comment on lines +394 to +399
export function generateTableServiceSasWithIdentifier({
accountName,
accountKey,
tableName,
identifier
}: {
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 39 out of 48 changed files in this pull request and generated 14 comments.

Comment thread tests/testutils.ts Outdated
Comment on lines +212 to +252
// export function overrideRequest(
// override: {
// headers: { [key: string]: string };
// } = { headers: {} },
// service: StorageServiceClient
// ) {
// const hasOriginal = !!(service as any).__proto__.__proto__
// .__original_buildRequestOptions;

// const original = hasOriginal
// ? (service as any).__proto__.__proto__.__original_buildRequestOptions
// : (service as any).__proto__.__proto__._buildRequestOptions;

// if (!hasOriginal) {
// (service as any).__proto__.__proto__.__original_buildRequestOptions = original;
// }

// const _buildRequestOptions = original.bind(service);
// (service as any).__proto__.__proto__._buildRequestOptions = (
// webResource: any,
// body: any,
// options: any,
// callback: any
// ) => {
// _buildRequestOptions(
// webResource,
// body,
// options,
// (err: any, finalRequestOptions: any) => {
// for (const key in override.headers) {
// if (Object.prototype.hasOwnProperty.call(override.headers, key)) {
// const element = override.headers[key];
// finalRequestOptions.headers[key] = element;
// }
// }

// callback(err, finalRequestOptions);
// }
// );
// };
// }
Comment on lines +8 to 16
public partitionKey: string;
public rowKey: string;
public myValue: string;

constructor(part: string, row: string, value: string) {
this.PartitionKey = eg.String(part);
this.RowKey = eg.String(row);
this.myValue = eg.String(value);
this.partitionKey = part;
this.rowKey = row;
this.myValue = value;
}
Comment thread tests/linuxbinary.test.ts Outdated
Comment on lines 1 to 380
// // run "EXE Mocha TS File - Loki" in VS Code to run this test
// import * as assert from 'assert';
// import { execFile } from 'child_process';
// import find from 'find-process';

// import {
// BlobServiceClient, newPipeline as blobNewPipeline,
// StorageSharedKeyCredential as blobStorageSharedKeyCredential
// } from '@azure/storage-blob';
// import {
// newPipeline as queueNewPipeline, QueueClient, QueueServiceClient,
// StorageSharedKeyCredential as queueStorageSharedKeyCredential
// } from '@azure/storage-queue';

// import { configLogger } from '../src/common/Logger';
// import { HeaderConstants, TABLE_API_VERSION } from '../src/table/utils/constants';
// import BlobTestServerFactory from './BlobTestServerFactory';
// import {
// createConnectionStringForTest, HOST, PORT, PROTOCOL
// } from './table/utils/table.entity.test.utils';
// import {
// bodyToString, EMULATOR_ACCOUNT_KEY, EMULATOR_ACCOUNT_NAME, getUniqueName, overrideRequest,
// restoreBuildRequestOptions
// } from './testutils';
// import { existsSync } from 'fs';

// // server address used for testing. Note that Azuritelinux has
// // server address of http://127.0.0.1:10000 and so on by default
// // and we need to configure them when starting azuritelinux
// const blobAddress = "http://127.0.0.1:11000";
// const queueAddress = "http://127.0.0.1:11001";
// const tableAddress = "http://127.0.0.1:11002";

// // Set true to enable debug log
// configLogger(false);
// // For convenience, we have a switch to control the use
// // of a local Azurite instance, otherwise we need an
// // ENV VAR called AZURE_TABLE_STORAGE added to mocha
// // script or launch.json containing
// // Azure Storage Connection String (using SAS or Key).
// const testLocalAzuriteInstance = true;

// const binaryPath = "./release/azuritelinux"

// function throwOnMissingBinary() {
// if (!existsSync(binaryPath)) {
// throw new Error("The Linux binary does not exist. You must build it first using 'npm run build:linux'.")
// }
// }

// describe("linux binary test", () => {

// const tableService = Azure.createTableService(
// createConnectionStringForTest(testLocalAzuriteInstance)
// );
// tableService.enableGlobalHttpAgent = true;

// let tableName: string = getUniqueName("table");

// const requestOverride = { headers: {} };

// let childPid: number;

// beforeEach(() => throwOnMissingBinary())

// before(async () => {
// throwOnMissingBinary()

// overrideRequest(requestOverride, tableService);
// tableName = getUniqueName("table");
// const child = execFile(binaryPath, ["--blobPort 11000", "--queuePort 11001", "--tablePort 11002"], { cwd: process.cwd(), shell: true, env: {} });

// childPid = child.pid;

// const fullSuccessMessage = "Azurite Blob service is starting at " + blobAddress + "\nAzurite Blob service is successfully listening at " + blobAddress +
// "\nAzurite Queue service is starting at " + queueAddress + "\nAzurite Queue service is successfully listening at " + queueAddress +
// "\nAzurite Table service is starting at " + tableAddress + "\nAzurite Table service is successfully listening at " + tableAddress + "\n";
// let messageReceived: string = "";

// function stdoutOn() {
// return new Promise(resolve => {
// // exclamation mark suppresses the TS error that "child.stdout is possibly null"
// child.stdout!.on('data', function (data: any) {
// messageReceived += data.toString();
// if (messageReceived == fullSuccessMessage) {
// resolve("resolveMessage");
// }
// });
// });
// }

// await stdoutOn();
// });

// after(async () => {
// // TO DO
// // Currently, the mocha test does not quit unless "--exit" is added to the mocha command
// // The current fix is to have "--exit" added but the issue causing mocha to be unable to
// // quit has not been identified
// restoreBuildRequestOptions(tableService);
// tableService.removeAllListeners();

// await find('name', 'azuritelinux', true).then((list: any) => {
// if (list.length > 0) {
// process.kill(list[0].pid);
// }
// });

// if (childPid) {
// process.kill(childPid);
// }
// });

// describe("table test", () => {
// it("createTable, prefer=return-no-content, accept=application/json;odata=minimalmetadata @loki", (done) => {
// /* Azure Storage Table SDK doesn't support customize Accept header and Prefer header,
// thus we workaround this by override request headers to test following 3 OData levels responses.
// - application/json;odata=nometadata
// - application/json;odata=minimalmetadata
// - application/json;odata=fullmetadata
// */
// requestOverride.headers = {
// Prefer: "return-no-content",
// accept: "application/json;odata=minimalmetadata"
// };

// tableService.createTable(tableName, (error, result, response) => {
// if (!error) {
// assert.strictEqual(result.TableName, tableName);
// assert.strictEqual(result.statusCode, 204);
// const headers = response.headers!;
// assert.strictEqual(headers["x-ms-version"], TABLE_API_VERSION);
// assert.deepStrictEqual(response.body, "");
// }
// done();
// });
// });

// it("queryTable, accept=application/json;odata=minimalmetadata @loki", (done) => {
// /* Azure Storage Table SDK doesn't support customize Accept header and Prefer header,
// thus we workaround this by override request headers to test following 3 OData levels responses.
// - application/json;odata=nometadata
// - application/json;odata=minimalmetadata
// - application/json;odata=fullmetadata
// */
// requestOverride.headers = {
// accept: "application/json;odata=minimalmetadata"
// };

// tableService.listTablesSegmented(null as any, (error, result, response) => {
// if (!error) {
// assert.strictEqual(response.statusCode, 200);
// const headers = response.headers!;
// assert.strictEqual(headers["x-ms-version"], TABLE_API_VERSION);
// const bodies = response.body! as any;
// assert.deepStrictEqual(
// bodies["odata.metadata"],
// `${PROTOCOL}://${HOST}:${PORT}/${EMULATOR_ACCOUNT_NAME}/$metadata#Tables`
// );
// assert.ok(bodies.value[0].TableName);
// }
// done();
// });
// });

// it("deleteTable that exists, @loki", (done) => {
// /*
// https://docs.microsoft.com/en-us/rest/api/storageservices/delete-table
// */
// requestOverride.headers = {};

// const tableToDelete = tableName + "del";

// tableService.createTable(tableToDelete, (error, result, response) => {
// if (!error) {
// tableService.deleteTable(tableToDelete, (deleteError, deleteResult) => {
// if (!deleteError) {
// // no body expected, we expect 204 no content on successful deletion
// assert.strictEqual(deleteResult.statusCode, 204);
// } else {
// assert.ifError(deleteError);
// }
// done();
// });
// } else {
// assert.fail("Test failed to create the table");
// done();
// }
// });
// });

// it("deleteTable that does not exist, @loki", (done) => {
// // https://docs.microsoft.com/en-us/rest/api/storageservices/delete-table
// requestOverride.headers = {};

// const tableToDelete = tableName + "causeerror";

// tableService.deleteTable(tableToDelete, (error, result) => {
// assert.strictEqual(result.statusCode, 404); // no body expected, we expect 404
// const storageError = error as any;
// assert.strictEqual(storageError.code, "ResourceNotFound");
// done();
// });
// });

// it("createTable with invalid version, @loki", (done) => {
// requestOverride.headers = { [HeaderConstants.X_MS_VERSION]: "invalid" };

// tableService.createTable("test", (error, result) => {
// assert.strictEqual(result.statusCode, 400);
// done();
// });
// });
// });

// describe("blob test", () => {
// const factory = new BlobTestServerFactory();
// const blobServer = factory.createServer();

// const blobBaseURL = `http://${blobServer.config.host}:${blobServer.config.port}/devstoreaccount1`;
// const blobServiceClient = new BlobServiceClient(
// blobBaseURL,
// blobNewPipeline(
// new blobStorageSharedKeyCredential(
// EMULATOR_ACCOUNT_NAME,
// EMULATOR_ACCOUNT_KEY
// ),
// {
// retryOptions: { maxTries: 1 },
// // Make sure socket is closed once the operation is done.
// keepAliveOptions: { enable: false }
// }
// )
// );

// let containerName: string = getUniqueName("container");
// let containerClient = blobServiceClient.getContainerClient(containerName);
// let blobName: string = getUniqueName("blob");
// let blobClient = containerClient.getBlobClient(blobName);
// let blockBlobClient = blobClient.getBlockBlobClient();
// const content = "Hello World";

// beforeEach(async () => {
// containerName = getUniqueName("container");
// containerClient = blobServiceClient.getContainerClient(containerName);
// await containerClient.create();
// blobName = getUniqueName("blob");
// blobClient = containerClient.getBlobClient(blobName);
// blockBlobClient = blobClient.getBlockBlobClient();
// await blockBlobClient.upload(content, content.length);
// });

// afterEach(async () => {
// await containerClient.delete();
// });
// it("download with default parameters @loki @sql", async () => {
// const result = await blobClient.download(0);
// assert.deepStrictEqual(await bodyToString(result, content.length), content);
// assert.equal(result.contentRange, undefined);
// assert.equal(
// result._response.request.headers.get("x-ms-client-request-id"),
// result.clientRequestId
// );
// });

// it("download should work with conditional headers @loki @sql", async () => {
// const properties = await blobClient.getProperties();
// const result = await blobClient.download(0, undefined, {
// conditions: {
// ifMatch: properties.etag,
// ifNoneMatch: "invalidetag",
// ifModifiedSince: new Date("2018/01/01"),
// ifUnmodifiedSince: new Date("2188/01/01")
// }
// });
// assert.deepStrictEqual(await bodyToString(result, content.length), content);
// assert.equal(result.contentRange, undefined);
// assert.equal(
// result._response.request.headers.get("x-ms-client-request-id"),
// result.clientRequestId
// );
// });
// });

// describe("queue test", () => {
// // TODO: Create a server factory as tests utils
// const host = "127.0.0.1";
// const port = 11001;

// const baseURL = `http://${host}:${port}/devstoreaccount1`;
// const serviceClient = new QueueServiceClient(
// baseURL,
// queueNewPipeline(
// new queueStorageSharedKeyCredential(
// EMULATOR_ACCOUNT_NAME,
// EMULATOR_ACCOUNT_KEY
// ),
// {
// retryOptions: { maxTries: 1 }
// }
// )
// );

// let queueName: string;
// let queueClient: QueueClient;

// beforeEach(async () => {
// queueName = getUniqueName("queue");
// queueClient = serviceClient.getQueueClient(queueName);
// await queueClient.create();
// });

// afterEach(async () => {
// await queueClient.delete();
// });

// it("setMetadata @loki", async () => {
// const metadata = {
// key0: "val0",
// keya: "vala",
// keyb: "valb"
// };
// const mResult = await queueClient.setMetadata(metadata);
// assert.equal(
// mResult._response.request.headers.get("x-ms-client-request-id"),
// mResult.clientRequestId
// );

// const result = await queueClient.getProperties();
// assert.deepEqual(result.metadata, metadata);
// assert.equal(
// result._response.request.headers.get("x-ms-client-request-id"),
// result.clientRequestId
// );
// });

// it("getProperties with default/all parameters @loki", async () => {
// const result = await queueClient.getProperties();
// assert.ok(result.approximateMessagesCount! >= 0);
// assert.ok(result.requestId);
// assert.ok(result.version);
// assert.ok(result.date);
// });

// it("SetAccessPolicy should work @loki", async () => {
// const queueAcl = [
// {
// accessPolicy: {
// expiresOn: new Date("2018-12-31T11:22:33.4567890Z"),
// permissions: "raup",
// startsOn: new Date("2017-12-31T11:22:33.4567890Z")
// },
// id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="
// },
// {
// accessPolicy: {
// expiresOn: new Date("2030-11-31T11:22:33.4567890Z"),
// permissions: "a",
// startsOn: new Date("2017-12-31T11:22:33.4567890Z")
// },
// id: "policy2"
// }
// ];

// const sResult = await queueClient.setAccessPolicy(queueAcl);
// assert.equal(
// sResult._response.request.headers.get("x-ms-client-request-id"),
// sResult.clientRequestId
// );

// const result = await queueClient.getAccessPolicy();
// assert.deepEqual(result.signedIdentifiers, queueAcl);
// assert.equal(
// result._response.request.headers.get("x-ms-client-request-id"),
// result.clientRequestId
// );
// });
// });
// });

Comment thread tests/blob/sas.test.ts
Comment on lines 142 to +174
@@ -156,7 +155,7 @@ describe("Shared Access Signature (SAS) authentication", () => {
storageSharedKeyCredential as StorageSharedKeyCredential
).toString();

assert.equal(sas2, "sv=2018-11-09&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T13%3A31%3A48Z&se=2022-04-17T13%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=o23T5PzZn4Daklb%2F8Ef25%2FUprkIIeq4zI4QxT57iim8%3D");
assert.equal(sas2, "sv=2018-11-09&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T06%3A31%3A48Z&se=2022-04-17T06%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=zty6%2BwJgp86CuAlzq9w%2F%2BavVwjoEHgBOTXXmN7xAyio%3D");

const sas3 = generateAccountSASQueryParameters(
{
@@ -172,7 +171,7 @@ describe("Shared Access Signature (SAS) authentication", () => {
storageSharedKeyCredential as StorageSharedKeyCredential
).toString();

assert.equal(sas3, "sv=2020-12-06&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T13%3A31%3A48Z&se=2022-04-17T13%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=zbYgTg6EQCUeDmU4CbXEE6nMA7jA4E7d%2FXBVd7rifng%3D");
assert.equal(sas3, "sv=2020-12-06&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T06%3A31%3A48Z&se=2022-04-17T06%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=QB5jKCJTqn7jcPidkkXAazBQBL6VDMY7HumUIM78ROE%3D");
Comment on lines +307 to +335
const stringToSign =
permissions +
"\n" +
"" +
"\n" + // start time (optional)
expiry +
"\n" +
`/table/${accountName}/${tableName}` +
"\n" +
"" +
"\n" +
"" +
"\n" +
"https,http\n" + // protocol
version;

const signature = crypto
.createHmac("sha256", Uint8Array.from(Buffer.from(accountKey, "base64")))
.update(stringToSign, "utf8")
.digest("base64");

return (
`sv=${version}` +
`&tn=${tableName}` +
`&sp=${permissions}` +
`&se=${encodeURIComponent(expiry)}` +
`&sig=${encodeURIComponent(signature)}`
);
}
Comment on lines +60 to 67
try {
await tableService.getStatistics();
assert.fail("Expected error");
} catch (err: any) {
assert.strictEqual(err.statusCode, 400);
assert.strictEqual(err.code, "InvalidQueryParameterValue");
assert.ok(err);
});
}
});
Comment on lines +115 to 121
it("createTable, prefer=return-content, accept=application/json;odata=minimalmetadata @loki", async () => {
// TODO
done();
});

it("createTable, prefer=return-content, accept=application/json;odata=nometadata @loki", (done) => {
it("createTable, prefer=return-content, accept=application/json;odata=nometadata @loki", async () => {
// TODO
done();
});
Comment on lines +311 to 330
it("Should have a valid OData Metadata value when inserting a table, @loki", async () => {
const capture: { headers?: any; body?: any; status?: number } = {};
const requestHeaders = {
Prefer: "return-content",
Accept: "application/json;odata=fullmetadata"
};
const aclTableName: string = tableName + "setAcl";
tableService.createTable(aclTableName, (error, result, response) => {
if (error) {
const storageErr = error as StorageError;
assert.strictEqual(storageErr.statusCode, 409, "TableDidNotExist");
const client = TableServiceClient.fromConnectionString(
createConnectionStringForTest(testLocalAzuriteInstance),
{
allowInsecureConnection: testLocalAzuriteInstance,
httpClient: createHttpClientForTest(requestHeaders, capture)
}
);
const newTableName: string = getUniqueName("table");

// a random id used to test whether response returns the client id sent in request
const setClientRequestId = "b86e2b01-a7b5-4df2-b190-205a0c24bd36";

tableService.setTableAcl(
aclTableName,
tableAcl,
{ clientRequestId: setClientRequestId },
(error2, result2, response2) => {
if (error2) {
assert.ifError(error2);
}
if (response2.headers) {
assert.strictEqual(
response2.headers["x-ms-client-request-id"],
setClientRequestId
);
}

// tslint:disable-next-line: no-shadowed-variable
tableService.getTableAcl(
aclTableName,
{ clientRequestId: setClientRequestId },
(error3, result3, response3) => {
if (error3) {
assert.ifError(error3);
}

if (response3.headers) {
assert.strictEqual(
response3.headers["x-ms-client-request-id"],
setClientRequestId
);
}

assert.deepStrictEqual(result3.signedIdentifiers, tableAcl);
done();
}
);
}
);
});
await client.createTable(newTableName);
const body = capture.body as any;
const meta: string = body["odata.metadata" as keyof object];
assert.strictEqual(meta.endsWith("/@Element"), true);
});
Comment on lines +588 to +638
it("10. Upsert succeeds with Update permission, @loki", async () => {
const tableName: string = getUniqueName("sas10");
tableService.createTable(tableName, (error, result, response) => {
// created table for tests
const sasService = getSasService(
{
Permissions: TableSASPermission.Update,
...sasPeriod(0, 5)
},
tableName
);

// this upserts, so we expect success
sasService.insertOrReplaceEntity(
tableName,
{ PartitionKey: "part1", RowKey: "row4", myValue: "newValue" },
(updateError, updateResult, updateResponse) => {
if (updateError) {
const castUpdateStatusCode = (updateError as StorageError)
.statusCode;
assert.fail(
"Test failed and had HTTP error : " + castUpdateStatusCode
);
} else {
assert.strictEqual(
updateResponse.statusCode,
204,
"We did not get the expected status code : " +
updateResponse.statusCode
);
}
done();
}
);
const conn = createConnectionStringForTest(testLocalAzuriteInstance);
const accountName = /AccountName=([^;]*)/.exec(conn)![1];
const accountKey = /AccountKey=([^;]*)/.exec(conn)![1];
const baseUrl = getBaseUrlForTest();

const adminClient = TableClient.fromConnectionString(conn, tableName, {
allowInsecureConnection: testLocalAzuriteInstance
});

await adminClient.createTable();

const now = Date.now();
const start = new Date(now).toISOString();
const expiry = new Date(now + 5 * 60 * 1000).toISOString();

const sas = generateTableAccountSasToken({
accountName,
accountKey,
permissions: "u",
start,
expiry
});

const sasClient = new TableClient(
baseUrl,
tableName,
new AzureSASCredential(sas),
{
allowInsecureConnection: testLocalAzuriteInstance
}
);

await sasClient.upsertEntity(
{
partitionKey: "part1",
rowKey: "row4",
myValue: "newValue"
},
"Replace"
);

// validate that the entity now exists
const stored = await adminClient.getEntity("part1", "row4");

assert.strictEqual(stored.partitionKey, "part1");
assert.strictEqual(stored.rowKey, "row4");
assert.strictEqual(stored.myValue, "newValue");
});
Comment on lines +278 to +288
capture.status = response.status;
capture.headers = response.headers.toJSON();

try {
capture.body = JSON.parse(response.bodyAsText ?? "");
} catch {
capture.body = response.bodyAsText;
}

return response;
}
Copilot AI review requested due to automatic review settings May 28, 2026 08:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 41 out of 50 changed files in this pull request and generated 7 comments.

Comment on lines 80 to +81
this.getHeaderValueToSign(req, HeaderConstants.CONTENT_LANGUAGE),
this.getHeaderValueToSign(req, HeaderConstants.CONTENT_ENCODING),
Comment on lines +328 to +334
return (
`sv=${version}` +
`&tn=${tableName}` +
`&sp=${permissions}` +
`&se=${encodeURIComponent(expiry)}` +
`&sig=${encodeURIComponent(signature)}`
);
Comment on lines +113 to 118
const sas = generateTableAccountSasToken({
accountName,
accountKey,
permissions: "a", // ✅ Add only
expiry
});
Comment on lines +588 to +638
it("10. Upsert succeeds with Update permission, @loki", async () => {
const tableName: string = getUniqueName("sas10");
tableService.createTable(tableName, (error, result, response) => {
// created table for tests
const sasService = getSasService(
{
Permissions: TableSASPermission.Update,
...sasPeriod(0, 5)
},
tableName
);

// this upserts, so we expect success
sasService.insertOrReplaceEntity(
tableName,
{ PartitionKey: "part1", RowKey: "row4", myValue: "newValue" },
(updateError, updateResult, updateResponse) => {
if (updateError) {
const castUpdateStatusCode = (updateError as StorageError)
.statusCode;
assert.fail(
"Test failed and had HTTP error : " + castUpdateStatusCode
);
} else {
assert.strictEqual(
updateResponse.statusCode,
204,
"We did not get the expected status code : " +
updateResponse.statusCode
);
}
done();
}
);
const conn = createConnectionStringForTest(testLocalAzuriteInstance);
const accountName = /AccountName=([^;]*)/.exec(conn)![1];
const accountKey = /AccountKey=([^;]*)/.exec(conn)![1];
const baseUrl = getBaseUrlForTest();

const adminClient = TableClient.fromConnectionString(conn, tableName, {
allowInsecureConnection: testLocalAzuriteInstance
});

await adminClient.createTable();

const now = Date.now();
const start = new Date(now).toISOString();
const expiry = new Date(now + 5 * 60 * 1000).toISOString();

const sas = generateTableAccountSasToken({
accountName,
accountKey,
permissions: "u",
start,
expiry
});

const sasClient = new TableClient(
baseUrl,
tableName,
new AzureSASCredential(sas),
{
allowInsecureConnection: testLocalAzuriteInstance
}
);

await sasClient.upsertEntity(
{
partitionKey: "part1",
rowKey: "row4",
myValue: "newValue"
},
"Replace"
);

// validate that the entity now exists
const stored = await adminClient.getEntity("part1", "row4");

assert.strictEqual(stored.partitionKey, "part1");
assert.strictEqual(stored.rowKey, "row4");
assert.strictEqual(stored.myValue, "newValue");
});
Comment thread tests/linuxbinary.test.ts Outdated
Comment on lines +1 to +25
// // run "EXE Mocha TS File - Loki" in VS Code to run this test
// import * as assert from 'assert';
// import { execFile } from 'child_process';
// import find from 'find-process';

// import {
// BlobServiceClient, newPipeline as blobNewPipeline,
// StorageSharedKeyCredential as blobStorageSharedKeyCredential
// } from '@azure/storage-blob';
// import {
// newPipeline as queueNewPipeline, QueueClient, QueueServiceClient,
// StorageSharedKeyCredential as queueStorageSharedKeyCredential
// } from '@azure/storage-queue';

// import { configLogger } from '../src/common/Logger';
// import { HeaderConstants, TABLE_API_VERSION } from '../src/table/utils/constants';
// import BlobTestServerFactory from './BlobTestServerFactory';
// import {
// createConnectionStringForTest, HOST, PORT, PROTOCOL
// } from './table/utils/table.entity.test.utils';
// import {
// bodyToString, EMULATOR_ACCOUNT_KEY, EMULATOR_ACCOUNT_NAME, getUniqueName, overrideRequest,
// restoreBuildRequestOptions
// } from './testutils';
// import { existsSync } from 'fs';
Comment thread tests/blob/sas.test.ts
Comment on lines 142 to +174
@@ -156,7 +155,7 @@ describe("Shared Access Signature (SAS) authentication", () => {
storageSharedKeyCredential as StorageSharedKeyCredential
).toString();

assert.equal(sas2, "sv=2018-11-09&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T13%3A31%3A48Z&se=2022-04-17T13%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=o23T5PzZn4Daklb%2F8Ef25%2FUprkIIeq4zI4QxT57iim8%3D");
assert.equal(sas2, "sv=2018-11-09&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T06%3A31%3A48Z&se=2022-04-17T06%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=zty6%2BwJgp86CuAlzq9w%2F%2BavVwjoEHgBOTXXmN7xAyio%3D");

const sas3 = generateAccountSASQueryParameters(
{
@@ -172,7 +171,7 @@ describe("Shared Access Signature (SAS) authentication", () => {
storageSharedKeyCredential as StorageSharedKeyCredential
).toString();

assert.equal(sas3, "sv=2020-12-06&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T13%3A31%3A48Z&se=2022-04-17T13%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=zbYgTg6EQCUeDmU4CbXEE6nMA7jA4E7d%2FXBVd7rifng%3D");
assert.equal(sas3, "sv=2020-12-06&ss=btqf&srt=sco&spr=https%2Chttp&st=2022-04-16T06%3A31%3A48Z&se=2022-04-17T06%3A31%3A48Z&sip=0.0.0.0-255.255.255.255&sp=rwdlacup&sig=QB5jKCJTqn7jcPidkkXAazBQBL6VDMY7HumUIM78ROE%3D");
Comment thread package.json
Comment on lines 23 to +52
@@ -36,7 +36,7 @@
"rimraf": "^3.0.2",
"sequelize": "^6.31.0",
"stoppable": "^1.1.0",
"tedious": "^16.7.0",
"tedious": "^18.6.1",
"to-readable-stream": "^2.1.0",
"tslib": "^2.3.0",
"uri-templates": "^0.2.0",
@@ -48,8 +48,8 @@
"@azure/core-auth": "^1.3.2",
"@azure/core-rest-pipeline": "^1.2.0",
"@azure/data-tables": "^13.0.1",
"@azure/storage-blob": "^12.9.0",
"@azure/storage-queue": "^12.8.0",
"@azure/storage-blob": "^12.28.0",
"@azure/storage-queue": "^12.27.0",
Copilot AI review requested due to automatic review settings May 28, 2026 10:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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

Successfully merging this pull request may close these issues.

5 participants