Skip to content
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: concurrency control in persistence layer #2742

Merged
merged 29 commits into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
170e9d9
fix: allow async functions ordered by called position
lei9444 Apr 22, 2020
aaf5eed
Merge branch 'master' into fixasync
cwhitten Apr 22, 2020
57f0d1e
update the lock logic
lei9444 Apr 23, 2020
0f81a9a
Merge branch 'fixasync' of https://github.com/lei9444/BotFramework-Co…
lei9444 Apr 23, 2020
58ebc38
fix test
lei9444 Apr 23, 2020
c998a97
update the file perisitence logic
lei9444 Apr 23, 2020
0e6da8c
fix the test
lei9444 Apr 23, 2020
ca8a01f
Merge branch 'master' into fixasync
lei9444 Apr 23, 2020
22c01ec
Merge branch 'master' into fixasync
lei9444 Apr 24, 2020
676ab37
update some naming and function logic
lei9444 Apr 24, 2020
bd879a2
Merge branch 'fixasync' of https://github.com/lei9444/BotFramework-Co…
lei9444 Apr 24, 2020
404048d
fix undefined
lei9444 Apr 24, 2020
9db8af1
remove unnecessary code
lei9444 Apr 24, 2020
d3fdeba
Merge branch 'master' into fixasync
cwhitten Apr 24, 2020
527f690
Merge branch 'master' into fixasync
cwhitten Apr 24, 2020
f5cc6c9
Merge branch 'master' into fixasync
lei9444 Apr 26, 2020
aac1eb4
Merge branch 'master' into fixasync
lei9444 Apr 27, 2020
e957e00
Merge branch 'master' of https://github.com/microsoft/BotFramework-Co…
lei9444 Apr 27, 2020
d2fc7ad
set throttle wait time to 0
lei9444 Apr 27, 2020
ff37e1b
Merge branch 'fixasync' of https://github.com/lei9444/BotFramework-Co…
lei9444 Apr 27, 2020
ee94752
Merge branch 'master' into fixasync
lei9444 Apr 28, 2020
1e4604d
Merge branch 'master' into fixasync
lei9444 Apr 28, 2020
4254617
fix e2e test
lei9444 Apr 28, 2020
133fa7d
update the e2e test
lei9444 Apr 28, 2020
8f2febc
Merge branch 'master' into fixasync
lei9444 Apr 29, 2020
66211b9
revert the code about the Throttle
lei9444 Apr 29, 2020
409c67d
Merge branch 'master' into fixasync
beyackle Apr 29, 2020
79d2dd7
Merge branch 'master' of https://github.com/microsoft/BotFramework-Co…
lei9444 Apr 30, 2020
f2e13ad
Merge branch 'master' into fixasync
cwhitten Apr 30, 2020
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
3 changes: 2 additions & 1 deletion Composer/cypress/integration/NotificationPage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ context('Notification Page', () => {
.should('contain.text', 'expression');
cy.get('#root\\.condition')
.click()
.type('()');
.type('()')
.wait(1000);
});

cy.get('[data-testid="notifications-info-button"]').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,83 +10,44 @@ jest.mock('axios', () => {
return {
create: jest.fn(() => {
return {
put: jest.fn(() => Promise.resolve({ data: {} })),
post: jest.fn((url, data) => Promise.resolve({ data })),
delete: jest.fn(() => Promise.resolve({ data: {} })),
put: new Promise(resolve => setTimeout(() => resolve({ data: {} }), 10)),
post: new Promise(resolve => setTimeout(() => resolve({ data: {} }), 10)),
delete: new Promise(resolve => setTimeout(() => resolve({ data: {} }), 10)),
};
}),
};
});

const files = [
{
name: 'a.dialog',
content: '',
lastModified: 'Tue Mar 31 2020 23:08:15 GMT+0800 (GMT+08:00)',
path: 'C:/a.dialog',
relativePath: 'a.dialog',
},
{
name: 'a.en-us.lg',
content: '',
lastModified: 'Tue Mar 31 2020 23:08:15 GMT+0800 (GMT+08:00)',
path: 'C:/a.dialog',
relativePath: 'a.en-us.lg',
},
{
name: 'a.en-us.lu',
content: '',
lastModified: 'Tue Mar 31 2020 23:08:15 GMT+0800 (GMT+08:00)',
path: 'C:/a.en-us.lu',
relativePath: 'a.en-us.lu',
},
];

describe('test persistence layer', () => {
it('test attach file', () => {
expect(Object.keys(filePersistence.files).length).toBe(0);
it('test init persistence', () => {
expect(filePersistence.projectId).toBe('');
filePersistence.projectId = 'projectId';
files.forEach(file => filePersistence.attach(file.name, file));
expect(Object.keys(filePersistence.files).length).toBe(3);
filePersistence.notify({} as State, {} as State, {
type: ActionTypes.GET_PROJECT_SUCCESS,
payload: { response: { data: { id: 'a' } } },
});
expect(filePersistence.projectId).toBe('a');
});

it('test notify update', async () => {
const state1 = {
dialogs: [{ id: 'a', content: {} }] as DialogInfo[],
dialogs: [{ id: 'a', content: { a: 'a' } }] as DialogInfo[],
lgFiles: [{ id: 'a.en-us', content: '' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: '' }] as LuFile[],
} as State;

const state2 = {
dialogs: [{ id: 'a', content: { a: 'a' } }] as DialogInfo[],
lgFiles: [{ id: 'a.en-us', content: 'a' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: 'a' }] as LuFile[],
lgFiles: [{ id: 'a.en-us', content: 'a.lg' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: 'a.lu' }] as LuFile[],
} as State;

await filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_DIALOG, payload: { id: 'a' } });
await filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_LG, payload: { id: 'a.en-us' } });
await filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_LU, payload: { id: 'a.en-us' } });
await new Promise(res =>
setTimeout(() => {
const dialog = filePersistence.files['a.dialog'].file;
const lg = filePersistence.files['a.en-us.lg'].file;
const lu = filePersistence.files['a.en-us.lu'].file;
expect(dialog).toBeDefined();
if (dialog) {
expect(JSON.parse(dialog.content).a).toBe('a');
}
expect(lg).toBeDefined();
if (lg) {
expect(lg.content).toBe('a');
}
expect(lu).toBeDefined();
if (lu) {
expect(lu.content).toBe('a');
}
res();
}, 601)
);
filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_DIALOG, payload: { id: 'a' } });
expect(JSON.parse(filePersistence.taskQueue['a.dialog'][0].change).a).toBe('a');
filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_LG, payload: { id: 'a.en-us' } });
expect(filePersistence.taskQueue['a.en-us.lg'][0].change).toBe('a.lg');
filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_LU, payload: { id: 'a.en-us' } });
expect(filePersistence.taskQueue['a.en-us.lu'][0].change).toBe('a.lu');
});

it('test notify create', async () => {
Expand All @@ -103,45 +64,34 @@ describe('test persistence layer', () => {
] as DialogInfo[],
lgFiles: [
{ id: 'a.en-us', content: 'a' },
{ id: 'b.en-us', content: 'b' },
{ id: 'b.en-us', content: 'b.lg' },
] as LgFile[],
luFiles: [
{ id: 'a.en-us', content: 'a' },
{ id: 'b.en-us', content: 'b' },
{ id: 'b.en-us', content: 'b.lu' },
] as LuFile[],
} as State;

await filePersistence.notify(state1, state2, { type: ActionTypes.CREATE_DIALOG, payload: { id: 'b' } });
const dialog = filePersistence.files['b.dialog'].file;
const lg = filePersistence.files['b.en-us.lg'].file;
const lu = filePersistence.files['b.en-us.lu'].file;
expect(dialog).toBeDefined();
if (dialog) {
expect(JSON.parse(dialog.content).b).toBe('b');
}
expect(lg).toBeDefined();
if (lg) {
expect(lg.content).toBe('b');
}
expect(lu).toBeDefined();
if (lu) {
expect(lu.content).toBe('b');
}
await filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_DIALOG, payload: { id: 'a' } });
filePersistence.notify(state1, state2, { type: ActionTypes.CREATE_DIALOG, payload: { id: 'b' } });
expect(JSON.parse(filePersistence.taskQueue['b.dialog'][0].change).b).toBe('b');
expect(filePersistence.taskQueue['b.en-us.lg'][0].change).toBe('b.lg');
expect(filePersistence.taskQueue['b.en-us.lu'][0].change).toBe('b.lu');
});

it('test notify remove', async () => {
const state1 = {
dialogs: [
{ id: 'a', content: { a: 'a' } },
{ id: 'b', content: { b: 'b' } },
{ id: 'b', content: { b: 'b.pre' } },
] as DialogInfo[],
lgFiles: [
{ id: 'a.en-us', content: 'a' },
{ id: 'b.en-us', content: 'b' },
{ id: 'b.en-us', content: 'b.pre.lg' },
] as LgFile[],
luFiles: [
{ id: 'a.en-us', content: 'a' },
{ id: 'b.en-us', content: 'b' },
{ id: 'b.en-us', content: 'b.pre.lu' },
] as LuFile[],
} as State;

Expand All @@ -150,21 +100,10 @@ describe('test persistence layer', () => {
lgFiles: [{ id: 'a.en-us', content: 'a' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: 'a' }] as LuFile[],
} as State;

await filePersistence.notify(state1, state2, { type: ActionTypes.REMOVE_DIALOG, payload: { id: 'b' } });
const dialog = filePersistence.files['b.dialog'];
const lg = filePersistence.files['b.en-us.lg'];
const lu = filePersistence.files['b.en-us.lu'];
expect(dialog).toBeUndefined();
expect(lg).toBeUndefined();
expect(lu).toBeUndefined();
});
it('test detach', async () => {
filePersistence.detach('a.dialog');
expect(filePersistence.files['a.dialog']).toBeUndefined();
});
it('test clear', async () => {
filePersistence.clear();
expect(Object.keys(filePersistence.files).length).toBe(0);
await filePersistence.notify(state1, state2, { type: ActionTypes.UPDATE_DIALOG, payload: { id: 'a' } });
filePersistence.notify(state1, state2, { type: ActionTypes.REMOVE_DIALOG, payload: { id: 'b' } });
expect(JSON.parse(filePersistence.taskQueue['b.dialog'][1].change).b).toBe('b.pre');
expect(filePersistence.taskQueue['b.en-us.lg'][1].change).toBe('b.pre.lg');
expect(filePersistence.taskQueue['b.en-us.lu'][1].change).toBe('b.pre.lu');
});
});
55 changes: 0 additions & 55 deletions Composer/packages/client/src/store/persistence/FileOperation.ts

This file was deleted.

Loading