Merge branch '5692-pysdk-manifest-text-flush' closes #5692
authorPeter Amstutz <peter.amstutz@curoverse.com>
Mon, 13 Apr 2015 17:10:09 +0000 (13:10 -0400)
committerPeter Amstutz <peter.amstutz@curoverse.com>
Mon, 13 Apr 2015 17:10:09 +0000 (13:10 -0400)
14 files changed:
apps/workbench/app/controllers/application_controller.rb
apps/workbench/app/helpers/application_helper.rb
apps/workbench/app/helpers/jobs_helper.rb
apps/workbench/app/models/arvados_base.rb
apps/workbench/app/models/arvados_resource_list.rb
apps/workbench/app/views/application/_content.html.erb
apps/workbench/app/views/pipeline_instances/_running_component.html.erb
apps/workbench/app/views/pipeline_instances/_show_components_editable.html.erb
apps/workbench/app/views/pipeline_instances/_show_components_running.html.erb
apps/workbench/test/controllers/application_controller_test.rb
apps/workbench/test/integration/anonymous_access_test.rb
services/api/test/fixtures/jobs.yml
services/api/test/fixtures/logs.yml
services/api/test/fixtures/pipeline_instances.yml

index 1b59c574b774a897372a7f771dc4cdeda5f45df2..db00be390a7e6846c2c8983efb90c2f213fd4336 100644 (file)
@@ -1068,6 +1068,39 @@ class ApplicationController < ActionController::Base
     @all_log_collections_for
   end
 
+  # Helper method to get one collection for the given portable_data_hash
+  # This is used to determine if a pdh is readable by the current_user
+  helper_method :collection_for_pdh
+  def collection_for_pdh pdh
+    raise ArgumentError, 'No input argument' unless pdh
+    preload_for_pdhs([pdh])
+    @all_pdhs_for[pdh] ||= []
+  end
+
+  # Helper method to preload one collection each for the given pdhs
+  # This is used to determine if a pdh is readable by the current_user
+  helper_method :preload_for_pdhs
+  def preload_for_pdhs pdhs
+    @all_pdhs_for ||= {}
+
+    raise ArgumentError, 'Argument is not an array' unless pdhs.is_a? Array
+    return @all_pdhs_for if pdhs.empty?
+
+    # if already preloaded for all of these pdhs, return
+    if not pdhs.select { |x| @all_pdhs_for[x].nil? }.any?
+      return @all_pdhs_for
+    end
+
+    pdhs.each do |x|
+      @all_pdhs_for[x] = []
+    end
+
+    Collection.select(%w(portable_data_hash)).where(portable_data_hash: pdhs).distinct().each do |collection|
+      @all_pdhs_for[collection.portable_data_hash] << collection
+    end
+    @all_pdhs_for
+  end
+
   # helper method to get object of a given dataclass and uuid
   helper_method :object_for_dataclass
   def object_for_dataclass dataclass, uuid
@@ -1087,10 +1120,14 @@ class ApplicationController < ActionController::Base
     return @objects_for if uuids.empty?
 
     # if already preloaded for all of these uuids, return
-    if not uuids.select { |x| @objects_for[x].nil? }.any?
+    if not uuids.select { |x| !@objects_for.include?(x) }.any?
       return @objects_for
     end
 
+    # preset all uuids to nil
+    uuids.each do |x|
+      @objects_for[x] = nil
+    end
     dataclass.where(uuid: uuids).each do |obj|
       @objects_for[obj.uuid] = obj
     end
index a80290cfa0a4433a7bd5707bbd9e277208c1f103..72f961f38a225e1e707fc8db92d1da77e5f7c7d7 100644 (file)
@@ -177,6 +177,29 @@ module ApplicationHelper
     end
   end
 
+  def link_to_arvados_object_if_readable(attrvalue, link_text_if_not_readable, opts={})
+    resource_class = resource_class_for_uuid(attrvalue)
+    if !resource_class
+      return link_to_if_arvados_object attrvalue, opts
+    end
+
+    if resource_class.to_s == 'Collection'
+      if CollectionsHelper.match(attrvalue)
+        readable = collection_for_pdh(attrvalue).any?
+      else
+        readable = collections_for_object(attrvalue).any?
+      end
+    else
+      readable = object_for_dataclass(resource_class, attrvalue)
+    end
+
+    if readable
+      link_to_if_arvados_object attrvalue, opts
+    else
+      link_text_if_not_readable
+    end
+  end
+
   def render_editable_attribute(object, attr, attrvalue=nil, htmloptions={})
     attrvalue = object.send(attr) if attrvalue.nil?
     if not object.attribute_editable?(attr)
@@ -271,7 +294,7 @@ module ApplicationHelper
     end
 
     if not object.andand.attribute_editable?(attr)
-      return link_to_if_arvados_object attrvalue
+      return link_to_arvados_object_if_readable(attrvalue, attrvalue, friendly_name: true)
     end
 
     if dataclass
index 24033137b0f349f9bf0fd7cbc17bc2b717c82fef..889dd23823b2c1050bc2f05ec2d69cc95900984c 100644 (file)
@@ -1,9 +1,9 @@
 module JobsHelper
-  def stderr_log_history(job_uuids)
+  def stderr_log_history(job_uuids, limit=2000)
     results = []
 
     log_history = Log.where(event_type: 'stderr',
-                            object_uuid: job_uuids).limit(2000).order('id DESC')
+                            object_uuid: job_uuids).limit(limit).order('id DESC')
     if !log_history.results.empty?
       reversed_results = log_history.results.reverse
       reversed_results.each do |entry|
index f19d47435ae979564c94cf9117109ff44fe5acdf..2fca11ecf13f75fb1b5a3838659da64665d40fbf 100644 (file)
@@ -135,6 +135,10 @@ class ArvadosBase < ActiveRecord::Base
     ArvadosResourceList.new(self).select(*args)
   end
 
+  def self.distinct(*args)
+    ArvadosResourceList.new(self).distinct(*args)
+  end
+
   def self.eager(*args)
     ArvadosResourceList.new(self).eager(*args)
   end
index d989715080fd1c244fecf557824a4a0dac883944..9f66d392270b88c50df561e2f6f91c6f2852b013 100644 (file)
@@ -16,6 +16,11 @@ class ArvadosResourceList
     self
   end
 
+  def distinct(bool=true)
+    @distinct = bool
+    self
+  end
+
   def limit(max_results)
     if not max_results.nil? and not max_results.is_a? Integer
       raise ArgumentError("argument to limit() must be an Integer or nil")
@@ -178,6 +183,7 @@ class ArvadosResourceList
     api_params[:select] = @select if @select
     api_params[:order] = @orderby_spec if @orderby_spec
     api_params[:filters] = @filters if @filters
+    api_params[:distinct] = @distinct if @distinct
 
 
     item_count = 0
index 782a6af07996efe888489b33bf04c0145d76d9d3..5e6211f4623fbedfcfe72539fc1beb4c56b3540c 100644 (file)
@@ -5,10 +5,36 @@
   <ul class="nav nav-tabs" data-tab-counts-url="<%= url_for(action: :tab_counts) rescue '' %>">
     <% pane_list.each_with_index do |pane, i| %>
       <% pane_name = (pane.is_a?(Hash) ? pane[:name] : pane) %>
-      <li class="<%= 'active' if i==0 %>">
+
+      <% data_toggle = "tab" %>
+      <% tab_tooltip = "" %>
+      <% link_disabled = "" %>
+
+      <% if (pane_name == "Log") and !(ArvadosBase.find(@object.owner_uuid).writable_by.include?(current_user.andand.uuid) rescue nil)
+          if controller.model_class.to_s == 'Job'
+            if @object.log and !@object.log.empty?
+              logCollection = Collection.find? @object.log
+              if !logCollection
+                data_toggle = "disabled"
+                tab_tooltip = "Log data is not available"
+                link_disabled = "disabled"
+              end
+            end
+          elsif controller.model_class.to_s == 'PipelineInstance'
+            log_uuids = [@object.uuid] + pipeline_jobs(@object).collect{|x|x[:job].andand[:uuid]}.compact
+            if stderr_log_history(log_uuids, 1).empty?
+              data_toggle = "disabled"
+              tab_tooltip = "Log data is not available"
+              link_disabled = "disabled"
+            end
+          end
+        end
+      %>
+
+      <li class="<%= 'active' if i==0 %> <%= link_disabled %>" data-toggle="tooltip" data-placement="top" title="<%=tab_tooltip%>">
         <a href="#<%= pane_name %>"
            id="<%= pane_name %>-tab"
-           data-toggle="tab"
+           data-toggle="<%= data_toggle %>"
            data-tab-history=true
            data-tab-history-update-url=true
            >
index 018d49f5e4a10f5ed9ab81385d8a2416b0b3a0b1..1a9cb3562afac89b3f615156af5c193851dc9c71 100644 (file)
@@ -66,9 +66,9 @@
             <%# column offset 8 %>
             <div class="col-md-4 text-overflow-ellipsis">
               <% if pj[:output_uuid] %>
-                <%= link_to_if_arvados_object pj[:output_uuid], friendly_name: true %>
+                <%= link_to_arvados_object_if_readable(pj[:output_uuid], 'Output data not available', friendly_name: true) %>
               <% elsif current_job[:output] %>
-                <%= link_to_if_arvados_object current_job[:output], link_text: "Output of #{pj[:name]}" %>
+                <%= link_to_arvados_object_if_readable(current_job[:output], 'Output data not available', link_text: "Output of #{pj[:name]}") %>
               <% else %>
                 No output.
               <% end %>
                     docker_image_locator:
                   </td>
                   <td>
-                    <%= link_to_if_arvados_object current_component[:docker_image_locator], friendly_name: true %>
+                    <%= link_to_arvados_object_if_readable(current_component[:docker_image_locator],
+                      current_component[:docker_image_locator], friendly_name: true) %>
                   </td>
                 </tr>
               <% else %>
                   </td>
                   <td>
                     <% if k == :uuid %>
-                      <%= link_to_if_arvados_object current_component[k], link_text: current_component[k] %>
+                      <%= link_to_arvados_object_if_readable(current_component[k], current_component[k], link_text: current_component[k]) %>
                     <% elsif k.to_s.end_with? 'uuid' %>
-                      <%= link_to_if_arvados_object current_component[k], friendly_name: true %>
+                      <%= link_to_arvados_object_if_readable(current_component[k], current_component[k], friendly_name: true) %>
                     <% elsif k.to_s.end_with? '_at' %>
                       <%= render_localized_date(current_component[k]) %>
                     <% else %>
index f6c9e85883487c611de38276ca8ee5dd579ca1d9..51fe8d4d3c717025c349391036e518a68782c058 100644 (file)
@@ -1,3 +1,23 @@
+<%
+  input_uuids = []
+  input_pdhs = []
+  @object.components.each do |k, component|
+    next if !component
+    component[:script_parameters].andand.each do |p, tv|
+      if tv.is_a? Hash and !tv[:value].nil? and (tv[:dataclass] == "Collection")
+        if CollectionsHelper.match(tv[:value])
+          input_pdhs << tv[:value]
+        else
+          input_uuids << tv[:value]
+        end
+      end
+    end
+  end
+
+  preload_collections_for_objects input_uuids if input_uuids.any?
+  preload_for_pdhs input_pdhs if input_pdhs.any?
+%>
+
 <table class="table pipeline-components-table" style="margin-top: -.1em">
   <colgroup>
     <col style="width: 20%" />
index d99ac23ab8c969f08f50cb3132ac610502762e0a..6fa409a1ce4c211570ca55b256410e37029861a3 100644 (file)
 
 <%# Components %>
 
+<%
+  job_uuids = pipeline_jobs.collect {|j| j[:job][:uuid]}.compact
+  if job_uuids.any?
+    resource_class = resource_class_for_uuid(job_uuids.first, friendly_name: true)
+    preload_objects_for_dataclass resource_class, job_uuids
+  end
+
+  job_collections = pipeline_jobs.collect {|j| j[:job][:output]}.compact
+  job_collections.concat pipeline_jobs.collect {|j| j[:job][:docker_image_locator]}.uniq.compact
+  job_collections_pdhs = job_collections.select {|x| !(m = CollectionsHelper.match(x)).nil?}.uniq.compact
+  job_collections_uuids = job_collections - job_collections_pdhs
+  preload_collections_for_objects job_collections_uuids if job_collections_uuids.any?
+  preload_for_pdhs job_collections_pdhs if job_collections_pdhs.any?
+%>
+
 <% pipeline_jobs.each_with_index do |pj, i| %>
   <%= render partial: 'running_component', locals: {tasks: tasks, pj: pj, i: i, expanded: false} %>
 <% end %>
index 978524393124792269beafeeaee0393a282377fd..22ff7d4b2bfc60c35309eb6c654a087de5c0a3f8 100644 (file)
@@ -59,6 +59,7 @@ class ApplicationControllerTest < ActionController::TestCase
     [:preload_collections_for_objects, [] ],
     [:preload_log_collections_for_objects, [] ],
     [:preload_objects_for_dataclass, [] ],
+    [:preload_for_pdhs, [] ],
   ].each do |input|
     test "preload data for empty array input #{input}" do
       use_token :active
@@ -90,6 +91,8 @@ class ApplicationControllerTest < ActionController::TestCase
     [:preload_objects_for_dataclass, nil],
     [:object_for_dataclass, 'some_dataclass', nil],
     [:object_for_dataclass, nil, 'some_uuid'],
+    [:preload_for_pdhs, 'input not an array'],
+    [:preload_for_pdhs, nil],
   ].each do |input|
     test "preload data for wrong type input #{input}" do
       use_token :active
@@ -112,6 +115,7 @@ class ApplicationControllerTest < ActionController::TestCase
     [:collections_for_object, 'no-such-uuid' ],
     [:log_collections_for_object, 'no-such-uuid' ],
     [:object_for_dataclass, 'no-such-uuid' ],
+    [:collection_for_pdh, 'no-such-pdh' ],
   ].each do |input|
     test "get data for no such uuid #{input}" do
       use_token :active
@@ -125,6 +129,7 @@ class ApplicationControllerTest < ActionController::TestCase
         objects = ac.send input[0], input[1]
         assert objects, 'Expected objects'
         assert objects.is_a?(Array), 'Expected a array'
+        assert_empty objects
       end
     end
   end
@@ -300,6 +305,27 @@ class ApplicationControllerTest < ActionController::TestCase
     assert users.size == 3, 'Expected two objects in the preloaded hash'
   end
 
+  test "preload one collection each for given portable_data_hash list" do
+    use_token :active
+
+    ac = ApplicationController.new
+
+    pdh1 = api_fixture('collections')['foo_file']['portable_data_hash']
+    pdh2 = api_fixture('collections')['bar_file']['portable_data_hash']
+
+    pdhs = [pdh1, pdh2]
+    collections = ac.send :preload_for_pdhs, pdhs
+
+    assert collections, 'Expected collections map'
+    assert collections.is_a?(Hash), 'Expected a hash'
+    # Each pdh has more than one collection; however, we should get only one for each
+    assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
+    assert collections[pdh1], 'Expected collections for the passed in pdh #{pdh1}'
+    assert_equal collections[pdh1].size, 1, 'Expected one collection for the passed in pdh #{pdh1}'
+    assert collections[pdh2], 'Expected collections for the passed in pdh #{pdh2}'
+    assert_equal collections[pdh2].size, 1, 'Expected one collection for the passed in pdh #{pdh2}'
+  end
+
   test "requesting a nonexistent object returns 404" do
     # We're really testing ApplicationController's find_object_by_uuid.
     # It's easiest to do that by instantiating a concrete controller.
index 4447bd3596b16742c0a68bc5d369b64b21135ecb..e8917792ad6a5f579f0550dd18ea8cea1b535157 100644 (file)
@@ -183,6 +183,98 @@ class AnonymousAccessTest < ActionDispatch::IntegrationTest
     assert_no_selector 'a', text: 'Run this pipeline'
   end
 
+  [
+    ['pipeline_in_publicly_accessible_project', true],
+    ['pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false],
+    ['pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false, 'spectator'],
+    ['pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', true, 'admin'],
+
+    ['completed_job_in_publicly_accessible_project', true],
+    ['job_in_publicly_accessible_project_but_other_objects_elsewhere', false],
+  ].each do |fixture, objects_readable, user=nil|
+    test "access #{fixture} in public project with objects readable=#{objects_readable} with user #{user}" do
+      pipeline_page = true if fixture.include?('pipeline')
+
+      if pipeline_page
+        object = api_fixture('pipeline_instances')[fixture]
+        page = "/pipeline_instances/#{object['uuid']}"
+      else      # job
+        object = api_fixture('jobs')[fixture]
+        page = "/jobs/#{object['uuid']}"
+      end
+
+      if user
+        visit page_with_token user, page
+      else
+        visit page
+      end
+
+      # click job link, if in pipeline page
+      click_link 'foo' if pipeline_page
+
+      if objects_readable
+        if pipeline_page
+          assert_text 'This pipeline was created from'
+          assert_selector 'a', text: object['components']['foo']['job']['uuid']
+        end
+        assert_no_text 'Output data not available'
+        assert_selector 'a[href="#Log"]', text: 'Log'
+        assert_no_selector 'a[data-toggle="disabled"]', text: 'Log'
+      else
+        if pipeline_page
+          assert_no_text 'This pipeline was created from'  # template is not readable
+          assert_no_selector 'a', text: object['components']['foo']['job']['uuid']
+        end
+        assert_text 'Output data not available'
+        assert_text object['job']
+        assert_selector 'a[data-toggle="disabled"]', text: 'Log'
+      end
+
+      click_link 'Log'
+      if objects_readable
+        assert_no_text 'foo'  # should be in Log tab
+        assert_text 'stderr crunchstat'   if pipeline_page
+      else
+        assert_text 'foo'     # Log tab disabled and hence still in first tab
+        assert_no_text 'stderr crunchstat'  # log line shouldn't be seen
+      end
+    end
+  end
+
+  [
+    ['new_pipeline_in_publicly_accessible_project', true],
+    ['new_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false],
+    ['new_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false, 'spectator'],
+    ['new_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', true, 'admin'],
+  ].each do |fixture, objects_readable, user=nil|
+    test "access #{fixture} in public project with objects readable=#{objects_readable} with user #{user}" do
+      object = api_fixture('pipeline_instances')[fixture]
+      page = "/pipeline_instances/#{object['uuid']}"
+      if user
+        visit page_with_token user, page
+      else
+        visit page
+      end
+
+      # click Components tab
+      click_link 'Components'
+
+      if objects_readable
+        assert_text 'This pipeline was created from'
+        if user == 'admin'
+          assert_text 'input'
+          assert_selector 'a', text: 'Choose'
+        else
+          assert_selector 'a', text: object['components']['foo']['script_parameters']['input']['value']
+        end
+      else
+        assert_no_text 'This pipeline was created from'  # template is not readable
+        assert_text object['components']['foo']['script_parameters']['input']['value']
+        assert_no_selector 'a', text: object['components']['foo']['script_parameters']['input']['value']
+      end
+    end
+  end
+
   test "anonymous user accesses collection in shared project" do
     visit "/collections/#{api_fixture('collections')['public_text_file']['uuid']}"
 
index ea6cbb0868049de00550d0b2d05706233d958d6a..c6620627041a9552d65fbac8610153ac79dbe195 100644 (file)
@@ -425,6 +425,22 @@ completed_job_in_publicly_accessible_project:
   script_parameters:
     input: fa7aeb5140e2848d39b416daeef4ffc5+45
     input2: "stuff2"
+  log: ~
+  output: b519d9cb706a29fc7ea24dbea2f05851+93
+
+job_in_publicly_accessible_project_but_other_objects_elsewhere:
+  uuid: zzzzz-8i9sb-jyq01muyhgr4ofj
+  owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+  repository: active/foo
+  script: completed_job_script
+  script_version: 4fe459abe02d9b365932b8f5dc419439ab4e2577
+  state: Complete
+  script_parameters:
+    input: fa7aeb5140e2848d39b416daeef4ffc5+45
+    input2: "stuff2"
+  log: zzzzz-4zz18-fy296fx3hot09f7
+  output: zzzzz-4zz18-bv31uwvy3neko21
 
 # Test Helper trims the rest of the file
 
index 06f7a021d6e6edf7de2f1ae31f28cdcc55087c16..aea7980b0509fda97c40a662807ae2e671f3f77f 100644 (file)
@@ -63,3 +63,41 @@ crunchstat_for_running_job:
   updated_at: 2014-11-07 23:33:42.347455000 Z
   modified_at: 2014-11-07 23:33:42.347455000 Z
   object_owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
+
+log_line_for_pipeline_in_publicly_accessible_project:
+  id: 8
+  uuid: zzzzz-57u5n-tmymyrojrjyhb45
+  owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  modified_by_client_uuid: zzzzz-ozdt8-obw7foaks3qjyej
+  modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+  object_uuid: zzzzz-d1hrv-n68vc490mloy4fi
+  event_at: 2014-11-07 23:33:42.347455000 Z
+  event_type: stderr
+  summary: ~
+  properties:
+    text: '2014-11-07_23:33:41 zzzzz-d1hrv-n68vc490mloy4fi 31708 1 stderr crunchstat:
+      cpu 1935.4300 user 59.4100 sys 8 cpus -- interval 10.0002 seconds 12.9900 user
+      0.9900 sys'
+  created_at: 2014-11-07 23:33:42.351913000 Z
+  updated_at: 2014-11-07 23:33:42.347455000 Z
+  modified_at: 2014-11-07 23:33:42.347455000 Z
+  object_owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
+
+log_line_for_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere:
+  id: 9
+  uuid: zzzzz-57u5n-tmyhy56k9lnhb45
+  owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
+  modified_by_client_uuid: zzzzz-ozdt8-obw7foaks3qjyej
+  modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+  object_uuid: zzzzz-d1hrv-pisharednotobjs
+  event_at: 2014-11-07 23:33:42.347455000 Z
+  event_type: stderr
+  summary: ~
+  properties:
+    text: '2014-11-07_23:33:41 zzzzz-d1hrv-pisharednotobjs 31708 1 stderr crunchstat:
+      cpu 1935.4300 user 59.4100 sys 8 cpus -- interval 10.0002 seconds 12.9900 user
+      0.9900 sys'
+  created_at: 2014-11-07 23:33:42.351913000 Z
+  updated_at: 2014-11-07 23:33:42.347455000 Z
+  modified_at: 2014-11-07 23:33:42.347455000 Z
+  object_owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
index df010353a8db60223f882cdbe70c7cf6ba62c92e..1f1b128133d32c22d715909c2f45d91aecd010ab 100644 (file)
@@ -254,6 +254,7 @@ pipeline_in_publicly_accessible_project:
   uuid: zzzzz-d1hrv-n68vc490mloy4fi
   owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
   name: Pipeline in publicly accessible project
+  pipeline_template_uuid: zzzzz-p5p6p-tmpltpublicproj
   state: Complete
   created_at: 2014-09-15 12:00:00
   components:
@@ -265,6 +266,77 @@ pipeline_in_publicly_accessible_project:
           required: true
           dataclass: Collection
           title: foo instance input
+      job:
+        uuid: zzzzz-8i9sb-jyq01m7in1jlofj
+        repository: active/foo
+        script: foo
+        script_version: master
+        script_parameters:
+          input: zzzzz-4zz18-4en62shvi99lxd4
+        log: zzzzz-4zz18-4en62shvi99lxd4
+        output: b519d9cb706a29fc7ea24dbea2f05851+93
+        state: Complete
+
+pipeline_in_publicly_accessible_project_but_other_objects_elsewhere:
+  uuid: zzzzz-d1hrv-pisharednotobjs
+  owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  name: Pipeline in public project with other objects elsewhere
+  pipeline_template_uuid: zzzzz-p5p6p-aox0k0ofxrystgw
+  state: Complete
+  created_at: 2014-09-15 12:00:00
+  components:
+    foo:
+      script: foo
+      script_version: master
+      script_parameters:
+        input:
+          required: true
+          dataclass: Collection
+          title: foo instance input
+      job:
+        uuid: zzzzz-8i9sb-aceg2bnq7jt7kon
+        repository: active/foo
+        script: foo
+        script_version: master
+        script_parameters:
+          input: zzzzz-4zz18-bv31uwvy3neko21
+        log: zzzzz-4zz18-bv31uwvy3neko21
+        output: zzzzz-4zz18-bv31uwvy3neko21
+        state: Complete
+
+new_pipeline_in_publicly_accessible_project:
+  uuid: zzzzz-d1hrv-newpisharedobjs
+  owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  name: Pipeline in New state in publicly accessible project
+  pipeline_template_uuid: zzzzz-p5p6p-tmpltpublicproj
+  state: New
+  created_at: 2014-09-15 12:00:00
+  components:
+    foo:
+      script: foo
+      script_version: master
+      script_parameters:
+        input:
+          required: true
+          dataclass: Collection
+          value: b519d9cb706a29fc7ea24dbea2f05851+93
+
+new_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere:
+  uuid: zzzzz-d1hrv-newsharenotobjs
+  owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+  name: Pipeline in New state in public project with objects elsewhere
+  pipeline_template_uuid: zzzzz-p5p6p-aox0k0ofxrystgw
+  state: New
+  created_at: 2014-09-15 12:00:00
+  components:
+    foo:
+      script: foo
+      script_version: master
+      script_parameters:
+        input:
+          required: true
+          dataclass: Collection
+          value: zzzzz-4zz18-bv31uwvy3neko21
 
 pipeline_in_running_state:
   name: running_with_job