-
-
Notifications
You must be signed in to change notification settings - Fork 345
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
Add tests for UsersManager #1149
Conversation
b65d331
to
c5a693e
Compare
2cf3fdb
to
abdfccc
Compare
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.
Comments after having taken a look at the PR with @hexaltation
ca8492a
to
7d8b326
Compare
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.
LGTM
import { updateDb } from 'app/server/lib/dbUtils'; | ||
|
||
const username = process.env.USER || "nobody"; | ||
const tmpDir = path.join(tmpdir(), `grist_test_${username}_userendpoint`); |
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.
Should we randomize it more? Runing this test twice will reuse the same folder?
https://dev.to/omardulaimi/how-to-create-unique-temporary-directories-in-nodejs-1n69
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.
I would say it is not necessary.
The point here is:
- to have a temporary path, so it does not pollute the user filesystem;
- to have a predictable path, so you can take a look after the tests run at the assets (here the databases) if something surprising happened;
- to have this folder cleared before each run thanks to the call of
prepareFilesystemDirectoryForTests
(called here), so the test run is not affected by previous ones.
What do you think? Does it make sense 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.
I'm just worry about running this tests twice (simultaneously) on the same machine, most of our tests (if not all of them) can be run simultaneously without a problem.
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.
I see!
FWIW, I took inspiration of what those other tests suit do:
- Webhook-Proxies (tmpDir declaration and use of prepareFilesystemDirectoryForTests);
- DocsApi (tmpDir declaration and use of prepareFilesystemDirectoryForTests);
That being said, I can think of something that would get the best of the two worlds.
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.
this.timeout(30000); | ||
|
||
describe('static method', function () { | ||
function* makeIdxIterator() { |
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 you move helper methods to the end of the file? (And even outside of the describe
funcition)
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.
I prefer having the helper functions in the most limited scope, so it is clear where it is meant to be used, and for what purpose.
That being said, if you say your convention is to rather put all the helper at the end, I would agree to follow it.
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.
Ok, I don't have a strong opinion here. I just prefer to have them hidden, or not to have them at all :).
} | ||
} | ||
|
||
function makeUsers(nbUsers: number, idxIt = makeIdxIterator()) { |
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 you use here the range
function from lodash
? I think it will look much more simpler, this one is hard to follow.
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.
I need to keep track of the increment for users' id across makeUsers
call. When I call makeUsers
let's say this way:
const idxIt = makeIdxIterator();
const groupsUsersMap = {
'editors': makeUsers(2, idxIt),
'owners': makeUsers(1, idxIt),
};
groupsUsersMap equals to the following object, whose users' id are unique:
{
'editors': [{id: 0, name: 'user 0'}, {id: 1, name: 'user 1'}],
'owners': [{id: 2, name: 'user 2'}]
}
I don't know how to make a similar thing with lodash.range()
.
An alternative I can do, but I find it less elegant, would consist in passing the start index each time:
let startIdx = 0;
const groupsUsersMap = {};
groupsUsersMap['editors'] = makeUsers(2, startIdx);
startIdx += 2;
groupsUsersMap['owners'] = makeUsers(1, startIdx);
startIdx += 1;
}); | ||
} | ||
|
||
function makeUsersList(usersListLength: number, nbUsersByGroups: number) { |
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.
What does nb
stands for?
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.
number of
. I am commenting the function, with the hope to make things clearer
@berhalak I think of something: my test assume that they run using Sqlite. Several questions come to my mind:
To the first question, my answer would be no, the UsersManager uses a lot of TypeORM methods, and does not seem to make SQL query directly (but I may be a bit biased by my lazyness). |
42eee85
to
2a2ccf1
Compare
Mostly styling issues
To address @berhalak comment: > I'm just worry about running this tests twice (simultaneously) on the same machine, most of our tests (if not all of them) can be run simultaneously without a problem.
2a2ccf1
to
eaaff1b
Compare
} | ||
} | ||
|
||
export function dereferenceConnection(name: string) { | ||
// There seem to be no official way to delete connections. | ||
// Also we should probably get rid of the use of connectionManager, which is deprecated |
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.
I am tempted to do that right now, but I fear that the PR becomes huge, especially to review it.
The new way consist in using DataSource
(which is the new name for the Connection
class, renamed because it is confusing), and instantiate using the constructor in place of createConnection
.
We won't have any name collision, as only the ConnectionManager use it for other purposes than identifying the DataSource in error messages.
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.
Thanks @fflorent!
test/gen-server/seed.ts
Outdated
export async function removeConnection() { | ||
if (getConnectionManager().connections.length > 0) { | ||
if (getConnectionManager().connections.length > 1) { | ||
export async function removeConnection(name?: string) { |
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 name parameter doesn't seem to be used here.
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.
That's true, thanks!
We run some tests with Postgresql in our internal CI, but since it is not part of the |
if (!connectionMap.has(name)) { | ||
throw new Error('connection with this name not found: ' + name); | ||
} | ||
connectionMap.delete(name); |
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 possible this results in the change of behavior we see in our tests @fflorent? This is a pretty murky corner of TypeORM.
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.
I feel more like the issue is due to this helper:
https://github.com/gristlabs/grist-core/pull/1149/files#diff-3d1ec6a021479fb3895f89f5c855b14f664e45c31e979082da277538b906cc5cR264-R282
Which has been introduced to test functions related to special ids, but I feel like these two tests bring more pain than are actually helpful:
- The test that check the getters related to the special IDs without initialization fail
- The test of initializeSpecialIds
I also tried to see whether removing the Connection related methods in favor of using DataSource would help, but with no luck (see #1166, which I may continue to work on but rather for the satisfaction of stop using deprecated entities and functions).
So I won't mind removing these tests, especially if it solves your failures, I agree that it deals with strange behaviors of TypeORM.
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 is awkward getting this sorted out, so I'm going to land and that'll force us to sort it out internally. Thanks for the suggestions.
Thank you @paulfitz! |
Context HomeDBManager lacks of direct tests, which makes hard to make rework or refactorations. Proposed solution Specifically here, I introduce tests which call exposed UsersManager methods directly and check their result. Also: I removed updateUserName which seems to me useless (updateUser does the same work) Taking a look at the getUserByLogin methods, it appears that Typescirpt infers it returns a Promise<User|null> while in no case it may resolve a nullish value, therefore I have forced to return a Promise<User> and have changed the call sites to reflect the change. Related issues I make this change for then working on gristlabs#870
Context
HomeDBManager lacks of direct tests, which makes hard to make rework or refactorations.
Proposed solution
Specifically here, I introduce tests which call exposed UsersManager methods directly and check their result.
Also:
updateUserName
which seems to me useless (updateUser
does the same work)getUserByLogin
methods, it appears that Typescirpt infers it returns aPromise<User|null>
while in no case it may resolve a nullish value, therefore I have forced to return aPromise<User>
and have changed the call sites to reflect the change.Related issues
I make this change for then working on #870
Has this been tested?