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
Add configuration for setting the Jenkins URL. #13
Conversation
There should be corresponding unit and amulet test coverage for the new config option. This reactive rewrite has pretty good unit and amulet test coverage and I'd really like to see us keep that level of trust as contributions are made. Thank you. |
There are corresponding unit tests in my submission. As far as amulet tests, I couldn't get them to work with Juju2 and I have no Juju1 environments anymore. In my dev instead I used an mojo spec to test the full integration, I was hoping Travis would exercise the amulet tests for me, but I see that isn't the case. Is there a place where I can run amulet test any changes or a trick to getting them to work with Juju2? The bug I hit is https://bugs.launchpad.net/juju/+bug/1608723 The basic amulet tests will of course use the default config value, I would just add changing it and verifying the change was made. |
Tim Kuhlman <notifications@github.com> writes:
There are corresponding unit tests in my submission.
As far as amulet tests, I couldn't get them to work with Juju2 and I
have no Juju1 environments anymore.
They used to pass on Juju 2. Something has probably regressed, I'll have
a look tomorrow.
In my dev instead I used an mojo
spec to test the full integration, I was hoping Travis would exercise
the amulet tests for me, but I see that isn't the case.
Yes, this a known pain point. There is some on going work from the
juju-solutions team to provide easy glue between Jenkins and GitHub in
order to run charm integration tests on custom Jenkins servers (Travis
is unfortunately to limited to run juju integration tests properly).
Is there a
place where I can run amulet test any changes or a trick to getting
them to work with Juju2? The bug I hit is
https://bugs.launchpad.net/juju/+bug/1608723
Good question. The situation has gone a bit wild since Juju 2 AFAIK,
what I can say is that I use bundletester.
Remember however that integration tests are supposed to be
self-contained executables, so provided you have the required Python
packages in your PATH and that you have a clean Juju 2 model at hand,
you can just invoke:
./tests/NN_some_test
The basic amulet tests will of course use the default config value, I
would just add changing it and verifying the change was made.
Sounds good.
|
Thanks! I was able to get the amulet tests working with Juju2 by invoking the amulet tests directly which obviously I missed before. I'll add in some amulet tests later today. |
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.
Nice, I have a number of comments but mainly minor or stylistic.
I'll give the branch another pass once those are addressed.
@@ -6,3 +6,4 @@ | |||
*.pyc | |||
lib/charms/__init__.py | |||
lib/charms/layer/__init__.py | |||
.idea |
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 looks like a leftover?
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.
Out of habit I added that in since I use pycharm, I'll remove it.
@@ -48,3 +48,9 @@ options: | |||
default: 1 | |||
description: | | |||
Number of executors to configure for jenkins master. | |||
public_url: |
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.
Please use dashes as separator, like the other config keys in this file:
"public_url" -> "public-url"
public_url: | ||
type: string | ||
default: "" | ||
description: > |
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.
Please use a pipe here (for consistencies with other config keys in this file):
"description: >" -> "description: |"
@@ -1,4 +1,5 @@ | |||
import requests | |||
from urllib.parse import urlparse |
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.
Please follow PEP8 conventions, placing absolute imports before relative imports, and standard library imports before third-party and local library imports (all groups separated by a blank line):
import requests
import jenkins
from urllib.parse import urlparse
from charmhelpers.core.hookenv import ERROR
from charms.layer.jenkins.credentials import Credentials
prefix = urlparse(config["public_url"]).path | ||
if not prefix: | ||
prefix = "/" | ||
return "http://localhost:8080{}".format(prefix) |
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.
Please take advantage of the URL constants defined in charms.layer.jenkins.service and use urljoin:
return urljoin(URL, perfix)
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 is no URL constant in service anymore, I removed it. A constant is no longer valid with the ability to change prefix and it was only used by API calls so it makes more sense to be in the api file rather than in the service file. This method is the replacement for the constant.
@@ -11,8 +12,47 @@ | |||
class Configuration(object): | |||
"""Manage global Jenkins configuration.""" | |||
|
|||
@staticmethod |
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's no need for the @staticmethod decorator, please just add "self" to the signature and make it a regular instance method.
def test_10_change_url(self): | ||
"""Validate that after changing public_url we can login at the new | ||
prefix and that the public_url has been updated. | ||
""" |
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.
Please format the docstring like this:
"""
Validate that after changing public_url we can login at the new
prefix and that the public_url has been updated.
"""
@@ -34,6 +36,46 @@ def test_bootstrap(self): | |||
FileContains(matcher=Contains("<numExecutors>1</numExecutors>"))) | |||
self.assertEqual({8080}, self.fakes.juju.ports["TCP"]) | |||
|
|||
def test_set_prefix(self): | |||
test_file = tempfile.NamedTemporaryFile() |
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 file will be left around after the test suite completes. Please use something like:
from fixtures import TempDir
# ...
test_file = self.useFixture(TempDir()).join("test-file")
See the fixtures package for more details.
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.
No NamedTemporaryFile defaults to deleting the file when it is closed so it doesn't hang around after the test suite completes. I'm happy to use the fixtures though.
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.
Yeah, I should have mentioned that the case were it hangs around is if the test method fails. In that case the close() call never gets executed (an exception is raised before).
updated = self.configuration._set_prefix("") | ||
self.assertTrue(updated) | ||
|
||
# Case #6 - no config file, no expected change |
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.
Please break down all these separate cases in separate test methods. You'll probably want a small helper function to create the test file.
In this way if something breaks you can have an instant look at all edge cases that don't pass, instead of having to run the suite N times and discover a new failure each time.
@@ -33,6 +33,10 @@ def test_configure_admin_custom_password(self): | |||
If a password is provided, it's used to configure the admin user. | |||
""" | |||
self.fakes.juju.config["password"] = "x" | |||
# TODO figure out why self.fakes.juju setting is not reliably working. |
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 clarify this comment? I'll try to given an explanation or maybe fix an bug in the underlying machinery.
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 problem here is I expected from looking at other code that self.fakes.juju.config["password"] would set the config option for the password but in my testing it did nothing it wasn't until I used hookenv.config() to get the config and set it that way that the test begun to work.
I made updates as above, squashed all the commits together and rebased. I didn't end up switching NamedTemporaryFile for a fixture because there is only a temporary dir for the fixture so I still have to open a file an write to it anyway. |
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.
Looks good to me. I have a final comment (that I should have made from the beginning), feel free to address it or not.
""" Setup a temporary DEFAULTS_CONFIG_FILE | ||
:return: a temporary file with the name attribute being the path | ||
""" | ||
test_file_path = self.useFixture(fixtures.TempDir()).join("test-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.
Thanks for using the TempDir fixture, so no temporary files are left around when the test fails.
However, I just realized that I could have suggested you a way simpler approach with systemfixtures:
http://systemfixtures.readthedocs.io/en/latest/?badge=latest#filesystem
that's the pattern that the rest of the unit test code in this charm uses. In your case I think you would have to write something like:
self.fakes.fs.add(paths.DEFAULTS_CONFIG_FILE)
os.makedirs("/etc/default")
and from this point any call to open("/etc/default/jenkins") will be magically redirected to a temporary file (something like "/tmp/tmpxxx/etc/default/jenkins).
You could add the code above to unit_tests.states.AptInstallJenkins, and since ConfigurationTest already uses the AptInstalledJenkins state fixtures all you unit tests will have that default file already setup (since it's a file that is always expected to be there in a real unit).
I realize the above is a tad tricky, if you have troubles getting it done let me know, or just land this PR as it is and I'll take care of this small clean up myself.
Great that does clean up the tests nicely. I rebased and squashed to a single commit again since a new change just merged. |
Ah timing, I missed the fix from PR #16, which I am glad to see merge, one more rebase coming up. |
Thanks, the change looks good to me. Do you have commit rights or should I trigger the merge myself? |
I don't have commit rights. |
This change adds the public_url charm configuration option so you can
specify the Jenkins URL and prefix.