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

feat: guess subdomains based on conventions (DEV-1979) #445

Merged
merged 14 commits into from Jul 27, 2023

Conversation

jnussbaum
Copy link
Collaborator

No description provided.

@jnussbaum jnussbaum self-assigned this Jul 26, 2023
@linear
Copy link

linear bot commented Jul 26, 2023

DEV-1979 DSP-TOOLS: guess subdomains based on conventions

Problem

https://docs.dasch.swiss/2023.03.02/DSP-TOOLS/cli-commands/#before-starting-have-in-mind-the-subdomains-of-a-dsp-server explains how to address the subdomains of a DSP server.

But if a user makes the mistake to address a server with admin.dasch.swiss instead of api.dasch.swiss, he doesn't get a useful error message. Even worse: If he forgets to specify the SIPI server for an xmlupload, DSP-TOOLS tries to send the multimedia files to a localhost SIPI, which leads to cryptic error messages.

Solution

Don't care about subdomains at all, and just rely on the convention that admin=DSP-APP, api=DSP-API, iiif=SIPI. We could then get rid of this complicated paragraph that makes user's lives difficult: https://docs.dasch.swiss/2023.03.02/DSP-TOOLS/cli-commands/#before-starting-have-in-mind-the-subdomains-of-a-dsp-server.
I could then entirely get rid of the -S https://iiif.dasch.swiss flag.

@jnussbaum jnussbaum changed the title feat: guess subdomains based on conventions (DEV-2413) feat: guess subdomains based on conventions (DEV-1979) Jul 26, 2023
@linear
Copy link

linear bot commented Jul 26, 2023

DEV-1979 DSP-TOOLS: guess subdomains based on conventions

Problem

https://docs.dasch.swiss/2023.03.02/DSP-TOOLS/cli-commands/#before-starting-have-in-mind-the-subdomains-of-a-dsp-server explains how to address the subdomains of a DSP server.

But if a user makes the mistake to address a server with admin.dasch.swiss instead of api.dasch.swiss, he doesn't get a useful error message. Even worse: If he forgets to specify the SIPI server for an xmlupload, DSP-TOOLS tries to send the multimedia files to a localhost SIPI, which leads to cryptic error messages.

Solution

Don't care about subdomains at all, and just rely on the convention that admin=DSP-APP, api=DSP-API, iiif=SIPI. We could then get rid of this complicated paragraph that makes user's lives difficult: https://docs.dasch.swiss/2023.03.02/DSP-TOOLS/cli-commands/#before-starting-have-in-mind-the-subdomains-of-a-dsp-server.
I could then entirely get rid of the -S https://iiif.dasch.swiss flag.

Copy link
Collaborator

@BalduinLandolt BalduinLandolt left a comment

Choose a reason for hiding this comment

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

I added some comments, feel free to apply or ignore what you see fit

docs/cli-commands.md Show resolved Hide resolved
docs/cli-commands.md Show resolved Hide resolved
src/dsp_tools/dsp_tools.py Outdated Show resolved Hide resolved
src/dsp_tools/dsp_tools.py Outdated Show resolved Hide resolved
test/unittests/test_cli.py Outdated Show resolved Hide resolved
Comment on lines +28 to +113
cls.positive_testcases = {
"https://0.0.0.0:3333/": [
cls.default_dsp_api_url,
cls.default_sipi_url,
],
"0.0.0.0:3333": [
cls.default_dsp_api_url,
cls.default_sipi_url,
],
"localhost:3333": [
cls.default_dsp_api_url,
cls.default_sipi_url,
],
"https://admin.dasch.swiss": [
"https://api.dasch.swiss",
"https://iiif.dasch.swiss",
],
"https://api.dasch.swiss": [
"https://api.dasch.swiss",
"https://iiif.dasch.swiss",
],
"https://app.dasch.swiss": [
"https://api.dasch.swiss",
"https://iiif.dasch.swiss",
],
"https://iiif.dasch.swiss": [
"https://api.dasch.swiss",
"https://iiif.dasch.swiss",
],
"https://dasch.swiss": [
"https://api.dasch.swiss",
"https://iiif.dasch.swiss",
],
"dasch.swiss": [
"https://api.dasch.swiss",
"https://iiif.dasch.swiss",
],
"http://admin.test.dasch.swiss/": [
"https://api.test.dasch.swiss",
"https://iiif.test.dasch.swiss",
],
"http://app.staging.dasch.swiss/": [
"https://api.staging.dasch.swiss",
"https://iiif.staging.dasch.swiss",
],
"https://demo.dasch.swiss/": [
"https://api.demo.dasch.swiss",
"https://iiif.demo.dasch.swiss",
],
"http://api.dev.dasch.swiss/": [
"https://api.dev.dasch.swiss",
"https://iiif.dev.dasch.swiss",
],
"dev-02.dasch.swiss": [
"https://api.dev-02.dasch.swiss",
"https://iiif.dev-02.dasch.swiss",
],
"082a-test-server.dasch.swiss": [
"https://api.082a-test-server.dasch.swiss",
"https://iiif.082a-test-server.dasch.swiss",
],
"admin.08F4-test-server.dasch.swiss": [
"https://api.08F4-test-server.dasch.swiss",
"https://iiif.08F4-test-server.dasch.swiss",
],
"app.08F4-test-server.dasch.swiss": [
"https://api.08F4-test-server.dasch.swiss",
"https://iiif.08F4-test-server.dasch.swiss",
],
"iiif.E5bC-test-server.dasch.swiss": [
"https://api.E5bC-test-server.dasch.swiss",
"https://iiif.E5bC-test-server.dasch.swiss",
],
"not-yet-0826-test-server.dasch.swiss": [
"https://api.not-yet-0826-test-server.dasch.swiss",
"https://iiif.not-yet-0826-test-server.dasch.swiss",
],
"https://admin.ls-prod-server.dasch.swiss": [
"https://api.ls-prod-server.dasch.swiss",
"https://iiif.ls-prod-server.dasch.swiss",
],
"https://ls-test-server.dasch.swiss": [
"https://api.ls-test-server.dasch.swiss",
"https://iiif.ls-test-server.dasch.swiss",
],
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not a fan of this kind of test parameterisation: if you want to test arbitrary strings because you're concerned the behaviour might be flaky, then you should use a framework for property-based testing (like Hypothesis); otherwise you should identify the different possible code paths and test those systematically with one test per possible case.
If you expect a different behaviour for "082a-test-server.dasch.swiss" and "http://api.dev.dasch.swiss/" then this test either tests the regex you wrote (if you don't trust that) or the correctness of the python regex implementation. If the first is the case, then factor out your regexes and test them separately, if the latter is the case, then don't! 😉

And if you reduce the number of cases you want to test, then you don't need to parametrise your tests, and instead you can have a dedicated test method for each case you want to test, which gives you clearer and more expressive test results.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think there is another case: I'd like my unit tests to be an executable requirements specification. I think I have read that in David Farley's "Modern Software Engineering", but I'm not sure.

The idea that I have in mind: Some day, someone might come across and modify my code, so that by mistake, one of the subdomains isn't covered any more. So I want my unit tests to be a protection against future harm.

Does that make sense?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Makes sense, but I argue that it's a trade-off: Of course better coverage gives confidence for future code changes. But at the same time, test cases come with a maintenance cost - if requirements change, not only production code but also test code has to be adopted. That's why the granularity and amount of tests are a balance to get right.
(That's an issue we're struggling with, both in the API and the JS-LIB: We have huge amounts of "reference test data" and normally it takes longer to update "fix" all the tests afterwards than to implement an actual feature. I don't think this case is comparable - but I'm a bit hyper-sensitive to that now... 😉 )

If you feel that testing all this helps, then I'm 100% fine with it, but it may not be the kind of testing I currently like to do.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Okay - I see your point, and will keep it in mind. thanks for the input, it's always interesting to exchange thoughts with you, and I can learn a lot from your comments :-)

Comment on lines 120 to 134
api_url_canonical, sipi_url = expected
args_orig = argparse.Namespace(
action="xmlupload",
server=api_url_orig,
user="some.user@dasch.swiss",
password="password",
xmlfile="data.xml",
)
args_new = _derive_sipi_url(
parsed_arguments=args_orig,
default_dsp_api_url=self.default_dsp_api_url,
default_sipi_url=self.default_sipi_url,
)
self.assertEqual(args_new.server, api_url_canonical)
self.assertEqual(args_new.sipi_url, sipi_url) # pylint: disable=no-member
Copy link
Collaborator

Choose a reason for hiding this comment

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

see my comment above on the information flow: if _derive_sipi_url() is changed to a str -> tuple[str, str] function, then this test can be simplified a lot:

        api, sipi = _derive_sipi_url("localhost:3333") # or whatever you want to test
        self.assertEqual(api, "http://0.0.0.0:3333")
        self.assertEqual(sipi, "http://0.0.0.0:1024")

and as such it's also not too much to have separate test methods:

    def test_derive_sipi_localhost(self) -> None:
        api, sipi = _derive_sipi_url("localhost:3333")
        self.assertEqual(api, "http://0.0.0.0:3333")
        self.assertEqual(sipi, "http://0.0.0.0:1024")

    def test_derive_sipi_localhost_zeros(self) -> None:
        api, sipi = _derive_sipi_url("0.0.0.0:3333")
        self.assertEqual(api, "http://0.0.0.0:3333")
        self.assertEqual(sipi, "http://0.0.0.0:1024")

etc.

@jnussbaum jnussbaum merged commit d6c4ff4 into main Jul 27, 2023
5 checks passed
@jnussbaum jnussbaum deleted the wip/dev-2413-guess-subdomains branch July 27, 2023 15:18
@daschbot daschbot mentioned this pull request Jul 27, 2023
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.

None yet

2 participants