-
Notifications
You must be signed in to change notification settings - Fork 76
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
CLOUDP-289219: Create CLI commands for manipulating stream processors #3496
base: master
Are you sure you want to change the base?
Conversation
22ef83a
to
e916573
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.
Next time, it might be a little easier to review if we break down the commits into each command or each command into their own PR :)
Dropping comments because I think I have gone through all of the create
command. I haven't looked but I will try not to leave the same comments on the other commands if they have the same issues. I will continue looking at the other commands and try to only leave net new stuff
ListProcessors(*atlasv2.ListStreamProcessorsApiParams) (*atlasv2.PaginatedApiStreamsStreamProcessorWithStats, error) | ||
} | ||
|
||
type ProcessorDescriber interface { | ||
StreamProcessor(*atlasv2.GetStreamProcessorApiParams) (*atlasv2.StreamsProcessorWithStats, error) | ||
} | ||
|
||
type ProcessorStarter interface { | ||
StartStreamProcessor(*atlasv2.StartStreamProcessorApiParams) error | ||
} | ||
|
||
type ProcessorStopper interface { | ||
StopStreamProcessor(*atlasv2.StopStreamProcessorApiParams) error | ||
} | ||
|
||
type ProcessorDeleter interface { | ||
DeleteStreamProcessor(string, string, string) error | ||
} | ||
|
||
type ProcessorCreator interface { | ||
CreateStreamProcessor(*atlasv2.CreateStreamProcessorApiParams) (*atlasv2.StreamsProcessor, 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.
Can you name the arguments to each of these functions?
For example, it is hard to know what each of the parameters are/should be for DeleteStreamProcessor
} | ||
|
||
// DeleteStreamProcessor deletes the specified Stream Processor. | ||
func (s *Store) DeleteStreamProcessor(projectID, tenantName, processorName 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.
It is interesting that the other functions here all take a request and pull what they need while this method takes each value as a string. I have a personal preference towards this approach (explicitly calling for what you need rather than taking a whole request object), but more important than one direction vs the other I think we should be consistent.
Pick one approach and stick to it for the implementations unless there is something that makes this method especially unique.
* - -o, --output | ||
- string | ||
- false | ||
- Output format. Valid values are json, json-path, go-template, or go-template-file. To see the full output, use the -o json option. |
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 is the purpose of outputing a create command? Why would someone want to dump Processor <Name> created.
to a file?
}, | ||
} | ||
|
||
cmd.Flags().StringVar(&opts.ProjectID, flag.ProjectID, "", usage.ProjectID) |
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 start using:
cmd.Flags().StringVar(&opts.ProjectID, flag.ProjectID, "", usage.ProjectID) | |
opts.AddProjectOptsFlags(cmd) |
_ = cmd.MarkFlagFilename(flag.File) | ||
|
||
_ = cmd.MarkFlagRequired(flag.Instance) | ||
_ = cmd.MarkFlagRequired(flag.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.
[nit] Is it a linting rule that makes us have to assign to something? I think it would be a little cleaner to do something like this:
_ = cmd.MarkFlagFilename(flag.File) | |
_ = cmd.MarkFlagRequired(flag.Instance) | |
_ = cmd.MarkFlagRequired(flag.File) | |
cmd.MarkFlagFilename(flag.File) | |
cmd.MarkFlagRequired(flag.Instance) | |
cmd.MarkFlagRequired(flag.File) |
* - -f, --file | ||
- string | ||
- true | ||
- Path to a JSON configuration file that defines an Atlas Stream Processing connection. |
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 this creating stream processor connection or a stream processor?
require.Error(t, err) | ||
assert.Contains(t, err.Error(), "missing 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.
Could these be combined?
require.Error(t, err) | |
assert.Contains(t, err.Error(), "missing file") | |
assert.Contains(t, err, "missing 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.
Similar comment for all the error assertions
}, | ||
} | ||
|
||
name := "ExampleSP" |
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] we should either inline this down where it is used or use string interpolation to inject this value into the string that is written to the config file so that it is forced to be aligned with the test input and the expected output. Assigning it to a variable that we don't reuse feels weird.
if err := createOpts.Run(); err != nil { | ||
t.Fatalf("Run() unexpected error: %v", err) | ||
} | ||
t.Log(buf.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.
Is this a debugging line? Maybe it should be removed?
t.Fatalf("Run() unexpected error: %v", err) | ||
} | ||
t.Log(buf.String()) | ||
test.VerifyOutputTemplate(t, createTemplate, expected) |
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 this assertion verify? It isn't clear what it actually does, we might want a comment here, especially because I think it might be asserting the same thing as the next line?
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.
E2E tests reviewed
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.
[q] I am only seeing this used by changes from 8 months ago. Any ideas why it is being added in your PR/where it is coming from?
a.Equal(processorName, *processor.Name) | ||
}) | ||
|
||
t.Run("Describe a stream processor with an atlas cluster sink", func(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.
All of the tests below this one concern me because they are relying on data populated/created by previous t.Run() tests. Each test should be able to function in isolation. If you want to rely on previous configuration, then it should be nested within the test.
I would recommend each of the commands describe
, list
, delete
, start
, stop
do all of the creation/setup necessary and just don't run assertions on those steps (since the assertions are covered here).
An alternative idea is to create a larger E2E test that tests everything. It could create, do assertions on the creation; describe, do assertions on the describe; list and assert; start and assert; stop and assert; and delete and assert.
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.
Delete and Describe reviewed
} | ||
cmd := &cobra.Command{ | ||
Use: "delete <processorName>", | ||
Short: "Delete a specific Atlas Stream Processor in a Stream Processing Instance.", |
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]
Short: "Delete a specific Atlas Stream Processor in a Stream Processing Instance.", | |
Short: "Delete an Atlas Stream Processor in a Stream Processing Instance.", |
cmd := &cobra.Command{ | ||
Use: "delete <processorName>", | ||
Short: "Delete a specific Atlas Stream Processor in a Stream Processing Instance.", | ||
Long: fmt.Sprintf(usage.RequiredRole, "Project Read Only"), |
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 role doesn't seem correct.... I don't think you should be able to delete with a read only role.
"github.com/mongodb/mongodb-atlas-cli/atlascli/internal/mocks" | ||
) | ||
|
||
func TestDeleteOpts_Run(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.
There should be a t.Run()
call in this test describing what is being tested/asserted.
opts := &DescribeOpts{} | ||
cmd := &cobra.Command{ | ||
Use: "describe <processorName>", | ||
Short: "Get details about a specific Atlas Stream Processor in a Stream Processing Instance.", |
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]
Short: "Get details about a specific Atlas Stream Processor in a Stream Processing Instance.", | |
Short: "Get details about an Atlas Stream Processor in a Stream Processing Instance.", |
func DescribeBuilder() *cobra.Command { | ||
opts := &DescribeOpts{} | ||
cmd := &cobra.Command{ | ||
Use: "describe <processorName>", |
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, this command seems like it would make more sense to have a json output file that is the .json configuration file that would work with the create command (and eventually update).
if opts.includeStats { | ||
return opts.Print(r) | ||
} | ||
|
||
sp := atlasv2.NewStreamsProcessorWithStats(r.Id, r.Name, r.Pipeline, r.State) | ||
return opts.Print(sp) |
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 the logic is backwards here... we should be returning early if !opts.includeStats
return opts.Print(r) | ||
} | ||
|
||
sp := atlasv2.NewStreamsProcessorWithStats(r.Id, r.Name, r.Pipeline, r.State) |
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 should be created through a store method. I am not familiar with the decision patterns, I have only seen the CLI interact with the api through stores rather than directly like this.
mockStore. | ||
EXPECT(). | ||
StreamProcessor(gomock.Any()). | ||
Return(expected, nil). | ||
Times(2) |
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 that separate stores should be pulled into each test to more specifically assert each test's code.
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.
Start and Stop reviewed
cmd := &cobra.Command{ | ||
Use: "start <processorName>", | ||
Short: "Start a specific Atlas Stream Processor in a Stream Processing Instance.", | ||
Long: fmt.Sprintf(usage.RequiredRole, "Project Read Only"), |
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 docs indicate this command will require either Project Owner
or Project Stream Processing Owner
|
||
mockStore. | ||
EXPECT(). | ||
StartStreamProcessor(gomock.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.
I think we should have stricter assertions on what we pass to the store calls. Splitting the commands out into separate strings might make this easier to assert on then reconstructing Params objects. But it shouldn't be too hard either way.
Proposed changes
This work adds the noun
processors
to the top level nounstreams
so that stream processors can be interacted with through the CLI. Theprocessors
noun has the following verbs:Jira ticket: CLOUDP-289219
Checklist
make fmt
and formatted my code