1 # Copyright 2018 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import logging 6 import os 7 import time 8 9 from commands import * 10 11 from autotest_lib.client.common_lib import error 12 from autotest_lib.client.common_lib.cros import chromedriver 13 from selenium.webdriver.common.keys import Keys 14 from autotest_lib.client.cros.graphics import graphics_utils 15 from selenium.webdriver.common.action_chains import ActionChains 16 from selenium.common.exceptions import WebDriverException 17 18 TIMEOUT_TO_COPY = 1800 # in Secs. This timeout is for files beyond 1GB 19 SEARCH_BUTTON_ID = "search-button" 20 SEARCH_BOX_CSS = "div#search-box" 21 PAPER_CONTAINTER = "paper-input-container" 22 DELETE_BUTTON_ID = "delete-button" 23 FILE_LIST_ID = "file-list" 24 LABLE_ENTRY_CSS = "span.label.entry-name" 25 CR_DIALOG_CLASS = "cr-dialog-ok" 26 USER_LOCATION = "/home/chronos/user" 27 # Using graphics_utils to simulate below keys 28 OPEN_FILES_APPLICATION_KEYS = ["KEY_RIGHTSHIFT", "KEY_LEFTALT", "KEY_M"] 29 SWITCH_TO_APP_KEY_COMBINATION = ["KEY_LEFTALT", 'KEY_TAB'] 30 SELECT_ALL_KEY_COMBINATION = ["KEY_LEFTCTRL", "KEY_A"] 31 PASTE_KEY_COMBINATION = ["KEY_LEFTCTRL", "KEY_V"] 32 GOOGLE_DRIVE = 'My Drive' 33 34 35 class files_CopyFileToGoogleDriveUI(graphics_utils.GraphicsTest): 36 37 """Copy a file from Downloads folder to Google drive""" 38 39 version = 1 40 TIME_DELAY = 5 41 _WAIT_TO_LOAD = 5 42 43 def initialize(self): 44 """Autotest initialize function""" 45 super(files_CopyFileToGoogleDriveUI, self).initialize( 46 raise_error_on_hang=True) 47 48 def cleanup(self): 49 """Autotest cleanup function""" 50 if self._GSC: 51 keyvals = self._GSC.get_memory_difference_keyvals() 52 for key, val in keyvals.iteritems(): 53 self.output_perf_value( 54 description=key, 55 value=val, 56 units='bytes', 57 higher_is_better=False) 58 self.write_perf_keyval(keyvals) 59 super(files_CopyFileToGoogleDriveUI, self).cleanup() 60 # If test fails then script will collect the screen shot to know at 61 # which instance failure occurred. 62 if not self.success: 63 graphics_utils.take_screenshot(os.path.join(self.debugdir), 64 "chrome") 65 66 def switch_to_app(self, driver, title): 67 """Switching to application using title 68 69 @param driver: chrome driver object 70 @param title: Title of the application 71 @return: True if the app is detected otherwise False 72 """ 73 windows = driver.window_handles 74 logging.debug("Windows opened: %s", windows) 75 # Checking current window initially.. 76 logging.debug("Current window is %s", driver.title) 77 if driver.title.strip().lower() == title.lower(): 78 return True 79 # Switching to all opened windows to find out the required window 80 for window in windows: 81 try: 82 logging.debug("Switching to window") 83 driver.switch_to_window(window) 84 logging.debug("Switched to window: %s", driver.title) 85 time.sleep(2) 86 if driver.title.strip().lower() == title.lower(): 87 logging.info("%s application opened!", title) 88 return True 89 except WebDriverException as we: 90 logging.debug("Webdriver exception occurred. Exception: %s", 91 str(we)) 92 except Exception as e: 93 logging.debug("Exception: %s", str(e)) 94 return False 95 96 def open_files_application(self, driver): 97 """Open and switch to files application using graphics_utils.py 98 99 @param driver: chrome driver object 100 """ 101 logging.info("Opening files application") 102 graphics_utils.press_keys(OPEN_FILES_APPLICATION_KEYS) 103 time.sleep(self._WAIT_TO_LOAD) 104 try: 105 self.switch_to_files(driver) 106 except Exception as e: 107 logging.error("Exception when switching files application.. %s", 108 str(e)) 109 logging.error("Failed to find files application. Trying again.") 110 graphics_utils.press_keys(OPEN_FILES_APPLICATION_KEYS) 111 time.sleep(self._WAIT_TO_LOAD) 112 self.switch_to_files(driver) 113 114 def switch_to_files(self, driver, title="Downloads"): 115 """Switch to files application 116 117 @param driver: chrome driver object 118 @param title: Title of the Files application 119 """ 120 logging.debug("Switching/Focus on the Files app") 121 if self.switch_to_app(driver, title): 122 logging.info("Focused on Files application") 123 graphics_utils.press_keys(SWITCH_TO_APP_KEY_COMBINATION) 124 time.sleep(1) 125 else: 126 raise error.TestFail("Failed to open on Files application") 127 128 def check_folder_opened(self, driver, title): 129 """Check the selected folder is opened or not 130 131 @param driver: chrome driver object 132 @param title: Folder name 133 @return: Returns True if expected folder is opened otherwise False 134 """ 135 logging.info("Actual files application title is %s", driver.title) 136 logging.info("Expected files application title is %s", title) 137 if driver.title == title: 138 return True 139 return False 140 141 def open_folder(self, driver, folder): 142 """Open given folder 143 144 @param driver: chrome driver object 145 @param folder: Directory name 146 """ 147 folder_webelements = driver.find_elements_by_css_selector( 148 LABLE_ENTRY_CSS) 149 for element in folder_webelements: 150 try: 151 logging.debug("Found folder name: %s", element.text.strip()) 152 if folder == element.text.strip(): 153 element.click() 154 time.sleep(3) 155 if self.check_folder_opened(driver, element.text.strip()): 156 logging.info("Folder is opened!") 157 return 158 except Exception as e: 159 logging.error("Exception when getting Files application " 160 "folders %s", str(e)) 161 raise error.TestError("Folder :%s is not opened or found", folder) 162 163 def list_files(self, driver): 164 """List files in the folder 165 166 @param driver: chrome driver object 167 @return: Returns list of files 168 """ 169 return driver.find_element_by_id( 170 FILE_LIST_ID).find_elements_by_tag_name('li') 171 172 def search_file(self, driver, file_name): 173 """Search given file in Files application 174 175 @param driver: chrome driver object 176 @param file_name: Required file 177 """ 178 driver.find_element_by_id(SEARCH_BUTTON_ID).click() 179 search_box_element = driver.find_element_by_css_selector( 180 SEARCH_BOX_CSS) 181 search_box_element.find_element_by_css_selector( 182 PAPER_CONTAINTER).find_element_by_tag_name('input').clear() 183 search_box_element.find_element_by_css_selector( 184 PAPER_CONTAINTER).find_element_by_tag_name('input').send_keys( 185 file_name) 186 187 def copy_file(self, driver, source, destination, file_name, clean=True): 188 """Copy file from one directory to another 189 190 @param driver: chrome driver object 191 @param source: Directory name from where to copy 192 @param destination: Directory name to where to copy 193 @param file_name: File to copy 194 @param clean: Cleans destination if True otherwise nothing 195 """ 196 self.open_folder(driver, source) 197 self.search_file(driver, file_name) 198 files = self.list_files(driver) 199 action_chains = ActionChains(driver) 200 201 for item in files: 202 logging.info("Selecting file to copy in %s", file_name) 203 item.click() 204 file_size = item.text.split()[1].strip() 205 file_size_units = item.text.split()[2].strip() 206 logging.debug("Select copy") 207 action_chains.move_to_element(item) \ 208 .click(item).key_down(Keys.CONTROL) \ 209 .send_keys("c") \ 210 .key_up(Keys.CONTROL) \ 211 .perform() 212 self.open_folder(driver, destination) 213 if clean: 214 drive_files = self.list_files(driver) 215 if len(drive_files) != 0: 216 logging.info("Removing existing files from %s", 217 destination) 218 drive_files[0].click() 219 logging.debug("Select all files/dirs") 220 graphics_utils.press_keys(SELECT_ALL_KEY_COMBINATION) 221 time.sleep(0.2) 222 driver.find_element_by_id(DELETE_BUTTON_ID).click() 223 driver.find_element_by_class_name(CR_DIALOG_CLASS).click() 224 time.sleep(self.TIME_DELAY) 225 logging.debug("Pressing control+v to paste the file in required " 226 "location") 227 graphics_utils.press_keys(PASTE_KEY_COMBINATION) 228 time.sleep(self.TIME_DELAY) 229 # Take dummy values initially 230 required_file_size = "0" 231 required_file_size_units = "KB" 232 required_file = None 233 # wait till the data copied 234 start_time = time.time() 235 while required_file_size != file_size and \ 236 required_file_size_units != file_size_units and \ 237 (time.time() - start_time <= TIMEOUT_TO_COPY): 238 drive_files_during_copy = self.list_files(driver) 239 if len(drive_files_during_copy) == 0: 240 raise error.TestError("File copy not started!") 241 for i_item in drive_files_during_copy: 242 if i_item.text.strip().split()[0].strip() == file_name: 243 logging.info("File found %s", i_item.text.split()[ 244 0].strip()) 245 required_file = file 246 if not required_file: 247 raise error.TestError("No such file/directory in drive, " 248 "%s", required_file) 249 logging.info(required_file.text.split()) 250 required_file_size = required_file.text.split()[1] 251 required_file_size_units = required_file.text.split()[2] 252 time.sleep(5) 253 logging.debug("%s %s data copied" % (required_file_size, 254 required_file_size_units)) 255 # Validation starts here 256 found = False 257 drive_files_after_copy = self.list_files(driver) 258 for copied_file in drive_files_after_copy: 259 logging.debug("File in destination: %s", 260 copied_file.text.strip()) 261 if copied_file.find_element_by_class_name( 262 'entry-name').text.strip() == file_name: 263 found = True 264 break 265 266 if found: 267 logging.info("Copied the file successfully!") 268 else: 269 raise error.TestFail("File not transferred successfully!") 270 271 def catch_info_or_error_messages(self, driver): 272 """Logic to catch the error 273 274 @param driver: chrome driver object 275 """ 276 errors = [] 277 try: 278 driver.find_element_by_css_selector( 279 'div.button-frame').find_element_by_class_name('open').click() 280 except Exception as e: 281 logging.info("Error in open error messages") 282 logging.info(str(e)) 283 error_elements = driver.find_elements_by_css_selector( 284 'div.progress-frame') 285 if len(error_elements) != 0: 286 for error_element in error_elements: 287 info_text = error_element.find_element_by_tag_name( 288 'label').text 289 if info_text != "": 290 errors.append(info_text) 291 return errors 292 293 def create_file(self, filename): 294 """Create a file""" 295 status, output = getstatusoutput('dd if=/dev/zero of=%s bs=%s ' 296 'count=1 iflag=fullblock' % 297 (filename, 1024)) 298 if status: 299 raise error.TestError("Failed to create file") 300 301 def run_once(self, username=None, password=None, source="Downloads", 302 file_name='test.dat'): 303 """Copy file to Google Drive in Files application 304 305 @param username: Real user(Not default autotest user) 306 @param password: Password for the user. 307 @param source: From where to copy file 308 @param file_name: File name 309 """ 310 self.success = False # Used to capture the screenshot if the TC fails 311 with chromedriver.chromedriver(username=username, 312 password=password, 313 disable_default_apps=False, 314 gaia_login=True) as cr_instance: 315 driver = cr_instance.driver 316 self.open_files_application(driver) 317 self.create_file(os.path.join(os.path.join(USER_LOCATION, 318 source), file_name)) 319 self.copy_file(driver, source, GOOGLE_DRIVE, file_name) 320 errors = self.catch_info_or_error_messages(driver) 321 if len(errors): 322 raise error.TestFail("Test failed with the following" 323 " errors. %s", errors) 324 self.success = True 325