-
Notifications
You must be signed in to change notification settings - Fork 929
WIP: refactor(database): Add migrated test harness [Part 3/3] #71
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
WIP: refactor(database): Add migrated test harness [Part 3/3] #71
Conversation
This PR presumes that #62 has been merged first. |
All integration tests pass at this point
* refactor(database): classes for typescript database implementation * refactor(database): requested changes & other improvements
0414ce2
to
8d4fd92
Compare
There are some tests that have weird timing issues, and because of the polling nature of the original implementation, we never caught the issue. These should be resolved when able
8d4fd92
to
342d527
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.
Some random feedback on EventAccumulator in case you want it. :-) I also spot-checked the tests a little bit, but didn't do a deep comparison between the old and new tests. In general, the approach looks good to me though! Thanks.
public eventData = []; | ||
public promise; | ||
public resolve; | ||
public 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.
Are you intentionally not typing these? I would have assumed we'd include types for any new code we write...
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.
Not intentional no. Just was more focused on nailing the test meaning over the helper implementation.
public resolve; | ||
public reject; | ||
constructor(private expectedEvents: number) { | ||
if (!this.expectedEvents) throw new Error('EventAccumulator:You must pass a number of expected events to the constructor'); |
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.
FWIW, the compiler will require you to pass a (number) argument, so this check shouldn't be necessary... unless you're actually trying to check for passing 0, in which case I would do an explicit === 0 check.
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.
Also, I'm not sure if just counting events will work for many of the existing waitsFor() use cases. I suspect you'll need to be able to provide a closure that inspects the event or similar.
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.
Some of the tests used the condition checking that you mentioned before, but the events were predictable enough that I just used the counts. If you feel we need the condition based then I'll prob refactor accordingly.
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.
"predictable enough" makes me a bit nervous. If you're confident the counts are predictable then it's fine, but there are definitely cases where there could be races. E.g. if you write on one connection and listen on another, you may get an initial empty event first, or you may get the written data first, depending on which one hits the server first.
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.
"predictable enough" means it really only has the possibility to vary if there is more than just the test suite hitting the server. It would probably be smart for us to find a way to isolate these tests from the firebase server somehow. That would remove a lot of moving parts.
this.reject = reject; | ||
}); | ||
} | ||
addEvent(eventData?: any) { |
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.
FWIW, "any" is considered dangerous and should generally be avoided. You could use a more specific type ("object" or "object|number|string" or something), but even better might be to make EventAccumulator generic (i.e. make it "EventAccumulator<T>", this method would take a "eventData: T" and this.promise would be a Promise<T[]>, etc. Then the events are typed all the way through. That's definitely how I'd write it from scratch, but if it complicates the migration, it's okay to do something easier.
this.eventData = [ | ||
...this.eventData, | ||
eventData | ||
]; |
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.
Hrm. Why isn't this "this.eventData.push(eventData)" ?
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.
Effectively the same thing. I have been in a habit of doing immutable arrays for a while. No big deal either way to me.
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 prefer to use push() here since it is easier to read.
eventData | ||
]; | ||
if (this.eventData.length >= this.expectedEvents) { | ||
this.resolve(this.eventData); |
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 if this gets hit multiple times? I'm not sure if resolve() will ignore or throw... My guess is you'll want it to ignore because that's what waitsFor() would essentially do (since it stops polling once the condition is met)
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.
A promise can only resolve once, so if it gets hit multiple times, only the first invocation will actually trigger a call to .then
. All other invocations are ignored.
} | ||
} | ||
reset(expectedEvents?: number) { | ||
this.expectedEvents = expectedEvents || this.expectedEvents; |
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.
FWIW, it might be cleaner to have a .waitFor(events: number): Promise method instead of this (and drop the number from the constructor).
And you could potentially have a .waitForCount(count: number) and .waitForEventMatching(condition: (event: T => boolean)) versions depending on whether you want to wait for a specific number, or wait until a condition is true, etc.
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.
Fair enough! We could refactor to add that sure. I only ever used the event counter but there were a couple cases where we could leverage the event matching if we wanted.
The tests pass as it stands, but they aren't as flexible as allowing for a condition might be.
tests/database/query.test.ts
Outdated
* We are actually hitting a server during these tests, due to | ||
* the increased potential latency, adding a little extra to | ||
* the timeout counter to help counteract tests that may seem | ||
* flaky due to network conditions |
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: This is a very run-on-y sentence. :-)
expect(childNames).to.deep.equal(['Walker', 'Michael']); | ||
done(); | ||
}); | ||
}); |
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.
did you intentionally un-promisify this? :-)
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 only refactored completely those functions that chained runs
/waitsFor
blocks. If there was a path were there was a smaller code delta (in this case the function waited for an assignment of a truthy value to done
) then I favored that.
This is something we could clean up as well if we wanted and I'm totally in favor of this. Just already a lot of code change and wanted to make review easy where I could.
68ac56c
to
379a263
Compare
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that they're okay with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
4add144
to
2939025
Compare
@@ -1,6 +1,6 @@ | |||
import { IndexedFilter } from "./IndexedFilter"; | |||
import { PRIORITY_INDEX } from "../../../core/snap/indexes/PriorityIndex"; | |||
import { NamedNode } from "../../../core/snap/Node"; | |||
import { Node, NamedNode } from "../../../core/snap/Node"; |
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 doesn't seem to be needed.
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.
Typescript throws an "Unknown Symbol" compiler error if it isn't present :(
@@ -114,7 +114,7 @@ export const buildLogMessage_ = function(var_args) { | |||
* Use this for all debug messages in Firebase. | |||
* @type {?function(string)} | |||
*/ | |||
export var logger = console.log.bind(console); | |||
export var logger = null; |
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.
Intentional?
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.
Yes, the value is originally null
. I set it because I was using the logging everywhere.
src/database/core/util/SortedMap.ts
Outdated
@@ -714,35 +714,35 @@ export class SortedMap { | |||
* @param {(function(K, V):T)=} opt_resultGenerator | |||
* @return {SortedMapIterator.<K, V, T>} The iterator. | |||
*/ | |||
getIterator(opt_resultGenerator) { | |||
getIterator(resultGnerator?) { |
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.
Typo (here and everywhere)
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'll get it fixed.
// This test mostly exists to make sure restRef really is using ReadonlyRestClient | ||
// and we're not accidentally testing a normal Firebase connection. It also can | ||
// be a little slow so adding an extra timeout to help out. | ||
this.timeout(3500); |
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 prefer that we set a global timeout for these tests rather than individual ones.
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.
Agreed, I'll update this
tests/database/helpers/events.ts
Outdated
@@ -31,7 +31,7 @@ function rawPath(firebaseRef) { | |||
* @param {string=} opt_helperName | |||
* @return {{waiter: waiter, watchesInitializedWaiter: watchesInitializedWaiter, unregister: unregister, addExpectedEvents: addExpectedEvents}} | |||
*/ | |||
export function eventTestHelper(pathAndEvents, helperName?, eventAccumulator?: EventAccumulator) { | |||
export function eventTestHelper(pathAndEvents, helperName?, eventAccumulator?: EventAccumulator | EventAccumulator[]) { |
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 could be converted to a vararg.
tests/database/helpers/events.ts
Outdated
@@ -166,6 +189,7 @@ export function eventTestHelper(pathAndEvents, helperName?) { | |||
actualPathAndEvents.splice(actualPathAndEvents.length - initializationEvents, initializationEvents); | |||
initializationEvents = 0; | |||
|
|||
initResolve(); |
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: This is more of a "resolveInit()", since initX sounds like it would initialize X.
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.
Done
My comments look to be addressed in your reviews. Do you want to merge this PR as well? I think we still need to be some time making this more TypeScript like, but I don't want to block progress on further database development. |
Per convo with @schmidt-sebastian we are going to merge this and will address any lasting issues before merge to master. |
* refactor(database): remove old database implementation [Part 1/3] (#61) * refactor(database): remove old database implementation This is part #1 of 4 PR's to migrate database * refactor(database): remove database build processes * refactor(database): Add typescript database implementation [Part 2/3] (#62) * refactor(database): add typescript implementation * refactor(database): update build process to include database.ts All integration tests pass at this point * refactor(*): refactor environment builds to be based on separate .ts files * WIP: patch database code in nodeJS * refactor(database): classes for typescript database implementation (#55) * refactor(database): classes for typescript database implementation * refactor(database): requested changes & other improvements * fix(database): Add missing "typeof" (#74) https://github.com/firebase/firebase-js-sdk/blob/fd0728138d88c454f8e38a78f35d831d6365070c/src/database/js-client/core/Repo.js#L86 * WIP: fixes from @schmidt-sebastian's review * WIP: fix: TS Build error * fix(database): fix issue with missing repo method * WIP: review adjustments #1 * WIP: review comments #2 * WIP: refactor(database): Add migrated test harness [Part 3/3] (#71) * refactor(database): add typescript implementation * refactor(database): update build process to include database.ts All integration tests pass at this point * refactor(*): refactor environment builds to be based on separate .ts files * WIP: patch database code in nodeJS * refactor(database): classes for typescript database implementation (#55) * refactor(database): classes for typescript database implementation * refactor(database): requested changes & other improvements * WIP: add the /tests/config dir to the .gitignore * WIP: add test harness * WIP: add query tests There are some tests that have weird timing issues, and because of the polling nature of the original implementation, we never caught the issue. These should be resolved when able * WIP: add database.test.ts * WIP: add node.test.ts * WIP: add sortedmap.test.ts * WIP: add datasnapshot.test.ts * WIP: add sparsesnapshottree.test.ts * refactor(database): refactor query.test.ts to better preserve original test meaning * WIP: add crawler_support.test.ts * WIP: refactor EventAccumulator.ts for data.test.ts * WIP: fix issue with query.test.ts * WIP: add connection.test.ts * WIP: add info.test.ts * WIP: add order_by.test.ts I only migrated some of these tests as there was a dependency on the server for several tests * WIP: fix several code signature problems, add test files * WIP: add transaction.test.ts * WIP: working on the broken npm test command * WIP: working on fixes * WIP: remove logging * WIP: fix node tests * fix(*): fixing test files and CI integration * WIP: tEMP: Allow branch builds * WIP: escape string * refactor(CI): use ChromeHeadless launcher * WIP: fixes from review. * WIP: skip flakey test * WIP: remove unneeded debugger statement * WIP: fixing nits * Prevent using uninitialized array in EventEmitter (#85) * perf(*): fixing build size output issues * chore(*): remove unneeded build deps
Migrate the old test harness to the repo