-
Notifications
You must be signed in to change notification settings - Fork 535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix and reorganize stashed ops that wait for a summary #23542
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
packages/test/test-end-to-end-tests/src/test/offline/offlineTestsUtils.ts:43
- [nitpick] The magic number
30
should be defined as a constant or passed as a parameter for better readability and maintainability.
const lots = 30;
packages/test/test-end-to-end-tests/src/test/offline/containerDirtyFlag.spec.ts:31
- Ensure that map2 is properly initialized before using it. Add a check to verify that map2 is not null or undefined.
const map2 = await dataStore2.getSharedObject<ISharedMap>(mapId);
export async function loadOffline( | ||
testContainerConfig: ITestContainerConfig, | ||
testObjectProvider: ITestObjectProvider, | ||
request: IRequest, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The request
parameter should be validated to ensure it is not null or undefined before being used.
Copilot is powered by AI, so mistakes are possible. Review output carefully before use.
(getTestObjectProvider, apis) => { | ||
const mapId = "map"; | ||
const { SharedMap } = apis.dds; | ||
const registry: ChannelFactoryRegistry = [[mapId, SharedMap.getFactory()]]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really need a map? It would be simpler and less code to use the default root
DDS that the test data object exposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Map is not really needed but I'm trying to keep tests as close as we have them as stashedOps.spec.ts, so it's more just for consistency purposes.
let map1: ISharedMap; | ||
let dataStore1: ITestFluidObject; | ||
const testContainerConfig: ITestContainerConfig = { | ||
fluidDataObjectType: DataObjectFactoryType.Test, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to pass this? The default test object created by the test object provider should be sufficient right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as map, just trying to keep it consistent with other offline tests.
loader, | ||
provider.driver.createCreateNewRequest(provider.documentId), | ||
); | ||
provider.updateDocumentId(container.resolvedUrl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason for this 3-step process to create a container rather than just doing provider.createTestContainer(mainContainerConfig)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, consistency purposes. I'll consider making those suggestions to other offline tests as well if there is a strong reason for them.
await waitForContainerConnection(container2); | ||
await provider.ensureSynchronized(); | ||
|
||
assert.strictEqual(map2.get("1"), "1"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add messages to assert so that when one of these is hit, it's possible to tell which assert was hit. As of now, if this fails in say CI, there will be no way to tell which one of these asserts is hit making debugging harder.
|
||
it("can stash between summary op and ack", async function () { | ||
const waitForSummaryPromise = waitForSummary(provider, container, testContainerConfig); | ||
const pendingOps = await new Promise<string | undefined>((resolve, reject) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use timeoutPromise
or timeoutAwait
here in case the summarize op never comes.
* @param pendingLocalState - (Optional) custom PendingLocalState to load from. Defaults to using getPendingOps helper if omitted. | ||
* @returns A container instance with a connect function to unblock the Driver (simulating coming back from offline) | ||
*/ | ||
export async function loadOffline( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call this loadContainerWithDeferredConnection
or something along those lines. As of now, this name doesn't align with what it does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of now, this name doesn't align with what it does.
Not sure I see your point. What does "load offline" mean to you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't really mean anything to me. The fact that it loads a container is not obvious. loadOfflineContainer
or loadContainerOffline
would be understandable.
/** | ||
* load container, pause, create (local) ops from callback, then optionally send ops before closing container | ||
*/ | ||
export const getPendingOps = async ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call this loadContainerAndGetPendingState
. It's confusing that getPendingOps
would load a container as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe generatePendingState
? It needs a live container to do so, but it closes that container before returning, so I wouldn't put loadContainer
in the title.
|
||
map1.set("2", "2"); | ||
await waitForSummary(provider, container, testContainerConfig, summaryVersion); | ||
const container2 = await loader.resolve({ url }, pendingOps); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intentional that container2 doesn't load from the summary that happens before this step?
type ITestObjectProvider, | ||
} from "@fluidframework/test-utils/internal"; | ||
|
||
import { wrapObjectAndOverride } from "../mocking.js"; | ||
|
||
// eslint-disable-next-line import/no-internal-modules |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you avoid this by re-exporting under /offline/index.ts
? Not sure if there's precedence either way.
Could also consider moving that utils file to another package, probably @fluidframework/test-utils
? (tag it as internal)
const offlineObject = await loadOffline( | ||
testContainerConfig, | ||
provider, | ||
{ url }, | ||
pendingOps, | ||
); | ||
container2 = offlineObject.container; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, if you like it: This avoids having to name offlineObject
variable
const offlineObject = await loadOffline( | |
testContainerConfig, | |
provider, | |
{ url }, | |
pendingOps, | |
); | |
container2 = offlineObject.container; | |
const { container } = await loadOffline( | |
testContainerConfig, | |
provider, | |
{ url }, | |
pendingOps, | |
); | |
container2 = container; |
url = await container.getAbsoluteUrl(""); | ||
dataStore1 = (await container.getEntryPoint()) as ITestFluidObject; | ||
map1 = await dataStore1.getSharedObject<ISharedMap>(mapId); | ||
map1.set("1", "1"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you doing this to force a write connection? Nice to put a comment to that effect (some places even do set("force", "write connection");
🤷♂️
|
||
it("works with summary while offline", async function () { | ||
const summaryVersion = await waitForSummary(provider, container, testContainerConfig); | ||
const pendingOps = await getPendingOps( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I right that the container used here is totally discarded never to be used again? And not just the container instance but also the backing file that's created?
Some tests among stashedOps.spec.ts need to wait for a summary in order to fall into its test scenario. There was some missing configuration on them:
Besides those changes, I made some reorganization to these tests since added config is necessary only for tests that wait for a summary so I separated them into a different file and move some functions to a utils file well.
Some of these tests are currently failing in ODSP and so I'll head up OCE in case they keep failing after this PR is merged. If this approach work, I'll use it for refresh snapshot tests that are currently failing for what I suspect the same reason.