Add asynchronous provisioning test using the fake broker server#923
Add asynchronous provisioning test using the fake broker server#923arschles wants to merge 1 commit into
Conversation
| sharedInformers.Brokers().Informer().GetStore().Add(getTestBroker()) | ||
| sharedInformers.ServiceClasses().Informer().GetStore().Add(getTestServiceClass()) | ||
|
|
||
| // Specify we want asynchronous provisioning... |
| } | ||
| c.pollingQueue.Add(key) | ||
| } else { | ||
| } else if respCode == http.StatusCreated || respCode == http.StatusOK { |
There was a problem hiding this comment.
I'm a little perplexed that this is necessary because above L163 any error should be handled and these are the only cases that return a nil error so I'm just trying to understand why this change is necessary.
There was a problem hiding this comment.
There was a problem hiding this comment.
@vaikas-google good catch. The test code is using the fake broker client instead of the real one, and the fake doesn't check for response codes like the real one does.
I'd like to keep the test intact, so I'm going to see how hard it is to retrofit a fake broker server so we can use the real client here.
| } else { | ||
| // the broker returned a failure response | ||
| errorProvisionCalledMessage := fmt.Sprintf("provision call failed") | ||
| c.updateInstanceCondition( |
There was a problem hiding this comment.
fwiw, i notice a consistent pattern where we ignore any error that can be returned from this.
i think we should either return, or at minimum log the error.
There was a problem hiding this comment.
@derekwaynecarr good catch. I'll log and return on these changed portions, and I've created #925 as a follow-up
|
@pmorie @vaikas-google I've put this PR back into in-progress, I may have thought about this wrong. I'll ping you for re-review if I don't end up closing this completely. |
This is a continuation of kubernetes-retired#533, and is a pre-requisite for kubernetes-retired#923
|
Update: I've opened #928, which implements a fake broker server and refactors a single test to use the real OSB client against the fake broker server. After that is merged, I'll convert the test herein to use the real client and the fake broker server. Given that I've seen this bug in the wild, I'm hoping the test as-written will show the buggy behavior (although I agree with you @vaikas-google that I don't see how the OSB API client could miss any status codes). If it doesn't, it'll be back to the drawing board to expose this behavior. |
* Adding a fake broker server This is a continuation of #533, and is a pre-requisite for #923 * converting a single test to use the broker server * adding boilerplate and docs * naming the pivotal brokerapi package to eliminate possible ambiguity * adding clarifying comment to the catalog requests var * adding better godocs
5651ee8 to
17a1e1e
Compare
e85808e to
336a983
Compare
MHBauer
left a comment
There was a problem hiding this comment.
More detail about why the broker is unsupported.
Non conforming with osbapi how?
| } | ||
|
|
||
| // TestReconcileInstanceAsynchronousUnsupportedBrokerError tests to ensure that, on an asynchronous | ||
| // provision, an Instance's conditions get set with a Broker failure that is not OSB API spec |
|
|
||
| // The item should not have been added to the polling queue for later processing | ||
| if testController.pollingQueue.Len() != 0 { | ||
| t.Fatalf("Expected the asynchronous instance to end up in the polling queue") |
There was a problem hiding this comment.
This log message seems wrong?
|
@MHBauer I made the test comment more precise and added detail regarding the OSB spec. I think it will answer your question. |
| sharedInformers.Brokers().Informer().GetStore().Add(getTestBroker()) | ||
| sharedInformers.ServiceClasses().Informer().GetStore().Add(getTestServiceClass()) | ||
|
|
||
| // Specify an error from the instance client |
There was a problem hiding this comment.
is this the un'expected' error? can you add that word to match the comment above?
|
@arschles looks like this needs rebase |
47dd389 to
f00029e
Compare
|
@pmorie rebase done, and adaptations made to use the new OSB client that the rebase pulled in. PTAL |
59cfd91 to
6852321
Compare
pmorie
left a comment
There was a problem hiding this comment.
A couple small suggestions
|
|
||
| fakeBrokerServerHandler.Catalog = fakebrokerserver.ConvertCatalog(getTestCatalog()) | ||
|
|
||
| fakeKubeClient.AddReactor("get", "namespaces", func(action clientgotesting.Action) (bool, runtime.Object, error) { |
There was a problem hiding this comment.
I put in a litle macro for this
| // verify that 2 kubernetes actions occurred - a GET to the ServiceClass, then a GET to the | ||
| // Broker | ||
| kubeActions := fakeKubeClient.Actions() | ||
| if e, a := 2, len(kubeActions); e != a { |
There was a problem hiding this comment.
you can use assertNumberOfActions here too
| // InstanceName is a name used for test instances | ||
| InstanceName = "test-instance" | ||
| // InstanceGUID is the GUID used for test instances | ||
| InstanceGUID = "IGUID" |
There was a problem hiding this comment.
I think all of these should have some indication in the name that they are the Test constants.
There was a problem hiding this comment.
@MHBauer I argue that they already do when used externally to this package. Recall that the package name will come first, so this specific constant will be referenced as fake.InstanceGUID
There was a problem hiding this comment.
Agree that the name of the package carries the meaning. I suggest we call this package 'testfixtures', though, since the code here is not really a 'fake'.
| package fake | ||
|
|
||
| func boolPtr(b bool) *bool { | ||
| return &b |
There was a problem hiding this comment.
Why do these functions exist?
There was a problem hiding this comment.
various fields need to store *bools, and this is a convenience function to create them with a one-liner
There was a problem hiding this comment.
Having never actually tried it, I tried it, and apparently you can't take the address of a bool. Bizzare language.
Would it be better to have it once in a toplevel util package than rewriting this in a multiple places.
There was a problem hiding this comment.
I have seen truePtr and falsePtr around somewhere.
There was a problem hiding this comment.
yes, that would be nice, but out of the scope of this PR
There was a problem hiding this comment.
Oh, those are hanging around. We'll probably want to move them here naturally at some point.
pmorie
left a comment
There was a problem hiding this comment.
Very much like where you're headed with this, a couple minor suggestions. TLDR: let's run a whole controller and drive this from informers and waiting on conditions.
| limitations under the License. | ||
| */ | ||
|
|
||
| package fake |
| // InstanceName is a name used for test instances | ||
| InstanceName = "test-instance" | ||
| // InstanceGUID is the GUID used for test instances | ||
| InstanceGUID = "IGUID" |
There was a problem hiding this comment.
Agree that the name of the package carries the meaning. I suggest we call this package 'testfixtures', though, since the code here is not really a 'fake'.
| package fake | ||
|
|
||
| func boolPtr(b bool) *bool { | ||
| return &b |
There was a problem hiding this comment.
Oh, those are hanging around. We'll probably want to move them here naturally at some point.
|
|
||
| // AssertInstanceReadyTrue ensures that obj is an instance and has a ready condition of True | ||
| // on it | ||
| func AssertInstanceReadyTrue(t *testing.T, obj runtime.Object) { |
There was a problem hiding this comment.
Do we need to export these? The integration tests should wait for conditions to converge on an expected value, rather than making single assertions.
| if testController.PollingQueueLen() != 0 { | ||
| t.Fatalf("Expected polling queue to be empty") | ||
| } | ||
| controller.AssertAsyncOpInProgressFalse(t, updatedInstance) |
There was a problem hiding this comment.
Let's run the controller similar to the other integration tests so that are testing the behavior of a running controller instead of exercising a specific (and very clean) ordering of methods in a test harness
|
rebase needed |
93c6fdf to
8f6dc37
Compare
8f6dc37 to
ee89698
Compare
|
@arschles are you planning to rebase this and land it? |
|
This work looks good but might need to be broken into a few smaller PRs to be able to integrate today. |
|
@arschles can this be closed? |
|
Closing as inactive. @arschles feel free to reopen if needed. |
Overview
This patch creates a new test at
./test/integration/controller_instance_test.go, which exercises the controller'sReconcileInstancefunction against fake clients for everything except for a broker API. This test ensures that, if the broker API returns an HTTP response with a 500 error code, the controller will write the results of that response into theInstance's conditions.Refactors
The new test borrows a lot of logic from the existing controller unit tests, but it lives alongside the integration tests. I've done quite a bit of refactoring to enable this test to use functions that were previously only available to unit tests. Note that I've done the least amount of refactoring I had to, but there are still quite a few changes here. The result is that the unit test code is slightly more factored and reusable as well.
Follow-ups
While this PR only adds a single additional test, I plan to do several further follow-ups to add several additional tests that would best be written as this type of integration test (such as #984 and #985). The result of those additions will be further (but smaller) refactors and, of course, additional test coverage.
Related Issues
See #914 for details on motivations behind this test.
Partially addresses #914
Requires #928