Permalink
Browse files

Add integration test skeleton

Introduced the new module raven-integration-tests to test the actual
sending of messages to Sentry.
  • Loading branch information...
1 parent ccab7f7 commit 5c80b75746277957ae43ab248719cfba1925bc04 @roam roam committed Jul 1, 2012
View
@@ -4,4 +4,5 @@ target/*
**/target/*
.idea/*
*.iml
-example.log
+example.log
+raven-integration-tests/src/main/resources/sentry.db
View
@@ -14,6 +14,7 @@
<modules>
<module>raven</module>
<module>raven-log4j</module>
+ <module>raven-integration-tests</module>
</modules>
<build>
@@ -0,0 +1,23 @@
+# Raven Integration Tests
+
+This module provides integration tests for Raven-Java with Sentry. Running these tests is a bit cumbersome, but worth
+it.
+
+## 1. Install Sentry
+Make sure you have Sentry installed. Follow the instructions in
+[Sentry's documentation](http://sentry.readthedocs.org/en/latest/quickstart/index.html#install-sentry) if you haven't.
+
+## 2. Install foreman
+[Foreman](http://ddollar.github.com/foreman/) allows you to use a Procfile which we can use to run the HTTP and UDP
+services of Sentry in the same terminal.
+
+## 3. Run `src/main/resources/run_sentry.sh` before running the tests
+This script will remove any existing `sentry.db` at the *same* location so we can start fresh and then perform a Sentry
+upgrade using `default_config.py` as the Sentry configuration. During this process, you will be asked to create a
+superuser. Use username and password `test`.
+
+Once the Sentry installation is finished, the `Procfile` at the same location will be used to kickstart Sentry HTTP and
+UDP services at ports 9500 and 9501 respectively.
+
+## 4. Run the tests
+Run the tests like you normally would.
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.kencochrane</groupId>
+ <artifactId>raven-all</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>raven-integration-tests</artifactId>
+ <packaging>jar</packaging>
+ <name>raven-integration-tests</name>
+ <description>Raven-Java/Sentry integration tests</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>raven</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jsoup</groupId>
+ <artifactId>jsoup</artifactId>
+ <version>1.6.3</version>
+ </dependency>
+ <dependency>
+ <groupId>com.googlecode.json-simple</groupId>
+ <artifactId>json-simple</artifactId>
+ <version>1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.googlecode.jmockit</groupId>
+ <artifactId>jmockit</artifactId>
+ <version>0.999.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.3</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id> <!-- this is used for inheritance merges -->
+ <phase>package</phase> <!-- bind to the packaging phase -->
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
@@ -0,0 +1,136 @@
+package net.kencochrane.raven;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Sentry tools.
+ */
+public class SentryApi {
+
+ public final String host;
+ public final HttpClient client = new DefaultHttpClient();
+ public final HttpContext context = new BasicHttpContext();
+ private boolean loggedIn;
+
+ public SentryApi() throws MalformedURLException {
+ this("http://localhost:9500");
+ }
+
+ public SentryApi(String host) {
+ this.host = host;
+ }
+
+ public boolean login(String username, String password) throws IOException {
+ if (loggedIn) {
+ return true;
+ }
+ String url = host + "/login/";
+ HttpResponse response = client.execute(new HttpGet(url), context);
+ String html = EntityUtils.toString(response.getEntity());
+ Document doc = Jsoup.parse(html);
+ Elements inputs = doc.select("input[name=csrfmiddlewaretoken]");
+ String token = inputs.get(0).val();
+ List<NameValuePair> formparams = new ArrayList<NameValuePair>();
+ formparams.add(new BasicNameValuePair("username", username));
+ formparams.add(new BasicNameValuePair("password", password));
+ formparams.add(new BasicNameValuePair("csrfmiddlewaretoken", token));
+ HttpPost post = new HttpPost(host + "/login/");
+ UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");
+ post.setEntity(entity);
+ response = client.execute(post, context);
+ if (response.getStatusLine().getStatusCode() == 302) {
+ EntityUtils.toString(response.getEntity());
+ response = client.execute(new HttpGet(url), context);
+ html = EntityUtils.toString(response.getEntity());
+ doc = Jsoup.parse(html);
+ html = doc.getElementById("header").select("li.dropdown").get(1).html();
+ loggedIn = html.contains(">Logout<");
+ }
+ return loggedIn;
+ }
+
+ public String getDsn(String projectSlug) throws IOException {
+ HttpResponse response = client.execute(new HttpGet(host + "/account/projects/" + projectSlug + "/docs/"));
+ String html = EntityUtils.toString(response.getEntity());
+ Document doc = Jsoup.parse(html);
+ Element wrapper = doc.select("#content code.clippy").get(0);
+ return StringUtils.trim(wrapper.html());
+ }
+
+ public boolean clear(String projectId) throws IOException {
+ HttpResponse response = client.execute(new HttpPost(host + "/api/" + projectId + "/clear/"));
+ boolean ok = (response.getStatusLine().getStatusCode() == 200);
+ EntityUtils.toString(response.getEntity());
+ return ok;
+ }
+
+ public List<Event> getEvents(String projectSlug) throws IOException {
+ HttpResponse response = client.execute(new HttpGet(host + "/" + projectSlug));
+ Document doc = Jsoup.parse(EntityUtils.toString(response.getEntity()));
+ Elements items = doc.select("ul#event_list li.event");
+ List<Event> events = new LinkedList<Event>();
+ for (Element item : items) {
+ int count = Integer.parseInt(item.attr("data-count"));
+ int level = extractLevel(item.classNames());
+ Element anchor = item.select("h3 a").get(0);
+ String link = anchor.attr("href");
+ String title = StringUtils.trim(anchor.text());
+ Element messageElement = item.select("p.message").get(0);
+ String message = StringUtils.trim(messageElement.attr("title"));
+ String logger = StringUtils.trim(messageElement.select("span.tag-logger").text());
+ events.add(new Event(count, level, link, title, message, logger));
+ }
+ return events;
+ }
+
+ protected static int extractLevel(Collection<String> classNames) {
+ for (String name : classNames) {
+ if (name.startsWith("level-")) {
+ return Integer.parseInt(name.replace("level-", ""));
+ }
+ }
+ return 0;
+ }
+
+ public static class Event {
+ public final int count;
+ public final int level;
+ public final String url;
+ public final String title;
+ public final String message;
+ public final String logger;
+
+ public Event(int count, int level, String url, String title, String message, String logger) {
+ this.count = count;
+ this.level = level;
+ this.url = url;
+ this.title = title;
+ this.message = message;
+ this.logger = logger;
+ }
+
+ }
+
+}
@@ -0,0 +1,2 @@
+web: sentry --config=default_config.py start http
+udp: sentry --config=default_config.py start udp
@@ -0,0 +1,49 @@
+import os.path
+
+CONF_ROOT = os.path.dirname(__file__)
+
+DATABASES = {
+ 'default': {
+ # You can swap out the engine for MySQL easily by changing this value
+ # to ``django.db.backends.mysql`` or to PostgreSQL with
+ # ``django.db.backends.postgresql_psycopg2``
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(CONF_ROOT, 'sentry.db'),
+ 'USER': 'postgres',
+ 'PASSWORD': '',
+ 'HOST': '',
+ 'PORT': '',
+ }
+}
+
+SENTRY_KEY = 'dhrlPFFtABltJoCdbQ9b327uY6vufXGOymBZnC348p3Hoeot0K8CTw=='
+
+# Set this to false to require authentication
+SENTRY_PUBLIC = True
+
+# You should configure the absolute URI to Sentry. It will attempt to guess it if you don't
+# but proxies may interfere with this.
+# SENTRY_URL_PREFIX = 'http://sentry.example.com' # No trailing slash!
+
+SENTRY_WEB_HOST = '0.0.0.0'
+SENTRY_WEB_PORT = 9500
+SENTRY_WEB_OPTIONS = {
+ 'workers': 3, # the number of gunicorn workers
+ # 'worker_class': 'gevent',
+}
+
+# Mail server configuration
+
+# For more information check Django's documentation:
+# https://docs.djangoproject.com/en/1.3/topics/email/?from=olddocs#e-mail-backends
+
+EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
+
+EMAIL_HOST = 'localhost'
+EMAIL_HOST_PASSWORD = ''
+EMAIL_HOST_USER = ''
+EMAIL_PORT = 25
+EMAIL_USE_TLS = False
+
+SENTRY_UDP_HOST = '0.0.0.0' # bind to all addresses
+SENTRY_UDP_PORT = 9501
@@ -0,0 +1,4 @@
+#!/bin/sh
+rm -f sentry.db
+sentry --config=default_config.py upgrade
+foreman start
Oops, something went wrong.

0 comments on commit 5c80b75

Please sign in to comment.