-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Enterprise Search] Added Logic for the Credentials View #77626
Conversation
x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts
Outdated
Show resolved
Hide resolved
b0fcf4a
to
a5d638e
Compare
}); | ||
}); | ||
|
||
it('should not change any other values', () => { |
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 added one of these tests to each action. My reasoning is this:
- As I was testing, it helped ensure for me that I had covered all of the necessary values with tests. It will also serve as a reminder to add test coverage as we make updates as well.
- Avoid unintentional values changes in actions
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.
Follow up to my comment here: #77626 (comment)
I strongly think we should not have extra tests specifically for should not change any other values
. It's hard to read/understand, doesn't add anything significantly to line coverage, and bloats the file. That said, it's fully possible to check for this in your existing active tests. Simply do this:
// example assertion for "should remove an engine from the active api token's engine list" test
expect(CredentialsLogic.values).toEqual({
...DEFAULT_VALUES,
activeApiToken: {
...newToken,
engines: ['anotherEngine'],
},
});
Instead of:
Lines 144 to 147 in 91392ae
expect(CredentialsLogic.values.activeApiToken).toEqual({ | |
...newToken, | |
engines: ['anotherEngine'], | |
}); |
... and bam, you've proved other values haven't changed at the same time you have asserted your expected values do change, in a fixed 3 lines instead of 9+ 🤷 (also cuts down on test times / time spent mounting extra tests, etc.)
FWIW, we also don't have to check the full expect(SomeLogic.values)
for every action/value block, just the first one. Follow up edge case/conditional branch tests can simply check SomeLogic.values.someValue
after that since the first test asserts unchanged values for us.
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 gets a little weird when you have a bunch of values that change when you fire an action though, because then you can't just use DEFAULT_VALUES.
expect(CredentialsLogic.values).toEqual({
...DEFAULT_VALUES,
someOtherThing: 'foo',
anotherValueThatChanged: 'bar',
activeApiToken: {
...newToken,
engines: ['anotherEngine'],
},
});
You'd have to put in assertions for anotherValueThatChanged
and someOtherThing
as well, as seen above. At which point it's like, well I have a separate test for anotherValueThatChanged
and someOtherThing
below, why do I need both if it's being asserted here?
One way to avoid that is to use expect.any
to make it clear that that is not what's under test currently, and we don't care what is provided here.
expect(CredentialsLogic.values).toEqual({
...DEFAULT_VALUES,
someOtherThing: expect.any(string),
anotherValueThatChanged: expect.any(string),
activeApiToken: {
...newToken,
engines: ['anotherEngine'],
},
});
Which is what I arrived at, and I ultimately thought it would be clearer to just move that into a separate test so it's explicit what is being tested. I may have taken it a step too far though.
I don't have a strong opinion here. I think it IS important to assert that the other values do not change somehow though. The entire updated state (the values) are returned from every action and hence part of the public interface of that action and should be asserted. If you prefer the inline assertion on the first test, I find that acceptable.
I wonder if something like this would work....
const values = {
...DEFAULT_VALUES,
someOtherThing: expect.any(string),
anotherValueThatChanged: expect.any(string),
activeApiToken: expect.any(object)
}
....
expect(CredentialsLogic.values).toEqual({
...values,
activeApiToken: {
...newToken,
engines: ['anotherEngine'],
},
});
...
expect(CredentialsLogic.values).toEqual({
...values,
anotherValueThatChanged: 'foo'
});
...
expect(CredentialsLogic.values).toEqual({
...values,
someOtherThing: 'foo'
});
Thoughts?
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.
You totally beat me to this lol, I spent a few more hrs last night reading through the test file and definitely get now why my proposed solution doesn't work well for all the test suites (esp. the ones dealing w/ a bunch of deeply nested obj children).
You'd have to put in assertions for anotherValueThatChanged and someOtherThing as well, as seen above. At which point it's like, well I have a separate test for anotherValueThatChanged and someOtherThing below, why do I need both if it's being asserted here?
Definitely a good point, and also potentially a indication that (for some, definitely not all) tests, it may be worth considering whether it would be easier to just group all the changes values in a combined single test/assertion, rather than splitting them out 🤔 That being said, I totally get why not though for a lot of the more complex tests - also this is not me requesting a change to the current PR, just potentially food for thought for future logic tests.
All that being said, I also like the proposed compromise a lot! Would love to give it a shot - feel free to timebox though, if it starts taking too long to refactor or creates unexpected issues I'd also be fine leaving the current should not change
tests as-is.
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 removed the should not change tests and implemented the solution proposed above: 6347c61
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Outdated
Show resolved
Hide resolved
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Show resolved
Hide resolved
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Outdated
Show resolved
Hide resolved
}); | ||
|
||
describe('activeApiToken', () => { | ||
// TODO It is weird that methods like this update activeApiToken but not activeApiTokenIsExisting... |
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 found some oddities around this logic file that I just noted in TODOs for now. This is a good example. Everywhere else in the code, when we change the activeApiToken
, we also update activeApiTokenIsExisting
. They are manually kept in sync. Here, we do not update activeApiTokenIsExisting
.
I think the ultimate solution is to change activeApiTokenIsExisting
to be a selector, so we don't need to try to keep it in sync 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 think this is a super good example of unit tests catching a design flaw in code! I'd be +++ for fixing this behavior - this does indeed sound like the exact use-case for a selector.
Also while we're here, would we have any objections to renaming activeApiTokenIsExisting
? It's fairly awkward-sounding - maybe doesActiveApiTokenExist
or even just hasActiveApiToken
instead?
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.
BTW, would activeTokenRawName
be another good use-case to convert to a selector?
EDIT: After starting at this further it actually kinda feels to me like activeTokenRawName
should be the reducer and activeTokenName
should be the selector, since it undergoes a format. So something like activeTokenName
is the raw name and activeTokenFormattedName
is the final name 😛 Probably too annoying/large a change at this point tho so feel free to disregard unless you really like that idea
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.
Since we know this works as is, and this PR is already big, I'd like to address this is a follow-up PR.
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.
Sounds great! No rush at all!
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Show resolved
Hide resolved
}); | ||
|
||
// TODO Not sure if this is a good behavior or not | ||
it('if for some reason the existing token is not found, it adds a new token...', () => { |
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 shouldn't ever happen theoretically, because this gets triggered after a user updates and saves a token. If this happens, something went wrong. I am just documenting the behavior as written, though.
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.
Good point - I can't quite figure out if we should change this or not either 🤔 I'm fine kicking the can down on the road on this one I think / marking as tech debt for later
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.
Since we know this works as is, and this PR is already big, I'd like to address this is a follow-up PR.
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Outdated
Show resolved
Hide resolved
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Outdated
Show resolved
Hide resolved
); | ||
}); | ||
|
||
// TODO: This fails, is this an issue? Instead of reseting back to the default value, it sets it to the previously |
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.
Another oddity I found.
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.
Would be ++ for fixing. After some thought (maybe it's just very late) not totally sure how activeApiTokenRawName
works as a selector tho - shouldn't activeApiTokenName
be the selector instead? 🤷
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.
Since we know this works as is, and this PR is already big, I'd like to address this is a follow-up PR.
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.
Oh yeah, now that I think about it...
When a user enters a token name and then saves it, the token name is formatted before it's persisted to activeApiToken.name
.
activeApiTokenRawName
persists the unformatted name that the user had entered. I'm guessing this is used to back the form field, so is transient and only required until the user presses save.
...enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
Show resolved
Hide resolved
...enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/server/routes/app_search/credentials.ts
Show resolved
Hide resolved
a5d638e
to
7641d56
Compare
...enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
Show resolved
Hide resolved
...enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
Outdated
Show resolved
Hide resolved
...enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/public/applications/app_search/utils/format_api_name.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/public/applications/app_search/utils/format_api_name.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/public/applications/app_search/utils/index.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/public/applications/app_search/utils/format_api_name.test.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/public/applications/app_search/constants/credentials.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/public/applications/app_search/types.ts
Outdated
Show resolved
Hide resolved
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.
Ran tests on the credentials file and noticed we had a just few more uncovered lines to go. I know it's possibly unhealthy to chase those sweet sweet green 100%s with too much fervor, but in this case I think it's not too much extra effort to cover the lines we need (and in one case, reveals unnecessary code).
Let me know what you think!
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Outdated
Show resolved
Hide resolved
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Show resolved
Hide resolved
...enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
Outdated
Show resolved
Hide resolved
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Outdated
Show resolved
Hide resolved
Ah yes, I meant to run the coverage report but I ended up forgetting. I need to get in the habit of checking. I definitely feel the need to scratch that itch as well. |
@constancecchen Ready for a second look |
...prise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/enterprise_search/public/applications/app_search/types.ts
Outdated
Show resolved
Hide resolved
Changes look great!! Just two super minor comments left from me 🤞 |
💚 Build SucceededMetrics [docs]
History
To update your PR or re-run it, just comment with: |
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.
🎉 Wahoo!!! This looks amazing. Thanks so much as always for your patience with my review process Jason!
interface ITokenReadWrite { | ||
name: 'read' | 'write'; | ||
checked: boolean; | ||
} |
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.
Totally forgot to mention this too, but this one's super optional so feel free to ignore or do it another PR if you like it :) This might be a good candidate for moving to credentials/types
, but it's also used right here in this file, so whatever works for 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.
Good call. I will put this one up in my next PR.
@constancecchen Thanks for the review! |
* master: (226 commits) [Enterprise Search] Added Logic for the Credentials View (elastic#77626) [CSM] Js errors (elastic#77919) Add the @kbn/apm-config-loader package (elastic#77855) [Security Solution] Refactor useSelector (elastic#75297) Implement tagcloud renderer (elastic#77910) [APM] Alerting: Add global option to create all alert types (elastic#78151) [Ingest pipelines] Upload indexed document to test a pipeline (elastic#77939) TypeScript cleanup in visualizations plugin (elastic#78428) Lazy load metric & mardown visualizations (elastic#78391) [Detections][EQL] EQL rule execution in detection engine (elastic#77419) Update tutorial-full-experience.asciidoc (elastic#75836) Update tutorial-define-index.asciidoc (elastic#75754) Add support for runtime field types to mappings editor. (elastic#77420) [Monitoring] Usage collection (elastic#75878) [Docs][Actions] Add docs for Jira and IBM Resilient (elastic#78316) [Security Solution][Resolver] Update @timestamp formatting (elastic#78166) [Security Solution] Fix app layout (elastic#76668) [Security Solution][Resolver] 2 new functions to DAL (elastic#78477) Adds new elasticsearch client to telemetry plugin (elastic#78046) skip flaky suite (elastic#78512) (elastic#78511) (elastic#78510) (elastic#78509) (elastic#78508) (elastic#78507) (elastic#78506) (elastic#78505) (elastic#78504) (elastic#78503) (elastic#78502) (elastic#78501) (elastic#78500) ...
Friendly reminder: Looks like this PR hasn’t been backported yet. |
Summary
This PR adds the logic and API endpoints necessary for the Credentials View.
The logic file was ported largely as is from https://github.com/elastic/ent-search/blob/master/app/javascript/app_search/Credentials/CredentialsLogic.ts
I've added a number of comments inline explaining some of the thought behind the changes I made.
The main things that I added were:
Everything else is supporting code.
Checklist
Delete any items that are not applicable to this PR.
For maintainers