]> source.dussan.org Git - gitblit.git/commitdiff
Merged selenium tests from akquinet (pull request #65)
authorJames Moger <james.moger@gitblit.com>
Wed, 23 Jan 2013 13:30:28 +0000 (08:30 -0500)
committerJames Moger <james.moger@gitblit.com>
Wed, 23 Jan 2013 13:30:28 +0000 (08:30 -0500)
15 files changed:
.classpath
src/com/gitblit/build/Build.java
test-ui-gitblit.properties [new file with mode: 0644]
test-ui-users.conf [new file with mode: 0644]
tests/de/akquinet/devops/GitblitRunnable.java [new file with mode: 0644]
tests/de/akquinet/devops/LaunchWithUITestConfig.java [new file with mode: 0644]
tests/de/akquinet/devops/ManualUITestLaunch.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/TestUISuite.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/cases/UI_MultiAdminSupportTest.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/generic/AbstractUITest.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/view/Exp.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/view/GitblitDashboardView.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/view/GitblitPageView.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/view/RepoEditView.java [new file with mode: 0644]
tests/de/akquinet/devops/test/ui/view/RepoListView.java [new file with mode: 0644]

index e40223d2aee366ef7b8ebe44bc8366bbdc5a6d6e..365b6d44e333c6d79720dc6410e624db3e0af37c 100644 (file)
        <classpathentry kind="lib" path="ext/xz-1.0.jar" sourcepath="ext/src/xz-1.0-sources.jar" />
        <classpathentry kind="lib" path="ext/junit-4.10.jar" sourcepath="ext/src/junit-4.10-sources.jar" />
        <classpathentry kind="lib" path="ext/hamcrest-core-1.1.jar" />
+       <classpathentry kind="lib" path="ext/seleniumhq/selenium-java-2.28.0.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/selenium-api-2.28.0.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/selenium-remote-driver-2.28.0.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/selenium-support-2.28.0.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/guava-12.0.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/json-20080701.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/commons-exec-1.1.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/httpcore-4.2.1.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/httpmime-4.2.1.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/httpclient-4.2.1.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/commons-logging-1.1.1.jar"/>
+       <classpathentry kind="lib" path="ext/seleniumhq/selenium-firefox-driver-2.28.0.jar"/>
        <classpathentry kind="output" path="bin/classes" />
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" />
 </classpath>
\ No newline at end of file
index ecc072af55f3ab8f6bb39f05c814053b4c114241..21c16298f41e92c8381c1bab97361d5f602cf6ce 100644 (file)
@@ -109,6 +109,20 @@ public class Build {
                downloadFromApache(MavenObject.COMMONS_COMPRESS, BuildType.RUNTIME);\r
                downloadFromApache(MavenObject.XZ, BuildType.RUNTIME);\r
 \r
+               //needed for selenium ui tests\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_API, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_FF, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_JAVA, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_REMOTE, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_SUPPORT, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.GUAVA, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.JSON, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.COMMONS_EXEC, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.HTTPCLIENT, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.HTTPCORE, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.HTTPMIME, BuildType.RUNTIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.COMMONS_LOGGING, BuildType.RUNTIME);\r
+               \r
                downloadFromEclipse(MavenObject.JGIT, BuildType.RUNTIME);\r
                downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.RUNTIME);\r
        }\r
@@ -148,6 +162,20 @@ public class Build {
                downloadFromApache(MavenObject.COMMONS_COMPRESS, BuildType.COMPILETIME);\r
                downloadFromApache(MavenObject.XZ, BuildType.COMPILETIME);\r
 \r
+               //needed for selenium ui tests\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_API, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_FF, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_JAVA, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_REMOTE, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.SEL_SUPPORT, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.GUAVA, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.JSON, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.COMMONS_EXEC, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.HTTPCLIENT, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.HTTPCORE, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.HTTPMIME, BuildType.COMPILETIME);\r
+               downloadFromApacheToExtSelenium(MavenObject.COMMONS_LOGGING, BuildType.COMPILETIME);\r
+               \r
                downloadFromEclipse(MavenObject.JGIT, BuildType.COMPILETIME);\r
                downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.COMPILETIME);\r
 \r
@@ -217,7 +245,7 @@ public class Build {
                Properties properties = new Properties();\r
                FileInputStream is = null;\r
                try {\r
-                       is = new FileInputStream(new File("distrib", Constants.PROPERTIES_FILE));\r
+                       is = new FileInputStream(Constants.PROPERTIES_FILE);\r
                        properties.load(is);\r
                } catch (Throwable t) {\r
                        t.printStackTrace();\r
@@ -398,7 +426,7 @@ public class Build {
         *            the maven object to download.\r
         * @return\r
         */\r
-       private static List<File> downloadFromMaven(String mavenRoot, MavenObject mo, BuildType type) {\r
+       private static List<File> downloadFromMaven(String mavenRoot, MavenObject mo, BuildType type, String targetFolder) {\r
                List<File> downloads = new ArrayList<File>();\r
                String[] jars = { "" };\r
                if (BuildType.RUNTIME.equals(type)) {\r
@@ -407,9 +435,9 @@ public class Build {
                        jars = new String[] { "-sources" };\r
                }\r
                for (String jar : jars) {\r
-                       File targetFile = mo.getLocalFile("ext", jar);\r
+                       File targetFile = mo.getLocalFile(targetFolder, jar);\r
                        if ("-sources".equals(jar)) {\r
-                               File relocated = new File("ext/src", targetFile.getName());\r
+                               File relocated = new File(targetFolder+"/src", targetFile.getName());\r
                                if (targetFile.exists()) {\r
                                        // move -sources jar to ext/src folder\r
                                        targetFile.renameTo(relocated);\r
@@ -502,6 +530,31 @@ public class Build {
                return downloads;\r
        }\r
        \r
+       /**\r
+        * Download a file from the official Apache Maven repository.\r
+        * \r
+        * @param mo\r
+        *            the maven object to download.\r
+        * @return\r
+        */\r
+       private static List<File> downloadFromApacheToExtSelenium(MavenObject mo,\r
+                       BuildType type) {\r
+               return downloadFromMaven("http://repo1.maven.org/maven2/", mo, type,\r
+                               "ext/seleniumhq");\r
+       }\r
+       \r
+       /**\r
+        * Download a file from the official Apache Maven repository.\r
+        * \r
+        * @param mo\r
+        *            the maven object to download.\r
+        * @return\r
+        */\r
+       private static List<File> downloadFromMaven(String mavenRoot,\r
+                       MavenObject mo, BuildType type) {\r
+               return downloadFromMaven(mavenRoot, mo, type, "ext");\r
+       }\r
+       \r
        private static void removeObsoleteArtifacts(final MavenObject mo, final BuildType type, File folder) {\r
                File [] removals = folder.listFiles(new FilenameFilter() {\r
                        @Override\r
@@ -796,6 +849,59 @@ public class Build {
                 "ecff5cb8b1189514c9d1d8d68eb77ac372e000c9",\r
                                "f95e32a5d2dd8da643c4419814415b9704312993", "");\r
 \r
+               public static final MavenObject SEL_JAVA = new MavenObject(\r
+                               "selenium-java", "org/seleniumhq/selenium", "selenium-java",\r
+                               "2.28.0", 984098, 0, 0,\r
+                               "7606286989ac9cb942cc206d975ffe187c18d605", "4ede08d293dc153989a337cd0d31d26421433af5", "");\r
+\r
+               public static final MavenObject SEL_API = new MavenObject(\r
+                               "selenium-api", "org/seleniumhq/selenium", "selenium-api",\r
+                               "2.28.0", 984098, 0, 0,\r
+                               "c4044c40fff65cd25135a5f443638a2b1ccaeac5", "35fc6ec0804ae32b16a56627e69bdcb69995c515", "");\r
+\r
+               public static final MavenObject SEL_REMOTE = new MavenObject(\r
+                               "selenium-remote-driver", "org/seleniumhq/selenium",\r
+                               "selenium-remote-driver", "2.28.0", 984098, 0, 0,\r
+                               "c67f97cd94e02afec92b0ac881844febb4fc90be", "51a9c30de3c8c203cb7a474a10842443005a5fb4", "");\r
+               public static final MavenObject SEL_SUPPORT = new MavenObject(\r
+                               "selenium-support", "org/seleniumhq/selenium",\r
+                               "selenium-support", "2.28.0", 984098, 0, 0,\r
+                               "caf68d6310425f583bc592c08e43066b35eb94f6", "ce3831a601f5f50fda2f4604decde409b6c735a7", "");\r
+               public static final MavenObject SEL_FF = new MavenObject(\r
+                               "selenium-firefox-driver", "org/seleniumhq/selenium",\r
+                               "selenium-firefox-driver", "2.28.0", 984098, 0, 0,\r
+                               "a7c34e45dba39e65467b900aa67611aaa039692d", "aa8cd5fb49ca75a53d5b143406ea3d81ab3eddfd", "");\r
+\r
+               public static final MavenObject GUAVA = new MavenObject("guava",\r
+                               "com/google/guava", "guava", "12.0", 984098, 0, 0,\r
+                               "5bc66dd95b79db1e437eb08adba124a3e4088dc0", "f8b98e61865bed3c39b978ee3bf5c7fb990c4032", "");\r
+\r
+               public static final MavenObject JSON = new MavenObject("json",\r
+                               "org/json", "json", "20080701", 984098, 0, 0,\r
+                               "d652f102185530c93b66158b1859f35d45687258", "71bd54221e701df9d112bf9ba2918e13b0671f3a", "");\r
+\r
+               public static final MavenObject COMMONS_EXEC = new MavenObject(\r
+                               "commons-exec", "org/apache/commons", "commons-exec", "1.1",\r
+                               984098, 0, 0, "07dfdf16fade726000564386825ed6d911a44ba1", "f60bea898e18b308099862e8634d589b06a8b0be",\r
+                               "");\r
+\r
+               public static final MavenObject HTTPCORE = new MavenObject("httpcore",\r
+                               "org/apache/httpcomponents", "httpcore", "4.2.1", 984098, 0, 0,\r
+                               "2d503272bf0a8b5f92d64db78b4ba9abbaccc6fd", "3f6caf5334fa83607b82e2f32dd128a9d8a0ea5e", "");\r
+               \r
+               public static final MavenObject HTTPMIME = new MavenObject("httpmime",\r
+                               "org/apache/httpcomponents", "httpmime", "4.2.1", 984098, 0, 0,\r
+                               "7c772bace9aa31a728c39a88c6ff66a7cd177e89", "", "4e453843ae47f1c2d70e2eb2c13c037de4b614c4");\r
+               \r
+               public static final MavenObject HTTPCLIENT = new MavenObject(\r
+                               "httpclient", "org/apache/httpcomponents", "httpclient",\r
+                               "4.2.1", 984098, 0, 0,\r
+                               "b69bd03af60bf487b3ae1209a644ecac587bf6fc", "6b27312b9c28b59aaeb6c21f3490045690c703d3", "");\r
+               public static final MavenObject COMMONS_LOGGING = new MavenObject(\r
+                               "commons-logging", "commons-logging", "commons-logging",\r
+                               "1.1.1", 984098, 0, 0,\r
+                               "5043bfebc3db072ed80fbd362e7caf00e885d8ae", "f3f156cbff0e0fb0d64bfce31a352cce4a33bc19", "");\r
+               \r
                public final String name;\r
                public final String group;\r
                public final String artifact;\r
diff --git a/test-ui-gitblit.properties b/test-ui-gitblit.properties
new file mode 100644 (file)
index 0000000..c77de1a
--- /dev/null
@@ -0,0 +1,1203 @@
+#\r
+# Git Servlet Settings\r
+#\r
+\r
+# Base folder for repositories.\r
+# This folder may contain bare and non-bare repositories but Gitblit will only\r
+# allow you to push to bare repositories.\r
+# Use forward slashes even on Windows!!\r
+# e.g. c:/gitrepos\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+git.repositoriesFolder = ${baseFolder}/git\r
+\r
+# Build the available repository list at startup and cache this list for reuse.\r
+# This reduces disk io when presenting the repositories page, responding to rpcs,\r
+# etc, but it means that  Gitblit will not automatically identify repositories\r
+# added or deleted by external tools.\r
+#\r
+# For this case you can use curl, wget, etc to issue an rpc request to clear the\r
+# cache (e.g. https://localhost/rpc?req=CLEAR_REPOSITORY_CACHE)\r
+#\r
+# SINCE 1.1.0\r
+git.cacheRepositoryList = true\r
+\r
+# Search the repositories folder subfolders for other repositories.\r
+# Repositories MAY NOT be nested (i.e. one repository within another)\r
+# but they may be grouped together in subfolders.\r
+# e.g. c:/gitrepos/libraries/mylibrary.git\r
+#      c:/gitrepos/libraries/myotherlibrary.git\r
+#\r
+# SINCE 0.5.0\r
+git.searchRepositoriesSubfolders = true\r
+\r
+# Maximum number of folders to recurse into when searching for repositories.\r
+# The default value, -1, disables depth limits.\r
+#\r
+# SINCE 1.1.0\r
+git.searchRecursionDepth = -1\r
+\r
+# List of regex exclusion patterns to match against folders found in\r
+# *git.repositoriesFolder*.\r
+# Use forward slashes even on Windows!!\r
+# e.g. test/jgit\.git\r
+#\r
+# SPACE-DELIMITED\r
+# CASE-SENSITIVE\r
+# SINCE 1.1.0\r
+git.searchExclusions =\r
+\r
+# List of regex url patterns for extracting a repository name when locating\r
+# submodules.\r
+#   e.g. git.submoduleUrlPatterns = .*?://github.com/(.*) will extract\r
+#   *gitblit/gitblit.git* from *git://github.com/gitblit/gitblit.git*\r
+# If no matches are found then the submodule repository name is assumed to be\r
+# whatever trails the last / character. (e.g. gitblit.git).\r
+#\r
+# SPACE-DELIMITED\r
+# CASE-SENSITIVE\r
+# SINCE 1.1.0\r
+git.submoduleUrlPatterns = .*?://github.com/(.*)\r
+\r
+# Allow push/pull over http/https with JGit servlet.\r
+# If you do NOT want to allow Git clients to clone/push to Gitblit set this\r
+# to false.  You might want to do this if you are only using ssh:// or git://.\r
+# If you set this false, consider changing the *web.otherUrls* setting to\r
+# indicate your clone/push urls.\r
+#\r
+# SINCE 0.5.0\r
+git.enableGitServlet = true\r
+\r
+# If you want to restrict all git servlet access to those with valid X509 client\r
+# certificates then set this value to true.\r
+#\r
+# SINCE 1.2.0\r
+git.requiresClientCertificate = false\r
+\r
+# Enforce date checks on client certificates to ensure that they are not being\r
+# used prematurely and that they have not expired.\r
+#\r
+# SINCE 1.2.0\r
+git.enforceCertificateValidity = true\r
+\r
+# List of OIDs to extract from a client certificate DN to map a certificate to\r
+# an account username.\r
+#\r
+# e.g. git.certificateUsernameOIDs = CN\r
+# e.g. git.certificateUsernameOIDs = FirstName LastName\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 1.2.0\r
+git.certificateUsernameOIDs = CN\r
+\r
+# Only serve/display bare repositories.\r
+# If there are non-bare repositories in git.repositoriesFolder and this setting\r
+# is true, they will be excluded from the ui. \r
+#\r
+# SINCE 0.9.0\r
+git.onlyAccessBareRepositories = false\r
+\r
+# Allow an authenticated user to create a destination repository on a push if\r
+# the repository does not already exist.\r
+#\r
+# Administrator accounts can create a repository in any project.\r
+# These repositories are created with the default access restriction and authorization\r
+# control values.  The pushing account is set as the owner.\r
+#\r
+# Non-administrator accounts with the CREATE role may create personal repositories.\r
+# These repositories are created as VIEW restricted for NAMED users.\r
+# The pushing account is set as the owner.\r
+#\r
+# SINCE 1.2.0\r
+git.allowCreateOnPush = true\r
+\r
+# The default access restriction for new repositories.\r
+# Valid values are NONE, PUSH, CLONE, VIEW\r
+#  NONE = anonymous view, clone, & push\r
+#  PUSH = anonymous view & clone and authenticated push\r
+#  CLONE = anonymous view, authenticated clone & push\r
+#  VIEW = authenticated view, clone, & push\r
+#\r
+# SINCE 1.0.0\r
+git.defaultAccessRestriction = NONE\r
+\r
+# The default authorization control for new repositories.\r
+# Valid values are AUTHENTICATED and NAMED\r
+#  AUTHENTICATED = any authenticated user is granted restricted access\r
+#  NAMED = only named users/teams are granted restricted access\r
+#\r
+# SINCE 1.1.0\r
+git.defaultAuthorizationControl = NAMED\r
+\r
+# Enable JGit-based garbage collection. (!!EXPERIMENTAL!!)\r
+#\r
+# USE AT YOUR OWN RISK!\r
+#\r
+# If enabled, the garbage collection executor scans all repositories once a day\r
+# at the hour of your choosing.  The GC executor will take each repository "offline",\r
+# one-at-a-time, to check if the repository satisfies it's GC trigger requirements.\r
+#\r
+# While the repository is offline it will be inaccessible from the web UI or from\r
+# any of the other services (git, rpc, rss, etc).\r
+#\r
+# Gitblit's GC Executor MAY NOT PLAY NICE with the other Git kids on the block,\r
+# especially on Windows systems, so if you are using other tools please coordinate\r
+# their usage with your GC Executor schedule or do not use this feature.\r
+#\r
+# The GC algorithm complex and the JGit team advises caution when using their\r
+# young implementation of GC.\r
+#\r
+# http://wiki.eclipse.org/EGit/New_and_Noteworthy/2.1#Garbage_Collector_and_Repository_Storage_Statistics\r
+#\r
+# EXPERIMENTAL\r
+# SINCE 1.2.0\r
+# RESTART REQUIRED\r
+git.enableGarbageCollection = false\r
+\r
+# Hour of the day for the GC Executor to scan repositories.\r
+# This value is in 24-hour time.\r
+#\r
+# SINCE 1.2.0\r
+git.garbageCollectionHour = 0\r
+\r
+# The default minimum total filesize of loose objects to trigger early garbage\r
+# collection.\r
+#\r
+# You may specify a custom threshold for a repository in the repository's settings.\r
+# Common unit suffixes of k, m, or g are supported.\r
+#\r
+# SINCE 1.2.0\r
+git.defaultGarbageCollectionThreshold = 500k\r
+\r
+# The default period, in days, between GCs for a repository.  If the total filesize\r
+# of the loose object exceeds *git.garbageCollectionThreshold* or the repository's\r
+# custom threshold, this period will be short-circuited. \r
+#\r
+# e.g. if a repository collects 100KB of loose objects every day with a 500KB\r
+# threshold and a period of 7 days, it will take 5 days for the loose objects to\r
+# be collected, packed, and pruned.\r
+#\r
+# OR\r
+#\r
+# if a repository collects 10KB of loose objects every day with a 500KB threshold\r
+# and a period of 7 days, it will take the full 7 days for the loose objects to be\r
+# collected, packed, and pruned.\r
+#\r
+# You may specify a custom period for a repository in the repository's settings.\r
+#\r
+# The minimum value is 1 day since the GC Executor only runs once a day.\r
+#\r
+# SINCE 1.2.0\r
+git.defaultGarbageCollectionPeriod = 7\r
+\r
+# Number of bytes of a pack file to load into memory in a single read operation.\r
+# This is the "page size" of the JGit buffer cache, used for all pack access\r
+# operations. All disk IO occurs as single window reads. Setting this too large\r
+# may cause the process to load more data than is required; setting this too small\r
+# may increase the frequency of read() system calls.\r
+#\r
+# Default on JGit is 8 KiB on all platforms.\r
+#\r
+# Common unit suffixes of k, m, or g are supported.\r
+# Documentation courtesy of the Gerrit project.\r
+#\r
+# SINCE 1.0.0\r
+# RESTART REQUIRED\r
+git.packedGitWindowSize = 8k\r
+\r
+# Maximum number of bytes to load and cache in memory from pack files. If JGit\r
+# needs to access more than this many bytes it will unload less frequently used\r
+# windows to reclaim memory space within the process. As this buffer must be shared\r
+# with the rest of the JVM heap, it should be a fraction of the total memory available.\r
+#\r
+# The JGit team recommends setting this value larger than the size of your biggest\r
+# repository. This ensures you can serve most requests from memory.\r
+#\r
+# Default on JGit is 10 MiB on all platforms.\r
+#\r
+# Common unit suffixes of k, m, or g are supported.\r
+# Documentation courtesy of the Gerrit project.\r
+#\r
+# SINCE 1.0.0\r
+# RESTART REQUIRED\r
+git.packedGitLimit = 10m\r
+\r
+# Maximum number of bytes to reserve for caching base objects that multiple deltafied\r
+# objects reference. By storing the entire decompressed base object in a cache Git\r
+# is able to avoid unpacking and decompressing frequently used base objects multiple times.\r
+#\r
+# Default on JGit is 10 MiB on all platforms. You probably do not need to adjust\r
+# this value.\r
+#\r
+# Common unit suffixes of k, m, or g are supported.\r
+# Documentation courtesy of the Gerrit project.\r
+#\r
+# SINCE 1.0.0\r
+# RESTART REQUIRED\r
+git.deltaBaseCacheLimit = 10m\r
+\r
+# Maximum number of pack files to have open at once. A pack file must be opened\r
+# in order for any of its data to be available in a cached window.\r
+#\r
+# If you increase this to a larger setting you may need to also adjust the ulimit\r
+# on file descriptors for the host JVM, as Gitblit needs additional file descriptors\r
+# available for network sockets and other repository data manipulation.\r
+#\r
+# Default on JGit is 128 file descriptors on all platforms.\r
+# Documentation courtesy of the Gerrit project.\r
+#\r
+# SINCE 1.0.0\r
+# RESTART REQUIRED\r
+git.packedGitOpenFiles = 128\r
+\r
+# Largest object size, in bytes, that JGit will allocate as a contiguous byte\r
+# array. Any file revision larger than this threshold will have to be streamed,\r
+# typically requiring the use of temporary files under $GIT_DIR/objects to implement\r
+# psuedo-random access during delta decompression.\r
+#\r
+# Servers with very high traffic should set this to be larger than the size of\r
+# their common big files. For example a server managing the Android platform\r
+# typically has to deal with ~10-12 MiB XML files, so 15 m would be a reasonable\r
+# setting in that environment. Setting this too high may cause the JVM to run out\r
+# of heap space when handling very big binary files, such as device firmware or\r
+# CD-ROM ISO images. Make sure to adjust your JVM heap accordingly. \r
+#\r
+# Default is 50 MiB on all platforms.\r
+#\r
+# Common unit suffixes of k, m, or g are supported.\r
+# Documentation courtesy of the Gerrit project.\r
+#\r
+# SINCE 1.0.0\r
+# RESTART REQUIRED\r
+git.streamFileThreshold = 50m\r
+\r
+# When true, JGit will use mmap() rather than malloc()+read() to load data from\r
+# pack files.  The use of mmap can be problematic on some JVMs as the garbage\r
+# collector must deduce that a memory mapped segment is no longer in use before\r
+# a call to munmap() can be made by the JVM native code.\r
+#\r
+# In server applications (such as Gitblit) that need to access many pack files,\r
+# setting this to true risks artificially running out of virtual address space, \r
+# as the garbage collector cannot reclaim unused mapped spaces fast enough.\r
+#\r
+# Default on JGit is false. Although potentially slower, it yields much more\r
+# predictable behavior.\r
+# Documentation courtesy of the Gerrit project.\r
+#\r
+# SINCE 1.0.0\r
+# RESTART REQUIRED\r
+git.packedGitMmap = false\r
+\r
+#\r
+# Groovy Integration\r
+#\r
+\r
+# Location of Groovy scripts to use for Pre and Post receive hooks.\r
+# Use forward slashes even on Windows!!\r
+# e.g. c:/groovy\r
+#\r
+# RESTART REQUIRED\r
+# SINCE 0.8.0\r
+groovy.scriptsFolder = ${baseFolder}/groovy\r
+\r
+# Specify the directory Grape uses for downloading libraries.\r
+# http://groovy.codehaus.org/Grape\r
+#\r
+# RESTART REQUIRED\r
+# SINCE 1.0.0\r
+groovy.grapeFolder = ${baseFolder}/groovy/grape\r
+\r
+# Scripts to execute on Pre-Receive.\r
+#\r
+# These scripts execute after an incoming push has been parsed and validated\r
+# but BEFORE the changes are applied to the repository.  You might reject a\r
+# push in this script based on the repository and branch the push is attempting\r
+# to change.\r
+#\r
+# Script names are case-sensitive on case-sensitive file systems.  You may omit\r
+# the traditional ".groovy" from this list if your file extension is ".groovy" \r
+#\r
+# NOTE:\r
+# These scripts are only executed when pushing to *Gitblit*, not to other Git\r
+# tooling you may be using.  Also note that these scripts are shared between\r
+# repositories. These are NOT repository-specific scripts!  Within the script\r
+# you may customize the control-flow for a specific repository by checking the\r
+# *repository* variable.\r
+#\r
+# SPACE-DELIMITED\r
+# CASE-SENSITIVE\r
+# SINCE 0.8.0\r
+groovy.preReceiveScripts =\r
+\r
+# Scripts to execute on Post-Receive.\r
+#\r
+# These scripts execute AFTER an incoming push has been applied to a repository.\r
+# You might trigger a continuous-integration build here or send a notification.\r
+#\r
+# Script names are case-sensitive on case-sensitive file systems.  You may omit\r
+# the traditional ".groovy" from this list if your file extension is ".groovy" \r
+#\r
+# NOTE:\r
+# These scripts are only executed when pushing to *Gitblit*, not to other Git\r
+# tooling you may be using.  Also note that these scripts are shared between\r
+# repositories. These are NOT repository-specific scripts!  Within the script\r
+# you may customize the control-flow for a specific repository by checking the\r
+# *repository* variable.\r
+# \r
+# SPACE-DELIMITED\r
+# CASE-SENSITIVE\r
+# SINCE 0.8.0\r
+groovy.postReceiveScripts =\r
+\r
+# Repository custom fields for Groovy Hook mechanism\r
+#\r
+# List of key=label pairs of custom fields to prompt for in the Edit Repository\r
+# page.  These keys are stored in the repository's git config file in the \r
+# section [gitblit "customFields"].  Key names are alphanumeric only.  These\r
+# fields are intended to be used for the Groovy hook mechanism where a script\r
+# can adjust it's execution based on the custom fields stored in the repository\r
+# config.\r
+#\r
+# e.g. "commitMsgRegex=Commit Message Regular Expression" anotherProperty=Another\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 1.0.0\r
+groovy.customFields = \r
+\r
+#\r
+# Authentication Settings\r
+#\r
+\r
+# Require authentication to see everything but the admin pages\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+web.authenticateViewPages = false\r
+\r
+# Require admin authentication for the admin functions and pages\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+web.authenticateAdminPages = true\r
+\r
+# Allow Gitblit to store a cookie in the user's browser for automatic\r
+# authentication.  The cookie is generated by the user service.\r
+#\r
+# SINCE 0.5.0\r
+web.allowCookieAuthentication = true\r
+\r
+# Config file for storing project metadata\r
+#\r
+# SINCE 1.2.0\r
+web.projectsFile = ${baseFolder}/projects.conf\r
+\r
+# Either the full path to a user config file (users.conf)\r
+# OR the full path to a simple user properties file (users.properties)\r
+# OR a fully qualified class name that implements the IUserService interface.\r
+#\r
+# Alternative user services:\r
+#    com.gitblit.LdapUserService\r
+#    com.gitblit.RedmineUserService\r
+#\r
+# Any custom user service implementation must have a public default constructor.\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+realm.userService = test-ui-users.conf\r
+\r
+# How to store passwords.\r
+# Valid values are plain, md5, or combined-md5.  md5 is the hash of password.\r
+# combined-md5 is the hash of username.toLowerCase()+password.\r
+# Default is md5.\r
+#\r
+# SINCE 0.5.0 \r
+realm.passwordStorage = md5\r
+\r
+# Minimum valid length for a plain text password.\r
+# Default value is 5.  Absolute minimum is 4.\r
+#\r
+# SINCE 0.5.0 \r
+realm.minPasswordLength = 5\r
+\r
+#\r
+# Gitblit Web Settings\r
+#\r
+# If blank Gitblit is displayed.\r
+#\r
+# SINCE 0.5.0\r
+web.siteName =\r
+\r
+# If *web.authenticateAdminPages*=true, users with "admin" role can create\r
+# repositories, create users, and edit repository metadata.\r
+#\r
+# If *web.authenticateAdminPages*=false, any user can execute the aforementioned\r
+# functions. \r
+#\r
+# SINCE 0.5.0 \r
+web.allowAdministration = true\r
+\r
+# Allows rpc clients to list repositories and possibly manage or administer the \r
+# Gitblit server, if the authenticated account has administrator permissions.\r
+# See *web.enableRpcManagement* and *web.enableRpcAdministration*.\r
+#\r
+# SINCE 0.7.0 \r
+web.enableRpcServlet = true\r
+\r
+# Allows rpc clients to manage repositories and users of the Gitblit instance,\r
+# if the authenticated account has administrator permissions.\r
+# Requires *web.enableRpcServlet=true*.\r
+#\r
+# SINCE 0.7.0 \r
+web.enableRpcManagement = false\r
+\r
+# Allows rpc clients to control the server settings and monitor the health of this\r
+# this Gitblit instance, if the authenticated account has administrator permissions.\r
+# Requires *web.enableRpcServlet=true* and *web.enableRpcManagement*.\r
+#\r
+# SINCE 0.7.0 \r
+web.enableRpcAdministration = false\r
+\r
+# Full path to a configurable robots.txt file.  With this file you can control\r
+# what parts of your Gitblit server respectable robots are allowed to traverse.\r
+# http://googlewebmastercentral.blogspot.com/2008/06/improving-on-robots-exclusion-protocol.html\r
+#\r
+# SINCE 1.0.0\r
+web.robots.txt = \r
+\r
+# If true, the web ui layout will respond and adapt to the browser's dimensions.\r
+# if false, the web ui will use a 940px fixed-width layout.\r
+# http://twitter.github.com/bootstrap/scaffolding.html#responsive\r
+#\r
+# SINCE 1.0.0\r
+web.useResponsiveLayout = true\r
+\r
+# Allow Gravatar images to be displayed in Gitblit pages.\r
+#\r
+# SINCE 0.8.0\r
+web.allowGravatar = true\r
+\r
+# Allow dynamic zip downloads.\r
+#\r
+# SINCE 0.5.0   \r
+web.allowZipDownloads = true\r
+\r
+# If *web.allowZipDownloads=true* the following formats will be displayed for\r
+# download compressed archive links:\r
+#\r
+# zip   = standard .zip\r
+# tar   = standard tar format (preserves *nix permissions and symlinks)\r
+# gz    = gz-compressed tar\r
+# xz    = xz-compressed tar\r
+# bzip2 = bzip2-compressed tar\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 1.2.0\r
+web.compressedDownloads = zip gz\r
+\r
+# Allow optional Lucene integration. Lucene indexing is an opt-in feature.\r
+# A repository may specify branches to index with Lucene instead of using Git\r
+# commit traversal. There are scenarios where you may want to completely disable\r
+# Lucene indexing despite a repository specifying indexed branches.  One such\r
+# scenario is on a resource-constrained federated Gitblit mirror.\r
+#\r
+# SINCE 0.9.0\r
+web.allowLuceneIndexing = false\r
+\r
+# Allows an authenticated user to create forks of a repository\r
+#\r
+# set this to false if you want to disable all fork controls on the web site\r
+#\r
+web.allowForking = true\r
+\r
+# Controls the length of shortened commit hash ids\r
+#\r
+# SINCE 1.2.0\r
+web.shortCommitIdLength = 6\r
+\r
+# Use Clippy (Flash solution) to provide a copy-to-clipboard button.\r
+# If false, a button with a more primitive JavaScript-based prompt box will\r
+# offer a 3-step (click, ctrl+c, enter) copy-to-clipboard alternative.\r
+#\r
+# SINCE 0.8.0\r
+web.allowFlashCopyToClipboard = true\r
+\r
+# Default maximum number of commits that a repository may contribute to the\r
+# activity page, regardless of the selected duration.  This setting may be valuable\r
+# for an extremely busy server.  This value may also be configed per-repository\r
+# in Edit Repository. 0 disables this throttle.\r
+#\r
+# SINCE 1.2.0\r
+web.maxActivityCommits = 0\r
+\r
+# Default number of entries to include in RSS Syndication links\r
+#\r
+# SINCE 0.5.0\r
+web.syndicationEntries = 25\r
+\r
+# Show the size of each repository on the repositories page.\r
+# This requires recursive traversal of each repository folder.  This may be\r
+# non-performant on some operating systems and/or filesystems. \r
+#\r
+# SINCE 0.5.2\r
+web.showRepositorySizes = true\r
+\r
+# List of custom regex expressions that can be displayed in the Filters menu\r
+# of the Repositories and Activity pages.  Keep them very simple because you\r
+# are likely to run into encoding issues if they are too complex.\r
+#\r
+# Use !!! to separate the filters \r
+#\r
+# SINCE 0.8.0\r
+web.customFilters =\r
+\r
+# Show federation registrations (without token) and the current pull status\r
+# to non-administrator users. \r
+#\r
+# SINCE 0.6.0\r
+web.showFederationRegistrations = false\r
+\r
+# This is the message displayed when *web.authenticateViewPages=true*.\r
+# This can point to a file with Markdown content.\r
+# Specifying "gitblit" uses the internal login message.\r
+#\r
+# SINCE 0.7.0\r
+web.loginMessage = gitblit\r
+\r
+# This is the message displayed above the repositories table.\r
+# This can point to a file with Markdown content.\r
+# Specifying "gitblit" uses the internal welcome message.\r
+#\r
+# SINCE 0.5.0\r
+web.repositoriesMessage = gitblit\r
+\r
+# Ordered list of charsets/encodings to use when trying to display a blob.\r
+# If empty, UTF-8 and ISO-8859-1 are used.  The server's default charset\r
+# is always appended to the encoding list.  If all encodings fail to cleanly\r
+# decode the blob content, UTF-8 will be used with the standard malformed\r
+# input/unmappable character replacement strings.\r
+# \r
+# SPACE-DELIMITED\r
+# SINCE 1.0.0\r
+web.blobEncodings = UTF-8 ISO-8859-1\r
+\r
+# Manually set the default timezone to be used by Gitblit for display in the \r
+# web ui.  This value is independent of the JVM timezone.  Specifying a blank\r
+# value will default to the JVM timezone.\r
+# e.g. America/New_York, US/Pacific, UTC, Europe/Berlin\r
+#\r
+# SINCE 0.9.0\r
+# RESTART REQUIRED\r
+web.timezone =\r
+\r
+# Use the client timezone when formatting dates.\r
+# This uses AJAX to determine the browser's timezone and may require more\r
+# server overhead because a Wicket session is created.  All Gitblit pages\r
+# attempt to be stateless, if possible.\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+web.useClientTimezone = false\r
+\r
+# Time format\r
+# <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html>\r
+#\r
+# SINCE 0.8.0\r
+web.timeFormat = HH:mm\r
+\r
+# Short date format\r
+# <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html>\r
+#\r
+# SINCE 0.5.0\r
+web.datestampShortFormat = yyyy-MM-dd\r
+\r
+# Long date format\r
+#\r
+# SINCE 0.8.0\r
+web.datestampLongFormat = EEEE, MMMM d, yyyy\r
+\r
+# Long timestamp format\r
+# <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html>\r
+#\r
+# SINCE 0.5.0\r
+web.datetimestampLongFormat = EEEE, MMMM d, yyyy HH:mm Z\r
+\r
+# Mount URL parameters\r
+# This setting controls if pretty or parameter URLs are used.\r
+# i.e.\r
+# if true:\r
+#     http://localhost/commit/myrepo/abcdef\r
+# if false:\r
+#     http://localhost/commit/?r=myrepo&h=abcdef\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+web.mountParameters = true\r
+\r
+# Some servlet containers (e.g. Tomcat >= 6.0.10) disallow '/' (%2F) encoding\r
+# in URLs as a security precaution for proxies.  This setting tells Gitblit\r
+# to preemptively replace '/' with '*' or '!' for url string parameters.\r
+#\r
+# <https://issues.apache.org/jira/browse/WICKET-1303>\r
+# <http://tomcat.apache.org/security-6.html#Fixed_in_Apache_Tomcat_6.0.10>\r
+# Add *-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true* to your\r
+# *CATALINA_OPTS* or to your JVM launch parameters\r
+#\r
+# SINCE 0.5.2\r
+web.forwardSlashCharacter = /\r
+\r
+# Show other URLs on the summary page for accessing your git repositories\r
+# Use spaces to separate urls. {0} is the token for the repository name.\r
+# e.g.\r
+# web.otherUrls = ssh://localhost/git/{0} git://localhost/git/{0}\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 0.5.0\r
+web.otherUrls = \r
+\r
+# Choose how to present the repositories list.\r
+#   grouped = group nested/subfolder repositories together (no sorting)\r
+#   flat = flat list of repositories (sorting allowed)\r
+#\r
+# SINCE 0.5.0\r
+web.repositoryListType = grouped\r
+\r
+# If using a grouped repository list and there are repositories at the\r
+# root level of your repositories folder, you may specify the displayed\r
+# group name with this setting.  This value is only used for web presentation.\r
+#\r
+# SINCE 0.5.0\r
+web.repositoryRootGroupName = main\r
+\r
+# Display the repository swatch color next to the repository name link in the \r
+# repositories list. \r
+#\r
+# SINCE 0.8.0\r
+web.repositoryListSwatches = true\r
+\r
+# Choose the diff presentation style: gitblt, gitweb, or plain\r
+#\r
+# SINCE 0.5.0\r
+web.diffStyle = gitblit\r
+\r
+# Control if email addresses are shown in web ui\r
+#\r
+# SINCE 0.5.0\r
+web.showEmailAddresses = true\r
+\r
+# Shows a combobox in the page links header with commit, committer, and author\r
+# search selection.  Default search is commit.\r
+#\r
+# SINCE 0.5.0\r
+web.showSearchTypeSelection = false\r
+\r
+# Generates a line graph of repository activity over time on the Summary page.\r
+# This uses the Google Charts API.\r
+#\r
+# SINCE 0.5.0 \r
+web.generateActivityGraph = true\r
+\r
+# The number of days to show on the activity page.\r
+# Value must exceed 0 else default of 14 is used\r
+#\r
+# SINCE 0.8.0\r
+web.activityDuration = 14\r
+\r
+# The number of commits to display on the summary page\r
+# Value must exceed 0 else default of 20 is used\r
+#\r
+# SINCE 0.5.0\r
+web.summaryCommitCount = 16\r
+\r
+# The number of tags/branches to display on the summary page.\r
+# -1 = all tags/branches\r
+# 0 = hide tags/branches\r
+# N = N tags/branches\r
+#\r
+# SINCE 0.5.0\r
+web.summaryRefsCount = 5\r
+\r
+# The number of items to show on a page before showing the first, prev, next\r
+# pagination links.  A default if 50 is used for any invalid value.\r
+#\r
+# SINCE 0.5.0\r
+web.itemsPerPage = 50\r
+\r
+# Registered file extensions to ignore during Lucene indexing\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 0.9.0\r
+web.luceneIgnoreExtensions = 7z arc arj bin bmp dll doc docx exe gif gz jar jpg lib lzh odg odf odt pdf ppt png so swf xcf xls xlsx zip\r
+\r
+# Registered extensions for google-code-prettify\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 0.5.0\r
+web.prettyPrintExtensions = c cpp cs css frm groovy htm html java js php pl prefs properties py rb scala sh sql xml vb\r
+\r
+# Registered extensions for markdown transformation\r
+#\r
+# SPACE-DELIMITED\r
+# CASE-SENSITIVE\r
+# SINCE 0.5.0\r
+web.markdownExtensions = md mkd markdown MD MKD\r
+\r
+# Image extensions\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 0.5.0\r
+web.imageExtensions = bmp jpg gif png \r
+\r
+# Registered extensions for binary blobs\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 0.5.0\r
+web.binaryExtensions = jar pdf tar.gz zip\r
+\r
+# Aggressive heap management will run the garbage collector on every generated\r
+# page.  This slows down page generation a little but improves heap consumption. \r
+#\r
+# SINCE 0.5.0\r
+web.aggressiveHeapManagement = false\r
+\r
+# Run the webapp in debug mode\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+web.debugMode = false\r
+\r
+# Enable/disable global regex substitutions (i.e. shared across repositories)\r
+#\r
+# SINCE 0.5.0\r
+regex.global = true\r
+\r
+# Example global regex substitutions\r
+# Use !!! to separate the search pattern and the replace pattern\r
+# searchpattern!!!replacepattern\r
+# SINCE 0.5.0\r
+regex.global.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://somehost/bug/$3">Bug-Id: $3</a>\r
+# SINCE 0.5.0\r
+regex.global.changeid = \\b(Change-Id:\\s*)([A-Za-z0-9]*)\\b!!!<a href="http://somehost/changeid/$2">Change-Id: $2</a>\r
+\r
+# Example per-repository regex substitutions overrides global\r
+# SINCE 0.5.0\r
+regex.myrepository.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://elsewhere/bug/$3">Bug-Id: $3</a>\r
+\r
+#\r
+# Mail Settings\r
+# SINCE 0.6.0\r
+#\r
+# Mail settings are used to notify administrators of received federation proposals\r
+#\r
+\r
+# ip or hostname of smtp server\r
+#\r
+# SINCE 0.6.0\r
+mail.server =\r
+\r
+# port to use for smtp requests\r
+#\r
+# SINCE 0.6.0\r
+mail.port = 25\r
+\r
+# debug the mail executor\r
+#\r
+# SINCE 0.6.0\r
+mail.debug = false\r
+\r
+# if your smtp server requires authentication, supply the credentials here\r
+#\r
+# SINCE 0.6.0\r
+mail.username =\r
+# SINCE 0.6.0\r
+mail.password =\r
+\r
+# from address for generated emails\r
+#\r
+# SINCE 0.6.0\r
+mail.fromAddress = \r
+\r
+# List of email addresses for the Gitblit administrators\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 0.6.0\r
+mail.adminAddresses = \r
+\r
+# List of email addresses for sending push email notifications.\r
+#\r
+# This key currently requires use of the sendemail.groovy hook script.\r
+# If you set sendemail.groovy in *groovy.postReceiveScripts* then email\r
+# notifications for all repositories (regardless of access restrictions!)\r
+# will be sent to these addresses.\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 0.8.0\r
+mail.mailingLists =\r
+\r
+#\r
+# Federation Settings\r
+# SINCE 0.6.0\r
+#\r
+# A Gitblit federation is a way to backup one Gitblit instance to another.\r
+#\r
+# *git.enableGitServlet* must be true to use this feature.\r
+\r
+# Your federation name is used for federation status acknowledgments.  If it is\r
+# unset, and you elect to send a status acknowledgment, your Gitblit instance\r
+# will be identified by its hostname, if available, else your internal ip address.\r
+# The source Gitblit instance will also append your external IP address to your\r
+# identification to differentiate multiple pulling systems behind a single proxy.\r
+#\r
+# SINCE 0.6.0\r
+federation.name =\r
+\r
+# Specify the passphrase of this Gitblit instance.\r
+#\r
+# An unspecified (empty) passphrase disables processing federation requests.\r
+#\r
+# This value can be anything you want: an integer, a sentence, an haiku, etc.\r
+# Keep the value simple, though, to avoid Java properties file encoding issues.\r
+#\r
+# Changing your passphrase will break any registrations you have established with other\r
+# Gitblit instances.\r
+#\r
+# CASE-SENSITIVE\r
+# SINCE 0.6.0\r
+# RESTART REQUIRED *(only to enable or disable federation)*\r
+federation.passphrase =\r
+\r
+# Control whether or not this Gitblit instance can receive federation proposals\r
+# from another Gitblit instance.  Registering a federated Gitblit is a manual\r
+# process.  Proposals help to simplify that process by allowing a remote Gitblit\r
+# instance to send your Gitblit instance the federation pull data.\r
+#\r
+# SINCE 0.6.0\r
+federation.allowProposals = false\r
+\r
+# The destination folder for cached federation proposals.\r
+# Use forward slashes even on Windows!!\r
+#\r
+# SINCE 0.6.0\r
+federation.proposalsFolder = ${baseFolder}/proposals\r
+\r
+# The default pull frequency if frequency is unspecified on a registration\r
+#\r
+# SINCE 0.6.0\r
+federation.defaultFrequency = 60 mins\r
+\r
+# Federation Sets are named groups of repositories.  The Federation Sets are \r
+# available for selection in the repository settings page.  You can assign a\r
+# repository to one or more sets and then distribute the token for the set.\r
+# This allows you to grant federation pull access to a subset of your available\r
+# repositories.  Tokens for federation sets only grant repository pull access.\r
+#\r
+# SPACE-DELIMITED\r
+# CASE-SENSITIVE\r
+# SINCE 0.6.0\r
+federation.sets = \r
+\r
+# Federation pull registrations\r
+# Registrations are read once, at startup.\r
+#\r
+# RESTART REQUIRED\r
+#\r
+# frequency:\r
+#   The shortest frequency allowed is every 5 minutes\r
+#   Decimal frequency values are cast to integers\r
+#   Frequency values may be specified in mins, hours, or days\r
+#   Values that can not be parsed or are unspecified default to *federation.defaultFrequency*\r
+#\r
+# folder:\r
+#   if unspecified, the folder is *git.repositoriesFolder*\r
+#   if specified, the folder is relative to *git.repositoriesFolder*\r
+#\r
+# bare:\r
+#   if true, each repository will be created as a *bare* repository and will not\r
+#   have a working directory.\r
+#\r
+#   if false, each repository will be created as a normal repository suitable\r
+#   for local work.\r
+#\r
+# mirror:\r
+#   if true, each repository HEAD is reset to *origin/master* after each pull.\r
+#   The repository will be flagged *isFrozen* after the initial clone.\r
+#\r
+#   if false, each repository HEAD will point to the FETCH_HEAD of the initial\r
+#   clone from the origin until pushed to or otherwise manipulated.\r
+#\r
+# mergeAccounts:\r
+#   if true, remote accounts and their permissions are merged into your \r
+#   users.properties file \r
+#\r
+# notifyOnError:\r
+#   if true and the mail configuration is properly set, administrators will be\r
+#   notified by email of pull failures\r
+#\r
+# include and exclude:\r
+#   Space-delimited list of repositories to include or exclude from pull\r
+#   may be * wildcard to include or exclude all\r
+#   may use fuzzy match (e.g. org.eclipse.*)\r
+\r
+#\r
+# (Nearly) Perfect Mirror example\r
+#\r
+\r
+#federation.example1.url = https://go.gitblit.com\r
+#federation.example1.token = 6f3b8a24bf970f17289b234284c94f43eb42f0e4\r
+#federation.example1.frequency = 120 mins\r
+#federation.example1.folder =\r
+#federation.example1.bare = true \r
+#federation.example1.mirror = true \r
+#federation.example1.mergeAccounts = true\r
+\r
+#\r
+# Advanced Realm Settings\r
+#\r
+\r
+# URL of the LDAP server.\r
+# To use encrypted transport, use either ldaps:// URL for SSL or ldap+tls:// to\r
+# send StartTLS command.\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.server = ldap://localhost\r
+\r
+# Login username for LDAP searches.\r
+# If this value is unspecified, anonymous LDAP login will be used.\r
+# \r
+# e.g. mydomain\\username\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.username = cn=Directory Manager\r
+\r
+# Login password for LDAP searches.\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.password = password\r
+\r
+# The LdapUserService must be backed by another user service for standard user\r
+# and team management.\r
+# default: users.conf\r
+#\r
+# SINCE 1.0.0\r
+# RESTART REQUIRED\r
+realm.ldap.backingUserService = test-ui-users.conf\r
+\r
+# Delegate team membership control to LDAP.\r
+#\r
+# If true, team user memberships will be specified by LDAP groups.  This will\r
+# disable team selection in Edit User and user selection in Edit Team.\r
+#\r
+# If false, LDAP will only be used for authentication and Gitblit will maintain\r
+# team memberships with the *realm.ldap.backingUserService*.\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.maintainTeams = false\r
+\r
+# Root node for all LDAP users\r
+#\r
+# This is the root node from which subtree user searches will begin.\r
+# If blank, Gitblit will search ALL nodes.\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.accountBase = OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain\r
+\r
+# Filter criteria for LDAP users\r
+#\r
+# Query pattern to use when searching for a user account. This may be any valid \r
+# LDAP query expression, including the standard (&) and (|) operators.\r
+#\r
+# Variables may be injected via the ${variableName} syntax.\r
+# Recognized variables are:\r
+#    ${username} - The text entered as the user name\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.accountPattern = (&(objectClass=person)(sAMAccountName=${username}))\r
+\r
+# Root node for all LDAP groups to be used as Gitblit Teams\r
+#\r
+# This is the root node from which subtree team searches will begin.\r
+# If blank, Gitblit will search ALL nodes.  \r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.groupBase = OU=Groups,OU=UserControl,OU=MyOrganization,DC=MyDomain\r
+\r
+# Filter criteria for LDAP groups\r
+#\r
+# Query pattern to use when searching for a team. This may be any valid \r
+# LDAP query expression, including the standard (&) and (|) operators.\r
+#\r
+# Variables may be injected via the ${variableName} syntax.\r
+# Recognized variables are:\r
+#    ${username} - The text entered as the user name\r
+#    ${dn} - The Distinguished Name of the user logged in\r
+#\r
+# All attributes from the LDAP User record are available. For example, if a user\r
+# has an attribute "fullName" set to "John", "(fn=${fullName})" will be \r
+# translated to "(fn=John)".\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.groupMemberPattern = (&(objectClass=group)(member=${dn}))\r
+\r
+# LDAP users or groups that should be given administrator privileges.\r
+#\r
+# Teams are specified with a leading '@' character.  Groups with spaces in the\r
+# name can be entered as "@team name".\r
+#\r
+# e.g. realm.ldap.admins = john @git_admins "@git admins"\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 1.0.0\r
+realm.ldap.admins = @Git_Admins\r
+\r
+# Attribute(s) on the USER record that indicate their display (or full) name.\r
+# Leave blank for no mapping available in LDAP.\r
+#\r
+# This may be a single attribute, or a string of multiple attributes.  Examples:\r
+#  displayName - Uses the attribute 'displayName' on the user record\r
+#  ${personalTitle}. ${givenName} ${surname} - Will concatenate the 3 \r
+#       attributes together, with a '.' after personalTitle\r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.displayName = displayName\r
+\r
+# Attribute(s) on the USER record that indicate their email address.\r
+# Leave blank for no mapping available in LDAP.\r
+#\r
+# This may be a single attribute, or a string of multiple attributes.  Examples:\r
+#  email - Uses the attribute 'email' on the user record\r
+#  ${givenName}.${surname}@gitblit.com -Will concatenate the 2 attributes\r
+#       together with a '.' and '@' creating something like first.last@gitblit.com \r
+#\r
+# SINCE 1.0.0\r
+realm.ldap.email = email\r
+\r
+# The RedmineUserService must be backed by another user service for standard user\r
+# and team management.\r
+# default: users.conf\r
+#\r
+# RESTART REQUIRED\r
+realm.redmine.backingUserService = test-ui-users.conf\r
+\r
+# URL of the Redmine.\r
+realm.redmine.url = http://example.com/redmine\r
+\r
+#\r
+# Server Settings\r
+#\r
+\r
+# The temporary folder to decompress the embedded gitblit webapp. \r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.tempFolder = ${baseFolder}/temp\r
+\r
+# Use Jetty NIO connectors.  If false, Jetty Socket connectors will be used.\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.useNio = true\r
+\r
+# Context path for the GO application.  You might want to change the context\r
+# path if running Gitblit behind a proxy layer such as mod_proxy.\r
+#\r
+# SINCE 0.7.0\r
+# RESTART REQUIRED\r
+server.contextPath = /\r
+\r
+# Standard http port to serve.  <= 0 disables this connector.\r
+# On Unix/Linux systems, ports < 1024 require root permissions.\r
+# Recommended value: 80 or 8080\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.httpPort = 0\r
+\r
+# Secure/SSL https port to serve. <= 0 disables this connector.\r
+# On Unix/Linux systems, ports < 1024 require root permissions.\r
+# Recommended value: 443 or 8443\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.httpsPort = 8443\r
+\r
+# Port for serving an Apache JServ Protocol (AJP) 1.3 connector for integrating\r
+# Gitblit GO into an Apache HTTP server setup.  <= 0 disables this connector.\r
+# Recommended value: 8009\r
+#\r
+# SINCE 0.9.0\r
+# RESTART REQUIRED\r
+server.ajpPort = 0\r
+\r
+# Specify the interface for Jetty to bind the standard connector.\r
+# You may specify an ip or an empty value to bind to all interfaces.\r
+# Specifying localhost will result in Gitblit ONLY listening to requests to\r
+# localhost.\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.httpBindInterface = localhost\r
+\r
+# Specify the interface for Jetty to bind the secure connector.\r
+# You may specify an ip or an empty value to bind to all interfaces.\r
+# Specifying localhost will result in Gitblit ONLY listening to requests to\r
+# localhost.\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.httpsBindInterface = localhost\r
+\r
+# Specify the interface for Jetty to bind the AJP connector.\r
+# You may specify an ip or an empty value to bind to all interfaces.\r
+# Specifying localhost will result in Gitblit ONLY listening to requests to\r
+# localhost.\r
+#\r
+# SINCE 0.9.0\r
+# RESTART REQUIRED\r
+server.ajpBindInterface = localhost\r
+\r
+# Alias of certificate to use for https/SSL serving.  If blank the first\r
+# certificate found in the keystore will be used. \r
+#\r
+# SINCE 1.2.0\r
+# RESTART REQUIRED\r
+server.certificateAlias = localhost\r
+\r
+# Password for SSL keystore.\r
+# Keystore password and certificate password must match.\r
+# This is provided for convenience, its probably more secure to set this value\r
+# using the --storePassword command line parameter.\r
+#\r
+# If you are using the official JRE or JDK from Oracle you may not have the\r
+# JCE Unlimited Strength Jurisdiction Policy files bundled with your JVM.  Because\r
+# of this, your store/key password can not exceed 7 characters.  If you require\r
+# longer passwords you may need to install the JCE Unlimited Strength Jurisdiction\r
+# Policy files from Oracle.\r
+#\r
+# http://www.oracle.com/technetwork/java/javase/downloads/index.html\r
+#\r
+# Gitblit and the Gitblit Certificate Authority will both indicate if Unlimited\r
+# Strength encryption is available.\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.storePassword = gitblit\r
+\r
+# If serving over https (recommended) you might consider requiring clients to\r
+# authenticate with ssl certificates.  If enabled, only https clients with the\r
+# a valid client certificate will be able to access Gitblit.\r
+#\r
+# If disabled, client certificate authentication is optional and will be tried\r
+# first before falling-back to form authentication or basic authentication.\r
+#\r
+# Requiring client certificates to access any of Gitblit may be too extreme,\r
+# consider this carefully.\r
+#\r
+# SINCE 1.2.0\r
+# RESTART REQUIRED\r
+server.requireClientCertificates = false\r
+\r
+# Port for shutdown monitor to listen on.\r
+#\r
+# SINCE 0.5.0\r
+# RESTART REQUIRED\r
+server.shutdownPort = 8081\r
diff --git a/test-ui-users.conf b/test-ui-users.conf
new file mode 100644 (file)
index 0000000..5bf35f3
--- /dev/null
@@ -0,0 +1,44 @@
+[user "admin"]
+       password = admin
+       cookie = dd94709528bb1c83d08f3088d4043f4742891f4f
+       role = "#admin"
+       role = "#notfederated"
+[user "userthree"]
+       password = StoredInLDAP
+       cookie = d7d3894fc517612aa6c595555b6e1ab8e147e597
+       displayName = User Three
+       emailAddress = userthree@gitblit.com
+       role = "#admin"
+[user "userone"]
+       password = StoredInLDAP
+       cookie = c97cd38e50858cd0b389ec61b18fb9a89b4da54c
+       displayName = User One
+       emailAddress = User.One@gitblit.com
+       role = "#admin"
+[user "usertwo"]
+       password = StoredInLDAP
+       cookie = 498ca9bd2841d39050fa45d1d737b9f9f767858d
+       displayName = User Two
+       emailAddress = usertwo@gitblit.com
+       role = "#admin"
+[user "basic"]
+       password = MD5:f17aaabc20bfe045075927934fed52d2
+       cookie = dd94709528bb1c83d08f3088d4043f4742891f4f
+       role = "#fork"
+       repository = RW:~repocreator/shb.git
+       repository = V:test/gitective.git
+[user "repocreator"]
+       password = MD5:b77e53bb561c47368d133b22e285f60b
+       cookie = dd94709528bb1c83d08f3088d4043f4742891f4f
+       role = "#create"
+[team "Git_Admins"]
+       role = "#none"
+       user = userone
+[team "Git_Users"]
+       role = "#none"
+       user = userone
+       user = usertwo
+       user = userthree
+[team "Git Admins"]
+       role = "#none"
+       user = usertwo
diff --git a/tests/de/akquinet/devops/GitblitRunnable.java b/tests/de/akquinet/devops/GitblitRunnable.java
new file mode 100644 (file)
index 0000000..fc08f5a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops;
+
+import java.net.InetAddress;
+import java.net.ServerSocket;
+
+import com.gitblit.GitBlitServer;
+import com.gitblit.tests.GitBlitSuite;
+
+/**
+ * This is a runnable implementation, that is used to run a gitblit server in a
+ * separate thread (e.g. alongside test cases)
+ * 
+ * @author saheba
+ * 
+ */
+public class GitblitRunnable implements Runnable {
+
+       private int httpPort, httpsPort, shutdownPort;
+       private String userPropertiesPath, gitblitPropertiesPath;
+       private boolean startFailed = false;
+
+       /**
+        * constructor with reduced set of start params
+        * 
+        * @param httpPort
+        * @param httpsPort
+        * @param shutdownPort
+        * @param gitblitPropertiesPath
+        * @param userPropertiesPath
+        */
+       public GitblitRunnable(int httpPort, int httpsPort, int shutdownPort,
+                       String gitblitPropertiesPath, String userPropertiesPath) {
+               this.httpPort = httpPort;
+               this.httpsPort = httpsPort;
+               this.shutdownPort = shutdownPort;
+               this.userPropertiesPath = userPropertiesPath;
+               this.gitblitPropertiesPath = gitblitPropertiesPath;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see java.lang.Runnable#run()
+        */
+       public void run() {
+               boolean portsFree = false;
+               long lastRun = -1;
+               while (!portsFree) {
+                       long current = System.currentTimeMillis();
+                       if (lastRun == -1 || lastRun + 100 < current) {
+                               portsFree = areAllPortsFree(new int[] { httpPort, httpsPort,
+                                               shutdownPort }, "127.0.0.1");
+                       }
+                       lastRun = current;
+
+               }
+               try {
+                       GitBlitServer.main("--httpPort", "" + httpPort, "--httpsPort", ""
+                                       + httpsPort, "--shutdownPort", "" + shutdownPort,
+                                       "--repositoriesFolder",
+                                       "\"" + GitBlitSuite.REPOSITORIES.getAbsolutePath() + "\"",
+                                       "--userService", userPropertiesPath, "--settings",
+                                       gitblitPropertiesPath);
+                       setStartFailed(false);
+               } catch (Exception iex) {
+                       System.out.println("Gitblit server start failed");
+                       setStartFailed(true);
+               }
+       }
+
+       /**
+        * Method used to ensure that all ports are free, if the runnable is used
+        * JUnit test classes. Be aware that JUnit's setUpClass and tearDownClass
+        * methods, which are executed before and after a test class (consisting of
+        * several test cases), may be executed parallely if they are part of a test
+        * suite consisting of several test classes. Therefore the run method of
+        * this class calls areAllPortsFree to check port availability before
+        * starting another gitblit instance.
+        * 
+        * @param ports
+        * @param inetAddress
+        * @return
+        */
+       public static boolean areAllPortsFree(int[] ports, String inetAddress) {
+               System.out
+                               .println("\n"
+                                               + System.currentTimeMillis()
+                                               + " ----------------------------------- testing if all ports are free ...");
+               String blockedPorts = "";
+               for (int i = 0; i < ports.length; i++) {
+                       ServerSocket s;
+                       try {
+                               s = new ServerSocket(ports[i], 1,
+                                               InetAddress.getByName(inetAddress));
+                               s.close();
+                       } catch (Exception e) {
+                               if (!blockedPorts.equals("")) {
+                                       blockedPorts += ", ";
+                               }
+                       }
+               }
+               if (blockedPorts.equals("")) {
+                       System.out
+                                       .println(" ----------------------------------- ... verified");
+                       return true;
+               }
+               System.out.println(" ----------------------------------- ... "
+                               + blockedPorts + " are still blocked");
+               return false;
+       }
+
+       private void setStartFailed(boolean startFailed) {
+               this.startFailed = startFailed;
+       }
+
+       public boolean isStartFailed() {
+               return startFailed;
+       }
+}
diff --git a/tests/de/akquinet/devops/LaunchWithUITestConfig.java b/tests/de/akquinet/devops/LaunchWithUITestConfig.java
new file mode 100644 (file)
index 0000000..594d7fc
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlitServer;
+import com.gitblit.tests.GitBlitSuite;
+
+/**
+ * This test checks if it is possible to run two server instances in the same
+ * JVM sequentially
+ * 
+ * @author saheba
+ * 
+ */
+public class LaunchWithUITestConfig {
+
+       @Test
+       public void testSequentialLaunchOfSeveralInstances()
+                       throws InterruptedException {
+               // different ports than in testParallelLaunchOfSeveralInstances to
+               // ensure that both test cases do not affect each others test results
+               int httpPort = 9191, httpsPort = 9292, shutdownPort = 9393;
+               String gitblitPropertiesPath = "test-ui-gitblit.properties", usersPropertiesPath = "test-ui-users.conf";
+
+               GitblitRunnable gitblitRunnable = new GitblitRunnable(httpPort,
+                               httpsPort, shutdownPort, gitblitPropertiesPath,
+                               usersPropertiesPath);
+               Thread serverThread = new Thread(gitblitRunnable);
+               serverThread.start();
+               Thread.sleep(2000);
+               Assert.assertFalse(gitblitRunnable.isStartFailed());
+               LaunchWithUITestConfig.shutdownGitBlitServer(shutdownPort);
+
+               Thread.sleep(5000);
+
+               GitblitRunnable gitblitRunnable2 = new GitblitRunnable(httpPort,
+                               httpsPort, shutdownPort, gitblitPropertiesPath,
+                               usersPropertiesPath);
+               Thread serverThread2 = new Thread(gitblitRunnable2);
+               serverThread2.start();
+               Thread.sleep(2000);
+               Assert.assertFalse(gitblitRunnable2.isStartFailed());
+               LaunchWithUITestConfig.shutdownGitBlitServer(shutdownPort);
+       }
+
+       @Test
+       public void testParallelLaunchOfSeveralInstances()
+                       throws InterruptedException {
+               // different ports than in testSequentialLaunchOfSeveralInstances to
+               // ensure that both test cases do not affect each others test results
+               int httpPort = 9797, httpsPort = 9898, shutdownPort = 9999;
+               int httpPort2 = 9494, httpsPort2 = 9595, shutdownPort2 = 9696;
+               String gitblitPropertiesPath = "test-ui-gitblit.properties", usersPropertiesPath = "test-ui-users.conf";
+
+               GitblitRunnable gitblitRunnable = new GitblitRunnable(httpPort,
+                               httpsPort, shutdownPort, gitblitPropertiesPath,
+                               usersPropertiesPath);
+               Thread serverThread = new Thread(gitblitRunnable);
+               serverThread.start();
+               Thread.sleep(2000);
+               Assert.assertFalse(gitblitRunnable.isStartFailed());
+
+               GitblitRunnable gitblitRunnable2 = new GitblitRunnable(httpPort2,
+                               httpsPort2, shutdownPort2, gitblitPropertiesPath,
+                               usersPropertiesPath);
+               Thread serverThread2 = new Thread(gitblitRunnable2);
+               serverThread2.start();
+               Thread.sleep(2000);
+               Assert.assertFalse(gitblitRunnable2.isStartFailed());
+
+               LaunchWithUITestConfig.shutdownGitBlitServer(shutdownPort);
+               LaunchWithUITestConfig.shutdownGitBlitServer(shutdownPort2);
+       }
+
+       /**
+        * main runs the tests without assert checks. You have to check the console
+        * output manually.
+        * 
+        * @param args
+        * @throws InterruptedException
+        */
+       public static void main(String[] args) throws InterruptedException {
+               new LaunchWithUITestConfig().testSequentialLaunchOfSeveralInstances();
+               new LaunchWithUITestConfig().testParallelLaunchOfSeveralInstances();
+       }
+
+       private static void shutdownGitBlitServer(int shutdownPort) {
+               try {
+                       Socket s = new Socket(InetAddress.getByName("127.0.0.1"),
+                                       shutdownPort);
+                       OutputStream out = s.getOutputStream();
+                       System.out.println("Sending Shutdown Request to " + Constants.NAME);
+                       out.write("\r\n".getBytes());
+                       out.flush();
+                       s.close();
+               } catch (UnknownHostException e) {
+                       e.printStackTrace();
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+       }
+}
diff --git a/tests/de/akquinet/devops/ManualUITestLaunch.java b/tests/de/akquinet/devops/ManualUITestLaunch.java
new file mode 100644 (file)
index 0000000..2eff491
--- /dev/null
@@ -0,0 +1,14 @@
+package de.akquinet.devops;
+
+public class ManualUITestLaunch {
+public static void main(String[] args) {
+       int httpPort = 8080, httpsPort = 8443, shutdownPort = 8081;
+       String gitblitPropertiesPath = "test-ui-gitblit.properties", usersPropertiesPath = "test-ui-users.conf";
+
+       GitblitRunnable gitblitRunnable = new GitblitRunnable(httpPort,
+                       httpsPort, shutdownPort, gitblitPropertiesPath,
+                       usersPropertiesPath);
+       Thread serverThread = new Thread(gitblitRunnable);
+       serverThread.start();
+}
+}
diff --git a/tests/de/akquinet/devops/test/ui/TestUISuite.java b/tests/de/akquinet/devops/test/ui/TestUISuite.java
new file mode 100644 (file)
index 0000000..97bd903
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+import de.akquinet.devops.test.ui.cases.UI_MultiAdminSupportTest;
+
+/**
+ * the test suite including all selenium-based ui-tests.
+ * 
+ * @author saheba
+ *
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({ UI_MultiAdminSupportTest.class })
+public class TestUISuite {
+
+}
diff --git a/tests/de/akquinet/devops/test/ui/cases/UI_MultiAdminSupportTest.java b/tests/de/akquinet/devops/test/ui/cases/UI_MultiAdminSupportTest.java
new file mode 100644 (file)
index 0000000..9cdad16
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui.cases;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import de.akquinet.devops.test.ui.generic.AbstractUITest;
+import de.akquinet.devops.test.ui.view.RepoEditView;
+import de.akquinet.devops.test.ui.view.RepoListView;
+
+/**
+ * tests the multi admin per repo feature.
+ * 
+ * @author saheba
+ * 
+ */
+public class UI_MultiAdminSupportTest extends AbstractUITest {
+
+       String baseUrl = "https://localhost:8443";
+       RepoListView view;
+       RepoEditView editView;
+       private static final String TEST_MULTI_ADMIN_SUPPORT_REPO_NAME = "testmultiadminsupport";
+       private static final String TEST_MULTI_ADMIN_SUPPORT_REPO_PATH = "~repocreator/"
+                       + TEST_MULTI_ADMIN_SUPPORT_REPO_NAME + ".git";
+       private static final String TEST_MULTI_ADMIN_SUPPORT_REPO_PATH_WITHOUT_SUFFIX = "~repocreator/"
+                       + TEST_MULTI_ADMIN_SUPPORT_REPO_NAME;
+
+       @Before
+       public void before() {
+               System.out.println("IN BEFORE");
+               this.view = new RepoListView(AbstractUITest.getDriver(), baseUrl);
+               this.editView = new RepoEditView(AbstractUITest.getDriver());
+               AbstractUITest.getDriver().navigate().to(baseUrl);
+       }
+
+       @Test
+       public void test_MultiAdminSelectionInStandardRepo() {
+               // login
+               view.login("repocreator", "repocreator");
+
+               // create new repo
+               view.navigateToNewRepo(1);
+               editView.changeName(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH);
+               Assert.assertTrue(editView.navigateToPermissionsTab());
+
+               Assert.assertTrue(editView
+                               .changeAccessRestriction(RepoEditView.RESTRICTION_AUTHENTICATED_VCP));
+               Assert.assertTrue(editView
+                               .changeAuthorizationControl(RepoEditView.AUTHCONTROL_RWALL));
+
+               // with a second admin
+               editView.addRepoAdministrator("admin");
+               Assert.assertTrue(editView.save());
+               // user is automatically forwarded to repo list view
+               Assert.assertTrue(view.isEmptyRepo(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH));
+               Assert.assertTrue(view
+                               .isEditableRepo(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH));
+               Assert.assertTrue(view
+                               .isDeletableRepo(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH_WITHOUT_SUFFIX));
+               // logout repocreator
+               view.logout();
+
+               // check with admin account if second admin has the same rights
+               view.login("admin", "admin");
+               Assert.assertTrue(view.isEmptyRepo(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH));
+               Assert.assertTrue(view
+                               .isEditableRepo(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH));
+               Assert.assertTrue(view
+                               .isDeletableRepo(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH_WITHOUT_SUFFIX));
+               // delete repo to reach state as before test execution
+               view.navigateToDeleteRepo(TEST_MULTI_ADMIN_SUPPORT_REPO_PATH_WITHOUT_SUFFIX);
+               view.acceptAlertDialog();
+               view.logout();
+
+               Assert.assertTrue(view.isLoginPartVisible());
+       }
+
+}
diff --git a/tests/de/akquinet/devops/test/ui/generic/AbstractUITest.java b/tests/de/akquinet/devops/test/ui/generic/AbstractUITest.java
new file mode 100644 (file)
index 0000000..bb7b3da
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui.generic;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.firefox.FirefoxDriver;
+import org.openqa.selenium.firefox.FirefoxProfile;
+
+import com.gitblit.GitBlitServer;
+
+import de.akquinet.devops.GitblitRunnable;
+
+/**
+ * This abstract class implements the setUpClass and tearDownClass for
+ * selenium-based UITests. They require a running gitblit server instance and a
+ * webdriver instance, which are managed by the setUpClass and tearDownClass
+ * method. Write a separate test class derived from this abstract class for each
+ * scenario consisting of one or more test cases, which can share the same
+ * server instance.
+ * 
+ * @author saheba
+ * 
+ */
+public abstract class AbstractUITest {
+
+       private static Thread serverThread;
+       private static WebDriver driver;
+
+       private static final int HTTP_PORT = 8080, HTTPS_PORT = 8443,
+                       SHUTDOWN_PORT = 8081;
+       private static final String GITBLIT_PROPERTIES_PATH = "test-ui-gitblit.properties",
+                       USERS_PROPERTIES_PATH = "test-ui-users.conf";
+
+       /**
+        * starts a gitblit server instance in a separate thread before test cases
+        * of concrete, non-abstract child-classes are executed
+        */
+       @BeforeClass
+       public static void setUpClass() {
+               Runnable gitblitRunnable = new GitblitRunnable(HTTP_PORT, HTTPS_PORT,
+                               SHUTDOWN_PORT, GITBLIT_PROPERTIES_PATH, USERS_PROPERTIES_PATH);
+
+               serverThread = new Thread(gitblitRunnable);
+               serverThread.start();
+               FirefoxProfile firefoxProfile = new FirefoxProfile();
+               firefoxProfile.setPreference("startup.homepage_welcome_url",
+                               "https://www.google.de");
+
+               firefoxProfile.setPreference("browser.download.folderList", 2);
+               firefoxProfile.setPreference(
+                               "browser.download.manager.showWhenStarting", false);
+               String downloadDir = System.getProperty("java.io.tmpdir");
+               firefoxProfile.setPreference("browser.download.dir", downloadDir);
+               firefoxProfile.setPreference("browser.helperApps.neverAsk.saveToDisk",
+                               "text/csv,text/plain,application/zip,application/pdf");
+               firefoxProfile.setPreference("browser.helperApps.alwaysAsk.force",
+                               false);
+               System.out.println("Saving all attachments to: " + downloadDir);
+
+               driver = new FirefoxDriver(firefoxProfile);
+       }
+
+       /**
+        * stops the gitblit server instance running in a separate thread after test
+        * cases of concrete, non-abstract child-classes have been executed
+        */
+       @AfterClass
+       public static void tearDownClass() throws InterruptedException {
+               driver.close();
+               // Stop Gitblit
+               GitBlitServer.main("--stop", "--shutdownPort", "" + SHUTDOWN_PORT);
+
+               // Wait a few seconds for it to be running completely including thread
+               // destruction
+               Thread.sleep(1000);
+       }
+
+       public static WebDriver getDriver() {
+               return AbstractUITest.driver;
+       }
+}
diff --git a/tests/de/akquinet/devops/test/ui/view/Exp.java b/tests/de/akquinet/devops/test/ui/view/Exp.java
new file mode 100644 (file)
index 0000000..3433bbb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui.view;
+
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+
+/**
+ * container class for selenium conditions
+ * 
+ * @author saheba
+ *
+ */
+public class Exp {
+       public static class EditRepoViewLoaded implements ExpectedCondition<Boolean> {
+               public Boolean apply(WebDriver d) {
+                       List<WebElement> findElements = d.findElements(By.partialLinkText("general"));
+                       return findElements.size() == 1;
+               }
+       }
+       public static class RepoListViewLoaded implements ExpectedCondition<Boolean> {
+               public Boolean apply(WebDriver d) {
+                       String xpath = "//img[@src=\"git-black-16x16.png\"]";
+                       List<WebElement> findElements = d.findElements(By.xpath(xpath ));
+                       return findElements.size() == 1;
+               }
+       }
+}
diff --git a/tests/de/akquinet/devops/test/ui/view/GitblitDashboardView.java b/tests/de/akquinet/devops/test/ui/view/GitblitDashboardView.java
new file mode 100644 (file)
index 0000000..0908d7c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui.view;
+
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ * class representing the view componenents and possible user interactions, you
+ * can see and do on most screens when you are logged in.
+ * 
+ * @author saheba
+ * 
+ */
+public class GitblitDashboardView extends GitblitPageView {
+
+       public static final String TITLE_STARTS_WITH = "localhost";
+
+       public GitblitDashboardView(WebDriver driver, String baseUrl) {
+               super(driver, baseUrl);
+       }
+
+       public boolean isLoginPartVisible() {
+               List<WebElement> found = getDriver().findElements(
+                               By.partialLinkText("logout"));
+               return found == null || found.size() == 0;
+       }
+
+       public void logout() {
+               // String pathLogout = "//a[@href =\"?" + WICKET_HREF_PAGE_PATH
+               // + ".LogoutPage\"]";
+               // List<WebElement> logout =
+               // getDriver().findElements(By.xpath(pathLogout));
+               // logout.get(0).click();
+               // replaced by url call because click hangs sometimes if the clicked
+               // object is not a button or selenium ff driver does not notice the
+               // change for any other reason
+               getDriver().navigate().to(
+                               getBaseUrl() + "?" + WICKET_HREF_PAGE_PATH + ".LogoutPage");
+       }
+
+       public static final String LOGIN_AREA_SELECTOR = "//span[@class = \"form-search\" ]";
+       public static final String WICKET_PAGES_PACKAGE_NAME = "com.gitblit.wicket.pages";
+       public static final String WICKET_HREF_PAGE_PATH = "wicket:bookmarkablePage=:"
+                       + WICKET_PAGES_PACKAGE_NAME;
+
+       synchronized public void waitToLoadFor(int sec) {
+               WebDriverWait webDriverWait = new WebDriverWait(getDriver(), sec);
+               webDriverWait.until(new ExpectedCondition<Boolean>() {
+                       public Boolean apply(WebDriver d) {
+                               return d.getTitle().toLowerCase()
+                                               .startsWith(GitblitDashboardView.TITLE_STARTS_WITH);
+                       }
+               });
+       }
+
+       public void login(String id, String pw) {
+               String pathID = LOGIN_AREA_SELECTOR + "/input[@name = \"username\" ]";
+               String pathPW = LOGIN_AREA_SELECTOR + "/input[@name = \"password\" ]";
+               String pathSubmit = LOGIN_AREA_SELECTOR
+                               + "/button[@type = \"submit\" ]";
+               // System.out.println("DRIVER:"+getDriver());
+               // List<WebElement> findElement =
+               // getDriver().findElements(By.xpath("//span[@class = \"form-search\" ]"));
+               //
+               // System.out.println("ELEM: "+findElement);
+               // System.out.println("SIZE: "+findElement.size());
+               // System.out.println("XPath: "+pathID);
+               WebElement idField = getDriver().findElement(By.xpath(pathID));
+               // System.out.println("IDFIELD:"+idField);
+               idField.sendKeys(id);
+               WebElement pwField = getDriver().findElement(By.xpath(pathPW));
+               // System.out.println(pwField);
+               pwField.sendKeys(pw);
+               WebElement submit = getDriver().findElement(By.xpath(pathSubmit));
+               submit.click();
+       }
+
+       public void acceptAlertDialog() {
+               getDriver().switchTo().alert().accept();
+       }
+}
diff --git a/tests/de/akquinet/devops/test/ui/view/GitblitPageView.java b/tests/de/akquinet/devops/test/ui/view/GitblitPageView.java
new file mode 100644 (file)
index 0000000..4371643
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui.view;
+
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+/**
+ * general basic class representing a gitblit webpage and offering basic methods
+ * used in selenium tests.
+ * 
+ * @author saheba
+ * 
+ */
+public class GitblitPageView {
+       private WebDriver driver;
+       private String baseUrl;
+
+       public GitblitPageView(WebDriver driver, String baseUrl) {
+               this.driver = driver;
+               this.baseUrl = baseUrl;
+       }
+
+       public void sleep(int miliseconds) {
+               try {
+                       Thread.sleep(miliseconds);
+               } catch (InterruptedException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public WebElement getElementWithFocus() {
+               String elScript = "return document.activeElement;";
+
+               WebElement focuseedEl = (WebElement) ((JavascriptExecutor) getDriver())
+                               .executeScript(elScript);
+               return focuseedEl;
+       }
+
+       public void navigateToPreviousPageOfBrowserHistory() {
+               driver.navigate().back();
+       }
+
+       public void setDriver(WebDriver driver) {
+               this.driver = driver;
+       }
+
+       public WebDriver getDriver() {
+               return driver;
+       }
+
+       public void setBaseUrl(String baseUrl) {
+               this.baseUrl = baseUrl;
+       }
+
+       public String getBaseUrl() {
+               return baseUrl;
+       }
+}
diff --git a/tests/de/akquinet/devops/test/ui/view/RepoEditView.java b/tests/de/akquinet/devops/test/ui/view/RepoEditView.java
new file mode 100644 (file)
index 0000000..ef0a317
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui.view;
+
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ * class representing the tabs you can access when you edit a repo.
+ * 
+ * @author saheba
+ * 
+ */
+public class RepoEditView extends GitblitDashboardView {
+
+       public static final String PERMISSION_VIEW_USERS_NAME_PREFIX = "users:";
+       public static final String PERMISSION_VIEW_TEAMS_NAME_PREFIX = "teams:";
+
+       public static final String PERMISSION_VIEW_MUTABLE = "permissionToggleForm:showMutable";
+       public static final String PERMISSION_VIEW_SPECIFIED = "permissionToggleForm:showSpecified";
+       public static final String PERMISSION_VIEW_EFFECTIVE = "permissionToggleForm:showEffective";
+
+       public static final int RESTRICTION_ANONYMOUS_VCP = 0;
+       public static final int RESTRICTION_AUTHENTICATED_P = 1;
+       public static final int RESTRICTION_AUTHENTICATED_CP = 2;
+       public static final int RESTRICTION_AUTHENTICATED_VCP = 3;
+
+       public static final int AUTHCONTROL_RWALL = 0;
+       public static final int AUTHOCONTROL_FINE = 1;
+
+       public RepoEditView(WebDriver driver) {
+               super(driver, null);
+       }
+
+       public void changeName(String newName) {
+               String pathName = "//input[@id = \"name\" ]";
+               WebElement field = getDriver().findElement(By.xpath(pathName));
+               field.clear();
+               field.sendKeys(newName);
+       }
+
+       public boolean navigateToPermissionsTab() {
+               String linkText = "access permissions";
+               List<WebElement> found = getDriver().findElements(
+                               By.partialLinkText(linkText));
+               System.out.println("PERM TABS found =" + found.size());
+               if (found != null && found.size() == 1) {
+                       found.get(0).click();
+                       return true;
+               }
+               return false;
+       }
+
+       private void changeRepoAdministrators(String action,
+                       String affectedSelection, String username) {
+               String xpath = "//select[@name=\"" + affectedSelection
+                               + "\"]/option[@value = \"" + username + "\" ]";
+               WebElement option = getDriver().findElement(By.xpath(xpath));
+               option.click();
+               String buttonPath = "//button[@class=\"button " + action + "\"]";
+               WebElement button = getDriver().findElement(By.xpath(buttonPath));
+               button.click();
+       }
+
+       public void removeRepoAdministrator(String username) {
+               changeRepoAdministrators("remove", "repoAdministrators:selection",
+                               username);
+       }
+
+       public void addRepoAdministrator(String username) {
+               changeRepoAdministrators("add", "repoAdministrators:choices", username);
+       }
+
+       public WebElement getAccessRestrictionSelection() {
+               String xpath = "//select[@name =\"accessRestriction\"]";
+               List<WebElement> found = getDriver().findElements(By.xpath(xpath));
+               if (found != null && found.size() == 1) {
+                       return found.get(0);
+               }
+               return null;
+       }
+
+       public boolean changeAccessRestriction(int option) {
+               WebElement accessRestrictionSelection = getAccessRestrictionSelection();
+               if (accessRestrictionSelection == null) {
+                       return false;
+               }
+               accessRestrictionSelection.click();
+               sleep(100);
+               String xpath = "//select[@name =\"accessRestriction\"]/option[@value=\""
+                               + option + "\"]";
+               List<WebElement> found = getDriver().findElements(By.xpath(xpath));
+               if (found == null || found.size() == 0 || found.size() > 1) {
+                       return false;
+               }
+               found.get(0).click();
+               return true;
+       }
+
+       public boolean changeAuthorizationControl(int option) {
+               System.out.println("try to change auth control");
+               String xpath = "//input[@name =\"authorizationControl\" and @value=\""
+                               + option + "\"]";
+               List<WebElement> found = getDriver().findElements(By.xpath(xpath));
+               System.out.println("found auth CONTROL options " + found.size());
+               if (found == null || found.size() == 0 || found.size() > 1) {
+                       return false;
+               }
+               found.get(0).click();
+               return true;
+       }
+
+       private boolean isPermissionViewDisabled(String prefix, String view) {
+               String xpath = "//[@name =\"" + prefix + view + "\"]";
+               List<WebElement> found = getDriver().findElements(By.xpath(xpath));
+               if (found == null || found.size() == 0 || found.size() > 1) {
+                       return false;
+               }
+               String attrValue = found.get(0).getAttribute("disabled");
+               return (attrValue != null) && (attrValue.equals("disabled"));
+       }
+
+       public boolean isPermissionViewSectionDisabled(String prefix) {
+               return isPermissionViewDisabled(prefix, PERMISSION_VIEW_MUTABLE)
+                               && isPermissionViewDisabled(prefix, PERMISSION_VIEW_SPECIFIED)
+                               && isPermissionViewDisabled(prefix, PERMISSION_VIEW_EFFECTIVE);
+       }
+
+       public boolean save() {
+               String xpath = "//div[@class=\"form-actions\"]/input[@name =\""
+                               + "save" + "\"]";
+               List<WebElement> found = getDriver().findElements(By.xpath(xpath));
+               if (found == null || found.size() == 0 || found.size() > 1) {
+                       return false;
+               }
+               found.get(0).click();
+               WebDriverWait webDriverWait = new WebDriverWait(getDriver(), 1);
+               webDriverWait.until(new Exp.RepoListViewLoaded());
+               return true;
+       }
+}
diff --git a/tests/de/akquinet/devops/test/ui/view/RepoListView.java b/tests/de/akquinet/devops/test/ui/view/RepoListView.java
new file mode 100644 (file)
index 0000000..6ec6203
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2013 akquinet tech@spree GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.akquinet.devops.test.ui.view;
+
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ * class representing the repo list view, which you see e.g. right after you
+ * logged in.
+ * 
+ * @author saheba
+ * 
+ */
+public class RepoListView extends GitblitDashboardView {
+
+       public RepoListView(WebDriver driver, String baseUrl) {
+               super(driver, baseUrl);
+       }
+       
+       public boolean isEmptyRepo(String fullyQualifiedRepoName) {
+               String pathToLink = "//a[@href = \"?" + WICKET_HREF_PAGE_PATH
+                               + ".EmptyRepositoryPage&r=" + fullyQualifiedRepoName + "\"]";
+               List<WebElement> found = getDriver().findElements(By.xpath(pathToLink));
+               return found != null && found.size() > 0;
+       }
+
+       private String getEditRepoPath(String fullyQualifiedRepoName) {
+               return "//a[@href =\"?" + WICKET_HREF_PAGE_PATH
+                               + ".EditRepositoryPage&r=" + fullyQualifiedRepoName + "\"]";
+       }
+
+       private String getDeleteRepoOnclickIdentifier(
+                       String fullyQualifiedRepoPathAndName) {
+               return "var conf = confirm('Delete repository \""
+                               + fullyQualifiedRepoPathAndName
+                               + "\"?'); if (!conf) return false; ";
+       }
+
+       public boolean navigateToNewRepo(long waitSecToLoad) {
+               String pathToLink = "//a[@href =\"?" + WICKET_HREF_PAGE_PATH
+                               + ".EditRepositoryPage\"]";
+               List<WebElement> found = getDriver().findElements(By.xpath(pathToLink));
+               if (found == null || found.size() == 0 || found.size() > 1) {
+                       return false;
+               }
+               found.get(0).click();
+               WebDriverWait webDriverWait = new WebDriverWait(getDriver(),
+                               waitSecToLoad);
+               webDriverWait.until(new Exp.EditRepoViewLoaded());
+               return true;
+       }
+
+       private boolean checkOrDoEditRepo(String fullyQualifiedRepoName,
+                       boolean doEdit) {
+               List<WebElement> found = getDriver().findElements(
+                               By.xpath(getEditRepoPath(fullyQualifiedRepoName)));
+               if (found == null || found.size() == 0 || found.size() > 1) {
+                       return false;
+               }
+               if (doEdit) {
+                       found.get(0).click();
+               }
+               return true;
+       }
+
+       public boolean navigateToEditRepo(String fullyQualifiedRepoName,
+                       int waitSecToLoad) {
+               boolean result = checkOrDoEditRepo(fullyQualifiedRepoName, true);
+               WebDriverWait webDriverWait = new WebDriverWait(getDriver(),
+                               waitSecToLoad);
+               webDriverWait.until(new Exp.EditRepoViewLoaded());
+               return result;
+       }
+
+       public boolean isEditableRepo(String fullyQualifiedRepoName) {
+               return checkOrDoEditRepo(fullyQualifiedRepoName, false);
+       }
+
+       private boolean checkOrDoDeleteRepo(String fullyQualifiedRepoPathAndName,
+                       boolean doDelete) {
+               List<WebElement> found = getDriver().findElements(
+                               By.partialLinkText("delete"));
+               String onclickIdentifier = getDeleteRepoOnclickIdentifier(fullyQualifiedRepoPathAndName);
+               WebElement result = null;
+               for (WebElement webElement : found) {
+                       if (webElement.getAttribute("onclick") != null
+                                       && webElement.getAttribute("onclick").equals(
+                                                       onclickIdentifier)) {
+                               result = webElement;
+                               break;
+                       }
+               }
+               System.out.println("result ? " + result);
+               if (result == null) {
+                       return false;
+               }
+               if (doDelete) {
+                       System.out.println(".............. DO DELETE .... ");
+                       result.click();
+               }
+               return true;
+       }
+
+       public boolean isDeletableRepo(String fullyQualifiedRepoPathAndName) {
+               return checkOrDoDeleteRepo(fullyQualifiedRepoPathAndName, false);
+       }
+
+       public boolean navigateToDeleteRepo(String fullyQualifiedRepoPathAndName) {
+               return checkOrDoDeleteRepo(fullyQualifiedRepoPathAndName, true);
+
+       }
+}