From 795b227ed376f6ea9a6e13952a79770f33766266 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 23 Jan 2013 08:30:28 -0500 Subject: [PATCH] Merged selenium tests from akquinet (pull request #65) --- .classpath | 12 + src/com/gitblit/build/Build.java | 114 +- test-ui-gitblit.properties | 1203 +++++++++++++++++ test-ui-users.conf | 44 + tests/de/akquinet/devops/GitblitRunnable.java | 134 ++ .../devops/LaunchWithUITestConfig.java | 126 ++ .../akquinet/devops/ManualUITestLaunch.java | 14 + .../akquinet/devops/test/ui/TestUISuite.java | 33 + .../ui/cases/UI_MultiAdminSupportTest.java | 93 ++ .../test/ui/generic/AbstractUITest.java | 96 ++ .../de/akquinet/devops/test/ui/view/Exp.java | 45 + .../test/ui/view/GitblitDashboardView.java | 100 ++ .../devops/test/ui/view/GitblitPageView.java | 73 + .../devops/test/ui/view/RepoEditView.java | 158 +++ .../devops/test/ui/view/RepoListView.java | 130 ++ 15 files changed, 2371 insertions(+), 4 deletions(-) create mode 100644 test-ui-gitblit.properties create mode 100644 test-ui-users.conf create mode 100644 tests/de/akquinet/devops/GitblitRunnable.java create mode 100644 tests/de/akquinet/devops/LaunchWithUITestConfig.java create mode 100644 tests/de/akquinet/devops/ManualUITestLaunch.java create mode 100644 tests/de/akquinet/devops/test/ui/TestUISuite.java create mode 100644 tests/de/akquinet/devops/test/ui/cases/UI_MultiAdminSupportTest.java create mode 100644 tests/de/akquinet/devops/test/ui/generic/AbstractUITest.java create mode 100644 tests/de/akquinet/devops/test/ui/view/Exp.java create mode 100644 tests/de/akquinet/devops/test/ui/view/GitblitDashboardView.java create mode 100644 tests/de/akquinet/devops/test/ui/view/GitblitPageView.java create mode 100644 tests/de/akquinet/devops/test/ui/view/RepoEditView.java create mode 100644 tests/de/akquinet/devops/test/ui/view/RepoListView.java diff --git a/.classpath b/.classpath index e40223d2..365b6d44 100644 --- a/.classpath +++ b/.classpath @@ -38,6 +38,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/com/gitblit/build/Build.java b/src/com/gitblit/build/Build.java index ecc072af..21c16298 100644 --- a/src/com/gitblit/build/Build.java +++ b/src/com/gitblit/build/Build.java @@ -109,6 +109,20 @@ public class Build { downloadFromApache(MavenObject.COMMONS_COMPRESS, BuildType.RUNTIME); downloadFromApache(MavenObject.XZ, BuildType.RUNTIME); + //needed for selenium ui tests + downloadFromApacheToExtSelenium(MavenObject.SEL_API, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_FF, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_JAVA, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_REMOTE, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_SUPPORT, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.GUAVA, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.JSON, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.COMMONS_EXEC, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.HTTPCLIENT, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.HTTPCORE, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.HTTPMIME, BuildType.RUNTIME); + downloadFromApacheToExtSelenium(MavenObject.COMMONS_LOGGING, BuildType.RUNTIME); + downloadFromEclipse(MavenObject.JGIT, BuildType.RUNTIME); downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.RUNTIME); } @@ -148,6 +162,20 @@ public class Build { downloadFromApache(MavenObject.COMMONS_COMPRESS, BuildType.COMPILETIME); downloadFromApache(MavenObject.XZ, BuildType.COMPILETIME); + //needed for selenium ui tests + downloadFromApacheToExtSelenium(MavenObject.SEL_API, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_FF, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_JAVA, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_REMOTE, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.SEL_SUPPORT, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.GUAVA, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.JSON, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.COMMONS_EXEC, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.HTTPCLIENT, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.HTTPCORE, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.HTTPMIME, BuildType.COMPILETIME); + downloadFromApacheToExtSelenium(MavenObject.COMMONS_LOGGING, BuildType.COMPILETIME); + downloadFromEclipse(MavenObject.JGIT, BuildType.COMPILETIME); downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.COMPILETIME); @@ -217,7 +245,7 @@ public class Build { Properties properties = new Properties(); FileInputStream is = null; try { - is = new FileInputStream(new File("distrib", Constants.PROPERTIES_FILE)); + is = new FileInputStream(Constants.PROPERTIES_FILE); properties.load(is); } catch (Throwable t) { t.printStackTrace(); @@ -398,7 +426,7 @@ public class Build { * the maven object to download. * @return */ - private static List downloadFromMaven(String mavenRoot, MavenObject mo, BuildType type) { + private static List downloadFromMaven(String mavenRoot, MavenObject mo, BuildType type, String targetFolder) { List downloads = new ArrayList(); String[] jars = { "" }; if (BuildType.RUNTIME.equals(type)) { @@ -407,9 +435,9 @@ public class Build { jars = new String[] { "-sources" }; } for (String jar : jars) { - File targetFile = mo.getLocalFile("ext", jar); + File targetFile = mo.getLocalFile(targetFolder, jar); if ("-sources".equals(jar)) { - File relocated = new File("ext/src", targetFile.getName()); + File relocated = new File(targetFolder+"/src", targetFile.getName()); if (targetFile.exists()) { // move -sources jar to ext/src folder targetFile.renameTo(relocated); @@ -502,6 +530,31 @@ public class Build { return downloads; } + /** + * Download a file from the official Apache Maven repository. + * + * @param mo + * the maven object to download. + * @return + */ + private static List downloadFromApacheToExtSelenium(MavenObject mo, + BuildType type) { + return downloadFromMaven("http://repo1.maven.org/maven2/", mo, type, + "ext/seleniumhq"); + } + + /** + * Download a file from the official Apache Maven repository. + * + * @param mo + * the maven object to download. + * @return + */ + private static List downloadFromMaven(String mavenRoot, + MavenObject mo, BuildType type) { + return downloadFromMaven(mavenRoot, mo, type, "ext"); + } + private static void removeObsoleteArtifacts(final MavenObject mo, final BuildType type, File folder) { File [] removals = folder.listFiles(new FilenameFilter() { @Override @@ -796,6 +849,59 @@ public class Build { "ecff5cb8b1189514c9d1d8d68eb77ac372e000c9", "f95e32a5d2dd8da643c4419814415b9704312993", ""); + public static final MavenObject SEL_JAVA = new MavenObject( + "selenium-java", "org/seleniumhq/selenium", "selenium-java", + "2.28.0", 984098, 0, 0, + "7606286989ac9cb942cc206d975ffe187c18d605", "4ede08d293dc153989a337cd0d31d26421433af5", ""); + + public static final MavenObject SEL_API = new MavenObject( + "selenium-api", "org/seleniumhq/selenium", "selenium-api", + "2.28.0", 984098, 0, 0, + "c4044c40fff65cd25135a5f443638a2b1ccaeac5", "35fc6ec0804ae32b16a56627e69bdcb69995c515", ""); + + public static final MavenObject SEL_REMOTE = new MavenObject( + "selenium-remote-driver", "org/seleniumhq/selenium", + "selenium-remote-driver", "2.28.0", 984098, 0, 0, + "c67f97cd94e02afec92b0ac881844febb4fc90be", "51a9c30de3c8c203cb7a474a10842443005a5fb4", ""); + public static final MavenObject SEL_SUPPORT = new MavenObject( + "selenium-support", "org/seleniumhq/selenium", + "selenium-support", "2.28.0", 984098, 0, 0, + "caf68d6310425f583bc592c08e43066b35eb94f6", "ce3831a601f5f50fda2f4604decde409b6c735a7", ""); + public static final MavenObject SEL_FF = new MavenObject( + "selenium-firefox-driver", "org/seleniumhq/selenium", + "selenium-firefox-driver", "2.28.0", 984098, 0, 0, + "a7c34e45dba39e65467b900aa67611aaa039692d", "aa8cd5fb49ca75a53d5b143406ea3d81ab3eddfd", ""); + + public static final MavenObject GUAVA = new MavenObject("guava", + "com/google/guava", "guava", "12.0", 984098, 0, 0, + "5bc66dd95b79db1e437eb08adba124a3e4088dc0", "f8b98e61865bed3c39b978ee3bf5c7fb990c4032", ""); + + public static final MavenObject JSON = new MavenObject("json", + "org/json", "json", "20080701", 984098, 0, 0, + "d652f102185530c93b66158b1859f35d45687258", "71bd54221e701df9d112bf9ba2918e13b0671f3a", ""); + + public static final MavenObject COMMONS_EXEC = new MavenObject( + "commons-exec", "org/apache/commons", "commons-exec", "1.1", + 984098, 0, 0, "07dfdf16fade726000564386825ed6d911a44ba1", "f60bea898e18b308099862e8634d589b06a8b0be", + ""); + + public static final MavenObject HTTPCORE = new MavenObject("httpcore", + "org/apache/httpcomponents", "httpcore", "4.2.1", 984098, 0, 0, + "2d503272bf0a8b5f92d64db78b4ba9abbaccc6fd", "3f6caf5334fa83607b82e2f32dd128a9d8a0ea5e", ""); + + public static final MavenObject HTTPMIME = new MavenObject("httpmime", + "org/apache/httpcomponents", "httpmime", "4.2.1", 984098, 0, 0, + "7c772bace9aa31a728c39a88c6ff66a7cd177e89", "", "4e453843ae47f1c2d70e2eb2c13c037de4b614c4"); + + public static final MavenObject HTTPCLIENT = new MavenObject( + "httpclient", "org/apache/httpcomponents", "httpclient", + "4.2.1", 984098, 0, 0, + "b69bd03af60bf487b3ae1209a644ecac587bf6fc", "6b27312b9c28b59aaeb6c21f3490045690c703d3", ""); + public static final MavenObject COMMONS_LOGGING = new MavenObject( + "commons-logging", "commons-logging", "commons-logging", + "1.1.1", 984098, 0, 0, + "5043bfebc3db072ed80fbd362e7caf00e885d8ae", "f3f156cbff0e0fb0d64bfce31a352cce4a33bc19", ""); + public final String name; public final String group; public final String artifact; diff --git a/test-ui-gitblit.properties b/test-ui-gitblit.properties new file mode 100644 index 00000000..c77de1a2 --- /dev/null +++ b/test-ui-gitblit.properties @@ -0,0 +1,1203 @@ +# +# Git Servlet Settings +# + +# Base folder for repositories. +# This folder may contain bare and non-bare repositories but Gitblit will only +# allow you to push to bare repositories. +# Use forward slashes even on Windows!! +# e.g. c:/gitrepos +# +# SINCE 0.5.0 +# RESTART REQUIRED +git.repositoriesFolder = ${baseFolder}/git + +# Build the available repository list at startup and cache this list for reuse. +# This reduces disk io when presenting the repositories page, responding to rpcs, +# etc, but it means that Gitblit will not automatically identify repositories +# added or deleted by external tools. +# +# For this case you can use curl, wget, etc to issue an rpc request to clear the +# cache (e.g. https://localhost/rpc?req=CLEAR_REPOSITORY_CACHE) +# +# SINCE 1.1.0 +git.cacheRepositoryList = true + +# Search the repositories folder subfolders for other repositories. +# Repositories MAY NOT be nested (i.e. one repository within another) +# but they may be grouped together in subfolders. +# e.g. c:/gitrepos/libraries/mylibrary.git +# c:/gitrepos/libraries/myotherlibrary.git +# +# SINCE 0.5.0 +git.searchRepositoriesSubfolders = true + +# Maximum number of folders to recurse into when searching for repositories. +# The default value, -1, disables depth limits. +# +# SINCE 1.1.0 +git.searchRecursionDepth = -1 + +# List of regex exclusion patterns to match against folders found in +# *git.repositoriesFolder*. +# Use forward slashes even on Windows!! +# e.g. test/jgit\.git +# +# SPACE-DELIMITED +# CASE-SENSITIVE +# SINCE 1.1.0 +git.searchExclusions = + +# List of regex url patterns for extracting a repository name when locating +# submodules. +# e.g. git.submoduleUrlPatterns = .*?://github.com/(.*) will extract +# *gitblit/gitblit.git* from *git://github.com/gitblit/gitblit.git* +# If no matches are found then the submodule repository name is assumed to be +# whatever trails the last / character. (e.g. gitblit.git). +# +# SPACE-DELIMITED +# CASE-SENSITIVE +# SINCE 1.1.0 +git.submoduleUrlPatterns = .*?://github.com/(.*) + +# Allow push/pull over http/https with JGit servlet. +# If you do NOT want to allow Git clients to clone/push to Gitblit set this +# to false. You might want to do this if you are only using ssh:// or git://. +# If you set this false, consider changing the *web.otherUrls* setting to +# indicate your clone/push urls. +# +# SINCE 0.5.0 +git.enableGitServlet = true + +# If you want to restrict all git servlet access to those with valid X509 client +# certificates then set this value to true. +# +# SINCE 1.2.0 +git.requiresClientCertificate = false + +# Enforce date checks on client certificates to ensure that they are not being +# used prematurely and that they have not expired. +# +# SINCE 1.2.0 +git.enforceCertificateValidity = true + +# List of OIDs to extract from a client certificate DN to map a certificate to +# an account username. +# +# e.g. git.certificateUsernameOIDs = CN +# e.g. git.certificateUsernameOIDs = FirstName LastName +# +# SPACE-DELIMITED +# SINCE 1.2.0 +git.certificateUsernameOIDs = CN + +# Only serve/display bare repositories. +# If there are non-bare repositories in git.repositoriesFolder and this setting +# is true, they will be excluded from the ui. +# +# SINCE 0.9.0 +git.onlyAccessBareRepositories = false + +# Allow an authenticated user to create a destination repository on a push if +# the repository does not already exist. +# +# Administrator accounts can create a repository in any project. +# These repositories are created with the default access restriction and authorization +# control values. The pushing account is set as the owner. +# +# Non-administrator accounts with the CREATE role may create personal repositories. +# These repositories are created as VIEW restricted for NAMED users. +# The pushing account is set as the owner. +# +# SINCE 1.2.0 +git.allowCreateOnPush = true + +# The default access restriction for new repositories. +# Valid values are NONE, PUSH, CLONE, VIEW +# NONE = anonymous view, clone, & push +# PUSH = anonymous view & clone and authenticated push +# CLONE = anonymous view, authenticated clone & push +# VIEW = authenticated view, clone, & push +# +# SINCE 1.0.0 +git.defaultAccessRestriction = NONE + +# The default authorization control for new repositories. +# Valid values are AUTHENTICATED and NAMED +# AUTHENTICATED = any authenticated user is granted restricted access +# NAMED = only named users/teams are granted restricted access +# +# SINCE 1.1.0 +git.defaultAuthorizationControl = NAMED + +# Enable JGit-based garbage collection. (!!EXPERIMENTAL!!) +# +# USE AT YOUR OWN RISK! +# +# If enabled, the garbage collection executor scans all repositories once a day +# at the hour of your choosing. The GC executor will take each repository "offline", +# one-at-a-time, to check if the repository satisfies it's GC trigger requirements. +# +# While the repository is offline it will be inaccessible from the web UI or from +# any of the other services (git, rpc, rss, etc). +# +# Gitblit's GC Executor MAY NOT PLAY NICE with the other Git kids on the block, +# especially on Windows systems, so if you are using other tools please coordinate +# their usage with your GC Executor schedule or do not use this feature. +# +# The GC algorithm complex and the JGit team advises caution when using their +# young implementation of GC. +# +# http://wiki.eclipse.org/EGit/New_and_Noteworthy/2.1#Garbage_Collector_and_Repository_Storage_Statistics +# +# EXPERIMENTAL +# SINCE 1.2.0 +# RESTART REQUIRED +git.enableGarbageCollection = false + +# Hour of the day for the GC Executor to scan repositories. +# This value is in 24-hour time. +# +# SINCE 1.2.0 +git.garbageCollectionHour = 0 + +# The default minimum total filesize of loose objects to trigger early garbage +# collection. +# +# You may specify a custom threshold for a repository in the repository's settings. +# Common unit suffixes of k, m, or g are supported. +# +# SINCE 1.2.0 +git.defaultGarbageCollectionThreshold = 500k + +# The default period, in days, between GCs for a repository. If the total filesize +# of the loose object exceeds *git.garbageCollectionThreshold* or the repository's +# custom threshold, this period will be short-circuited. +# +# e.g. if a repository collects 100KB of loose objects every day with a 500KB +# threshold and a period of 7 days, it will take 5 days for the loose objects to +# be collected, packed, and pruned. +# +# OR +# +# if a repository collects 10KB of loose objects every day with a 500KB threshold +# and a period of 7 days, it will take the full 7 days for the loose objects to be +# collected, packed, and pruned. +# +# You may specify a custom period for a repository in the repository's settings. +# +# The minimum value is 1 day since the GC Executor only runs once a day. +# +# SINCE 1.2.0 +git.defaultGarbageCollectionPeriod = 7 + +# Number of bytes of a pack file to load into memory in a single read operation. +# This is the "page size" of the JGit buffer cache, used for all pack access +# operations. All disk IO occurs as single window reads. Setting this too large +# may cause the process to load more data than is required; setting this too small +# may increase the frequency of read() system calls. +# +# Default on JGit is 8 KiB on all platforms. +# +# Common unit suffixes of k, m, or g are supported. +# Documentation courtesy of the Gerrit project. +# +# SINCE 1.0.0 +# RESTART REQUIRED +git.packedGitWindowSize = 8k + +# Maximum number of bytes to load and cache in memory from pack files. If JGit +# needs to access more than this many bytes it will unload less frequently used +# windows to reclaim memory space within the process. As this buffer must be shared +# with the rest of the JVM heap, it should be a fraction of the total memory available. +# +# The JGit team recommends setting this value larger than the size of your biggest +# repository. This ensures you can serve most requests from memory. +# +# Default on JGit is 10 MiB on all platforms. +# +# Common unit suffixes of k, m, or g are supported. +# Documentation courtesy of the Gerrit project. +# +# SINCE 1.0.0 +# RESTART REQUIRED +git.packedGitLimit = 10m + +# Maximum number of bytes to reserve for caching base objects that multiple deltafied +# objects reference. By storing the entire decompressed base object in a cache Git +# is able to avoid unpacking and decompressing frequently used base objects multiple times. +# +# Default on JGit is 10 MiB on all platforms. You probably do not need to adjust +# this value. +# +# Common unit suffixes of k, m, or g are supported. +# Documentation courtesy of the Gerrit project. +# +# SINCE 1.0.0 +# RESTART REQUIRED +git.deltaBaseCacheLimit = 10m + +# Maximum number of pack files to have open at once. A pack file must be opened +# in order for any of its data to be available in a cached window. +# +# If you increase this to a larger setting you may need to also adjust the ulimit +# on file descriptors for the host JVM, as Gitblit needs additional file descriptors +# available for network sockets and other repository data manipulation. +# +# Default on JGit is 128 file descriptors on all platforms. +# Documentation courtesy of the Gerrit project. +# +# SINCE 1.0.0 +# RESTART REQUIRED +git.packedGitOpenFiles = 128 + +# Largest object size, in bytes, that JGit will allocate as a contiguous byte +# array. Any file revision larger than this threshold will have to be streamed, +# typically requiring the use of temporary files under $GIT_DIR/objects to implement +# psuedo-random access during delta decompression. +# +# Servers with very high traffic should set this to be larger than the size of +# their common big files. For example a server managing the Android platform +# typically has to deal with ~10-12 MiB XML files, so 15 m would be a reasonable +# setting in that environment. Setting this too high may cause the JVM to run out +# of heap space when handling very big binary files, such as device firmware or +# CD-ROM ISO images. Make sure to adjust your JVM heap accordingly. +# +# Default is 50 MiB on all platforms. +# +# Common unit suffixes of k, m, or g are supported. +# Documentation courtesy of the Gerrit project. +# +# SINCE 1.0.0 +# RESTART REQUIRED +git.streamFileThreshold = 50m + +# When true, JGit will use mmap() rather than malloc()+read() to load data from +# pack files. The use of mmap can be problematic on some JVMs as the garbage +# collector must deduce that a memory mapped segment is no longer in use before +# a call to munmap() can be made by the JVM native code. +# +# In server applications (such as Gitblit) that need to access many pack files, +# setting this to true risks artificially running out of virtual address space, +# as the garbage collector cannot reclaim unused mapped spaces fast enough. +# +# Default on JGit is false. Although potentially slower, it yields much more +# predictable behavior. +# Documentation courtesy of the Gerrit project. +# +# SINCE 1.0.0 +# RESTART REQUIRED +git.packedGitMmap = false + +# +# Groovy Integration +# + +# Location of Groovy scripts to use for Pre and Post receive hooks. +# Use forward slashes even on Windows!! +# e.g. c:/groovy +# +# RESTART REQUIRED +# SINCE 0.8.0 +groovy.scriptsFolder = ${baseFolder}/groovy + +# Specify the directory Grape uses for downloading libraries. +# http://groovy.codehaus.org/Grape +# +# RESTART REQUIRED +# SINCE 1.0.0 +groovy.grapeFolder = ${baseFolder}/groovy/grape + +# Scripts to execute on Pre-Receive. +# +# These scripts execute after an incoming push has been parsed and validated +# but BEFORE the changes are applied to the repository. You might reject a +# push in this script based on the repository and branch the push is attempting +# to change. +# +# Script names are case-sensitive on case-sensitive file systems. You may omit +# the traditional ".groovy" from this list if your file extension is ".groovy" +# +# NOTE: +# These scripts are only executed when pushing to *Gitblit*, not to other Git +# tooling you may be using. Also note that these scripts are shared between +# repositories. These are NOT repository-specific scripts! Within the script +# you may customize the control-flow for a specific repository by checking the +# *repository* variable. +# +# SPACE-DELIMITED +# CASE-SENSITIVE +# SINCE 0.8.0 +groovy.preReceiveScripts = + +# Scripts to execute on Post-Receive. +# +# These scripts execute AFTER an incoming push has been applied to a repository. +# You might trigger a continuous-integration build here or send a notification. +# +# Script names are case-sensitive on case-sensitive file systems. You may omit +# the traditional ".groovy" from this list if your file extension is ".groovy" +# +# NOTE: +# These scripts are only executed when pushing to *Gitblit*, not to other Git +# tooling you may be using. Also note that these scripts are shared between +# repositories. These are NOT repository-specific scripts! Within the script +# you may customize the control-flow for a specific repository by checking the +# *repository* variable. +# +# SPACE-DELIMITED +# CASE-SENSITIVE +# SINCE 0.8.0 +groovy.postReceiveScripts = + +# Repository custom fields for Groovy Hook mechanism +# +# List of key=label pairs of custom fields to prompt for in the Edit Repository +# page. These keys are stored in the repository's git config file in the +# section [gitblit "customFields"]. Key names are alphanumeric only. These +# fields are intended to be used for the Groovy hook mechanism where a script +# can adjust it's execution based on the custom fields stored in the repository +# config. +# +# e.g. "commitMsgRegex=Commit Message Regular Expression" anotherProperty=Another +# +# SPACE-DELIMITED +# SINCE 1.0.0 +groovy.customFields = + +# +# Authentication Settings +# + +# Require authentication to see everything but the admin pages +# +# SINCE 0.5.0 +# RESTART REQUIRED +web.authenticateViewPages = false + +# Require admin authentication for the admin functions and pages +# +# SINCE 0.5.0 +# RESTART REQUIRED +web.authenticateAdminPages = true + +# Allow Gitblit to store a cookie in the user's browser for automatic +# authentication. The cookie is generated by the user service. +# +# SINCE 0.5.0 +web.allowCookieAuthentication = true + +# Config file for storing project metadata +# +# SINCE 1.2.0 +web.projectsFile = ${baseFolder}/projects.conf + +# Either the full path to a user config file (users.conf) +# OR the full path to a simple user properties file (users.properties) +# OR a fully qualified class name that implements the IUserService interface. +# +# Alternative user services: +# com.gitblit.LdapUserService +# com.gitblit.RedmineUserService +# +# Any custom user service implementation must have a public default constructor. +# +# SINCE 0.5.0 +# RESTART REQUIRED +realm.userService = test-ui-users.conf + +# How to store passwords. +# Valid values are plain, md5, or combined-md5. md5 is the hash of password. +# combined-md5 is the hash of username.toLowerCase()+password. +# Default is md5. +# +# SINCE 0.5.0 +realm.passwordStorage = md5 + +# Minimum valid length for a plain text password. +# Default value is 5. Absolute minimum is 4. +# +# SINCE 0.5.0 +realm.minPasswordLength = 5 + +# +# Gitblit Web Settings +# +# If blank Gitblit is displayed. +# +# SINCE 0.5.0 +web.siteName = + +# If *web.authenticateAdminPages*=true, users with "admin" role can create +# repositories, create users, and edit repository metadata. +# +# If *web.authenticateAdminPages*=false, any user can execute the aforementioned +# functions. +# +# SINCE 0.5.0 +web.allowAdministration = true + +# Allows rpc clients to list repositories and possibly manage or administer the +# Gitblit server, if the authenticated account has administrator permissions. +# See *web.enableRpcManagement* and *web.enableRpcAdministration*. +# +# SINCE 0.7.0 +web.enableRpcServlet = true + +# Allows rpc clients to manage repositories and users of the Gitblit instance, +# if the authenticated account has administrator permissions. +# Requires *web.enableRpcServlet=true*. +# +# SINCE 0.7.0 +web.enableRpcManagement = false + +# Allows rpc clients to control the server settings and monitor the health of this +# this Gitblit instance, if the authenticated account has administrator permissions. +# Requires *web.enableRpcServlet=true* and *web.enableRpcManagement*. +# +# SINCE 0.7.0 +web.enableRpcAdministration = false + +# Full path to a configurable robots.txt file. With this file you can control +# what parts of your Gitblit server respectable robots are allowed to traverse. +# http://googlewebmastercentral.blogspot.com/2008/06/improving-on-robots-exclusion-protocol.html +# +# SINCE 1.0.0 +web.robots.txt = + +# If true, the web ui layout will respond and adapt to the browser's dimensions. +# if false, the web ui will use a 940px fixed-width layout. +# http://twitter.github.com/bootstrap/scaffolding.html#responsive +# +# SINCE 1.0.0 +web.useResponsiveLayout = true + +# Allow Gravatar images to be displayed in Gitblit pages. +# +# SINCE 0.8.0 +web.allowGravatar = true + +# Allow dynamic zip downloads. +# +# SINCE 0.5.0 +web.allowZipDownloads = true + +# If *web.allowZipDownloads=true* the following formats will be displayed for +# download compressed archive links: +# +# zip = standard .zip +# tar = standard tar format (preserves *nix permissions and symlinks) +# gz = gz-compressed tar +# xz = xz-compressed tar +# bzip2 = bzip2-compressed tar +# +# SPACE-DELIMITED +# SINCE 1.2.0 +web.compressedDownloads = zip gz + +# Allow optional Lucene integration. Lucene indexing is an opt-in feature. +# A repository may specify branches to index with Lucene instead of using Git +# commit traversal. There are scenarios where you may want to completely disable +# Lucene indexing despite a repository specifying indexed branches. One such +# scenario is on a resource-constrained federated Gitblit mirror. +# +# SINCE 0.9.0 +web.allowLuceneIndexing = false + +# Allows an authenticated user to create forks of a repository +# +# set this to false if you want to disable all fork controls on the web site +# +web.allowForking = true + +# Controls the length of shortened commit hash ids +# +# SINCE 1.2.0 +web.shortCommitIdLength = 6 + +# Use Clippy (Flash solution) to provide a copy-to-clipboard button. +# If false, a button with a more primitive JavaScript-based prompt box will +# offer a 3-step (click, ctrl+c, enter) copy-to-clipboard alternative. +# +# SINCE 0.8.0 +web.allowFlashCopyToClipboard = true + +# Default maximum number of commits that a repository may contribute to the +# activity page, regardless of the selected duration. This setting may be valuable +# for an extremely busy server. This value may also be configed per-repository +# in Edit Repository. 0 disables this throttle. +# +# SINCE 1.2.0 +web.maxActivityCommits = 0 + +# Default number of entries to include in RSS Syndication links +# +# SINCE 0.5.0 +web.syndicationEntries = 25 + +# Show the size of each repository on the repositories page. +# This requires recursive traversal of each repository folder. This may be +# non-performant on some operating systems and/or filesystems. +# +# SINCE 0.5.2 +web.showRepositorySizes = true + +# List of custom regex expressions that can be displayed in the Filters menu +# of the Repositories and Activity pages. Keep them very simple because you +# are likely to run into encoding issues if they are too complex. +# +# Use !!! to separate the filters +# +# SINCE 0.8.0 +web.customFilters = + +# Show federation registrations (without token) and the current pull status +# to non-administrator users. +# +# SINCE 0.6.0 +web.showFederationRegistrations = false + +# This is the message displayed when *web.authenticateViewPages=true*. +# This can point to a file with Markdown content. +# Specifying "gitblit" uses the internal login message. +# +# SINCE 0.7.0 +web.loginMessage = gitblit + +# This is the message displayed above the repositories table. +# This can point to a file with Markdown content. +# Specifying "gitblit" uses the internal welcome message. +# +# SINCE 0.5.0 +web.repositoriesMessage = gitblit + +# Ordered list of charsets/encodings to use when trying to display a blob. +# If empty, UTF-8 and ISO-8859-1 are used. The server's default charset +# is always appended to the encoding list. If all encodings fail to cleanly +# decode the blob content, UTF-8 will be used with the standard malformed +# input/unmappable character replacement strings. +# +# SPACE-DELIMITED +# SINCE 1.0.0 +web.blobEncodings = UTF-8 ISO-8859-1 + +# Manually set the default timezone to be used by Gitblit for display in the +# web ui. This value is independent of the JVM timezone. Specifying a blank +# value will default to the JVM timezone. +# e.g. America/New_York, US/Pacific, UTC, Europe/Berlin +# +# SINCE 0.9.0 +# RESTART REQUIRED +web.timezone = + +# Use the client timezone when formatting dates. +# This uses AJAX to determine the browser's timezone and may require more +# server overhead because a Wicket session is created. All Gitblit pages +# attempt to be stateless, if possible. +# +# SINCE 0.5.0 +# RESTART REQUIRED +web.useClientTimezone = false + +# Time format +# +# +# SINCE 0.8.0 +web.timeFormat = HH:mm + +# Short date format +# +# +# SINCE 0.5.0 +web.datestampShortFormat = yyyy-MM-dd + +# Long date format +# +# SINCE 0.8.0 +web.datestampLongFormat = EEEE, MMMM d, yyyy + +# Long timestamp format +# +# +# SINCE 0.5.0 +web.datetimestampLongFormat = EEEE, MMMM d, yyyy HH:mm Z + +# Mount URL parameters +# This setting controls if pretty or parameter URLs are used. +# i.e. +# if true: +# http://localhost/commit/myrepo/abcdef +# if false: +# http://localhost/commit/?r=myrepo&h=abcdef +# +# SINCE 0.5.0 +# RESTART REQUIRED +web.mountParameters = true + +# Some servlet containers (e.g. Tomcat >= 6.0.10) disallow '/' (%2F) encoding +# in URLs as a security precaution for proxies. This setting tells Gitblit +# to preemptively replace '/' with '*' or '!' for url string parameters. +# +# +# +# Add *-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true* to your +# *CATALINA_OPTS* or to your JVM launch parameters +# +# SINCE 0.5.2 +web.forwardSlashCharacter = / + +# Show other URLs on the summary page for accessing your git repositories +# Use spaces to separate urls. {0} is the token for the repository name. +# e.g. +# web.otherUrls = ssh://localhost/git/{0} git://localhost/git/{0} +# +# SPACE-DELIMITED +# SINCE 0.5.0 +web.otherUrls = + +# Choose how to present the repositories list. +# grouped = group nested/subfolder repositories together (no sorting) +# flat = flat list of repositories (sorting allowed) +# +# SINCE 0.5.0 +web.repositoryListType = grouped + +# If using a grouped repository list and there are repositories at the +# root level of your repositories folder, you may specify the displayed +# group name with this setting. This value is only used for web presentation. +# +# SINCE 0.5.0 +web.repositoryRootGroupName = main + +# Display the repository swatch color next to the repository name link in the +# repositories list. +# +# SINCE 0.8.0 +web.repositoryListSwatches = true + +# Choose the diff presentation style: gitblt, gitweb, or plain +# +# SINCE 0.5.0 +web.diffStyle = gitblit + +# Control if email addresses are shown in web ui +# +# SINCE 0.5.0 +web.showEmailAddresses = true + +# Shows a combobox in the page links header with commit, committer, and author +# search selection. Default search is commit. +# +# SINCE 0.5.0 +web.showSearchTypeSelection = false + +# Generates a line graph of repository activity over time on the Summary page. +# This uses the Google Charts API. +# +# SINCE 0.5.0 +web.generateActivityGraph = true + +# The number of days to show on the activity page. +# Value must exceed 0 else default of 14 is used +# +# SINCE 0.8.0 +web.activityDuration = 14 + +# The number of commits to display on the summary page +# Value must exceed 0 else default of 20 is used +# +# SINCE 0.5.0 +web.summaryCommitCount = 16 + +# The number of tags/branches to display on the summary page. +# -1 = all tags/branches +# 0 = hide tags/branches +# N = N tags/branches +# +# SINCE 0.5.0 +web.summaryRefsCount = 5 + +# The number of items to show on a page before showing the first, prev, next +# pagination links. A default if 50 is used for any invalid value. +# +# SINCE 0.5.0 +web.itemsPerPage = 50 + +# Registered file extensions to ignore during Lucene indexing +# +# SPACE-DELIMITED +# SINCE 0.9.0 +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 + +# Registered extensions for google-code-prettify +# +# SPACE-DELIMITED +# SINCE 0.5.0 +web.prettyPrintExtensions = c cpp cs css frm groovy htm html java js php pl prefs properties py rb scala sh sql xml vb + +# Registered extensions for markdown transformation +# +# SPACE-DELIMITED +# CASE-SENSITIVE +# SINCE 0.5.0 +web.markdownExtensions = md mkd markdown MD MKD + +# Image extensions +# +# SPACE-DELIMITED +# SINCE 0.5.0 +web.imageExtensions = bmp jpg gif png + +# Registered extensions for binary blobs +# +# SPACE-DELIMITED +# SINCE 0.5.0 +web.binaryExtensions = jar pdf tar.gz zip + +# Aggressive heap management will run the garbage collector on every generated +# page. This slows down page generation a little but improves heap consumption. +# +# SINCE 0.5.0 +web.aggressiveHeapManagement = false + +# Run the webapp in debug mode +# +# SINCE 0.5.0 +# RESTART REQUIRED +web.debugMode = false + +# Enable/disable global regex substitutions (i.e. shared across repositories) +# +# SINCE 0.5.0 +regex.global = true + +# Example global regex substitutions +# Use !!! to separate the search pattern and the replace pattern +# searchpattern!!!replacepattern +# SINCE 0.5.0 +regex.global.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!Bug-Id: $3 +# SINCE 0.5.0 +regex.global.changeid = \\b(Change-Id:\\s*)([A-Za-z0-9]*)\\b!!!Change-Id: $2 + +# Example per-repository regex substitutions overrides global +# SINCE 0.5.0 +regex.myrepository.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!Bug-Id: $3 + +# +# Mail Settings +# SINCE 0.6.0 +# +# Mail settings are used to notify administrators of received federation proposals +# + +# ip or hostname of smtp server +# +# SINCE 0.6.0 +mail.server = + +# port to use for smtp requests +# +# SINCE 0.6.0 +mail.port = 25 + +# debug the mail executor +# +# SINCE 0.6.0 +mail.debug = false + +# if your smtp server requires authentication, supply the credentials here +# +# SINCE 0.6.0 +mail.username = +# SINCE 0.6.0 +mail.password = + +# from address for generated emails +# +# SINCE 0.6.0 +mail.fromAddress = + +# List of email addresses for the Gitblit administrators +# +# SPACE-DELIMITED +# SINCE 0.6.0 +mail.adminAddresses = + +# List of email addresses for sending push email notifications. +# +# This key currently requires use of the sendemail.groovy hook script. +# If you set sendemail.groovy in *groovy.postReceiveScripts* then email +# notifications for all repositories (regardless of access restrictions!) +# will be sent to these addresses. +# +# SPACE-DELIMITED +# SINCE 0.8.0 +mail.mailingLists = + +# +# Federation Settings +# SINCE 0.6.0 +# +# A Gitblit federation is a way to backup one Gitblit instance to another. +# +# *git.enableGitServlet* must be true to use this feature. + +# Your federation name is used for federation status acknowledgments. If it is +# unset, and you elect to send a status acknowledgment, your Gitblit instance +# will be identified by its hostname, if available, else your internal ip address. +# The source Gitblit instance will also append your external IP address to your +# identification to differentiate multiple pulling systems behind a single proxy. +# +# SINCE 0.6.0 +federation.name = + +# Specify the passphrase of this Gitblit instance. +# +# An unspecified (empty) passphrase disables processing federation requests. +# +# This value can be anything you want: an integer, a sentence, an haiku, etc. +# Keep the value simple, though, to avoid Java properties file encoding issues. +# +# Changing your passphrase will break any registrations you have established with other +# Gitblit instances. +# +# CASE-SENSITIVE +# SINCE 0.6.0 +# RESTART REQUIRED *(only to enable or disable federation)* +federation.passphrase = + +# Control whether or not this Gitblit instance can receive federation proposals +# from another Gitblit instance. Registering a federated Gitblit is a manual +# process. Proposals help to simplify that process by allowing a remote Gitblit +# instance to send your Gitblit instance the federation pull data. +# +# SINCE 0.6.0 +federation.allowProposals = false + +# The destination folder for cached federation proposals. +# Use forward slashes even on Windows!! +# +# SINCE 0.6.0 +federation.proposalsFolder = ${baseFolder}/proposals + +# The default pull frequency if frequency is unspecified on a registration +# +# SINCE 0.6.0 +federation.defaultFrequency = 60 mins + +# Federation Sets are named groups of repositories. The Federation Sets are +# available for selection in the repository settings page. You can assign a +# repository to one or more sets and then distribute the token for the set. +# This allows you to grant federation pull access to a subset of your available +# repositories. Tokens for federation sets only grant repository pull access. +# +# SPACE-DELIMITED +# CASE-SENSITIVE +# SINCE 0.6.0 +federation.sets = + +# Federation pull registrations +# Registrations are read once, at startup. +# +# RESTART REQUIRED +# +# frequency: +# The shortest frequency allowed is every 5 minutes +# Decimal frequency values are cast to integers +# Frequency values may be specified in mins, hours, or days +# Values that can not be parsed or are unspecified default to *federation.defaultFrequency* +# +# folder: +# if unspecified, the folder is *git.repositoriesFolder* +# if specified, the folder is relative to *git.repositoriesFolder* +# +# bare: +# if true, each repository will be created as a *bare* repository and will not +# have a working directory. +# +# if false, each repository will be created as a normal repository suitable +# for local work. +# +# mirror: +# if true, each repository HEAD is reset to *origin/master* after each pull. +# The repository will be flagged *isFrozen* after the initial clone. +# +# if false, each repository HEAD will point to the FETCH_HEAD of the initial +# clone from the origin until pushed to or otherwise manipulated. +# +# mergeAccounts: +# if true, remote accounts and their permissions are merged into your +# users.properties file +# +# notifyOnError: +# if true and the mail configuration is properly set, administrators will be +# notified by email of pull failures +# +# include and exclude: +# Space-delimited list of repositories to include or exclude from pull +# may be * wildcard to include or exclude all +# may use fuzzy match (e.g. org.eclipse.*) + +# +# (Nearly) Perfect Mirror example +# + +#federation.example1.url = https://go.gitblit.com +#federation.example1.token = 6f3b8a24bf970f17289b234284c94f43eb42f0e4 +#federation.example1.frequency = 120 mins +#federation.example1.folder = +#federation.example1.bare = true +#federation.example1.mirror = true +#federation.example1.mergeAccounts = true + +# +# Advanced Realm Settings +# + +# URL of the LDAP server. +# To use encrypted transport, use either ldaps:// URL for SSL or ldap+tls:// to +# send StartTLS command. +# +# SINCE 1.0.0 +realm.ldap.server = ldap://localhost + +# Login username for LDAP searches. +# If this value is unspecified, anonymous LDAP login will be used. +# +# e.g. mydomain\\username +# +# SINCE 1.0.0 +realm.ldap.username = cn=Directory Manager + +# Login password for LDAP searches. +# +# SINCE 1.0.0 +realm.ldap.password = password + +# The LdapUserService must be backed by another user service for standard user +# and team management. +# default: users.conf +# +# SINCE 1.0.0 +# RESTART REQUIRED +realm.ldap.backingUserService = test-ui-users.conf + +# Delegate team membership control to LDAP. +# +# If true, team user memberships will be specified by LDAP groups. This will +# disable team selection in Edit User and user selection in Edit Team. +# +# If false, LDAP will only be used for authentication and Gitblit will maintain +# team memberships with the *realm.ldap.backingUserService*. +# +# SINCE 1.0.0 +realm.ldap.maintainTeams = false + +# Root node for all LDAP users +# +# This is the root node from which subtree user searches will begin. +# If blank, Gitblit will search ALL nodes. +# +# SINCE 1.0.0 +realm.ldap.accountBase = OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain + +# Filter criteria for LDAP users +# +# Query pattern to use when searching for a user account. This may be any valid +# LDAP query expression, including the standard (&) and (|) operators. +# +# Variables may be injected via the ${variableName} syntax. +# Recognized variables are: +# ${username} - The text entered as the user name +# +# SINCE 1.0.0 +realm.ldap.accountPattern = (&(objectClass=person)(sAMAccountName=${username})) + +# Root node for all LDAP groups to be used as Gitblit Teams +# +# This is the root node from which subtree team searches will begin. +# If blank, Gitblit will search ALL nodes. +# +# SINCE 1.0.0 +realm.ldap.groupBase = OU=Groups,OU=UserControl,OU=MyOrganization,DC=MyDomain + +# Filter criteria for LDAP groups +# +# Query pattern to use when searching for a team. This may be any valid +# LDAP query expression, including the standard (&) and (|) operators. +# +# Variables may be injected via the ${variableName} syntax. +# Recognized variables are: +# ${username} - The text entered as the user name +# ${dn} - The Distinguished Name of the user logged in +# +# All attributes from the LDAP User record are available. For example, if a user +# has an attribute "fullName" set to "John", "(fn=${fullName})" will be +# translated to "(fn=John)". +# +# SINCE 1.0.0 +realm.ldap.groupMemberPattern = (&(objectClass=group)(member=${dn})) + +# LDAP users or groups that should be given administrator privileges. +# +# Teams are specified with a leading '@' character. Groups with spaces in the +# name can be entered as "@team name". +# +# e.g. realm.ldap.admins = john @git_admins "@git admins" +# +# SPACE-DELIMITED +# SINCE 1.0.0 +realm.ldap.admins = @Git_Admins + +# Attribute(s) on the USER record that indicate their display (or full) name. +# Leave blank for no mapping available in LDAP. +# +# This may be a single attribute, or a string of multiple attributes. Examples: +# displayName - Uses the attribute 'displayName' on the user record +# ${personalTitle}. ${givenName} ${surname} - Will concatenate the 3 +# attributes together, with a '.' after personalTitle +# +# SINCE 1.0.0 +realm.ldap.displayName = displayName + +# Attribute(s) on the USER record that indicate their email address. +# Leave blank for no mapping available in LDAP. +# +# This may be a single attribute, or a string of multiple attributes. Examples: +# email - Uses the attribute 'email' on the user record +# ${givenName}.${surname}@gitblit.com -Will concatenate the 2 attributes +# together with a '.' and '@' creating something like first.last@gitblit.com +# +# SINCE 1.0.0 +realm.ldap.email = email + +# The RedmineUserService must be backed by another user service for standard user +# and team management. +# default: users.conf +# +# RESTART REQUIRED +realm.redmine.backingUserService = test-ui-users.conf + +# URL of the Redmine. +realm.redmine.url = http://example.com/redmine + +# +# Server Settings +# + +# The temporary folder to decompress the embedded gitblit webapp. +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.tempFolder = ${baseFolder}/temp + +# Use Jetty NIO connectors. If false, Jetty Socket connectors will be used. +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.useNio = true + +# Context path for the GO application. You might want to change the context +# path if running Gitblit behind a proxy layer such as mod_proxy. +# +# SINCE 0.7.0 +# RESTART REQUIRED +server.contextPath = / + +# Standard http port to serve. <= 0 disables this connector. +# On Unix/Linux systems, ports < 1024 require root permissions. +# Recommended value: 80 or 8080 +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.httpPort = 0 + +# Secure/SSL https port to serve. <= 0 disables this connector. +# On Unix/Linux systems, ports < 1024 require root permissions. +# Recommended value: 443 or 8443 +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.httpsPort = 8443 + +# Port for serving an Apache JServ Protocol (AJP) 1.3 connector for integrating +# Gitblit GO into an Apache HTTP server setup. <= 0 disables this connector. +# Recommended value: 8009 +# +# SINCE 0.9.0 +# RESTART REQUIRED +server.ajpPort = 0 + +# Specify the interface for Jetty to bind the standard connector. +# You may specify an ip or an empty value to bind to all interfaces. +# Specifying localhost will result in Gitblit ONLY listening to requests to +# localhost. +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.httpBindInterface = localhost + +# Specify the interface for Jetty to bind the secure connector. +# You may specify an ip or an empty value to bind to all interfaces. +# Specifying localhost will result in Gitblit ONLY listening to requests to +# localhost. +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.httpsBindInterface = localhost + +# Specify the interface for Jetty to bind the AJP connector. +# You may specify an ip or an empty value to bind to all interfaces. +# Specifying localhost will result in Gitblit ONLY listening to requests to +# localhost. +# +# SINCE 0.9.0 +# RESTART REQUIRED +server.ajpBindInterface = localhost + +# Alias of certificate to use for https/SSL serving. If blank the first +# certificate found in the keystore will be used. +# +# SINCE 1.2.0 +# RESTART REQUIRED +server.certificateAlias = localhost + +# Password for SSL keystore. +# Keystore password and certificate password must match. +# This is provided for convenience, its probably more secure to set this value +# using the --storePassword command line parameter. +# +# If you are using the official JRE or JDK from Oracle you may not have the +# JCE Unlimited Strength Jurisdiction Policy files bundled with your JVM. Because +# of this, your store/key password can not exceed 7 characters. If you require +# longer passwords you may need to install the JCE Unlimited Strength Jurisdiction +# Policy files from Oracle. +# +# http://www.oracle.com/technetwork/java/javase/downloads/index.html +# +# Gitblit and the Gitblit Certificate Authority will both indicate if Unlimited +# Strength encryption is available. +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.storePassword = gitblit + +# If serving over https (recommended) you might consider requiring clients to +# authenticate with ssl certificates. If enabled, only https clients with the +# a valid client certificate will be able to access Gitblit. +# +# If disabled, client certificate authentication is optional and will be tried +# first before falling-back to form authentication or basic authentication. +# +# Requiring client certificates to access any of Gitblit may be too extreme, +# consider this carefully. +# +# SINCE 1.2.0 +# RESTART REQUIRED +server.requireClientCertificates = false + +# Port for shutdown monitor to listen on. +# +# SINCE 0.5.0 +# RESTART REQUIRED +server.shutdownPort = 8081 diff --git a/test-ui-users.conf b/test-ui-users.conf new file mode 100644 index 00000000..5bf35f3b --- /dev/null +++ b/test-ui-users.conf @@ -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 index 00000000..fc08f5af --- /dev/null +++ b/tests/de/akquinet/devops/GitblitRunnable.java @@ -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 index 00000000..594d7fc7 --- /dev/null +++ b/tests/de/akquinet/devops/LaunchWithUITestConfig.java @@ -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 index 00000000..2eff4918 --- /dev/null +++ b/tests/de/akquinet/devops/ManualUITestLaunch.java @@ -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 index 00000000..97bd9037 --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/TestUISuite.java @@ -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 index 00000000..9cdad160 --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/cases/UI_MultiAdminSupportTest.java @@ -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 index 00000000..bb7b3da2 --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/generic/AbstractUITest.java @@ -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 index 00000000..3433bbb6 --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/view/Exp.java @@ -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 { + public Boolean apply(WebDriver d) { + List findElements = d.findElements(By.partialLinkText("general")); + return findElements.size() == 1; + } + } + public static class RepoListViewLoaded implements ExpectedCondition { + public Boolean apply(WebDriver d) { + String xpath = "//img[@src=\"git-black-16x16.png\"]"; + List 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 index 00000000..0908d7c9 --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/view/GitblitDashboardView.java @@ -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 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 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() { + 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 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 index 00000000..43716434 --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/view/GitblitPageView.java @@ -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 index 00000000..ef0a3171 --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/view/RepoEditView.java @@ -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 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 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 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 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 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 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 index 00000000..6ec6203f --- /dev/null +++ b/tests/de/akquinet/devops/test/ui/view/RepoListView.java @@ -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 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 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 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 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); + + } +} -- 2.39.5