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

Issue #179 Refactor and test handleJenkinsUIRequest() #198

Merged
merged 1 commit into from
Apr 9, 2018

Conversation

kishansagathiya
Copy link
Member

Fixes #179

@kishansagathiya kishansagathiya changed the title Issue #179 Refactor and test handleJenkinsUIRequest() [WIP] Issue #179 Refactor and test handleJenkinsUIRequest() Mar 16, 2018
@hferentschik
Copy link
Contributor

So that for now is just a variable rename?

@kishansagathiya
Copy link
Member Author

@hferentschik
No,
The code from handleJenkinsUIRequest() has been transferred to processTokenJSON() and checkCookies().
Does this refactor seem right to you?
If this is the kind of refactor that you were expecting I can move to writing tests.

if tj, ok := r.URL.Query()["token_json"]; ok { //If there is token_json in query, process it, find user info and login to Jenkins
if len(tj) < 1 {
p.HandleError(w, errors.New("could not read JWT token from URL"), requestLogEntry)
namespace, noProxy = p.processTokenJSON(responseWriter, request, requestLogEntry, redirectURL)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, now I get it. It is a start, but I don't think there is a need for returning anything here. Especially look at p.checkCookies.

I guess as a first step this works, but the next is to eliminate the returns. Thale the last if statement for example if needsAuth. This could be pulled out into a function which then can get called.

Also, we tried to remove most of the used naked returns in the code. In most places we have done it already, but the code in proxy.go uses still a lot of them. The use of naked returns is really discouraged and should if ever be only used for very small methods. IMO in the current code it just makes it hard to understand. Let's get rid of them.

Copy link
Contributor

Choose a reason for hiding this comment

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

That said, I think we need to keep some conditional there. Pulling the conditionals into the methods obfuscates the code. Now it looks like, you are always processing the JSON token and you are always proecssing the cookies. There are several phases here which are not obvious anymore.

Leaving the outer if statements here will makes things clearer

func (p *Proxy) processTokenJSON(responseWriter http.ResponseWriter, request *http.Request, requestLogEntry *log.Entry, redirectURL *url.URL) (namespace string, noProxy bool) {

// Checks if token_json is present in the query
if tokenJSON, ok := request.URL.Query()["token_json"]; ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

It might make sense to extract this into something like func isAuthenticatedRequest(request *http.Request) bool. If you then pull up the if statement again, the method name documents the alogrithm.

func (p *Proxy) handleJenkinsUIRequest(responseWriter http.ResponseWriter, request *http.Request, requestLogEntry *log.Entry) (cacheKey string, namespace string, noProxy bool) {
        if isAuthenticatedRequest(request) {
	   namespace, noProxy = p.processAuthenticatedRequest(responseWriter, request, requestLogEntry, redirectURL)
        } else {
           return redirectToAuth(...)
       }
 
        if isWaitLoopRequest(request) {
	    cacheKey, namespace, noProxy, needsAuth = p.checkCookies(responseWriter, request, requestLogEntry)
         }
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure which code segment could be kept in isWaitLoopRequest(request)

//redirect determines if we need to redirect to auth service
needsAuth := true
noProxy = true

//redirectURL is used for auth service as a target of successful auth redirect
redirectURL, err := url.ParseRequestURI(fmt.Sprintf("%s%s", strings.TrimRight(p.redirect, "/"), r.URL.Path))
// redirectURL is used for auth service as a target of successful auth redirect
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 think we need to do that here. We can do that where it is needed. And most likely it can also happen in a dedicated properly named function

Copy link
Member Author

Choose a reason for hiding this comment

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

return
}

//If the user provides OSO token, we can directly proxy
if _, ok := r.Header["Authorization"]; ok { //FIXME Do we need this?
if _, ok := request.Header["Authorization"]; ok { //FIXME Do we need this?
Copy link
Contributor

Choose a reason for hiding this comment

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

For the record, this can be removed. Needs to be tested though.

Copy link
Member Author

Choose a reason for hiding this comment

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

@hferentschik
Copy link
Contributor

While working on this you might want to verify by running the Proxy locally whether it still works. There might be an issue with cookies in this case. I have not confirmed that and I successfully did a proxying using a local Proxy instance, but there is this issue which might prevent you to test the workflow locally #174. Might be worth following up.

Being able to test the workflow locally will help a lot, but remember the end game is to "codify" the flow into some tests.

@hferentschik
Copy link
Contributor

Any more changes to this?

@kishansagathiya
Copy link
Member Author

Is this(https://github.com/fabric8-services/fabric8-jenkins-proxy/blob/master/internal/proxy/proxy.go#L315) the function that waits until jenkins is unidled?

@kishansagathiya
Copy link
Member Author

@chmouel If this seems right to you I can move forward with tests. Except for breaking the function this doesnt have much changed.

@chmouel
Copy link
Contributor

chmouel commented Mar 26, 2018

@kishansagathiya there is a few concernces about this from @hferentschik what are about?

@kishansagathiya
Copy link
Member Author

@chmouel I think they are all covered

  • No more naked returns
  • No more Authorization Header
  • redirectURL is in smaller functions
  • less returned values
  • conditions are out of the methods

@chmouel
Copy link
Contributor

chmouel commented Mar 26, 2018

I am worried to merge something like this without any tests (i.e: no proxy_test.go) can we have unitests along this commit please?

@kishansagathiya
Copy link
Member Author

@chmouel This is NOT ready for merge yet. It is WIP. We can merge this after tests. The reason for such temporary commits is to make sure that I am on the right path. If I get a review after tests, I will have change implementation and tests both.

@kishansagathiya
Copy link
Member Author

@chmouel Have added some tests. It needs much more, which I keep pushing with this PR.
btw do I need to mock the database as well? not sure, what should I do? fabric8-auth doesn't mock db.

@chmouel
Copy link
Contributor

chmouel commented Mar 28, 2018

look at the way it uses https://github.com/ory/dockertest for the database tests, there is already some example in the in db_store_test here

@kishansagathiya kishansagathiya changed the title [WIP] Issue #179 Refactor and test handleJenkinsUIRequest() Issue #179 Refactor and test handleJenkinsUIRequest() Apr 3, 2018
@kishansagathiya
Copy link
Member Author

kishansagathiya commented Apr 3, 2018

Tested this locally to be working using

http://localhost:8080/api/info/ksagathi-preview

It unidled the Jenkins and this is on running it again.

{"component":"proxy","header":"-H Accept-Encoding: gzip, deflate, br -H Accept-Language: en-US,en;q=0.9 -H Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 -H Cache-Control: max-age=0 -H Connection: keep-alive -H Cookie: JenkinsIdled=<hidden> -H Upgrade-Insecure-Requests: 1 -H User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36","level":"info","msg":"Handling incoming proxy request.","request":"GET /api/info/ksagathi-preview","request-hash":<hidden>,"time":"2018-04-03T16:37:41+05:30","type":"Jenkins UI"}
{"component":"proxy","level":"info","msg":"Accessing Jenkins route https://jenkins-ksagathi-preview-jenkins.b542.starter-us-east-2a.openshiftapps.com/securityRealm/commenceLogin?from=%2F","ns":"ksagathi-preview-jenkins","request-hash":<hidden>,"time":"2018-04-03T16:37:41+05:30"}
{"component":"proxy","level":"info","msg":"Found cookie <hidden>","ns":"ksagathi-preview-jenkins","request-hash":<hidden>,"time":"2018-04-03T16:37:42+05:30"}

Copy link
Contributor

@chmouel chmouel left a 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 mostly fine, it's quite large so I may miss a few things there and there. The coverage is improving thanks for the tests, but there is still quite a bit not covered there see the coverage html file here https://drive.google.com/a/chmouel.com/uc?id=1cLNs5KLcsSaGqKdaOARADp23p8ubfuED&export=download

return "", errors.New("Could not get valid OSO Token")
}

type mockIdler struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice that the mock class are moved to their own package so this can be reused like we do on idler repo (and usually type/struct are top of the files as convention btw)

@kishansagathiya
Copy link
Member Author

So far tests are only for handleJenkinsUIRequest. We can add other tests using a different PR and a different issue.

@chmouel
Copy link
Contributor

chmouel commented Apr 5, 2018

@kishansagathiya fair enough, feel free to address the mock package move and i'll be 👍 with this,

@kishansagathiya
Copy link
Member Author

kishansagathiya commented Apr 5, 2018 via email

	- Splitted handleJenkinsUIRequest() to smaller methods
	- Added error package, removed naked returns, decreased returned parameters
	- Added tests
@kishansagathiya
Copy link
Member Author

@chmouel
Moving mocks to other package was very hairy

  • It creates import cycle
  • Removing import cycle would require us to move tests to a separate package say something like proxy_test, which would require us to export a lot of structs, interfaces, and methods
  • I requires to move other tests also like move db_store_test to separate package. I have those changes, but thought just moving mocks to different file would be a much better solution.

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.

3 participants