Project

General

Profile

« Previous | Next » 

Revision 7cdaddab

Added by Shlomi Zadok over 8 years ago

fixes #12714 - Show proxy status in index, and create a show page for proxy

View differences:

app/assets/javascripts/about.js
$(function() {
$(".proxy-version").each(function(index, item) {
var item = $(item);
var url = item.data('url');
$.ajax({
type: 'get',
url: url,
success: function(response) {
item.attr('title',response.message);
if(response.success == true) {
item.addClass('label label-success')
item.text(__(response.message));
} else {
item.addClass('label label-danger')
item.text(__('Error'));
}
item.tooltip({html: true});
}
})
});
$(".proxy-status, .compute-status").each(function(index, item) {
"use strict";
$(".compute-status").each(function(index, item) {
var item = $(item);
var url = item.data('url');
$.ajax({
......
success: function(response) {
item.text(__(response.status));
item.attr('title',response.message);
if(response.status == "OK"){
if(response.status === "OK"){
item.addClass('label label-success')
}else{
item.addClass('label label-danger')
}
item.tooltip({html: true});
}
})
});
});
});
app/assets/javascripts/application.js
//= require two-pane
//= require vendor
//= require about
//= require proxy_status
//= require jquery.extentions
//= require jquery.multi-select
//= require settings
......
$(item).blur();
}
function icon(name) {
"use strict";
return '<span class="glyphicon glyphicon-' + name + '" />';
}
app/assets/javascripts/proxy_status.js
function setItemStatus(item, response) {
if(response.success) {
item.attr('title', __('Active'));
item.addClass('text-success');
item.html(icon('ok-sign'));
} else {
item.attr('title', response.message);
item.addClass('text-danger');
item.html(icon('exclamation-sign'));
}
item.tooltip({html: true});
}
function setProxyVersion(item, response) {
var text = response.message.version ? response.message.version : response.message;
generateItem(item, response.success, text);
}
function setPluginVersion(item, response) {
var pluginName = item.data('plugin');
var pluginVersion = response.message.modules ? response.message.modules[pluginName] : response.message;
generateItem(item, response.success, pluginVersion);
}
function generateItem(item, status, text) {
"use strict";
if (status === true) {
item.text(text);
} else {
item.attr('title', text);
item.addClass('text-danger');
item.html(icon('exclamation-sign'));
}
item.tooltip({html: true});
}
$(function() {
$('.proxy-show').each(function(index, item) {
var proxy = new ProxyStatus($(item));
proxy.getVersions();
});
$('.proxy-tftp').each(function(index, item) {
var item = $(item);
var url = item.data('url');
$.ajax({
type: 'get',
url: url,
success: function (response) {
generateItem(item, response.success, response.message);
},
error: function (response) {
generateItem(item, false, response.message);
}
});
});
});
function ProxyStatus(item) {
this.url = item.data('url');
this.item = item;
var self = this;
this.getVersions = function() {
$.ajax({
type: 'get',
url: this.url,
success: function (response) {
populateData(response, self.item);
}.bind(this),
error: function (response) {
populateData(response, self.item);
}.bind(this)
});
};
}
function populateData(response, item) {
$(item.children().find(".proxy-version")).each(function(index, i) {
var item = $(i);
setProxyVersion(item, response);
});
$(".plugin-version").each(function(index, i) {
var item = $(i);
setPluginVersion(item, response);
});
$(item.children().find(".proxy-show-status")).each(function(index, i) {
var item = $(i);
setItemStatus(item, response);
});
}
app/assets/javascripts/two-pane.js
}
});
$(document).on('click', "a[href$='edit'].edit_two_pane", function(e) {
if ($('.table-two-pane').length) {
e.preventDefault();
two_pane_open(this);
}
});
$(document).on('submit','.two-pane-right', function() {
two_pane_submit();
return false;
app/assets/stylesheets/application.scss
.spinner-placeholder {
width: 16px;
height: 16px;
background: image-url('spinner.gif');
background: image-url('spinner.gif') no-repeat top left;
text-indent: 20px;
white-space: nowrap;
margin: 20% 30% 0 40%;
display: block;
}
.exit-fullscreen {
......
.ms-container {
background: transparent image-url('switch.png') no-repeat 270px 80px;
}
.big {
font-size: 3rem;
color: #797979;
}
app/assets/stylesheets/bootstrap_and_overrides.scss
.btn-strike {
text-decoration: line-through;
}
#proxy-tab {
margin-bottom: 0px;
}
.proxy-content.tab-content {
padding: 19px;
min-height: 0px;
border: 1px solid #ddd;
border-radius: 2px;
border-top: 0px;
float: left;
width: 100%;
}
app/assets/stylesheets/two_pane.scss
}
.two-pane-right{
.spinner-placeholder {
margin: 20% 30% 0 40%;
}
.well{
padding: 19px;
min-height: 460px;
app/controllers/smart_proxies_controller.rb
class SmartProxiesController < ApplicationController
include Foreman::Controller::AutoCompleteSearch
before_filter :find_resource, :only => [:edit, :update, :refresh, :ping, :version, :destroy]
before_filter :find_resource, :only => [:show, :edit, :update, :refresh, :ping, :tftp_server, :destroy]
def index
@smart_proxies = resource_base.includes(:features).search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
end
def show
end
def new
@smart_proxy = SmartProxy.new
end
......
@proxy = @smart_proxy
end
def ping
@proxy = @smart_proxy
respond_to do |format|
format.json {render :json => errors_hash(@smart_proxy.refresh)}
end
end
def refresh
old_features = @smart_proxy.features
old_features = @smart_proxy.features.to_a
if @smart_proxy.refresh.blank? && @smart_proxy.save
msg = @smart_proxy.features == old_features ? _("No changes found when refreshing features from %s.") : _("Successfully refreshed features from %s.")
msg = @smart_proxy.features.to_a == old_features ? _("No changes found when refreshing features from %s.") : _("Successfully refreshed features from %s.")
process_success :object => @smart_proxy, :success_msg => msg % @smart_proxy.name
else
process_error :object => @smart_proxy
end
end
def version
begin
version = @smart_proxy.version
rescue Foreman::Exception => exception
render :json => {:success => false, :message => exception.message} and return
end
render :json => {:success => true, :message => version[:message]}
def ping
requested_data(:version)
end
def tftp_server
requested_data(:tftp_server)
end
def update
......
private
def requested_data(data_name)
data = @smart_proxy.public_send(data_name)
render :json => {:success => true, :message => data}
rescue Foreman::Exception => exception
render :json => {:success => false, :message => exception.message} and return
end
def action_permission
case params[:action]
when 'refresh'
:edit
when 'ping', 'version'
when 'ping', 'tftp_server'
:view
else
super
app/helpers/application_helper.rb
url, :rel => 'external', :class => 'btn btn-info', :target => '_blank')
end
def generate_links_for(sub_model)
return _("None found") if sub_model.empty?
sub_model.map {|model| link_to(model.to_label, { :controller => model.class.model_name.plural.downcase, :action => :index, :search => "name = #{model.name}" })}.to_sentence
end
private
def edit_inline(object, property, options = {})
app/helpers/layout_helper.rb
end
end
def spinner
'<span class="spinner-placeholder" />'.html_safe
end
private
def table_css_classes(classes = '')
app/helpers/smart_proxies_helper.rb
module SmartProxiesHelper
def proxy_actions(proxy, authorizer)
[ display_link_if_authorized(_("Edit"), hash_for_edit_smart_proxy_path(:id => proxy), :class => 'edit_two_pane') ] +
[if proxy.has_feature?('Puppet CA')
[display_link_if_authorized(_("Certificates"), hash_for_smart_proxy_puppetca_index_path(:smart_proxy_id => proxy).
merge(:auth_object => proxy, :permission => 'view_smart_proxies_puppetca', :authorizer => authorizer)),
merge(:auth_object => proxy, :permission => 'view_smart_proxies_puppetca', :authorizer => authorizer)),
display_link_if_authorized(_("Autosign"), hash_for_smart_proxy_autosign_index_path(:smart_proxy_id => proxy).
merge(:auth_object => proxy, :permission => 'view_smart_proxies_autosign', :authorizer => authorizer))]
end,
merge(:auth_object => proxy, :permission => 'view_smart_proxies_autosign', :authorizer => authorizer))]
end] +
[ display_delete_if_authorized(hash_for_smart_proxy_path(:id => proxy).merge(:auth_object => proxy, :authorizer => authorizer),
:data => {:confirm => _("Delete %s?") % proxy.name}, :class => 'delete') ]
end
def smart_proxy_title_actions(proxy, authorizer)
actions = [display_link_if_authorized(_("Refresh features"), hash_for_refresh_smart_proxy_path(:id => proxy).
merge(:auth_object => proxy, :permission => 'edit_smart_proxies', :authorizer => authorizer), :method => :put)]
if proxy.has_feature?('Puppet CA')
actions << [display_link_if_authorized(_("Certificates"), hash_for_smart_proxy_puppetca_index_path(:smart_proxy_id => proxy).
merge(:auth_object => proxy, :permission => 'view_smart_proxies_puppetca', :authorizer => authorizer))]
actions << [display_link_if_authorized(_("Autosign"), hash_for_smart_proxy_autosign_index_path(:smart_proxy_id => proxy).
merge(:auth_object => proxy, :permission => 'view_smart_proxies_autosign', :authorizer => authorizer))]
end
if SETTINGS[:unattended] and proxy.has_feature?('DHCP')
actions << display_link_if_authorized(_("Import subnets"), hash_for_import_subnets_path(:smart_proxy_id => proxy))
end
if SETTINGS[:unattended] and proxy.has_feature?('DHCP')
display_link_if_authorized(_("Import subnets"), hash_for_import_subnets_path(:smart_proxy_id => proxy))
end,
title_actions(
button_group(
link_to(_("Back"), smart_proxies_path)
),
select_action_button(_("Select Action"), {}, actions),
button_group(
display_link_if_authorized(_("Edit"), hash_for_edit_smart_proxy_path(:id => proxy))
),
button_group(
display_delete_if_authorized(hash_for_smart_proxy_path(:id => proxy).merge(:auth_object => proxy, :authorizer => authorizer),
:data => {:confirm => _("Delete %s?") % proxy.name}, :class => 'btn-danger')
)
)
end
display_link_if_authorized(_("Refresh features"), hash_for_refresh_smart_proxy_path(:id => proxy).
merge(:auth_object => proxy, :permission => 'edit_smart_proxies', :authorizer => authorizer), :method => :put),
def refresh_proxy_icon(proxy, authorizer)
display_link_if_authorized(icon_text("refresh"), hash_for_refresh_smart_proxy_path(:id => proxy).
merge(:auth_object => proxy, :permission => 'edit_smart_proxies', :authorizer => authorizer), :method => :put)
end
display_delete_if_authorized(hash_for_smart_proxy_path(:id => proxy).merge(:auth_object => proxy, :authorizer => authorizer), :data => { :confirm => _("Delete %s?") % proxy.name })]
def proxy_features_besides_puppet(proxy)
proxy_features_lowercase = proxy.features.pluck("LOWER(REPLACE(name, ' ', '_'))").uniq
puppet_features_lowercase = %w(puppet puppet_ca)
proxy_features_lowercase - puppet_features_lowercase
end
end
app/models/smart_proxy.rb
scoped_search :on => :url, :complete_value => :true
scoped_search :in => :features, :on => :name, :rename => :feature, :complete_value => :true
delegate :version, :tftp_server, :to => :proxy_status
# with proc support, default_scope can no longer be chained
# include all default scoping here
default_scope lambda {
......
scope :with_features, ->(*feature_names) { where(:features => { :name => feature_names }).joins(:features) if feature_names.any? }
HTTP_ERRORS = [Errno::EINVAL, Errno::ECONNRESET, EOFError, Timeout::Error,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError]
def hostname
URI(url).host
end
......
end
def refresh
proxy_status.revoke_cache!
associate_features
errors
end
......
self.features.any? { |proxy_feature| proxy_feature.name == feature }
end
def version
result = {}
begin
Timeout::timeout(20) do
version = ProxyAPI::Version.new(:url => url).version
result[:success] = true
result[:message] = version
end
rescue *HTTP_ERRORS => exception
raise ::Foreman::WrappedException.new exception, N_("Unable to connect to smart proxy")
end
result
end
private
def proxy_status
@proxy_status ||= ProxyStatus.new(self)
end
def sanitize_url
self.url.chomp!('/') unless url.empty?
end
app/services/foreman/access_permissions.rb
end
permission_set.security_block :smart_proxies do |map|
map.permission :view_smart_proxies, {:smart_proxies => [:index, :ping, :auto_complete_search, :version],
map.permission :view_smart_proxies, {:smart_proxies => [:index, :ping, :auto_complete_search, :version,
:show, :plugin_version, :tftp_server],
:"api/v1/smart_proxies" => [:index, :show],
:"api/v2/smart_proxies" => [:index, :show, :version]
}
app/services/proxy_status.rb
class ProxyStatus
CONNECTION_ERRORS = [Errno::EINVAL, Errno::ECONNRESET, EOFError, Timeout::Error, Errno::ENOENT,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError]
def initialize(proxy, opts = {})
@proxy = proxy
@cache_duration = opts[:cache_duration] || 3.minutes
@api ||= ProxyAPI::Version.new(:url => proxy.url)
end
def api_versions
Rails.cache.fetch(versions_cache_key, :expires_in => cache_duration) do
fetch_proxy_data do
api.proxy_versions
end
end
end
# TODO: extract to another status implementation
def tftp_server
raise ::Foreman::Exception.new(N_('No TFTP feature for %s') % proxy.to_label) unless proxy.has_feature?('TFTP')
Rails.cache.fetch("proxy_#{proxy.id}/tftp_server", :expires_in => cache_duration) do
fetch_proxy_data do
ProxyAPI::TFTP.new(:url => proxy.url).bootServer
end
end
end
def revoke_cache!
# As memcached does not support delete_matched, we need to delete each
Rails.cache.delete(versions_cache_key)
Rails.cache.delete("proxy_#{proxy.id}/tftp_server")
end
def versions_cache_key
"proxy_#{proxy.id}/versions"
end
private
attr_reader :proxy, :cache_duration, :api
alias_method :version, :api_versions
def fetch_proxy_data
begin
yield
rescue *CONNECTION_ERRORS => exception
raise ::Foreman::WrappedException.new exception, N_("Unable to connect to smart proxy")
end
end
end
app/views/about/index.html.erb
</thead>
<tbody>
<% @smart_proxies.each do |proxy| %>
<tr>
<td><%= link_to_if_authorized proxy.name, hash_for_edit_smart_proxy_path(proxy) %></td>
<tr class="proxy-show" data-url="<%= ping_smart_proxy_path(proxy) %>">
<td><%= link_to_if_authorized proxy.name, hash_for_smart_proxy_path(proxy) %></td>
<td><%=h proxy.features.to_sentence %></td>
<td><div class="proxy-status" data-url=<%= ping_smart_proxy_path(proxy) %>><%= _("Connecting..") %></div></td>
<td><div class="proxy-version" data-url=<%= version_smart_proxy_path(proxy) %>><%= _("Connecting..") %></div></td>
<td><div class="proxy-show-status"><%= spinner %></div></td>
<td><div class="proxy-version"><%= spinner %></div></td>
</tr>
<% end %>
</tbody>
......
<tr>
<td><%= link_to compute.name, compute %></td>
<td><%= compute.provider_friendly_name %></td>
<td><div class="compute-status" data-url=<%= ping_compute_resource_path(compute) %>><%= _("Connecting..") %></div></td>
<td><div class="compute-status" data-url=<%= ping_compute_resource_path(compute) %>><%= spinner %></div></td>
</tr>
<% end %>
</tbody>
app/views/smart_proxies/index.html.erb
<thead>
<tr>
<th class="col-md-2"><%= s_("SmartProxy|Name") %></th>
<th class="col-md-5"><%= s_("SmartProxy|Url") %></th>
<th class="col-md-3"><%= _("Features") %></th>
<th class="col-md-4"><%= s_("SmartProxy|Url") %></th>
<th class="col-md-4"><%= _("Features") %></th>
<th class="col-md-1"><%= _('Status') %></th>
<th></th>
</tr>
</thead>
<tbody>
<% for proxy in @smart_proxies %>
<tr>
<td class="display-two-pane ellipsis"><%= link_to_if_authorized proxy.name, hash_for_edit_smart_proxy_path(:id => proxy).merge(:auth_object => proxy, :authorizer => authorizer) %></td>
<td class="ellipsis"><%= proxy.url %></td>
<td class="ellipsis"><%= proxy.features.to_sentence %></td>
<tr class="proxy-show" data-url="<%= ping_smart_proxy_path(proxy) %>">
<td><%= link_to_if_authorized proxy.name, hash_for_smart_proxy_path(:id => proxy).merge(:auth_object => proxy, :authorizer => authorizer) %></td>
<td><%= proxy.url %></td>
<td><%= proxy.features.to_sentence %></td>
<td>
<span class="proxy-show-status"><%= spinner %></span>
</td>
<td><%= action_buttons(*proxy_actions(proxy, authorizer)) %></td>
</tr>
<% end %>
app/views/smart_proxies/plugins/_dhcp.html.erb
<div class="row">
<h3><%= _('DHCP') %></h3>
<%= render :partial => 'smart_proxies/plugins/plugin_version', :locals => {:feature => feature, :proxy => @smart_proxy} %>
<div class="col-md-4">
<%= _('Subnets') %>
</div>
<div class="col-md-8">
<%= generate_links_for(@smart_proxy.subnets).html_safe %>
</div>
</div>
app/views/smart_proxies/plugins/_dns.html.erb
<div class="row">
<h3><%= _('DNS') %></h3>
<%= render :partial => 'smart_proxies/plugins/plugin_version', :locals => {:feature => feature, :proxy => @smart_proxy} %>
<div class="col-md-4">
<%= _('Domains') %>
</div>
<div class="col-md-8">
<%= generate_links_for(@smart_proxy.domains).html_safe %>
</div>
</div>
app/views/smart_proxies/plugins/_no_template.html.erb
<div class="row">
<h3><%= _("#{feature.capitalize}") %></h3>
<%= render :partial => 'smart_proxies/plugins/plugin_version', :locals => {:feature => feature, :proxy => @smart_proxy} %>
<div class="col-md-12"><%= _('Data not available for %s') % feature %></div>
</div>
app/views/smart_proxies/plugins/_plugin_version.html.erb
<div class="col-md-4"><%= _('Version') %></div>
<div class="col-md-8">
<span class="plugin-version" data-plugin="<%= feature %>">
<%= spinner %>
</span>
</div>
app/views/smart_proxies/plugins/_realm.html.erb
<div class="row">
<h3><%= _('Realm') %></h3>
<%= render :partial => 'smart_proxies/plugins/plugin_version', :locals => {:feature => feature, :proxy => @smart_proxy} %>
<div class="col-md-4">
<%= _('Realms') %>
</div>
<div class="col-md-8">
<%= generate_links_for(@smart_proxy.realms).html_safe %>
</div>
</div>
app/views/smart_proxies/plugins/_tftp.html.erb
<div class="row">
<h3><%= _('TFTP') %></h3>
<%= render :partial => 'smart_proxies/plugins/plugin_version', :locals => {:feature => feature, :proxy => @smart_proxy} %>
<div class="col-md-4">
<%= _('TFTP server') %>
</div>
<div class="col-md-8">
<span class="proxy-tftp" data-url="<%= tftp_server_smart_proxy_path(@smart_proxy) %>">
<%= spinner %>
</span>
</div>
</div>
app/views/smart_proxies/show.html.erb
<% javascript('proxy_status') %>
<% title(_('Smart Proxy: %s') % @smart_proxy.to_label) %>
<%= smart_proxy_title_actions(@smart_proxy, authorizer) %>
<% service_features = proxy_features_besides_puppet(@smart_proxy) %>
<div class="row proxy-show" data-url="<%= ping_smart_proxy_path(@smart_proxy) %>">
<ul id="proxy-tab" class="nav nav-tabs">
<li class="active"><a href="#properties" data-toggle="tab"><%= _('Overview') %></a></li>
<% if service_features.any? %>
<li><a href="#services" data-toggle="tab"><%= _('Services') %></a></li>
<% end %>
</ul>
<div id="proxy-tab-content" class="proxy-content tab-content">
<div class="tab-pane active in" id="properties">
<div class="col-md-6">
<div class="row">
<h3><%= _('Details') %></h3>
</div>
<div class="row">
<div class="col-md-4">
<%= _('Communication status') %>
</div>
<div class="col-md-8">
<span class="proxy-show-status">
<%= spinner %>
</span>
</div>
</div>
<div class="row">
<div class="col-md-4">
<%= _('URL') %>
</div>
<div class="col-md-8">
<%= @smart_proxy.url %>
</div>
</div>
<div class="row">
<div class="col-md-4">
<%= _('Version') %>
</div>
<div class="col-md-8">
<span class="proxy-version" data-url="<%= ping_smart_proxy_path(@smart_proxy) %>">
<%= spinner %>
</span>
</div>
</div>
<div class="row">
<div class="col-md-4">
<%= _('Features') %>
</div>
<div class="col-md-8">
<%= @smart_proxy.features.to_sentence %> <%= refresh_proxy_icon(@smart_proxy, authorizer) %>
</div>
</div>
</div>
<div class="col-md-6">
<!--place holder for Capsule sync-->
</div>
</div>
<% if service_features.any? %>
<div class="tab-pane" id="services">
<div class="col-md-6">
<% service_features.each do |feature| %>
<% feature_erb = "smart_proxies/plugins/#{feature}" %>
<% if lookup_context.template_exists?(feature_erb, [], true) %>
<%= render :partial => feature_erb, :locals => {:feature => feature} %>
<% else %>
<%= render :partial => "smart_proxies/plugins/no_template", :locals => {:feature => feature} %>
<% end %>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
config/environments/production.rb
auth_source_ldap
subnets
hidden_values
password_strength)
password_strength
proxy-status)
stylesheets = %w( )
config/routes.rb
end
end
resources :smart_proxies, :except => [:show] do
resources :smart_proxies do
member do
post 'ping'
get 'ping'
put 'refresh'
get 'version'
get 'plugin_version'
get 'tftp_server'
end
constraints(:id => /[^\/]+/) do
resources :puppetca, :only => [:index, :update, :destroy]
lib/proxy_api/tftp.rb
# returns the TFTP boot server for this proxy
def bootServer
if (response = parse(get("serverName"))) and response["serverName"].present?
if (response = parse(get("serverName"))) && response["serverName"].present?
return response["serverName"]
end
false
lib/proxy_api/version.rb
end
def proxy_versions
parse get
@proxy_versions ||= parse(get)
rescue => e
raise ProxyException.new(url, e, N_("Unable to detect version"))
end
def version
proxy_versions["version"]
end
end
end
test/functional/smart_proxies_controller_test.rb
end
test "smart proxy version succeeded" do
SmartProxy.any_instance.stubs(:version).returns({:success => true, :message => '1.11'})
get :version, { :id => smart_proxies(:one).to_param }, set_session_user
expected_response = {'version' => '1.11', 'modules' => {'dns' => '1.11'}}
SmartProxy.any_instance.stubs(:version).returns(expected_response)
get :ping, { :id => smart_proxies(:one).to_param }, set_session_user
assert_response :success
show_response = ActiveSupport::JSON.decode(@response.body)
assert_equal('1.11', show_response['message'])
assert_equal('1.11', show_response['message']['version'])
end
test "smart proxy version failed" do
SmartProxy.any_instance.stubs(:version).raises(Foreman::Exception, 'Exception message')
get :version, { :id => smart_proxies(:one).to_param }, set_session_user
get :ping, { :id => smart_proxies(:one).to_param }, set_session_user
assert_response :success
show_response = ActiveSupport::JSON.decode(@response.body)
assert_match(/Exception message/, show_response['message'])
end
test '#show' do
proxy = smart_proxies(:one)
get :show, { :id => proxy.id }, set_session_user
assert_response :success
assert_template 'show'
end
test 'tftp_server should return tftp address' do
SmartProxy.any_instance.stubs(:tftp_server).returns('127.13.0.1')
get :tftp_server, { :id => smart_proxies(:one).to_param }, set_session_user
assert_response :success
show_response = ActiveSupport::JSON.decode(@response.body)
assert_equal('127.13.0.1', show_response['message'])
end
test 'tftp server should return false if not found' do
get :tftp_server, { :id => smart_proxies(:one).to_param }, set_session_user
assert_response :success
show_response = ActiveSupport::JSON.decode(@response.body)
assert_match(/No TFTP feature/, show_response['message'])
end
end
test/integration/smart_proxy_test.rb
test "edit page" do
visit smart_proxies_path
click_link "DHCP Proxy"
click_link "Edit"
fill_in "smart_proxy_name", :with => "DHCP Secure"
fill_in "smart_proxy_url", :with => "https://secure.net:8443"
assert_submit_button(smart_proxies_path)
assert page.has_link? 'DHCP Secure'
assert_submit_button(smart_proxy_path(smart_proxies(:one)))
assert page.has_title? 'DHCP Secure'
assert page.has_content? "https://secure.net:8443"
end
test "show page" do
proxy = smart_proxies(:one)
visit smart_proxy_path(proxy)
assert page.has_selector?('h1', :text => proxy.to_label), "#{proxy.to_label} <h1> tag, but was not found"
assert page.has_content? proxy.url
assert page.has_link? "Delete"
assert page.has_link? "Edit"
assert page.has_link? "Refresh features"
assert page.has_link? "Services"
click_link "Services"
# smart_proxies(:one) has DHCP feature
assert page.has_selector?('h3', :text => "DHCP")
assert page.has_content? "Version"
end
end
test/unit/proxy_status_test.rb
require 'test_helper'
class ProxyStatusTest < ActiveSupport::TestCase
setup do
@proxy = FactoryGirl.
build_stubbed(:template_smart_proxy, :url => 'https://secure.proxy:4568')
end
test '#versions_cache_key' do
proxy_status = ProxyStatus.new(@proxy)
assert_equal("proxy_#{@proxy.id}/versions", proxy_status.versions_cache_key)
end
context '#tftp_server' do
test 'it returns tftp server ip' do
ProxyAPI::TFTP.any_instance.stubs(:bootServer).returns('127.13.0.1')
proxy_status = ProxyStatus.new(@proxy)
assert_equal('127.13.0.1', proxy_status.tftp_server)
end
test 'it caches tftp_server' do
ProxyAPI::TFTP.any_instance.stubs(:bootServer).returns('127.13.0.1')
ProxyStatus.new(@proxy).tftp_server
assert_equal('127.13.0.1', Rails.cache.fetch("proxy_#{@proxy.id}/tftp_server"))
end
test 'it raises an error if proxy has no tftp feature' do
proxy = FactoryGirl.build_stubbed(:smart_proxy)
assert_raise Foreman::Exception do
ProxyStatus.new(proxy).tftp_server
end
end
end
context '#api_versions' do
setup do
@expected_versions = {'version' => '1.11', 'modules' => {'dns' => '1.11'}}
ProxyAPI::Version.any_instance.stubs(:proxy_versions).returns(@expected_versions)
end
test 'it returns version from the proxy' do
proxy_status = ProxyStatus.new(@proxy)
assert_equal(@expected_versions, proxy_status.api_versions)
end
test 'it caches api_versions' do
ProxyStatus.new(@proxy).api_versions
assert_equal(@expected_versions, Rails.cache.fetch("proxy_#{@proxy.id}/versions"))
end
test 'it raises error if no connection to proxy' do
ProxyAPI::Version.any_instance.stubs(:proxy_versions).raises(Net::HTTPBadResponse)
assert_raise(Foreman::WrappedException, "Unable to connect to smart proxy") do
ProxyStatus.new(@proxy).api_versions
end
end
end
end
test/unit/smart_proxy_test.rb
end
context "#version" do
def setup
Rails.cache.clear
end
test "should succeed" do
proxy = smart_proxies(:one)
fake_version = {:version => '1.11'}
fake_version = {'version' => '1.11'}
ProxyAPI::Version.any_instance.expects(:get).returns(fake_response(fake_version))
assert_equal(fake_version[:version], proxy.version[:message])
assert_equal(fake_version, proxy.version)
end
test "should raise error" do

Also available in: Unified diff