summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstance.java212
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstanceId.java265
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstanceReport.java43
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstanceStat.java127
-rw-r--r--src/main/java/com/gitblit/models/ServerStatus.java8
-rw-r--r--src/main/java/com/gitblit/servlet/GitblitContext.java9
-rw-r--r--src/test/config/test-gitblit.properties1
-rw-r--r--src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java158
-rw-r--r--src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java184
-rw-r--r--src/test/java/com/gitblit/instance/GitblitInstanceTest.java64
-rw-r--r--src/test/java/com/gitblit/tests/GitBlitSuite.java6
-rw-r--r--src/test/java/com/gitblit/tests/GitblitUnitTest.java5
-rw-r--r--src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java7
13 files changed, 1085 insertions, 4 deletions
diff --git a/src/main/java/com/gitblit/instance/GitblitInstance.java b/src/main/java/com/gitblit/instance/GitblitInstance.java
new file mode 100644
index 00000000..ca1fda38
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstance.java
@@ -0,0 +1,212 @@
+package com.gitblit.instance;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.gitblit.utils.JsonUtils.sendJsonString;
+
+public class GitblitInstance
+{
+ private final static String STATS_URL = "https://instats.gitblit.dev/hiitsme/";
+ private final static Logger LOG = LoggerFactory.getLogger(GitblitInstance.class);
+
+ private IRuntimeManager runtimeManager;
+
+ private String instanceId;
+
+ private GitblitInstanceReport report;
+
+ private ScheduledExecutorService executor;
+
+
+ /**
+ * Initialize the Gitblit instance reporting system.
+ *
+ * This will gather the static and dynamic statistics about the running
+ * instance, so that they can be reported.
+ *
+ * @param runtimeManager
+ * The runtime manager is used to determine the type of instance
+ * as well as for some other settings and data.
+ */
+ public void init(IRuntimeManager runtimeManager) {
+ this.runtimeManager = runtimeManager;
+
+ // Initialize ID
+ GitblitInstanceId instanceId = new GitblitInstanceId(runtimeManager.getBaseFolder());
+ this.instanceId = instanceId.getId().toString();
+ LOG.info(this.instanceId);
+
+ GitblitInstanceStat instanceStat;
+
+ if (runtimeManager.getSettings().hasSettings("container.dockerfileVersion")) {
+ instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.DOCKER);
+ }
+ else if (runtimeManager.getStatus().isGO){
+ instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.GO);
+ }
+ else {
+ instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.WAR);
+ }
+
+ instanceStat.init(runtimeManager.getStatus());
+
+ this.report = new GitblitInstanceReport(this.instanceId, instanceStat);
+ }
+
+
+ public void start()
+ {
+ if (shouldRunReports()) {
+ startReports();
+ }
+ }
+
+ public void stop()
+ {
+ if (this.executor != null && !this.executor.isShutdown() && !this.executor.isTerminated()) {
+ this.executor.shutdownNow();
+ System.out.println("Gitblit instance reporting task stopped.");
+ }
+ }
+
+
+
+ /**
+ * Determine if the reporting task should run.
+ *
+ * We do not want to report anything, i.e. the reporting task to run,
+ * if we are running unit tests or integration tests.
+ * Instance reports should only be sent for production instances or released versions.
+ * Therefore we also check if the Gitblit version is a SNAPSHOT version,
+ * or if the docker image is not a release version, when running from a docker image.
+ * A docker image running under GOSS should also not report anything.
+ */
+ boolean shouldRunReports()
+ {
+ // We can only run reports when we have been initialized
+ if (this.report == null || this.runtimeManager == null) {
+ return false;
+ }
+
+ // Check if we are running in a test environment
+ IStoredSettings settings = this.runtimeManager.getSettings();
+ if (! settings.getString("gitblit.testReportingUrl", "").isEmpty()) {
+ // Force reporting to run overriding any test settings
+ LOG.debug("Enabled reporting to test server URL: {}", settings.getString("gitblit.testReportingUrl", ""));
+ return true;
+ }
+ if (settings.getBoolean("gitblit.testRun", false)) {
+ return false;
+ }
+
+ // Check if we are running a SNAPSHOT version
+ if (this.runtimeManager.getStatus().version.endsWith("SNAPSHOT")) {
+ return false;
+ }
+
+ if (this.report.instanceStat.instanceType == GitblitInstanceStat.GitblitInstanceType.DOCKER) {
+ // Check if we are running a docker image that is not a release version
+ if (! settings.getString("container.imageType", "").equals("release")) {
+ return false;
+ }
+
+ // Check if we are running a docker image under GOSS
+ if (System.getenv("GITBLIT_GOSS_TEST") != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Start the reporting task.
+ *
+ * This will start a thread that runs once a day and sends the instance
+ * report to the popularity report server.
+ */
+ private void startReports()
+ {
+ this.executor = Executors.newSingleThreadScheduledExecutor();
+
+ String statsUrl = STATS_URL;
+ int delay = 24;
+ int period = 24 * 60; // 24 hours in minutes
+ TimeUnit unit = TimeUnit.MINUTES;
+ long retryInterval = 60 * 60 * 1000; // 1 hour in milliseconds
+ final long retryTimeout = 20 * 60 * 60 * 1000; // 20 hours in milliseconds
+
+ // If we are running in a test environment, we will send the reports more frequently
+ String testUrl = this.runtimeManager.getSettings().getString("gitblit.testReportingUrl", "");
+ if (! testUrl.isEmpty()) {
+ statsUrl = testUrl;
+ delay = 10;
+ period = 24;
+ unit = TimeUnit.SECONDS;
+ retryInterval = 10 * 1000; // 10 seconds in milliseconds
+ }
+
+ final String baseUrl = statsUrl;
+ final long retryIntervalFinal = retryInterval;
+ this.executor.scheduleAtFixedRate(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ sendMyStats(baseUrl + instanceId, retryIntervalFinal, retryTimeout);
+ }
+ }, delay, period, unit);
+ }
+
+ /**
+ * Send the instance report to the popularity report server.
+ *
+ * This will send a JSON object to the server with the instance report.
+ *
+ * @param reportUrl
+ * The URL to send the report to.
+ * @param retryInterval
+ * The interval in milliseconds to wait before retrying to send the report if it failed.
+ * @param retryTimeout
+ * The timeout in milliseconds to give up sending the report if it fails repeatedly.
+ */
+ private void sendMyStats(String reportUrl, long retryInterval, long retryTimeout)
+ {
+ // Create a HTTP POST request payload
+ String report = JsonUtils.toJsonString(this.report.fromNow());
+
+ int status = 0;
+ long timeToGiveup = System.currentTimeMillis() + retryTimeout;
+ while (status != 200 && System.currentTimeMillis() < timeToGiveup) {
+ try {
+ status = sendJsonString(reportUrl, report, "gitblitta", "countmein".toCharArray());
+ if (status != 200) {
+ LOG.debug("Error sending stats to " + reportUrl + ": " + status);
+ }
+ }
+ catch (IOException e) {
+ LOG.debug("Exception sending stats to " + reportUrl + ": " + e.getMessage());
+ }
+
+ if (status != 200) {
+ try {
+ Thread.sleep(retryInterval);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return; // exit if interrupted
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/gitblit/instance/GitblitInstanceId.java b/src/main/java/com/gitblit/instance/GitblitInstanceId.java
new file mode 100644
index 00000000..652c200c
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstanceId.java
@@ -0,0 +1,265 @@
+package com.gitblit.instance;
+
+import com.gitblit.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * The instance id is a unique identifier for an installed Gitblit instance.
+ *
+ * This is used to track the number of Gitblit instances in the field.
+ * Its purpose is to gauge the popularity of Gitblit and to help
+ * prioritize feature requests.
+ *
+ * The instance id should be unique between different instances, even
+ * on the same machine. But it should stay the same between restarts of
+ * the same instance. It should also stay the same between upgrades of
+ * the same instance. Therefore, it must be stored in a file that is
+ * not overwritten during upgrades, once it has been created.
+ */
+public class GitblitInstanceId
+{
+ static final String STORAGE_FILE = "gbins";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final File idFileBase;
+
+ private UUID id;
+
+
+ /**
+ * Constructor.
+ */
+ public GitblitInstanceId()
+ {
+ this.idFileBase = null;
+ }
+
+ /**
+ * Constructor.
+ */
+ public GitblitInstanceId(File idFileBase)
+ {
+ this.idFileBase = idFileBase;
+ }
+
+
+ /**
+ * Get the instance id.
+ *
+ * @return the instance id.
+ */
+ public UUID getId() {
+ if (this.id == null) {
+ load();
+ }
+ return this.id;
+ }
+
+
+ /**
+ * Load the instance id from the file.
+ */
+ private void load()
+ {
+ if (this.idFileBase == null) {
+ // Not working with stored id.
+ log.debug("No id file base directory specified. Generated id is not persisted.");
+ generate();
+ return;
+ }
+
+ File idFile = new File(this.idFileBase, STORAGE_FILE);
+ if (idFile.exists()) {
+ // Read the file
+ String uuidString = readFromFile(idFile);
+
+ // Parse the UUID
+ try {
+ this.id = UUID.fromString(uuidString);
+ return;
+ }
+ catch (IllegalArgumentException e) {
+ log.debug("Unable to parse instance id. Will generate a new one: {}", e.getMessage(), e);
+ }
+ }
+
+ // Generate a new instance id and persist it to disk.
+ generate();
+ storeToFile(idFile);
+ }
+
+
+ private String readFromFile(File idfile)
+ {
+// log.debug("Loading instance id from file: {}", idfile.getAbsolutePath());
+
+ String string = FileUtils.readContent(idfile, null).trim();
+ String uuidString = string.replaceAll("\\s+","");
+ return uuidString.trim();
+ }
+
+ private void storeToFile(File idfile)
+ {
+ // Make sure that the directory exists
+ if (!idfile.getParentFile().exists()) {
+ if (!idfile.getParentFile().mkdirs()) {
+ log.debug("Unable to create directory for instance id file: {}", idfile.getParentFile().getAbsolutePath());
+ return;
+ }
+ }
+
+ // Write the UUID to the file
+ String uuidString = this.id.toString();
+ FileUtils.writeContent(idfile, uuidString);
+ }
+
+
+ /**
+ * Generate a new instance id and persist it to disk.
+ *
+ * UUID is variant, i.e. OSF DCE, version 8, a custom format.
+ * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ * date -rand-8rnd-8rnd- rand OUI
+ *
+ * The variant nibble has the variant (1) in the upper two bits as 0b10xx,
+ * and the lower two bits are used as a version, currently 0bxx00.
+ * Should the format of this UUID change, the version can be incremented
+ * to 0bxx01 or 0bxx10. Further increments would set the bits in the variant
+ * nibble to 0bxx11 and employ more bits from the next nibble for further
+ * differentiation.
+ */
+ private void generate()
+ {
+ // Start with a random UUID
+ UUID id = UUID.randomUUID();
+ long upper = id.getMostSignificantBits();
+ long lower = id.getLeastSignificantBits();
+
+
+ // Set the variant bits to 0b1000, variant 1, our version 0.
+ lower &= 0x0FFFFFFFFFFFFFFFL; // Clear the variant bits
+ lower |= 0x8000000000000000L; // Set the variant bits to 0b1000
+
+ // Set the version bits to 0b1000, version 8.
+ upper &= 0xFFFFFFFFFFFF0FFFL; // Clear the version bits
+ upper |= 0x0000000000008000L; // Set the version bits to 0b1000
+
+
+ // Set the first four bytes to represent the date.
+ long date = System.currentTimeMillis();
+ date &= 0xFFFFFFFFFFFF0000L; // Clear the last two bytes, those are only a few minutes.
+ date <<= 2 * 8; // We do not need the upper two bytes, that is too far into the future.
+
+ upper &= 0x00000000FFFFFFFFL; // Clear the date bits.
+ upper |= date; // Set the date in the upper 32 bits.
+
+
+ // Set the OUI in the lower three bytes.
+ Long oui = getNodeOUI();
+ if (oui != null) {
+ lower &= 0xFFFFFFFFFF000000L; // Clear the OUI bits.
+ lower |= (0x1000000L | oui); // Set the OUI in the lower three bytes. Mark as valid OUI in bit above them.
+ }
+ else {
+ // Mark this as an invalid OUI, i.e. random bits, by setting the bit above the OUI bits to zero.
+ lower &= 0xFFFFFFFFFEFFFFFFL; // Clear the valid OUI indicator bit.
+ }
+
+ this.id = new UUID(upper, lower);
+ }
+
+
+ /**
+ * Get the OUI of one NIC of this host.
+ *
+ * @return null if no OUI could be detected, otherwise the OUI in the lower three bytes of a Long.
+ */
+ private Long getNodeOUI()
+ {
+ byte[] node = null;
+ String logPrefix = "Unable to detect host. Use random value.";
+
+ try {
+ InetAddress ipa = InetAddress.getLocalHost();
+ NetworkInterface iface = NetworkInterface.getByInetAddress(ipa);
+ if (iface != null) {
+ node = iface.getHardwareAddress();
+ logPrefix = "From getLocalHost:";
+ }
+
+ if (node == null) {
+ List<byte[]> macs = new ArrayList<>();
+ List<byte[]> offmacs = new ArrayList<>();
+ Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
+ while (interfaces.hasMoreElements()) {
+ iface = interfaces.nextElement();
+ byte[] mac = iface.getHardwareAddress();
+ if (mac != null) {
+ if (iface.isLoopback()) {
+ continue;
+ }
+ if (iface.isVirtual() || iface.isPointToPoint()) {
+ continue;
+ }
+ if (iface.isUp()) {
+ macs.add(mac);
+ }
+ else {
+ offmacs.add(mac);
+ }
+ }
+ }
+
+ if (macs.size() == 1) {
+ node = macs.get(0);
+ logPrefix = "From up iface:";
+ }
+ else if (offmacs.size() == 1) {
+ node = offmacs.get(0);
+ logPrefix = "From down iface:";
+ }
+ }
+
+ if (node == null) {
+ Socket socket = new Socket("www.gitblit.dev", 80);
+ ipa = socket.getLocalAddress();
+ socket.close();
+ iface = NetworkInterface.getByInetAddress(ipa);
+ if (iface != null) {
+ node = iface.getHardwareAddress();
+ logPrefix = "From socket:";
+ }
+ }
+
+ if (node == null) {
+ log.debug(logPrefix);
+ return null;
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("{} {}", logPrefix, String.format("%02X:%02X:%02X", node[0], node[1], node[2]));
+ }
+
+ long l = (((long)node[0]) << 16) & 0xff0000;
+ l |= (((long)node[1]) << 8) & 0xff00;
+ l |= ((long)node[2]) & 0xff;
+ return l;
+ }
+ catch (IOException e) {
+ log.debug("Exception while getting OUI: {}", e.getMessage(), e);
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/instance/GitblitInstanceReport.java b/src/main/java/com/gitblit/instance/GitblitInstanceReport.java
new file mode 100644
index 00000000..7b8db370
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstanceReport.java
@@ -0,0 +1,43 @@
+package com.gitblit.instance;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+/**
+ * GitblitInstanceReport collects the static and dynamic statistics about a running
+ * Gitblit instance, pairs it with a report version and instance id.
+ * This can then be send to the popularity report server.
+ *
+ */
+class GitblitInstanceReport
+{
+ private final int reportVersion = 1;
+ @SerializedName("instance")
+ private final String instanceId;
+ private final String startTs;
+ private String lpingTs;
+
+ final GitblitInstanceStat instanceStat;
+
+ GitblitInstanceReport(String instanceId, GitblitInstanceStat instanceStat)
+ {
+ this.instanceId = instanceId;
+ this.instanceStat = instanceStat;
+
+ // Convert the timestamp taken from instanceStat to a string in the format "yyyy-MM-dd'T'HHmmssZ" so
+ // it can be used better in a file name. It is replicated here so that it can be directly used by the receiver.
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ this.startTs = dateFormat.format(instanceStat.startTs);
+ }
+
+ GitblitInstanceReport fromNow()
+ {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ this.lpingTs = dateFormat.format(System.currentTimeMillis());
+ return this;
+ }
+}
diff --git a/src/main/java/com/gitblit/instance/GitblitInstanceStat.java b/src/main/java/com/gitblit/instance/GitblitInstanceStat.java
new file mode 100644
index 00000000..15ae6fa7
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstanceStat.java
@@ -0,0 +1,127 @@
+package com.gitblit.instance;
+
+import com.gitblit.models.ServerStatus;
+
+import java.util.Date;
+
+/**
+ * GitblitInstanceStat collects the static information about a Gitblit instance,
+ * such as its version, type, operating system and other static data.
+ *
+ */
+class GitblitInstanceStat
+{
+
+ enum GitblitInstanceType {
+ GO,
+ WAR,
+ EXPRESS,
+ DOCKER
+ }
+
+ final GitblitInstanceType instanceType;
+
+ String version;
+ Date startTs;
+ String os;
+ String osName;
+ String osVersion;
+ String osArch;
+ String javaVersion;
+ String javaVendor;
+ String javaRuntimeVersion;
+ String javaRuntimeName;
+ String javaVmVersion;
+ String javaVmName;
+ long maxMem;
+
+
+ GitblitInstanceStat()
+ {
+ this.instanceType = GitblitInstanceType.WAR;
+ initOS();
+ initJava();
+ }
+
+ GitblitInstanceStat(GitblitInstanceType instanceType)
+ {
+ this.instanceType = instanceType;
+ initOS();
+ initJava();
+ }
+
+
+ GitblitInstanceStat init(ServerStatus serverStatus)
+ {
+ this.version = serverStatus.version;
+ this.startTs = serverStatus.bootDate;
+
+ this.maxMem = serverStatus.heapMaximum;
+
+ return this;
+ }
+
+
+ void initOS()
+ {
+ String os = System.getProperty("os.name");
+ if (os == null) {
+ this.os = "Unknown";
+ } else {
+ String oslc = os.toLowerCase();
+ if (oslc.contains("windows")) {
+ this.os = "Windows";
+ } else if (oslc.contains("linux")) {
+ this.os = "Linux";
+ } else if (oslc.contains("mac") || oslc.contains("darwin")) {
+ this.os = "macOS";
+ } else if (oslc.contains("bsd")) {
+ this.os = "BSD";
+ } else if (oslc.contains("solaris") || oslc.contains("sun") ||
+ oslc.contains("aix") || oslc.contains("hpux") || oslc.contains("unix")) {
+ this.os = "Unix";
+ } else {
+ this.os = os;
+ }
+ }
+
+ this.osName = System.getProperty("os.name");
+ this.osVersion = System.getProperty("os.version");
+ this.osArch = System.getProperty("os.arch");
+ }
+
+ void initJava()
+ {
+ this.javaVersion = System.getProperty("java.version");
+ this.javaVendor = System.getProperty("java.vendor");
+ this.javaRuntimeVersion = System.getProperty("java.runtime.version", "");
+ this.javaRuntimeName = System.getProperty("java.runtime.name", "");
+ this.javaVmVersion = System.getProperty("java.vm.version", "");
+ this.javaVmName = System.getProperty("java.vm.name", "");
+ }
+
+
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("GitblitInstanceStat {")
+ .append("\n instanceType: ").append(instanceType)
+ .append(",\n version: ").append(version)
+ .append(",\n startTs: ").append(startTs)
+ .append(",\n os: ").append(os)
+ .append(",\n osName: ").append(osName)
+ .append(",\n osVersion: ").append(osVersion)
+ .append(",\n osArch: ").append(osArch)
+ .append(",\n javaVersion: ").append(javaVersion)
+ .append(",\n javaVendor: ").append(javaVendor)
+ .append(",\n javaRuntimeVersion: ").append(javaRuntimeVersion)
+ .append(",\n javaRuntimeName: ").append(javaRuntimeName)
+ .append(",\n javaVmVersion: ").append(javaVmVersion)
+ .append(",\n javaVmName: ").append(javaVmName)
+ .append(",\n maxMem: ").append(maxMem)
+ .append("\n}");
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/gitblit/models/ServerStatus.java b/src/main/java/com/gitblit/models/ServerStatus.java
index bb6396bc..db56f8f9 100644
--- a/src/main/java/com/gitblit/models/ServerStatus.java
+++ b/src/main/java/com/gitblit/models/ServerStatus.java
@@ -51,9 +51,9 @@ public class ServerStatus implements Serializable {
public String servletContainer;
- public ServerStatus() {
+ public ServerStatus(String version) {
this.bootDate = new Date();
- this.version = Constants.getVersion();
+ this.version = version;
this.releaseDate = Constants.getBuildDate();
this.heapMaximum = Runtime.getRuntime().maxMemory();
@@ -76,6 +76,10 @@ public class ServerStatus implements Serializable {
put("os.version");
}
+ public ServerStatus() {
+ this(Constants.getVersion());
+ }
+
private void put(String key) {
systemProperties.put(key, System.getProperty(key));
}
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index cd8615a8..b370867c 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -32,6 +32,7 @@ import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
+import com.gitblit.instance.GitblitInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -87,6 +88,8 @@ public class GitblitContext extends GuiceServletContextListener {
private final File goBaseFolder;
+ private final GitblitInstance instance = new GitblitInstance();
+
/**
* Construct a Gitblit WAR/Express context.
*/
@@ -224,6 +227,10 @@ public class GitblitContext extends GuiceServletContextListener {
logger.error(null, t);
}
}
+
+ instance.init(runtime);
+ // The instance is up and running. Make it count.
+ instance.start();
}
private String lookupBaseFolderFromJndi() {
@@ -303,6 +310,8 @@ public class GitblitContext extends GuiceServletContextListener {
}
}
+ this.instance.stop();
+
for (IManager manager : managers) {
logger.debug("stopping {}", manager.getClass().getSimpleName());
manager.stop();
diff --git a/src/test/config/test-gitblit.properties b/src/test/config/test-gitblit.properties
index ef6a6c51..1b988cf7 100644
--- a/src/test/config/test-gitblit.properties
+++ b/src/test/config/test-gitblit.properties
@@ -1,6 +1,7 @@
#
# Gitblit Unit Testing properties
#
+gitblit.testRun = true
git.allowAnonymousPushes = true
git.defaultAccessRestriction = NONE
git.repositoriesFolder = ${baseFolder}/git
diff --git a/src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java b/src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java
new file mode 100644
index 00000000..e1c03757
--- /dev/null
+++ b/src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java
@@ -0,0 +1,158 @@
+package com.gitblit.instance;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+public class GitblitInstanceIdTest
+{
+ @Rule
+ public TemporaryFolder baseFolder = new TemporaryFolder();
+
+ /**
+ * Tests that the version nibble is set to 0x8.
+ */
+ @Test
+ public void testUuidVersion() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId();
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long upper = uuid.getMostSignificantBits();
+ assertEquals(0x0000000000008000L, (upper & 0x000000000000F000L));
+ }
+
+ /**
+ * Tests that the variant nibble is set to 0x8.
+ */
+ @Test
+ public void testUuidVariant() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId();
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long lower = uuid.getLeastSignificantBits();
+ assertEquals(0x8000000000000000L, (lower & 0xF000000000000000L));
+ }
+
+ /**
+ * Test that the first four bytes hold a timestamp in a newly generated id.
+ */
+ @Test
+ public void testDatePart() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId();
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long upper = uuid.getMostSignificantBits();
+ long ts = System.currentTimeMillis();
+ assertEquals("Date part of UUID does not equal current date/time.", ts >> 2*8, upper >> 4*8);
+ }
+
+
+
+ /**
+ * Test that a new id is generated and stored in a file, when none existed.
+ */
+ @Test
+ public void testStoreId() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId(baseFolder.getRoot());
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long lower = uuid.getLeastSignificantBits();
+ assertEquals(0x8000000000000000L, (lower & 0xF000000000000000L));
+ long upper = uuid.getMostSignificantBits();
+ assertEquals(0x0000000000008000L, (upper & 0x000000000000F000L));
+
+ File idFile = new File(baseFolder.getRoot(), GitblitInstanceId.STORAGE_FILE);
+ assertTrue("Id file was not created", idFile.exists());
+
+ String string = Files.readAllLines(idFile.toPath()).get(0);
+ try {
+ UUID uuidFromFile = UUID.fromString(string);
+ assertEquals("Returned id and id read from file are not equal.", uuid, uuidFromFile);
+ } catch (IllegalArgumentException e) {
+ fail("UUID read from file is not valid: " + string);
+ }
+ }
+
+
+ /**
+ * Test that a new id is generated and stored in a file, when none existed.
+ */
+ @Test
+ public void testStoreIdNonexistingFolder() throws Exception
+ {
+ File baseSubFolder = new File(baseFolder.getRoot(), "nonexisting");
+
+ GitblitInstanceId id = new GitblitInstanceId(baseSubFolder);
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long lower = uuid.getLeastSignificantBits();
+ assertEquals(0x8000000000000000L, (lower & 0xF000000000000000L));
+ long upper = uuid.getMostSignificantBits();
+ assertEquals(0x0000000000008000L, (upper & 0x000000000000F000L));
+
+ File idFile = new File(baseSubFolder, GitblitInstanceId.STORAGE_FILE);
+ assertTrue("Id file was not created", idFile.exists());
+
+ String string = Files.readAllLines(idFile.toPath()).get(0);
+ try {
+ UUID uuidFromFile = UUID.fromString(string);
+ assertEquals("Returned id and id read from file are not equal.", uuid, uuidFromFile);
+ } catch (IllegalArgumentException e) {
+ fail("UUID read from file is not valid: " + string);
+ }
+ }
+
+
+ /**
+ * Test that an existing id is read from an existing id file.
+ */
+ @Test
+ public void testReadId() throws Exception
+ {
+ File idFile = new File(baseFolder.getRoot(), GitblitInstanceId.STORAGE_FILE);
+ String uuidString = "0196e409-c664-82f3-88f1-e963d16c7b8a";
+ Files.write(idFile.toPath(), uuidString.getBytes());
+
+ GitblitInstanceId id = new GitblitInstanceId(baseFolder.getRoot());
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+
+ UUID refUuid = UUID.fromString(uuidString);
+ assertEquals("Returned id is not equal to reference id", refUuid, uuid);
+ }
+
+
+ /**
+ * Test reading id from a file with whitespace
+ */
+ @Test
+ public void testReadIdWhitespace() throws Exception
+ {
+ File idFile = new File(baseFolder.getRoot(), GitblitInstanceId.STORAGE_FILE);
+ String uuidString = "0196e409-c664-82f3-88f1-e963d16c7b8a";
+ String fileString = "\n " + uuidString + " \n \n";
+ Files.write(idFile.toPath(), fileString.getBytes());
+
+ GitblitInstanceId id = new GitblitInstanceId(baseFolder.getRoot());
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+
+ UUID refUuid = UUID.fromString(uuidString);
+ assertEquals("Returned id is not equal to reference id", refUuid, uuid);
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java b/src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java
new file mode 100644
index 00000000..0b883a33
--- /dev/null
+++ b/src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java
@@ -0,0 +1,184 @@
+package com.gitblit.instance;
+
+import com.gitblit.Constants;
+import com.gitblit.models.ServerStatus;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Date;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class GitblitInstanceStatTest
+{
+
+ protected GitblitInstanceStat instanceStat;
+ protected ServerStatus serverStatus;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ instanceStat = new GitblitInstanceStat();
+ serverStatus = new ServerStatus();
+ instanceStat.init(serverStatus);
+ }
+
+
+ @Test
+ public void testGetVersion()
+ {
+ String version = instanceStat.version;
+ assertNotNull(version);
+ assertFalse(version.isEmpty());
+ assertEquals(Constants.getVersion(), version);
+ }
+
+ @Test
+ public void testGetStartTs()
+ {
+ Date date = instanceStat.startTs;
+ assertNotNull(date);
+ assertEquals(serverStatus.bootDate, date);
+ }
+
+ @Test
+ public void testGetType()
+ {
+ String type = instanceStat.instanceType.name();
+ assertNotNull(type);
+ assertFalse(type.isEmpty());
+ assertEquals("WAR", type);
+ }
+
+ @Test
+ public void testGetOS()
+ {
+ String os = instanceStat.os;
+
+ String oslc = System.getProperty("os.name").toLowerCase();
+
+ if (oslc.contains("windows")) {
+ assertEquals("Windows", os);
+ }
+ else if (oslc.contains("linux")) {
+ assertEquals("Linux", os);
+ }
+ else if (oslc.contains("mac")) {
+ assertEquals("macOS", os);
+ }
+ }
+
+ @Test
+ public void testGetOSName()
+ {
+ String name = instanceStat.osName;
+ assertNotNull(name);
+ assertFalse(name.isEmpty());
+ assertEquals(System.getProperty("os.name"), name);
+ }
+
+ @Test
+ public void testGetOSVersion()
+ {
+ String version = instanceStat.osVersion;
+ assertNotNull(version);
+ assertFalse(version.isEmpty());
+ assertEquals(System.getProperty("os.version"), version);
+ }
+
+ @Test
+ public void testGetOSArch()
+ {
+ String arch = instanceStat.osArch;
+ assertNotNull(arch);
+ assertFalse(arch.isEmpty());
+ assertEquals(System.getProperty("os.arch"), arch);
+ }
+
+ @Test
+ public void testGetJavaVersion()
+ {
+ String version = instanceStat.javaVersion;
+ assertNotNull(version);
+ assertFalse(version.isEmpty());
+ assertEquals(System.getProperty("java.version"), version);
+ }
+
+ @Test
+ public void testGetJavaVendor()
+ {
+ String vendor = instanceStat.javaVendor;
+ assertNotNull(vendor);
+ assertFalse(vendor.isEmpty());
+ assertEquals(System.getProperty("java.vendor"), vendor);
+ }
+
+ @Test
+ public void testGetJavaRuntimeVersion()
+ {
+ String rt = instanceStat.javaRuntimeVersion;
+ assertNotNull(rt);
+ assertFalse(rt.isEmpty());
+ assertEquals(System.getProperty("java.runtime.version"), rt);
+ }
+
+ @Test
+ public void testGetJavaRuntimeName()
+ {
+ String rt = instanceStat.javaRuntimeName;
+ assertNotNull(rt);
+ assertFalse(rt.isEmpty());
+ assertEquals(System.getProperty("java.runtime.name"), rt);
+ }
+
+ @Test
+ public void testGetJavaVmVersion()
+ {
+ String vm = instanceStat.javaVmVersion;
+ assertNotNull(vm);
+ assertFalse(vm.isEmpty());
+ assertEquals(System.getProperty("java.vm.version"), vm);
+ }
+
+ @Test
+ public void testGetJavaVmName()
+ {
+ String vm = instanceStat.javaVmName;
+ assertNotNull(vm);
+ assertFalse(vm.isEmpty());
+ assertEquals(System.getProperty("java.vm.name"), vm);
+ }
+
+ @Test
+ public void testGetMaxMem()
+ {
+ long maxMem = instanceStat.maxMem;
+ assertTrue(maxMem > 0);
+ assertEquals(Runtime.getRuntime().maxMemory(), maxMem);
+ }
+
+ @Test
+ public void testToString()
+ {
+ String str = instanceStat.toString();
+ assertNotNull(str);
+ assertFalse(str.isEmpty());
+ assertTrue(str.contains("GitblitInstanceStat"));
+ assertTrue(str.contains("version"));
+ assertTrue(str.contains("instanceType"));
+ assertTrue(str.contains("os"));
+ assertTrue(str.contains("osName"));
+ assertTrue(str.contains("osVersion"));
+ assertTrue(str.contains("osArch"));
+ assertTrue(str.contains("javaVersion"));
+ assertTrue(str.contains("javaVendor"));
+ assertTrue(str.contains("javaRuntimeVersion"));
+ assertTrue(str.contains("javaRuntimeName"));
+ assertTrue(str.contains("javaVmVersion"));
+ assertTrue(str.contains("javaVmName"));
+
+ }
+}
diff --git a/src/test/java/com/gitblit/instance/GitblitInstanceTest.java b/src/test/java/com/gitblit/instance/GitblitInstanceTest.java
new file mode 100644
index 00000000..8ebc5d2a
--- /dev/null
+++ b/src/test/java/com/gitblit/instance/GitblitInstanceTest.java
@@ -0,0 +1,64 @@
+package com.gitblit.instance;
+
+import com.gitblit.manager.IRuntimeManager;
+
+import com.gitblit.models.ServerStatus;
+import com.gitblit.tests.mock.MockRuntimeManager;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+
+public class GitblitInstanceTest
+{
+ @Test
+ public void testShouldNotReportUnintialized()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ assertFalse(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldNotReportInTests()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ instance.init(new MockRuntimeManager());
+ assertFalse(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldNotReportInSnapshotVersion()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ IRuntimeManager runtimeManager = new MockRuntimeManager();
+ runtimeManager.getSettings().overrideSetting("gitblit.testRun", "false");
+ instance.init(runtimeManager);
+ assertFalse(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldReportIfForced()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ IRuntimeManager runtimeManager = new MockRuntimeManager();
+ runtimeManager.getSettings().overrideSetting("gitblit.testRunReporting", "true");
+ instance.init(runtimeManager);
+ assertTrue(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldReportInReleaseVersion()
+ {
+ ServerStatus serverStatus = new ServerStatus("1.10.123");
+ MockRuntimeManager runtimeManager = new MockRuntimeManager();
+ runtimeManager.setStatus(serverStatus);
+ runtimeManager.getSettings().overrideSetting("gitblit.testRun", "false");
+
+ GitblitInstance instance = new GitblitInstance();
+ instance.init(runtimeManager);
+ assertTrue(instance.shouldRunReports());
+ }
+
+}
diff --git a/src/test/java/com/gitblit/tests/GitBlitSuite.java b/src/test/java/com/gitblit/tests/GitBlitSuite.java
index fbae039c..94150325 100644
--- a/src/test/java/com/gitblit/tests/GitBlitSuite.java
+++ b/src/test/java/com/gitblit/tests/GitBlitSuite.java
@@ -26,6 +26,9 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import com.gitblit.instance.GitblitInstanceIdTest;
+import com.gitblit.instance.GitblitInstanceStatTest;
+import com.gitblit.instance.GitblitInstanceTest;
import com.gitblit.utils.TimeUtilsTest;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
@@ -74,7 +77,8 @@ import com.gitblit.utils.JGitUtils;
ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,
SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class, SshKerberosAuthenticationTest.class,
- GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class, TicketReferenceTest.class })
+ GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class, TicketReferenceTest.class,
+ GitblitInstanceIdTest.class, GitblitInstanceStatTest.class, GitblitInstanceTest.class })
public class GitBlitSuite {
public static final File BASEFOLDER = new File("data");
diff --git a/src/test/java/com/gitblit/tests/GitblitUnitTest.java b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
index 58bc60e4..2d915612 100644
--- a/src/test/java/com/gitblit/tests/GitblitUnitTest.java
+++ b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
@@ -31,7 +31,10 @@ import com.gitblit.servlet.GitblitContext;
public class GitblitUnitTest extends org.junit.Assert {
public static IStoredSettings settings() {
- return runtime().getSettings();
+ IStoredSettings settings = runtime().getSettings();
+ // Insert marker that this is running as a test
+ settings.overrideSetting("gitblit.testRun", "true");
+ return settings;
}
public static IRuntimeManager runtime() {
diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
index 8897ef7e..1553e2a5 100644
--- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
+++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
@@ -52,6 +52,8 @@ public class MockRuntimeManager implements IRuntimeManager {
public MockRuntimeManager(IStoredSettings settings) {
this.settings = settings;
+ // Insert marker that this is running as a test
+ settings.overrideSetting("gitblit.testRun", "true");
this.serverStatus = new ServerStatus();
this.serverStatus.servletContainer = "MockServer";
@@ -94,6 +96,11 @@ public class MockRuntimeManager implements IRuntimeManager {
return serverStatus.bootDate;
}
+ public void setStatus(ServerStatus status)
+ {
+ this.serverStatus = status;
+ }
+
@Override
public ServerStatus getStatus() {
// update heap memory status