-
Notifications
You must be signed in to change notification settings - Fork 304
feat(cli): Add support for password credential in redis helper #6213
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
feat(cli): Add support for password credential in redis helper #6213
Conversation
317c4cf to
997c3ce
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.
Thanks for adding e2e tests for this - great to see it coming together.
I left a comment around the what is happening parseCredentials
Also when working on add CLI comments I really love to see some sample CLI usage in the PR description as it clearly shows what the UX will be. Could you add CLI request and response for:
- Create a password credential
- Add it as a brokered credential source, and then should the response from
boundary connect(not the redis connect as I don't want it consumed)
8f10b67 to
24e2d38
Compare
testing/internal/e2e/tests/base/target_tcp_connect_redis_test.go
Outdated
Show resolved
Hide resolved
3b9ffeb to
d7d5258
Compare
| t.Cleanup(func() { | ||
| flushRedis(t, ctx, resources.targetId) | ||
| }) |
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 why you did this here. However, can we just flush it at the end of the test (where we are running the commands) after the GET command? This would save us from connecting to the target once again?
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 chose to separate the cleanup from the validation logic here for readability and maintainability. i think the trade-off of requiring a reconnect is worth it
if for some reason someone needs to update this test they don't need to pay attention to cleanup logic (they can't accidentally insert after flushing for example)
| for _, c := range cases { | ||
| t.Run(c.name, func(t *testing.T) { | ||
| // Setup | ||
| resources := setupBoundaryCredentialStore(t, ctx, redisInfo.Hostname, redisInfo.Port) |
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): can we reuse one credential store for all tests in the list instead of setting one up per test? I feel like both approaches are fine so I will leave it up to you on this one
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 it's better to have complete isolation here. it's unlikely but possible for a test to reconfigure resources, and that could cause issues if they are shared. we just avoid a lot of issues by ensuring there's a clean setup for each step
i'd consider recreating redis too, but i think that is probably overkill 🤔
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.
One idea I'm toying with is actually just separating these into two different tests in different files
target_tcp_connect_redis_username_password_test.go
target_tcp_connect_redis_password_test.go
That would help with readability of the test and how this file is currently organized. That would make it so you're recreating redis, but docker containers aren't too bad to spin up and down.
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.
redis starts up pretty quickly. would you choose separate files over creating two separate test functions in this file? i originally had two functions like so:
func TestCliTcpTargetConnectRedisWithUsernamePassword(t *testing.T) {...}
func TestCliTcpTargetConnectRedisWithPassword(t *testing.T) {...}
we moved to using subtests to re-use redis and reduce repeated code. i am partial to to having separate functions within the same file because it's a bit easier to browse in an IDE, and simpler to share helper functions if 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.
I may be off-base in my opinion right now 😅 but here's what i'm thinking
- I'm less concerned about repeated code in e2e tests as they are limited in scope. They also help to serve as sort of like documentation for how to run certain tests.
- I'm currently leaning towards having separate files. Part of me likes having one e2e test in a file. It keeps the file length smaller and helps to see the e2e coverage when looking at the files in a folder.
Please feel free to challenge those opinions.
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 saw your comment after i updated my comment, so i will just reiterate to make sure it's not lost:
- that's a really great point about repeated code in e2e, thanks for the insight!
- regarding the test organization:
- having the tests in one file improves readability/organization when there are shared helper functions (although based on other comments these helpers are probably getting removed or refactored into a more appropriate place anyways)
- just noting: some of the other e2e test files have multiple test functions already so using relying on filenames isn't giving us a full picture as it is. so you'd have to dive into those files anyways. it can still help if we stick to one test per file moving forward though
- i think in most scenarios, people would be more interested in the coverage over a particular feature rather than overall coverage. it's easier to scroll down the outline / function list to see coverage of a feature, there is less to parse through because i'm not looking at a list containing unrelated filenames
- i do agree that having smaller test files is a lot more readable than the large ones
i don't have a strong opinion on this, just exploring the options here. let me know if that has changed your mind or if you'd prefer to stick to one test per file 😄
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 went ahead and put them into separate files for now based on your original suggestion:
target_tcp_connect_redis_username_password_test.go
target_tcp_connect_redis_password_test.go
| // provided static credential store. | ||
| // Returns the id of the new credential | ||
| func CreateStaticCredentialPasswordCli(t testing.TB, ctx context.Context, credentialStoreId string, user string, password string) (string, error) { | ||
| func CreateStaticCredentialUsernamePasswordCli(t testing.TB, ctx context.Context, credentialStoreId string, user string, password string) (string, error) { |
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 change makes sense. Appreciate the cleanup/refactor here
| require.NoError(t, err) | ||
| require.Equal(t, c.expectedUsername, output) | ||
|
|
||
| output, err = sendRedisCommand(stdin, stdout, "SET e2etestkey e2etestvalue\r\n") |
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 we could randomize or name the key that's used here to prevent any potential conflicts? A potential idea could be
t.Name() + timestamp
That way, we could potentially remove the need for that FLUSH.
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 like this idea, i will add it 😄
i'd prefer to keep the flush to ensure a clean slate for the next test (and to stick to the principle of isolating these tests from each other). i don't think there is much overhead to doing that here, and in the scenario someone updates this test, it will help ensure the tests don't affect each other.
although if we split the test apart like you suggested in the other comment and spin up redis per test, then we wouldn't need to flush
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.
actually ended up keeping the existing code since we're recreating the redis containers now
| } | ||
|
|
||
| // setupRedisContainer starts a Redis container and returns its connection info | ||
| func setupRedisContainer(t *testing.T, ctx context.Context) *redisContainerInfo { |
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.
Feels like some of these redis methods might be better suited in another package? One idea is in e2e/infra/redis_docker.go?
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 agree, especially if we want to consider splitting the test into separate files. your suggestion makes sense, i'll go ahead and try that
| for _, c := range cases { | ||
| t.Run(c.name, func(t *testing.T) { | ||
| // Setup | ||
| resources := setupBoundaryCredentialStore(t, ctx, redisInfo.Hostname, redisInfo.Port) |
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.
One idea I'm toying with is actually just separating these into two different tests in different files
target_tcp_connect_redis_username_password_test.go
target_tcp_connect_redis_password_test.go
That would help with readability of the test and how this file is currently organized. That would make it so you're recreating redis, but docker containers aren't too bad to spin up and down.
ad72114 to
45054ca
Compare
louisruch
left a comment
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.
Great work on this! Please wait for @moduli to approve as well before merging
bgajjala8
left a comment
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.
LG2M! 😄
45054ca to
779e378
Compare
moduli
left a comment
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.
one minor comment, but looks good
|
|
||
| // TestCliTcpTargetConnectRedis uses the boundary cli to connect to a target using `connect redis` | ||
| func TestCliTcpTargetConnectRedis(t *testing.T) { | ||
| func TestCliTcpTargetConnectRedisUsernamePassword(t *testing.T) { |
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: perhaps a comment describing the intent of the test?
// TestCliTcpTargetConnectRedisUsernamePassword uses the boundary cli to connect to a target using `connect redis`. The target is configured to use a username/password credential... etc. etc.
same with the other 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.
will add descriptions, thanks for catching this
779e378 to
2b4a102
Compare
Moving password changes as a new migration
Moving password changes as a new migration
Description
UsernamePasswordfor usage in brokeringSample CLI Usage
(most responses omitted for brevity)
boundary scopes create -scope-id globalboundary scopes create -scope-id o_fJtwTPHZdMboundary targets create tcp -name "test-target" -scope-id p_SdrMtBv6Zi -default-port 22 -address 127.0.0.1boundary credential-stores create static -scope-id p_SdrMtBv6Ziexport TESTPASS="test-password"boundary credentials create password -credential-store-id csst_POG2btczXC -password env://TESTPASS -name test-pcredboundary targets add-credential-sources -id ttcp_tucp5A15x1 -brokered-credential-source credp_DlHnSSRBpuboundary connect -target-id ttcp_tucp5A15x1