Skip to content
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

Avoid to submit empty params #735

Merged
merged 5 commits into from
Oct 18, 2018
Merged

Conversation

andresmgot
Copy link
Contributor

Fixes #411

When creating a service instance or a binding, if the schema is provided, avoid to submit empty objects. This is only made when we are sure that the parameter is not required.

},
},
};
// It omits "f" because it's empty but not "b" because it's required
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explanation.

What's the difference between sending empty required parameters and not sending them at all? Wouldn't not sending the empty parameters regardless of being required or not have the same effect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, that't the root of the issue of #411. The GCP service broker has some kind of validation that if the key exists it's not empty. We were sending a subscription object with all the inner elements empty (but with keys). With that the broker replies 'roles/pubsub.subscriber' is a required role when 'subscription' is specified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, my comment was related to not to send the parameters if they are empty in any case. The difference is that you still send them if they are required params but I am suggesting not to send them even in that case. I might be missing something though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, yes, it's true that it should be safe to not send anything that is empty.

@@ -60,16 +62,44 @@ const actions = [

export type ServiceCatalogAction = ActionType<typeof actions[number]>;

function isEmptyDeep(obj: any): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a description of what this function does. Mainly because it seems to have a recursive behavior.

@@ -60,16 +62,44 @@ const actions = [

export type ServiceCatalogAction = ActionType<typeof actions[number]>;

function isEmptyDeep(obj: any): boolean {
if (typeof obj === "number") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is number a special case? What about string and others?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a lodash problem:

https://github.com/lodash/lodash/blob/4ea8c2ec249be046a0f4ae32539d652194caf74f/isEmpty.js#L33

In our case, we want to mark a number as non empty so we need this special case. It's not critical though because you cannot set a "number" in a form (AFAIK) but just in case.

return _.isEmpty(obj);
}

function removeEmptyFields(obj: object, schema?: JSONSchema6) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename to removeEmptyNonRequiredFields?

@@ -60,16 +62,44 @@ const actions = [

export type ServiceCatalogAction = ActionType<typeof actions[number]>;

function isEmptyDeep(obj: any): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that we are testing the overall behavior at the action level but could we add unit tests for this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid that because that would require to export the function. This is supposed to be a inner function so I prefer to test this with the exposed function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. There should be a way to unit test functions without exporting them, otherwise we are not unit testing.

Can't we make it work like this?

wrapper = shallow("foo")
instance = wrapper.instance();
instance.isEmptyDeep(...) ?

The thing is that this function is complex enough too deserve its unit test. Relying on functional/integration test might not be the best option once the complexity starts growing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving this function to a different helper to be able to test it

): ThunkAction<Promise<boolean>, IStoreState, null, ServiceCatalogAction> {
return async dispatch => {
try {
await ServiceInstance.create(releaseName, namespace, className, planName, parameters);
const filteredParams = removeEmptyFields(parameters, schema);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we do not need to pass schema all the time since it is actually optional and with default value to JSONSchema6? Or do we support other schemas?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you mean here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I was understanding schema like the schema type and thought that the default value was JSONSchema6. When what it actually does it to receive an instance of jsonschema.

export function provision(
releaseName: string,
namespace: string,
className: string,
planName: string,
parameters: {},
schema?: JSONSchema6,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is schema optional?

},
},
};
// It omits "f" because it's empty but not "b" because it's required
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, my comment was related to not to send the parameters if they are empty in any case. The difference is that you still send them if they are required params but I am suggesting not to send them even in that case. I might be missing something though.

Copy link
Contributor

@migmartri migmartri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thanks for the changes :)

@@ -165,6 +165,40 @@ describe("provision", () => {
await store.dispatch(provisionCMD);
expect(store.getActions()).toEqual(expectedActions);
});

it("filters the submitted parameters if they are not required", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that description accurate?

filters submitted params if they are empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not, I missed this

@@ -227,6 +261,41 @@ describe("addBinding", () => {
await store.dispatch(provisionCMD);
expect(store.getActions()).toEqual(expectedActions);
});

it("filters the submitted parameters if they are not required", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

@@ -69,7 +70,8 @@ export function provision(
): ThunkAction<Promise<boolean>, IStoreState, null, ServiceCatalogAction> {
return async dispatch => {
try {
await ServiceInstance.create(releaseName, namespace, className, planName, parameters);
const filteredParams = helpers.object.removeEmptyFields(parameters);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice.

@@ -0,0 +1,34 @@
import * as object from "./object";

describe("isEmptyDeep", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great :)

{ object: { a: 1 }, isEmpty: false },
{ object: { a: { b: "" } }, isEmpty: true },
{ object: { a: { c: { d: "" } } }, isEmpty: true },
{ object: { a: { c: { d: "a" } } }, isEmpty: false },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about an example that contains both an empty and non-empty at the leaf?

    { object: { a: { c: { d: "a" }, d: "" } }, isEmpty: false },

@@ -0,0 +1,30 @@
import * as _ from "lodash";

// Check if all the keys of an object are empty. If any value of the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the description :)

// is empty.
export function isEmptyDeep(obj: any): boolean {
if (typeof obj === "number") {
// isEmpty(number) is true but it's not empty
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you mention that it is a limitation of lodash?

@andresmgot andresmgot merged commit 1dc3a2b into vmware-tanzu:master Oct 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants