Merge branch 'origin-2939-re-run-job-button' into 2882-job-process-stats
authorPeter Amstutz <peter.amstutz@curoverse.com>
Wed, 4 Jun 2014 19:03:37 +0000 (15:03 -0400)
committerPeter Amstutz <peter.amstutz@curoverse.com>
Wed, 4 Jun 2014 19:03:37 +0000 (15:03 -0400)
29 files changed:
apps/workbench/app/controllers/application_controller.rb
apps/workbench/app/helpers/application_helper.rb
apps/workbench/app/models/api_client_authorization.rb
apps/workbench/app/models/arvados_base.rb
apps/workbench/app/models/authorized_key.rb
apps/workbench/app/models/collection.rb
apps/workbench/app/models/job.rb
apps/workbench/app/models/pipeline_instance.rb
apps/workbench/app/models/user.rb
apps/workbench/app/models/virtual_machine.rb
services/api/app/controllers/arvados/v1/groups_controller.rb
services/api/app/controllers/arvados/v1/job_tasks_controller.rb
services/api/app/controllers/arvados/v1/pipeline_instances_controller.rb
services/api/app/controllers/arvados/v1/users_controller.rb
services/api/app/mailers/admin_notifier.rb
services/api/app/models/link.rb
services/api/app/models/pipeline_instance.rb
services/api/app/models/user.rb
services/api/app/views/admin_notifier/after_create_user.text.erb [deleted file]
services/api/app/views/admin_notifier/new_inactive_user.text.erb [new file with mode: 0644]
services/api/app/views/admin_notifier/new_user.text.erb [new file with mode: 0644]
services/api/app/views/pipeline_instances/index.html.erb
services/api/config/application.default.yml
services/api/db/migrate/20140602143352_remove_active_and_success_from_pipeline_instances.rb [new file with mode: 0644]
services/api/db/schema.rb
services/api/test/integration/serialized_encoding_test.rb
services/api/test/unit/pipeline_instance_test.rb
services/api/test/unit/user_test.rb
services/fuse/tests/test_mount.py

index c99960f971bc2dc3cbcbe6cff2156d2fa8995b7a..ae802f840e66ab8a91d76611f05eaebc69077ca4 100644 (file)
@@ -422,4 +422,30 @@ class ApplicationController < ActionController::Base
       @notification_count = ''
     end
   end
+
+  helper_method :my_folders
+  def my_folders
+    return @my_folders if @my_folders
+    @my_folders = []
+    root_of = {}
+    Group.filter([['group_class','=','folder']]).each do |g|
+      root_of[g.uuid] = g.owner_uuid
+      @my_folders << g
+    end
+    done = false
+    while not done
+      done = true
+      root_of = root_of.each_with_object({}) do |(child, parent), h|
+        if root_of[parent]
+          h[child] = root_of[parent]
+          done = false
+        else
+          h[child] = parent
+        end
+      end
+    end
+    @my_folders = @my_folders.select do |g|
+      root_of[g.uuid] == current_user.uuid
+    end
+  end
 end
index d844350927dfa8c748788b20a2fe523e5af81bf0..7a955e5336fcbf85b8f1e047efdb0f3566208330 100644 (file)
@@ -128,7 +128,11 @@ module ApplicationHelper
 
   def render_editable_attribute(object, attr, attrvalue=nil, htmloptions={})
     attrvalue = object.send(attr) if attrvalue.nil?
-    return attrvalue if !object.attribute_editable? attr
+    if !object.attribute_editable?(attr, :ever) or
+        (!object.editable? and
+         !object.owner_uuid.in?(my_folders.collect(&:uuid)))
+      return attrvalue 
+    end
 
     input_type = 'text'
     case object.class.attribute_info[attr.to_sym].andand[:type]
@@ -197,7 +201,10 @@ module ApplicationHelper
       end
     end
 
-    unless object.andand.attribute_editable? attr
+    if !object or
+        !object.attribute_editable?(attr, :ever) or
+        (!object.editable? and
+         !object.owner_uuid.in?(my_folders.collect(&:uuid)))
       return link_to_if_arvados_object attrvalue
     end
 
index 620ebc7b9600b8ea777cf869874f0f4f45d3d71c..ac3a9bf8ed53998adcb1ebfdcc6dc038fdc84136 100644 (file)
@@ -1,5 +1,5 @@
 class ApiClientAuthorization < ArvadosBase
-  def attribute_editable?(attr)
+  def attribute_editable? attr, *args
     ['expires_at', 'default_owner_uuid'].index attr
   end
   def self.creatable?
index 76e9967077991c3336a04ca0b18ab8494a875e31..33e107e3693c94b4954f4e155312b060ab50205e 100644 (file)
@@ -306,13 +306,15 @@ class ArvadosBase < ActiveRecord::Base
       (writable_by.include? current_user.uuid rescue false)))
   end
 
-  def attribute_editable?(attr)
+  def attribute_editable?(attr, ever=nil)
     if "created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at".index(attr.to_s)
       false
     elsif not (current_user.andand.is_active)
       false
     elsif attr == 'uuid'
       current_user.is_admin
+    elsif ever
+      true
     else
       editable?
     end
index c018cc56b04051a442b382c4546f9fea0e253bce..724c996e4a4ef173f432514349921ab249eddf2a 100644 (file)
@@ -1,9 +1,9 @@
 class AuthorizedKey < ArvadosBase
-  def attribute_editable?(attr)
+  def attribute_editable? attr, *args
     if attr.to_s == 'authorized_user_uuid'
       current_user and current_user.is_admin
     else
-      super(attr)
+      super
     end
   end
 end
index 2fe4e2b748f1119f8d2c7b1934e4679480fcb781..a64f7e1e10c6c3ee635689cae09403963868198d 100644 (file)
@@ -47,7 +47,7 @@ class Collection < ArvadosBase
     dir_to_tree.call('.')
   end
 
-  def attribute_editable?(attr)
+  def attribute_editable? attr, *args
     false
   end
 
index 8dd66ed6b9296ed00396b8924f50d152388841ed..173d3a06964fb5667b9546aee4bab518baf3c190 100644 (file)
@@ -3,7 +3,7 @@ class Job < ArvadosBase
     true
   end
 
-  def attribute_editable?(attr)
+  def attribute_editable? attr, *args
     false
   end
 
index aad7cfc4cc9858e837505cc85f7eb5a5a118c212..5a88003f8281199547431ca8051eea980c0a9d0f 100644 (file)
@@ -21,9 +21,10 @@ class PipelineInstance < ArvadosBase
     end
   end
   
-  def attribute_editable?(attr)
-    attr && (attr.to_sym == :name ||
-            (attr.to_sym == :components and (self.state == 'New' || self.state == 'Ready')))
+  def attribute_editable? attr, *args
+    super && (attr.to_sym == :name ||
+              (attr.to_sym == :components and
+               (self.state == 'New' || self.state == 'Ready')))
   end
 
   def attributes_for_display
index c1656bde692ea1b0d454585663b1aca7ec4d3a8a..9c914776a2cf43b5ef0241dfced63c0a745a1bb5 100644 (file)
@@ -31,8 +31,8 @@ class User < ArvadosBase
     super.reject { |k,v| %w(owner_uuid default_owner_uuid identity_url prefs).index k }
   end
 
- def attribute_editable?(attr)
-    (not (self.uuid.andand.match(/000000000000000$/) and self.is_admin)) and super(attr)
+ def attribute_editable? attr, *args
+    (not (self.uuid.andand.match(/000000000000000$/) and self.is_admin)) and super
   end
 
   def friendly_link_name
index 5ff7798a959162eb27d27cf9c35fd41748bd35ac..978964196d412b76f993e46b717a7977ea773ecc 100644 (file)
@@ -6,7 +6,7 @@ class VirtualMachine < ArvadosBase
   def attributes_for_display
     super.append ['current_user_logins', @current_user_logins]
   end
-  def attribute_editable?(attr)
+  def attribute_editable? attr, *args
     attr != 'current_user_logins' and super
   end
   def self.attribute_info
index 4bccbcc710987e8867a8cbb8768655ff6b2c19d3..da82e81ef81374e39994b08a27518e3f60de84e6 100644 (file)
@@ -20,9 +20,10 @@ class Arvados::V1::GroupsController < ApplicationController
     offset_all = @offset
     @orders = []
 
-    [Group, Job, PipelineInstance, PipelineTemplate,
-     Human, Specimen, Trait,
-     Collection].each do |klass|
+    [Group,
+     Job, PipelineInstance, PipelineTemplate,
+     Collection,
+     Human, Specimen, Trait].each do |klass|
       @objects = klass.readable_by(*@read_users)
       cond_sql = "#{klass.table_name}.owner_uuid = ?"
       cond_params = [@object.uuid]
index d2916242ef57484195ecd579a51cd232f712a828..434550c13fbbe71a09908be8dcd8e37854bae114 100644 (file)
@@ -1,2 +1,3 @@
 class Arvados::V1::JobTasksController < ApplicationController
+  accept_attribute_as_json :parameters, Hash
 end
index 9781caf7e8183f618d33971335ed4d6e38a23ab3..614af685f93d49ae7611f81b077205a3ed7f798c 100644 (file)
@@ -1,5 +1,5 @@
 class Arvados::V1::PipelineInstancesController < ApplicationController
-  accept_attribute_as_json :components_summary, Hash
   accept_attribute_as_json :components, Hash
   accept_attribute_as_json :properties, Hash
+  accept_attribute_as_json :components_summary, Hash
 end
index c2a32f02f1b7e0e68bd8da293e34a0269308b4c0..7311deb3860c9337914ea10fe3122dfad62bdad4 100644 (file)
@@ -1,4 +1,6 @@
 class Arvados::V1::UsersController < ApplicationController
+  accept_attribute_as_json :prefs, Hash
+
   skip_before_filter :find_object_by_uuid, only:
     [:activate, :event_stream, :current, :system, :setup]
   skip_before_filter :render_404_if_no_object, only:
index 5de70053dcf0265258244ad252df341936334154..e17f4a14dab2d05f16780b09a76844401ad3cbff 100644 (file)
@@ -1,34 +1,40 @@
 class AdminNotifier < ActionMailer::Base
+  include AbstractController::Callbacks
+
   default from: Rails.configuration.admin_notifier_email_from
+  before_filter :load_variables
 
-  def after_create(model, *args)
-    self.generic_callback('after_create', model, *args)
+  def new_user(user)
+    @user = user
+    if not Rails.configuration.new_user_notification_recipients.empty? then
+      @recipients = Rails.configuration.new_user_notification_recipients
+      logger.info "Sending mail to #{@recipients} about new user #{@user.uuid} (#{@user.full_name} <#{@user.email}>)"
+      mail(to: @recipients,
+           subject: "#{Rails.configuration.email_subject_prefix}New user notification"
+          )
+    end
   end
 
-  protected
-
-  def generic_callback(callback_type, model, *args)
-    model_specific_method = "#{callback_type}_#{model.class.to_s.underscore}".to_sym
-    if self.respond_to? model_specific_method
-      self.send model_specific_method, model, *args
+  def new_inactive_user(user)
+    @user = user
+    if not Rails.configuration.new_inactive_user_notification_recipients.empty? then
+      @recipients = Rails.configuration.new_inactive_user_notification_recipients
+      logger.info "Sending mail to #{@recipients} about new user #{@user.uuid} (#{@user.full_name} <#{@user.email}>)"
+      mail(to: @recipients,
+           subject: "#{Rails.configuration.email_subject_prefix}New inactive user notification"
+          )
     end
   end
 
-  def all_admin_emails()
-    User.
-      where(is_admin: true).
-      collect(&:email).
-      compact.
-      uniq.
-      select { |e| e.match /\@/ }
+private
+  def load_variables
+    if Rails.configuration.respond_to?('workbench_address') and
+       not Rails.configuration.workbench_address.nil? and
+       not Rails.configuration.workbench_address.empty? then
+      @wb_address = Rails.configuration.workbench_address.sub(/\/$/,'') + '/users'
+    else
+      @wb_address = ''
+    end
   end
 
-  def after_create_user(user, *args)
-    @new_user = user
-    logger.info "Sending mail to #{@recipients} about new user #{@new_user.uuid} (#{@new_user.full_name}, #{@new_user.email})"
-    mail({
-           to: self.all_admin_emails,
-           subject: "#{Rails.configuration.email_subject_prefix}New user: #{@new_user.full_name}, #{@new_user.email}"
-         })
-  end
 end
index af3918551e441a2ccaea47ea67e19e8f23a73b1f..1b3fc34eab926a4486f794a42e10f5721e7deb46 100644 (file)
@@ -10,6 +10,7 @@ class Link < ArvadosModel
   after_destroy :maybe_invalidate_permissions_cache
   attr_accessor :head_kind, :tail_kind
   validate :name_link_has_valid_name
+  validate :name_link_owner_is_tail
 
   api_accessible :user, extend: :common do |t|
     t.add :tail_uuid
@@ -92,4 +93,11 @@ class Link < ArvadosModel
       true
     end
   end
+
+  def name_link_owner_is_tail
+    if link_class == 'name'
+      self.owner_uuid = tail_uuid
+      ensure_owner_uuid_is_permitted
+    end
+  end
 end
index 7bb814c60d4a902d15a61485952ead0437a96cbe..354c8924e78f691cce4f327edb75ca37ec261f71 100644 (file)
@@ -8,7 +8,7 @@ class PipelineInstance < ArvadosModel
   belongs_to :pipeline_template, :foreign_key => :pipeline_template_uuid, :primary_key => :uuid
 
   before_validation :bootstrap_components
-  before_validation :update_success
+  before_validation :update_state
   before_validation :verify_status
   before_create :set_state_before_save
   before_save :set_state_before_save
@@ -18,8 +18,6 @@ class PipelineInstance < ArvadosModel
     t.add :pipeline_template, :if => :pipeline_template
     t.add :name
     t.add :components
-    t.add :success
-    t.add :active
     t.add :dependencies
     t.add :properties
     t.add :state
@@ -80,7 +78,7 @@ class PipelineInstance < ArvadosModel
         else
           row << 0.0
           if step['failed']
-            self.success = false
+            self.state = Failed
           end
         end
         row << (step['warehousejob']['id'] rescue nil)
@@ -111,9 +109,9 @@ class PipelineInstance < ArvadosModel
     end
   end
 
-  def update_success
+  def update_state
     if components and progress_ratio == 1.0
-      self.success = true
+      self.state = Complete
     end
   end
 
@@ -144,60 +142,9 @@ class PipelineInstance < ArvadosModel
   def verify_status
     changed_attributes = self.changed
 
-    if 'state'.in? changed_attributes
-      case self.state
-      when New, Ready, Paused
-        self.active = nil
-        self.success = nil
-      when RunningOnServer
-        self.active = true
-        self.success = nil
-      when RunningOnClient
-        self.active = nil
-        self.success = nil
-      when Failed
-        self.active = false
-        self.success = false
-        self.state = Failed   # before_validation will fail if false is returned in the previous line
-      when Complete
-        self.active = false
-        self.success = true
-      else
-        return false
-      end
-    elsif 'success'.in? changed_attributes
-      logger.info "pipeline_instance changed_attributes has success for #{self.uuid}"
-      if self.success
-        self.active = false
-        self.state = Complete
-      else
-        self.active = false
-        self.state = Failed
-      end
-    elsif 'active'.in? changed_attributes
-      logger.info "pipeline_instance changed_attributes has active for #{self.uuid}"
-      if self.active
-        if self.state.in? [New, Ready, Paused]
-          self.state = RunningOnServer
-        end
-      else
-        if self.state == RunningOnServer # state was RunningOnServer
-          self.active = nil
-          self.state = Paused
-        elsif self.components_look_ready?
-          self.state = Ready
-        else
-          self.state = New
-        end
-      end
-    elsif new_record? and self.state.nil?
-      # No state, active, or success given
-      self.state = New
-    end
-
     if new_record? or 'components'.in? changed_attributes
       self.state ||= New
-      if self.state == New and self.components_look_ready?
+      if (self.state == New) and self.components_look_ready?
         self.state = Ready
       end
     end
@@ -211,12 +158,8 @@ class PipelineInstance < ArvadosModel
   end
 
   def set_state_before_save
-    if !self.state || self.state == New || self.state == Ready || self.state == Paused
-      if self.active
-        self.state = RunningOnServer
-      elsif self.components_look_ready? && (!self.state || self.state == New)
-        self.state = Ready
-      end
+    if self.components_look_ready? && (!self.state || self.state == New)
+      self.state = Ready
     end
   end
 
index d21991519553b9d889f742d1f137b11fc93e17bb..52dd8d79ff47014a9bfe0896a818b28c4d83395d 100644 (file)
@@ -12,7 +12,7 @@ class User < ArvadosModel
   before_update :prevent_inactive_admin
   before_create :check_auto_admin
   after_create :add_system_group_permission_link
-  after_create AdminNotifier
+  after_create :send_admin_notifications
 
   has_many :authorized_keys, :foreign_key => :authorized_user_uuid, :primary_key => :uuid
 
@@ -402,4 +402,12 @@ class User < ArvadosModel
                   head_uuid: self.uuid)
     end
   end
+
+  # Send admin notifications
+  def send_admin_notifications
+    AdminNotifier.new_user(self).deliver
+    if not self.is_active then
+      AdminNotifier.new_inactive_user(self).deliver
+    end
+  end
 end
diff --git a/services/api/app/views/admin_notifier/after_create_user.text.erb b/services/api/app/views/admin_notifier/after_create_user.text.erb
deleted file mode 100644 (file)
index 40bafd2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-A user has logged in for the first time.
-
-<%= @new_user.uuid %> -- <%= @new_user.full_name %>, <%= @new_user.email %>
-
-View or activate the user:
-
-<%= users_url %>
diff --git a/services/api/app/views/admin_notifier/new_inactive_user.text.erb b/services/api/app/views/admin_notifier/new_inactive_user.text.erb
new file mode 100644 (file)
index 0000000..2e9e01d
--- /dev/null
@@ -0,0 +1,13 @@
+
+A new user landed on the inactive user page:
+
+  <%= @user.full_name %> <<%= @user.email %>>
+
+<% if not @wb_address.empty? -%>
+Please see workbench for more information:
+
+  <%= @wb_address %>
+
+<% end -%>
+Thanks,
+Your friendly Arvados robot.
diff --git a/services/api/app/views/admin_notifier/new_user.text.erb b/services/api/app/views/admin_notifier/new_user.text.erb
new file mode 100644 (file)
index 0000000..374e46e
--- /dev/null
@@ -0,0 +1,16 @@
+
+A new user has been created:
+
+  <%= @user.full_name %> <<%= @user.email %>>
+
+This user is <%= @user.is_active ? '' : 'NOT ' %>active.
+
+<% if not @wb_address.empty? -%>
+Please see workbench for more information:
+
+  <%= @wb_address %>
+
+<% end -%>
+Thanks,
+Your friendly Arvados robot.
+
index e8cb553daff3508fce09b54b903743ed640c366c..cfadd26cdd28ae473b78bf3cc79f26253e8d9e2d 100644 (file)
 
   <% @objects.each do |o| %>
 
-  <% status = o.success ? 'success' : (o.success == false ? 'failure' : 'pending') %>
+  <% status = (o.state == 'Complete') ? 'success' : ((o.state == 'Failed') ? 'failure' : 'pending') %>
 
   <tr class="pipeline-instance-status pipeline-instance-status-<%= status %>" data-showhide-selector="tr#extra-info-<%= o.uuid %>" style="cursor:pointer">
     <td>
       <%= status %>
     </td><td>
-      <%= o.active ? 'yes' : '-' %>
+      <%= (o.state == 'RunningOnServer') ? 'yes' : '-' %>
     </td><td>
       <%= (o.progress_ratio * 1000).floor / 10 %>
     </td><td>
index a3ff6800be23bf336f8741a147c642000d1a69b9..848675cb55b5afa702502201c94624be8f3f32be 100644 (file)
@@ -87,6 +87,8 @@ common:
   admin_notifier_email_from: arvados@example.com
   email_subject_prefix: "[ARVADOS] "
   user_notifier_email_from: arvados@example.com
+  new_user_notification_recipients: [ ]
+  new_inactive_user_notification_recipients: [ ]
 
   # Visitors to the API server will be redirected to the workbench
   workbench_address: https://workbench.local:3001/
diff --git a/services/api/db/migrate/20140602143352_remove_active_and_success_from_pipeline_instances.rb b/services/api/db/migrate/20140602143352_remove_active_and_success_from_pipeline_instances.rb
new file mode 100644 (file)
index 0000000..6d4014c
--- /dev/null
@@ -0,0 +1,42 @@
+class RemoveActiveAndSuccessFromPipelineInstances < ActiveRecord::Migration
+  include CurrentApiClient
+
+  def up
+    if column_exists?(:pipeline_instances, :active)
+      remove_column :pipeline_instances, :active
+    end
+
+    if column_exists?(:pipeline_instances, :success)
+      remove_column :pipeline_instances, :success
+    end
+  end
+
+  def down
+    if !column_exists?(:pipeline_instances, :success)
+      add_column :pipeline_instances, :success, :boolean, :null => true
+    end
+    if !column_exists?(:pipeline_instances, :active)
+      add_column :pipeline_instances, :active, :boolean, :default => false
+    end
+
+    act_as_system_user do
+      PipelineInstance.all.each do |pi|
+        case pi.state
+        when PipelineInstance::New, PipelineInstance::Ready, PipelineInstance::Paused, PipelineInstance::RunningOnClient
+          pi.active = nil
+          pi.success = nil
+        when PipelineInstance::RunningOnServer
+          pi.active = true
+          pi.success = nil
+        when PipelineInstance::Failed
+          pi.active = false
+          pi.success = false
+        when PipelineInstance::Complete
+          pi.active = false
+          pi.success = true
+        end
+        pi.save!
+      end
+    end
+  end
+end
index c63a312dcff3d33d8c2acd11a1bc2f56e60ec453..1ef80ab670389f3a7f87bc9e9581e44cd618a656 100644 (file)
@@ -12,7 +12,7 @@
 # It's strongly recommended to check this file into your version control system.
 
 
-ActiveRecord::Schema.define(:version => 20140601022548) do
+ActiveRecord::Schema.define(:version => 20140602143352) do
 
   create_table "api_client_authorizations", :force => true do |t|
     t.string   "api_token",                                           :null => false
@@ -320,16 +320,14 @@ ActiveRecord::Schema.define(:version => 20140601022548) do
   create_table "pipeline_instances", :force => true do |t|
     t.string   "uuid"
     t.string   "owner_uuid"
-    t.datetime "created_at",                                 :null => false
+    t.datetime "created_at",              :null => false
     t.string   "modified_by_client_uuid"
     t.string   "modified_by_user_uuid"
     t.datetime "modified_at"
     t.string   "pipeline_template_uuid"
     t.string   "name"
     t.text     "components"
-    t.boolean  "success"
-    t.boolean  "active",                  :default => false
-    t.datetime "updated_at",                                 :null => false
+    t.datetime "updated_at",              :null => false
     t.text     "properties"
     t.string   "state"
     t.text     "components_summary"
index 10b94351a6550ac853d05ba12556f96b3b0fd691..ed30fdb5df24a40db878a1869e6e7b5ca26a4573 100644 (file)
@@ -1,27 +1,51 @@
 require 'test_helper'
+load 'test/functional/arvados/v1/git_setup.rb'
 
 class SerializedEncodingTest < ActionDispatch::IntegrationTest
+  include GitSetup
+
   fixtures :all
 
-  test "store json-encoded link with properties hash" do
-    post "/arvados/v1/links", {
-      :link => {
-        :link_class => 'test',
-        :name => 'test',
-        :properties => {:foo => :bar}
-      }.to_json,
-      :format => :json
-    }, auth(:active)
-    assert_response :success
-  end
+  {
+    api_client_authorization: {scopes: []},
+
+    human: {properties: {eye_color: 'gray'}},
+
+    job: {
+      repository: 'foo',
+      runtime_constraints: {docker_image: 'arvados/jobs'},
+      script: 'hash',
+      script_version: 'master',
+      script_parameters: {pattern: 'foobar'},
+      tasks_summary: {todo: 0},
+    },
+
+    job_task: {parameters: {pattern: 'foo'}},
+
+    link: {link_class: 'test', name: 'test', properties: {foo: :bar}},
+
+    node: {info: {uptime: 1234}},
+
+    pipeline_instance: {
+      components: {"job1" => {parameters: {pattern: "xyzzy"}}},
+      components_summary: {todo: 0},
+      properties: {test: true},
+    },
+
+    pipeline_template: {
+      components: {"job1" => {parameters: {pattern: "xyzzy"}}},
+    },
+
+    specimen: {properties: {eye_color: 'meringue'}},
+
+    trait: {properties: {eye_color: 'brown'}},
 
-  test "store json-encoded pipeline instance with components_summary hash" do
-    post "/arvados/v1/pipeline_instances", {
-      :pipeline_instance => {
-        :components_summary => {:todo => 0}
-      }.to_json,
-      :format => :json
-    }, auth(:active)
-    assert_response :success
+    user: {prefs: {cookies: 'thin mint'}},
+  }.each_pair do |resource, postdata|
+    test "create json-encoded #{resource.to_s}" do
+      post("/arvados/v1/#{resource.to_s.pluralize}",
+           {resource => postdata.to_json}, auth(:admin_trustedclient))
+      assert_response :success
+    end
   end
 end
index 0f2c2edad83dc7ff15b561c536c637e040febd6e..93354f8b1edd31d2b332a71cd6d7de28bcc490e6 100644 (file)
@@ -5,8 +5,6 @@ class PipelineInstanceTest < ActiveSupport::TestCase
   test "check active and success for a pipeline in new state" do
     pi = pipeline_instances :new_pipeline
 
-    assert !pi.active, 'expected active to be false for :new_pipeline'
-    assert !pi.success, 'expected success to be false for :new_pipeline'
     assert_equal 'New', pi.state, 'expected state to be New for :new_pipeline'
 
     # save the pipeline and expect state to be New
@@ -15,8 +13,6 @@ class PipelineInstanceTest < ActiveSupport::TestCase
     pi.save
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::New, pi.state, 'expected state to be New for new pipeline'
-    assert !pi.active, 'expected active to be false for a new pipeline'
-    assert !pi.success, 'expected success to be false for a new pipeline'
   end
 
   test "check active and success for a newly created pipeline" do
@@ -26,8 +22,6 @@ class PipelineInstanceTest < ActiveSupport::TestCase
     pi.save
 
     assert pi.valid?, 'expected newly created empty pipeline to be valid ' + pi.errors.messages.to_s
-    assert !pi.active, 'expected active to be false for a new pipeline'
-    assert !pi.success, 'expected success to be false for a new pipeline'
     assert_equal 'Ready', pi.state, 'expected state to be Ready for a new empty pipeline'
   end
 
@@ -44,8 +38,6 @@ class PipelineInstanceTest < ActiveSupport::TestCase
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::New, pi.state, 'expected state to be New after adding component with input'
     assert_equal pi.components.size, 1, 'expected one component'
-    assert !pi.active, 'expected active to be false after update'
-    assert !pi.success, 'expected success to be false for a new pipeline'
 
     # add a component with no input not required
     component = {'script_parameters' => {"input_not_provided" => {"required" => false}}}
@@ -55,8 +47,6 @@ class PipelineInstanceTest < ActiveSupport::TestCase
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::Ready, pi.state, 'expected state to be Ready after adding component with input'
     assert_equal pi.components.size, 1, 'expected one component'
-    assert !pi.active, 'expected active to be false after update'
-    assert !pi.success, 'expected success to be false for a new pipeline'
 
     # add a component with input and expect state to become Ready
     component = {'script_parameters' => {"input" => "yyyad4b39ca5a924e481008009d94e32+210"}}
@@ -66,57 +56,31 @@ class PipelineInstanceTest < ActiveSupport::TestCase
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::Ready, pi.state, 'expected state to be Ready after adding component with input'
     assert_equal pi.components.size, 1, 'expected one component'
-    assert !pi.active, 'expected active to be false after update'
-    assert !pi.success, 'expected success to be false for a new pipeline'
-
-    pi.active = true
-    assert_equal true, pi.save, 'expected pipeline instance to save, but ' + pi.errors.messages.to_s
-    pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
-    assert_equal PipelineInstance::RunningOnServer, pi.state, 'expected state to be RunningOnServer after updating active to true'
-    assert pi.active, 'expected active to be true after update'
-    assert !pi.success, 'expected success to be false for a new pipeline'
-
-    pi.success = false
-    pi.save
-    pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
-    assert_equal PipelineInstance::Failed, pi.state, 'expected state to be Failed after updating success to false'
-    assert !pi.active, 'expected active to be false after update'
-    assert !pi.success, 'expected success to be false for a new pipeline'
 
     pi.state = PipelineInstance::RunningOnServer
     pi.save
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::RunningOnServer, pi.state, 'expected state to be RunningOnServer after updating state to RunningOnServer'
-    assert pi.active, 'expected active to be true after update'
-    assert !pi.success, 'expected success to be alse after update'
 
     pi.state = PipelineInstance::Paused
     pi.save
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::Paused, pi.state, 'expected state to be Paused after updating state to Paused'
-    assert !pi.active, 'expected active to be false after update'
-    assert !pi.success, 'expected success to be false after update'
 
     pi.state = PipelineInstance::Complete
     pi.save
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::Complete, pi.state, 'expected state to be Complete after updating state to Complete'
-    assert !pi.active, 'expected active to be false after update'
-    assert pi.success, 'expected success to be true after update'
 
     pi.state = 'bogus'
     pi.save
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::Complete, pi.state, 'expected state to be unchanged with set to a bogus value'
-    assert !pi.active, 'expected active to be false after update'
-    assert pi.success, 'expected success to be true after update'
 
     pi.state = PipelineInstance::Failed
     pi.save
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::Failed, pi.state, 'expected state to be Failed after updating state to Failed'
-    assert !pi.active, 'expected active to be false after update'
-    assert !pi.success, 'expected success to be false after update'
   end
 
   test "update attributes for pipeline with two components" do
@@ -135,8 +99,6 @@ class PipelineInstanceTest < ActiveSupport::TestCase
     pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
     assert_equal PipelineInstance::New, pi.state, 'expected state to be New after adding component with input'
     assert_equal pi.components.size, 2, 'expected two components'
-    assert !pi.active, 'expected active to be false after update'
-    assert !pi.success, 'expected success to be false for a new pipeline'
   end
 
   [:has_component_with_no_script_parameters,
@@ -145,10 +107,7 @@ class PipelineInstanceTest < ActiveSupport::TestCase
       pi = pipeline_instances pi_name
 
       Thread.current[:user] = users(:active)
-      # Make sure we go through the "active_changed? and active" code:
-      assert_equal true, pi.update_attributes(active: true), pi.errors.messages
-      assert_equal true, pi.update_attributes(active: false), pi.errors.messages
-      assert_equal PipelineInstance::Paused, pi.state
+      assert_equal PipelineInstance::Ready, pi.state
     end
   end
 end
index 2d2db160cd3a0e971dd7ae56073b1de85216cfd0..8f0277909a4126826be910d635ab809c1225a836 100644 (file)
@@ -7,23 +7,10 @@ class UserTest < ActiveSupport::TestCase
   setup do
     # Make sure system_user exists before making "pre-test users" list
     system_user
-
-    @all_users = User.find(:all)
-
-    @all_users.each do |user|
-      if user.uuid == system_user_uuid
-        @system_user = user
-      elsif user.is_admin && user.is_active
-        @admin_user = user
-      elsif user.is_active && !user.is_admin
-        @active_user = user
-      elsif !user.is_active && !user.is_invited
-        @uninvited_user = user
-      end
-    end
   end
 
   test "check non-admin active user properties" do
+    @active_user = users(:active)     # get the active user
     assert !@active_user.is_admin, 'is_admin should not be set for a non-admin user'
     assert @active_user.is_active, 'user should be active'
     assert @active_user.is_invited, 'is_invited should be set'
@@ -35,12 +22,14 @@ class UserTest < ActiveSupport::TestCase
     assert @active_user.groups_i_can(:read).size > 0, "active user should be able read at least one group"
 
     # non-admin user cannot manage or write other user objects
+    @uninvited_user = users(:inactive_uninvited)     # get the uninvited user
     assert !(@active_user.can? :read=>"#{@uninvited_user.uuid}")
     assert !(@active_user.can? :write=>"#{@uninvited_user.uuid}")
     assert !(@active_user.can? :manage=>"#{@uninvited_user.uuid}")
   end
 
   test "check admin user properties" do
+    @admin_user = users(:admin)     # get the admin user
     assert @admin_user.is_admin, 'is_admin should be set for admin user'
     assert @admin_user.is_active, 'admin user cannot be inactive'
     assert @admin_user.is_invited, 'is_invited should be set'
@@ -56,12 +45,14 @@ class UserTest < ActiveSupport::TestCase
     assert @admin_user.groups_i_can(:manage).size > 0, "admin active user should be able manage at least one group"
 
     # admin user can also write or manage other users
+    @uninvited_user = users(:inactive_uninvited)     # get the uninvited user
     assert @admin_user.can? :read=>"#{@uninvited_user.uuid}"
     assert @admin_user.can? :write=>"#{@uninvited_user.uuid}"
     assert @admin_user.can? :manage=>"#{@uninvited_user.uuid}"
   end
 
   test "check inactive and uninvited user properties" do
+    @uninvited_user = users(:inactive_uninvited)     # get the uninvited user
     assert !@uninvited_user.is_admin, 'is_admin should not be set for a non-admin user'
     assert !@uninvited_user.is_active, 'user should be inactive'
     assert !@uninvited_user.is_invited, 'is_invited should not be set'
@@ -88,7 +79,7 @@ class UserTest < ActiveSupport::TestCase
   end
 
   test "full name should not contain spurious whitespace" do
-    Thread.current[:user] = @admin_user   # set admin user as the current user
+    set_user_from_auth :admin
 
     user = User.create ({uuid: 'zzzzz-tpzed-abcdefghijklmno', email: 'foo@example.com' })
 
@@ -101,7 +92,9 @@ class UserTest < ActiveSupport::TestCase
   end
 
   test "create new user" do
-    Thread.current[:user] = @admin_user   # set admin user as the current user
+    set_user_from_auth :admin
+
+    @all_users = User.find(:all)
 
     user = User.new
     user.first_name = "first_name_for_newly_created_user"
@@ -122,8 +115,22 @@ class UserTest < ActiveSupport::TestCase
     assert_equal(user.first_name, 'first_name_for_newly_created_user_updated')
   end
 
+  test "create new user with notifications" do
+    set_user_from_auth :admin
+
+    user_notification_helper true, 'active-notify-address@example.com', 'inactive-notify-address@example.com'
+    user_notification_helper true, 'active-notify-address@example.com', []
+    user_notification_helper true, [], []
+    user_notification_helper false, 'active-notify-address@example.com', 'inactive-notify-address@example.com'
+    user_notification_helper false, [], 'inactive-notify-address@example.com'
+    user_notification_helper false, [], []
+  end
+
   test "update existing user" do
-    Thread.current[:user] = @active_user    # set active user as current user
+    set_user_from_auth :active    # set active user as current user
+
+    @active_user = users(:active)     # get the active user
+
     @active_user.first_name = "first_name_changed"
     @active_user.save
 
@@ -131,7 +138,7 @@ class UserTest < ActiveSupport::TestCase
     assert_equal(@active_user.first_name, 'first_name_changed')
 
     # admin user also should be able to update the "active" user info
-    Thread.current[:user] = @admin_user # set admin user as current user
+    set_user_from_auth :admin # set admin user as current user
     @active_user.first_name = "first_name_changed_by_admin_for_active_user"
     @active_user.save
 
@@ -140,9 +147,10 @@ class UserTest < ActiveSupport::TestCase
   end
 
   test "delete a user and verify" do
+    @active_user = users(:active)     # get the active user
     active_user_uuid = @active_user.uuid
 
-    Thread.current[:user] = @admin_user
+    set_user_from_auth :admin
     @active_user.delete
 
     found_deleted_user = false
@@ -157,7 +165,7 @@ class UserTest < ActiveSupport::TestCase
   end
 
   test "create new user as non-admin user" do
-    Thread.current[:user] = @active_user
+    set_user_from_auth :active
 
     begin
       user = User.new
@@ -169,7 +177,7 @@ class UserTest < ActiveSupport::TestCase
   end
 
   test "setup new user" do
-    Thread.current[:user] = @admin_user
+    set_user_from_auth :admin
 
     email = 'foo@example.com'
     openid_prefix = 'http://openid/prefix'
@@ -202,7 +210,7 @@ class UserTest < ActiveSupport::TestCase
   end
 
   test "setup new user with junk in database" do
-    Thread.current[:user] = @admin_user
+    set_user_from_auth :admin
 
     email = 'foo@example.com'
     openid_prefix = 'http://openid/prefix'
@@ -246,7 +254,7 @@ class UserTest < ActiveSupport::TestCase
 
 
   test "setup new user in multiple steps" do
-    Thread.current[:user] = @admin_user
+    set_user_from_auth :admin
 
     email = 'foo@example.com'
     openid_prefix = 'http://openid/prefix'
@@ -343,4 +351,55 @@ class UserTest < ActiveSupport::TestCase
     end
   end
 
+  def user_notification_helper (active, active_recipients, inactive_recipients)
+    Rails.configuration.new_user_notification_recipients = active_recipients
+    Rails.configuration.new_inactive_user_notification_recipients = inactive_recipients
+
+    assert_equal active_recipients, Rails.configuration.new_user_notification_recipients
+    assert_equal inactive_recipients, Rails.configuration.new_inactive_user_notification_recipients
+
+    ActionMailer::Base.deliveries = []
+
+    user = User.new
+    user.first_name = "first_name_for_newly_created_user"
+    user.is_active = active
+    user.save
+
+    new_user_email = nil
+    new_inactive_user_email = nil
+
+    ActionMailer::Base.deliveries.each do |d|
+      if d.subject == "#{Rails.configuration.email_subject_prefix}New user notification" then
+        new_user_email = d
+      elsif d.subject == "#{Rails.configuration.email_subject_prefix}New inactive user notification" then
+        new_inactive_user_email = d
+      end
+    end
+
+    if not active
+      if not inactive_recipients.empty? then
+        assert_not_nil new_inactive_user_email, 'Expected new inactive user email after setup'
+        assert_equal Rails.configuration.user_notifier_email_from, new_inactive_user_email.from[0]
+        assert_equal inactive_recipients, new_inactive_user_email.to[0]
+        assert_equal "#{Rails.configuration.email_subject_prefix}New inactive user notification", new_inactive_user_email.subject
+      else
+        assert_nil new_inactive_user_email, 'Did not expect new inactive user email after setup'
+      end
+    end
+
+    if active
+      assert_nil new_inactive_user_email, 'Expected email after setup'
+      if not active_recipients.empty? then
+        assert_not_nil new_user_email, 'Expected new user email after setup'
+        assert_equal Rails.configuration.user_notifier_email_from, new_user_email.from[0]
+        assert_equal active_recipients, new_user_email.to[0]
+        assert_equal "#{Rails.configuration.email_subject_prefix}New user notification", new_user_email.subject
+      else
+        assert_nil new_user_email, 'Did not expect new user email after setup'
+      end
+    end
+    ActionMailer::Base.deliveries = []
+
+  end
+
 end
index a6440033e15256a6557de12570dc0ce595a2287e..3939e5ada89906b65659069a15879ebe8367a038 100644 (file)
@@ -21,7 +21,12 @@ class MountTestBase(unittest.TestCase):
     def tearDown(self):
         # llfuse.close is buggy, so use fusermount instead.
         #llfuse.close(unmount=True)
-        subprocess.call(["fusermount", "-u", self.mounttmp])
+        count = 0
+        success = 1
+        while (count < 9 and success != 0):
+          success = subprocess.call(["fusermount", "-u", self.mounttmp])
+          time.sleep(0.5)
+          count += 1
 
         os.rmdir(self.mounttmp)
         shutil.rmtree(self.keeptmp)