Merge in default

This commit is contained in:
Simon MacMullen 2011-05-31 10:46:40 +01:00
commit d5ecd7c62f
22 changed files with 189 additions and 89 deletions

View File

@ -1,7 +1,7 @@
{application, rabbitmq_management,
[{description, "RabbitMQ Management Console"},
{vsn, "%%VSN%%"},
{modules, [rabbit_mgmt_app]}, %% TODO generate automatically. NB: _app needed!
{modules, []},
{registered, []},
{mod, {rabbit_mgmt_app, []}},
{env, [{http_log_dir, none}]},

View File

@ -13,4 +13,4 @@ $(PACKAGE_DIR)+pre-test::
if [ "`erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] >= [5,8]), halt().'`" != true ] ; then \
echo "Need Erlang/OTP R14A or higher" ; \
exit 1 ; \
fi
fi

View File

@ -24,9 +24,9 @@ table th { font-weight: normal; color: black; }
table th, table td { font: 12px/17px Verdana,sans-serif; padding: 4px; }
table.list th, table.list td { vertical-align: top; min-width: 5em; width: auto; }
table.list { border-width: 1px; border-bottom: 1px solid #bbb; margin-bottom: 1em; }
table.list th, table.list td { border-left: 1px solid #bbb; border-right: 1px solid #bbb; }
table.list th { text-align: center; border-top: 1px solid #bbb; border-bottom: 1px solid #bbb; }
table.list { border-width: 1px; border-bottom: 1px solid #ccc; margin-bottom: 1em; }
table.list th, table.list td { border-left: 1px solid #ccc; border-right: 1px solid #ccc; }
table.list th { text-align: center; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; }
table.list td a { display: block; width: 100%; }
table.list th a.sort { display: block; width: 100%; cursor: pointer; }
table.list th a.sort .arrow { color: #888; }
@ -67,10 +67,10 @@ td.c { text-align: center !important; }
td.r { text-align: right !important; }
p.status-ok { color: #888; }
p.status-error { background: #f44; border: 2px solid #800; color: white; margin-top: 50px !important; }
p.warning, div.form-popup-warn { background: #ff8; border: 2px solid #880; }
div.form-popup-info { background: #8f8; border: 2px solid #080; }
div.form-popup-help { text-align: left !important; background: #f8f8f8; border: 2px solid #888; }
p.status-error { background: #f44; border: 1px solid #800; color: white; margin-top: 50px !important; }
p.warning, div.form-popup-warn { background: #ff8; border: 1px solid #bb8; }
div.form-popup-info { background: #8f8; border: 1px solid #4b4; }
div.form-popup-help { text-align: left !important; background: #f8f8f8; border: 1px solid #ccc; }
div.form-popup-warn, div.form-popup-info, div.form-popup-help { margin: 20px; padding: 15px; border-radius: 10px; -moz-border-radius: 10px; text-align: center; max-width: 600px; }
p.status-error, p.warning { margin: 20px; padding: 15px; border-radius: 10px; -moz-border-radius: 10px; text-align: center; font-weight: bold; }
@ -88,16 +88,16 @@ div.section, div.section-hidden { margin: 0 0 1em 0; }
div.section-invisible div.hider { display: none; }
div.section div.hider, div.section-hidden div.hider { padding: 0.5em 0; }
div.section h2, div.section-hidden h2 { font-size: 1em; padding: 5px 5px 5px 25px; cursor: pointer; margin: 0; }
div.section-invisible h2 { background: white; border: 1px solid #ddd; background-image: url(../img/collapse.png); background-repeat:no-repeat; background-position:4px 4px; }
div.section-visible h2 { background: #eee; border: 1px solid #eee; background-image: url(../img/expand.png); background-repeat:no-repeat; background-position:4px 4px; }
div.section-invisible h2 { background: white; border-bottom: 1px solid #ddd; background-image: url(../img/collapse.png); background-repeat:no-repeat; background-position:4px 4px; }
div.section-visible h2 { background: #f8f8f8; border-bottom: 1px solid #ddd; background-image: url(../img/expand.png); background-repeat:no-repeat; background-position:4px 4px; }
form { margin: 0; }
form.inline-form { float: left; }
form.inline-form-right { float: right; }
input, select { padding: 0.2em; }
input[type=text], input[type=password] { font: 1.1em Lucidatypewriter, Courier, monospace; }
input[type=text], input[type=password] { font: 1.1em Andale Mono, Lucidatypewriter, Courier New, Courier, monospace; border: 1px solid #ccc; }
input[type=text].wide, input[type=password].wide { width: 300px; }
textarea { width: 600px; height: 200px; }
textarea { width: 600px; height: 200px; border: 1px solid #ccc; }
.mand { color: #f88; padding: 0 5px;}
table.form { margin-bottom: 0.5em; }
@ -107,11 +107,24 @@ table.form select { width: 200px; }
table.form select.narrow { width: 110px; }
table.form .multifield { margin: 0; padding: 0; }
table.form .multifield p { margin: 0; padding: 0; }
table.form label { margin-top: 5px; display: block; }
table.two-col-layout { width: 100%; }
table.two-col-layout > tbody > tr > td { width: 50%; vertical-align: top; }
input[type=submit], button { padding: 8px; background-color: #aaf; border-radius: 5px; -moz-border-radius: 5px; color: black !important; text-decoration: none; cursor: pointer; border: none; font-weight: bold; }
input[type=submit], button { padding: 8px; border-radius: 5px; -moz-border-radius: 5px; color: black !important; text-decoration: none; cursor: pointer; font-weight: normal; }
input[type=submit], button {
background: #ddf;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ddf),color-stop(1, #bbf));
border: 1px solid #88d;
}
input[type=submit]:hover, button:hover {
background: #bbf;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #bbf),color-stop(1, #99d));
border: 1px solid #66b;
}
.form-popup-warn, .form-popup-info, .form-popup-help { display: none; position: fixed; min-width: 500px; }
.form-popup-warn span, .form-popup-info span, .form-popup-help span { color: black; font-weight: bold; cursor: pointer; }
@ -120,8 +133,8 @@ h3 { padding: 0 0 2px 0; margin: 1em 0 1em 0; font-size: 1em; border-bottom: 1px
acronym { background: #add; color: #222; padding: 2px 4px; border-radius: 2px; -moz-border-radius: 2px; border: none; cursor: default; }
table.bindings { margin-bottom: 2em; }
td.binding-endpoint span.object { border: 2px solid #bbb; padding: 10px; border-radius: 10px; -moz-border-radius: 10px; }
table.bindings { margin-bottom: 1em; }
td.binding-endpoint span.object { border: 1px solid #bbb; padding: 10px; border-radius: 10px; -moz-border-radius: 10px; }
td.binding-endpoint span.arrow { font-size: 200%; }
#no-password { display: none; }
@ -141,5 +154,5 @@ tr.alt2>td {
.highlight, .mini-highlight {
background: -moz-linear-gradient(center top, #f0f0f0 0%,#e0e0e0 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #f0f0f0),color-stop(1, #e0e0e0));
border: 2px solid #e0e0e0;
border: 1px solid #e0e0e0;
}

View File

@ -47,20 +47,59 @@ function fmt_date(d) {
":" + f(d.getSeconds());
}
KNOWN_ARGS = {'alternate-exchange': 'AE',
'x-message-ttl': 'TTL',
'x-expires': 'Exp'};
IMPLICIT_ARGS = {'durable': 'D',
'auto-delete': 'AD',
'internal': 'I'};
ALL_ARGS = {};
for (var k in KNOWN_ARGS) ALL_ARGS[k] = KNOWN_ARGS[k];
for (var k in IMPLICIT_ARGS) ALL_ARGS[k] = IMPLICIT_ARGS[k];
function fmt_parameters(obj) {
return fmt_table_short(args_to_params(obj));
}
function fmt_parameters_short(obj) {
var res = '';
var params = args_to_params(obj);
for (var k in ALL_ARGS) {
if (params[k] != undefined) {
res += '<acronym title="' + k + ': ' + params[k] + '">' +
ALL_ARGS[k] + '</acronym> ';
}
}
if (params.arguments) {
res += '<acronym title="' + fmt_table_flat(params.arguments) +
'">Args</acronym>';
}
return res;
}
function args_to_params(obj) {
var res = {};
for (var k in obj.arguments) {
if (k in KNOWN_ARGS) {
res[k] = obj.arguments[k];
}
else {
if (res.arguments == undefined) res.arguments = {};
res.arguments[k] = obj.arguments[k];
}
}
if (obj.durable) {
res += '<acronym title="Durable">D</acronym> ';
res['durable'] = true;
}
if (obj.auto_delete) {
res += '<acronym title="Auto-delete">AD</acronym> ';
res['auto-delete'] = true;
}
if (obj.internal != undefined && obj.internal) {
res += '<acronym title="Internal">I</acronym> ';
}
var args = fmt_table_short(obj.arguments);
if (args != '') {
res += args;
res['internal'] = true;
}
return res;
}
@ -183,6 +222,30 @@ function fmt_amqp_value(val) {
}
}
function fmt_table_flat(table) {
var res = [];
for (k in table) {
res.push(k + ': ' + fmt_amqp_value_flat(table[k]));
}
return res.join(', ');
}
function fmt_amqp_value_flat(val) {
if (val instanceof Array) {
var val2 = new Array();
for (var i = 0; i < val.length; i++) {
val2[i] = fmt_amqp_value_flat(val[i]);
}
return '[' + val2.join(",") + ']';
} else if (val instanceof Object) {
return '(' + fmt_table_flat(val) + ')';
} else if (typeof(val) == 'string') {
return fmt_escape_html(val);
} else {
return val;
}
}
function fmt_uptime(u) {
var uptime = Math.floor(u / 1000);
var sec = uptime % 60;

View File

@ -1,4 +1,4 @@
<h3>Add Binding</h3>
<h3>Add binding</h3>
<form action="#/bindings" method="post">
<table class="bindings">
<tr>
@ -42,7 +42,7 @@
</tr>
<% } %>
<tr>
<th><label>Routing Key:</label></th>
<th><label>Routing key:</label></th>
<td><input type="text" name="routing_key" value=""/></td>
</tr>
<tr>

View File

@ -1,3 +1,4 @@
<%= maybe_truncate(bindings) %>
<% if (bindings.length > 0) { %>
<table class="list bindings">
<thead>
@ -7,7 +8,7 @@
<% } else { %>
<th>From</th>
<% } %>
<th>Routing Key</th>
<th>Routing key</th>
<th>Arguments</th>
<th></th>
</tr>

View File

@ -72,7 +72,7 @@
<% if (statistics_level == 'fine') { %>
<div class="section">
<h2>Message Rates</h2>
<h2>Message rates</h2>
<div class="hider updatable">
<table class="two-col-layout">
<tr>

View File

@ -133,7 +133,7 @@
<% if (properties_size(connection.client_properties) > 0) { %>
<div class="section-hidden">
<h2>Client Library</h2>
<h2>Client properties</h2>
<div class="hider">
<%= fmt_table_long(connection.client_properties) %>
</div>
@ -141,7 +141,7 @@
<% } %>
<div class="section-hidden">
<h2>Close This Connection</h2>
<h2>Close this connection</h2>
<div class="hider">
<form action="#/connections" method="delete" class="confirm">
<input type="hidden" name="name" value="<%= connection.name %>"/>

View File

@ -4,12 +4,12 @@
<tr>
<% if (mode == 'queue') { %>
<th>Channel</th>
<th>Consumer Tag</th>
<th>Consumer tag</th>
<% } else { %>
<th>Consumer Tag</th>
<th>Consumer tag</th>
<th>Queue</th>
<% } %>
<th>Ack Required</th>
<th>Ack required</th>
<th>Exclusive</th>
</tr>
</thead>

View File

@ -25,7 +25,7 @@
<% if (statistics_level == 'fine') { %>
<div class="section-hidden">
<h2>Message Rates</h2>
<h2>Message rates</h2>
<div class="hider updatable">
<table class="two-col-layout">
<tr>
@ -96,7 +96,7 @@
<% if (!exchange.internal) { %>
<div class="section-hidden">
<h2>Publish Message</h2>
<h2>Publish message</h2>
<div class="hider">
<form action="#/exchanges/publish" method="post">
<input type="hidden" name="vhost" value="<%= exchange.vhost %>"/>
@ -118,8 +118,10 @@
</tr>
<tr>
<th>
<label>Headers:</label>
<span class="help" id="message-publish-headers"></span>
<label>
Headers:
<span class="help" id="message-publish-headers"></span>
</label>
</th>
<td>
<span class="multifield" id="headers"></span>
@ -127,8 +129,10 @@
</tr>
<tr>
<th>
<label>Properties:</label>
<span class="help" id="message-publish-properties"></span>
<label>
Properties:
<span class="help" id="message-publish-properties"></span>
</label>
</th>
<td>
<span class="multifield" id="props"></span>
@ -139,7 +143,7 @@
<td><textarea name="payload"></textarea></td>
</tr>
</table>
<input type="submit" value="Publish Message" />
<input type="submit" value="Publish message" />
</form>
<span class="br"></span>
</div>
@ -148,7 +152,7 @@
<% if (exchange.name != "") { %>
<div class="section-hidden">
<h2>Delete This Exchange</h2>
<h2>Delete this exchange</h2>
<div class="hider">
<form action="#/exchanges" method="delete" class="confirm">
<input type="hidden" name="vhost" value="<%= exchange.vhost %>"/>

View File

@ -28,7 +28,7 @@
<% } %>
<td><%= link_exchange(exchange.vhost, exchange.name) %></td>
<td class="c"><%= exchange.type %></td>
<td class="c"><%= fmt_parameters(exchange) %></td>
<td class="c"><%= fmt_parameters_short(exchange) %></td>
<td class="r"><%= fmt_rate(exchange.message_stats_in, 'publish', false) %></td>
</tr>
<% } %>
@ -42,6 +42,7 @@
<div class="hider">
<form action="#/exchanges" method="put">
<table class="form">
<% if (vhosts_interesting) { %>
<tr>
<th><label>Virtual host:</label></th>
<td>
@ -52,6 +53,9 @@
</select>
</td>
</tr>
<% } else { %>
<tr><td><input type="hidden" name="vhost" value="<%= vhosts[0].name %>"/></td></tr>
<% } %>
<tr>
<th><label>Name:</label></th>
<td><input type="text" name="name"/><span class="mand">*</span></td>

View File

@ -6,7 +6,7 @@
<table class="facts">
<tr>
<th>
File Descriptors <span class="help" id="file-descriptors"></span>
File descriptors <span class="help" id="file-descriptors"></span>
<sub>(used / available)</sub>
</th>
<td class="status">
@ -18,7 +18,7 @@
</tr>
<tr>
<th>
Socket Descriptors <span class="help" id="socket-descriptors"></span>
Socket descriptors <span class="help" id="socket-descriptors"></span>
<sub>(used / available)</sub>
</th>
<td class="status">
@ -30,7 +30,7 @@
</tr>
<tr>
<th>
Erlang Processes
Erlang processes
<sub>(used / available)</sub>
</th>
<td class="status">
@ -70,22 +70,22 @@
<td><%= fmt_uptime(node.uptime) %></td>
</tr>
<tr>
<th>RabbitMQ Version</th>
<th>RabbitMQ version</th>
<td><%= fmt_rabbit_version(node.applications) %></td>
</tr>
<tr>
<th>Erlang Version</th>
<th>Erlang version</th>
<td><%= node.erlang_version %></td>
</tr>
<tr>
<th>Mnesia Storage <span class="help" id="mnesia-storage"></span></th>
<th>Mnesia storage <span class="help" id="mnesia-storage"></span></th>
<td><%= node.type %></td>
</tr>
</table>
<table class="facts">
<tr>
<th>OS Pid</th>
<th>OS pid</th>
<td><%= node.os_pid %></td>
</tr>
<tr>
@ -93,7 +93,7 @@
<td><%= node.statistics_level %></td>
</tr>
<tr>
<th>Run Queue</th>
<th>Run queue</th>
<td><%= node.run_queue %></td>
</tr>
<tr>
@ -137,9 +137,9 @@
<div class="section-hidden">
<h2>Registry</h2>
<div class="hider updatable">
<h3>Exchange Types</h3>
<h3>Exchange types</h3>
<%= format('registry', {'list': node.exchange_types, 'node': node, 'show_enabled': false} ) %>
<h3>Authentication Mechanisms</h3>
<h3>Authentication mechanisms</h3>
<%= format('registry', {'list': node.auth_mechanisms, 'node': node, 'show_enabled': true} ) %>
</div>
</div>

View File

@ -3,7 +3,7 @@
<div class="section">
<h2>Totals</h2>
<div class="hider updatable">
<h3>Queued Messages</h3>
<h3>Queued messages</h3>
<div class="highlight">
Ready
<strong><%= overview.queue_totals.messages_ready %></strong>
@ -18,7 +18,7 @@
</div>
<span class="br"></span>
<% if (statistics_level == 'fine') { %>
<h3>Message Rates</h3>
<h3>Message rates</h3>
<%= message_rates(overview.message_stats) %>
<% } %>
<span class="br"></span>
@ -27,22 +27,22 @@
<% if (user_administrator) { %>
<div class="section">
<h2>Nodes and Ports</h2>
<h2>Nodes and ports</h2>
<div class="hider updatable">
<h3>RabbitMQ Nodes</h3>
<h3>RabbitMQ nodes</h3>
<table class="list">
<tr>
<th>Name</th>
<th>
File Descriptors <span class="help" id="file-descriptors"></span>
File descriptors <span class="help" id="file-descriptors"></span>
<sub>(used / available)</sub>
</th>
<th>
Socket Descriptors <span class="help" id="socket-descriptors"></span>
Socket descriptors <span class="help" id="socket-descriptors"></span>
<sub>(used / available)</sub>
</th>
<th>
Erlang Processes
Erlang processes
<sub>(used / available)</sub>
</th>
<th>
@ -53,7 +53,7 @@
Version
<sub>(RabbitMQ / Erlang)</sub>
</th>
<th>Mnesia Storage <span class="help" id="mnesia-storage"></span></th>
<th>Mnesia storage <span class="help" id="mnesia-storage"></span></th>
</tr>
<%
for (var i = 0; i < nodes.length; i++) {
@ -138,7 +138,7 @@
<tr>
<td>
<h3>Listening Ports</h3>
<h3>Listening ports</h3>
<table class="list">
<tr>
<th>Host</th>
@ -166,7 +166,7 @@
</table>
</td>
<td>
<h3>Web Contexts</h3>
<h3>Web contexts</h3>
<table class="list">
<tr>
<th>Context</th>
@ -203,7 +203,7 @@
</div>
<div class="section-hidden administrator-only">
<h2>Import / Export Configuration</h2>
<h2>Import / export configuration</h2>
<div class="hider">
<form action="../api/all-configuration" method="post" enctype="multipart/form-data">
<table class="two-col-layout">

View File

@ -8,11 +8,11 @@
<% if (mode == 'vhost') { %>
<th>User</th>
<% } else { %>
<th>Virtual Host</th>
<th>Virtual host</th>
<% } %>
<th>Configure Regexp</th>
<th>Write Regexp</th>
<th>Read Regexp</th>
<th>Configure regexp</th>
<th>Write regexp</th>
<th>Read regexp</th>
<th></th>
</tr>
</thead>
@ -46,7 +46,7 @@ for (var i = 0; i < permissions.length; i++) {
<% } %>
<div class="section-hidden">
<h2>Set Permission</h2>
<h2>Set permission</h2>
<div class="hider">
<form action="#/permissions" method="put">
<table class="form">
@ -74,19 +74,19 @@ for (var i = 0; i < permissions.length; i++) {
<% } %>
</tr>
<tr>
<th><label>Configure Regexp:</label></th>
<th><label>Configure regexp:</label></th>
<td><input type="text" name="configure" value=".*"/></td>
</tr>
<tr>
<th><label>Write Regexp:</label></th>
<th><label>Write regexp:</label></th>
<td><input type="text" name="write" value=".*"/></td>
</tr>
<tr>
<th><label>Read Regexp:</label></th>
<th><label>Read regexp:</label></th>
<td><input type="text" name="read" value=".*"/></td>
</tr>
</table>
<input type="submit" value="Set Permission"/>
<input type="submit" value="Set permission"/>
</form>
</div>
</div>

View File

@ -71,7 +71,7 @@
<% if (statistics_level == 'fine') { %>
<div class="section-hidden">
<h2>Message Rates</h2>
<h2>Message rates</h2>
<div class="hider updatable">
<table class="two-col-layout">
<tr>
@ -125,7 +125,7 @@
</div>
<div class="section-hidden">
<h2>Get Messages</h2>
<h2>Get messages</h2>
<div class="hider">
<p>
Warning: getting messages from a queue is a destructive action.
@ -168,7 +168,7 @@
</div>
<div class="section-hidden">
<h2>Delete / Purge</h2>
<h2>Delete / purge</h2>
<div class="hider">
<form action="#/queues" method="delete" class="confirm inline-form">
<input type="hidden" name="vhost" value="<%= queue.vhost %>"/>

View File

@ -53,7 +53,7 @@
<% } %>
</td>
<td class="c">
<%= fmt_parameters(queue) %>
<%= fmt_parameters_short(queue) %>
</td>
<td class="c"><%= fmt_idle(queue) %></td>
<td class="r"><%= fmt_string(queue.messages_ready) %></td>
@ -79,6 +79,7 @@
<div class="hider">
<form action="#/queues" method="put">
<table class="form">
<% if (vhosts_interesting) { %>
<tr>
<th><label>Virtual host:</label></th>
<td>
@ -89,6 +90,9 @@
</select>
</td>
</tr>
<% } else { %>
<tr><td><input type="hidden" name="vhost" value="<%= vhosts[0].name %>"/></td></tr>
<% } %>
<tr>
<th><label>Name:</label></th>
<td><input type="text" name="name"/><span class="mand">*</span></td>

View File

@ -27,7 +27,7 @@
<%= format('permissions', {'mode': 'user', 'permissions': permissions, 'vhosts': vhosts, 'parent': user}) %>
<div class="section-hidden">
<h2>Delete This User</h2>
<h2>Delete this user</h2>
<div class="hider">
<form action="#/users" method="delete" class="confirm">
<input type="hidden" name="username" value="<%= user.name %>"/>

View File

@ -7,6 +7,19 @@
</p>
<% } %>
<div class="section">
<h2>Overview</h2>
<div class="hider">
<table class="facts">
<tr>
<th>Tracing enabled:</th>
<td><%= fmt_boolean(vhost.tracing) %></td>
</tr>
</table>
<span class="br"></span>
</div>
</div>
<%= format('permissions', {'mode': 'vhost', 'permissions': permissions, 'users': users, 'parent': vhost}) %>
<div class="section-hidden">

View File

@ -201,7 +201,7 @@ if_unknown(Val, _Def) -> Val.
init([]) ->
{ok, #state{tables = orddict:from_list(
[{Key, ets:new(anon, [private])} ||
[{Key, ets:new(anon, [private, ordered_set])} ||
Key <- ?TABLES])}}.
handle_call({get_queue, Q0}, _From, State = #state{tables = Tables}) ->

View File

@ -39,8 +39,7 @@ resource_exists(ReqData, Context) ->
{rabbit_vhost:exists(id(ReqData)), ReqData, Context}.
to_json(ReqData, Context) ->
VHost = [{name, id(ReqData)}],
rabbit_mgmt_util:reply(VHost, ReqData, Context).
rabbit_mgmt_util:reply(rabbit_vhost:info(id(ReqData)), ReqData, Context).
accept_content(ReqData, Context) ->
put_vhost(id(ReqData)),

View File

@ -29,7 +29,8 @@ content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
to_json(ReqData, Context = #context{user = User}) ->
VHosts = format(rabbit_access_control:list_vhosts(User, read)),
VHosts = [rabbit_vhost:info(V) ||
V <- rabbit_access_control:list_vhosts(User, read)],
rabbit_mgmt_util:reply_list(VHosts, ReqData, Context).
is_authorized(ReqData, Context) ->
@ -38,7 +39,4 @@ is_authorized(ReqData, Context) ->
%%--------------------------------------------------------------------
vhosts() ->
format(rabbit_vhost:list()).
format(Vs) ->
[[{name, N}] || N <- Vs].
rabbit_vhost:info_all([name]).

View File

@ -56,16 +56,17 @@ auth_test() ->
%% This test is rather over-verbose as we're trying to test understanding of
%% Webmachine
vhosts_test() ->
[[{name, <<"/">>}]] = http_get("/vhosts"),
assert_list([[{name, <<"/">>}]], http_get("/vhosts")),
%% Create a new one
http_put("/vhosts/myvhost", [], ?NO_CONTENT),
%% PUT should be idempotent
http_put("/vhosts/myvhost", [], ?NO_CONTENT),
%% Check it's there
[[{name, <<"/">>}], [{name, <<"myvhost">>}]] = http_get("/vhosts"),
assert_list([[{name, <<"/">>}], [{name, <<"myvhost">>}]],
http_get("/vhosts")),
%% Check individually
[{name, <<"/">>}] = http_get("/vhosts/%2f", ?OK),
[{name, <<"myvhost">>}] = http_get("/vhosts/myvhost"),
assert_item([{name, <<"/">>}], http_get("/vhosts/%2f", ?OK)),
assert_item([{name, <<"myvhost">>}],http_get("/vhosts/myvhost")),
%% Delete it
http_delete("/vhosts/myvhost", ?NO_CONTENT),
%% It's not there