Merge branch '2449-keep-write-blocks' into 2449-keep-index-status-handlers
authorTim Pierce <twp@curoverse.com>
Fri, 11 Apr 2014 15:30:25 +0000 (11:30 -0400)
committerTim Pierce <twp@curoverse.com>
Fri, 11 Apr 2014 15:30:25 +0000 (11:30 -0400)
apps/workbench/Gemfile
apps/workbench/Gemfile.lock
apps/workbench/README.textile
apps/workbench/app/views/pipeline_instances/_show_components.html.erb
apps/workbench/app/views/pipeline_instances/show.js.erb
apps/workbench/test/integration/users_test.rb
services/keep/keep_test.go

index 1e43d1c522190d7599f5fe4bf9c4c6a1caa193df..ee43a895c713c3d995164f35e93a1ed78af659f9 100644 (file)
@@ -28,7 +28,7 @@ group :test do
   gem 'selenium-webdriver'
   gem 'capybara'
   gem 'poltergeist'
-  gem 'capybara-webkit'
+  gem 'headless'
 end
 
 gem 'jquery-rails'
index 0795f752db7ee4d40a94f47d6addd27382fb75b2..e1e2b819542d94a0305c4813cd1f14cba143b707 100644 (file)
@@ -48,9 +48,6 @@ GEM
       rack (>= 1.0.0)
       rack-test (>= 0.5.4)
       xpath (~> 2.0)
-    capybara-webkit (1.1.0)
-      capybara (~> 2.0, >= 2.0.2)
-      json
     childprocess (0.5.1)
       ffi (~> 1.0, >= 1.0.11)
     cliver (0.3.2)
@@ -67,6 +64,7 @@ GEM
     erubis (2.7.0)
     execjs (2.0.2)
     ffi (1.9.3)
+    headless (1.0.1)
     highline (1.6.20)
     hike (1.2.3)
     httpclient (2.3.4.1)
@@ -185,9 +183,9 @@ DEPENDENCIES
   bootstrap-sass (~> 3.1.0)
   bootstrap-x-editable-rails
   capybara
-  capybara-webkit
   coffee-rails (~> 3.2.0)
   deep_merge
+  headless
   httpclient
   jquery-rails
   less
index 00588e8e8a79bd46bb6c5b785cce21694a3eff0f..7991978592e01958819ebf9af553c7e518d281c6 100644 (file)
@@ -6,20 +6,10 @@ h2. Running tests
 
 The Workbench application includes a series of integration tests.  When you run these, it starts the API server in a test environment, with all of its fixtures loaded, then tests Workbench by starting that server and making requests against it.
 
-Before running @bundle install@, make sure you install QT development dependencies (otherwise, capybara-webkit installation will fail). For example, on a Debian or Ubuntu system:
+In order for this to work, you must have Firefox installed (or Iceweasel, if you're running Debian), as well as the X Virtual Frame Buffer driver.
 
 <pre>
-arvados/apps/workbench$ sudo apt-get install qt4-qmake libqt4-dev
-arvados/apps/workbench$ RAILS_ENV=test bundle install
-</pre>
-
-In addition to bundled gems, running the integration tests requires "PhantomJS":http://phantomjs.org/download.html to test JavaScript elements.  The simplest way to get started is to download one of the binary builds provided, and install the executable into one of the directories in your @$PATH@.
-
-<pre>
-$ cd /tmp
-/tmp$ wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.7-linux-x86_64.tar.bz2
-/tmp$ tar xjf phantomjs-1.9.7-linux-x86_64.tar.bz2
-/tmp$ sudo cp -ip phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/bin/
+$ sudo apt-get install iceweasel xvfb
 </pre>
 
 If you install the Workbench Bundle in deployment mode, you must also install the API server Bundle in deployment mode, and vice versa.  If your Bundle installs have mismatched modes, the integration tests will fail with "Gem not found" errors.
index eafaf8d1db0792c2ca5ff3ccf06f0a269b1167c7..119415b9a682d32d4f40b1d7170cae0e3d5beaa0 100644 (file)
@@ -5,8 +5,14 @@
 <% template = PipelineTemplate.find(@object.pipeline_template_uuid) rescue nil %>
 
 <%= content_for :content_top do %>
+  <h2>
+    <%= render_editable_attribute @object, 'name', nil, { 'data-emptytext' => 'Unnamed pipeline', 'data-mode' => 'inline' } %>
+  </h2>
   <% if template %>
-    <h2><%= template.name %></h2>
+  <h4>
+    From template:
+    <%= link_to_if_arvados_object template, friendly_name: true %>
+  </h4>
   <% end %>
 <% end %>
 
index cfe288d0e322785294fce8bbcaaf8c4f144e268e..8d8292cb7436e29cb1cfad658541fb2389dd9c0b 100644 (file)
@@ -1,5 +1,16 @@
 <% self.formats = [:html] %>
 var new_content = "<%= escape_javascript(render template: 'pipeline_instances/show') %>";
-if ($('div.body-content').html() != new_content)
-   $('div.body-content').html(new_content);
+var selected_tab_hrefs = [];
+if ($('div.body-content').html() != new_content) {
+    $('.nav-tabs li.active a').each(function() {
+        selected_tab_hrefs.push($(this).attr('href'));
+    });
+
+    $('div.body-content').html(new_content);
+
+    // Show the same tabs that were active before we rewrote body-content
+    $.each(selected_tab_hrefs, function(i, href) {
+        $('.nav-tabs li a[href="' + href + '"]').tab('show');
+    });
+}
 $(document).trigger('ajax:complete');
index 9ee12d80861d1609af75a51728e671570eac09b7..22b92c02e1d23dbc55740f8c6209744a5a3a30df 100644 (file)
@@ -1,6 +1,9 @@
 require 'integration_helper'
+require 'selenium-webdriver'
+require 'headless'
 
 class UsersTest < ActionDispatch::IntegrationTest
+
   test "login as active user but not admin" do
     Capybara.current_driver = Capybara.javascript_driver
     visit page_with_token('active_trustedclient')
@@ -38,7 +41,11 @@ class UsersTest < ActionDispatch::IntegrationTest
   end
 
   test "create a new user" do
-    Capybara.current_driver = :webkit
+    headless = Headless.new
+    headless.start
+
+    Capybara.current_driver = :selenium
+
     visit page_with_token('admin_trustedclient')
 
     click_link 'Users'
@@ -61,14 +68,19 @@ class UsersTest < ActionDispatch::IntegrationTest
     # verify that the new user showed up in the users page
     assert page.has_text? 'foo@example.com'
 
-    page.within(:xpath, '//tr[@data-object-uuid][1]') do
-      assert (text.include? 'foo@example.com false'), 'Expected email'
-      new_user_uuid = text.split[0]
-
-      # go to the new user's page
-      click_link new_user_uuid
+    new_user_uuid = nil
+    all("tr").each do |elem|
+      if elem.text.include? 'foo@example.com'
+        new_user_uuid = elem.text.split[0]
+        break
+      end
     end
 
+    assert new_user_uuid, "Expected new user uuid not found"
+
+    # go to the new user's page
+    click_link new_user_uuid
+
     assert page.has_text? 'modified_by_user_uuid'
     page.within(:xpath, '//a[@data-name="is_active"]') do
       assert_equal "false", text, "Expected new user's is_active to be false"
@@ -77,10 +89,15 @@ class UsersTest < ActionDispatch::IntegrationTest
     click_link 'Metadata'
     assert page.has_text? '(Repository: test_repo)'
     assert !(page.has_text? '(VirtualMachine:)')
+
+    headless.stop
   end
 
   test "setup the active user" do
-    Capybara.current_driver = :webkit
+    headless = Headless.new
+    headless.start
+
+    Capybara.current_driver = :selenium
     visit page_with_token('admin_trustedclient')
 
     click_link 'Users'
@@ -97,6 +114,7 @@ class UsersTest < ActionDispatch::IntegrationTest
     click_link 'Setup Active User'
 
     sleep(0.1)
+
     popup = page.driver.browser.window_handles.last
     page.within_window popup do
       assert has_text? 'Virtual Machine'
@@ -129,10 +147,15 @@ class UsersTest < ActionDispatch::IntegrationTest
     click_link 'Metadata'
     assert page.has_text? '(Repository: second_test_repo)'
     assert page.has_text? '(VirtualMachine: testvm.shell)'
+
+    headless.stop
   end
 
   test "unsetup active user" do
-    Capybara.current_driver = :webkit
+    headless = Headless.new
+    headless.start
+
+    Capybara.current_driver = :selenium
 
     visit page_with_token('admin_trustedclient')
 
@@ -160,6 +183,7 @@ class UsersTest < ActionDispatch::IntegrationTest
     sleep(0.1)
 
     # Should now be back in the Attributes tab for the user
+    page.driver.browser.switch_to.alert.accept
     assert page.has_text? 'modified_by_user_uuid'
     page.within(:xpath, '//a[@data-name="is_active"]') do
       assert_equal "false", text, "Expected user's is_active to be false after unsetup"
@@ -188,6 +212,8 @@ class UsersTest < ActionDispatch::IntegrationTest
     click_link 'Metadata'
     assert page.has_text? '(Repository: second_test_repo)'
     assert page.has_text? '(VirtualMachine: testvm.shell)'
+
+    headless.stop
   end
 
 end
index 250c556a03b2c4868b1fd46fed07b9edae7bd949..9f6963b06f68a11935151d3b97e7f59cb851d7bb 100644 (file)
@@ -25,15 +25,18 @@ var BAD_BLOCK = []byte("The magic words are squeamish ossifrage.")
 
 // TODO(twp): Tests still to be written
 //
-//   * PutBlockCollision
-//       - test that PutBlock(BLOCK, HASH) reports a collision. HASH must
-//         be present in Keep and identify a block which sums to HASH but
-//         which does not match BLOCK. (Requires an interface to mock MD5.)
-//
 //   * PutBlockFull
 //       - test that PutBlock returns 503 Full if the filesystem is full.
 //         (must mock FreeDiskSpace or Statfs? use a tmpfs?)
-
+//
+//   * PutBlockWriteErr
+//       - test the behavior when Write returns an error.
+//           - Possible solutions: use a small tmpfs and a high
+//             MIN_FREE_KILOBYTES to trick PutBlock into attempting
+//             to write a block larger than the amount of space left
+//           - use an interface to mock ioutil.TempFile with a File
+//             object that always returns an error on write
+//
 // ========================================
 // GetBlock tests.
 // ========================================
@@ -208,6 +211,30 @@ func TestPutBlockCorrupt(t *testing.T) {
        }
 }
 
+// PutBlockCollision
+//     PutBlock returns a 400 Collision error when attempting to
+//     store a block that collides with another block on disk.
+//
+func TestPutBlockCollision(t *testing.T) {
+       defer teardown()
+
+       // These blocks both hash to the MD5 digest cee9a457e790cf20d4bdaa6d69f01e41.
+       var b1 = []byte("\x0e0eaU\x9a\xa7\x87\xd0\x0b\xc6\xf7\x0b\xbd\xfe4\x04\xcf\x03e\x9epO\x854\xc0\x0f\xfbe\x9cL\x87@\xcc\x94/\xeb-\xa1\x15\xa3\xf4\x15\\\xbb\x86\x07Is\x86em}\x1f4\xa4 Y\xd7\x8fZ\x8d\xd1\xef")
+       var b2 = []byte("\x0e0eaU\x9a\xa7\x87\xd0\x0b\xc6\xf7\x0b\xbd\xfe4\x04\xcf\x03e\x9etO\x854\xc0\x0f\xfbe\x9cL\x87@\xcc\x94/\xeb-\xa1\x15\xa3\xf4\x15\xdc\xbb\x86\x07Is\x86em}\x1f4\xa4 Y\xd7\x8fZ\x8d\xd1\xef")
+       var locator = "cee9a457e790cf20d4bdaa6d69f01e41"
+
+       // Prepare two test Keep volumes. Store one block,
+       // then attempt to store the other.
+       KeepVolumes = setup(t, 2)
+       store(t, KeepVolumes[1], locator, b1)
+
+       if err := PutBlock(b2, locator); err == nil {
+               t.Error("PutBlock did not report a collision")
+       } else if err.(*KeepError).HTTPCode != ErrCollision {
+               t.Errorf("PutBlock returned %v", err)
+       }
+}
+
 // ========================================
 // FindKeepVolumes tests.
 // ========================================