13996: Update tests for cleaner config access
[arvados.git] / services / api / test / functional / arvados / v1 / users_controller_test.rb
index c4a99648cb25982723b370afdb5e61d31d3ef427..0501da1673ebdff87c5c9900b205dfdde96dce42 100644 (file)
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
 require 'test_helper'
 require 'helpers/users_test_helper'
 
@@ -6,13 +10,14 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   include UsersTestHelper
 
   setup do
-    @all_links_at_start = Link.all
+    @initial_link_count = Link.count
     @vm_uuid = virtual_machines(:testvm).uuid
+    ActionMailer::Base.deliveries = []
   end
 
   test "activate a user after signing UA" do
     authorize_with :inactive_but_signed_user_agreement
-    post :activate, id: users(:inactive_but_signed_user_agreement).uuid
+    post :activate, params: {id: users(:inactive_but_signed_user_agreement).uuid}
     assert_response :success
     assert_not_nil assigns(:object)
     me = JSON.parse(@response.body)
@@ -44,7 +49,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     authorize_with :inactive
     assert_equal false, users(:inactive).is_active
 
-    post :activate, id: users(:inactive).uuid
+    post :activate, params: {id: users(:inactive).uuid}
     assert_response 403
 
     resp = json_response
@@ -54,7 +59,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
 
   test "activate an already-active user" do
     authorize_with :active
-    post :activate, id: users(:active).uuid
+    post :activate, params: {id: users(:active).uuid}
     assert_response :success
     me = JSON.parse(@response.body)
     assert_equal true, me['is_active']
@@ -68,10 +73,12 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
 
   test "create new user with user as input" do
     authorize_with :admin
-    post :create, user: {
-      first_name: "test_first_name",
-      last_name: "test_last_name",
-      email: "foo@example.com"
+    post :create, params: {
+      user: {
+        first_name: "test_first_name",
+        last_name: "test_last_name",
+        email: "foo@example.com"
+      }
     }
     assert_response :success
     created = JSON.parse(@response.body)
@@ -85,7 +92,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     authorize_with :admin
     repo_name = 'usertestrepo'
 
-    post :setup, {
+    post :setup, params: {
       repo_name: repo_name,
       openid_prefix: 'https://www.google.com/accounts/o8/id',
       user: {
@@ -107,7 +114,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     assert_nil created['identity_url'], 'expected no identity_url'
 
     # arvados#user, repo link and link add user to 'All users' group
-    verify_num_links @all_links_at_start, 4
+    verify_links_added 4
 
     verify_link response_items, 'arvados#user', true, 'permission', 'can_login',
         created['uuid'], created['email'], 'arvados#user', false, 'User'
@@ -127,7 +134,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with bogus uuid and expect error" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       uuid: 'bogus_uuid',
       repo_name: 'usertestrepo',
       vm_uuid: @vm_uuid
@@ -141,7 +148,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with bogus uuid in user and expect error" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       user: {uuid: 'bogus_uuid'},
       repo_name: 'usertestrepo',
       vm_uuid: @vm_uuid,
@@ -157,7 +164,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with no uuid and user, expect error" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       repo_name: 'usertestrepo',
       vm_uuid: @vm_uuid,
       openid_prefix: 'https://www.google.com/accounts/o8/id'
@@ -172,7 +179,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with no uuid and email, expect error" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       user: {},
       repo_name: 'usertestrepo',
       vm_uuid: @vm_uuid,
@@ -189,7 +196,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     authorize_with :admin
     inactive_user = users(:inactive)
 
-    post :setup, {
+    post :setup, params: {
       uuid: users(:inactive).uuid,
       repo_name: 'usertestrepo',
       vm_uuid: @vm_uuid
@@ -213,31 +220,11 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
         @vm_uuid, resp_obj['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
   end
 
-  test "invoke setup with existing uuid in user, verify response" do
-    authorize_with :admin
-    inactive_user = users(:inactive)
-
-    post :setup, {
-      user: {uuid: inactive_user['uuid']},
-      openid_prefix: 'https://www.google.com/accounts/o8/id'
-    }
-
-    assert_response :success
-
-    response_items = JSON.parse(@response.body)['items']
-    resp_obj = find_obj_in_resp response_items, 'User', nil
-
-    assert_not_nil resp_obj['uuid'], 'expected uuid for the new user'
-    assert_equal inactive_user['uuid'], resp_obj['uuid']
-    assert_equal inactive_user['email'], resp_obj['email'],
-        'expecting inactive user email'
-  end
-
   test "invoke setup with existing uuid but different email, expect original email" do
     authorize_with :admin
     inactive_user = users(:inactive)
 
-    post :setup, {
+    post :setup, params: {
       uuid: inactive_user['uuid'],
       user: {email: 'junk_email'}
     }
@@ -256,7 +243,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with valid email and repo as input" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       repo_name: 'usertestrepo',
       user: {email: 'foo@example.com'},
       openid_prefix: 'https://www.google.com/accounts/o8/id'
@@ -269,13 +256,13 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     assert_equal response_object['email'], 'foo@example.com', 'expected given email'
 
     # four extra links; system_group, login, group and repo perms
-    verify_num_links @all_links_at_start, 4
+    verify_links_added 4
   end
 
   test "setup user with fake vm and expect error" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       repo_name: 'usertestrepo',
       vm_uuid: 'no_such_vm',
       user: {email: 'foo@example.com'},
@@ -292,7 +279,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with valid email, repo and real vm as input" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       repo_name: 'usertestrepo',
       openid_prefix: 'https://www.google.com/accounts/o8/id',
       vm_uuid: @vm_uuid,
@@ -306,13 +293,13 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     assert_equal response_object['email'], 'foo@example.com', 'expected given email'
 
     # five extra links; system_group, login, group, vm, repo
-    verify_num_links @all_links_at_start, 5
+    verify_links_added 5
   end
 
   test "setup user with valid email, no vm and no repo as input" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       user: {email: 'foo@example.com'},
       openid_prefix: 'https://www.google.com/accounts/o8/id'
     }
@@ -324,7 +311,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     assert_equal response_object['email'], 'foo@example.com', 'expected given email'
 
     # three extra links; system_group, login, and group
-    verify_num_links @all_links_at_start, 3
+    verify_links_added 3
 
     verify_link response_items, 'arvados#user', true, 'permission', 'can_login',
         response_object['uuid'], response_object['email'], 'arvados#user', false, 'User'
@@ -342,7 +329,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with email, first name, repo name and vm uuid" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       openid_prefix: 'https://www.google.com/accounts/o8/id',
       repo_name: 'usertestrepo',
       vm_uuid: @vm_uuid,
@@ -361,14 +348,14 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
         'expecting first name'
 
     # five extra links; system_group, login, group, repo and vm
-    verify_num_links @all_links_at_start, 5
+    verify_links_added 5
   end
 
   test "setup user with an existing user email and check different object is created" do
     authorize_with :admin
     inactive_user = users(:inactive)
 
-    post :setup, {
+    post :setup, params: {
       openid_prefix: 'https://www.google.com/accounts/o8/id',
       repo_name: 'usertestrepo',
       user: {
@@ -384,13 +371,13 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
         'expected different uuid after create operation'
     assert_equal inactive_user['email'], response_object['email'], 'expected given email'
     # system_group, openid, group, and repo. No vm link.
-    verify_num_links @all_links_at_start, 4
+    verify_links_added 4
   end
 
   test "setup user with openid prefix" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       repo_name: 'usertestrepo',
       openid_prefix: 'http://www.example.com/account',
       user: {
@@ -412,7 +399,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
 
     # verify links
     # four new links: system_group, arvados#user, repo, and 'All users' group.
-    verify_num_links @all_links_at_start, 4
+    verify_links_added 4
 
     verify_link response_items, 'arvados#user', true, 'permission', 'can_login',
         created['uuid'], created['email'], 'arvados#user', false, 'User'
@@ -430,7 +417,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "invoke setup with no openid prefix, expect error" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       repo_name: 'usertestrepo',
       user: {
         first_name: "in_create_test_first_name",
@@ -449,7 +436,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with user, vm and repo and verify links" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       user: {
         first_name: "in_create_test_first_name",
         last_name: "test_last_name",
@@ -472,7 +459,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
 
     # five new links: system_group, arvados#user, repo, vm and 'All
     # users' group link
-    verify_num_links @all_links_at_start, 5
+    verify_links_added 5
 
     verify_link response_items, 'arvados#user', true, 'permission', 'can_login',
         created['uuid'], created['email'], 'arvados#user', false, 'User'
@@ -490,7 +477,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "create user as non admin user and expect error" do
     authorize_with :active
 
-    post :create, {
+    post :create, params: {
       user: {email: 'foo@example.com'}
     }
 
@@ -504,7 +491,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user as non admin user and expect error" do
     authorize_with :active
 
-    post :setup, {
+    post :setup, params: {
       openid_prefix: 'https://www.google.com/accounts/o8/id',
       user: {email: 'foo@example.com'}
     }
@@ -521,7 +508,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     active_user = users(:active)
 
     # invoke setup with a repository
-    post :setup, {
+    post :setup, params: {
       repo_name: 'usertestrepo',
       uuid: active_user['uuid']
     }
@@ -554,7 +541,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     repo_link_count = repo_link_query.count
 
     # invoke setup with a repository
-    post :setup, {
+    post :setup, params: {
       vm_uuid: @vm_uuid,
       uuid: active_user['uuid'],
       email: 'junk_email'
@@ -589,7 +576,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     authorize_with :admin
 
     # now unsetup this user
-    post :unsetup, id: active_user['uuid']
+    post :unsetup, params: {id: active_user['uuid']}
     assert_response :success
 
     response_user = JSON.parse(@response.body)
@@ -603,7 +590,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
 
     active_user = User.find_by_uuid(users(:active).uuid)
     readable_groups = active_user.groups_i_can(:read)
-    all_users_group = Group.all.collect(&:uuid).select { |g| g.match /-f+$/ }
+    all_users_group = Group.all.collect(&:uuid).select { |g| g.match(/-f+$/) }
     refute_includes(readable_groups, all_users_group,
                     "active user can read All Users group after being deactivated")
     assert_equal(false, active_user.is_invited,
@@ -613,7 +600,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with send notification param false and verify no email" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       openid_prefix: 'http://www.example.com/account',
       send_notification_email: 'false',
       user: {
@@ -634,7 +621,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with send notification param true and verify email" do
     authorize_with :admin
 
-    post :setup, {
+    post :setup, params: {
       openid_prefix: 'http://www.example.com/account',
       send_notification_email: 'true',
       user: {
@@ -651,13 +638,30 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     setup_email = ActionMailer::Base.deliveries.last
     assert_not_nil setup_email, 'Expected email after setup'
 
-    assert_equal Rails.configuration.user_notifier_email_from, setup_email.from[0]
+    assert_equal Rails.configuration.Users.UserNotifierEmailFrom, setup_email.from[0]
     assert_equal 'foo@example.com', setup_email.to[0]
-    assert_equal 'Welcome to Curoverse - shell account enabled', setup_email.subject
+    assert_equal 'Welcome to Arvados - shell account enabled', setup_email.subject
     assert (setup_email.body.to_s.include? 'Your Arvados shell account has been set up'),
         'Expected Your Arvados shell account has been set up in email body'
-    assert (setup_email.body.to_s.include? Rails.configuration.workbench_address),
-        'Expected workbench url in email body'
+    assert (setup_email.body.to_s.include? "#{Rails.configuration.Services.Workbench1.ExternalURL}users/#{created['uuid']}/virtual_machines"), 'Expected virtual machines url in email body'
+  end
+
+  test "setup inactive user by changing is_active to true" do
+    authorize_with :admin
+    active_user = users(:active)
+
+    # invoke setup with a repository
+    put :update, params: {
+          id: active_user['uuid'],
+          user: {
+            is_active: true,
+          }
+        }
+    assert_response :success
+    assert_equal active_user['uuid'], json_response['uuid']
+    updated = User.where(uuid: active_user['uuid']).first
+    assert_equal(true, updated.is_active)
+    assert_equal({read: true}, updated.group_permissions[all_users_group_uuid])
   end
 
   test "non-admin user can get basic information about readable users" do
@@ -674,7 +678,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     users = create_list :active_user, 2, join_groups: [g]
     token = create :token, user: users[0]
     authorize_with_token token
-    get :show, id: users[1].uuid
+    get :show, params: {id: users[1].uuid}
     check_non_admin_show
   end
 
@@ -687,7 +691,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
       token = create :token, user: users[0]
 
       authorize_with_token token
-      get(:index, limit: limit)
+      get(:index, params: {limit: limit})
       check_non_admin_index
       assert_equal(limit, json_response["items"].size,
                    "non-admin index limit was ineffective")
@@ -706,14 +710,14 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
 
   test "admin can filter on user.is_active" do
     authorize_with :admin
-    get(:index, filters: [["is_active", "=", "true"]])
+    get(:index, params: {filters: [["is_active", "=", "true"]]})
     assert_response :success
     check_readable_users_index [:active, :spectator], [:inactive]
   end
 
   test "admin can search where user.is_active" do
     authorize_with :admin
-    get(:index, where: {is_active: true})
+    get(:index, params: {where: {is_active: true}})
     assert_response :success
     check_readable_users_index [:active, :spectator], [:inactive]
   end
@@ -721,7 +725,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "update active_no_prefs user profile and expect notification email" do
     authorize_with :admin
 
-    put :update, {
+    put :update, params: {
       id: users(:active_no_prefs).uuid,
       user: {
         prefs: {:profile => {'organization' => 'example.com'}}
@@ -745,7 +749,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     user = {}
     user[:prefs] = users(:active_no_prefs_profile_no_getting_started_shown).prefs
     user[:prefs][:profile] = {:profile => {'organization' => 'example.com'}}
-    put :update, {
+    put :update, params: {
       id: users(:active_no_prefs_profile_no_getting_started_shown).uuid,
       user: user
     }
@@ -764,7 +768,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "update active user profile and expect no notification email" do
     authorize_with :admin
 
-    put :update, {
+    put :update, params: {
       id: users(:active).uuid,
       user: {
         prefs: {:profile => {'organization' => 'anotherexample.com'}}
@@ -792,9 +796,147 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
                     "user's writable_by should include its owner_uuid")
   end
 
+  [
+    [:admin, true],
+    [:active, false],
+  ].each do |auth_user, expect_success|
+    test "update_uuid as #{auth_user}" do
+      authorize_with auth_user
+      orig_uuid = users(:active).uuid
+      post :update_uuid, params: {
+             id: orig_uuid,
+             new_uuid: 'zbbbb-tpzed-abcde12345abcde',
+           }
+      if expect_success
+        assert_response :success
+        assert_empty User.where(uuid: orig_uuid)
+      else
+        assert_response 403
+        assert_not_empty User.where(uuid: orig_uuid)
+      end
+    end
+  end
+
+  test "refuse to merge with redirect_to_user_uuid=false (not yet supported)" do
+    authorize_with :project_viewer_trustedclient
+    post :merge, params: {
+           new_user_token: api_client_authorizations(:active_trustedclient).api_token,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: false,
+         }
+    assert_response(422)
+  end
+
+  test "refuse to merge user into self" do
+    authorize_with(:active_trustedclient)
+    post(:merge, params: {
+           new_user_token: api_client_authorizations(:active_trustedclient).api_token,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(422)
+  end
+
+  [[:active, :project_viewer_trustedclient],
+   [:active_trustedclient, :project_viewer]].each do |src, dst|
+    test "refuse to merge with untrusted token (#{src} -> #{dst})" do
+      authorize_with(src)
+      post(:merge, params: {
+             new_user_token: api_client_authorizations(dst).api_token,
+             new_owner_uuid: api_client_authorizations(dst).user.uuid,
+             redirect_to_new_user: true,
+           })
+      assert_response(403)
+    end
+  end
+
+  [[:expired_trustedclient, :project_viewer_trustedclient],
+   [:project_viewer_trustedclient, :expired_trustedclient]].each do |src, dst|
+    test "refuse to merge with expired token (#{src} -> #{dst})" do
+      authorize_with(src)
+      post(:merge, params: {
+             new_user_token: api_client_authorizations(dst).api_token,
+             new_owner_uuid: api_client_authorizations(dst).user.uuid,
+             redirect_to_new_user: true,
+           })
+      assert_response(401)
+    end
+  end
+
+  [['src', :active_trustedclient],
+   ['dst', :project_viewer_trustedclient]].each do |which_scoped, auth|
+    test "refuse to merge with scoped #{which_scoped} token" do
+      act_as_system_user do
+        api_client_authorizations(auth).update_attributes(scopes: ["GET /", "POST /", "PUT /"])
+      end
+      authorize_with(:active_trustedclient)
+      post(:merge, params: {
+             new_user_token: api_client_authorizations(:project_viewer_trustedclient).api_token,
+             new_owner_uuid: users(:project_viewer).uuid,
+             redirect_to_new_user: true,
+           })
+      assert_response(403)
+    end
+  end
+
+  test "refuse to merge if new_owner_uuid is not writable" do
+    authorize_with(:project_viewer_trustedclient)
+    post(:merge, params: {
+           new_user_token: api_client_authorizations(:active_trustedclient).api_token,
+           new_owner_uuid: groups(:anonymously_accessible_project).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(403)
+  end
+
+  test "refuse to merge if new_owner_uuid is empty" do
+    authorize_with(:project_viewer_trustedclient)
+    post(:merge, params: {
+           new_user_token: api_client_authorizations(:active_trustedclient).api_token,
+           new_owner_uuid: "",
+           redirect_to_new_user: true,
+         })
+    assert_response(422)
+  end
+
+  test "refuse to merge if new_owner_uuid is not provided" do
+    authorize_with(:project_viewer_trustedclient)
+    post(:merge, params: {
+           new_user_token: api_client_authorizations(:active_trustedclient).api_token,
+           redirect_to_new_user: true,
+         })
+    assert_response(422)
+  end
+
+  test "refuse to update redirect_to_user_uuid directly" do
+    authorize_with(:active_trustedclient)
+    patch(:update, params: {
+            id: users(:active).uuid,
+            user: {
+              redirect_to_user_uuid: users(:active).uuid,
+            },
+          })
+    assert_response(403)
+  end
+
+  test "merge 'project_viewer' account into 'active' account" do
+    authorize_with(:project_viewer_trustedclient)
+    post(:merge, params: {
+           new_user_token: api_client_authorizations(:active_trustedclient).api_token,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(:success)
+    assert_equal(users(:project_viewer).redirect_to_user_uuid, users(:active).uuid)
+
+    auth = ApiClientAuthorization.validate(token: api_client_authorizations(:project_viewer).api_token)
+    assert_not_nil(auth)
+    assert_not_nil(auth.user)
+    assert_equal(users(:active).uuid, auth.user.uuid)
+  end
 
   NON_ADMIN_USER_DATA = ["uuid", "kind", "is_active", "email", "first_name",
-                         "last_name"].sort
+                         "last_name", "username"].sort
 
   def check_non_admin_index
     assert_response :success
@@ -832,7 +974,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
 
   def check_inactive_user_findable(params={})
     inactive_user = users(:inactive)
-    get(:index, params.merge(filters: [["email", "=", inactive_user.email]]))
+    get(:index, params: params.merge(filters: [["email", "=", inactive_user.email]]))
     assert_response :success
     user_list = json_response["items"]
     assert_equal(1, user_list.andand.count)
@@ -842,15 +984,13 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
                  "admin's filtered index did not return inactive user")
   end
 
-  def verify_num_links (original_links, expected_additional_links)
-    links_now = Link.all
-    assert_equal expected_additional_links, Link.all.size-original_links.size,
-        "Expected #{expected_additional_links.inspect} more links"
+  def verify_links_added more
+    assert_equal @initial_link_count+more, Link.count,
+        "Started with #{@initial_link_count} links, expected #{more} more"
   end
 
   def find_obj_in_resp (response_items, object_type, head_kind=nil)
     return_obj = nil
-    response_items
     response_items.each { |x|
       if !x
         next