From 0f484ec326f56ccdd5c13605a2d8c86337459d49 Mon Sep 17 00:00:00 2001 From: Duncan Paterson Date: Thu, 22 Nov 2018 21:19:32 +0100 Subject: [PATCH 01/11] preface e2e article --- .../integration-testing.xml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/xar-resources/data/integration-testing/integration-testing.xml diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml new file mode 100644 index 00000000..6b9d8c34 --- /dev/null +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -0,0 +1,26 @@ +
+ + Integration Testing + 4Q18 + + testing + application-development + CI + + + + + + To ensure the long-term maintainability of an application, it is important to not only test its individual functions, but also the way the application interacts with other components of the exist-db environment. This artilce covers recommendations for configuring an automated test environment to perform integration test of eXist-db apps. + These recommendations apply to application developers of any level. However, it also defines the minimal requirements for authors who wish to publish their apps under the exist-db namespace. It assumes that you are familiar with the XQsuite framework for unit-testing. + + + + + blah + + + +
From b391421e3d0975122fa8e4ba5696ba39ae361c94 Mon Sep 17 00:00:00 2001 From: Duncan Paterson Date: Thu, 22 Nov 2018 21:30:40 +0100 Subject: [PATCH 02/11] feat(ci): install docs via docker --- .travis.yml | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 88b27b34..0adca557 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,31 @@ jdk: - oraclejdk8 - oraclejdk11 +services: + - docker + +env: + - img=existdb/existdb:latest + - img=existdb/existdb:release + +before_install: + - docker pull $img + - docker create --name exist-ci -p 8080:8080 $img + +install: + - mvn clean package + +before_script: + - docker cp ./target/exist-documentation-*.xar exist-ci:exist/autodeploy + - docker start exist-ci + # exist needs time + - sleep 30 + script: - - mvn -B test package - mvn validate +after_success: + - docker ps + notifications: hipchat: ec8fcfa661addc56a361a8ef536320@integrations From 9454de6f9e6095d23c6317a9b0bbd006a106fe2a Mon Sep 17 00:00:00 2001 From: Duncan Paterson Date: Thu, 22 Nov 2018 23:20:25 +0100 Subject: [PATCH 03/11] feat(ci): chrome-headless (wip) --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0adca557..34f653f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,9 @@ env: - img=existdb/existdb:latest - img=existdb/existdb:release +addons: + chrome: stable + before_install: - docker pull $img - docker create --name exist-ci -p 8080:8080 $img @@ -26,6 +29,7 @@ before_script: script: - mvn validate + - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost:8080/exist/apps/doc/documentation.xml & after_success: - docker ps From 2e1974173784f635210eef5d54fdf1e64e4fbbb8 Mon Sep 17 00:00:00 2001 From: Duncan Paterson Date: Thu, 22 Nov 2018 23:40:48 +0100 Subject: [PATCH 04/11] wip: outline contents (draft) --- .../integration-testing.xml | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml index 6b9d8c34..31b72b95 100644 --- a/src/main/xar-resources/data/integration-testing/integration-testing.xml +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -19,8 +19,30 @@ - blah - - + Introduction + Testing your code is good for you and the community. + There are three parts to the minimal sort of integration test decribed here. + Too many frameworks, please check their documentation, we'll focus on travis xqsuite and ant. + Examples: generator, gulp-exist, documentation. + based on experience. + This tests are minimal because they are a smoke test. + What is an integration test (smoke test) + + + Building on a clean system + build on a clean system, with all targets, and multiple OS if necessary. + + + Install your app (or library) into a running exist + docker or node, but make it foward looking. + + + Access your app + Open index.html in headless browser + + + Run your testsuite + tests that aren't run continuously are no good to anyone. + From c22d5ea1b846c454b860bf83034c6c6b890a6ab4 Mon Sep 17 00:00:00 2001 From: Duncan Paterson Date: Mon, 10 Dec 2018 02:35:34 +0100 Subject: [PATCH 05/11] wip: first draft --- .travis.yml | 4 -- .../integration-testing.xml | 47 ++++++++++++------- .../integration-testing/listings/cypress.txt | 27 +++++++++++ .../integration-testing/listings/travis-1.txt | 10 ++++ .../integration-testing/listings/travis-2.txt | 25 ++++++++++ .../integration-testing/listings/travis-3.txt | 26 ++++++++++ .../integration-testing/listings/travis-4.txt | 26 ++++++++++ 7 files changed, 143 insertions(+), 22 deletions(-) create mode 100644 src/main/xar-resources/data/integration-testing/listings/cypress.txt create mode 100644 src/main/xar-resources/data/integration-testing/listings/travis-1.txt create mode 100644 src/main/xar-resources/data/integration-testing/listings/travis-2.txt create mode 100644 src/main/xar-resources/data/integration-testing/listings/travis-3.txt create mode 100644 src/main/xar-resources/data/integration-testing/listings/travis-4.txt diff --git a/.travis.yml b/.travis.yml index 34f653f3..0adca557 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,6 @@ env: - img=existdb/existdb:latest - img=existdb/existdb:release -addons: - chrome: stable - before_install: - docker pull $img - docker create --name exist-ci -p 8080:8080 $img @@ -29,7 +26,6 @@ before_script: script: - mvn validate - - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost:8080/exist/apps/doc/documentation.xml & after_success: - docker ps diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml index 31b72b95..b48433ed 100644 --- a/src/main/xar-resources/data/integration-testing/integration-testing.xml +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -14,35 +14,46 @@ To ensure the long-term maintainability of an application, it is important to not only test its individual functions, but also the way the application interacts with other components of the exist-db environment. This artilce covers recommendations for configuring an automated test environment to perform integration test of eXist-db apps. - These recommendations apply to application developers of any level. However, it also defines the minimal requirements for authors who wish to publish their apps under the exist-db namespace. It assumes that you are familiar with the XQsuite framework for unit-testing. + These recommendations apply to application developers of any level. It also defines the minimal requirements for authors who wish to publish their apps under the exist-db namespace. It assumes that you are familiar with the XQsuite framework for unit-testing. Introduction - Testing your code is good for you and the community. - There are three parts to the minimal sort of integration test decribed here. - Too many frameworks, please check their documentation, we'll focus on travis xqsuite and ant. - Examples: generator, gulp-exist, documentation. - based on experience. - This tests are minimal because they are a smoke test. - What is an integration test (smoke test) - + It is possible to create an automated mininal testsuite with relatively little effort. Instead of post-poning the process it is often more efficient to take the need for testing into account in the earliest phases of development. This enables others whishing to extend your program with new features, by knowning that these don't break existing functions, and by allowing test only contributions to help you to gradually advance your test coverage. The following section will walk you trough the three main aspects of such a minimal test setup. Building on a clean system - build on a clean system, with all targets, and multiple OS if necessary. + Before you start designing tests, you should start to automate your build process. This ensures that things don't only work on your system, and it can catch some common errors. + The examples in this article will use travis-ci as it is the most popular continual integration (ci) provider in the exist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . A simple configuration that builds your application on a clean virtual machine, witout the risk of local hidden files interfering, looks like this: + + For travis the required name of such a configuration is .travis.yml for the correct way to create such a configuration file for your CI provider please consult their documantation. In all cases, since exist-db is written in Java, your app should be build on a system that comes with the Java, version required by eXist-db. Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. + Depending on your the design of your app, you should make sure that all build targets and configurations are run by the ci service. If you use java code in your app, it makes sense to build with multiple java versions (e.g. by adding - openjdk11). It might be necessary to test building on on different operation systems. You can consult your ci services documentation for the list of options they support and for how to configure them. - Install your app (or library) into a running exist - docker or node, but make it foward looking. + Add a running eXist-db instance and install your app + The next step is to take the result of your automated build process and install it in a running eXist-db instance. We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of getting an instance up and running. Let's extend the file create in the previous section. + + The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use (e.g. :4.4.0), if you want to ensure backwards compatibility. But these two tags will ensure that whatever that your code is tests both with the most current stable release, and with upcoming changes. To actually install the app we have simply copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. + So far we have simply automated the basic steps of building and installing your app. This only catches the most basic and sever erros. While it is important to ensure that others can actually build and run your application, this is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we imitate their process properly, we need to add the means of running actual tests within our ci environment. - - Access your app - Open index.html in headless browser + + Integrating unit tests into ci + Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests, that test the functional components of your code. Tests that are invisible to other contributers because they are hidden away, and have only every been run on the original authors system, are of very limited use. Instead, your unit tests should run whenever your code changes, and they should run on a neutral system. You unit tests must therefore be integrated into your automated build and testing pipeline. As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite. To run these tests, we are going to leverate the support for running unit tests of our build system (e.g.: npm test, mvm test, …): + + Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find your tests, if you make the test command explicit. If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist is already running in the background withou our app installed, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. + How to right good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on integration tests alone, and your unit tests should be integrated into your ci system. - - Run your testsuite - tests that aren't run continuously are no good to anyone. + + Testing your app in a controlled context + As we have seen in the previous section unit tests are an important prerequiste for effective integration testing. The difference between the two is that unit tests excell at testing individual functions, and are quick to write and perform. Yet, they cannot capture the complex interaction between your code and that of the larger environment. Just search for 2 unit tests 0 integration tests to see what I mean. + For eXist-db applications, integration test will typically involve a browser, as we are trying to mimick the way a user will typically interact with our application, so our examples will focus on these kinds of browser testing. The concept, however, is not restricted to browser based applications. If you look at the test-suite for building the docker images used in these example you'll find some shell based tests that move between unit and integration testing. + Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to you, whichever you choose it should be clearely documented to your contributors know how to adjust test cases for new features and how to maintain your tests. In the following examples we will focus on cypress, as it does not require any additional steps for configuring a browser first. + As with your unit tests command, you can simply execute the cypress test command inside your ci test script. + + You write your tests in the same fashion as you would with mocha unit tests, however, you are now address the rendered document inside a browser instead of individual js or xquery functions. + + The above example opens a page in the browser, logs in, and close the window it just opened. You can do many more things, but these kind of simple examples should give you a good starting point for creating your first integration tests. If there are any console errors or problems with rendering content cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. + Now that we have opened build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. (we switched it on and there was no smoke). Now proper testing can commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers. All of which are excellent ideas, and with these basics in place it might no longer seem so daunting a task. Depending on your own specific requirments I would encourage your to browse other repositories in addition to the documentation of your CI and test-suite vendors. Chances are someone already has created a solid test, for what you want to try. Even without full test coverage, a litte effort can go a long way. diff --git a/src/main/xar-resources/data/integration-testing/listings/cypress.txt b/src/main/xar-resources/data/integration-testing/listings/cypress.txt new file mode 100644 index 00000000..f021e1a2 --- /dev/null +++ b/src/main/xar-resources/data/integration-testing/listings/cypress.txt @@ -0,0 +1,27 @@ +describe('The dashboard', function() { + it('should load', function() { + // Go to Dashboard + cy.visit('/dashboard/index.html') + }) + // Click the login button + describe('login', function() { + before(function() { + cy.get('#user_label').click() + + cy.get('#dijit_form_ValidationTextBox_0').type('admin') + + cy.get('#dijit_form_Button_0_label').click() + }) + + // check if Collection browser is there + it('should see Collection Browser', function() { + // click Collection Browser + cy.contains('Collections').click() + + // more tests go here … + + // close the window + cy.get('#inlineClose') + }) + }) +}) diff --git a/src/main/xar-resources/data/integration-testing/listings/travis-1.txt b/src/main/xar-resources/data/integration-testing/listings/travis-1.txt new file mode 100644 index 00000000..5657c258 --- /dev/null +++ b/src/main/xar-resources/data/integration-testing/listings/travis-1.txt @@ -0,0 +1,10 @@ +# Tell travis that we want java +language: java + +# This should be the minimal java version required by eXist-db +jdk: + - oraclejdk8 + +# This makes the build command explicit. +install: + - ant diff --git a/src/main/xar-resources/data/integration-testing/listings/travis-2.txt b/src/main/xar-resources/data/integration-testing/listings/travis-2.txt new file mode 100644 index 00000000..0e3e0f97 --- /dev/null +++ b/src/main/xar-resources/data/integration-testing/listings/travis-2.txt @@ -0,0 +1,25 @@ +language: java + +jdk: + - oraclejdk8 + - oraclejdk11 + +# Tell travis that we are using docker +services: + - docker + +# Always test against current and upcoming releases +env: + - img=existdb/existdb:latest + - img=existdb/existdb:release + +install: + - ant develop + +# take the .xar created above and install and deploy in a clean exist instance +before_script: + - docker cp ./build/*-dev.xar exist-ci:exist/autodeploy + - docker start exist-ci + # exist needs time + - sleep 30 + - docker ps diff --git a/src/main/xar-resources/data/integration-testing/listings/travis-3.txt b/src/main/xar-resources/data/integration-testing/listings/travis-3.txt new file mode 100644 index 00000000..7c5063f7 --- /dev/null +++ b/src/main/xar-resources/data/integration-testing/listings/travis-3.txt @@ -0,0 +1,26 @@ +language: java + +jdk: + - oraclejdk8 + - oraclejdk11 + +services: + - docker + +env: + - img=existdb/existdb:latest + - img=existdb/existdb:release + +install: + - ant develop + +before_script: + - docker cp ./build/*-dev.xar exist-ci:exist/autodeploy + - docker start exist-ci + # exist needs time + - sleep 30 + - docker ps + +# This makes the test command explicit. +script: + - ant test diff --git a/src/main/xar-resources/data/integration-testing/listings/travis-4.txt b/src/main/xar-resources/data/integration-testing/listings/travis-4.txt new file mode 100644 index 00000000..46fe10aa --- /dev/null +++ b/src/main/xar-resources/data/integration-testing/listings/travis-4.txt @@ -0,0 +1,26 @@ +language: java + +jdk: + - oraclejdk8 + - oraclejdk11 + +services: + - docker + +env: + - img=existdb/existdb:latest + - img=existdb/existdb:release + +install: + - ant develop + +before_script: + - docker cp ./build/*-dev.xar exist-ci:exist/autodeploy + - docker start exist-ci + # exist needs time + - sleep 30 + - docker ps + +script: + - ant test + - npx cypress run From c903216eda9aa48e2e29091c428681906024ed26 Mon Sep 17 00:00:00 2001 From: duncdrum Date: Mon, 10 Dec 2018 13:48:43 +0100 Subject: [PATCH 06/11] add general testing article --- .../integration-testing.xml | 17 ++--- .../xar-resources/data/testing/testing.xml | 76 +++++++++++++++++++ .../xar-resources/data/xqsuite/xqsuite.xml | 20 ++--- 3 files changed, 94 insertions(+), 19 deletions(-) create mode 100644 src/main/xar-resources/data/testing/testing.xml diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml index b48433ed..b9cf21da 100644 --- a/src/main/xar-resources/data/integration-testing/integration-testing.xml +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -5,16 +5,15 @@ Integration Testing 4Q18 - testing application-development - CI + testing - To ensure the long-term maintainability of an application, it is important to not only test its individual functions, but also the way the application interacts with other components of the exist-db environment. This artilce covers recommendations for configuring an automated test environment to perform integration test of eXist-db apps. - These recommendations apply to application developers of any level. It also defines the minimal requirements for authors who wish to publish their apps under the exist-db namespace. It assumes that you are familiar with the XQsuite framework for unit-testing. + This article discusses intergration testing of eXist-db applications. It also covers recommendations for the configuration of automated test environments, and explains the minimum testing requirements for apps that are published under the eXist-db namespace. + It assumes that you are familiar with the XQsuite framework for unit-testing, and the general strategies for designing tests in eXist-db. @@ -25,21 +24,21 @@ Building on a clean system Before you start designing tests, you should start to automate your build process. This ensures that things don't only work on your system, and it can catch some common errors. The examples in this article will use travis-ci as it is the most popular continual integration (ci) provider in the exist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . A simple configuration that builds your application on a clean virtual machine, witout the risk of local hidden files interfering, looks like this: - + For travis the required name of such a configuration is .travis.yml for the correct way to create such a configuration file for your CI provider please consult their documantation. In all cases, since exist-db is written in Java, your app should be build on a system that comes with the Java, version required by eXist-db. Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. Depending on your the design of your app, you should make sure that all build targets and configurations are run by the ci service. If you use java code in your app, it makes sense to build with multiple java versions (e.g. by adding - openjdk11). It might be necessary to test building on on different operation systems. You can consult your ci services documentation for the list of options they support and for how to configure them. Add a running eXist-db instance and install your app The next step is to take the result of your automated build process and install it in a running eXist-db instance. We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of getting an instance up and running. Let's extend the file create in the previous section. - + The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use (e.g. :4.4.0), if you want to ensure backwards compatibility. But these two tags will ensure that whatever that your code is tests both with the most current stable release, and with upcoming changes. To actually install the app we have simply copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. So far we have simply automated the basic steps of building and installing your app. This only catches the most basic and sever erros. While it is important to ensure that others can actually build and run your application, this is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we imitate their process properly, we need to add the means of running actual tests within our ci environment. Integrating unit tests into ci Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests, that test the functional components of your code. Tests that are invisible to other contributers because they are hidden away, and have only every been run on the original authors system, are of very limited use. Instead, your unit tests should run whenever your code changes, and they should run on a neutral system. You unit tests must therefore be integrated into your automated build and testing pipeline. As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite. To run these tests, we are going to leverate the support for running unit tests of our build system (e.g.: npm test, mvm test, …): - + Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find your tests, if you make the test command explicit. If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist is already running in the background withou our app installed, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. How to right good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on integration tests alone, and your unit tests should be integrated into your ci system. @@ -49,9 +48,9 @@ For eXist-db applications, integration test will typically involve a browser, as we are trying to mimick the way a user will typically interact with our application, so our examples will focus on these kinds of browser testing. The concept, however, is not restricted to browser based applications. If you look at the test-suite for building the docker images used in these example you'll find some shell based tests that move between unit and integration testing. Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to you, whichever you choose it should be clearely documented to your contributors know how to adjust test cases for new features and how to maintain your tests. In the following examples we will focus on cypress, as it does not require any additional steps for configuring a browser first. As with your unit tests command, you can simply execute the cypress test command inside your ci test script. - + You write your tests in the same fashion as you would with mocha unit tests, however, you are now address the rendered document inside a browser instead of individual js or xquery functions. - + The above example opens a page in the browser, logs in, and close the window it just opened. You can do many more things, but these kind of simple examples should give you a good starting point for creating your first integration tests. If there are any console errors or problems with rendering content cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. Now that we have opened build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. (we switched it on and there was no smoke). Now proper testing can commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers. All of which are excellent ideas, and with these basics in place it might no longer seem so daunting a task. Depending on your own specific requirments I would encourage your to browse other repositories in addition to the documentation of your CI and test-suite vendors. Chances are someone already has created a solid test, for what you want to try. Even without full test coverage, a litte effort can go a long way. diff --git a/src/main/xar-resources/data/testing/testing.xml b/src/main/xar-resources/data/testing/testing.xml new file mode 100644 index 00000000..76e03d1d --- /dev/null +++ b/src/main/xar-resources/data/testing/testing.xml @@ -0,0 +1,76 @@ +
+ + Testing + 4Q18 + + application-development + + + + + + In this article we discuss the types of testing available in relation to eXist-db and its applications. It assumes readers have a basic understanding of XML and XQuery. + + + + + Overview + + + Different kinds of tests play an essential role in maintain a high quality code base both for eXist-db itself, and for applications that interact with eXist-db either as deployed packages from the inside, or in the forms of external tools. + + The test framework of eXist-db and its apps is under continuous development, with frequent changes to the softwares and services in use. Covering them all is not feasible in this article. So we recommend that you check our Github repositories and search for a system that is similar to yours, for further insipiration. + + While the exact terminology varies between different sources, the following categories are all recogniced as distinct types of test, even when the terms might slightly vary. + + + + + Validation + : Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should consider how you can leverary these features native features first. + + + + + Unit testing + : these tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery name XQsuite. It is prominenlty used in our bug reports. You can run multiple unit test tools to test, e.g. java, javascript, and Xquery code. + + + + + integration testing + : A (rewritten) range index which provides superior performance on large data sets. + + + + + (WIP) Performance and Stress testing + : Performance testing ensures that your code continous to function under heavy load, or with very little resources. Stress tests go one step further, by crashing your code on-purpose to ensure that it recovers gracefully. Practically speaking the difference between the two is very fluid. + + + There will never be a one size fits all solution to take care of all your testing needs. Writing good test takes time an planning. You can find out more about available options and their use cases in the articles linked above. The remainder of this article will discuss some general considerations for how to design your test-suite, without referencing a specifc implementation. + + + + + + Deciding on the right type of test + + Generally speaking, you should follow the sequence provided by the above list. Whatever, can be tested as part of your validation tests, should do so. If validation based testing isn't a good fit, go for unit tests, followed by integration and lastly performance tests. Not only are validation tests faster then most unit tests (which in turn are slower then integration tests and performance tests). They also are more easy to configure, and have a higher chance of providing you with the information that you need when a test fails. + + Selection example + To illustrate this lets take a theoretical example, imagine your code includes a online form where users pick a data that needs to be stored in the database. For the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other means. + Provided that you are using eXist-db, we can assume that the date will be stored in some kind of xml file. By validating this xml file, and ensuring that it's content are of the correct datatype xs:date you can be sure that your data is what you expect it to be, and you can prevent your users from providing an input that is not a date. + You could also run a unit test on the function that takes the user input and stores it in the database. With validation already taken care of, you can focus your unit tests on corner cases, such as dates that are very unlikely, or that use a different date format. If don't take advantage of validation first, you would have to write many unit tests, that check what happens when the user types 29.02.1983 vs 28.02.1983, and whole range of other possibilties. + This same process happens for the next type, integration testing. Without unit tests you would have to mock a large number of ways that users interact with your date form, from typos, to different browsers, or pointer devices. Instead, with both validation and unit tests in place, your integration tests should focus on the question if the form appears to working, that is can users see it (presumably in the browser), and interact with it in the way that you intended them to by clicking, typing, etc. Since you no longer have to worry about the contents, you can focus on the interaction. + Lastly, performance and stess tests would simply assume all of the above to be in place. They would check for problems that might occur, when large numbers of users select the same date simultaneously, or provide an invalid data, to ensure that your code is not crashing under heavy load. + This quick example should give you an idea on how to think about testing your code. Each type of test has its own reason for being, and requires your attention. A good performance test cannot substitue unit or integration tests. If you feel that your tests are not working well, because they frequently fail to show problems in your code, and when they do they don't make identifying the source of the problem easier, chances are that you are trying to test something with one type of test, that would be better suited to another type. + + + + How many tests do I need + The short answers is: the more the merrier. It is certainly possible to reach full test coverage for you code, meaning that every meaningful unit of code has a corresponding set of tests. While other programming languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. The section on integration testing contains the definition of a minimal smoke test that the eXist-db community is using internally. + +
diff --git a/src/main/xar-resources/data/xqsuite/xqsuite.xml b/src/main/xar-resources/data/xqsuite/xqsuite.xml index 69b37f9d..26ab3cc3 100644 --- a/src/main/xar-resources/data/xqsuite/xqsuite.xml +++ b/src/main/xar-resources/data/xqsuite/xqsuite.xml @@ -1,16 +1,16 @@ -
- - XQSuite - Annotation-based Test Framework for XQuery - 4Q18 - - application-development - xquery - - +
+ + XQSuite - Annotation-based Test Framework for XQuery + 4Q18 + + application-development + testing + xquery + + From 52174fbcb8240e90f7cb3b32bafb68ee34ac9006 Mon Sep 17 00:00:00 2001 From: duncdrum Date: Mon, 10 Dec 2018 15:42:00 +0100 Subject: [PATCH 07/11] edits --- .../integration-testing.xml | 41 +++++++---- .../data/testing/assets/browse-form.png | Bin 0 -> 21695 bytes .../data/testing/assets/date-form.png | Bin 0 -> 9252 bytes .../data/testing/listings/data-1.txt | 3 + .../data/testing/listings/valid.txt | 3 + .../data/testing/listings/xq-test.txt | 6 ++ .../xar-resources/data/testing/testing.xml | 69 +++++++++++++----- 7 files changed, 87 insertions(+), 35 deletions(-) create mode 100644 src/main/xar-resources/data/testing/assets/browse-form.png create mode 100644 src/main/xar-resources/data/testing/assets/date-form.png create mode 100644 src/main/xar-resources/data/testing/listings/data-1.txt create mode 100644 src/main/xar-resources/data/testing/listings/valid.txt create mode 100644 src/main/xar-resources/data/testing/listings/xq-test.txt diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml index b9cf21da..5e4609c6 100644 --- a/src/main/xar-resources/data/integration-testing/integration-testing.xml +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -19,40 +19,49 @@ Introduction - It is possible to create an automated mininal testsuite with relatively little effort. Instead of post-poning the process it is often more efficient to take the need for testing into account in the earliest phases of development. This enables others whishing to extend your program with new features, by knowning that these don't break existing functions, and by allowing test only contributions to help you to gradually advance your test coverage. The following section will walk you trough the three main aspects of such a minimal test setup. + Creating an automated mininal testsuite is possible with relatively little effort. It pays to take the need for testing into account when you start developing your application. This enables others to extend your program with new features, by knowning that these don't break existing functions. It also allows test only contributions, to help you to gradually advance your test coverage. The following section will walk you trough the three main aspects of such a minimal test setup. Building on a clean system Before you start designing tests, you should start to automate your build process. This ensures that things don't only work on your system, and it can catch some common errors. - The examples in this article will use travis-ci as it is the most popular continual integration (ci) provider in the exist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . A simple configuration that builds your application on a clean virtual machine, witout the risk of local hidden files interfering, looks like this: + The examples in this article will use travis-ci as it is the most popular continual integration (ci) provider in the exist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . + The services typically require a small configuration file, so you can build your code on a clean virtual machine, without the risk of local files interfering. For travis the required name of such a file is .travis.yml and in its simplest form it would look like this: - For travis the required name of such a configuration is .travis.yml for the correct way to create such a configuration file for your CI provider please consult their documantation. In all cases, since exist-db is written in Java, your app should be build on a system that comes with the Java, version required by eXist-db. Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. - Depending on your the design of your app, you should make sure that all build targets and configurations are run by the ci service. If you use java code in your app, it makes sense to build with multiple java versions (e.g. by adding - openjdk11). It might be necessary to test building on on different operation systems. You can consult your ci services documentation for the list of options they support and for how to configure them. + For the correct way to create such a configuration file for other CI providers please consult their documantation. In all cases, since exist-db is written in Java, your app should be build on a system that comes with the minimal Java version required by eXist-db. + Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. + If you have multiple build targets for production and development, you should make sure that each build targets is actually run by the ci service. + You can extend this basic template depending on your needs. E.g.: Apps written in java might want to run the build step on multiple java versions (by adding - openjdk11); or to test building on on different operation systems. You should consult your ci services documentation for the list of available configuration options. Add a running eXist-db instance and install your app The next step is to take the result of your automated build process and install it in a running eXist-db instance. We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of getting an instance up and running. Let's extend the file create in the previous section. - The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use (e.g. :4.4.0), if you want to ensure backwards compatibility. But these two tags will ensure that whatever that your code is tests both with the most current stable release, and with upcoming changes. To actually install the app we have simply copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. - So far we have simply automated the basic steps of building and installing your app. This only catches the most basic and sever erros. While it is important to ensure that others can actually build and run your application, this is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we imitate their process properly, we need to add the means of running actual tests within our ci environment. + The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use (e.g. :4.4.0), if you want to ensure backwards compatibility. But these two tags will ensure that your code is tested against both the most current stable release, and upcoming changes. + To actually install the app we have simply copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. + So far we have simply automated the basic steps of building and installing your app. This already catches some basic and particularly severe erros, but it is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we imitate their process properly, we first need to add the means of running actual tests within our ci environment. Integrating unit tests into ci - Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests, that test the functional components of your code. Tests that are invisible to other contributers because they are hidden away, and have only every been run on the original authors system, are of very limited use. Instead, your unit tests should run whenever your code changes, and they should run on a neutral system. You unit tests must therefore be integrated into your automated build and testing pipeline. As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite. To run these tests, we are going to leverate the support for running unit tests of our build system (e.g.: npm test, mvm test, …): + Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests for the functional components of your code. By running your unit tests inside your ci server, these become immediately visible to potential contributors, and you have the advantage of immediate feedback on every code change. + Tests that are invisible to other contributers because they are hidden away, and have only every been run on the original authors system, are of very limited use. + As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite. To run your tests, we are going to leverage the support for running unit tests of our build system (e.g.: npm test, mvm test, …): - Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find your tests, if you make the test command explicit. If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist is already running in the background withou our app installed, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. - How to right good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on integration tests alone, and your unit tests should be integrated into your ci system. + Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find your tests, if you make the test command explicit. + If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist is already running in the background t our app installed, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. + How to write good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on integration tests alone, and your unit tests should be integrated into your ci system. Testing your app in a controlled context - As we have seen in the previous section unit tests are an important prerequiste for effective integration testing. The difference between the two is that unit tests excell at testing individual functions, and are quick to write and perform. Yet, they cannot capture the complex interaction between your code and that of the larger environment. Just search for 2 unit tests 0 integration tests to see what I mean. - For eXist-db applications, integration test will typically involve a browser, as we are trying to mimick the way a user will typically interact with our application, so our examples will focus on these kinds of browser testing. The concept, however, is not restricted to browser based applications. If you look at the test-suite for building the docker images used in these example you'll find some shell based tests that move between unit and integration testing. - Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to you, whichever you choose it should be clearely documented to your contributors know how to adjust test cases for new features and how to maintain your tests. In the following examples we will focus on cypress, as it does not require any additional steps for configuring a browser first. - As with your unit tests command, you can simply execute the cypress test command inside your ci test script. + As we have seen in the previous section unit tests are an important pre-requiste for effective integration testing. The difference between the two is that unit tests excell at testing individual functions, and are quick to write and perform. Yet, they cannot capture the complex interaction between your code and that of the larger environment. Just search for 2 unit tests 0 integration tests to see what I mean. + For eXist-db applications, integration test will typically involve a browser, as we are trying to mimick the way a user will typically interact with our application. While our examples focus on browser testing, you can see shell based integration tests at the test-suite for building the docker images we used earlier. + Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to you, whichever you choose it should be clearely documented so your contributors know how to adjust test cases for new features and how to maintain your tests. We focus on cypress, as it does not require any additional steps for configuring a browser first. + If you need to perform cross-browser testing you can take a look at services such as sauce labs + You can simply execute the cypress test command inside your ci test script after the unit test command we added earlier. - You write your tests in the same fashion as you would with mocha unit tests, however, you are now address the rendered document inside a browser instead of individual js or xquery functions. + With cypress you write your tests in the same fashion as you would with mocha unit tests, however, you now address the rendered document inside a browser instead of individual js functions. - The above example opens a page in the browser, logs in, and close the window it just opened. You can do many more things, but these kind of simple examples should give you a good starting point for creating your first integration tests. If there are any console errors or problems with rendering content cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. - Now that we have opened build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. (we switched it on and there was no smoke). Now proper testing can commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers. All of which are excellent ideas, and with these basics in place it might no longer seem so daunting a task. Depending on your own specific requirments I would encourage your to browse other repositories in addition to the documentation of your CI and test-suite vendors. Chances are someone already has created a solid test, for what you want to try. Even without full test coverage, a litte effort can go a long way. + The above example opens a page (the dashboard) in the browser, logs in, and close the window it just opened. You can do many more things, but these kind of simple examples should give you a good starting point for creating your first integration test. If there are any console errors or problems with rendering content cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. + Now that we have build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. We switched it on and there was no smoke. Proper testing can now commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers, or … . + All of which are excellent ideas, and with these basics in place it might no longer seem so daunting a task. Depending on your own specific requirments I would encourage your to browse other eXist-db repositories in addition to the documentation of your CI and test-suite vendors. Chances are someone already has created a solid test, similar to what you want to try.
diff --git a/src/main/xar-resources/data/testing/assets/browse-form.png b/src/main/xar-resources/data/testing/assets/browse-form.png new file mode 100644 index 0000000000000000000000000000000000000000..a3f3d61a05f99336902674a102a95e83c44dde19 GIT binary patch literal 21695 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 literal 0 HcmV?d00001 diff --git a/src/main/xar-resources/data/testing/listings/data-1.txt b/src/main/xar-resources/data/testing/listings/data-1.txt new file mode 100644 index 00000000..d0573583 --- /dev/null +++ b/src/main/xar-resources/data/testing/listings/data-1.txt @@ -0,0 +1,3 @@ +… +$USER_INPUT +… diff --git a/src/main/xar-resources/data/testing/listings/valid.txt b/src/main/xar-resources/data/testing/listings/valid.txt new file mode 100644 index 00000000..1f4fb216 --- /dev/null +++ b/src/main/xar-resources/data/testing/listings/valid.txt @@ -0,0 +1,3 @@ +declare function local:check-input($input as item()*) as xs:date { + $input cast as xs:date +}; diff --git a/src/main/xar-resources/data/testing/listings/xq-test.txt b/src/main/xar-resources/data/testing/listings/xq-test.txt new file mode 100644 index 00000000..00a1b957 --- /dev/null +++ b/src/main/xar-resources/data/testing/listings/xq-test.txt @@ -0,0 +1,6 @@ +declare + %test:arg("input", '11.11.2010') %test:assertEquals('11.11.2010') + %test:arg("input", '5') %test:assertError() + function local:check-input($input as item()*) as xs:date { + $input cast as xs:date +}; diff --git a/src/main/xar-resources/data/testing/testing.xml b/src/main/xar-resources/data/testing/testing.xml index 76e03d1d..5c6e5c33 100644 --- a/src/main/xar-resources/data/testing/testing.xml +++ b/src/main/xar-resources/data/testing/testing.xml @@ -23,31 +23,31 @@ The test framework of eXist-db and its apps is under continuous development, with frequent changes to the softwares and services in use. Covering them all is not feasible in this article. So we recommend that you check our Github repositories and search for a system that is similar to yours, for further insipiration. - While the exact terminology varies between different sources, the following categories are all recogniced as distinct types of test, even when the terms might slightly vary. + While the terminology might vary slighlty between different sources dealing with testing, the principle categories apply to all irrespective of terminology. - Validation - : Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should consider how you can leverary these features native features first. + Validation: + Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should consider how you can leverary these features native features first. - Unit testing - : these tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery name XQsuite. It is prominenlty used in our bug reports. You can run multiple unit test tools to test, e.g. java, javascript, and Xquery code. + Unit testing: + These tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery named xQsuite. It is prominenlty used in our bug reports and source-code repo. Typicall applications will need to run multiple unit test tools to test, e.g. java, javascript, and Xquery code. - integration testing - : A (rewritten) range index which provides superior performance on large data sets. + integration testing: + Look at your programm as a whole, similar to how a user would interact with it, by simulating user input and running you programm not in isolation but in concert with different applications. - (WIP) Performance and Stress testing - : Performance testing ensures that your code continous to function under heavy load, or with very little resources. Stress tests go one step further, by crashing your code on-purpose to ensure that it recovers gracefully. Practically speaking the difference between the two is very fluid. + (WIP) Performance and Stress testing: + Performance testing ensures that your code continous to function under heavy load, or with very little resources. Stress tests go one step further by purposfully crashing your application to ensure that it recovers gracefully. Practically speaking, the difference between the two is fluid. There will never be a one size fits all solution to take care of all your testing needs. Writing good test takes time an planning. You can find out more about available options and their use cases in the articles linked above. The remainder of this article will discuss some general considerations for how to design your test-suite, without referencing a specifc implementation. @@ -56,21 +56,52 @@ - Deciding on the right type of test + Deciding on how to test - Generally speaking, you should follow the sequence provided by the above list. Whatever, can be tested as part of your validation tests, should do so. If validation based testing isn't a good fit, go for unit tests, followed by integration and lastly performance tests. Not only are validation tests faster then most unit tests (which in turn are slower then integration tests and performance tests). They also are more easy to configure, and have a higher chance of providing you with the information that you need when a test fails. + Generally speaking, you should follow the sequence provided above. Whatever, can be tested as part of your validation tests, is best tested there. When validation testing isn't a good fit, go for unit tests, followed by integration and lastly performance tests. The reasons for this are twofold. On the one hand, validation tests tend to be faster than unit tests, which in turn are slower then integration tests and performance tests. on the other hand, each type tends to be more easy to configure, with a higher chance of providing you with the information that you need when a test fails. - Selection example - To illustrate this lets take a theoretical example, imagine your code includes a online form where users pick a data that needs to be stored in the database. For the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other means. - Provided that you are using eXist-db, we can assume that the date will be stored in some kind of xml file. By validating this xml file, and ensuring that it's content are of the correct datatype xs:date you can be sure that your data is what you expect it to be, and you can prevent your users from providing an input that is not a date. - You could also run a unit test on the function that takes the user input and stores it in the database. With validation already taken care of, you can focus your unit tests on corner cases, such as dates that are very unlikely, or that use a different date format. If don't take advantage of validation first, you would have to write many unit tests, that check what happens when the user types 29.02.1983 vs 28.02.1983, and whole range of other possibilties. - This same process happens for the next type, integration testing. Without unit tests you would have to mock a large number of ways that users interact with your date form, from typos, to different browsers, or pointer devices. Instead, with both validation and unit tests in place, your integration tests should focus on the question if the form appears to working, that is can users see it (presumably in the browser), and interact with it in the way that you intended them to by clicking, typing, etc. Since you no longer have to worry about the contents, you can focus on the interaction. - Lastly, performance and stess tests would simply assume all of the above to be in place. They would check for problems that might occur, when large numbers of users select the same date simultaneously, or provide an invalid data, to ensure that your code is not crashing under heavy load. + Selecting test types + To illustrate this, lets take a theoretical example: imagine your code includes an online form where users submit a date that needs to be stored in the database. For the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other means.Provided that you are using eXist-db, we assume that the date will be stored in some kind of xml file. + + a basic form example + a simple form: + + + + + that will create something like this: + + + By using a schema for validating this xml file, you can ensure the correct datatype xs:date of the provided input, and prevent users from storing something in the database that is not a date. + + using native types + + + To check that your local:check-input function is working as expected, you can define a few unit test Typically, such a test would include some corner cases like BCE dates, leap years, or dates in foreign date formats, as well as a basic test date that should simply store in the db. + + testing corner cases + + For in-depth examples of unit testing in xQuery please see the examples in the xQsuite article + + Integration testing is most effective when it can rely on existing unit tests and focus on how a user typically interacts with the UI components. Does the browser display the input form correctly at different resolutions, and the form be selected with a mouse, or on touch screens. + + browser testing + For in-depth examples of unit testing in xQuery please see the examples in the xQsuite article +
+ form in browser + + + + + +
+
+ Lastly, performance and stress tests would simply assume all of the above to be in place. They would check for problems that might occur, when large numbers of users select the same or invalide dates, or access the same form simultaneously. This quick example should give you an idea on how to think about testing your code. Each type of test has its own reason for being, and requires your attention. A good performance test cannot substitue unit or integration tests. If you feel that your tests are not working well, because they frequently fail to show problems in your code, and when they do they don't make identifying the source of the problem easier, chances are that you are trying to test something with one type of test, that would be better suited to another type.
- How many tests do I need - The short answers is: the more the merrier. It is certainly possible to reach full test coverage for you code, meaning that every meaningful unit of code has a corresponding set of tests. While other programming languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. The section on integration testing contains the definition of a minimal smoke test that the eXist-db community is using internally. + Test Coverage + Ideally, we would always achieve full test coverage for our code. So that every meaningful unit of code has a corresponding set of tests. While other programming languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. The section on integration testing contains the definition of a minimal smoke test that the eXist-db community is using internally.
From 5a445957fc10cdcfe9e543a708aa36b2d1ed1a88 Mon Sep 17 00:00:00 2001 From: duncdrum Date: Mon, 10 Dec 2018 16:21:26 +0100 Subject: [PATCH 08/11] edit landing page, add testing keyword, minor edits --- .../author-reference/author-reference.xml | 1146 ++++++++----- .../data/documentation/documentation.xml | 1512 +++++++++-------- .../integration-testing.xml | 117 +- .../xar-resources/data/testing/testing.xml | 137 +- .../data/validation/validation.xml | 393 +++-- 5 files changed, 1967 insertions(+), 1338 deletions(-) diff --git a/src/main/xar-resources/data/author-reference/author-reference.xml b/src/main/xar-resources/data/author-reference/author-reference.xml index 8130d1ad..f62baf2b 100644 --- a/src/main/xar-resources/data/author-reference/author-reference.xml +++ b/src/main/xar-resources/data/author-reference/author-reference.xml @@ -1,199 +1,456 @@
- - - - Author Reference - 1Q18 - - authoring - exist - - - - - - This article describes the conventions for writing articles for the eXist-db documentation - set. The eXist-db documentation set is (since beginning 2018) based on a subset of the - Docbook 5 content model. If you want to contribute an article (please do) it must conform to - the standards described here. - - - - - General guidelines - - Here are some general writing (and tagging) guidelines: - - - Please start of with a short introduction of your article in one or a few - paragraphs before diving in. These paragraphs must be placed - before the first sect1. - Describe what the article is about and for whom. What is the subject? Is it - for total novices, beginners, advanced programming gurus in Java hyperspace? - Prevent readers from diving in and find out that it's not for them. - - - Presenting longer listings can best be done by storing these in separate - documents and linking them (see ). This makes - maintenance easier (ever edited a large CDATA section with XML inside?). - An additional reason is that somewhere in the future we intend to enable - running code-examples directly from the documentation app. For this these - examples must be in separate documents. So make sure that at least runnable - examples are separated from your text. - - - Of course all the normal technical writing guidelines apply: Keep your target - group in mind (what do they know and, more importantly, what not), write correct - English, use plenty of examples, split the article in sections and sub-sections - that make sense, etc. - - - - - Patterns to avoid - - The following patterns tend to occur again and again in writing documentation. - Please try to avoid them… - The examples exaggerated, but that's for illustration purposes, not to offend - anyone. - - - Avoid the difficult and explain the easy - - It is very tempting to skip quickly over some hard parts of the documentation - and instead describe some of the easy parts in length. For instance: - - - <para>To configure the <emphasis>xyz</emphasis> extension you have to create an - XML configuration file. Here is an example:</para> - <programlisting>(some skimpy example of a complicated configuration file that is supposed to speak for itself + <!-- ================================================================== --> + + <info> + <title>Author Reference + 1Q18 + + authoring + exist + + + + + + This article describes the conventions for writing articles for the eXist-db documentation + set. The eXist-db documentation set is (since beginning 2018) based on a subset of the Docbook 5 + content model. If you want to contribute an article (please do) it must conform to the standards + described here. + + + + + General guidelines + + Here are some general writing (and tagging) guidelines: + + + Please start of with a short introduction of your article in one or a few paragraphs + before diving in. These paragraphs must be placed before the first + sect1. + Describe what the article is about and for whom. What is the subject? Is it for total + novices, beginners, advanced programming gurus in Java hyperspace? Prevent readers from + diving in and find out that it's not for them. + + + Presenting longer listings can best be done by storing these in separate documents and + linking them (see ). This makes maintenance easier (ever edited + a large CDATA section with XML inside?). + An additional reason is that somewhere in the future we intend to enable running + code-examples directly from the documentation app. For this these examples must be in + separate documents. So make sure that at least runnable examples are separated from your + text. + + + Of course all the normal technical writing guidelines apply: Keep your target group in + mind (what do they know and, more importantly, what not), write correct English, use + plenty of examples, split the article in sections and sub-sections that make sense, + etc. + + + + + Patterns to avoid + + The following patterns tend to occur again and again in writing documentation. Please + try to avoid them… + The examples exaggerated, but that's for illustration purposes, not to offend + anyone. + + + Avoid the difficult and explain the easy + + It is very tempting to skip quickly over some hard parts of the documentation and + instead describe some of the easy parts in length. For instance: + + + <para>To configure the <emphasis>xyz</emphasis> extension you have to create an XML + configuration file. Here is an example:</para> + <programlisting>(some skimpy example of a complicated configuration file that is supposed to speak for itself but does not because its too simple)</programlisting> - <para>To work with the user interface open this, click here, enter the password - twice, click ok, bla bla bla, going on for multiple paragraphs…</para> - </example> - - <para>Well, your reader isn't stupid and hasn't seen a GUI for the first time. So - telling him/her that a password needs to be entered twice and that ok must be - clicked is completely superfluous. Just point your reader to the GUI and maybe - to the right menu but that's all. Believe me, they know how to fill in a dialog - box.</para> - <para>But they do not know what all these elements and attributes in the - configuration file mean. Even if the names speak for themselves, some - explanation will be necessary. Best to describe them all, mention defaults, - examples, etc.</para> - <para>And yes, that's hard work, both in thinking and writing. But if you want your - xyz extension to be used and useful (that's what you wrote it for, right?) its - part of the job.</para> - </sect3> - - <sect3 xml:id="polite"> - <title>Being overly polite - - Sometimes writers try to be very polite to both the reader and, strangely - enough, the system. Since the reader wants it clear and you can't offend a - system, don't. - - - Table title - - - - - - Polite version - Straight version - - - - - The logfile should appear. - The logfile appears. - - - You may enter ... - Enter ... - - - If you wish you can also... - It is also possible to ... Also: - ... - - - Please navigate to... - Navigate to ... - - - -
-
- - - Using thus instead of therefore - Somehow there seems to be a preference among eXist-db's documentation writers - for the word "thus" when "therefore" is meant. Thus is almost always wrong in - this kind of prose, so please default to therefore. If you want to know more - read on here. - - - - Java isn't always interesting - Some articles that explain stuff about things in the XQuery realm keep - rambling on about stuff in Java or in eXist-db's architecture: Servlets that - execute, methods that are called, etc. - Yes, because you are a Java programmer its probably - interesting to you. But when the intended audience of the article is XQuery - programmers, don't bother them with this. And if you really (really!) think it - is necessary information for some of them, add it to a separate section at the - bottom. - - -
- - -
- - - - - Technical guidelines - - More information about Docbook itself can be found on the official Docbook site. - - - - - Collection (directory) structure - - - A single article must be stored in a collection on its own, the - article-collection. Related assets or other files will - be stored in sub-collections of this. This setup ensures that everything - belonging to a single article stays together. - - - In the eXist documentation app, the article-collection will become a - sub-collection of the data collection. So an article-collection - called new-cool-feature will become - /db/apps/doc/data/new-cool-feature. - - - The name of the article-collection should be the same as the document-name - of the article itself. So if your article is called - new-cool-feature.xml, store it as - new-cool-feature/new-cool-feature.xml. - - - Any binary assets (images, etc.) referenced by your article must be stored - in a sub-collection assets. So in our example in - new-cool-feature/assets. - - - Any non-binary assets (usually included program/text listings) referenced - by your article must be stored in a sub-collection listings. So - in our example in new-cool-feature/listings. - - + To work with the user interface open this, click here, enter the password twice, + click ok, bla bla bla, going on for multiple paragraphs… +
+ + Well, your reader isn't stupid and hasn't seen a GUI for the first time. So telling + him/her that a password needs to be entered twice and that ok must be clicked is + completely superfluous. Just point your reader to the GUI and maybe to the right menu but + that's all. Believe me, they know how to fill in a dialog box. + But they do not know what all these elements and attributes in the configuration file + mean. Even if the names speak for themselves, some explanation will be necessary. Best to + describe them all, mention defaults, examples, etc. + And yes, that's hard work, both in thinking and writing. But if you want your xyz + extension to be used and useful (that's what you wrote it for, right?) its part of the + job. +
+ + + Being overly polite + + Sometimes writers try to be very polite to both the reader and, strangely enough, the + system. Since the reader wants it clear and you can't offend a system, don't. + + + Table title + + + + + + + Polite version + + + Straight version + + + + + + + The logfile should appear. + + + The logfile appears. + + + + + You may enter ... + + + Enter ... + + + + + If you wish you can also... + + + It is also possible to ... + Also: ... + + + + + Please navigate to... + + + Navigate to ... + + + + +
+
+ + + Using thus instead of therefore + Somehow there seems to be a preference among eXist-db's documentation writers for the + word "thus" when "therefore" is meant. Thus is almost always wrong in this kind of prose, + so please default to therefore. If you want to know more read on here. + + + + Java isn't always interesting + Some articles that explain stuff about things in the XQuery realm keep rambling on + about stuff in Java or in eXist-db's architecture: Servlets that execute, methods that are + called, etc. + Yes, because you are a Java programmer its probably interesting + to you. But when the intended audience of the article is XQuery programmers, don't bother + them with this. And if you really (really!) think it is necessary information for some of + them, add it to a separate section at the bottom. + + +
+ + +
+ + + + + Technical guidelines + + More information about Docbook itself can be found on the official Docbook site. + + + + + Collection (directory) structure + + + A single article must be stored in a collection on its own, the + article-collection. Related assets or other files will be stored + in sub-collections of this. This setup ensures that everything belonging to a single + article stays together. + + + In the eXist documentation app, the article-collection will become a sub-collection + of the data collection. So an article-collection called + new-cool-feature will become + /db/apps/doc/data/new-cool-feature. + + + The name of the article-collection should be the same as the document-name of the + article itself. So if your article is called new-cool-feature.xml, store it + as new-cool-feature/new-cool-feature.xml. + + + Any binary assets (images, etc.) referenced by your article must be stored in a + sub-collection assets. So in our example in + new-cool-feature/assets. + + + Any non-binary assets (usually included program/text listings) referenced by your + article must be stored in a sub-collection listings. So in our example in + new-cool-feature/listings. + + + + All rules regarding collection names are not there for technical reasons but to + promote consistency. If you deviate and make sure all references are correct it will still + work. However, to keep things maintainable it is strongly recommended to follow the rules + stated above (or, if you really think they're stupid, apply for a rule change). + + + + + + + Overall XML structure + Here is an example how an article for this documentation set looks like: + + Both the processing instructions at the top are optional but strongly recommended. + They're present to guide tools like oXygen in validating the document and provide authoring + hints. + + + + + + Article information + Here is an example the article's mandatory information section: + + The following rules and guidelines apply: + + + There must be a title present in a title element. + This is the main title of the document. It will be displayed at the top of the + page. + + + Optional but strongly recommended is a date in the date element. This + will be displayed below the title and provide the reader with some clue on how old this + information is. We all know that sometimes articles get outdated but are not removed... + You don't have to provide an exact date. Just month and year will do, or some indication + like 1Q18. + + + We use keywords to mark an article for certain subject areas. See . + + + You can add more information in info to your heart's desire but the + renderer won't use nor display it. + + + + + Keyword usage + + The info element must contain at least one keyword. This is used to create + an index on subject. Multiple keywords can be specified by repeating the + keyword element. + Keywords are always written lower-case and must not contain + spaces. + The following keywords are in use: + + Keyword usage + + + + + + + Keyword + + + Meaning + + + + + + + + + application-development + + + + Information related to using eXIst-db as an application platform. + + + + + + exist + + + + Anything related to eXist-db itself, like legal statements, how to send in + bugs, etc. + + + + + + getting-started + + + + Basic information on how to get eXist-db up and running. + + + + + + java-development + + + + Information about programming Java for or in eXist-db. + + + + + + indexing + + + + Information related to eXist-db's indexes. + + + + + + installation + + + + Information about installing eXist-db + + + + + + interfaces + + + + Information about specific interfaces eXist-db provides + + + + + + operations + + + + How to keep eXist-db up and running, not from a programmer's but from a + system maintenance point of view. + + + + + + testing + + + + Information related to testing eXist-db or its applications. + + + + + + xquery + + + + Information related to XQuery (or XPath) in general or eXist-db's specific + features of the language. + + + + +
+ + + Tables like the one above tend to get outdated sooner or later (because somebody + adds/deletes a keyword and forgets to update it). To see all the keywords actually in + use, look at the index-by-subject section of the main documentation page. + Watch out: For legibility reasons the keywords there are presented + capitalized. Remember that in the article documents the keywords + must be stated in lower-case! + + +
+ +
+ + + + + Supported block elements + + The following Docbook 5 block level elements are supported for the eXist-db + documentation set. Unsupported elements will be flagged when the content is rendered (you'll + see a bold red error message in the middle of your story). + + + + + Paragraphs + + Use para to tag text as a paragraph. + + + + + Section levels + + You can use sect1 up to sect3 as section levels. Only + sect1 and sect2 will appear in the table of contents. Markup + in titles is ignored. + + + + + Lists + + You can use either itemizedlist (with bullets) or + orderedlist (with numbers). + + + + + Variable list + + A variablelist is a bit of a misnomer. It creates lists like this one + (the list of block elements you're looking at now), so it's useful for much more than + variables. + If you want a narrow left column (like this one), add + spacing="compact". + + + + + Notes + All rules regarding collection names are not there for technical reasons but to promote consistency. If you deviate and make sure all references are correct @@ -525,191 +782,318 @@ but does not because its too simple) Inline elements in title elements are not supported. Any markup in titles is ignored. - - - - - Emphasis - - Use emphasis for emphasizing. - Although discouraged, you can request a specific emphasis type: - - - Use role="bold" for bold - emphasis. - - - Use role="underline" for underlined emphasis. - - - Use role="italic" for italic emphasis. This looks the same as no - role attribute but produces an i instead - of an em. - - - - - - - GUI Items - - Use guimenuitem around anything referring to choices in a - GUI, for instance menu choices. The effect is - now simple italic but that might change later. - - - - - Code - - Use code or literal for literals, pieces of - code, commands, etc. The result will be mono-spaced. - The general guideline is to use this for everything that lists pieces - of code, attributes, variable names, etc. For elements use - tag. - - - - - Tags - - A tag element surrounds its content with < and > and - formats it like code. Meant to make life easier: - is the shorter - version of - . - - - - - Figures - - Use the inlinemediaobject to add an asset inline in the - text. Docbook prescribes an elaborate XML construction, here is an - example of a paragraph with an inline figure: - - This produces: - There is an asset - - - - here. - The width attribute is the only size-related attribute - recognized and used. - - - - - Internal links - - You can create a link to any block level element with the - xref element. To do so, give the target an identifier by - using xml:id="..." and mention this identifier in the - linkend attribute of the xref. - You can generate a specific link text by adding an - xreflabel attribute to the target - element, like here: . If this - attribute is not present on the target its title is used, like this: - . If there is no title, the name of - the element is presented. - - - - - External links - - Links to external sources are done with the link element. - Place the target's full URI in the xlink:href attribute. - For instance, - - links to the eXist - home page. - To open the link on a new page, add - condition="_blank". - - - - - Article links - - To create a link to another article in this documentation set, also - use the link element. However, use the target's document name - (without the .xml extension) as the link address. For - instance, - links - to the documentation home - page. - - - - - - - - - - - Generating indexes - - Indexes can be automagicly generated. For examples have a look at the documentation home page. There are three - variations: - - - Alphabetical index on title - - Add a role="indexontitle" attribute to a para - element. An index on title will be generated after it. - - - - Index on keyword, all - - Add a role="indexonkeyword" attribute to a - para element. An index on keywords (as specified in the - info element, see ) will be - generated after it. - - - - Index on keyword, single - - Add a role="indexonkeyword:somekeyword" attribute to a - para element to generate a list of articles with this - specific keyword (as specified in the info element, see ). - - - - - -
- - - - - Additional tools - - There are two additional pages in the documentation app to help authors and - editors: - - - Editorial - view - - The editorial view provides an overview of all the articles and their - incoming and outgoing links. - - - - Diagnostics - - Performs limited diagnostics. Checks whether the outgoing links in - articles to other articles, listings and assets are ok. Also checks whether - there are unreferenced (and therefore superfluous) listings and - assets. - - - - - - -
\ No newline at end of file + + + + + Examples + + + An example of an example + The example element produces an example in a layout like this. It + must have a title element, which is displayed at the bottom: + + + + + + Listings + + Anything you want to present as a program listing or other fixed text (e.g. a + sequence of commands) must be enclosed in a programlisting element. There + are two ways to provide the actual contents of the listing: + + + Simply enclose the text in the programlisting element. Use CDATA if + necessary. Any markup will be ignored. + + + Add an xlink:href attribute + (xmlns:xlink="http://www.w3.org/1999/xlink") with a reference to a + file containing the text. This must be a relative reference + (e.g. xlink:href="listings/mylisting.txt"). The contents of the + element will be ignored. + Using the xlink:href attribute is definitely + not the proper way to do this. It should be done by using + an xi:include element inside programlisting. However, + current XInclude limitations in eXist prevent this from working properly (it can + only include XML, not text). So therefore this workaround. + + + Listings have two display modes: + + + If it's a listing in some language (like XML), add a language + attribute with the name of the language. The render will try to add some color + coding (if it recognizes it). Here is a listing with + language="xml": + + + + For a straight listing, don't add a language attribute. Here is + the same listing as above without: + + + + + + + + Figures + + Use figure or informalfigure to add an asset. The effect of + both elements is almost the same, the only difference is that an informal figure has + no title. Docbook prescribes an elaborate XML construction, here is an example: + + This produces: +
+ Figure title here + + + + + +
+ The width attribute is the only size-related attribute used. It sets + the width relative to the available horizontal space. If you don't specify a width a + default of 75% is used. +
+
+ + + Tables + + Use table or informaltable to add a table. The effect of + both elements is almost the same, the only difference is that an informal table has no + title. Table layout is kept simple and straight. Here is how a simple table looks + like: + + And this is the result: + + Table title + + + + + + + Col 1 + + + Col 2 + + + + + + + Bla + + + More bla + + + + + Blegh + + + More blegh + + + + +
+
+
+ + + + + + + + + Supported inline elements + The following inline elements are supported: + + Inline elements in title elements are not supported. + Any markup in titles is ignored. + + + + + + Emphasis + + Use emphasis for emphasizing. + Although discouraged, you can request a specific emphasis type: + + + Use role="bold" for bold + emphasis. + + + Use role="underline" for underlined + emphasis. + + + Use role="italic" for italic + emphasis. This looks the same as no role attribute but + produces an i instead of an em. + + + + + + + GUI Items + + Use guimenuitem around anything referring to choices in a GUI, for + instance menu choices. The effect is now simple italic but + that might change later. + + + + + Code + + Use code or literal for literals, pieces of code, commands, + etc. The result will be mono-spaced. + The general guideline is to use this for everything that lists pieces of code, + attributes, variable names, etc. For elements use tag. + + + + + Tags + + A tag element surrounds its content with < and > and formats it + like code. Meant to make life easier: is the + shorter version of . + + + + + Figures + + Use the inlinemediaobject to add an asset inline in the text. Docbook + prescribes an elaborate XML construction, here is an example of a paragraph with an + inline figure: + + This produces: + There is an asset + + + + here. + The width attribute is the only size-related attribute recognized and + used. + + + + + Internal links + + You can create a link to any block level element with the xref element. + To do so, give the target an identifier by using xml:id="..." and mention + this identifier in the linkend attribute of the xref. + You can generate a specific link text by adding an xreflabel + attribute to the target element, like here: . If this attribute is not present on the target its + title is used, like this: . If there is no title, + the name of the element is presented. + + + + + External links + + Links to external sources are done with the link element. Place the + target's full URI in the xlink:href attribute. For instance, + + links to the eXist home page. + To open the link on a new page, add condition="_blank". + + + + + Article links + + To create a link to another article in this documentation set, also use the + link element. However, use the target's document name (without the + .xml extension) as the link address. For instance, + links to the documentation home page. + + + + + + + + + + + Generating indexes + + Indexes can be automagicly generated. For examples have a look at the documentation home page. There are three + variations: + + + Alphabetical index on title + + Add a role="indexontitle" attribute to a para element. An + index on title will be generated after it. + + + + Index on keyword, all + + Add a role="indexonkeyword" attribute to a para element. + An index on keywords (as specified in the info element, see ) will be generated after it. + + + + Index on keyword, single + + Add a role="indexonkeyword:somekeyword" attribute to a + para element to generate a list of articles with this specific keyword + (as specified in the info element, see ). + + + + + + + + + + + Additional tools + + There are two additional pages in the documentation app to help authors and + editors: + + + + Editorial view + + + The editorial view provides an overview of all the articles and their incoming and + outgoing links. + + + + + Diagnostics + + + Performs limited diagnostics. Checks whether the outgoing links in articles + to other articles, listings and assets are ok. Also checks whether there are + unreferenced (and therefore superfluous) listings and assets. + + + + + + + diff --git a/src/main/xar-resources/data/documentation/documentation.xml b/src/main/xar-resources/data/documentation/documentation.xml index eb8c7c58..fdace17a 100644 --- a/src/main/xar-resources/data/documentation/documentation.xml +++ b/src/main/xar-resources/data/documentation/documentation.xml @@ -1,685 +1,829 @@
- - Documentation - 1Q18 - - getting-started - - - - Welcome to eXist-db. This article serves as an index to the eXist-db documentation - articles, which will help you getting to know, install and use eXist-db. - - - - - Getting Started - The following articles and resources will help you getting started using eXist. - - - - Basic Installation - - How to do a basic installation of eXist-db and fire it up for the first - time. - - - - Screencasts - - For the first steps with your freshly installed eXist-db, watch the - screencasts available on the eXist-db homepage - - - - eXist-db - Book - - There is a whole book about eXist-db, written for both the novice - and the more experienced user. - - - - Getting Help - - This article will tell you where to go for help and advice. - - - - Dashboard - - Learn how to use and populate eXist-db's main user interface, the - dashboard. - - - - Uploading files - - Learn how to get files in and populate your database. - - - - WebDAV - - One of the ways to easily view and populate the database is using the - WebDAV protocol. - - - - Using Collections in eXist-db - - Provide information about how to set up a collection structure in - eXist-db. - - - - Learning XQuery - - Provides tips and resources for newcomers to XQuery and eXist-db - - - - How to use oXygen together with eXist-db - - If you're using oXygen, this article describes how - to make the most of it in combination with eXIst-db. - - - - How to report an issue - - If you think you found a bug, this article will tell you how to report - it. - - - - - - - - - - XQuery - eXist-db's main programming language is XQuery. This documentation set does not - contain a full introduction to XQuery. For this read the excellent book about XQuery by - Priscilla Walmsley. The XQuery related articles below discuss specific eXist-db - related details or shed light on some of the lesser known features of the - language. - - - - Learning XQuery - - This provides tips and resources for newcomers to XQuery and - eXist-db - - - - XQuery in eXist-db - - This discusses the XQuery implementation of eXist-db for the somewhat more - experienced user - - - - KWIC (Keywords In Context) - - This article will learn you how to display search results in context - (parts of the document surrounding the search match). - - - - XQuery Update Extensions - - Tells you how to update XML stored in the database using eXist-db's update - extension. - - - - xqDoc - - Describes the built-in XQuery documentation system. - - - - XQsuite - - This is an annotation based framework that allows you to add tests to - XQuery functions and execute them. - - - - - - - - - - Application development - - eXist-db is not only a database but also an excellent application development - platform. The following articles will help you find your way in this: - - - - Getting Started with Web Application - Development - - This will help you build a basic web application using the built-in HTML templating framework. - - - - Using Collections in eXist-db - - Provide information about how to set up your application's collection - structure in eXist-db. - - - - xmldb module - - Provides an overview of the functions to query and manipulate the database - contents in the xmldb module. - - - - URL Rewriting - - How to control the mapping of URL's to code in eXist-db. This is one the - most important mechanisms in eXist-db to base applications on. - - - - XSL Transformations - - Explains how to perform XSL Transformation in XQuery code. - - - - Indexing - - This will provide you with an overview of eXist-db's indexes and how to - configure them. More about indexing in: - - - Full Text indexing - - Will provide with all the information necessary to use - eXist-db's Lucene based full-text indexing. - - - - N-Gram Index - - Provides information on how to configure the - ngram index. - - - - Range Index - - This article describes eXist-db's super fast modularized range - index based on Apache Lucene. - There is also an older - version of the range index, kept for compatibility - reasons. Usage of this range index is discouraged. - - - - - - - XInclude Support - - Explains how to use XInclude in eXist-db. - - - - The beginners guide to - XRX - - This article will learn you how to create a simple application using XRX - (XForms, REST, XQuery). - - - - Package Repository - - How to work with EXPath packages in eXist-db. - - - - Content extraction - - Shows how to extract and index non-XML contents, like PDF or Word - documents. - - - - REST-Style Web API - - Explains how to use eXist-db's REST interface, a useful tool in building - applications. - - - - HTTP Request/Session - - Provides information about the functions available working with HTTP - requests and sessions. - - - - Scheduler Module - - How to regularly schedule jobs. - - - - Security - - When you get serious writing applications, you need to be aware of the - security model of eXist-db. - - - - REST-Style Web API - - Explains how to use eXist-db's REST interface, a useful tool in building - applications. - - - - XML Validation - - Explains how to do XML validation in eXist-db. - - - - HTTP Request/Session - - Provides information about the functions available working with HTTP - requests and sessions. - - - - XForms Introduction - - Introduces the bright shiny world of XForms inside eXist-db to you. - - - - Tuning the Database - - Explains what you can do to optimize your queries and indexes. - - - - Configuring Database Triggers - - Will tell you how to use and configure triggers in your database that - fire when things get created, updated or deleted. - - - - Versioning Extension - - Explains how to use the built-in versioning system of eXist-db. - - - - XQsuite - - This is an annotation based framework that allows you to add tests to - XQuery functions and execute them. - - - - - - - - - - Interfaces - - eXist-db provides many ways of interfacing with the database. - - - - REST-Style Web API - - Explains how to use eXist-db's REST interface. - - - - SOAP Interface Developer's Guide - - Explains how to add a SOAP interface to eXist-db using Java code. - - - - XML-RPC API Developer's Guide - - Explains how to interface with eXist-db using the XML-RPC API. - - - - WebDAV - - Explains how to use eXist-db's WebDAV interface. - - - - - - - - - - Operations - Operations is the art of installing eXist-db and keeping it up-and-running - professionally. This includes things like more advanced installation types, doing - backups and restores, automate data transfers, etc. - - - - Java Admin Client - - This is a utility for performing basic administrative tasks. It has both a - GUI and a command line interface. - - - - Configuration - - How to configure eXist-db using its main configuration file - conf.xml. - - - - Backups - - How to backup and restore an eXist-db database. - - - - Advanced Installation - - How to install eXist-db on a headless (no GUI) system and run it as a - service. - - - - Ant tasks - - How to use the specific eXist-db Ant tasks to automate common - system administration and operation tasks. - - - - Database Deployment - - How to install eXist-db as a stand-alone or embedded server. - - - - Building eXist - - How to build Java .jar or .war files from an - eXist distribution. - - - - Performance FAQ - - Contains a short FAQ about eXist-db's performance. - - - - Production Use - Good - Practice - - When you use eXist-db on a production system, please read this for - advice. - - - - Production use - Proxying eXist-db - behind a Web Server - - You can proxy eXist-db behind a web server like Nginx or Apache. This - article will provide you with some examples. - - - - JMX - - eXist has a JMX interface for access to internal statistics about memory, - caching, etc. - - - - incompatibilities overview - - Consult this article when you upgrade from an older version of - eXist-db. - - - - Scheduler Module - - Scheduling jobs (like backups) is a useful tool in an eXist-db - installation. - - - - Security - - The security model of eXist. Also explains how to connect eXist-db to - other authentication realms like LDAP or OAuth. - - - - Tuning the Database - - Explains what you can do to optimize the database's performance. - - - - Performance FAQ - - Contains a short FAQ about eXist-db's performance. - - - - - - - - - - Upgrade Guide - - Helps you updating to a new version of eXist-db. - - - - incompatibilities overview - - Consult this article when you upgrade from an older version of - eXist-db. - - - - - - - - - - Java development - eXist-db is based on Java. Besides using eXist-db as a stand-alone application - platform, you can also use it from within Java code. The following - articles will help you with this. - - - - Database Deployment - - How to install eXist-db as a stand-alone or embedded server. An embedded - server can be accessed directly from Java code. - - - - Writing Java Applications with the XML:DB - API - - Explains how to work with eXist-db from Java code using the XML:DB API. - This API provides a common interface to native or XML-enabled databases and - supports the development of portable, reusable applications. - - - - Building eXist - - How to build Java .jar or .war files from an - eXist distribution. - - - - Developer's Guide to Modularized - Indexes - - Explains how the internal indexing mechanism works and how to add your own - indexes to it. - - - - Log4j Logging Guide - - This article explains how to add logging to your Java code using - Log4J. - - - - SOAP Interface Developer's Guide - - Explains how to add a SOAP interface to eXist-db using Java code. - - - - XML-RPC API Developer's Guide - - Explains how to interface with eXist-db using the XML-RPC API. - - - - Extension Modules - - Provides an overview of how to create eXist-db extension modules (in Java) - and contains a list of available extension modules. - - - - JMX - - eXist provides access to various management interfaces using JMX. - - - - Developer's Guide to Modularized - Indexes - - Explains how the internal indexing mechanism works and how to add your own - indexes to it. - - - - Log4j Logging Guide - - This article explains how to add logging to your Java code using - Log4J. - - - - SOAP Interface Developer's Guide - - Explains how to add a SOAP interface to eXist-db using Java code. - - - - XML-RPC API Developer's Guide - - Explains how to interface with eXist-db using the XML-RPC API. - - - - Extension Modules - - Provides an overview of how to create eXist-db extension modules (in Java) - and contains a list of available extension modules. - - - - - - - - - - Developing eXist-db - - The following articles provide information on how to work on eXist-db itself, either - by enhancing its code or providing documentation. - - - - eXist-db Developer Manifesto - - This article lays out guidelines for developers that wish to contribute to - eXist-db's code base itself. - - - - Code Review Guide - - Provides instructions how to review somebody else's (or your own of - course) code. - - - - Author Reference - - Explains how to write a documentation article for eXist-db (like the ones - you are looking at now). - - - - Legal Statement - - Provides information about the legal status of eXist as an open source - product. - - - - - - - - - - Alphabetical index - This section lists all available articles in title alphabetical order. - - - - - - - Subject index - This section lists all available articles by subject. - - - -
\ No newline at end of file + + Documentation + 1Q18 + + getting-started + + + + Welcome to eXist-db. This article serves as an index to the eXist-db documentation articles, + which will help you getting to know, install and use eXist-db. + + + + + Getting Started + The following articles and resources will help you getting started using eXist. + + + + + Basic Installation + + + How to do a basic installation of eXist-db and fire it up for the first time. + + + + Screencasts + + For the first steps with your freshly installed eXist-db, watch the screencasts + available on the eXist-db + homepage + + + + + + eXist-db Book + + + There is a whole book about eXist-db, written for both the novice + and the more experienced user. + + + + + Getting Help + + + This article will tell you where to go for help and advice. + + + + + Dashboard + + + Learn how to use and populate eXist-db's main user interface, the dashboard. + + + + + Uploading files + + + Learn how to get files in and populate your database. + + + + + WebDAV + + + One of the ways to easily view and populate the database is using the WebDAV + protocol. + + + + + Using Collections in eXist-db + + + Provide information about how to set up a collection structure in eXist-db. + + + + + Learning XQuery + + + Provides tips and resources for newcomers to XQuery and eXist-db + + + + + How to use oXygen together with eXist-db + + + If you're using oXygen, this article describes how to make the most of it in combination with + eXIst-db. + + + + + How to report an issue + + + If you think you found a bug, this article will tell you how to report it. + + + + + + + + + + XQuery + eXist-db's main programming language is XQuery. This documentation set does not contain a + full introduction to XQuery. For this read the excellent book about XQuery by Priscilla + Walmsley. The XQuery related articles below discuss specific eXist-db related details + or shed light on some of the lesser known features of the language. + + + + + Learning XQuery + + + This provides tips and resources for newcomers to XQuery and eXist-db + + + + + XQuery in eXist-db + + + This discusses the XQuery implementation of eXist-db for the somewhat more + experienced user + + + + + KWIC (Keywords In Context) + + + This article will learn you how to display search results in context (parts of the + document surrounding the search match). + + + + + XQuery Update Extensions + + + Tells you how to update XML stored in the database using eXist-db's update + extension. + + + + + xqDoc + + + Describes the built-in XQuery documentation system. + + + + + XQsuite + + + This is an annotation based framework that allows you to add tests to XQuery + functions and execute them. + + + + + + + + + + Application development + + eXist-db is not only a database but also an excellent application development platform. + The following articles will help you find your way in this: + + + + + Getting Started with Web Application + Development + + + This will help you build a basic web application using the built-in HTML templating framework. + + + + + Using Collections in eXist-db + + + Provide information about how to set up your application's collection structure in + eXist-db. + + + + + xmldb module + + + Provides an overview of the functions to query and manipulate the database contents + in the xmldb module. + + + + + URL Rewriting + + + How to control the mapping of URL's to code in eXist-db. This is one the most + important mechanisms in eXist-db to base applications on. + + + + + XSL Transformations + + + Explains how to perform XSL Transformation in XQuery code. + + + + + Indexing + + + This will provide you with an overview of eXist-db's indexes and how to configure + them. More about indexing in: + + + + Full Text indexing + + + Will provide with all the information necessary to use eXist-db's Lucene based + full-text indexing. + + + + + N-Gram Index + + + Provides information on how to configure the ngram index. + + + + + Range Index + + + This article describes eXist-db's super fast modularized range index based on + Apache Lucene. + There is also an older version of the range + index, kept for compatibility reasons. Usage of this range index is + discouraged. + + + + + + + + Testing and Validation + + + This will provide you with an overview of testing eXist-db and its applications. More about testing in: + + + + XML Validation + + + Explains how to do XML validation in eXist-db. + + + + + XQsuite + + + This is an annotation based framework that allows you to add unit tests to XQuery + functions and execute them. + + + + + Integration testing + + + Provides information on how to configure automated test pipelines, and recommends minimal test configurations. + + + + + + + + XInclude Support + + + Explains how to use XInclude in eXist-db. + + + + + The beginners guide to XRX + + + This article will learn you how to create a simple application using XRX (XForms, + REST, XQuery). + + + + + Package Repository + + + How to work with EXPath packages in eXist-db. + + + + + Content extraction + + + Shows how to extract and index non-XML contents, like PDF or Word documents. + + + + + REST-Style Web API + + + Explains how to use eXist-db's REST interface, a useful tool in building + applications. + + + + + HTTP Request/Session + + + Provides information about the functions available working with HTTP requests and + sessions. + + + + + Scheduler Module + + + How to regularly schedule jobs. + + + + + Security + + + When you get serious writing applications, you need to be aware of the security + model of eXist-db. + + + + + XForms Introduction + + + Introduces the bright shiny world of XForms inside eXist-db to you. + + + + + Tuning the Database + + + Explains what you can do to optimize your queries and indexes. + + + + + Configuring Database Triggers + + + Will tell you how to use and configure triggers in your database that fire when + things get created, updated or deleted. + + + + + Versioning Extension + + + Explains how to use the built-in versioning system of eXist-db. + + + + + + + + + + Interfaces + + eXist-db provides many ways of interfacing with the database. + + + + + REST-Style Web API + + + Explains how to use eXist-db's REST interface. + + + + + SOAP Interface Developer's Guide + + + Explains how to add a SOAP interface to eXist-db using Java code. + + + + + XML-RPC API Developer's Guide + + + Explains how to interface with eXist-db using the XML-RPC API. + + + + + WebDAV + + + Explains how to use eXist-db's WebDAV interface. + + + + + + + + + + Operations + Operations is the art of installing eXist-db and keeping it up-and-running professionally. + This includes things like more advanced installation types, doing backups and restores, + automate data transfers, etc. + + + + + Java Admin Client + + + This is a utility for performing basic administrative tasks. It has both a GUI and a + command line interface. + + + + + Configuration + + + How to configure eXist-db using its main configuration file + conf.xml. + + + + + Backups + + + How to backup and restore an eXist-db database. + + + + + Advanced Installation + + + How to install eXist-db on a headless (no GUI) system and run it as a + service. + + + + + Ant tasks + + + How to use the specific eXist-db Ant tasks to automate common system + administration and operation tasks. + + + + + Database Deployment + + + How to install eXist-db as a stand-alone or embedded server. + + + + + Building eXist + + + How to build Java .jar or .war files from an eXist + distribution. + + + + + Performance FAQ + + + Contains a short FAQ about eXist-db's performance. + + + + + Production Use - Good Practice + + + When you use eXist-db on a production system, please read this for advice. + + + + + Production use - Proxying eXist-db behind a Web + Server + + + You can proxy eXist-db behind a web server like Nginx or Apache. This article will + provide you with some examples. + + + + + JMX + + + eXist has a JMX interface for access to internal statistics about memory, caching, + etc. + + + + + incompatibilities overview + + + Consult this article when you upgrade from an older version of eXist-db. + + + + + Scheduler Module + + + Scheduling jobs (like backups) is a useful tool in an eXist-db installation. + + + + + Security + + + The security model of eXist. Also explains how to connect eXist-db to other + authentication realms like LDAP or OAuth. + + + + + Tuning the Database + + + Explains what you can do to optimize the database's performance. + + + + + Performance FAQ + + + Contains a short FAQ about eXist-db's performance. + + + + + + + + + + + Upgrade Guide + + + Helps you updating to a new version of eXist-db. + + + + + incompatibilities overview + + + Consult this article when you upgrade from an older version of eXist-db. + + + + + + + + + + Java development + eXist-db is based on Java. Besides using eXist-db as a stand-alone application platform, + you can also use it from within Java code. The following articles will + help you with this. + + + + + Database Deployment + + + How to install eXist-db as a stand-alone or embedded server. An embedded server can + be accessed directly from Java code. + + + + + Writing Java Applications with the XML:DB API + + + Explains how to work with eXist-db from Java code using the XML:DB API. This API + provides a common interface to native or XML-enabled databases and supports the + development of portable, reusable applications. + + + + + Building eXist + + + How to build Java .jar or .war files from an eXist + distribution. + + + + + Developer's Guide to Modularized Indexes + + + Explains how the internal indexing mechanism works and how to add your own indexes + to it. + + + + + Log4j Logging Guide + + + This article explains how to add logging to your Java code using Log4J. + + + + + SOAP Interface Developer's Guide + + + Explains how to add a SOAP interface to eXist-db using Java code. + + + + + XML-RPC API Developer's Guide + + + Explains how to interface with eXist-db using the XML-RPC API. + + + + + Extension Modules + + + Provides an overview of how to create eXist-db extension modules (in Java) and + contains a list of available extension modules. + + + + + JMX + + + eXist provides access to various management interfaces using JMX. + + + + + Developer's Guide to Modularized Indexes + + + Explains how the internal indexing mechanism works and how to add your own indexes + to it. + + + + + Log4j Logging Guide + + + This article explains how to add logging to your Java code using Log4J. + + + + + SOAP Interface Developer's Guide + + + Explains how to add a SOAP interface to eXist-db using Java code. + + + + + XML-RPC API Developer's Guide + + + Explains how to interface with eXist-db using the XML-RPC API. + + + + + Extension Modules + + + Provides an overview of how to create eXist-db extension modules (in Java) and + contains a list of available extension modules. + + + + + + + + + + Developing eXist-db + + The following articles provide information on how to work on eXist-db itself, either by + enhancing its code or providing documentation. + + + + + eXist-db Developer Manifesto + + + This article lays out guidelines for developers that wish to contribute to + eXist-db's code base itself. + + + + + Code Review Guide + + + Provides instructions how to review somebody else's (or your own of course) + code. + + + + + Author Reference + + + Explains how to write a documentation article for eXist-db (like the ones you are + looking at now). + + + + + Legal Statement + + + Provides information about the legal status of eXist as an open source + product. + + + + + + + + + + Alphabetical index + This section lists all available articles in title alphabetical order. + + + + + + + Subject index + This section lists all available articles by subject. + + + + diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml index 5e4609c6..4331efa9 100644 --- a/src/main/xar-resources/data/integration-testing/integration-testing.xml +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -9,59 +9,104 @@ testing - - - This article discusses intergration testing of eXist-db applications. It also covers recommendations for the configuration of automated test environments, and explains the minimum testing requirements for apps that are published under the eXist-db namespace. + This article discusses intergration testing of eXist-db applications. It also covers recommendations for the configuration of automated test environments, and explains the + minimum testing requirements for apps that are published under the eXist-db namespace. It assumes that you are familiar with the XQsuite framework for unit-testing, and the general strategies for designing tests in eXist-db. - - Introduction - Creating an automated mininal testsuite is possible with relatively little effort. It pays to take the need for testing into account when you start developing your application. This enables others to extend your program with new features, by knowning that these don't break existing functions. It also allows test only contributions, to help you to gradually advance your test coverage. The following section will walk you trough the three main aspects of such a minimal test setup. + Creating an automated mininal testsuite is possible with relatively little effort. It pays to take the need for testing into account when you start developing your + application. This enables others to extend your program with new features, by knowning that these don't break existing functions. It also allows test only contributions, to + help you to gradually advance your test coverage. The following section will walk you trough the three main aspects of such a minimal test setup. Building on a clean system - Before you start designing tests, you should start to automate your build process. This ensures that things don't only work on your system, and it can catch some common errors. - The examples in this article will use travis-ci as it is the most popular continual integration (ci) provider in the exist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . - The services typically require a small configuration file, so you can build your code on a clean virtual machine, without the risk of local files interfering. For travis the required name of such a file is .travis.yml and in its simplest form it would look like this: - - For the correct way to create such a configuration file for other CI providers please consult their documantation. In all cases, since exist-db is written in Java, your app should be build on a system that comes with the minimal Java version required by eXist-db. - Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. + Before you start designing tests, you should start to automate your build process. This ensures that things don't only work on your system, and it can catch some common + errors. + The examples in this article will use travis-ci as it is the most popular continual integration (ci) + provider in the exist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . + The services typically require a small configuration file, so you can build your code on a clean virtual machine, without the risk of local files interfering. For + travis the required name of such a file is .travis.yml and in its simplest form it would look like this: + + For the correct way to create such a configuration file for other CI providers please consult their documantation. In all cases, since exist-db is written in Java, your + app should be build on a system that comes with the minimal Java version required by eXist-db. + + Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses + ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. + If you have multiple build targets for production and development, you should make sure that each build targets is actually run by the ci service. - You can extend this basic template depending on your needs. E.g.: Apps written in java might want to run the build step on multiple java versions (by adding - openjdk11); or to test building on on different operation systems. You should consult your ci services documentation for the list of available configuration options. + You can extend this basic template according to your needs, e.g.: Apps written in java might want to run the build step on multiple java versions (by adding - + openjdk11); or to test building on on different operation systems. You should consult your ci services documentation for the list of available configuration + options. Add a running eXist-db instance and install your app - The next step is to take the result of your automated build process and install it in a running eXist-db instance. We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of getting an instance up and running. Let's extend the file create in the previous section. - - The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use (e.g. :4.4.0), if you want to ensure backwards compatibility. But these two tags will ensure that your code is tested against both the most current stable release, and upcoming changes. - To actually install the app we have simply copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. - So far we have simply automated the basic steps of building and installing your app. This already catches some basic and particularly severe erros, but it is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we imitate their process properly, we first need to add the means of running actual tests within our ci environment. + The next step is to take the result of your automated build process and install it in a running eXist-db instance. We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of + getting an instance up and running. Let's extend the file create in the previous section. + + The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use + (e.g. :4.4.0), if you want to ensure backwards compatibility. But these two tags will ensure that your code is tested against both the most current + stable release, and upcoming changes. + + To actually install the app we have simply copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared + for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. + + So far we have simply automated the basic steps of building and installing your app. This already catches some basic and particularly severe erros, but it is not a + very realistic test of what users actually experience when they install your application. Before we can refine the way we imitate their process properly, we first need to + add the means of running actual tests within our ci environment. Integrating unit tests into ci - Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests for the functional components of your code. By running your unit tests inside your ci server, these become immediately visible to potential contributors, and you have the advantage of immediate feedback on every code change. - Tests that are invisible to other contributers because they are hidden away, and have only every been run on the original authors system, are of very limited use. - As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite. To run your tests, we are going to leverage the support for running unit tests of our build system (e.g.: npm test, mvm test, …): - - Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find your tests, if you make the test command explicit. - If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist is already running in the background t our app installed, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. - How to write good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on integration tests alone, and your unit tests should be integrated into your ci system. + Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests + for the functional components of your code. By running your unit tests inside your ci server, these become immediately visible to potential contributors, and you have the + advantage of immediate feedback on every code change. + + Tests that are invisible to other contributers because they are hidden away, and have only every been run on the original authors system, are of very limited + use. + + As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite for xQuery. To run your tests, we are going to leverage the support for running unit tests of our build system (e.g.: npm test, mvm test, + …): + + + Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find + your tests, if you make the test command explicit. + + If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist is already running in the background t our app + installed, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. + How to write good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you + are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on integration tests alone, and your + unit tests should be integrated into your ci system. Testing your app in a controlled context - As we have seen in the previous section unit tests are an important pre-requiste for effective integration testing. The difference between the two is that unit tests excell at testing individual functions, and are quick to write and perform. Yet, they cannot capture the complex interaction between your code and that of the larger environment. Just search for 2 unit tests 0 integration tests to see what I mean. - For eXist-db applications, integration test will typically involve a browser, as we are trying to mimick the way a user will typically interact with our application. While our examples focus on browser testing, you can see shell based integration tests at the test-suite for building the docker images we used earlier. - Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to you, whichever you choose it should be clearely documented so your contributors know how to adjust test cases for new features and how to maintain your tests. We focus on cypress, as it does not require any additional steps for configuring a browser first. - If you need to perform cross-browser testing you can take a look at services such as sauce labs + As we have seen in the previous section unit tests are an important pre-requiste for effective integration testing. The difference between the two is that unit tests + excell at testing individual functions, and are quick to write and perform. Yet, they cannot capture the complex interaction between your code and that of the larger + environment. Just search for 2 unit tests 0 + integration tests to see what I mean. + For eXist-db applications, integration test will typically involve a browser, as we are trying to mimick the way a user interacts with our application from their system. + + While our examples focus on browser testing, you can see shell based integration tests at the test-suite for building the docker images we used earlier. + Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to + you, whichever you choose it should be clearely documented so your contributors know how to adjust test cases for new features and how to maintain your tests. We focus on + cypress, as it does not require any additional steps for configuring a browser first. + + If you need to perform cross-browser testing you can take a look at services such as sauce + labs + You can simply execute the cypress test command inside your ci test script after the unit test command we added earlier. - - With cypress you write your tests in the same fashion as you would with mocha unit tests, however, you now address the rendered document inside a browser instead of individual js functions. - - The above example opens a page (the dashboard) in the browser, logs in, and close the window it just opened. You can do many more things, but these kind of simple examples should give you a good starting point for creating your first integration test. If there are any console errors or problems with rendering content cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. - Now that we have build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. We switched it on and there was no smoke. Proper testing can now commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers, or … . - All of which are excellent ideas, and with these basics in place it might no longer seem so daunting a task. Depending on your own specific requirments I would encourage your to browse other eXist-db repositories in addition to the documentation of your CI and test-suite vendors. Chances are someone already has created a solid test, similar to what you want to try. + + With cypress you write your tests in the same fashion as you would with mocha unit tests, however, you now address the rendered document inside a browser instead of + individual js functions. + + The above example opens a page (the dashboard) in the browser, logs in, and close the window it just opened. You can do many more things, but these kind of simple + examples should give you a good starting point for creating your first integration test. If there are any console errors or problems with rendering content cypress will + create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. + Now that we have build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have + achieved a basic smoke test. We switched it on and there was no smoke. Proper testing can now commence. Obviously you might want to visit multiple pages, or compare + screenshots to avoid visual regressions, or compare images in multiple browsers, or … . + All of which are excellent ideas, and with these basics in place it might no longer seem so daunting a task. Depending on your own specific requirments I would + encourage your to browse other eXist-db repositories in addition to the documentation of your CI and test-suite vendors. Chances are someone already has created a solid + test, similar to what you want to try. - + \ No newline at end of file diff --git a/src/main/xar-resources/data/testing/testing.xml b/src/main/xar-resources/data/testing/testing.xml index 5c6e5c33..8576f0b4 100644 --- a/src/main/xar-resources/data/testing/testing.xml +++ b/src/main/xar-resources/data/testing/testing.xml @@ -6,22 +6,21 @@ 4Q18 application-development + testing - - - In this article we discuss the types of testing available in relation to eXist-db and its applications. It assumes readers have a basic understanding of XML and XQuery. - + In this article we discuss the types of testing available in relation to eXist-db and its applications. It assumes readers have a basic understanding of XML and + XQuery. - Overview - - - Different kinds of tests play an essential role in maintain a high quality code base both for eXist-db itself, and for applications that interact with eXist-db either as deployed packages from the inside, or in the forms of external tools. + Different kinds of tests play an essential role in maintain a high quality code base both for eXist-db itself, and for applications that interact with eXist-db either as + deployed packages from the inside, or in the forms of external tools. - The test framework of eXist-db and its apps is under continuous development, with frequent changes to the softwares and services in use. Covering them all is not feasible in this article. So we recommend that you check our Github repositories and search for a system that is similar to yours, for further insipiration. + The test framework of eXist-db and its apps is under continuous development, with frequent changes to the softwares and services in use. Covering them all is not + feasible in this article. So we recommend that you check our Github repositories and search for a + system that is similar to yours, for further insipiration. While the terminology might vary slighlty between different sources dealing with testing, the principle categories apply to all irrespective of terminology. @@ -29,79 +28,93 @@ Validation: - Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should consider how you can leverary these features native features first. + Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should consider how you can leverary + these features native features first. Unit testing: - These tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery named xQsuite. It is prominenlty used in our bug reports and source-code repo. Typicall applications will need to run multiple unit test tools to test, e.g. java, javascript, and Xquery code. + These tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery named xQsuite. It is prominenlty + used in our bug reports and source-code repo. Typicall applications will need to run multiple unit test tools to test, e.g. java, javascript, and Xquery code. - integration testing: - Look at your programm as a whole, similar to how a user would interact with it, by simulating user input and running you programm not in isolation but in concert with different applications. + Integration testing: + Look at your programm as a whole, similar to how a user would interact with it, by simulating user input and running you programm not in isolation but in + concert with different applications. - - (WIP) Performance and Stress testing: - Performance testing ensures that your code continous to function under heavy load, or with very little resources. Stress tests go one step further by purposfully crashing your application to ensure that it recovers gracefully. Practically speaking, the difference between the two is fluid. + (WIP) Performance and Stress testing: Performance testing ensures that your code continous to function under heavy load, or with very little + resources. Stress tests go one step further by purposfully crashing your application to ensure that it recovers gracefully. Practically speaking, the difference between + the two is fluid. - There will never be a one size fits all solution to take care of all your testing needs. Writing good test takes time an planning. You can find out more about available options and their use cases in the articles linked above. The remainder of this article will discuss some general considerations for how to design your test-suite, without referencing a specifc implementation. + There will never be a one size fits all solution to take care of all your testing needs. Writing good test takes time an planning. You can find out more about available + options and their use cases in the articles linked above. The remainder of this article will discuss some general considerations for how to design your test-suite, without + referencing a specifc implementation. - - - Deciding on how to test - - Generally speaking, you should follow the sequence provided above. Whatever, can be tested as part of your validation tests, is best tested there. When validation testing isn't a good fit, go for unit tests, followed by integration and lastly performance tests. The reasons for this are twofold. On the one hand, validation tests tend to be faster than unit tests, which in turn are slower then integration tests and performance tests. on the other hand, each type tends to be more easy to configure, with a higher chance of providing you with the information that you need when a test fails. + Picking a Type + Generally speaking, you should follow the sequence provided above. Whatever, can be tested as part of your validation tests, is best tested there. When validation testing + isn't a good fit, go for unit tests, followed by integration and lastly performance tests. The reasons for this are twofold. On the one hand, validation tests tend to be + faster than unit tests, which in turn are slower then integration tests and performance tests. on the other hand, each type tends to be more easy to configure, with a higher + chance of providing you with the information that you need when a test fails. - Selecting test types - To illustrate this, lets take a theoretical example: imagine your code includes an online form where users submit a date that needs to be stored in the database. For the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other means.Provided that you are using eXist-db, we assume that the date will be stored in some kind of xml file. - - a basic form example - a simple form: - - - - - that will create something like this: - - - By using a schema for validating this xml file, you can ensure the correct datatype xs:date of the provided input, and prevent users from storing something in the database that is not a date. - - using native types - - - To check that your local:check-input function is working as expected, you can define a few unit test Typically, such a test would include some corner cases like BCE dates, leap years, or dates in foreign date formats, as well as a basic test date that should simply store in the db. - - testing corner cases - - For in-depth examples of unit testing in xQuery please see the examples in the xQsuite article - - Integration testing is most effective when it can rely on existing unit tests and focus on how a user typically interacts with the UI components. Does the browser display the input form correctly at different resolutions, and the form be selected with a mouse, or on touch screens. - - browser testing - For in-depth examples of unit testing in xQuery please see the examples in the xQsuite article -
- form in browser - - - - - -
-
- Lastly, performance and stress tests would simply assume all of the above to be in place. They would check for problems that might occur, when large numbers of users select the same or invalide dates, or access the same form simultaneously. - This quick example should give you an idea on how to think about testing your code. Each type of test has its own reason for being, and requires your attention. A good performance test cannot substitue unit or integration tests. If you feel that your tests are not working well, because they frequently fail to show problems in your code, and when they do they don't make identifying the source of the problem easier, chances are that you are trying to test something with one type of test, that would be better suited to another type. + Selection Example + To illustrate this, lets take a theoretical example: imagine your code includes an online form where users submit a date that needs to be stored in the database. For + the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other means.Provided that you are using eXist-db, we assume that the date + will be stored in some kind of xml file. + + a basic form example + a simple form: + + + + + that will create something like this: + + + By using a schema for validating this xml file, you can ensure the correct datatype xs:date of the provided input, and prevent users + from storing something in the database that is not a date. + + using native types + + + To check that your local:check-input function is working as expected, you can define a few unit test Typically, such a test + would include some corner cases like BCE dates, leap years, or dates in foreign date formats, as well as a basic test date that should simply store in the db. + + testing corner cases + + For in-depth examples of unit testing in xQuery please see the examples in the xQsuite article + + Integration testing is most effective when it can rely on existing unit tests and focus on how a user typically interacts with the UI components. + Does the browser display the input form correctly at different resolutions, and the form be selected with a mouse, or on touch screens. + + browser testing + + + + + + + + + Lastly, performance and stress tests would simply assume all of the above to be in place. They would check for problems that might occur, when + large numbers of users select the same or invalide dates, or access the same form simultaneously. + This quick example should give you an idea on how to think about testing your code. Each type of test has its own reason for being, and requires your attention. A good + performance test cannot substitue unit or integration tests. If you feel that your tests are not working well, because they frequently fail to show problems in your code, + and when they do they don't make identifying the source of the problem easier, chances are that you are trying to test something with one type of test, that would be better + suited to another type.
Test Coverage - Ideally, we would always achieve full test coverage for our code. So that every meaningful unit of code has a corresponding set of tests. While other programming languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. The section on integration testing contains the definition of a minimal smoke test that the eXist-db community is using internally. + Ideally, we would always achieve full test coverage for our code. So that every meaningful unit of code has a corresponding set of tests. While other programming + languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. The section on integration testing contains the definition of a minimal smoke test that the eXist-db community is using + internally. - + \ No newline at end of file diff --git a/src/main/xar-resources/data/validation/validation.xml b/src/main/xar-resources/data/validation/validation.xml index 49a1dfde..27130249 100644 --- a/src/main/xar-resources/data/validation/validation.xml +++ b/src/main/xar-resources/data/validation/validation.xml @@ -1,20 +1,42 @@ -
- - XML Validation - 2Q18 - - application-development - - - - - - eXist-db supports validation of XML documents. - There are two ways to validate documents: + schematypens="http://purl.oclc.org/dsdl/schematron"?>
+ + XML Validation + 2Q18 + + application-development + testing + + + + + + eXist-db supports validation of XML documents. + There are two ways to validate documents: + + + + is executed automatically when documents are + inserted into the database. + + + + is performed through the use of provided XQuery + extension functions. + + + + + + + + Implicit validation + + Implicit validation is executed automatically when documents are inserted into the + database. + To enable implicit validation, change eXist-db configuration by editing + conf.xml. The following two items must be configured: is executed automatically when @@ -323,177 +345,198 @@ Schematron 1.5 (.sch) - The jing() and jing-report() functions accept the - following parameters: - - - $instance - - The XML instance document as document node, element node, - xs:anyURI, or as Java file object. - - - - $grammar - - The grammar file can be referenced either as document node, element - node, xs:anyURI, binary document, or as Java file - object. - - - - - You can use util:binary-doc() to pass .rnc files as - binary document - - - - - - - - Validation report + + + + - A validation report contains the following for a valid document: + - + + Jing - For an invalid document the following is returned: - - When something goes wrong you might the following: - - - - - - - Grammar management - - The Xerces XML parser compiles all grammar files upon first use. For efficiency - reasons these compiled grammars are cached, resulting in a significant increase in - validation processing performance. However, sometimes it may be desirable to manually - clear this cache. For this purpose two grammar management functions are provided: - - - clear-grammar-cache() - - Removes all cached grammar and returns the number of removed - grammar - - - - pre-parse-grammar(xs:anyURI) - - Parses the referenced grammar and returns the namespace of the parsed - XSD. - - - - show-grammar-cache() - - Returns an XML report about all cached grammars. For instance: - - The BaseSystemId element typically does - not provide useful information. - - - - - + The Jing validation functions are based on James Clark's Jing library. eXist uses the maintained version that is available via Google Code. + The library relies on the com.thaiopensource.validate.ValidationDriver which supports a + wide range of grammar types: + + + XML schema (.xsd) + + + Namespace-based Validation Dispatching Language (.nvdl) + + + RelaxNG (.rng and .rnc) + + + Schematron 1.5 (.sch) + + + The jing() and jing-report() functions accept the following + parameters: + + + + $instance + + + The XML instance document as document node, element node, + xs:anyURI, or as Java file object. + + + + + $grammar + + + The grammar file can be referenced either as document node, element node, xs:anyURI, binary document, or as Java file object. + + + + You can use util:binary-doc() to pass .rnc files as binary document + + + + + + + Validation report + + A validation report contains the following for a valid document: + + + + For an invalid document the following is returned: + + When something goes wrong you might the following: + + + + + + + Grammar management + + The Xerces XML parser compiles all grammar files upon first use. For efficiency reasons + these compiled grammars are cached, resulting in a significant increase in validation + processing performance. However, sometimes it may be desirable to manually clear this cache. + For this purpose two grammar management functions are provided: + + + + clear-grammar-cache() + + + Removes all cached grammar and returns the number of removed grammar + + + + + pre-parse-grammar(xs:anyURI) + + + Parses the referenced grammar and returns the namespace of the parsed XSD. + + + + + show-grammar-cache() + + + Returns an XML report about all cached grammars. For instance: + + The BaseSystemId element typically does not provide + useful information. + + + - + - - Interactive Client + - The interactive shell mode of the Java Admin - Client provides a simple validate command that accepts the - similar explicit validation arguments. - + + Interactive Client - + The interactive shell mode of the Java Admin Client provides a simple + validate command that accepts the similar explicit validation + arguments. + - - Special notes + - - - To avoid potential deadlocking it is considered good practice to store XML - instance documents and grammar documents in separate collections. - - - Tomcat has an long standing bug which makes it impossible to register a custom - protocol handler (object URLStreamHandler) to the JVM. The alternative is to - register the object by setting the system property - java.protocol.handler.pkgs but this fails as well. - As a result, the validation features are only partly useable in Tomcat. There - are two alternatives: (1) switch to a recent version of Jetty, or (2) use - absolute URLs pointing the REST interface, e.g. - http://localhost:8080/exist/rest/db/mycollection/schema.xsd. - - - eXist relies heavily on features provided by the Xerces XML parser. Out of the - box the eXist izPack installer provides all required .jar files. - However, when eXist is installed in for instance Tomcat, the required parser - libraries need to be copied manually from the eXist lib/endorsed - directory into the server endorsed directory. - Required endorsed files: resolver-*.jar xalan-*.jar serializer-*.jar - xercesImpl-*.jar - + + Special notes - - The explicit validation is performed by Xerces (XML schema, DTD) and by oNVDL: oXygen XML NVDL - implementation based on Jing (XSD, RelaxNG, Schematron and Namespace-based - Validation Dispatching Language). - - - + + + To avoid potential deadlocking it is considered good practice to store XML instance + documents and grammar documents in separate collections. + + + Tomcat has an long standing bug which makes it impossible to register a custom + protocol handler (object URLStreamHandler) to the JVM. The alternative is to register + the object by setting the system property java.protocol.handler.pkgs but this + fails as well. + As a result, the validation features are only partly useable in Tomcat. There are two + alternatives: (1) switch to a recent version of Jetty, or (2) use absolute URLs pointing + the REST interface, e.g. + http://localhost:8080/exist/rest/db/mycollection/schema.xsd. + + + eXist relies heavily on features provided by the Xerces XML parser. Out of the box the + eXist izPack installer provides all required .jar files. However, when eXist + is installed in for instance Tomcat, the required parser libraries need to be copied + manually from the eXist lib/endorsed directory into the server endorsed directory. + Required endorsed files: resolver-*.jar xalan-*.jar serializer-*.jar + xercesImpl-*.jar + + + + + The explicit validation is performed by Xerces (XML schema, DTD) and by oNVDL: oXygen + XML NVDL implementation based on Jing (XSD, RelaxNG, Schematron and Namespace-based + Validation Dispatching Language). + + + - + - - References + + References - - - Apache xml-commons - resolver - - - OASIS XML Catalog - Specification V1.1 - - - Xerces caching - grammars. - - - jing-trang Schema validation and conversion based on RELAX NG - - - NVDL (Namespace-based Validation Dispatching Language) - - - Schematron - - - Relax NG - - - + + + Apache xml-commons resolver + + + + OASIS XML Catalog + Specification V1.1 + + + Xerces caching grammars. + + + + jing-trang + Schema validation and conversion based on RELAX NG + + + + NVDL (Namespace-based Validation Dispatching Language) + + + + Schematron + + + + + Relax NG + + + +
From 2012736f5cd9ff7825c617dd4b66bac571789e51 Mon Sep 17 00:00:00 2001 From: duncdrum Date: Mon, 10 Dec 2018 16:30:21 +0100 Subject: [PATCH 09/11] fix accidental cdata excaping --- .../data/author-reference/author-reference.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/xar-resources/data/author-reference/author-reference.xml b/src/main/xar-resources/data/author-reference/author-reference.xml index f62baf2b..f44999c7 100644 --- a/src/main/xar-resources/data/author-reference/author-reference.xml +++ b/src/main/xar-resources/data/author-reference/author-reference.xml @@ -969,8 +969,8 @@ but does not because its too simple) Tags A tag element surrounds its content with < and > and formats it - like code. Meant to make life easier: is the - shorter version of . + like code. Meant to make life easier: xxx]]> is the + shorter version of <xxx>]]>. @@ -1010,7 +1010,7 @@ but does not because its too simple) Links to external sources are done with the link element. Place the target's full URI in the xlink:href attribute. For instance, - + ]]> links to the eXist home page. To open the link on a new page, add condition="_blank". @@ -1022,7 +1022,7 @@ but does not because its too simple) To create a link to another article in this documentation set, also use the link element. However, use the target's document name (without the .xml extension) as the link address. For instance, - links to the documentation home page. + ]]> links to the documentation home page. From f58e2f99d0fb5a229d70425d8f65c1c26ee4fffb Mon Sep 17 00:00:00 2001 From: Duncan Paterson Date: Sun, 30 Dec 2018 13:49:11 +0100 Subject: [PATCH 10/11] chore(): typos --- .../integration-testing.xml | 70 +++++++------------ .../xar-resources/data/testing/testing.xml | 58 ++++++++------- 2 files changed, 53 insertions(+), 75 deletions(-) diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml index 4331efa9..0b6306e2 100644 --- a/src/main/xar-resources/data/integration-testing/integration-testing.xml +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -28,85 +28,65 @@ The services typically require a small configuration file, so you can build your code on a clean virtual machine, without the risk of local files interfering. For travis the required name of such a file is .travis.yml and in its simplest form it would look like this: - For the correct way to create such a configuration file for other CI providers please consult their documantation. In all cases, since exist-db is written in Java, your + For the correct way to create such a configuration file for other CI providers please consult their documentation. In all cases, since exist-db is written in Java, your app should be build on a system that comes with the minimal Java version required by eXist-db. Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses - ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. + ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. - If you have multiple build targets for production and development, you should make sure that each build targets is actually run by the ci service. + If you have multiple build targets for production and development, you should make sure that each build target is actually run by the ci service. You can extend this basic template according to your needs, e.g.: Apps written in java might want to run the build step on multiple java versions (by adding - - openjdk11); or to test building on on different operation systems. You should consult your ci services documentation for the list of available configuration - options. + openjdk11); or to test building on on different operation systems. You should consult your ci services documentation for the list of available configuration options. Add a running eXist-db instance and install your app - The next step is to take the result of your automated build process and install it in a running eXist-db instance. We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of - getting an instance up and running. Let's extend the file create in the previous section. + The next step takes the result of your automated build process and installs it in a running eXist-db instance (external tools might want to talk to a running eXist-db instance in some other way). We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of + getting an instance up and running. Let's extend the file created in the previous section. The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use - (e.g. :4.4.0), if you want to ensure backwards compatibility. But these two tags will ensure that your code is tested against both the most current - stable release, and upcoming changes. + (e.g. :4.4.0) to ensure backwards compatibility. These two tags will ensure that your code is tested against both the most current stable release, and upcoming changes ahead of time. - To actually install the app we have simply copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared + + To actually install the app, we copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. - So far we have simply automated the basic steps of building and installing your app. This already catches some basic and particularly severe erros, but it is not a - very realistic test of what users actually experience when they install your application. Before we can refine the way we imitate their process properly, we first need to - add the means of running actual tests within our ci environment. + So far, we have simply automated the basic steps of building and installing your app. This already catches some basic and particularly severe erros, but it is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we simulate usage patterns, we first need to add the means of running actual tests within our ci environment. Integrating unit tests into ci - Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests - for the functional components of your code. By running your unit tests inside your ci server, these become immediately visible to potential contributors, and you have the - advantage of immediate feedback on every code change. + Integration testing and unit testing go hand in hand, as one without the other does not work well. If you are writing an application, you already should have unit tests for the functional components of your code. By running your unit tests inside your ci server, these become immediately visible to potential contributors, and you have the advantage of immediate feedback on every code change. - Tests that are invisible to other contributers because they are hidden away, and have only every been run on the original authors system, are of very limited - use. + Tests that are invisible to other contributers because they are hidden away, and have only ever been run on the original author's system, are of very limited use. As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite for xQuery. To run your tests, we are going to leverage the support for running unit tests of our build system (e.g.: npm test, mvm test, …): - Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find - your tests, if you make the test command explicit. + Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find your tests, if you make the test command explicit. - If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist is already running in the background t our app - installed, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. - How to write good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you - are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on integration tests alone, and your - unit tests should be integrated into your ci system. + If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist with our app is already running in the background, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. + How to write good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on either unit or integration tests alone, and both should be integrated into your ci pipeline. Testing your app in a controlled context - As we have seen in the previous section unit tests are an important pre-requiste for effective integration testing. The difference between the two is that unit tests - excell at testing individual functions, and are quick to write and perform. Yet, they cannot capture the complex interaction between your code and that of the larger + Unlike unit tests which excell at testing individual functions, and are quick to write and perform. Interation tests focus on the complex interaction between your code and that of the larger environment. Just search for 2 unit tests 0 integration tests to see what I mean. - For eXist-db applications, integration test will typically involve a browser, as we are trying to mimick the way a user interacts with our application from their system. + For eXist-db applications, integration tests will typically involve a browser, as we are trying to mimick the way a user interacts with our application from their system. - While our examples focus on browser testing, you can see shell based integration tests at the test-suite for building the docker images we used earlier. + While our examples focus on browser testing, you can see shell based integration tests at the testsuite for building the docker images we used earlier. Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to - you, whichever you choose it should be clearely documented so your contributors know how to adjust test cases for new features and how to maintain your tests. We focus on - cypress, as it does not require any additional steps for configuring a browser first. + you, whichever you choose it should be clearely documented so your contributors know how to adjust test cases for new features and how to maintain your tests. We focus on cypress, as it does not require any additional steps for configuring a browser first. - If you need to perform cross-browser testing you can take a look at services such as sauce - labs + If you need to perform cross-browser testing you can take a look at services such as sauce-labs You can simply execute the cypress test command inside your ci test script after the unit test command we added earlier. - With cypress you write your tests in the same fashion as you would with mocha unit tests, however, you now address the rendered document inside a browser instead of - individual js functions. + With cypress you write your tests in the same fashion as you would with mocha unit tests, however, you now address the rendered document inside a browser instead of individual js functions. - The above example opens a page (the dashboard) in the browser, logs in, and close the window it just opened. You can do many more things, but these kind of simple - examples should give you a good starting point for creating your first integration test. If there are any console errors or problems with rendering content cypress will - create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. - Now that we have build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have - achieved a basic smoke test. We switched it on and there was no smoke. Proper testing can now commence. Obviously you might want to visit multiple pages, or compare - screenshots to avoid visual regressions, or compare images in multiple browsers, or … . - All of which are excellent ideas, and with these basics in place it might no longer seem so daunting a task. Depending on your own specific requirments I would - encourage your to browse other eXist-db repositories in addition to the documentation of your CI and test-suite vendors. Chances are someone already has created a solid - test, similar to what you want to try. + The above example opens a page (the dashboard) in the browser, logs in, and close the window it just opened. You can do many more things, but these examples are meant to provide a good starting point for creating your first integration test. If there are any console errors or problems with rendering content cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. + Now that we have build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. We switched it on and there was no smoke. Proper testing can now commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers, or … . + All of which are excellent ideas, and with these basics in place it hopefully no longer seem so daunting a task. Depending on your own specific requirments I would encourage your to browse other eXist-db repositories in addition to the documentation of your CI and testsuite vendors. Chances are someone already has created a solid test, similar to your needs. -
\ No newline at end of file + diff --git a/src/main/xar-resources/data/testing/testing.xml b/src/main/xar-resources/data/testing/testing.xml index 8576f0b4..b659e1fa 100644 --- a/src/main/xar-resources/data/testing/testing.xml +++ b/src/main/xar-resources/data/testing/testing.xml @@ -13,63 +13,62 @@ In this article we discuss the types of testing available in relation to eXist-db and its applications. It assumes readers have a basic understanding of XML and XQuery. - + Overview - Different kinds of tests play an essential role in maintain a high quality code base both for eXist-db itself, and for applications that interact with eXist-db either as - deployed packages from the inside, or in the forms of external tools. + Different kinds of tests play an essential role in maintaining a high quality code base both for eXist-db itself, and for applications that interact with eXist-db. - The test framework of eXist-db and its apps is under continuous development, with frequent changes to the softwares and services in use. Covering them all is not - feasible in this article. So we recommend that you check our Github repositories and search for a - system that is similar to yours, for further insipiration. + The test framework of eXist-db and its apps is under continuous development, with frequent changes to the software and services in use. Covering them all is not + feasible in this article. We recommend that you check the official Github repositories and search for + systems that are similar to yours for further insipiration. - While the terminology might vary slighlty between different sources dealing with testing, the principle categories apply to all irrespective of terminology. + While the terminology varies between different sources dealing with software testing, the following categories are widely acknowledged to apply irrespective of terminological differences. Validation: - Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should consider how you can leverary - these features native features first. + Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should first consider how your code can leverage + these native features via strong typing and schema based validation. Unit testing: - These tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery named xQsuite. It is prominenlty - used in our bug reports and source-code repo. Typicall applications will need to run multiple unit test tools to test, e.g. java, javascript, and Xquery code. + These tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery named xQsuite. It is prominenlty + used in our bug reports and source-code repo. Typicall applications will need to run multiple unit test tools to test, e.g. java, javascript, and Xquery code. Integration testing: - Look at your programm as a whole, similar to how a user would interact with it, by simulating user input and running you programm not in isolation but in + Here we look at your programm as a whole, similar to how a user would interact with it, by simulating user input and running you programm not in isolation but in concert with different applications. - (WIP) Performance and Stress testing: Performance testing ensures that your code continous to function under heavy load, or with very little + (WIP) Performance and Stress testing: Performance testing ensures that your code continous to function under heavy load, or with very little resources. Stress tests go one step further by purposfully crashing your application to ensure that it recovers gracefully. Practically speaking, the difference between the two is fluid. - There will never be a one size fits all solution to take care of all your testing needs. Writing good test takes time an planning. You can find out more about available - options and their use cases in the articles linked above. The remainder of this article will discuss some general considerations for how to design your test-suite, without - referencing a specifc implementation. + When running these different tests in concert, we usually speak of end-to-end testing (e2e). There will never be a one size fits all solution to take care of all your testing needs. Writing good testsuites takes time an planning. You can find out more about available + options and their use cases in the articles linked above. The remainder of this article will discuss some general considerations for how to design your testsuite, without + referencing a specifc implementation. The listings use pseudo-code to focus on relevant lines. Pseudo-code is not intended to be executable, so it won't run if you copy-paste it into e.g. eXide. For working code, please consult the articles links throughout. - + Picking a Type - Generally speaking, you should follow the sequence provided above. Whatever, can be tested as part of your validation tests, is best tested there. When validation testing - isn't a good fit, go for unit tests, followed by integration and lastly performance tests. The reasons for this are twofold. On the one hand, validation tests tend to be - faster than unit tests, which in turn are slower then integration tests and performance tests. on the other hand, each type tends to be more easy to configure, with a higher + Generally speaking, you should follow the sequence provided above. Whatever can be tested as part of your validation tests, is best tested there. When validation testing + isn't a good fit, go for unit tests, followed by integration and lastly performance tests. The reasons for this are twofold: On the one hand, validation tests tend to be + faster than unit tests, which in turn are slower then integration tests and performance tests. On the other hand, each type tends to be more easy to configure, with a higher chance of providing you with the information that you need when a test fails. - + Selection Example To illustrate this, lets take a theoretical example: imagine your code includes an online form where users submit a date that needs to be stored in the database. For - the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other means.Provided that you are using eXist-db, we assume that the date + the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other form. Provided that you are using eXist-db, we assume that the date will be stored in some kind of xml file. - a basic form example + A basic form example a simple form: @@ -81,7 +80,7 @@ By using a schema for validating this xml file, you can ensure the correct datatype xs:date of the provided input, and prevent users from storing something in the database that is not a date. - using native types + Using native types To check that your local:check-input function is working as expected, you can define a few unit test Typically, such a test @@ -92,7 +91,7 @@ For in-depth examples of unit testing in xQuery please see the examples in the xQsuite article Integration testing is most effective when it can rely on existing unit tests and focus on how a user typically interacts with the UI components. - Does the browser display the input form correctly at different resolutions, and the form be selected with a mouse, or on touch screens. + Does the browser display the input form correctly at different resolutions, can the form be selected with a mouse, or on touch screens, … ? browser testing @@ -108,13 +107,12 @@ This quick example should give you an idea on how to think about testing your code. Each type of test has its own reason for being, and requires your attention. A good performance test cannot substitue unit or integration tests. If you feel that your tests are not working well, because they frequently fail to show problems in your code, and when they do they don't make identifying the source of the problem easier, chances are that you are trying to test something with one type of test, that would be better - suited to another type. + suited for another type. - + Test Coverage Ideally, we would always achieve full test coverage for our code. So that every meaningful unit of code has a corresponding set of tests. While other programming - languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. The section on integration testing contains the definition of a minimal smoke test that the eXist-db community is using - internally. + languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. How much testing is necessary for you to ship with confidence, rests on each developer. For apps published under the exist-db namespace, we have outlined a set of minimum requirementes (more is obviously desirable) which are featured in the section on integration testing. - \ No newline at end of file + From 1152977779b1e9f720ee2727192d30ef1620c741 Mon Sep 17 00:00:00 2001 From: Duncan Paterson Date: Wed, 2 Jan 2019 13:38:54 +0100 Subject: [PATCH 11/11] fix(typos): review comments --- .../data/documentation/documentation.xml | 4 +- .../integration-testing.xml | 47 +++++++++---------- .../xar-resources/data/testing/testing.xml | 28 +++++------ 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/main/xar-resources/data/documentation/documentation.xml b/src/main/xar-resources/data/documentation/documentation.xml index fdace17a..6899c77e 100644 --- a/src/main/xar-resources/data/documentation/documentation.xml +++ b/src/main/xar-resources/data/documentation/documentation.xml @@ -171,7 +171,7 @@ XQsuite - This is an annotation based framework that allows you to add tests to XQuery + This is an annotation-based framework that allows you to add tests to XQuery functions and execute them. @@ -292,7 +292,7 @@ XQsuite - This is an annotation based framework that allows you to add unit tests to XQuery + This is an annotation-based framework that allows you to add unit tests to XQuery functions and execute them. diff --git a/src/main/xar-resources/data/integration-testing/integration-testing.xml b/src/main/xar-resources/data/integration-testing/integration-testing.xml index 0b6306e2..54f1f2a6 100644 --- a/src/main/xar-resources/data/integration-testing/integration-testing.xml +++ b/src/main/xar-resources/data/integration-testing/integration-testing.xml @@ -12,45 +12,44 @@ This article discusses intergration testing of eXist-db applications. It also covers recommendations for the configuration of automated test environments, and explains the minimum testing requirements for apps that are published under the eXist-db namespace. - It assumes that you are familiar with the XQsuite framework for unit-testing, and the general strategies for designing tests in eXist-db. + It assumes that you are familiar with the XQSuite framework for unit-testing, and the general strategies for designing tests in eXist-db. Introduction Creating an automated mininal testsuite is possible with relatively little effort. It pays to take the need for testing into account when you start developing your - application. This enables others to extend your program with new features, by knowning that these don't break existing functions. It also allows test only contributions, to - help you to gradually advance your test coverage. The following section will walk you trough the three main aspects of such a minimal test setup. + application. This enables others to extend your program with new features, by knowning that these don't break existing functions. It also allows test-only contributions, helping you to gradually advance your test coverage. The following section will walk you trough the three main aspects of such a minimal test setup. Building on a clean system Before you start designing tests, you should start to automate your build process. This ensures that things don't only work on your system, and it can catch some common errors. The examples in this article will use travis-ci as it is the most popular continual integration (ci) - provider in the exist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . + provider in the eXist-db organization on Github, other popuar choices include appveyor, jenkins, circl-ci, … . The services typically require a small configuration file, so you can build your code on a clean virtual machine, without the risk of local files interfering. For travis the required name of such a file is .travis.yml and in its simplest form it would look like this: - For the correct way to create such a configuration file for other CI providers please consult their documentation. In all cases, since exist-db is written in Java, your + For the correct way to create such a configuration file for other ci providers please consult their documentation. In all cases, since eXist-db is written in Java, your app should be build on a system that comes with the minimal Java version required by eXist-db. Most providers will automatically detect your build tool and run the required command even if you don't specify it. In the above example, our app to be tested uses ant as a build tool, change ant to suite your needs, e.g. maven clean package, npm install, etc. If you have multiple build targets for production and development, you should make sure that each build target is actually run by the ci service. - You can extend this basic template according to your needs, e.g.: Apps written in java might want to run the build step on multiple java versions (by adding - - openjdk11); or to test building on on different operation systems. You should consult your ci services documentation for the list of available configuration options. + You can extend this basic template according to your needs, e.g.: apps written in Java might want to run the build step on multiple Java versions (by adding - + openjdk11); or to test building on different operation systems. You should consult your ci services documentation for the list of available configuration options. Add a running eXist-db instance and install your app - The next step takes the result of your automated build process and installs it in a running eXist-db instance (external tools might want to talk to a running eXist-db instance in some other way). We are going to use exist's docker images for this, since it is supported by all CI providers, and it tends to be the fastest means of + The next step takes the result of your automated build process and installs it in a running eXist-db instance (external tools might want to talk to a running eXist-db instance in some other way). We are going to use exist's docker images for this, since it is supported by all ci providers, and it tends to be the quickest way of getting an instance up and running. Let's extend the file created in the previous section. The :release and :latest tags are specifically designed for use in ci environments. You can also specify exact version to use (e.g. :4.4.0) to ensure backwards compatibility. These two tags will ensure that your code is tested against both the most current stable release, and upcoming changes ahead of time. - To actually install the app, we copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared - for your app, will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. + To actually install the app, we copied it into exist's autodeploy folder, which will make sure that any dependencies that you declared + for your app will also be installed. If you require more complex installation steps, you can find more examples and links in the docker-existdb readme. - So far, we have simply automated the basic steps of building and installing your app. This already catches some basic and particularly severe erros, but it is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we simulate usage patterns, we first need to add the means of running actual tests within our ci environment. + So far, we have simply automated the basic steps of building and installing your app. This already catches some basic and particularly severe errors, but it is not a very realistic test of what users actually experience when they install your application. Before we can refine the way we simulate usage patterns, we first need to add the means of running actual tests within our ci environment. Integrating unit tests into ci @@ -58,35 +57,35 @@ Tests that are invisible to other contributers because they are hidden away, and have only ever been run on the original author's system, are of very limited use. - As with the previous options there are different test runners to do this work for you, such as junit for java, mocha for javascript, xQsuite for xQuery. To run your tests, we are going to leverage the support for running unit tests of our build system (e.g.: npm test, mvm test, + As with the previous options there are different test runners to do this work for you, such as junit for Java, Mocha for JavaScript, XQSuite for XQuery. To run your tests, we are going to leverage the support for running unit tests of our build system (e.g.: npm test, mvm test, …): Just as with the building example, many providers will execute this command automatically. But even in a simple case it helps others understand your code, and to find your tests, if you make the test command explicit. - If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist with our app is already running in the background, it is also possible to run your xqsuite unit tests. You can see how this is configured, for apps using our the yeoman templates. - How to write good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test, you should however, ask yourself if what you are trying to achieve, might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on either unit or integration tests alone, and both should be integrated into your ci pipeline. + If you use more then one test runner, you can simply add additional test commands to the script parameter. Since exist with our app is already running in the background, it is also possible to run your XQSuite unit tests. You can see how this is configured, for apps using our the yeoman templates. + How to write good unit tests is beyond the scope of this article. Whenever you are struggling with your integration test you should, however, ask yourself if what you are trying to achieve might not be better served by creating unit tests. Whichever solution works best for you, you should not rely on either unit or integration tests alone, and both should be integrated into your ci pipeline. Testing your app in a controlled context - Unlike unit tests which excell at testing individual functions, and are quick to write and perform. Interation tests focus on the complex interaction between your code and that of the larger - environment. Just search for 2 unit tests 0 - integration tests to see what I mean. + Unlike unit tests which excel at testing individual functions, and are quick to write and perform, interation tests focus on the complex interaction between your code and that of the larger + environment. Just search for 2 unit tests 0 + integration tests to see what we mean. For eXist-db applications, integration tests will typically involve a browser, as we are trying to mimick the way a user interacts with our application from their system. While our examples focus on browser testing, you can see shell based integration tests at the testsuite for building the docker images we used earlier. - Common tools for browser testing include cypress, Selenium, and webdriver. As before the choice is up to - you, whichever you choose it should be clearely documented so your contributors know how to adjust test cases for new features and how to maintain your tests. We focus on cypress, as it does not require any additional steps for configuring a browser first. + Common tools for browser testing include Cypress, Selenium, and webdriver. As before the choice is up to + you, whichever you choose it should be clearely documented so your contributors know how to adjust test cases for new features and how to maintain your tests. We focus on Cypress, as it does not require any additional steps for configuring a browser first. If you need to perform cross-browser testing you can take a look at services such as sauce-labs - You can simply execute the cypress test command inside your ci test script after the unit test command we added earlier. + You can simply execute the Cypress test command inside your ci test script after the unit test command we added earlier. - With cypress you write your tests in the same fashion as you would with mocha unit tests, however, you now address the rendered document inside a browser instead of individual js functions. + With Cypress you write your tests in the same fashion as you would with Mocha unit tests; however, you now address the rendered document inside a browser instead of individual js functions. - The above example opens a page (the dashboard) in the browser, logs in, and close the window it just opened. You can do many more things, but these examples are meant to provide a good starting point for creating your first integration test. If there are any console errors or problems with rendering content cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the cypress documentation. - Now that we have build our app on a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. We switched it on and there was no smoke. Proper testing can now commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers, or … . - All of which are excellent ideas, and with these basics in place it hopefully no longer seem so daunting a task. Depending on your own specific requirments I would encourage your to browse other eXist-db repositories in addition to the documentation of your CI and testsuite vendors. Chances are someone already has created a solid test, similar to your needs. + The above example opens a page (the dashboard) in the browser, logs in, and closes the window it just opened. You can do many more things, but these examples are meant to provide a good starting point for creating your first integration test. If there are any console errors or problems with rendering content Cypress will create an error message and your tests will fail. To check the syntax of these commands, and to see many more examples please visit the Cypress documentation. + Now that we have built our app in a clean system, executed its unit tests, and opened the start page of our freshly installed app in clean eXist-db instance, we have achieved a basic smoke test. We switched it on and there was no smoke. Proper testing can now commence. Obviously you might want to visit multiple pages, or compare screenshots to avoid visual regressions, or compare images in multiple browsers, or … . + All of which are excellent ideas, and with these basics in place it hopefully no longer seem so daunting a task. Depending on your own specific requirments we would encourage your to browse other eXist-db repositories in addition to the documentation of your ci and testsuite vendors. Chances are someone already has created a solid test, similar to your needs. diff --git a/src/main/xar-resources/data/testing/testing.xml b/src/main/xar-resources/data/testing/testing.xml index b659e1fa..17f52a21 100644 --- a/src/main/xar-resources/data/testing/testing.xml +++ b/src/main/xar-resources/data/testing/testing.xml @@ -27,31 +27,31 @@ Validation: - Xml comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should first consider how your code can leverage - these native features via strong typing and schema based validation. + XML comes with different means of validating and thus testing your data strucutures. When implementing a testsuite, you should first consider how your code can leverage + these native features via strong typing and schema-based validation. Unit testing: - These tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery named xQsuite. It is prominenlty - used in our bug reports and source-code repo. Typicall applications will need to run multiple unit test tools to test, e.g. java, javascript, and Xquery code. + These tests typically operate at the level of individual functions. eXist-db has its own unit testing framework for Xquery named XQSuite. It is prominently + used in our bug reports and source-code repo. Most applications will need to run multiple unit test tools to test, e.g. Java, JavaScript, and Xquery code. Integration testing: - Here we look at your programm as a whole, similar to how a user would interact with it, by simulating user input and running you programm not in isolation but in + Here we look at your programm as a whole, similar to how a user would interact with it, by simulating user input and running you program not in isolation but in concert with different applications. - (WIP) Performance and Stress testing: Performance testing ensures that your code continous to function under heavy load, or with very little + (WIP) Performance and Stress testing: Performance testing ensures that your code keeps running under heavy load, or with very little resources. Stress tests go one step further by purposfully crashing your application to ensure that it recovers gracefully. Practically speaking, the difference between the two is fluid. - When running these different tests in concert, we usually speak of end-to-end testing (e2e). There will never be a one size fits all solution to take care of all your testing needs. Writing good testsuites takes time an planning. You can find out more about available + When running these different tests in concert, we usually speak of end-to-end testing (e2e). There will never be a one-size-fits-all solution to take care of all your testing needs. Writing good testsuites takes time and planning. You can find out more about available options and their use cases in the articles linked above. The remainder of this article will discuss some general considerations for how to design your testsuite, without referencing a specifc implementation. The listings use pseudo-code to focus on relevant lines. Pseudo-code is not intended to be executable, so it won't run if you copy-paste it into e.g. eXide. For working code, please consult the articles links throughout. @@ -59,12 +59,12 @@ Picking a Type Generally speaking, you should follow the sequence provided above. Whatever can be tested as part of your validation tests, is best tested there. When validation testing - isn't a good fit, go for unit tests, followed by integration and lastly performance tests. The reasons for this are twofold: On the one hand, validation tests tend to be - faster than unit tests, which in turn are slower then integration tests and performance tests. On the other hand, each type tends to be more easy to configure, with a higher + isn't a good fit, go for unit tests, followed by integration and lastly performance tests. The reasons for this are twofold: on the one hand, validation tests tend to be + faster than unit tests, which in turn are slower then integration tests and performance tests. On the other hand, each type tends to be easier to configure, with a higher chance of providing you with the information that you need when a test fails. Selection Example - To illustrate this, lets take a theoretical example: imagine your code includes an online form where users submit a date that needs to be stored in the database. For + To illustrate this, let's take a theoretical example: imagine your code includes an online form where users submit a date that needs to be stored in the database. For the purpuse of this example it doesn't matter if this is text-input form, a calendar selector, or other form. Provided that you are using eXist-db, we assume that the date will be stored in some kind of xml file. @@ -83,10 +83,10 @@ Using native types - To check that your local:check-input function is working as expected, you can define a few unit test Typically, such a test - would include some corner cases like BCE dates, leap years, or dates in foreign date formats, as well as a basic test date that should simply store in the db. + To check that your local:check-input function is working as expected, you can define a few unit tests. Typically, such tests + would include corner cases like BCE dates, leap years, or dates in foreign date formats, as well as a basic test date that should simply store in the db. - testing corner cases + Testing Corner Cases For in-depth examples of unit testing in xQuery please see the examples in the xQsuite article @@ -113,6 +113,6 @@ Test Coverage Ideally, we would always achieve full test coverage for our code. So that every meaningful unit of code has a corresponding set of tests. While other programming - languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. How much testing is necessary for you to ship with confidence, rests on each developer. For apps published under the exist-db namespace, we have outlined a set of minimum requirementes (more is obviously desirable) which are featured in the section on integration testing. + languages offer automated means of analysing your code to indentify areas that aren't tested, such tools are unfortunately not very common for Xquery. How much testing is necessary for you to ship with confidence, rests on each developer. For apps published under the eXist-db namespace, we have outlined a set of minimum requirementes (more is obviously desirable) which are featured in the section on integration testing.