VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py

Last change on this file was 109330, checked in by vboxsync, 5 days ago

Validation Kit/tdAddGuestCtrl.py: Show SELinux status when preparing guest -- try harder using different paths [build fix].

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 290.8 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# pylint: disable=too-many-lines
4# $Id: tdAddGuestCtrl.py 109330 2025-05-20 06:00:17Z vboxsync $
5
6"""
7VirtualBox Validation Kit - Guest Control Tests.
8"""
9
10__copyright__ = \
11"""
12Copyright (C) 2010-2024 Oracle and/or its affiliates.
13
14This file is part of VirtualBox base platform packages, as
15available from https://www.215389.xyz.
16
17This program is free software; you can redistribute it and/or
18modify it under the terms of the GNU General Public License
19as published by the Free Software Foundation, in version 3 of the
20License.
21
22This program is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25General Public License for more details.
26
27You should have received a copy of the GNU General Public License
28along with this program; if not, see <https://www.gnu.org/licenses>.
29
30The contents of this file may alternatively be used under the terms
31of the Common Development and Distribution License Version 1.0
32(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
33in the VirtualBox distribution, in which case the provisions of the
34CDDL are applicable instead of those of the GPL.
35
36You may elect to license modified versions of this file under the
37terms and conditions of either the GPL or the CDDL or both.
38
39SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
40"""
41__version__ = "$Revision: 109330 $"
42
43# Standard Python imports.
44import errno
45import os
46import random
47import string
48import struct
49import sys
50import threading
51import time
52
53# Only the main script needs to modify the path.
54try: __file__ # pylint: disable=used-before-assignment
55except: __file__ = sys.argv[0];
56g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
57sys.path.append(g_ksValidationKitDir);
58
59# Validation Kit imports.
60from testdriver import reporter;
61from testdriver import base;
62from testdriver import testfileset;
63from testdriver import vbox;
64from testdriver import vboxcon;
65from testdriver import vboxtestfileset;
66from testdriver import vboxwrappers;
67from common import utils;
68
69# Python 3 hacks:
70if sys.version_info[0] >= 3:
71 long = int # pylint: disable=redefined-builtin,invalid-name
72 xrange = range; # pylint: disable=redefined-builtin,invalid-name
73
74def limitString(sString, cLimit = 128):
75 """
76 Returns a string with ellipsis ("...") when exceeding the specified limit.
77 Useful for toning down logging. By default strings will be shortened at 128 characters.
78 """
79 if not isinstance(sString, str):
80 sString = str(sString);
81 cLen = len(sString);
82 if not cLen:
83 return '';
84 return (sString[:cLimit] + '...[%d more]' % (cLen - cLimit)) if cLen > cLimit else sString;
85
86class GuestStream(bytearray):
87 """
88 Class for handling a guest process input/output stream.
89
90 @todo write stdout/stderr tests.
91 """
92 def appendStream(self, stream, convertTo = '<b'):
93 """
94 Appends and converts a byte sequence to this object;
95 handy for displaying a guest stream.
96 """
97 self.extend(struct.pack(convertTo, stream));
98
99
100class tdCtxCreds(object):
101 """
102 Provides credentials to pass to the guest.
103 """
104 def __init__(self, sUser = None, sPassword = None, sDomain = None):
105 self.oTestVm = None;
106 self.sUser = sUser;
107 self.sPassword = sPassword;
108 self.sDomain = sDomain;
109
110 def applyDefaultsIfNotSet(self, oTestVm):
111 """
112 Applies credential defaults, based on the test VM (guest OS), if
113 no credentials were set yet.
114
115 Returns success status.
116 """
117 self.oTestVm = oTestVm;
118 if not self.oTestVm:
119 reporter.log('VM object is invalid -- did VBoxSVC or a client crash?');
120 return False;
121
122 if self.sUser is None:
123 self.sUser = self.oTestVm.getTestUser();
124
125 if self.sPassword is None:
126 self.sPassword = self.oTestVm.getTestUserPassword(self.sUser);
127
128 if self.sDomain is None:
129 self.sDomain = '';
130
131 return True;
132
133class tdTestGuestCtrlBase(object):
134 """
135 Base class for all guest control tests.
136
137 Note: This test ASSUMES that working Guest Additions
138 were installed and running on the guest to be tested.
139 """
140 def __init__(self, oCreds = None):
141 self.oGuest = None; ##< IGuest.
142 self.oTestVm = None;
143 self.oCreds = oCreds ##< type: tdCtxCreds
144 self.timeoutMS = 30 * 1000; ##< 30s timeout
145 self.oGuestSession = None; ##< IGuestSession reference or None.
146
147 def setEnvironment(self, oSession, oTxsSession, oTestVm):
148 """
149 Sets the test environment required for this test.
150
151 Returns success status.
152 """
153 _ = oTxsSession;
154
155 fRc = True;
156 try:
157 self.oGuest = oSession.o.console.guest;
158 self.oTestVm = oTestVm;
159 except:
160 fRc = reporter.errorXcpt();
161
162 if self.oCreds is None:
163 self.oCreds = tdCtxCreds();
164
165 fRc = fRc and self.oCreds.applyDefaultsIfNotSet(self.oTestVm);
166
167 if not fRc:
168 reporter.log('Error setting up Guest Control testing environment!');
169
170 return fRc;
171
172 def uploadLogData(self, oTstDrv, aData, sFileName, sDesc):
173 """
174 Uploads (binary) data to a log file for manual (later) inspection.
175 """
176 reporter.log('Creating + uploading log data file "%s"' % sFileName);
177 sHstFileName = os.path.join(oTstDrv.sScratchPath, sFileName);
178 try:
179 with open(sHstFileName, "wb") as oCurTestFile:
180 oCurTestFile.write(aData);
181 except:
182 return reporter.error('Unable to create temporary file for "%s"' % (sDesc,));
183 return reporter.addLogFile(sHstFileName, 'misc/other', sDesc);
184
185 def createSession(self, sName, fIsError = True):
186 """
187 Creates (opens) a guest session.
188 Returns (True, IGuestSession) on success or (False, None) on failure.
189 """
190 if self.oGuestSession is None:
191 if sName is None:
192 sName = "<untitled>";
193
194 reporter.log('Creating session "%s" ...' % (sName,));
195 try:
196 self.oGuestSession = self.oGuest.createSession(self.oCreds.sUser,
197 self.oCreds.sPassword,
198 self.oCreds.sDomain,
199 sName);
200 except:
201 # Just log, don't assume an error here (will be done in the main loop then).
202 reporter.maybeErrXcpt(fIsError, 'Creating a guest session "%s" failed; sUser="%s", pw="%s", sDomain="%s":'
203 % (sName, self.oCreds.sUser, self.oCreds.sPassword, self.oCreds.sDomain));
204 return (False, None);
205
206 tsStartMs = base.timestampMilli();
207 while base.timestampMilli() - tsStartMs < self.timeoutMS:
208 reporter.log('Waiting for session "%s" to start within %dms...' % (sName, self.timeoutMS));
209 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
210 try:
211 waitResult = self.oGuestSession.waitForArray(aeWaitFor, self.timeoutMS);
212
213 # Log session status changes.
214 if waitResult is vboxcon.GuestSessionWaitResult_Status:
215 reporter.log('Session "%s" indicated status change (status is now %d)' \
216 % (sName, self.oGuestSession.status));
217 if self.oGuestSession.status is vboxcon.GuestSessionStatus_Started:
218 # We indicate an error here, as we intentionally waited for the session start
219 # in the wait call above and got back a status change instead.
220 reporter.error('Session "%s" successfully started (thru status change)' % (sName,));
221 break;
222 continue; # Continue waiting for the session to start.
223
224 #
225 # Be nice to Guest Additions < 4.3: They don't support session handling and
226 # therefore return WaitFlagNotSupported.
227 #
228 if waitResult not in (vboxcon.GuestSessionWaitResult_Start, \
229 vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
230 # Just log, don't assume an error here (will be done in the main loop then).
231 reporter.maybeErr(fIsError, 'Session did not start successfully, returned wait result: %d' \
232 % (waitResult,));
233 return (False, None);
234 reporter.log('Session "%s" successfully started' % (sName,));
235
236 #
237 # Make sure that the test VM configuration and Guest Control use the same path separator style for the guest.
238 #
239 sGstSep = '\\' if self.oGuestSession.pathStyle is vboxcon.PathStyle_DOS else '/';
240 if self.oTestVm.pathSep() != sGstSep:
241 reporter.error('Configured test VM uses a different path style (%s) than Guest Control (%s)' \
242 % (self.oTestVm.pathSep(), sGstSep));
243 break;
244 except:
245 # Just log, don't assume an error here (will be done in the main loop then).
246 reporter.maybeErrXcpt(fIsError, 'Waiting for guest session "%s" (usr=%s;pw=%s;dom=%s) to start failed:'
247 % (sName, self.oCreds.sUser, self.oCreds.sPassword, self.oCreds.sDomain,));
248 return (False, None);
249 else:
250 reporter.log('Warning: Session already set; this is probably not what you want');
251 return (True, self.oGuestSession);
252
253 def setSession(self, oGuestSession):
254 """
255 Sets the current guest session and closes
256 an old one if necessary.
257 """
258 if self.oGuestSession is not None:
259 self.closeSession();
260 self.oGuestSession = oGuestSession;
261 return self.oGuestSession;
262
263 def closeSession(self, fIsError = True):
264 """
265 Closes the guest session.
266 """
267 if self.oGuestSession is not None:
268 try:
269 sName = self.oGuestSession.name;
270 except:
271 return reporter.errorXcpt();
272
273 reporter.log('Closing session "%s" ...' % (sName,));
274 try:
275 self.oGuestSession.close();
276 self.oGuestSession = None;
277 except:
278 # Just log, don't assume an error here (will be done in the main loop then).
279 reporter.maybeErrXcpt(fIsError, 'Closing guest session "%s" failed:' % (sName,));
280 return False;
281 return True;
282
283class tdTestCopyFrom(tdTestGuestCtrlBase):
284 """
285 Test for copying files from the guest to the host.
286 """
287 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None, oSrc = None):
288 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
289 self.sSrc = sSrc;
290 self.sDst = sDst;
291 self.afFlags = afFlags;
292 self.oSrc = oSrc # type: testfileset.TestFsObj
293 if oSrc and not sSrc:
294 self.sSrc = oSrc.sPath;
295
296class tdTestCopyFromDir(tdTestCopyFrom):
297
298 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None, oSrc = None, fIntoDst = False):
299 tdTestCopyFrom.__init__(self, sSrc, sDst, oCreds, afFlags, oSrc);
300 self.fIntoDst = fIntoDst; # hint to the verification code that sDst == oSrc, rather than sDst+oSrc.sNAme == oSrc.
301
302class tdTestCopyFromFile(tdTestCopyFrom):
303 pass;
304
305class tdTestRemoveHostDir(object):
306 """
307 Test step that removes a host directory tree.
308 """
309 def __init__(self, sDir):
310 self.sDir = sDir;
311
312 def execute(self, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
313 _ = oTstDrv; _ = oVmSession; _ = oTxsSession; _ = oTestVm; _ = sMsgPrefix;
314 if os.path.exists(self.sDir):
315 if base.wipeDirectory(self.sDir) != 0:
316 return False;
317 try:
318 os.rmdir(self.sDir);
319 except:
320 return reporter.errorXcpt('%s: sDir=%s' % (sMsgPrefix, self.sDir,));
321 return True;
322
323
324
325class tdTestCopyTo(tdTestGuestCtrlBase):
326 """
327 Test for copying files from the host to the guest.
328 """
329 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None):
330 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
331 self.sSrc = sSrc;
332 self.sDst = sDst;
333 self.afFlags = afFlags;
334
335class tdTestCopyToFile(tdTestCopyTo):
336 pass;
337
338class tdTestCopyToDir(tdTestCopyTo):
339 pass;
340
341class tdTestDirCreate(tdTestGuestCtrlBase):
342 """
343 Test for directoryCreate call.
344 """
345 def __init__(self, sDirectory = "", oCreds = None, fMode = 0, afFlags = None):
346 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
347 self.sDirectory = sDirectory;
348 self.fMode = fMode;
349 self.afFlags = afFlags;
350
351class tdTestDirCreateTemp(tdTestGuestCtrlBase):
352 """
353 Test for the directoryCreateTemp call.
354 """
355 def __init__(self, sDirectory = "", sTemplate = "", oCreds = None, fMode = 0, fSecure = False):
356 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
357 self.sDirectory = sDirectory;
358 self.sTemplate = sTemplate;
359 self.fMode = fMode;
360 self.fSecure = fSecure;
361
362class tdTestDirOpen(tdTestGuestCtrlBase):
363 """
364 Test for the directoryOpen call.
365 """
366 def __init__(self, sDirectory = "", oCreds = None, sFilter = "", afFlags = None):
367 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
368 self.sDirectory = sDirectory;
369 self.sFilter = sFilter;
370 self.afFlags = afFlags or [];
371
372class tdTestDirRead(tdTestDirOpen):
373 """
374 Test for the opening, reading and closing a certain directory.
375 """
376 def __init__(self, sDirectory = "", oCreds = None, sFilter = "", afFlags = None):
377 tdTestDirOpen.__init__(self, sDirectory, oCreds, sFilter, afFlags);
378
379class tdTestExec(tdTestGuestCtrlBase):
380 """
381 Specifies exactly one guest control execution test.
382 Has a default timeout of 5 minutes (for safety).
383 """
384 def __init__(self, sCmd = "", sCwd = "", asArgs = None, aEnv = None, afFlags = None, # pylint: disable=too-many-arguments
385 timeoutMS = 5 * 60 * 1000, oCreds = None, fWaitForExit = True):
386 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
387 self.sCmd = sCmd;
388 self.sCwd = sCwd;
389 self.asArgs = asArgs if asArgs is not None else [sCmd,];
390 self.aEnv = aEnv;
391 self.afFlags = afFlags or [];
392 self.timeoutMS = timeoutMS;
393 self.fWaitForExit = fWaitForExit;
394 self.uExitStatus = 0;
395 self.iExitCode = 0;
396 self.cbStdOut = 0;
397 self.cbStdErr = 0;
398 self.sBuf = '';
399
400class tdTestFileExists(tdTestGuestCtrlBase):
401 """
402 Test for the file exists API call (fileExists).
403 """
404 def __init__(self, sFile = "", oCreds = None):
405 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
406 self.sFile = sFile;
407
408class tdTestFileRemove(tdTestGuestCtrlBase):
409 """
410 Test querying guest file information.
411 """
412 def __init__(self, sFile = "", oCreds = None):
413 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
414 self.sFile = sFile;
415
416class tdTestRemoveBase(tdTestGuestCtrlBase):
417 """
418 Removal base.
419 """
420 def __init__(self, sPath, fRcExpect = True, oCreds = None):
421 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
422 self.sPath = sPath;
423 self.fRcExpect = fRcExpect;
424
425 def execute(self, oSubTstDrv):
426 """
427 Executes the test, returns True/False.
428 """
429 _ = oSubTstDrv;
430 return True;
431
432 def checkRemoved(self, sType):
433 """ Check that the object was removed using fObjExists. """
434 try:
435 fExists = self.oGuestSession.fsObjExists(self.sPath, False);
436 except:
437 return reporter.errorXcpt('fsObjExists failed on "%s" after deletion (type: %s)' % (self.sPath, sType));
438 if fExists:
439 return reporter.error('fsObjExists says "%s" still exists after deletion (type: %s)!' % (self.sPath, sType));
440 return True;
441
442class tdTestRemoveFile(tdTestRemoveBase):
443 """
444 Remove a single file.
445 """
446 def __init__(self, sPath, fRcExpect = True, oCreds = None):
447 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds);
448
449 def execute(self, oSubTstDrv):
450 reporter.log2('Deleting file "%s" ...' % (limitString(self.sPath),));
451 try:
452 if oSubTstDrv.oTstDrv.fpApiVer >= 5.0:
453 self.oGuestSession.fsObjRemove(self.sPath);
454 else:
455 self.oGuestSession.fileRemove(self.sPath);
456 except:
457 reporter.maybeErrXcpt(self.fRcExpect, 'Removing "%s" failed' % (self.sPath,));
458 return not self.fRcExpect;
459 if not self.fRcExpect:
460 return reporter.error('Expected removing "%s" to failed, but it succeeded' % (self.sPath,));
461
462 return self.checkRemoved('file');
463
464class tdTestRemoveDir(tdTestRemoveBase):
465 """
466 Remove a single directory if empty.
467 """
468 def __init__(self, sPath, fRcExpect = True, oCreds = None):
469 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds);
470
471 def execute(self, oSubTstDrv):
472 _ = oSubTstDrv;
473 reporter.log2('Deleting directory "%s" ...' % (limitString(self.sPath),));
474 try:
475 self.oGuestSession.directoryRemove(self.sPath);
476 except:
477 reporter.maybeErrXcpt(self.fRcExpect, 'Removing "%s" (as a directory) failed' % (self.sPath,));
478 return not self.fRcExpect;
479 if not self.fRcExpect:
480 return reporter.error('Expected removing "%s" (dir) to failed, but it succeeded' % (self.sPath,));
481
482 return self.checkRemoved('directory');
483
484class tdTestRemoveTree(tdTestRemoveBase):
485 """
486 Recursively remove a directory tree.
487 """
488 def __init__(self, sPath, afFlags = None, fRcExpect = True, fNotExist = False, oCreds = None):
489 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds = None);
490 self.afFlags = afFlags if afFlags is not None else [];
491 self.fNotExist = fNotExist; # Hack for the ContentOnly scenario where the dir does not exist.
492
493 def execute(self, oSubTstDrv):
494 reporter.log2('Deleting tree "%s" ...' % (limitString(self.sPath),));
495 try:
496 oProgress = self.oGuestSession.directoryRemoveRecursive(self.sPath, self.afFlags);
497 except:
498 reporter.maybeErrXcpt(self.fRcExpect, 'Removing directory tree "%s" failed (afFlags=%s)'
499 % (self.sPath, self.afFlags));
500 return not self.fRcExpect;
501
502 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, oSubTstDrv.oTstDrv.oVBoxMgr, oSubTstDrv.oTstDrv,
503 "remove-tree: %s" % (self.sPath,));
504 oWrappedProgress.wait();
505 if not oWrappedProgress.isSuccess():
506 oWrappedProgress.logResult(fIgnoreErrors = not self.fRcExpect);
507 return not self.fRcExpect;
508 if not self.fRcExpect:
509 return reporter.error('Expected removing "%s" (tree) to failed, but it succeeded' % (self.sPath,));
510
511 if vboxcon.DirectoryRemoveRecFlag_ContentAndDir not in self.afFlags and not self.fNotExist:
512 # Cannot use directoryExists here as it is buggy.
513 try:
514 if oSubTstDrv.oTstDrv.fpApiVer >= 5.0:
515 oFsObjInfo = self.oGuestSession.fsObjQueryInfo(self.sPath, False);
516 else:
517 oFsObjInfo = self.oGuestSession.fileQueryInfo(self.sPath);
518 eType = oFsObjInfo.type;
519 except:
520 return reporter.errorXcpt('sPath=%s' % (self.sPath,));
521 if eType != vboxcon.FsObjType_Directory:
522 return reporter.error('Found file type %d, expected directory (%d) for %s after rmtree/OnlyContent'
523 % (eType, vboxcon.FsObjType_Directory, self.sPath,));
524 return True;
525
526 return self.checkRemoved('tree');
527
528
529class tdTestFileStat(tdTestGuestCtrlBase):
530 """
531 Test querying guest file information.
532 """
533 def __init__(self, sFile = "", oCreds = None, cbSize = 0, eFileType = 0):
534 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
535 self.sFile = sFile;
536 self.cbSize = cbSize;
537 self.eFileType = eFileType;
538
539class tdTestFileIO(tdTestGuestCtrlBase):
540 """
541 Test for the IGuestFile object.
542 """
543 def __init__(self, sFile = "", oCreds = None):
544 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
545 self.sFile = sFile;
546
547class tdTestFileQuerySize(tdTestGuestCtrlBase):
548 """
549 Test for the file size query API call (fileQuerySize).
550 """
551 def __init__(self, sFile = "", oCreds = None):
552 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
553 self.sFile = sFile;
554
555class tdTestFileOpen(tdTestGuestCtrlBase):
556 """
557 Tests opening a guest files.
558 """
559 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None,
560 fCreationMode = 0o660, oCreds = None):
561 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
562 self.sFile = sFile;
563 self.eAccessMode = eAccessMode if eAccessMode is not None else vboxcon.FileAccessMode_ReadOnly;
564 self.eAction = eAction if eAction is not None else vboxcon.FileOpenAction_OpenExisting;
565 self.eSharing = eSharing if eSharing is not None else vboxcon.FileSharingMode_All;
566 self.fCreationMode = fCreationMode;
567 self.afOpenFlags = [];
568 self.oOpenedFile = None;
569
570 def toString(self):
571 """ Get a summary string. """
572 return 'eAccessMode=%s eAction=%s sFile=%s' % (self.eAccessMode, self.eAction, self.sFile);
573
574 def doOpenStep(self, fExpectSuccess):
575 """
576 Does the open step, putting the resulting file in oOpenedFile.
577 """
578 try:
579 self.oOpenedFile = self.oGuestSession.fileOpenEx(self.sFile, self.eAccessMode, self.eAction,
580 self.eSharing, self.fCreationMode, self.afOpenFlags);
581 except:
582 reporter.maybeErrXcpt(fExpectSuccess, 'fileOpenEx(%s, %s, %s, %s, %s, %s)'
583 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
584 self.fCreationMode, self.afOpenFlags,));
585 return False;
586 return True;
587
588 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
589 """ Overridden by children to do more testing. """
590 _ = fExpectSuccess; _ = oSubTst;
591 return True;
592
593 def doCloseStep(self):
594 """ Closes the file. """
595 if self.oOpenedFile:
596 try:
597 self.oOpenedFile.close();
598 except:
599 return reporter.errorXcpt('close([%s, %s, %s, %s, %s, %s])'
600 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
601 self.fCreationMode, self.afOpenFlags,));
602 self.oOpenedFile = None;
603 return True;
604
605 def doSteps(self, fExpectSuccess, oSubTst):
606 """ Do the tests. """
607 fRc = self.doOpenStep(fExpectSuccess);
608 if fRc is True:
609 fRc = self.doStepsOnOpenedFile(fExpectSuccess, oSubTst);
610 if self.oOpenedFile:
611 fRc = self.doCloseStep() and fRc;
612 return fRc;
613
614
615class tdTestFileOpenCheckSize(tdTestFileOpen):
616 """
617 Opens a file and checks the size.
618 """
619 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None,
620 fCreationMode = 0o660, cbOpenExpected = 0, oCreds = None):
621 tdTestFileOpen.__init__(self, sFile, eAccessMode, eAction, eSharing, fCreationMode, oCreds);
622 self.cbOpenExpected = cbOpenExpected;
623
624 def toString(self):
625 return 'cbOpenExpected=%s %s' % (self.cbOpenExpected, tdTestFileOpen.toString(self),);
626
627 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
628 #
629 # Call parent.
630 #
631 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
632
633 #
634 # Check the size. Requires 6.0 or later (E_NOTIMPL in 5.2).
635 #
636 if oSubTst.oTstDrv.fpApiVer >= 6.0:
637 try:
638 oFsObjInfo = self.oOpenedFile.queryInfo();
639 except:
640 return reporter.errorXcpt('queryInfo([%s, %s, %s, %s, %s, %s])'
641 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
642 self.fCreationMode, self.afOpenFlags,));
643 if oFsObjInfo is None:
644 return reporter.error('IGuestFile::queryInfo returned None');
645 try:
646 cbFile = oFsObjInfo.objectSize;
647 except:
648 return reporter.errorXcpt();
649 if cbFile != self.cbOpenExpected:
650 return reporter.error('Wrong file size after open (%d): %s, expected %s (file %s) (#1)'
651 % (self.eAction, cbFile, self.cbOpenExpected, self.sFile));
652
653 try:
654 cbFile = self.oOpenedFile.querySize();
655 except:
656 return reporter.errorXcpt('querySize([%s, %s, %s, %s, %s, %s])'
657 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
658 self.fCreationMode, self.afOpenFlags,));
659 if cbFile != self.cbOpenExpected:
660 return reporter.error('Wrong file size after open (%d): %s, expected %s (file %s) (#2)'
661 % (self.eAction, cbFile, self.cbOpenExpected, self.sFile));
662
663 return fRc;
664
665
666class tdTestFileOpenAndWrite(tdTestFileOpen):
667 """
668 Opens the file and writes one or more chunks to it.
669
670 The chunks are a list of tuples(offset, bytes), where offset can be None
671 if no seeking should be performed.
672 """
673 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None, # pylint: disable=too-many-arguments
674 fCreationMode = 0o660, atChunks = None, fUseAtApi = False, abContent = None, oCreds = None):
675 tdTestFileOpen.__init__(self, sFile, eAccessMode if eAccessMode is not None else vboxcon.FileAccessMode_WriteOnly,
676 eAction, eSharing, fCreationMode, oCreds);
677 assert atChunks is not None;
678 self.atChunks = atChunks # type: list(tuple(int,bytearray))
679 self.fUseAtApi = fUseAtApi;
680 self.fAppend = ( eAccessMode in (vboxcon.FileAccessMode_AppendOnly, vboxcon.FileAccessMode_AppendRead)
681 or eAction == vboxcon.FileOpenAction_AppendOrCreate);
682 self.abContent = abContent # type: bytearray
683
684 def toString(self):
685 sChunks = ', '.join('%s LB %s' % (tChunk[0], len(tChunk[1]),) for tChunk in self.atChunks);
686 sApi = 'writeAt' if self.fUseAtApi else 'write';
687 return '%s [%s] %s' % (sApi, sChunks, tdTestFileOpen.toString(self),);
688
689 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
690 #
691 # Call parent.
692 #
693 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
694
695 #
696 # Do the writing.
697 #
698 for offFile, abBuf in self.atChunks:
699 if self.fUseAtApi:
700 #
701 # writeAt:
702 #
703 assert offFile is not None;
704 reporter.log2('writeAt(%s, %s bytes)' % (offFile, len(abBuf),));
705 if self.fAppend:
706 if self.abContent is not None: # Try avoid seek as it updates the cached offset in GuestFileImpl.
707 offExpectAfter = len(self.abContent);
708 else:
709 try:
710 offSave = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
711 offExpectAfter = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_End);
712 self.oOpenedFile.seek(offSave, vboxcon.FileSeekOrigin_Begin);
713 except:
714 return reporter.errorXcpt();
715 offExpectAfter += len(abBuf);
716 else:
717 offExpectAfter = offFile + len(abBuf);
718
719 try:
720 cbWritten = self.oOpenedFile.writeAt(offFile, abBuf, 30*1000);
721 except:
722 return reporter.errorXcpt('writeAt(%s, %s bytes)' % (offFile, len(abBuf),));
723
724 else:
725 #
726 # write:
727 #
728 if self.fAppend:
729 if self.abContent is not None: # Try avoid seek as it updates the cached offset in GuestFileImpl.
730 offExpectAfter = len(self.abContent);
731 else:
732 try:
733 offSave = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
734 offExpectAfter = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_End);
735 self.oOpenedFile.seek(offSave, vboxcon.FileSeekOrigin_Begin);
736 except:
737 return reporter.errorXcpt('seek(0,End)');
738 if offFile is not None:
739 try:
740 self.oOpenedFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
741 except:
742 return reporter.errorXcpt('seek(%s,Begin)' % (offFile,));
743 else:
744 try:
745 offFile = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
746 except:
747 return reporter.errorXcpt();
748 if not self.fAppend:
749 offExpectAfter = offFile;
750 offExpectAfter += len(abBuf);
751
752 reporter.log2('write(%s bytes @ %s)' % (len(abBuf), offFile,));
753 try:
754 cbWritten = self.oOpenedFile.write(abBuf, 30*1000);
755 except:
756 return reporter.errorXcpt('write(%s bytes @ %s)' % (len(abBuf), offFile));
757
758 #
759 # Check how much was written, ASSUMING nothing we push thru here is too big:
760 #
761 if cbWritten != len(abBuf):
762 fRc = reporter.errorXcpt('Wrote less than expected: %s out of %s, expected all to be written'
763 % (cbWritten, len(abBuf),));
764 if not self.fAppend:
765 offExpectAfter -= len(abBuf) - cbWritten;
766
767 #
768 # Update the file content tracker if we've got one and can:
769 #
770 if self.abContent is not None:
771 if cbWritten < len(abBuf):
772 abBuf = abBuf[:cbWritten];
773
774 #
775 # In append mode, the current file offset shall be disregarded and the
776 # write always goes to the end of the file, regardless of writeAt or write.
777 # Note that RTFileWriteAt only naturally behaves this way on linux and
778 # (probably) windows, so VBoxService makes that behaviour generic across
779 # all OSes.
780 #
781 if self.fAppend:
782 reporter.log2('len(self.abContent)=%s + %s' % (len(self.abContent), cbWritten, ));
783 self.abContent.extend(abBuf);
784 else:
785 if offFile is None:
786 offFile = offExpectAfter - cbWritten;
787 reporter.log2('len(self.abContent)=%s + %s @ %s' % (len(self.abContent), cbWritten, offFile, ));
788 if offFile > len(self.abContent):
789 self.abContent.extend(bytearray(offFile - len(self.abContent)));
790 self.abContent[offFile:offFile + cbWritten] = abBuf;
791 reporter.log2('len(self.abContent)=%s' % (len(self.abContent),));
792
793 #
794 # Check the resulting file offset with IGuestFile::offset.
795 #
796 try:
797 offApi = self.oOpenedFile.offset; # Must be gotten first!
798 offSeek = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
799 except:
800 fRc = reporter.errorXcpt();
801 else:
802 reporter.log2('offApi=%s offSeek=%s offExpectAfter=%s' % (offApi, offSeek, offExpectAfter,));
803 if offSeek != offExpectAfter:
804 fRc = reporter.error('Seek offset is %s, expected %s after %s bytes write @ %s (offApi=%s)'
805 % (offSeek, offExpectAfter, len(abBuf), offFile, offApi,));
806 if offApi != offExpectAfter:
807 fRc = reporter.error('IGuestFile::offset is %s, expected %s after %s bytes write @ %s (offSeek=%s)'
808 % (offApi, offExpectAfter, len(abBuf), offFile, offSeek,));
809 # for each chunk - end
810 return fRc;
811
812
813class tdTestFileOpenAndCheckContent(tdTestFileOpen):
814 """
815 Opens the file and checks the content using the read API.
816 """
817 def __init__(self, sFile = "", eSharing = None, abContent = None, cbContentExpected = None, oCreds = None):
818 tdTestFileOpen.__init__(self, sFile = sFile, eSharing = eSharing, oCreds = oCreds);
819 self.abContent = abContent # type: bytearray
820 self.cbContentExpected = cbContentExpected;
821
822 def toString(self):
823 return 'check content %s (%s) %s' % (len(self.abContent), self.cbContentExpected, tdTestFileOpen.toString(self),);
824
825 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
826 #
827 # Call parent.
828 #
829 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
830
831 #
832 # Check the expected content size.
833 #
834 if self.cbContentExpected is not None:
835 if len(self.abContent) != self.cbContentExpected:
836 fRc = reporter.error('Incorrect abContent size: %s, expected %s'
837 % (len(self.abContent), self.cbContentExpected,));
838
839 #
840 # Read the file and compare it with the content.
841 #
842 offFile = 0;
843 while True:
844 try:
845 abChunk = self.oOpenedFile.read(512*1024, 30*1000);
846 except:
847 return reporter.errorXcpt('read(512KB) @ %s' % (offFile,));
848 cbChunk = len(abChunk);
849 if cbChunk == 0:
850 if offFile != len(self.abContent):
851 fRc = reporter.error('Unexpected EOF @ %s, len(abContent)=%s' % (offFile, len(self.abContent),));
852 break;
853 if offFile + cbChunk > len(self.abContent):
854 fRc = reporter.error('File is larger than expected: at least %s bytes, expected %s bytes'
855 % (offFile + cbChunk, len(self.abContent),));
856 elif not utils.areBytesEqual(abChunk, self.abContent[offFile:(offFile + cbChunk)]):
857 fRc = reporter.error('Mismatch in range %s LB %s!' % (offFile, cbChunk,));
858 offFile += cbChunk;
859
860 return fRc;
861
862
863class tdTestSession(tdTestGuestCtrlBase):
864 """
865 Test the guest session handling.
866 """
867 def __init__(self, sUser = None, sPassword = None, sDomain = None, sSessionName = ""):
868 tdTestGuestCtrlBase.__init__(self, oCreds = tdCtxCreds(sUser, sPassword, sDomain));
869 self.sSessionName = sSessionName;
870
871 def getSessionCount(self, oVBoxMgr):
872 """
873 Helper for returning the number of currently
874 opened guest sessions of a VM.
875 """
876 if self.oGuest is None:
877 return 0;
878 try:
879 aoSession = oVBoxMgr.getArray(self.oGuest, 'sessions')
880 except:
881 reporter.errorXcpt('sSessionName: %s' % (self.sSessionName,));
882 return 0;
883 return len(aoSession);
884
885
886class tdTestSessionEx(tdTestGuestCtrlBase):
887 """
888 Test the guest session.
889 """
890 def __init__(self, aoSteps = None, enmUser = None):
891 tdTestGuestCtrlBase.__init__(self);
892 assert enmUser is None; # For later.
893 self.enmUser = enmUser;
894 self.aoSteps = aoSteps if aoSteps is not None else [];
895
896 def execute(self, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
897 """
898 Executes the test.
899 """
900 #
901 # Create a session.
902 #
903 assert self.enmUser is None; # For later.
904 self.oCreds = tdCtxCreds();
905 fRc = self.setEnvironment(oVmSession, oTxsSession, oTestVm);
906 if not fRc:
907 return False;
908 reporter.log2('%s: %s steps' % (sMsgPrefix, len(self.aoSteps),));
909 fRc, oCurSession = self.createSession(sMsgPrefix);
910 if fRc is True:
911 #
912 # Execute the tests.
913 #
914 try:
915 fRc = self.executeSteps(oTstDrv, oCurSession, sMsgPrefix);
916 except:
917 fRc = reporter.errorXcpt('%s: Unexpected exception executing test steps' % (sMsgPrefix,));
918
919 #
920 # Close the session.
921 #
922 fRc2 = self.closeSession();
923 if fRc2 is False:
924 fRc = reporter.error('%s: Session could not be closed' % (sMsgPrefix,));
925 else:
926 fRc = reporter.error('%s: Session creation failed' % (sMsgPrefix,));
927 return fRc;
928
929 def executeSteps(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
930 """
931 Executes just the steps.
932 Returns True on success, False on test failure.
933 """
934 fRc = True;
935 for (i, oStep) in enumerate(self.aoSteps):
936 fRc2 = oStep.execute(oTstDrv, oGstCtrlSession, sMsgPrefix + ', step #%d' % i);
937 if fRc2 is True:
938 pass;
939 elif fRc2 is None:
940 reporter.log('%s: skipping remaining %d steps' % (sMsgPrefix, len(self.aoSteps) - i - 1,));
941 break;
942 else:
943 fRc = False;
944 return fRc;
945
946 @staticmethod
947 def executeListTestSessions(aoTests, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
948 """
949 Works thru a list of tdTestSessionEx object.
950 """
951 fRc = True;
952 for (i, oCurTest) in enumerate(aoTests):
953 try:
954 fRc2 = oCurTest.execute(oTstDrv, oVmSession, oTxsSession, oTestVm, '%s / %#d' % (sMsgPrefix, i,));
955 if fRc2 is not True:
956 fRc = False;
957 except:
958 fRc = reporter.errorXcpt('%s: Unexpected exception executing test #%d' % (sMsgPrefix, i ,));
959
960 return (fRc, oTxsSession);
961
962
963class tdSessionStepBase(object):
964 """
965 Base class for the guest control session test steps.
966 """
967
968 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
969 """
970 Executes the test step.
971
972 Returns True on success.
973 Returns False on failure (must be reported as error).
974 Returns None if to skip the remaining steps.
975 """
976 _ = oTstDrv;
977 _ = oGstCtrlSession;
978 return reporter.error('%s: Missing execute implementation: %s' % (sMsgPrefix, self,));
979
980
981class tdStepRequireMinimumApiVer(tdSessionStepBase):
982 """
983 Special test step which will cause executeSteps to skip the remaining step
984 if the VBox API is too old:
985 """
986 def __init__(self, fpMinApiVer):
987 self.fpMinApiVer = fpMinApiVer;
988
989 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
990 """ Returns None if API version is too old, otherwise True. """
991 if oTstDrv.fpApiVer >= self.fpMinApiVer:
992 return True;
993 _ = oGstCtrlSession;
994 _ = sMsgPrefix;
995 return None; # Special return value. Don't use elsewhere.
996
997
998#
999# Scheduling Environment Changes with the Guest Control Session.
1000#
1001
1002class tdStepSessionSetEnv(tdSessionStepBase):
1003 """
1004 Guest session environment: schedule putenv
1005 """
1006 def __init__(self, sVar, sValue, hrcExpected = 0):
1007 self.sVar = sVar;
1008 self.sValue = sValue;
1009 self.hrcExpected = hrcExpected;
1010
1011 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1012 """
1013 Executes the step.
1014 Returns True on success, False on test failure.
1015 """
1016 reporter.log2('tdStepSessionSetEnv: sVar=%s sValue=%s hrcExpected=%#x' % (self.sVar, self.sValue, self.hrcExpected,));
1017 try:
1018 if oTstDrv.fpApiVer >= 5.0:
1019 oGstCtrlSession.environmentScheduleSet(self.sVar, self.sValue);
1020 else:
1021 oGstCtrlSession.environmentSet(self.sVar, self.sValue);
1022 except vbox.ComException as oXcpt:
1023 # Is this an expected failure?
1024 if vbox.ComError.equal(oXcpt, self.hrcExpected):
1025 return True;
1026 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (setenv %s=%s)'
1027 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
1028 vbox.ComError.getXcptResult(oXcpt),
1029 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
1030 self.sVar, self.sValue,));
1031 except:
1032 return reporter.errorXcpt('%s: Unexpected exception in tdStepSessionSetEnv::execute (%s=%s)'
1033 % (sMsgPrefix, self.sVar, self.sValue,));
1034
1035 # Should we succeed?
1036 if self.hrcExpected != 0:
1037 return reporter.error('%s: Expected hrcExpected=%#x, got S_OK (putenv %s=%s)'
1038 % (sMsgPrefix, self.hrcExpected, self.sVar, self.sValue,));
1039 return True;
1040
1041class tdStepSessionUnsetEnv(tdSessionStepBase):
1042 """
1043 Guest session environment: schedule unset.
1044 """
1045 def __init__(self, sVar, hrcExpected = 0):
1046 self.sVar = sVar;
1047 self.hrcExpected = hrcExpected;
1048
1049 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1050 """
1051 Executes the step.
1052 Returns True on success, False on test failure.
1053 """
1054 reporter.log2('tdStepSessionUnsetEnv: sVar=%s hrcExpected=%#x' % (self.sVar, self.hrcExpected,));
1055 try:
1056 if oTstDrv.fpApiVer >= 5.0:
1057 oGstCtrlSession.environmentScheduleUnset(self.sVar);
1058 else:
1059 oGstCtrlSession.environmentUnset(self.sVar);
1060 except vbox.ComException as oXcpt:
1061 # Is this an expected failure?
1062 if vbox.ComError.equal(oXcpt, self.hrcExpected):
1063 return True;
1064 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (unsetenv %s)'
1065 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
1066 vbox.ComError.getXcptResult(oXcpt),
1067 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
1068 self.sVar,));
1069 except:
1070 return reporter.errorXcpt('%s: Unexpected exception in tdStepSessionUnsetEnv::execute (%s)'
1071 % (sMsgPrefix, self.sVar,));
1072
1073 # Should we succeed?
1074 if self.hrcExpected != 0:
1075 return reporter.error('%s: Expected hrcExpected=%#x, got S_OK (unsetenv %s)'
1076 % (sMsgPrefix, self.hrcExpected, self.sVar,));
1077 return True;
1078
1079class tdStepSessionBulkEnv(tdSessionStepBase):
1080 """
1081 Guest session environment: Bulk environment changes.
1082 """
1083 def __init__(self, asEnv = None, hrcExpected = 0):
1084 self.asEnv = asEnv if asEnv is not None else [];
1085 self.hrcExpected = hrcExpected;
1086
1087 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1088 """
1089 Executes the step.
1090 Returns True on success, False on test failure.
1091 """
1092 reporter.log2('tdStepSessionBulkEnv: asEnv=%s hrcExpected=%#x' % (self.asEnv, self.hrcExpected,));
1093 try:
1094 if oTstDrv.fpApiVer >= 5.0:
1095 oTstDrv.oVBoxMgr.setArray(oGstCtrlSession, 'environmentChanges', self.asEnv);
1096 else:
1097 oTstDrv.oVBoxMgr.setArray(oGstCtrlSession, 'environment', self.asEnv);
1098 except vbox.ComException as oXcpt:
1099 # Is this an expected failure?
1100 if vbox.ComError.equal(oXcpt, self.hrcExpected):
1101 return True;
1102 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (asEnv=%s)'
1103 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
1104 vbox.ComError.getXcptResult(oXcpt),
1105 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
1106 self.asEnv,));
1107 except:
1108 return reporter.errorXcpt('%s: Unexpected exception writing the environmentChanges property (asEnv=%s).'
1109 % (sMsgPrefix, self.asEnv));
1110 return True;
1111
1112class tdStepSessionClearEnv(tdStepSessionBulkEnv):
1113 """
1114 Guest session environment: clears the scheduled environment changes.
1115 """
1116 def __init__(self):
1117 tdStepSessionBulkEnv.__init__(self);
1118
1119
1120class tdStepSessionCheckEnv(tdSessionStepBase):
1121 """
1122 Check the currently scheduled environment changes of a guest control session.
1123 """
1124 def __init__(self, asEnv = None):
1125 self.asEnv = asEnv if asEnv is not None else [];
1126
1127 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1128 """
1129 Executes the step.
1130 Returns True on success, False on test failure.
1131 """
1132 reporter.log2('tdStepSessionCheckEnv: asEnv=%s' % (self.asEnv,));
1133
1134 #
1135 # Get the environment change list.
1136 #
1137 try:
1138 if oTstDrv.fpApiVer >= 5.0:
1139 asCurEnv = oTstDrv.oVBoxMgr.getArray(oGstCtrlSession, 'environmentChanges');
1140 else:
1141 asCurEnv = oTstDrv.oVBoxMgr.getArray(oGstCtrlSession, 'environment');
1142 except:
1143 return reporter.errorXcpt('%s: Unexpected exception reading the environmentChanges property.' % (sMsgPrefix,));
1144
1145 #
1146 # Compare it with the expected one by trying to remove each expected value
1147 # and the list anything unexpected.
1148 #
1149 fRc = True;
1150 asCopy = list(asCurEnv); # just in case asCurEnv is immutable
1151 for sExpected in self.asEnv:
1152 try:
1153 asCopy.remove(sExpected);
1154 except:
1155 fRc = reporter.error('%s: Expected "%s" to be in the resulting environment' % (sMsgPrefix, sExpected,));
1156 for sUnexpected in asCopy:
1157 fRc = reporter.error('%s: Unexpected "%s" in the resulting environment' % (sMsgPrefix, sUnexpected,));
1158
1159 if fRc is not True:
1160 reporter.log2('%s: Current environment: %s' % (sMsgPrefix, asCurEnv));
1161 return fRc;
1162
1163
1164#
1165# File system object statistics (i.e. stat()).
1166#
1167
1168class tdStepStat(tdSessionStepBase):
1169 """
1170 Stats a file system object.
1171 """
1172 def __init__(self, sPath, hrcExpected = 0, fFound = True, fFollowLinks = True, enmType = None, oTestFsObj = None):
1173 self.sPath = sPath;
1174 self.hrcExpected = hrcExpected;
1175 self.fFound = fFound;
1176 self.fFollowLinks = fFollowLinks;
1177 self.enmType = enmType if enmType is not None else vboxcon.FsObjType_File;
1178 self.cbExactSize = None;
1179 self.cbMinSize = None;
1180 self.oTestFsObj = oTestFsObj # type: testfileset.TestFsObj
1181
1182 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1183 """
1184 Execute the test step.
1185 """
1186 reporter.log2('tdStepStat: sPath=%s enmType=%s hrcExpected=%s fFound=%s fFollowLinks=%s'
1187 % (limitString(self.sPath), self.enmType, self.hrcExpected, self.fFound, self.fFollowLinks,));
1188
1189 # Don't execute non-file tests on older VBox version.
1190 if oTstDrv.fpApiVer >= 5.0 or self.enmType == vboxcon.FsObjType_File or not self.fFound:
1191 #
1192 # Call the API.
1193 #
1194 try:
1195 if oTstDrv.fpApiVer >= 5.0:
1196 oFsInfo = oGstCtrlSession.fsObjQueryInfo(self.sPath, self.fFollowLinks);
1197 else:
1198 oFsInfo = oGstCtrlSession.fileQueryInfo(self.sPath);
1199 except vbox.ComException as oXcpt:
1200 ## @todo: The error reporting in the API just plain sucks! Most of the errors are
1201 ## VBOX_E_IPRT_ERROR and there seems to be no way to distinguish between
1202 ## non-existing files/path and a lot of other errors. Fix API and test!
1203 if not self.fFound:
1204 return True;
1205 if vbox.ComError.equal(oXcpt, self.hrcExpected): # Is this an expected failure?
1206 return True;
1207 return reporter.errorXcpt('%s: Unexpected exception for exiting path "%s" (enmType=%s, hrcExpected=%s):'
1208 % (sMsgPrefix, self.sPath, self.enmType, self.hrcExpected,));
1209 except:
1210 return reporter.errorXcpt('%s: Unexpected exception in tdStepStat::execute (%s)'
1211 % (sMsgPrefix, self.sPath,));
1212 if oFsInfo is None:
1213 return reporter.error('%s: "%s" got None instead of IFsObjInfo instance!' % (sMsgPrefix, self.sPath,));
1214
1215 #
1216 # Check type expectations.
1217 #
1218 try:
1219 enmType = oFsInfo.type;
1220 except:
1221 return reporter.errorXcpt('%s: Unexpected exception in reading "IFsObjInfo::type"' % (sMsgPrefix,));
1222 if enmType != self.enmType:
1223 return reporter.error('%s: "%s" has type %s, expected %s'
1224 % (sMsgPrefix, self.sPath, enmType, self.enmType));
1225
1226 #
1227 # Check size expectations.
1228 # Note! This is unicode string here on windows, for some reason.
1229 # long long mapping perhaps?
1230 #
1231 try:
1232 cbObject = long(oFsInfo.objectSize);
1233 except:
1234 return reporter.errorXcpt('%s: Unexpected exception in reading "IFsObjInfo::objectSize"'
1235 % (sMsgPrefix,));
1236 if self.cbExactSize is not None \
1237 and cbObject != self.cbExactSize:
1238 return reporter.error('%s: "%s" has size %s bytes, expected %s bytes'
1239 % (sMsgPrefix, self.sPath, cbObject, self.cbExactSize));
1240 if self.cbMinSize is not None \
1241 and cbObject < self.cbMinSize:
1242 return reporter.error('%s: "%s" has size %s bytes, expected as least %s bytes'
1243 % (sMsgPrefix, self.sPath, cbObject, self.cbMinSize));
1244 return True;
1245
1246class tdStepStatDir(tdStepStat):
1247 """ Checks for an existing directory. """
1248 def __init__(self, sDirPath, oTestDir = None):
1249 tdStepStat.__init__(self, sPath = sDirPath, enmType = vboxcon.FsObjType_Directory, oTestFsObj = oTestDir);
1250
1251class tdStepStatDirEx(tdStepStatDir):
1252 """ Checks for an existing directory given a TestDir object. """
1253 def __init__(self, oTestDir): # type: (testfileset.TestDir)
1254 tdStepStatDir.__init__(self, oTestDir.sPath, oTestDir);
1255
1256class tdStepStatFile(tdStepStat):
1257 """ Checks for an existing file """
1258 def __init__(self, sFilePath = None, oTestFile = None):
1259 tdStepStat.__init__(self, sPath = sFilePath, enmType = vboxcon.FsObjType_File, oTestFsObj = oTestFile);
1260
1261class tdStepStatFileEx(tdStepStatFile):
1262 """ Checks for an existing file given a TestFile object. """
1263 def __init__(self, oTestFile): # type: (testfileset.TestFile)
1264 tdStepStatFile.__init__(self, oTestFile.sPath, oTestFile);
1265
1266class tdStepStatFileSize(tdStepStat):
1267 """ Checks for an existing file of a given expected size.. """
1268 def __init__(self, sFilePath, cbExactSize = 0):
1269 tdStepStat.__init__(self, sPath = sFilePath, enmType = vboxcon.FsObjType_File);
1270 self.cbExactSize = cbExactSize;
1271
1272class tdStepStatFileNotFound(tdStepStat):
1273 """ Checks for an existing directory. """
1274 def __init__(self, sPath):
1275 tdStepStat.__init__(self, sPath = sPath, fFound = False);
1276
1277class tdStepStatPathNotFound(tdStepStat):
1278 """ Checks for an existing directory. """
1279 def __init__(self, sPath):
1280 tdStepStat.__init__(self, sPath = sPath, fFound = False);
1281
1282
1283#
1284#
1285#
1286
1287class tdTestSessionFileRefs(tdTestGuestCtrlBase):
1288 """
1289 Tests session file (IGuestFile) reference counting.
1290 """
1291 def __init__(self, cRefs = 0):
1292 tdTestGuestCtrlBase.__init__(self);
1293 self.cRefs = cRefs;
1294
1295class tdTestSessionDirRefs(tdTestGuestCtrlBase):
1296 """
1297 Tests session directory (IGuestDirectory) reference counting.
1298 """
1299 def __init__(self, cRefs = 0):
1300 tdTestGuestCtrlBase.__init__(self);
1301 self.cRefs = cRefs;
1302
1303class tdTestSessionProcRefs(tdTestGuestCtrlBase):
1304 """
1305 Tests session process (IGuestProcess) reference counting.
1306 """
1307 def __init__(self, cRefs = 0):
1308 tdTestGuestCtrlBase.__init__(self);
1309 self.cRefs = cRefs;
1310
1311class tdTestUpdateAdditions(tdTestGuestCtrlBase):
1312 """
1313 Test updating the Guest Additions inside the guest.
1314 """
1315 def __init__(self, sSrc = "", asArgs = None, afFlags = None, oCreds = None):
1316 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
1317 self.sSrc = sSrc;
1318 self.asArgs = asArgs;
1319 self.afFlags = afFlags;
1320
1321class tdTestResult(object):
1322 """
1323 Base class for test results.
1324 """
1325 def __init__(self, fRc = False):
1326 ## The overall test result.
1327 self.fRc = fRc;
1328
1329class tdTestResultFailure(tdTestResult):
1330 """
1331 Base class for test results.
1332 """
1333 def __init__(self):
1334 tdTestResult.__init__(self, fRc = False);
1335
1336class tdTestResultSuccess(tdTestResult):
1337 """
1338 Base class for test results.
1339 """
1340 def __init__(self):
1341 tdTestResult.__init__(self, fRc = True);
1342
1343class tdTestResultDirRead(tdTestResult):
1344 """
1345 Test result for reading guest directories.
1346 """
1347 def __init__(self, fRc = False, cFiles = 0, cDirs = 0, cOthers = None):
1348 tdTestResult.__init__(self, fRc = fRc);
1349 self.cFiles = cFiles;
1350 self.cDirs = cDirs;
1351 self.cOthers = cOthers;
1352
1353class tdTestResultExec(tdTestResult):
1354 """
1355 Holds a guest process execution test result,
1356 including the exit code, status + afFlags.
1357 """
1358 def __init__(self, fRc = False, uExitStatus = 500, iExitCode = 0, sBuf = None, cbBuf = 0, cbStdOut = None, cbStdErr = None):
1359 tdTestResult.__init__(self);
1360 ## The overall test result.
1361 self.fRc = fRc;
1362 ## Process exit stuff.
1363 self.uExitStatus = uExitStatus;
1364 self.iExitCode = iExitCode;
1365 ## Desired buffer length returned back from stdout/stderr.
1366 self.cbBuf = cbBuf;
1367 ## Desired buffer result from stdout/stderr. Use with caution!
1368 self.sBuf = sBuf;
1369 self.cbStdOut = cbStdOut;
1370 self.cbStdErr = cbStdErr;
1371
1372class tdTestResultFileStat(tdTestResult):
1373 """
1374 Test result for stat'ing guest files.
1375 """
1376 def __init__(self, fRc = False,
1377 cbSize = 0, eFileType = 0):
1378 tdTestResult.__init__(self, fRc = fRc);
1379 self.cbSize = cbSize;
1380 self.eFileType = eFileType;
1381 ## @todo Add more information.
1382
1383class tdTestResultFileReadWrite(tdTestResult):
1384 """
1385 Test result for reading + writing guest directories.
1386 """
1387 def __init__(self, fRc = False,
1388 cbProcessed = 0, offFile = 0, abBuf = None):
1389 tdTestResult.__init__(self, fRc = fRc);
1390 self.cbProcessed = cbProcessed;
1391 self.offFile = offFile;
1392 self.abBuf = abBuf;
1393
1394class tdTestResultSession(tdTestResult):
1395 """
1396 Test result for guest session counts.
1397 """
1398 def __init__(self, fRc = False, cNumSessions = 0):
1399 tdTestResult.__init__(self, fRc = fRc);
1400 self.cNumSessions = cNumSessions;
1401
1402class tdDebugSettings(object):
1403 """
1404 Contains local test debug settings.
1405 """
1406 def __init__(self, sVBoxServiceExeHst = None):
1407 self.sVBoxServiceExeHst = sVBoxServiceExeHst;
1408 self.sGstVBoxServiceLogPath = '';
1409
1410class SubTstDrvAddGuestCtrl(base.SubTestDriverBase):
1411 """
1412 Sub-test driver for executing guest control (VBoxService, IGuest) tests.
1413 """
1414
1415 def __init__(self, oTstDrv):
1416 base.SubTestDriverBase.__init__(self, oTstDrv, 'add-guest-ctrl', 'Guest Control');
1417
1418 ## @todo base.TestBase.
1419 self.asTestsDef = [
1420 'debug',
1421 'session_basic', 'session_env', 'session_file_ref', 'session_dir_ref', 'session_proc_ref', 'session_reboot',
1422 'exec_basic', 'exec_timeout',
1423 'dir_create', 'dir_create_temp', 'dir_read',
1424 'file_open', 'file_remove', 'file_stat', 'file_read', 'file_write',
1425 'copy_to', 'copy_from',
1426 'update_additions',
1427 '3d'
1428 ];
1429
1430 # Possible paths for the Guest Control Helper binary.
1431 self.asGstCtlHelperPaths = [
1432 # Debugging stuff (SCP'd over to the guest).
1433 '/tmp/VBoxGuestControlHelper',
1434 'C:\\Temp\\VBoxGuestControlHelper',
1435 # Validation Kit .ISO.
1436 '${CDROM}/vboxvalidationkit/${OS/ARCH}/VBoxGuestControlHelper${EXESUFF}',
1437 '${CDROM}/${OS/ARCH}/VBoxGuestControlHelper${EXESUFF}',
1438 # Test VMs.
1439 '/opt/apps/VBoxGuestControlHelper',
1440 '/opt/apps/VBoxGuestControlHelper',
1441 '/apps/VBoxGuestControlHelper',
1442 'C:\\Apps\\VBoxGuestControlHelper${EXESUFF}'
1443 ];
1444 # Full path to the Guest Control Helper binary we're going to use. Only gets resolved once.
1445 self.sGstCtlHelperExe = '';
1446
1447 self.asTests = self.asTestsDef;
1448 self.fSkipKnownBugs = False;
1449 self.oTestFiles = None # type: vboxtestfileset.TestFileSet
1450 self.oDebug = tdDebugSettings();
1451 self.sPathVBoxServiceExeGst = '';
1452 self.tpAdditionsVer = ();
1453
1454 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
1455 if asArgs[iArg] == '--add-guest-ctrl-tests':
1456 iArg += 1;
1457 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1458 if asArgs[iArg] == 'all': # Nice for debugging scripts.
1459 self.asTests = self.asTestsDef;
1460 else:
1461 self.asTests = asArgs[iArg].split(':');
1462 for s in self.asTests:
1463 if s not in self.asTestsDef:
1464 raise base.InvalidOption('The "--add-guest-ctrl-tests" value "%s" is not valid; valid values are: %s'
1465 % (s, ' '.join(self.asTestsDef)));
1466 return iNext;
1467 if asArgs[iArg] == '--add-guest-ctrl-skip-known-bugs':
1468 self.fSkipKnownBugs = True;
1469 return iArg + 1;
1470 if asArgs[iArg] == '--no-add-guest-ctrl-skip-known-bugs':
1471 self.fSkipKnownBugs = False;
1472 return iArg + 1;
1473 if asArgs[iArg] == '--add-guest-ctrl-debug-img':
1474 iArg += 1;
1475 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1476 self.oDebug.sVBoxServiceExeHst = asArgs[iArg];
1477 return iNext;
1478 return iArg;
1479
1480 def showUsage(self):
1481 base.SubTestDriverBase.showUsage(self);
1482 reporter.log(' --add-guest-ctrl-tests <s1[:s2[:]]>');
1483 reporter.log(' Default: %s (all)' % (':'.join(self.asTestsDef)));
1484 reporter.log(' --add-guest-ctrl-skip-known-bugs');
1485 reporter.log(' Skips known bugs. Default: --no-add-guest-ctrl-skip-known-bugs');
1486 reporter.log('Debugging:');
1487 reporter.log(' --add-guest-ctrl-debug-img');
1488 reporter.log(' Sets VBoxService image to deploy for debugging');
1489 return True;
1490
1491 def testIt(self, oTestVm, oSession, oTxsSession):
1492 """
1493 Executes the test.
1494
1495 Returns fRc, oTxsSession. The latter may have changed.
1496 """
1497
1498 self.sPathVBoxServiceExeGst = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm), 'VBoxService') \
1499 + base.exeSuff();
1500
1501 # For some tests we need know the Guest Additions version, so fetch it now.
1502 self.tpAdditionsVer = self.oTstDrv.getGuestAdditionsVersion(oSession);
1503
1504 reporter.log("Active tests: %s" % (self.asTests,));
1505
1506 # The tests. Must-succeed tests should be first.
1507 atTests = [
1508 ( True, self.prepareGuestForDebugging, None, 'Manual Debugging',),
1509 ( True, self.prepareGuestForTesting, None, 'Preparations',),
1510 ( True, self.testGuestCtrlSession, 'session_basic', 'Session Basics',),
1511 ( True, self.testGuestCtrlExec, 'exec_basic', 'Execution',),
1512 ( False, self.testGuestCtrlExecTimeout, 'exec_timeout', 'Execution Timeouts',),
1513 ( False, self.testGuestCtrlSessionEnvironment, 'session_env', 'Session Environment',),
1514 ( False, self.testGuestCtrlSessionFileRefs, 'session_file_ref', 'Session File References',),
1515 #( False, self.testGuestCtrlSessionDirRefs, 'session_dir_ref', 'Session Directory References',),
1516 ( False, self.testGuestCtrlSessionProcRefs, 'session_proc_ref', 'Session Process References',),
1517 ( False, self.testGuestCtrlDirCreate, 'dir_create', 'Creating directories',),
1518 ( False, self.testGuestCtrlDirCreateTemp, 'dir_create_temp', 'Creating temporary directories',),
1519 ( False, self.testGuestCtrlDirRead, 'dir_read', 'Reading directories',),
1520 ( False, self.testGuestCtrlCopyTo, 'copy_to', 'Copy to guest',),
1521 ( False, self.testGuestCtrlCopyFrom, 'copy_from', 'Copy from guest',),
1522 ( False, self.testGuestCtrlFileStat, 'file_stat', 'Querying file information (stat)',),
1523 ( False, self.testGuestCtrlFileOpen, 'file_open', 'File open',),
1524 ( False, self.testGuestCtrlFileRead, 'file_read', 'File read',),
1525 ( False, self.testGuestCtrlFileWrite, 'file_write', 'File write',),
1526 ( False, self.testGuestCtrlFileRemove, 'file_remove', 'Removing files',), # Destroys prepped files.
1527 ( False, self.testGuestCtrlUpdateAdditions, 'update_additions', 'Updating Guest Additions',),
1528 # @todo r=aeichner Only enable it again when this really works,
1529 # the 3D tests should probably live in a separate file
1530 # ( False, self.testGuestCtrl3D, '3d', '3D acceleration',),
1531 ];
1532
1533 if not self.fSkipKnownBugs:
1534 atTests.extend([
1535 # @todo Seems to (mainly?) fail on Linux guests, primarily running with systemd as service supervisor.
1536 # Needs to be investigated and fixed.
1537 ( False, self.testGuestCtrlSessionReboot, 'session_reboot', 'Session w/ Guest Reboot',), # May zap /tmp.
1538 ]);
1539
1540 fRc = True;
1541 for fMustSucceed, fnHandler, sShortNm, sTestNm in atTests:
1542
1543 # If for whatever reason the VM object became invalid, bail out.
1544 if not oTestVm:
1545 reporter.error('Test VM object invalid (VBoxSVC or client process crashed?), aborting tests');
1546 fRc = False;
1547 break;
1548
1549 reporter.testStart(sTestNm);
1550 if sShortNm is None or sShortNm in self.asTests:
1551 # Returns (fRc, oTxsSession, oSession) - but only the first one is mandatory.
1552 aoResult = fnHandler(oSession, oTxsSession, oTestVm);
1553 if aoResult is None or isinstance(aoResult, bool):
1554 fRcTest = aoResult;
1555 else:
1556 fRcTest = aoResult[0];
1557 if len(aoResult) > 1:
1558 oTxsSession = aoResult[1];
1559 if len(aoResult) > 2:
1560 oSession = aoResult[2];
1561 assert len(aoResult) == 3;
1562 else:
1563 fRcTest = None;
1564
1565 if fRcTest is False and reporter.testErrorCount() == 0:
1566 fRcTest = reporter.error('Buggy test! Returned False w/o logging the error!');
1567 if reporter.testDone(fRcTest is None)[1] != 0:
1568 fRcTest = False;
1569 fRc = False;
1570
1571 # Stop execution if this is a must-succeed test and it failed.
1572 if fRcTest is False and fMustSucceed is True:
1573 reporter.log('Skipping any remaining tests since the previous one failed.');
1574 break;
1575
1576 # Upload VBoxService logs on failure.
1577 if reporter.testErrorCount() > 0 \
1578 and self.oDebug.sGstVBoxServiceLogPath:
1579 sVBoxServiceLogsTarGz = 'ga-vboxservice-logs-%s.tar.gz' % oTestVm.sVmName;
1580 sGstVBoxServiceLogsTarGz = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), sVBoxServiceLogsTarGz);
1581 if self.oTstDrv.txsPackFile(oSession, oTxsSession, \
1582 sGstVBoxServiceLogsTarGz, self.oDebug.sGstVBoxServiceLogPath, fIgnoreErrors = True):
1583 self.oTstDrv.txsDownloadFiles(oSession, oTxsSession, [ (sGstVBoxServiceLogsTarGz, sVBoxServiceLogsTarGz) ], \
1584 fIgnoreErrors = True);
1585
1586 return (fRc, oTxsSession);
1587
1588 def prepareGuestForDebugging(self, oSession, oTxsSession, oTestVm): # pylint: disable=unused-argument
1589 """
1590 Prepares a guest for (manual) debugging.
1591
1592 This involves copying over and invoking a the locally built VBoxService binary.
1593 """
1594
1595 if self.oDebug.sVBoxServiceExeHst is None: # If no debugging enabled, bail out.
1596 reporter.log('Skipping debugging');
1597 return True;
1598
1599 reporter.log('Preparing for debugging ...');
1600
1601 try:
1602 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1603
1604 self.oTstDrv.sleep(5); # Fudge factor -- wait until the service stopped.
1605
1606 reporter.log('Uploading "%s" to "%s" ...' % (self.oDebug.sVBoxServiceExeHst, self.sPathVBoxServiceExeGst));
1607 oTxsSession.syncUploadFile(self.oDebug.sVBoxServiceExeHst, self.sPathVBoxServiceExeGst);
1608
1609 if oTestVm.isLinux():
1610 oTxsSession.syncChMod(self.sPathVBoxServiceExeGst, 0o755);
1611
1612 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1613
1614 self.oTstDrv.sleep(5); # Fudge factor -- wait until the service is ready.
1615
1616 except:
1617 return reporter.errorXcpt('Unable to prepare for debugging');
1618
1619 return True;
1620
1621 def locateGstBinary(self, oTxsSession, asPaths):
1622 """
1623 Locates a guest binary on the guest by checking the paths in \a asPaths.
1624
1625 Returns a tuple (success, path).
1626 """
1627 for sCurPath in asPaths:
1628 reporter.log2('Checking for \"%s\" ...' % (sCurPath));
1629 if oTxsSession.syncIsFile(sCurPath, fIgnoreErrors = True):
1630 return (True, oTxsSession.syncExpandString(sCurPath));
1631 reporter.error('Unable to find guest binary in any of these places:\n%s' % ('\n'.join(asPaths),));
1632 return (False, "");
1633
1634 #
1635 # VBoxService handling.
1636 #
1637 def vboxServiceControl(self, oTxsSession, oTestVm, fStart):
1638 """
1639 Controls VBoxService on the guest by starting or stopping the service.
1640 Returns success indicator.
1641 """
1642
1643 fRc = True;
1644
1645 if oTestVm.isWindows():
1646 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'sc.exe');
1647 if oTestVm.sKind in ('WindowsNT3x', 'WindowsNT4', 'Windows2000',): # W2K too?
1648 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'net.exe');
1649 if fStart is True:
1650 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Starting VBoxService', 30 * 1000,
1651 sPathSC, (sPathSC, 'start', 'VBoxService'));
1652 else:
1653 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Stopping VBoxService', 30 * 1000,
1654 sPathSC, (sPathSC, 'stop', 'VBoxService'));
1655 elif oTestVm.isLinux():
1656 sPathService = "/sbin/rcvboxadd-service";
1657 if fStart is True:
1658 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Starting VBoxService', 30 * 1000,
1659 sPathService, (sPathService, 'start'));
1660 else:
1661 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Stopping VBoxService', 30 * 1000,
1662 sPathService, (sPathService, 'stop'));
1663 else:
1664 reporter.log('Controlling VBoxService not supported for this guest yet');
1665
1666 return fRc;
1667
1668 def waitForGuestFacility(self, oSession, eFacilityType, sDesc,
1669 eFacilityStatus, cMsTimeout = 30 * 1000):
1670 """
1671 Waits for a guest facility to enter a certain status.
1672 By default the "Active" status is being used.
1673
1674 Returns success status.
1675 """
1676
1677 reporter.log('Waiting for Guest Additions facility "%s" to change to status %s (%dms timeout)...'
1678 % (sDesc, str(eFacilityStatus), cMsTimeout));
1679
1680 fRc = False;
1681
1682 eStatusOld = None;
1683 tsStart = base.timestampMilli();
1684 while base.timestampMilli() - tsStart < cMsTimeout:
1685 try:
1686 eStatus, _ = oSession.o.console.guest.getFacilityStatus(eFacilityType);
1687 reporter.log('Current status is %s' % (str(eStatus)));
1688 if eStatusOld is None:
1689 eStatusOld = eStatus;
1690 except:
1691 reporter.errorXcpt('Getting facility status failed');
1692 break;
1693 if eStatus != eStatusOld:
1694 reporter.log('Status changed to %s' % (str(eStatus)));
1695 eStatusOld = eStatus;
1696 if eStatus == eFacilityStatus:
1697 fRc = True;
1698 break;
1699 self.oTstDrv.sleep(5); # Do some busy waiting.
1700
1701 if not fRc:
1702 reporter.error('Waiting for Guest Additions facility "%s" timed out' % (sDesc));
1703 else:
1704 reporter.log('Guest Additions facility "%s" reached requested status %s after %dms'
1705 % (sDesc, str(eFacilityStatus), base.timestampMilli() - tsStart));
1706
1707 return fRc;
1708
1709 #
1710 # Guest test files.
1711 #
1712
1713 def prepareGuestForTesting(self, oSession, oTxsSession, oTestVm):
1714 """
1715 Prepares the VM for testing, uploading a bunch of files and stuff via TXS.
1716 Returns success indicator.
1717 """
1718 _ = oSession;
1719
1720 #
1721 # Make sure the temporary directory exists.
1722 #
1723 for sDir in [self.oTstDrv.getGuestTempDir(oTestVm), ]:
1724 if oTxsSession.syncMkDirPath(sDir, 0o777) is not True:
1725 return reporter.error('Failed to create directory "%s"!' % (sDir,));
1726
1727 # Query the TestExecService (TXS) version first to find out on what we run.
1728 fGotTxsVer = self.oTstDrv.txsVer(oSession, oTxsSession, 30 * 100, fIgnoreErrors = True);
1729
1730 # Whether to enable verbose logging for VBoxService.
1731 fEnableVerboseLogging = False;
1732
1733 # On Windows and Linux guests we always can (try to) enable verbose logging.
1734 if (oTestVm.isWindows() or oTestVm.isLinux()):
1735 fEnableVerboseLogging = True;
1736
1737 # Old TxS versions had a bug which caused an infinite loop when executing stuff containing "$xxx",
1738 # so check if we got the version here first and skip enabling verbose logging nonetheless if needed.
1739 if not fGotTxsVer:
1740 reporter.log('Too old TxS service running')
1741 fEnableVerboseLogging = False;
1742
1743 self.oDebug.sGstVBoxServiceLogPath = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), "VBoxService");
1744 sPathLogFile = oTestVm.pathJoin(self.oDebug.sGstVBoxServiceLogPath, 'VBoxService.log');
1745
1746 if oTestVm.isWindows():
1747 sImagePath = '%s -vvvv --logfile %s' % (self.sPathVBoxServiceExeGst, sPathLogFile);
1748 # For newer revisions we use VBoxGuestInstallHelper.exe. Should work on all Windows versions.
1749 if self.oTstDrv.fpApiVer >= 7.0 \
1750 and self.oTstDrv.getGuestAdditionsRevision(oSession) >= 166162:
1751 sRegEditorExeBasePath = 'C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\';
1752 if self.oTstDrv.fpApiVer >= 7.2 \
1753 and self.oTstDrv.getGuestAdditionsRevision(oSession) >= 168202:
1754 sRegEditorExePath = sRegEditorExeBasePath + 'Tools\\VBoxGuestInstallHelper.exe';
1755 else:
1756 sRegEditorExePath = sRegEditorExeBasePath + 'VBoxGuestInstallHelper.exe';
1757 asRegEditorArgs = [ sRegEditorExePath, 'registry', 'write', 'HKLM',
1758 'SYSTEM\\CurrentControlSet\\Services\\VBoxService', 'ImagePath', 'REG_SZ',
1759 sImagePath ];
1760 # reg.exe is not able to write keys on older Windows versions (NT4, 2k).
1761 elif oTestVm.sKind not in ('WindowsNT4', 'Windows2000',):
1762 sRegEditorExePath = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'reg.exe');
1763 asRegEditorArgs = [ sRegEditorExePath, 'add', 'HKLM\\SYSTEM\\CurrentControlSet\\Services\\VBoxService',
1764 '/v', 'ImagePath', '/t', 'REG_SZ', '/d', sImagePath, '/f' ];
1765 else:
1766 reporter.log('VBoxService logging is not available on this Windows guest');
1767 fEnableVerboseLogging = False;
1768
1769 # Some older Linux test VMs (like tst-rhel5) don't have a pre-configured 'vbox' user.
1770 # So make sure that this user exists and has the appropriate password set. Ignore any errors.
1771 elif oTestVm.isLinux():
1772 sCmdUserAdd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr'), 'useradd');
1773 asArgs = [ sCmdUserAdd, '-m', 'vbox' ];
1774 self.oTstDrv.txsRunTest(oTxsSession, sCmdUserAdd, 5 * 60 * 1000, sCmdUserAdd, asArgs,
1775 fCheckSessionStatus = False);
1776 # We must supply the password in an encrypted form using chpasswd (via stdin).
1777 sCmdChPasswd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr'), 'chpasswd');
1778 asArgs = [ sCmdChPasswd ];
1779 self.oTstDrv.txsRunTestStdIn(oTxsSession, sCmdChPasswd, 5 * 60 * 1000, sCmdChPasswd, asArgs,
1780 sStdIn = 'vbox:password\n', fIgnoreErrors = True);
1781 # Show SELinux status (might not be available everywhere, so check for binary first).
1782 asCmdSELinuxSts = [
1783 oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr'), 'sestatus'),
1784 oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr/local'), 'sestatus'),
1785 ];
1786 fSELinuxFound = False;
1787 for sCmdSELinuxSts in asCmdSELinuxSts:
1788 fSELinuxFound = self.oTstDrv.txsIsFile(oSession, oTxsSession, sCmdSELinuxSts, fIgnoreErrors = True);
1789 if fSELinuxFound:
1790 reporter.log('SELinux found:');
1791 asArgs = [ sCmdSELinuxSts ];
1792 self.oTstDrv.txsRunTest(oTxsSession, sCmdSELinuxSts, 5 * 60 * 1000, sCmdSELinuxSts, asArgs,
1793 fCheckSessionStatus = False);
1794 break;
1795 if not fSELinuxFound:
1796 reporter.log('SELinux not found');
1797 #
1798 # Enable VBoxService verbose logging.
1799 #
1800 reporter.log('Enabling verbose VBoxService logging: %s' % (fEnableVerboseLogging));
1801 if fEnableVerboseLogging:
1802 if oTxsSession.syncMkDirPath(self.oDebug.sGstVBoxServiceLogPath, 0o777) is not True:
1803 return reporter.error('Failed to create directory "%s"!' % (self.oDebug.sGstVBoxServiceLogPath,));
1804 reporter.log('VBoxService logs will be stored in "%s"' % (self.oDebug.sGstVBoxServiceLogPath,));
1805
1806 fRestartVBoxService = False;
1807
1808 if oTestVm.isWindows():
1809 asArgs = [ sRegEditorExePath ] + asRegEditorArgs;
1810 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging (via registry)',
1811 30 * 1000,
1812 sRegEditorExePath, asRegEditorArgs);
1813 elif oTestVm.isLinux():
1814 # Need to use some stupid trickery here to locate the sed binary,
1815 # as this might differ on various Linux hosts, sigh. We also could use 'which' or some sort on the guest.
1816 # Note: Sorted by likeliness.
1817 asSedPaths = [
1818 '/bin/sed',
1819 '/usr/bin/sed',
1820 '/usr/local/bin/sed'
1821 ];
1822 fRc, sPathSed = self.locateGstBinary(oTxsSession, asSedPaths);
1823 if fRc:
1824 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging', 30 * 1000,
1825 sPathSed,
1826 (sPathSed, '-i', '-e', 's/'
1827 '\\$2 \\$3'
1828 '/'
1829 '\\$2 \\$3 -vvvv --logfile \\/var\\/tmp\\/VBoxService\\/VBoxService.log'
1830 '/g',
1831 '/sbin/rcvboxadd-service'));
1832 else:
1833 reporter.log('Verbose logging for VBoxService not supported for this guest yet');
1834
1835 if fRestartVBoxService:
1836 # Wait for VBoxService to start up properly so, we can shut it down again and restart.
1837 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1838 vboxcon.AdditionsFacilityStatus_Active);
1839 if not fRc:
1840 reporter.log('VBoxService didn\'t startup in time');
1841 return False;
1842
1843 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1844 self.oTstDrv.sleep(5);
1845 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1846
1847 # Wait for VBoxService to start up in any case.
1848 reporter.testStart('Waiting for VBoxService to get started');
1849 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1850 vboxcon.AdditionsFacilityStatus_Active);
1851 reporter.testDone();
1852 if not fRc:
1853 return False;
1854
1855 #
1856 # Generate and upload some random files and dirs to the guest.
1857 # Note! Make sure we don't run into too-long-path issues when using
1858 # the test files on the host if.
1859 #
1860 cchGst = len(self.oTstDrv.getGuestTempDir(oTestVm)) + 1 + len('addgst-1') + 1;
1861 cchHst = len(self.oTstDrv.sScratchPath) + 1 + len('copyto/addgst-1') + 1;
1862 cchMaxPath = 230;
1863 if cchHst > cchGst:
1864 cchMaxPath -= cchHst - cchGst;
1865 reporter.log('cchMaxPath=%s (cchHst=%s, cchGst=%s)' % (cchMaxPath, cchHst, cchGst,));
1866 self.oTestFiles = vboxtestfileset.TestFileSet(oTestVm,
1867 self.oTstDrv.getGuestTempDir(oTestVm), 'addgst-1',
1868 # Make sure that we use a lowest common denominator across all supported
1869 # platforms, to make testing the randomly generated file paths work
1870 # reliably.
1871 cchMaxPath = cchMaxPath, asCompatibleWith = [ ('cross') ]);
1872 return self.oTestFiles.upload(oTxsSession, self.oTstDrv);
1873
1874
1875 #
1876 # gctrlXxxx stuff.
1877 #
1878
1879 def gctrlCopyFileFrom(self, oGuestSession, oTest, fExpected):
1880 """
1881 Helper function to copy a single file from the guest to the host.
1882 """
1883
1884 # As we pass-in randomly generated file names, the source sometimes can be empty, which
1885 # in turn will result in a (correct) error by the API. Simply skip this function then.
1886 if not oTest.sSrc:
1887 reporter.log2('Skipping guest file "%s"' % (limitString(oTest.sSrc)));
1888 return fExpected;
1889
1890 #
1891 # Do the copying.
1892 #
1893 reporter.log2('Copying guest file "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1894 try:
1895 if self.oTstDrv.fpApiVer >= 5.0:
1896 oCurProgress = oGuestSession.fileCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1897 else:
1898 oCurProgress = oGuestSession.copyFrom(oTest.sSrc, oTest.sDst, oTest.afFlags);
1899 except:
1900 reporter.maybeErrXcpt(fExpected, 'Copy from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1901 return False;
1902 if oCurProgress is None:
1903 return reporter.error('No progress object returned');
1904 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlFileCopyFrom");
1905 oProgress.wait();
1906 if not oProgress.isSuccess():
1907 oProgress.logResult(fIgnoreErrors = not fExpected);
1908 return False;
1909
1910 #
1911 # Check the result if we can.
1912 #
1913 if oTest.oSrc:
1914 assert isinstance(oTest.oSrc, testfileset.TestFile);
1915 sDst = oTest.sDst;
1916 if os.path.isdir(sDst):
1917 sDst = os.path.join(sDst, oTest.oSrc.sName);
1918 try:
1919 oFile = open(sDst, 'rb'); # pylint: disable=consider-using-with
1920 except:
1921 # Don't report expected non-existing paths / files as an error.
1922 return reporter.maybeErrXcpt(fExpected, 'open(%s) failed during verfication (file / path not found)' % (sDst,));
1923 fEqual = oTest.oSrc.equalFile(oFile);
1924 oFile.close();
1925 if not fEqual:
1926 return reporter.error('Content differs for "%s"' % (sDst,));
1927
1928 return True;
1929
1930 def __compareTestDir(self, oDir, sHostPath): # type: (testfileset.TestDir, str) -> bool
1931 """
1932 Recursively compare the content of oDir and sHostPath.
1933
1934 Returns True on success, False + error logging on failure.
1935
1936 Note! This ASSUMES that nothing else was copied to sHostPath!
1937 """
1938 #
1939 # First check out all the entries and files in the directory.
1940 #
1941 dLeftUpper = dict(oDir.dChildrenUpper);
1942 try:
1943 asEntries = os.listdir(sHostPath);
1944 except:
1945 return reporter.errorXcpt('os.listdir(%s) failed' % (sHostPath,));
1946
1947 fRc = True;
1948 for sEntry in asEntries:
1949 sEntryUpper = sEntry.upper();
1950 if sEntryUpper not in dLeftUpper:
1951 fRc = reporter.error('Unexpected entry "%s" in "%s"' % (sEntry, sHostPath,));
1952 else:
1953 oFsObj = dLeftUpper[sEntryUpper];
1954 del dLeftUpper[sEntryUpper];
1955
1956 if isinstance(oFsObj, testfileset.TestFile):
1957 sFilePath = os.path.join(sHostPath, oFsObj.sName);
1958 try:
1959 oFile = open(sFilePath, 'rb'); # pylint: disable=consider-using-with
1960 except:
1961 fRc = reporter.errorXcpt('open(%s) failed during verfication' % (sFilePath,));
1962 else:
1963 fEqual = oFsObj.equalFile(oFile);
1964 oFile.close();
1965 if not fEqual:
1966 fRc = reporter.error('Content differs for "%s"' % (sFilePath,));
1967
1968 # List missing entries:
1969 for sKey in dLeftUpper:
1970 oEntry = dLeftUpper[sKey];
1971 fRc = reporter.error('%s: Missing %s "%s" (src path: %s)'
1972 % (sHostPath, oEntry.sName,
1973 'file' if isinstance(oEntry, testfileset.TestFile) else 'directory', oEntry.sPath));
1974
1975 #
1976 # Recurse into subdirectories.
1977 #
1978 for oFsObj in oDir.aoChildren:
1979 if isinstance(oFsObj, testfileset.TestDir):
1980 fRc = self.__compareTestDir(oFsObj, os.path.join(sHostPath, oFsObj.sName)) and fRc;
1981 return fRc;
1982
1983 def gctrlCopyDirFrom(self, oGuestSession, oTest, fExpected):
1984 """
1985 Helper function to copy a directory from the guest to the host.
1986 """
1987
1988 # As we pass-in randomly generated directories, the source sometimes can be empty, which
1989 # in turn will result in a (correct) error by the API. Simply skip this function then.
1990 if not oTest.sSrc:
1991 reporter.log2('Skipping guest dir "%s"' % (limitString(oTest.sSrc)));
1992 return fExpected;
1993
1994 #
1995 # Do the copying.
1996 #
1997 reporter.log2('Copying guest dir "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1998 try:
1999 if self.oTstDrv.fpApiVer >= 7.0:
2000 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
2001 if not oTest.afFlags:
2002 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
2003 elif vboxcon.DirectoryCopyFlag_Recursive not in oTest.afFlags:
2004 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
2005 ## @todo Ditto.
2006 if not oTest.afFlags:
2007 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_FollowLinks, ];
2008 elif vboxcon.DirectoryCopyFlag_FollowLinks not in oTest.afFlags:
2009 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
2010 oCurProgress = oGuestSession.directoryCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
2011 except:
2012 reporter.maybeErrXcpt(fExpected, 'Copy dir from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
2013 return False;
2014 if oCurProgress is None:
2015 return reporter.error('No progress object returned');
2016
2017 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlDirCopyFrom");
2018 oProgress.wait();
2019 if not oProgress.isSuccess():
2020 oProgress.logResult(fIgnoreErrors = not fExpected);
2021 return False;
2022
2023 #
2024 # Check the result if we can.
2025 #
2026 if oTest.oSrc:
2027 assert isinstance(oTest.oSrc, testfileset.TestDir);
2028 sDst = oTest.sDst;
2029 if oTest.fIntoDst:
2030 return self.__compareTestDir(oTest.oSrc, os.path.join(sDst, oTest.oSrc.sName));
2031 oDummy = testfileset.TestDir(None, 'dummy');
2032 oDummy.aoChildren = [oTest.oSrc,]
2033 oDummy.dChildrenUpper = { oTest.oSrc.sName.upper(): oTest.oSrc, };
2034 return self.__compareTestDir(oDummy, sDst);
2035 return True;
2036
2037 def gctrlCopyFileTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
2038 """
2039 Helper function to copy a single file from the host to the guest.
2040
2041 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
2042 """
2043 reporter.log2('Copying host file "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
2044 try:
2045 if self.oTstDrv.fpApiVer >= 5.0:
2046 oCurProgress = oGuestSession.fileCopyToGuest(sSrc, sDst, afFlags);
2047 else:
2048 oCurProgress = oGuestSession.copyTo(sSrc, sDst, afFlags);
2049 except:
2050 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
2051 return False;
2052
2053 if oCurProgress is None:
2054 return reporter.error('No progress object returned');
2055 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
2056
2057 try:
2058 oProgress.wait();
2059 if not oProgress.isSuccess():
2060 oProgress.logResult(fIgnoreErrors = not fIsError);
2061 return False;
2062 except:
2063 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
2064 return False;
2065 return True;
2066
2067 def gctrlCopyDirTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
2068 """
2069 Helper function to copy a directory (tree) from the host to the guest.
2070
2071 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
2072 """
2073 reporter.log2('Copying host directory "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
2074 try:
2075 if self.oTstDrv.fpApiVer >= 7.0:
2076 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
2077 if not afFlags:
2078 afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
2079 elif vboxcon.DirectoryCopyFlag_Recursive not in afFlags:
2080 afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
2081 ## @todo Ditto.
2082 if not afFlags:
2083 afFlags = [vboxcon.DirectoryCopyFlag_FollowLinks,];
2084 elif vboxcon.DirectoryCopyFlag_FollowLinks not in afFlags:
2085 afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
2086 oCurProgress = oGuestSession.directoryCopyToGuest(sSrc, sDst, afFlags);
2087 except:
2088 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
2089 return False;
2090
2091 if oCurProgress is None:
2092 return reporter.error('No progress object returned');
2093 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
2094
2095 try:
2096 oProgress.wait();
2097 if not oProgress.isSuccess():
2098 oProgress.logResult(fIgnoreErrors = not fIsError);
2099 return False;
2100 except:
2101 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
2102 return False;
2103 return True;
2104
2105 def gctrlCreateDir(self, oTest, oRes, oGuestSession):
2106 """
2107 Helper function to create a guest directory specified in the current test.
2108 """
2109 reporter.log2('Creating directory "%s"' % (limitString(oTest.sDirectory),));
2110 try:
2111 oGuestSession.directoryCreate(oTest.sDirectory, oTest.fMode, oTest.afFlags);
2112 except:
2113 reporter.maybeErrXcpt(oRes.fRc, 'Failed to create "%s" fMode=%o afFlags=%s'
2114 % (oTest.sDirectory, oTest.fMode, oTest.afFlags,));
2115 return not oRes.fRc;
2116 if oRes.fRc is not True:
2117 return reporter.error('Did not expect to create directory "%s"!' % (oTest.sDirectory,));
2118
2119 # Check if the directory now exists.
2120 try:
2121 if self.oTstDrv.fpApiVer >= 5.0:
2122 fDirExists = oGuestSession.directoryExists(oTest.sDirectory, False);
2123 else:
2124 fDirExists = oGuestSession.directoryExists(oTest.sDirectory);
2125 except:
2126 return reporter.errorXcpt('directoryExists failed on "%s"!' % (oTest.sDirectory,));
2127 if not fDirExists:
2128 return reporter.errorXcpt('directoryExists returned False on "%s" after directoryCreate succeeded!'
2129 % (oTest.sDirectory,));
2130 return True;
2131
2132 def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, fUseDirList = False, cEntriesPerRead = 0, sSubDir = None):
2133 """
2134 Helper function to recursively read a guest directory tree specified in the current test.
2135 """
2136 sDir = oTest.sDirectory;
2137 sFilter = oTest.sFilter;
2138 afFlags = oTest.afFlags;
2139 oTestVm = oTest.oCreds.oTestVm;
2140 sCurDir = oTestVm.pathJoin(sDir, sSubDir) if sSubDir else sDir;
2141
2142 fRc = True; # Be optimistic.
2143 cDirs = 0; # Number of directories read.
2144 cFiles = 0; # Number of files read.
2145 cOthers = 0; # Other files.
2146
2147 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2148 aFsObjInfo = [];
2149
2150 # Open the directory:
2151 reporter.log2('Directory="%s", filter="%s", afFlags="%s", fUseDirList=%s, cEntriesPerRead=%d'
2152 % (limitString(sCurDir), sFilter, afFlags, fUseDirList, cEntriesPerRead));
2153 try:
2154 oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
2155 except:
2156 reporter.maybeErrXcpt(fIsError, 'sCurDir=%s sFilter=%s afFlags=%s' % (sCurDir, sFilter, afFlags,))
2157 return (False, 0, 0, 0);
2158
2159 # Read the directory.
2160 fDone = False;
2161 while fRc is True:
2162 reporter.log3('Reading next batch ...');
2163 aFsObjInfo = [];
2164 try:
2165 if not fUseDirList:
2166 aFsObjInfo.append(oCurDir.read());
2167 else:
2168 if not cEntriesToRead:
2169 cEntriesToRead = random.randrange(1, 32768);
2170 aFsObjInfo = oCurDir.list(cEntriesToRead);
2171 except Exception as oXcpt:
2172 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2173 if fUseDirList:
2174 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % (sCurDir, cEntriesToRead));
2175 else:
2176 if self.oTstDrv.fpApiVer > 5.2:
2177 reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
2178 else:
2179 # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
2180 reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
2181 fRc = False;
2182 else:
2183 reporter.log2('\tNo more directory entries for "%s"' % (limitString(sCurDir),));
2184 fDone = True;
2185 break;
2186
2187 if fDone or not fRc: # Abort reading?
2188 break;
2189
2190 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2191 for oFsObjInfo in aFsObjInfo:
2192 try:
2193 sName = oFsObjInfo.name;
2194 eType = oFsObjInfo.type;
2195 except:
2196 fRc = reporter.errorXcpt();
2197 break;
2198
2199 if sName in ('.', '..', ):
2200 if eType != vboxcon.FsObjType_Directory:
2201 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2202 % (sName, eType, vboxcon.FsObjType_Directory));
2203 elif eType == vboxcon.FsObjType_Directory:
2204 reporter.log2(' Directory "%s"' % limitString(oFsObjInfo.name));
2205 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
2206 fUseDirList, cEntriesPerRead,
2207 oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
2208 fRc = aSubResult[0];
2209 cDirs += aSubResult[1] + 1;
2210 cFiles += aSubResult[2];
2211 cOthers += aSubResult[3];
2212 elif eType is vboxcon.FsObjType_File:
2213 reporter.log4(' File "%s"' % oFsObjInfo.name);
2214 cFiles += 1;
2215 elif eType is vboxcon.FsObjType_Symlink:
2216 reporter.log4(' Symlink "%s" -- not tested yet' % oFsObjInfo.name);
2217 cOthers += 1;
2218 elif oTestVm.isWindows() \
2219 or oTestVm.isOS2() \
2220 or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
2221 vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
2222 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
2223 (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
2224 else:
2225 cOthers += 1;
2226
2227 # Close the directory
2228 try:
2229 oCurDir.close();
2230 except:
2231 fRc = reporter.errorXcpt('sCurDir=%s' % (sCurDir));
2232
2233 return (fRc, cDirs, cFiles, cOthers);
2234
2235 def gctrlReadDirTree2(self, oGuestSession, oDir, fUseDirList = False, cEntriesPerRead = 0):
2236 # type: (testfileset.TestDir) -> bool
2237 """
2238 Helper function to recursively read a guest directory tree specified in the current test.
2239 """
2240
2241 #
2242 # Process the directory.
2243 #
2244
2245 # Open the directory:
2246 try:
2247 oCurDir = oGuestSession.directoryOpen(oDir.sPath, '', None);
2248 except:
2249 return reporter.errorXcpt('sPath=%s' % (oDir.sPath,));
2250
2251 # Read the directory.
2252 dLeftUpper = dict(oDir.dChildrenUpper);
2253 cDot = 0;
2254 cDotDot = 0;
2255 fRc = True;
2256 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2257 aFsObjInfo = [];
2258 while True:
2259 reporter.log3('Reading next batch ...');
2260 aFsObjInfo = [];
2261 try:
2262 if not fUseDirList:
2263 aFsObjInfo.append(oCurDir.read());
2264 else:
2265 if not cEntriesToRead:
2266 cEntriesToRead = random.randrange(1, 32768);
2267 aFsObjInfo = oCurDir.list(cEntriesToRead);
2268 except Exception as oXcpt:
2269 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2270 if fUseDirList:
2271 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % \
2272 (oDir.sPath, cEntriesToRead));
2273 else:
2274 fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath));
2275 else:
2276 reporter.log2('\tNo more directory entries for "%s"' % (limitString(oDir.sPath),));
2277 break;
2278
2279 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2280 for oFsObjInfo in aFsObjInfo:
2281 try:
2282 sName = oFsObjInfo.name;
2283 eType = oFsObjInfo.type;
2284 cbFile = oFsObjInfo.objectSize;
2285 ## @todo check further attributes.
2286 except:
2287 fRc = reporter.errorXcpt();
2288 break;
2289
2290 # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
2291 if sName in ('.', '..', ):
2292 if eType != vboxcon.FsObjType_Directory:
2293 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2294 % (sName, eType, vboxcon.FsObjType_Directory));
2295 if sName == '.': cDot += 1;
2296 else: cDotDot += 1;
2297 else:
2298 # Find the child and remove it from the dictionary.
2299 sNameUpper = sName.upper();
2300 oFsObj = dLeftUpper.get(sNameUpper);
2301 if oFsObj is None:
2302 fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
2303 % (sName, oDir.sPath, eType, cbFile,));
2304 else:
2305 del dLeftUpper[sNameUpper];
2306
2307 # Check type
2308 if isinstance(oFsObj, testfileset.TestDir):
2309 if eType != vboxcon.FsObjType_Directory:
2310 fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
2311 % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
2312 elif isinstance(oFsObj, testfileset.TestFile):
2313 if eType != vboxcon.FsObjType_File:
2314 fRc = reporter.error('%s: expected file (%d), got eType=%d!'
2315 % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
2316 else:
2317 fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
2318
2319 # Check the name.
2320 if oFsObj.sName != sName:
2321 fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % \
2322 (oFsObj.sPath, oFsObj.sName, sName,));
2323
2324 # Check the size if a file.
2325 if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
2326 fRc = reporter.error('%s: expected size %s, got %s instead!' % \
2327 (oFsObj.sPath, oFsObj.cbContent, cbFile,));
2328
2329 ## @todo check timestamps and attributes.
2330
2331 # Close the directory
2332 try:
2333 oCurDir.close();
2334 except:
2335 fRc = reporter.errorXcpt('oDir.sPath=%s' % (oDir.sPath,));
2336
2337 # Any files left over?
2338 for sKey in dLeftUpper:
2339 oFsObj = dLeftUpper[sKey];
2340 fRc = reporter.error('%s: Was not returned! (%s)' % (oFsObj.sPath, type(oFsObj),));
2341
2342 # Check the dot and dot-dot counts.
2343 if cDot != 1:
2344 fRc = reporter.error('%s: Found %s "." entries, expected exactly 1!' % (oDir.sPath, cDot,));
2345 if cDotDot != 1:
2346 fRc = reporter.error('%s: Found %s ".." entries, expected exactly 1!' % (oDir.sPath, cDotDot,));
2347
2348 #
2349 # Recurse into subdirectories using info from oDir.
2350 #
2351 for oFsObj in oDir.aoChildren:
2352 if isinstance(oFsObj, testfileset.TestDir):
2353 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj, fUseDirList, cEntriesPerRead) and fRc;
2354
2355 return fRc;
2356
2357 def gctrlExecDoTest(self, i, oTest, oRes, oGuestSession):
2358 """
2359 Wrapper function around gctrlExecute to provide more sanity checking
2360 when needed in actual execution tests.
2361 """
2362 reporter.log('Testing #%d, cmd="%s" ...' % (i, oTest.sCmd));
2363 fRcExec = self.gctrlExecute(oTest, oGuestSession, oRes.fRc);
2364 if fRcExec == oRes.fRc:
2365 fRc = True;
2366 if fRcExec is True:
2367 # Compare exit status / code on successful process execution.
2368 if oTest.uExitStatus != oRes.uExitStatus \
2369 or oTest.iExitCode != oRes.iExitCode:
2370 fRc = reporter.error('Test #%d (%s) failed: Got exit status + code %d,%d, expected %d,%d'
2371 % (i, oTest.asArgs, oTest.uExitStatus, oTest.iExitCode,
2372 oRes.uExitStatus, oRes.iExitCode));
2373
2374 # Compare test / result buffers on successful process execution.
2375 if oTest.sBuf is not None and oRes.sBuf is not None:
2376 if not utils.areBytesEqual(oTest.sBuf, oRes.sBuf):
2377 fRc = reporter.error('Test #%d (%s) failed: Got buffer\n%s (%d bytes), expected\n%s (%d bytes)'
2378 % (i, oTest.asArgs,
2379 map(hex, map(ord, oTest.sBuf)), len(oTest.sBuf),
2380 map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf)));
2381 reporter.log2('Test #%d passed: Buffers match (%d bytes)' % (i, len(oRes.sBuf)));
2382 elif oRes.sBuf and not oTest.sBuf:
2383 fRc = reporter.error('Test #%d (%s) failed: Got no buffer data, expected\n%s (%dbytes)' %
2384 (i, oTest.asArgs, map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf),));
2385
2386 if oRes.cbStdOut is not None and oRes.cbStdOut != oTest.cbStdOut:
2387 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stdout data, expected %d'
2388 % (i, oTest.asArgs, oTest.cbStdOut, oRes.cbStdOut));
2389 if oRes.cbStdErr is not None and oRes.cbStdErr != oTest.cbStdErr:
2390 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stderr data, expected %d'
2391 % (i, oTest.asArgs, oTest.cbStdErr, oRes.cbStdErr));
2392 else:
2393 fRc = reporter.error('Test #%d (%s) failed: Got %s, expected %s' % (i, oTest.asArgs, fRcExec, oRes.fRc));
2394 return fRc;
2395
2396 def processCreateWrapper(self, oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS):
2397 """
2398 Wrapepr function to deal with different flavors of the IGuestProcess::processCreate call,
2399 depending on the API version.
2400
2401 Returns oProcess object on success, None on failure.
2402 """
2403 oProcess = None;
2404
2405 reporter.log2('Executing sCmd=%s, cCwd=%s, afFlags=%s, timeoutMS=%d, asArgs=%s, asEnv=%s'
2406 % (sCmd, sCwd, afFlags, timeoutMS, limitString(asArgs), limitString(aEnv),));
2407
2408 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485:
2409 # 7.1 adds a current working directory parameter.
2410 oProcess = oGuestSession.processCreate(sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS);
2411 else:
2412 oProcess = oGuestSession.processCreate(sCmd,
2413 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2414 aEnv, afFlags, timeoutMS);
2415 return oProcess;
2416
2417 def processExecute(self, oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS, fIsError = True):
2418 """
2419 Executes a process on the guest and deals with input/output + waiting flags.
2420
2421 Returns tuple (success, exit status, exit code, stdout len, stderr len, stdout / stderr output).
2422 """
2423
2424 #
2425 # Start the process:
2426 #
2427 try:
2428 oProcess = self.processCreateWrapper(oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS);
2429 except:
2430 reporter.maybeErrXcpt(fIsError, 'type=%s, asArgs=%s' % (type(asArgs), asArgs,));
2431 return (False, vboxcon.ProcessStatus_Undefined, 0, 0, 0, '');
2432 if oProcess is None:
2433 reporter.error('oProcess is None! (%s)' % (asArgs,));
2434 return (False, vboxcon.ProcessStatus_Undefined, 0, 0, 0, '');
2435
2436 fRc = True;
2437 uExitStatus = vboxcon.ProcessStatus_Undefined;
2438 iExitCode = -1;
2439 cbStdOut = 0;
2440 cbStdErr = 0;
2441 sBufOut = '';
2442
2443 #time.sleep(5); # try this if you want to see races here.
2444
2445 # Wait for the process to start properly:
2446 reporter.log2('Process start requested, waiting for start (%dms) ...' % (timeoutMS,));
2447 iPid = -1;
2448 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Start, ];
2449 try:
2450 eWaitResult = oProcess.waitForArray(aeWaitFor, timeoutMS);
2451 except:
2452 reporter.maybeErrXcpt(fIsError, 'waitforArray failed for asArgs=%s' % (asArgs,));
2453 fRc = False;
2454 else:
2455 try:
2456 eStatus = oProcess.status;
2457 iPid = oProcess.PID;
2458 except:
2459 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2460 else:
2461 reporter.log2('Wait result returned: %d, current process status is: %d' % (eWaitResult, eStatus,));
2462
2463 #
2464 # Wait for the process to run to completion if necessary.
2465 #
2466 # Note! The above eWaitResult return value can be ignored as it will
2467 # (mostly) reflect the process status anyway.
2468 #
2469 if eStatus == vboxcon.ProcessStatus_Started:
2470
2471 # What to wait for:
2472 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, ];
2473 if vboxcon.ProcessCreateFlag_WaitForStdOut in afFlags:
2474 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdOut);
2475 if vboxcon.ProcessCreateFlag_WaitForStdErr in afFlags:
2476 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdErr);
2477 ## @todo Add vboxcon.ProcessWaitForFlag_StdIn.
2478
2479 reporter.log2('Process (PID %d) started, waiting for termination (%dms), aeWaitFor=%s ...'
2480 % (iPid, timeoutMS, aeWaitFor));
2481 acbFdOut = [0,0,0];
2482 while True:
2483 try:
2484 eWaitResult = oProcess.waitForArray(aeWaitFor, timeoutMS);
2485 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2486 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2487 try: oProcess.close();
2488 except: pass;
2489 break;
2490 except:
2491 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2492 break;
2493 #reporter.log2('Wait returned: %d' % (eWaitResult,));
2494
2495 # Process output:
2496 for eFdResult, iFd, sFdNm in [ (vboxcon.ProcessWaitResult_StdOut, 1, 'stdout'),
2497 (vboxcon.ProcessWaitResult_StdErr, 2, 'stderr'), ]:
2498 if eWaitResult in (eFdResult, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2499 try:
2500 abBuf = oProcess.read(iFd, 64 * 1024, timeoutMS);
2501 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2502 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2503 try: oProcess.close();
2504 except: pass;
2505 except:
2506 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (asArgs,));
2507 else:
2508 if abBuf:
2509 reporter.log2('Process (PID %d) got %d bytes of %s data (type: %s)'
2510 % (iPid, len(abBuf), sFdNm, type(abBuf)));
2511 if reporter.getVerbosity() >= 4:
2512 sBufOut = '';
2513 if sys.version_info >= (2, 7):
2514 if isinstance(abBuf, memoryview): ## @todo Why is this happening?
2515 abBuf = abBuf.tobytes();
2516 sBufOut = abBuf.decode("utf-8");
2517 if sys.version_info <= (2, 7):
2518 if isinstance(abBuf, buffer): # (for 3.0+) pylint: disable=undefined-variable
2519 sBufOut = str(abBuf);
2520 for sLine in sBufOut.splitlines():
2521 reporter.log4('%s: %s' % (sFdNm, sLine));
2522 acbFdOut[iFd] += len(abBuf);
2523 sBufOut = abBuf; ## @todo Figure out how to uniform + append!
2524
2525 ## Process input (todo):
2526 #if eWaitResult in (vboxcon.ProcessWaitResult_StdIn, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2527 # reporter.log2('Process (PID %d) needs stdin data' % (iPid,));
2528
2529 # Termination or error?
2530 if eWaitResult in (vboxcon.ProcessWaitResult_Terminate,
2531 vboxcon.ProcessWaitResult_Error,
2532 vboxcon.ProcessWaitResult_Timeout,):
2533 try: eStatus = oProcess.status;
2534 except: fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2535 reporter.log2('Process (PID %d) reported terminate/error/timeout: %d, status: %d'
2536 % (iPid, eWaitResult, eStatus,));
2537 break;
2538
2539 # End of the wait loop.
2540 _, cbStdOut, cbStdErr = acbFdOut;
2541
2542 try: eStatus = oProcess.status;
2543 except: fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2544 reporter.log2('Final process status (PID %d) is: %d' % (iPid, eStatus));
2545 reporter.log2('Process (PID %d) %d stdout, %d stderr' % (iPid, cbStdOut, cbStdErr));
2546
2547 #
2548 # Get the final status and exit code of the process.
2549 #
2550 try:
2551 uExitStatus = oProcess.status;
2552 iExitCode = oProcess.exitCode;
2553 except:
2554 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2555 reporter.log2('Process (PID %d) has exit code: %d; status: %d ' % (iPid, iExitCode, uExitStatus));
2556 return (fRc, uExitStatus, iExitCode, cbStdOut, cbStdErr, sBufOut);
2557
2558 def gctrlExecute(self, oTest, oGuestSession, fIsError): # pylint: disable=too-many-statements
2559 """
2560 Helper function to execute a program on a guest, specified in the current test.
2561
2562 Note! This weirdo returns results (process exitcode and status) in oTest.
2563 """
2564 fRc = True; # Be optimistic.
2565
2566 # Reset the weird result stuff:
2567 oTest.cbStdOut = 0;
2568 oTest.cbStdErr = 0;
2569 oTest.sBuf = '';
2570 oTest.uExitStatus = 0;
2571 oTest.iExitCode = 0;
2572
2573 ## @todo Compare execution timeouts!
2574 #tsStart = base.timestampMilli();
2575
2576 try:
2577 reporter.log2('Using session user=%s, sDomain=%s, name=%s, timeout=%d'
2578 % (oGuestSession.user, oGuestSession.domain, oGuestSession.name, oGuestSession.timeout,));
2579 except:
2580 return reporter.errorXcpt();
2581
2582 fRc, oTest.uExitStatus, oTest.iExitCode, oTest.cbStdOut, oTest.cbStdErr, oTest.sBuf = \
2583 self.processExecute(oGuestSession, oTest.sCmd, oTest.asArgs, oTest.sCwd, \
2584 oTest.aEnv, oTest.afFlags, oTest.timeoutMS, fIsError);
2585
2586 return fRc;
2587
2588 def executeGstCtlHelper(self, oTxsSession, oGuestSession, asArgs, asEnv = None, sCwd = '', timeoutMS = 30 * 1000):
2589 """
2590 Wrapper to invoke the Guest Control Helper on the guest.
2591
2592 Returns tuple (success, exit status, exit code, stdout len, stderr len, stdout / stderr output).
2593 """
2594 fRc = True;
2595 eExitStatus = vboxcon.ProcessStatus_Undefined;
2596 iExitCode = -1;
2597 cbStdOut = 0;
2598 cbStdErr = 0;
2599 sBuf = '';
2600
2601 if not self.sGstCtlHelperExe:
2602 fRc, self.sGstCtlHelperExe = self.locateGstBinary(oTxsSession, self.asGstCtlHelperPaths);
2603 if fRc:
2604 reporter.log('Using VBoxGuestControlHelper on guest at \"%s\"' % (self.sGstCtlHelperExe));
2605
2606 if fRc \
2607 and self.sGstCtlHelperExe:
2608 try:
2609 asArgs2 = [ self.sGstCtlHelperExe ]; # Always set argv0.
2610 asArgs2.extend(asArgs); # Add the arguments passed-in.
2611 if not asEnv:
2612 asEnv = [];
2613 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, \
2614 vboxcon.ProcessWaitForFlag_StdOut, \
2615 vboxcon.ProcessWaitForFlag_StdErr ];
2616
2617 fRc, eExitStatus, iExitCode, cbStdOut, cbStdErr, sBuf = \
2618 self.processExecute(oGuestSession, self.sGstCtlHelperExe, asArgs2, sCwd, \
2619 asEnv, aeWaitFor, timeoutMS);
2620 if eExitStatus != vboxcon.ProcessStatus_TerminatedNormally:
2621 reporter.log('VBoxGuestControlHelper failed to run; got exit status %d' % (eExitStatus,));
2622 fRc = False;
2623 except:
2624 fRc = reporter.errorXcpt();
2625
2626 return (fRc, eExitStatus, iExitCode, cbStdOut, cbStdErr, sBuf);
2627
2628 def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2629 """
2630 Tests the guest session environment changes.
2631 """
2632 aoTests = [
2633 # Check basic operations.
2634 tdTestSessionEx([ # Initial environment is empty.
2635 tdStepSessionCheckEnv(),
2636 # Check clearing empty env.
2637 tdStepSessionClearEnv(),
2638 tdStepSessionCheckEnv(),
2639 # Check set.
2640 tdStepSessionSetEnv('FOO', 'BAR'),
2641 tdStepSessionCheckEnv(['FOO=BAR',]),
2642 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2643 tdStepSessionClearEnv(),
2644 tdStepSessionCheckEnv(),
2645 # Check unset.
2646 tdStepSessionUnsetEnv('BAR'),
2647 tdStepSessionCheckEnv(['BAR']),
2648 tdStepSessionClearEnv(),
2649 tdStepSessionCheckEnv(),
2650 # Set + unset.
2651 tdStepSessionSetEnv('FOO', 'BAR'),
2652 tdStepSessionCheckEnv(['FOO=BAR',]),
2653 tdStepSessionUnsetEnv('FOO'),
2654 tdStepSessionCheckEnv(['FOO']),
2655 # Bulk environment changes (via attrib) (shall replace existing 'FOO').
2656 tdStepSessionBulkEnv( ['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2657 tdStepSessionCheckEnv(['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2658 ]),
2659 tdTestSessionEx([ # Check that setting the same value several times works.
2660 tdStepSessionSetEnv('FOO','BAR'),
2661 tdStepSessionCheckEnv([ 'FOO=BAR',]),
2662 tdStepSessionSetEnv('FOO','BAR2'),
2663 tdStepSessionCheckEnv([ 'FOO=BAR2',]),
2664 tdStepSessionSetEnv('FOO','BAR3'),
2665 tdStepSessionCheckEnv([ 'FOO=BAR3',]),
2666 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2667 # Add a little unsetting to the mix.
2668 tdStepSessionSetEnv('BAR', 'BEAR'),
2669 tdStepSessionCheckEnv([ 'FOO=BAR3', 'BAR=BEAR',]),
2670 tdStepSessionUnsetEnv('FOO'),
2671 tdStepSessionCheckEnv([ 'FOO', 'BAR=BEAR',]),
2672 tdStepSessionSetEnv('FOO','BAR4'),
2673 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR',]),
2674 # The environment is case sensitive.
2675 tdStepSessionSetEnv('foo','BAR5'),
2676 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo=BAR5']),
2677 tdStepSessionUnsetEnv('foo'),
2678 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo']),
2679 ]),
2680 tdTestSessionEx([ # Bulk settings merges stuff, last entry standing.
2681 tdStepSessionBulkEnv(['FOO=bar', 'foo=bar', 'FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2682 tdStepSessionCheckEnv(['FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2683 tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2684 tdStepSessionBulkEnv(['2=1+1', 'FOO=doofus2', ]),
2685 tdStepSessionCheckEnv(['2=1+1', 'FOO=doofus2' ]),
2686 ]),
2687 # Invalid variable names.
2688 tdTestSessionEx([
2689 tdStepSessionSetEnv('', 'FOO', vbox.ComError.E_INVALIDARG),
2690 tdStepSessionCheckEnv(),
2691 tdStepRequireMinimumApiVer(5.0), # 4.3 is too relaxed checking input!
2692 tdStepSessionBulkEnv(['', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2693 tdStepSessionCheckEnv(),
2694 tdStepSessionSetEnv('FOO=', 'BAR', vbox.ComError.E_INVALIDARG),
2695 tdStepSessionCheckEnv(),
2696 ]),
2697 # A bit more weird keys/values.
2698 tdTestSessionEx([ tdStepSessionSetEnv('$$$', ''),
2699 tdStepSessionCheckEnv([ '$$$=',]), ]),
2700 tdTestSessionEx([ tdStepSessionSetEnv('$$$', '%%%'),
2701 tdStepSessionCheckEnv([ '$$$=%%%',]),
2702 ]),
2703 tdTestSessionEx([ tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2704 tdStepSessionSetEnv(u'ß$%ß&', ''),
2705 tdStepSessionCheckEnv([ u'ß$%ß&=',]),
2706 ]),
2707 # Misc stuff.
2708 tdTestSessionEx([ tdStepSessionSetEnv('FOO', ''),
2709 tdStepSessionCheckEnv(['FOO=',]),
2710 ]),
2711 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2712 tdStepSessionCheckEnv(['FOO=BAR',])
2713 ],),
2714 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2715 tdStepSessionSetEnv('BAR', 'BAZ'),
2716 tdStepSessionCheckEnv([ 'FOO=BAR', 'BAR=BAZ',]),
2717 ]),
2718 ];
2719 # Leading '=' in the name is okay for windows guests in 6.1 and later (for driver letter CWDs).
2720 if (self.oTstDrv.fpApiVer < 6.1 and self.oTstDrv.fpApiVer >= 5.0) or not oTestVm.isWindows():
2721 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=', '===', vbox.ComError.E_INVALIDARG),
2722 tdStepSessionCheckEnv(),
2723 tdStepSessionSetEnv('=FOO', 'BAR', vbox.ComError.E_INVALIDARG),
2724 tdStepSessionCheckEnv(),
2725 tdStepSessionBulkEnv(['=', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2726 tdStepSessionCheckEnv(),
2727 tdStepSessionBulkEnv(['=FOO', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2728 tdStepSessionCheckEnv(),
2729 tdStepSessionBulkEnv(['=D:=D:/tmp', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2730 tdStepSessionCheckEnv(),
2731 tdStepSessionSetEnv('=D:', 'D:/temp', vbox.ComError.E_INVALIDARG),
2732 tdStepSessionCheckEnv(),
2733 ]));
2734 elif self.oTstDrv.fpApiVer >= 6.1 and oTestVm.isWindows():
2735 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=D:', 'D:/tmp'),
2736 tdStepSessionCheckEnv(['=D:=D:/tmp',]),
2737 tdStepSessionBulkEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2738 tdStepSessionCheckEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2739 tdStepSessionUnsetEnv('=D:'),
2740 tdStepSessionCheckEnv(['=D:', '=FOO', 'foo=bar']),
2741 ]));
2742
2743 return tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession, oTestVm, 'SessionEnv');
2744
2745 def testGuestCtrlSessionSimple(self, oSession, oTxsSession, oTestVm):
2746 """
2747 Tests simple session-based API calls.
2748 """
2749
2750 reporter.log('Testing simple session-based API calls ...');
2751
2752 # Start a valid session.
2753 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2754 try:
2755 oCreds = tdCtxCreds();
2756 oCreds.applyDefaultsIfNotSet(oTestVm);
2757 oGuest = oSession.o.console.guest;
2758 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionSimple");
2759 oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2760 except:
2761 reporter.logXcpt('Starting session for session-based API calls failed');
2762 return False;
2763
2764 fRc = True;
2765
2766 # Note: Starting with r161502 this should be fixed.
2767 # Session 0 separation started with Windows Vista, so skip everything older.
2768 if self.oTstDrv.uRevision >= 161502 \
2769 and oTestVm.isWindows() \
2770 and oTestVm.sKind not in ('WindowsNT3x', 'WindowsNT4', 'Windows2000', 'WindowsXP'):
2771 reporter.testStart('Windows guest processes in session >= 1');
2772 # Test in which Windows session Guest Control processes are being started.
2773 # We don't want them to be started in session 0, as this would prevent desktop interaction and other stuff.
2774 fRc, eExitStatus, iExitCode, _, _, _ = \
2775 self.executeGstCtlHelper(oTxsSession, oGuestSession, [ "show", "win-session-id" ]);
2776 if fRc \
2777 and eExitStatus == vboxcon.ProcessStatus_TerminatedNormally:
2778 if iExitCode >= 1000: # We report 1000 + <session ID> as exit code.
2779 uSessionId = iExitCode - 1000;
2780 if uSessionId >= 1:
2781 reporter.log('Guest processes start in session %d, good' % (uSessionId));
2782 else:
2783 reporter.error('Guest processes start in session 0, expected session >= 1');
2784 else:
2785 reporter.error('Guest Control Helper returned error %d (exit code)' % (iExitCode));
2786 reporter.testDone();
2787
2788 # User home.
2789 if self.oTstDrv.fpApiVer >= 7.0:
2790 reporter.log('Getting user\'s home directory ...');
2791 try:
2792 reporter.log('User home directory: %s' % (oGuestSession.userHome));
2793 except:
2794 fRc = reporter.logXcpt('Getting user home directory failed');
2795
2796 # User documents.
2797 if self.oTstDrv.fpApiVer >= 7.0:
2798 reporter.log('Getting user\'s documents directory ...');
2799 try:
2800 reporter.log('User documents directory: %s' % (oGuestSession.userDocuments));
2801 except:
2802 fRc = reporter.logXcpt('Getting user documents directory failed');
2803
2804 # Mount points. Only available for Guest Additions >= 7.1.
2805 if self.oTstDrv.fpApiVer >= 7.1:
2806 reporter.log('Getting mount points ...');
2807 try:
2808 aMountpoints = oGuestSession.getMountPoints();
2809 reporter.log('Got %ld mount points' % len(aMountpoints))
2810 for mountPoint in aMountpoints:
2811 reporter.log('Mountpoint: %s' % (mountPoint));
2812 except:
2813 fRc = reporter.logXcpt('Getting mount points failed');
2814
2815 # Close the session.
2816 try:
2817 oGuestSession.close();
2818 except:
2819 fRc = reporter.errorXcpt('Closing guest session failed');
2820
2821 return fRc;
2822
2823 def testGuestCtrlSession(self, oSession, oTxsSession, oTestVm):
2824 """
2825 Tests the guest session handling.
2826 """
2827
2828 #
2829 # Tests:
2830 #
2831 atTests = [
2832 # Invalid parameters.
2833 [ tdTestSession(sUser = ''), tdTestResultSession() ],
2834 # User account without a passwort - forbidden.
2835 [ tdTestSession(sPassword = "" ), tdTestResultSession() ],
2836 # Various wrong credentials.
2837 # Note! Only windows cares about sDomain, the other guests ignores it.
2838 # Note! On Guest Additions < 4.3 this always succeeds because these don't
2839 # support creating dedicated sessions. Instead, guest process creation
2840 # then will fail. See note below.
2841 [ tdTestSession(sPassword = 'bar'), tdTestResultSession() ],
2842 [ tdTestSession(sUser = 'foo', sPassword = 'bar'), tdTestResultSession() ],
2843 [ tdTestSession(sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2844 [ tdTestSession(sUser = 'foo', sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2845 ];
2846 if oTestVm.isWindows(): # domain is ignored elsewhere.
2847 atTests.append([ tdTestSession(sDomain = 'boo'), tdTestResultSession() ]);
2848
2849 # Finally, correct credentials.
2850 atTests.append([ tdTestSession(), tdTestResultSession(fRc = True, cNumSessions = 1) ]);
2851
2852 #
2853 # Run the tests.
2854 #
2855 fRc = True;
2856 for (i, tTest) in enumerate(atTests):
2857 oCurTest = tTest[0] # type: tdTestSession
2858 oCurRes = tTest[1] # type: tdTestResult
2859
2860 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2861 if not fRc:
2862 break;
2863 reporter.log('Testing #%d, user="%s", sPassword="%s", sDomain="%s" ...'
2864 % (i, oCurTest.oCreds.sUser, oCurTest.oCreds.sPassword, oCurTest.oCreds.sDomain));
2865 sCurGuestSessionName = 'testGuestCtrlSession: Test #%d' % (i,);
2866 fRc2, oCurGuestSession = oCurTest.createSession(sCurGuestSessionName, fIsError = oCurRes.fRc);
2867
2868 # See note about < 4.3 Guest Additions above.
2869 uProtocolVersion = 2;
2870 if oCurGuestSession is not None:
2871 try:
2872 uProtocolVersion = oCurGuestSession.protocolVersion;
2873 except:
2874 fRc = reporter.errorXcpt('Test #%d' % (i,));
2875
2876 if uProtocolVersion >= 2 and fRc2 is not oCurRes.fRc:
2877 fRc = reporter.error('Test #%d failed: Session creation failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
2878
2879 if fRc2 and oCurGuestSession is None:
2880 fRc = reporter.error('Test #%d failed: no session object' % (i,));
2881 fRc2 = False;
2882
2883 if fRc2:
2884 if uProtocolVersion >= 2: # For Guest Additions < 4.3 getSessionCount() always will return 1.
2885 cCurSessions = oCurTest.getSessionCount(self.oTstDrv.oVBoxMgr);
2886 if cCurSessions != oCurRes.cNumSessions:
2887 fRc = reporter.error('Test #%d failed: Session count does not match: Got %d, expected %d'
2888 % (i, cCurSessions, oCurRes.cNumSessions));
2889 try:
2890 sObjName = oCurGuestSession.name;
2891 except:
2892 fRc = reporter.errorXcpt('Test #%d' % (i,));
2893 else:
2894 if sObjName != sCurGuestSessionName:
2895 fRc = reporter.error('Test #%d failed: Session name does not match: Got "%s", expected "%s"'
2896 % (i, sObjName, sCurGuestSessionName));
2897 fRc2 = oCurTest.closeSession();
2898 if fRc2 is False:
2899 fRc = reporter.error('Test #%d failed: Session could not be closed' % (i,));
2900
2901 if fRc is False:
2902 return (False, oTxsSession);
2903
2904 #
2905 # Multiple sessions.
2906 #
2907 cMaxGuestSessions = 31; # Maximum number of concurrent guest session allowed.
2908 # Actually, this is 32, but we don't test session 0.
2909 aoMultiSessions = {};
2910 reporter.log2('Opening multiple guest tsessions at once ...');
2911 for i in xrange(cMaxGuestSessions + 1):
2912 aoMultiSessions[i] = tdTestSession(sSessionName = 'MultiSession #%d' % (i,));
2913 fRc = aoMultiSessions[i].setEnvironment(oSession, oTxsSession, oTestVm);
2914 if not fRc:
2915 break;
2916
2917 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2918 reporter.log2('MultiSession test #%d count is %d' % (i, cCurSessions));
2919 if cCurSessions != i:
2920 return (reporter.error('MultiSession count is %d, expected %d' % (cCurSessions, i)), oTxsSession);
2921 fRc2, _ = aoMultiSessions[i].createSession('MultiSession #%d' % (i,), i < cMaxGuestSessions);
2922 if fRc2 is not True:
2923 if i < cMaxGuestSessions:
2924 return (reporter.error('MultiSession #%d test failed' % (i,)), oTxsSession);
2925 reporter.log('MultiSession #%d exceeded concurrent guest session count, good' % (i,));
2926 break;
2927
2928 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2929 if cCurSessions is not cMaxGuestSessions:
2930 return (reporter.error('Final session count %d, expected %d ' % (cCurSessions, cMaxGuestSessions,)), oTxsSession);
2931
2932 reporter.log2('Closing MultiSessions ...');
2933 for i in xrange(cMaxGuestSessions):
2934 # Close this session:
2935 oClosedGuestSession = aoMultiSessions[i].oGuestSession;
2936 fRc2 = aoMultiSessions[i].closeSession();
2937 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr)
2938 reporter.log2('MultiSession #%d count is %d' % (i, cCurSessions,));
2939 if fRc2 is False:
2940 fRc = reporter.error('Closing MultiSession #%d failed' % (i,));
2941 elif cCurSessions != cMaxGuestSessions - (i + 1):
2942 fRc = reporter.error('Expected %d session after closing #%d, got %d instead'
2943 % (cMaxGuestSessions - (i + 1), cCurSessions, i,));
2944 assert aoMultiSessions[i].oGuestSession is None or not fRc2;
2945 ## @todo any way to check that the session is closed other than the 'sessions' attribute?
2946
2947 # Try check that none of the remaining sessions got closed.
2948 try:
2949 aoGuestSessions = self.oTstDrv.oVBoxMgr.getArray(atTests[0][0].oGuest, 'sessions');
2950 except:
2951 return (reporter.errorXcpt('i=%d/%d' % (i, cMaxGuestSessions,)), oTxsSession);
2952 if oClosedGuestSession in aoGuestSessions:
2953 fRc = reporter.error('i=%d/%d: %s should not be in %s'
2954 % (i, cMaxGuestSessions, oClosedGuestSession, aoGuestSessions));
2955 if i + 1 < cMaxGuestSessions: # Not sure what xrange(2,2) does...
2956 for j in xrange(i + 1, cMaxGuestSessions):
2957 if aoMultiSessions[j].oGuestSession not in aoGuestSessions:
2958 fRc = reporter.error('i=%d/j=%d/%d: %s should be in %s'
2959 % (i, j, cMaxGuestSessions, aoMultiSessions[j].oGuestSession, aoGuestSessions));
2960 ## @todo any way to check that they work?
2961
2962 ## @todo Test session timeouts.
2963
2964 fRc2 = self.testGuestCtrlSessionSimple(oSession, oTxsSession, oTestVm);
2965 if fRc:
2966 fRc = fRc2;
2967
2968 return (fRc, oTxsSession);
2969
2970 def testGuestCtrlSessionFileRefs(self, oSession, oTxsSession, oTestVm):
2971 """
2972 Tests the guest session file reference handling.
2973 """
2974
2975 # Find a file to play around with:
2976 sFile = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2977
2978 # Use credential defaults.
2979 oCreds = tdCtxCreds();
2980 oCreds.applyDefaultsIfNotSet(oTestVm);
2981
2982 # Number of stale guest files to create.
2983 cStaleFiles = 10;
2984
2985 #
2986 # Start a session.
2987 #
2988 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2989 try:
2990 oGuest = oSession.o.console.guest;
2991 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionFileRefs");
2992 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2993 except:
2994 return (reporter.errorXcpt(), oTxsSession);
2995
2996 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2997 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2998 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2999 reporter.log('Session successfully started');
3000
3001 #
3002 # Open guest files and "forget" them (stale entries).
3003 # For them we don't have any references anymore intentionally.
3004 #
3005 reporter.log2('Opening stale files');
3006 fRc = True;
3007 for i in xrange(0, cStaleFiles):
3008 try:
3009 if self.oTstDrv.fpApiVer >= 5.0:
3010 oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly, vboxcon.FileOpenAction_OpenExisting, 0);
3011 else:
3012 oGuestSession.fileOpen(sFile, "r", "oe", 0);
3013 # Note: Use a timeout in the call above for not letting the stale processes
3014 # hanging around forever. This can happen if the installed Guest Additions
3015 # do not support terminating guest processes.
3016 except:
3017 fRc = reporter.errorXcpt('Opening stale file #%d failed:' % (i,));
3018 break;
3019
3020 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3021 except: fRc = reporter.errorXcpt();
3022 else:
3023 if cFiles != cStaleFiles:
3024 fRc = reporter.error('Got %d stale files, expected %d' % (cFiles, cStaleFiles));
3025
3026 if fRc is True:
3027 #
3028 # Open non-stale files and close them again.
3029 #
3030 reporter.log2('Opening non-stale files');
3031 aoFiles = [];
3032 for i in xrange(0, cStaleFiles):
3033 try:
3034 if self.oTstDrv.fpApiVer >= 5.0:
3035 oCurFile = oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly,
3036 vboxcon.FileOpenAction_OpenExisting, 0);
3037 else:
3038 oCurFile = oGuestSession.fileOpen(sFile, "r", "oe", 0);
3039 aoFiles.append(oCurFile);
3040 except:
3041 fRc = reporter.errorXcpt('Opening non-stale file #%d failed:' % (i,));
3042 break;
3043
3044 # Check the count.
3045 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3046 except: fRc = reporter.errorXcpt();
3047 else:
3048 if cFiles != cStaleFiles * 2:
3049 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles * 2));
3050
3051 # Close them.
3052 reporter.log2('Closing all non-stale files again ...');
3053 for i, oFile in enumerate(aoFiles):
3054 try:
3055 oFile.close();
3056 except:
3057 fRc = reporter.errorXcpt('Closing non-stale file #%d failed:' % (i,));
3058
3059 # Check the count again.
3060 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3061 except: fRc = reporter.errorXcpt();
3062 # Here we count the stale files (that is, files we don't have a reference
3063 # anymore for) and the opened and then closed non-stale files (that we still keep
3064 # a reference in aoFiles[] for).
3065 if cFiles != cStaleFiles:
3066 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles));
3067
3068 #
3069 # Check that all (referenced) non-stale files are now in the "closed" state.
3070 #
3071 reporter.log2('Checking statuses of all non-stale files ...');
3072 for i, oFile in enumerate(aoFiles):
3073 try:
3074 eFileStatus = aoFiles[i].status;
3075 except:
3076 fRc = reporter.errorXcpt('Checking status of file #%d failed:' % (i,));
3077 else:
3078 if eFileStatus != vboxcon.FileStatus_Closed:
3079 fRc = reporter.error('Non-stale file #%d has status %d, expected %d'
3080 % (i, eFileStatus, vboxcon.FileStatus_Closed));
3081
3082 if fRc is True:
3083 reporter.log2('All non-stale files closed');
3084
3085 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3086 except: fRc = reporter.errorXcpt();
3087 else: reporter.log2('Final guest session file count: %d' % (cFiles,));
3088
3089 #
3090 # Now try to close the session and see what happens.
3091 # Note! Session closing is why we've been doing all the 'if fRc is True' stuff above rather than returning.
3092 #
3093 reporter.log2('Closing guest session ...');
3094 try:
3095 oGuestSession.close();
3096 except:
3097 fRc = reporter.errorXcpt('Testing for stale processes failed:');
3098
3099 return (fRc, oTxsSession);
3100
3101 #def testGuestCtrlSessionDirRefs(self, oSession, oTxsSession, oTestVm):
3102 # """
3103 # Tests the guest session directory reference handling.
3104 # """
3105
3106 # fRc = True;
3107 # return (fRc, oTxsSession);
3108
3109 def testGuestCtrlSessionProcRefs(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
3110 """
3111 Tests the guest session process reference handling.
3112 """
3113
3114 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3115 asArgs = [sShell,];
3116
3117 # Use credential defaults.
3118 oCreds = tdCtxCreds();
3119 oCreds.applyDefaultsIfNotSet(oTestVm);
3120
3121 # Number of guest processes per group to create.
3122 cProcsPerGroup = 10;
3123
3124 #
3125 # Start a session.
3126 #
3127 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3128 try:
3129 oGuest = oSession.o.console.guest;
3130 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionProcRefs");
3131 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3132 except:
3133 return (reporter.errorXcpt(), oTxsSession);
3134
3135 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3136 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3137 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3138 reporter.log('Session successfully started');
3139
3140 #
3141 # Fire off forever-running processes and "forget" them (stale entries).
3142 # For them we don't have any references anymore intentionally.
3143 #
3144 reporter.log('Starting stale processes...');
3145 fRc = True;
3146 for i in xrange(0, cProcsPerGroup):
3147 try:
3148 reporter.log2('Starting stale process #%d...' % (i));
3149 self.processCreateWrapper(oGuestSession, sShell, asArgs, "", # Working directory.
3150 [], # Environment changes.
3151 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], 30 * 1000);
3152 # Note: Not keeping a process reference from the created process above is intentional and part of the test!
3153
3154 # Note: Use a timeout in the call above for not letting the stale processes
3155 # hanging around forever. This can happen if the installed Guest Additions
3156 # do not support terminating guest processes.
3157 except:
3158 fRc = reporter.errorXcpt('Creating stale process #%d failed:' % (i,));
3159 break;
3160
3161 if fRc:
3162 reporter.log2('Starting stale processes successful');
3163 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3164 except: fRc = reporter.errorXcpt();
3165 else:
3166 reporter.log2('Proccess count is: %d' % (cProcs));
3167 if cProcs != cProcsPerGroup:
3168 fRc = reporter.error('Got %d stale processes, expected %d (stale)' % (cProcs, cProcsPerGroup));
3169
3170 if fRc:
3171 #
3172 # Fire off non-stale processes and wait for termination.
3173 #
3174 if oTestVm.isWindows() or oTestVm.isOS2():
3175 asArgs = [ sShell, '/C', 'dir', '/S', self.oTstDrv.getGuestSystemDir(oTestVm), ];
3176 else:
3177 asArgs = [ sShell, '-c', 'ls -la ' + self.oTstDrv.getGuestSystemDir(oTestVm), ];
3178 reporter.log('Starting non-stale processes...');
3179 aoProcs = [];
3180 for i in xrange(0, cProcsPerGroup):
3181 try:
3182 reporter.log2('Starting non-stale process #%d...' % (i));
3183 oCurProc = self.processCreateWrapper(oGuestSession, sShell, asArgs,
3184 "", # Working directory.
3185 [], [], 0); # Infinite timeout.
3186 aoProcs.append(oCurProc);
3187 except:
3188 fRc = reporter.errorXcpt('Creating non-stale process #%d failed:' % (i,));
3189 break;
3190
3191 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3192 except: fRc = reporter.errorXcpt();
3193 else:
3194 reporter.log2('Proccess count is: %d' % (cProcs));
3195
3196 reporter.log('Waiting for non-stale processes to terminate...');
3197 for i, oProcess in enumerate(aoProcs):
3198 try:
3199 reporter.log('Waiting for non-stale process #%d...' % (i));
3200 eWaitResult = oProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 30 * 1000);
3201 eProcessStatus = oProcess.status;
3202 except:
3203 fRc = reporter.errorXcpt('Waiting for non-stale process #%d failed:' % (i,));
3204 else:
3205 if eProcessStatus != vboxcon.ProcessStatus_TerminatedNormally:
3206 fRc = reporter.error('Waiting for non-stale processes #%d resulted in status %d, expected %d (wr=%d)'
3207 % (i, eProcessStatus, vboxcon.ProcessStatus_TerminatedNormally, eWaitResult));
3208 if fRc:
3209 reporter.log('All non-stale processes ended successfully');
3210
3211 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3212 except: fRc = reporter.errorXcpt();
3213 else:
3214 reporter.log2('Proccess count is: %d' % (cProcs));
3215
3216 # Here we count the stale processes (that is, processes we don't have a reference
3217 # anymore for) and the started + ended non-stale processes (that we still keep
3218 # a reference in aoProcesses[] for).
3219 cProcsExpected = cProcsPerGroup * 2;
3220 if cProcs != cProcsExpected:
3221 fRc = reporter.error('Got %d total processes, expected %d (stale vs. non-stale)' \
3222 % (cProcs, cProcsExpected));
3223 #
3224 # Fire off non-stale blocking processes which are terminated via terminate().
3225 #
3226 if oTestVm.isWindows() or oTestVm.isOS2():
3227 sCmd = sShell;
3228 asArgs = [ sCmd, '/C', 'pause'];
3229 else:
3230 sCmd = '/usr/bin/yes';
3231 asArgs = [ sCmd ];
3232 reporter.log('Starting blocking processes...');
3233 aoProcs = [];
3234 for i in xrange(0, cProcsPerGroup):
3235 try:
3236 reporter.log2('Starting blocking process #%d...' % (i));
3237 oCurProc = self.processCreateWrapper(oGuestSession, sCmd, asArgs,
3238 "", # Working directory.
3239 [], [], 30 * 1000);
3240
3241 # Note: Use a timeout in the call above for not letting the stale processes
3242 # hanging around forever. This can happen if the installed Guest Additions
3243 # do not support terminating guest processes.
3244 try:
3245 reporter.log('Waiting for blocking process #%d getting started...' % (i));
3246 eWaitResult = oCurProc.waitForArray([ vboxcon.ProcessWaitForFlag_Start, ], 30 * 1000);
3247 eProcessStatus = oCurProc.status;
3248 except:
3249 fRc = reporter.errorXcpt('Waiting for blocking process #%d failed:' % (i,));
3250 else:
3251 if eProcessStatus != vboxcon.ProcessStatus_Started:
3252 fRc = reporter.error('Waiting for blocking processes #%d resulted in status %d, expected %d (wr=%d)'
3253 % (i, eProcessStatus, vboxcon.ProcessStatus_Started, eWaitResult));
3254 aoProcs.append(oCurProc);
3255 except:
3256 fRc = reporter.errorXcpt('Creating blocking process #%d failed:' % (i,));
3257 break;
3258
3259 if fRc:
3260 reporter.log2('Starting blocking processes successful');
3261
3262 reporter.log2('Terminating blocking processes...');
3263 for i, oProcess in enumerate(aoProcs):
3264 try:
3265 reporter.log('Terminating blocking process #%d...' % (i));
3266 oProcess.terminate();
3267 except: # Termination might not be supported, just skip and log it.
3268 reporter.logXcpt('Termination of blocking process #%d failed, skipped:' % (i,));
3269 if self.oTstDrv.fpApiVer >= 6.1: # Termination is supported since 5.2 or so.
3270 fRc = False;
3271 if fRc:
3272 reporter.log('All blocking processes were terminated successfully');
3273
3274 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3275 except: fRc = reporter.errorXcpt();
3276 else:
3277 # There still should be 20 processes because we just terminated the 10 blocking ones above.
3278 cProcsExpected = cProcsPerGroup * 2;
3279 if cProcs != cProcsExpected:
3280 fRc = reporter.error('Got %d total processes, expected %d (final)' % (cProcs, cProcsExpected));
3281 reporter.log2('Final guest session processes count: %d' % (cProcs,));
3282
3283 if not fRc:
3284 aoProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3285 for i, oProc in enumerate(aoProcs):
3286 try:
3287 aoArgs = self.oTstDrv.oVBoxMgr.getArray(oProc, 'arguments');
3288 reporter.log('Process %d (\'%s\') still around, status is %d' \
3289 % (i, ' '.join([str(x) for x in aoArgs]), oProc.status));
3290 except:
3291 reporter.errorXcpt('Process lookup failed:');
3292 #
3293 # Now try to close the session and see what happens.
3294 #
3295 reporter.log('Closing guest session ...');
3296 try:
3297 oGuestSession.close();
3298 except:
3299 fRc = reporter.errorXcpt('Closing session for testing process references failed:');
3300
3301 return (fRc, oTxsSession);
3302
3303 def testGuestCtrlExec(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
3304 """
3305 Tests the basic execution feature.
3306 """
3307
3308 # Paths:
3309 sVBoxControl = None; # Only available on supported Windows guests.
3310 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3311 sShellOpt = '/C' if oTestVm.isWindows() or oTestVm.isOS2() else '-c';
3312 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3313 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
3314 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
3315 if oTestVm.isWindows() or oTestVm.isOS2():
3316 sImageOut = self.oTstDrv.getGuestSystemShell(oTestVm);
3317 if oTestVm.isWindows():
3318 sVBoxControl = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm), 'VBoxControl.exe');
3319 else:
3320 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3321 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/ls", fIgnoreErrors = True):
3322 sImageOut = "/bin/ls";
3323 else:
3324 sImageOut = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'ls');
3325 if oTestVm.isLinux(): ## @todo check solaris and darwin.
3326 sVBoxControl = "/usr/bin/VBoxControl"; # Symlink
3327
3328 # Use credential defaults.
3329 oCreds = tdCtxCreds();
3330 oCreds.applyDefaultsIfNotSet(oTestVm);
3331
3332 atInvalid = [
3333 # Invalid parameters.
3334 [ tdTestExec(), tdTestResultExec() ],
3335 # Non-existent / invalid image.
3336 [ tdTestExec(sCmd = "non-existent"), tdTestResultExec() ],
3337 [ tdTestExec(sCmd = "non-existent2"), tdTestResultExec() ],
3338 # Use an invalid format string.
3339 [ tdTestExec(sCmd = "%$%%%&"), tdTestResultExec() ],
3340 # More stuff.
3341 [ tdTestExec(sCmd = u"ƒ‰‹ˆ÷‹¸"), tdTestResultExec() ],
3342 [ tdTestExec(sCmd = "???://!!!"), tdTestResultExec() ],
3343 [ tdTestExec(sCmd = "<>!\\"), tdTestResultExec() ],
3344 # Enable as soon as ERROR_BAD_DEVICE is implemented.
3345 #[ tdTestExec(sCmd = "CON", tdTestResultExec() ],
3346 ];
3347
3348 atExec = [];
3349 if oTestVm.isWindows() or oTestVm.isOS2():
3350 if oTestVm.sKind == 'WindowsNT4':
3351 # For whatever reason NT4 SP6 (tst-nt4sp6) returns exit code 2 for existing *and* non-existing files.
3352 # I've manually checked that on the VM itself, so this is *not* a bug in the Guest Control code.
3353 # So we have to tweak the expected exit codes here in order to make the following tests pass.
3354 iExitCodeForExistingFiles = 2
3355 iExitCodeForNonExistingFiles = 2
3356 else:
3357 iExitCodeForExistingFiles = 0
3358 iExitCodeForNonExistingFiles = 1
3359 atExec += [
3360 # Basic execution.
3361 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3362 tdTestResultExec(fRc = True) ],
3363 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sFileForReading ]),
3364 tdTestResultExec(fRc = True, iExitCode = iExitCodeForExistingFiles) ],
3365 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir + '\\nonexist.dll' ]),
3366 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3367 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ]),
3368 tdTestResultExec(fRc = True, iExitCode = 1) ],
3369 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3370 tdTestResultExec(fRc = True, iExitCode = 1) ],
3371 # StdOut.
3372 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3373 tdTestResultExec(fRc = True) ],
3374 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ]),
3375 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3376 # StdErr.
3377 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3378 tdTestResultExec(fRc = True) ],
3379 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ]),
3380 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3381 # StdOut + StdErr.
3382 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3383 tdTestResultExec(fRc = True) ],
3384 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ]),
3385 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3386 ];
3387
3388 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3389 atExec.extend([
3390 # Current working directory set (VBox >= 7.1).
3391 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3392 tdTestResultExec(fRc = True) ]
3393 ]);
3394
3395 # atExec.extend([
3396 # FIXME: Failing tests.
3397 # Environment variables.
3398 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3399 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3400 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3401 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3402 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3403 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3404 # aEnv = [ 'TEST_FOO=BAR' ],
3405 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3406 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3407 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3408 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3409 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3410 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3411
3412 ## @todo Create some files (or get files) we know the output size of to validate output length!
3413 ## @todo Add task which gets killed at some random time while letting the guest output something.
3414 #];
3415 else:
3416 atExec += [
3417 # Basic execution.
3418 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '-R', sSystemDir ]),
3419 tdTestResultExec(fRc = True) ],
3420 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sFileForReading ]),
3421 tdTestResultExec(fRc = True) ],
3422 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '--wrong-parameter' ]),
3423 tdTestResultExec(fRc = True, iExitCode = 2) ],
3424 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/non/existent' ]),
3425 tdTestResultExec(fRc = True, iExitCode = 2) ],
3426 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3427 tdTestResultExec(fRc = True, iExitCode = 127) ],
3428 # StdOut.
3429 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3430 tdTestResultExec(fRc = True) ],
3431 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdout-non-existing' ]),
3432 tdTestResultExec(fRc = True, iExitCode = 2) ],
3433 # StdErr.
3434 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3435 tdTestResultExec(fRc = True) ],
3436 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stderr-non-existing' ]),
3437 tdTestResultExec(fRc = True, iExitCode = 2) ],
3438 # StdOut + StdErr.
3439 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3440 tdTestResultExec(fRc = True) ],
3441 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdouterr-non-existing' ]),
3442 tdTestResultExec(fRc = True, iExitCode = 2) ],
3443 ];
3444
3445 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3446 atExec.extend([
3447 # Current working directory set (VBox >= 7.1).
3448 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '-R', sSystemDir ]),
3449 tdTestResultExec(fRc = True) ]
3450 ]);
3451
3452 # atExec.extend([
3453 # FIXME: Failing tests.
3454 # Environment variables.
3455 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3456 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3457 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3458 #
3459 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3460 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3461 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3462 # aEnv = [ 'TEST_FOO=BAR' ],
3463 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3464 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3465 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3466 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3467 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3468 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3469
3470 ## @todo Create some files (or get files) we know the output size of to validate output length!
3471 ## @todo Add task which gets killed at some random time while letting the guest output something.
3472 #];
3473
3474 #
3475 #for iExitCode in xrange(0, 127):
3476 # atExec.append([ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'exit %s' % iExitCode ]),
3477 # tdTestResultExec(fRc = True, iExitCode = iExitCode) ]);
3478
3479 if sVBoxControl \
3480 and self.oTstDrv.fpApiVer >= 6.0: # Investigate with this doesn't work on (<) 5.2.
3481 # Paths with spaces on windows.
3482 atExec.append([ tdTestExec(sCmd = sVBoxControl, asArgs = [ sVBoxControl, 'version' ],
3483 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3484 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3485 tdTestResultExec(fRc = True) ]);
3486
3487 # Test very long arguments. Be careful when tweaking this to not break the tests.
3488 # Regarding paths:
3489 # - We have RTPATH_BIG_MAX (64K)
3490 # - MSDN says 32K for CreateFileW()
3491 # - On Windows, each path component must not be longer than MAX_PATH (260), see
3492 # https://docs.microsoft.com/en-us/windows/win32/fileio/filesystem-functionality-comparison#limits
3493 #
3494 # Old(er) Windows OSes tend to crash in cmd.exe, so skip this on these OSes.
3495 if self.oTstDrv.fpApiVer >= 6.1 \
3496 and oTestVm.sKind not in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
3497 sEndMarker = '--end-marker';
3498 if oTestVm.isWindows() \
3499 or oTestVm.isOS2():
3500 sCmd = sShell;
3501 else:
3502 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3503 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/echo", fIgnoreErrors = True):
3504 sCmd = "/bin/echo";
3505 else:
3506 sCmd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'echo');
3507
3508 for _ in xrange(0, 16):
3509 if oTestVm.isWindows() \
3510 or oTestVm.isOS2():
3511 asArgs = [ sShell, sShellOpt, "echo" ];
3512 else:
3513 asArgs = [ sCmd ];
3514
3515 # Append a random number of arguments with random length.
3516 for _ in xrange(0, self.oTestFiles.oRandom.randrange(1, 64)):
3517 asArgs.append(''.join(random.choice(string.ascii_lowercase)
3518 for _ in range(self.oTestFiles.oRandom.randrange(1, 196))));
3519
3520 asArgs.append(sEndMarker);
3521
3522 reporter.log2('asArgs=%s (%d args), type=%s' % (limitString(asArgs), len(asArgs), type(asArgs)));
3523
3524 ## @todo Check limits; on Ubuntu with 256KB IPRT returns VERR_NOT_IMPLEMENTED.
3525 # Use a higher timeout (15 min) than usual for these long checks.
3526 atExec.append([ tdTestExec(sCmd = sCmd, asArgs = asArgs,
3527 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3528 vboxcon.ProcessCreateFlag_WaitForStdErr ],
3529 timeoutMS = 15 * 60 * 1000),
3530 tdTestResultExec(fRc = True) ]);
3531
3532 # Build up the final test array for the first batch.
3533 atTests = atInvalid + atExec;
3534
3535 #
3536 # First batch: One session per guest process.
3537 #
3538 reporter.log('One session per guest process ...');
3539 fRc = True;
3540 for (i, tTest) in enumerate(atTests):
3541 oCurTest = tTest[0] # type: tdTestExec
3542 oCurRes = tTest[1] # type: tdTestResultExec
3543 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3544 if not fRc:
3545 break;
3546 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlExec: Test #%d' % (i,));
3547 if fRc2 is not True:
3548 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3549 break;
3550 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession) and fRc;
3551 fRc = oCurTest.closeSession() and fRc;
3552
3553 reporter.log('Execution of all tests done, checking for stale sessions');
3554
3555 # No sessions left?
3556 try:
3557 aSessions = self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions');
3558 except:
3559 fRc = reporter.errorXcpt();
3560 else:
3561 cSessions = len(aSessions);
3562 if cSessions != 0:
3563 fRc = reporter.error('Found %d stale session(s), expected 0:' % (cSessions,));
3564 for (i, aSession) in enumerate(aSessions):
3565 try: reporter.log(' Stale session #%d ("%s")' % (aSession.id, aSession.name));
3566 except: reporter.errorXcpt();
3567
3568 if fRc is not True:
3569 return (fRc, oTxsSession);
3570
3571 reporter.log('Now using one guest session for all tests ...');
3572
3573 #
3574 # Second batch: One session for *all* guest processes.
3575 #
3576
3577 # Create session.
3578 reporter.log('Creating session for all tests ...');
3579 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
3580 try:
3581 oGuest = oSession.o.console.guest;
3582 oCurGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain,
3583 'testGuestCtrlExec: One session for all tests');
3584 except:
3585 return (reporter.errorXcpt(), oTxsSession);
3586
3587 try:
3588 eWaitResult = oCurGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3589 except:
3590 fRc = reporter.errorXcpt('Waiting for guest session to start failed:');
3591 else:
3592 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3593 fRc = reporter.error('Session did not start successfully, returned wait result: %d' % (eWaitResult,));
3594 else:
3595 reporter.log('Session successfully started');
3596
3597 # Do the tests within this session.
3598 for (i, tTest) in enumerate(atTests):
3599 oCurTest = tTest[0] # type: tdTestExec
3600 oCurRes = tTest[1] # type: tdTestResultExec
3601
3602 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3603 if not fRc:
3604 break;
3605 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession);
3606 if fRc is False:
3607 break;
3608
3609 # Close the session.
3610 reporter.log2('Closing guest session ...');
3611 try:
3612 oCurGuestSession.close();
3613 oCurGuestSession = None;
3614 except:
3615 fRc = reporter.errorXcpt('Closing guest session failed:');
3616
3617 # No sessions left?
3618 reporter.log('Execution of all tests done, checking for stale sessions again');
3619 try: cSessions = len(self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions'));
3620 except: fRc = reporter.errorXcpt();
3621 else:
3622 if cSessions != 0:
3623 fRc = reporter.error('Found %d stale session(s), expected 0' % (cSessions,));
3624 return (fRc, oTxsSession);
3625
3626 def threadForTestGuestCtrlSessionReboot(self, oGuestProcess):
3627 """
3628 Thread routine which waits for the stale guest process getting terminated (or some error)
3629 while the main test routine reboots the guest. It then compares the expected guest process result
3630 and logs an error if appropriate.
3631 """
3632 reporter.log('Waiting for process to get terminated at reboot ...');
3633 try:
3634 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate ], 5 * 60 * 1000);
3635 except:
3636 return reporter.errorXcpt('waitForArray failed');
3637 try:
3638 eStatus = oGuestProcess.status
3639 except:
3640 return reporter.errorXcpt('failed to get status (wait result %d)' % (eWaitResult,));
3641
3642 if eWaitResult == vboxcon.ProcessWaitResult_Terminate and eStatus == vboxcon.ProcessStatus_Down:
3643 reporter.log('Stale process was correctly terminated (status: down)');
3644 return True;
3645
3646 return reporter.error('Process wait across reboot failed: eWaitResult=%d, expected %d; eStatus=%d, expected %d'
3647 % (eWaitResult, vboxcon.ProcessWaitResult_Terminate, eStatus, vboxcon.ProcessStatus_Down,));
3648
3649 def testGuestCtrlSessionReboot(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3650 """
3651 Tests guest object notifications when a guest gets rebooted / shutdown.
3652
3653 These notifications gets sent from the guest sessions in order to make API clients
3654 aware of guest session changes.
3655
3656 To test that we create a stale guest process and trigger a reboot of the guest.
3657 """
3658
3659 ## @todo backport fixes to 6.0 and maybe 5.2
3660 if self.oTstDrv.fpApiVer <= 6.0:
3661 reporter.log('Skipping: Required fixes not yet backported!');
3662 return None;
3663
3664 # Use credential defaults.
3665 oCreds = tdCtxCreds();
3666 oCreds.applyDefaultsIfNotSet(oTestVm);
3667
3668 fRebooted = False;
3669 fRc = True;
3670
3671 #
3672 # Start a session.
3673 #
3674 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3675 try:
3676 oGuest = oSession.o.console.guest;
3677 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionReboot");
3678 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3679 except:
3680 return (reporter.errorXcpt(), oTxsSession);
3681
3682 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3683 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3684 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3685 reporter.log('Session successfully started');
3686
3687 #
3688 # Create a process.
3689 #
3690 # That process will also be used later to see if the session cleanup worked upon reboot.
3691 #
3692 sImage = self.oTstDrv.getGuestSystemShell(oTestVm);
3693 asArgs = [ sImage, ];
3694 aEnv = [];
3695 afFlags = [];
3696 try:
3697 oGuestProcess = self.processCreateWrapper(oGuestSession, sImage, asArgs,
3698 "", # Working directory.
3699 aEnv, afFlags, 30 * 1000);
3700 except:
3701 fRc = reporter.error('Failed to start shell process (%s)' % (sImage,));
3702 else:
3703 try:
3704 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3705 except:
3706 fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3707 else:
3708 # Check the result and state:
3709 try: eStatus = oGuestProcess.status;
3710 except: fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3711 else:
3712 reporter.log2('Starting process wait result returned: %d; Process status is: %d' % (eWaitResult, eStatus,));
3713 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3714 fRc = reporter.error('wait for ProcessWaitForFlag_Start failed: %d, expected %d (Start)'
3715 % (eWaitResult, vboxcon.ProcessWaitResult_Start,));
3716 elif eStatus != vboxcon.ProcessStatus_Started:
3717 fRc = reporter.error('Unexpected process status after startup: %d, wanted %d (Started)'
3718 % (eStatus, vboxcon.ProcessStatus_Started,));
3719 else:
3720 # Create a thread that waits on the process to terminate
3721 reporter.log('Creating reboot thread ...');
3722 oThreadReboot = threading.Thread(target = self.threadForTestGuestCtrlSessionReboot,
3723 args = (oGuestProcess,),
3724 name = 'threadForTestGuestCtrlSessionReboot');
3725 oThreadReboot.setDaemon(True); # pylint: disable=deprecated-method
3726 oThreadReboot.start();
3727
3728 # Do the reboot.
3729 reporter.log('Rebooting guest and reconnecting TXS ...');
3730 (oSession, oTxsSession) = self.oTstDrv.txsRebootAndReconnectViaTcp(oSession, oTxsSession,
3731 cMsTimeout = 3 * 60000);
3732 if oSession \
3733 and oTxsSession:
3734 # Set reboot flag (needed later for session closing).
3735 fRebooted = True;
3736 else:
3737 reporter.error('Rebooting via TXS failed');
3738 try: oGuestProcess.terminate();
3739 except: reporter.logXcpt();
3740 fRc = False;
3741
3742 reporter.log('Waiting for thread to finish ...');
3743 oThreadReboot.join();
3744
3745 # Check that the guest session now still has the formerly guest process object created above,
3746 # but with the "down" status now (because of guest reboot).
3747 try:
3748 aoGuestProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3749 if len(aoGuestProcs) == 1:
3750 enmProcSts = aoGuestProcs[0].status;
3751 if enmProcSts != vboxcon.ProcessStatus_Down:
3752 fRc = reporter.error('Old guest process (before reboot) has status %d, expected %s' \
3753 % (enmProcSts, vboxcon.ProcessStatus_Down));
3754 else:
3755 fRc = reporter.error('Old guest session (before reboot) has %d processes registered, expected 1' \
3756 % (len(aoGuestProcs)));
3757 except:
3758 fRc = reporter.errorXcpt();
3759 #
3760 # Try make sure we don't leave with a stale process on failure.
3761 #
3762 try: oGuestProcess.terminate();
3763 except: reporter.logXcpt();
3764
3765 #
3766 # Close the session.
3767 #
3768 reporter.log2('Closing guest session ...');
3769 try:
3770 oGuestSession.close();
3771 except:
3772 # Closing the guest session will fail when the guest reboot has been triggered,
3773 # as the session object will be cleared on a guest reboot.
3774 if fRebooted:
3775 reporter.logXcpt('Closing guest session failed, good (guest rebooted)');
3776 else: # ... otherwise this (still) should succeed. Report so if it doesn't.
3777 reporter.errorXcpt('Closing guest session failed');
3778
3779 return (fRc, oTxsSession);
3780
3781 def testGuestCtrlExecTimeout(self, oSession, oTxsSession, oTestVm):
3782 """
3783 Tests handling of timeouts of started guest processes.
3784 """
3785
3786 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3787
3788 # Use credential defaults.
3789 oCreds = tdCtxCreds();
3790 oCreds.applyDefaultsIfNotSet(oTestVm);
3791
3792 #
3793 # Create a session.
3794 #
3795 try:
3796 oGuest = oSession.o.console.guest;
3797 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlExecTimeout");
3798 eWaitResult = oGuestSession.waitForArray([ vboxcon.GuestSessionWaitForFlag_Start, ], 30 * 1000);
3799 except:
3800 return (reporter.errorXcpt(), oTxsSession);
3801
3802 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3803 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3804 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3805 reporter.log('Session successfully started');
3806
3807 #
3808 # Create a process which never terminates and should timeout when
3809 # waiting for termination.
3810 #
3811 fRc = True;
3812 try:
3813 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [ sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3814 "", # Working directory.
3815 [], [], 30 * 1000);
3816 except:
3817 fRc = reporter.errorXcpt();
3818 else:
3819 reporter.log('Waiting for process 1 being started ...');
3820 try:
3821 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3822 except:
3823 fRc = reporter.errorXcpt();
3824 else:
3825 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3826 fRc = reporter.error('Waiting for process 1 to start failed, got status %d' % (eWaitResult,));
3827 else:
3828 for msWait in (1, 32, 2000,):
3829 reporter.log('Waiting for process 1 to time out within %sms ...' % (msWait,));
3830 try:
3831 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], msWait);
3832 except:
3833 fRc = reporter.errorXcpt();
3834 break;
3835 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3836 fRc = reporter.error('Waiting for process 1 did not time out in %sms as expected: %d'
3837 % (msWait, eWaitResult,));
3838 break;
3839 reporter.log('Waiting for process 1 timed out in %u ms, good' % (msWait,));
3840
3841 try:
3842 oCurProcess.terminate();
3843 except:
3844 reporter.errorXcpt();
3845 oCurProcess = None;
3846
3847 #
3848 # Create another process that doesn't terminate, but which will be killed by VBoxService
3849 # because it ran out of execution time (3 seconds).
3850 #
3851 try:
3852 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3853 "", # Working directory.
3854 [], [], 3 * 1000);
3855 except:
3856 fRc = reporter.errorXcpt();
3857 else:
3858 reporter.log('Waiting for process 2 being started ...');
3859 try:
3860 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3861 except:
3862 fRc = reporter.errorXcpt();
3863 else:
3864 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3865 fRc = reporter.error('Waiting for process 2 to start failed, got status %d' % (eWaitResult,));
3866 else:
3867 reporter.log('Waiting for process 2 to get killed for running out of execution time ...');
3868 try:
3869 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 15 * 1000);
3870 except:
3871 fRc = reporter.errorXcpt();
3872 else:
3873 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3874 fRc = reporter.error('Waiting for process 2 did not time out when it should, got wait result %d'
3875 % (eWaitResult,));
3876 else:
3877 reporter.log('Waiting for process 2 did not time out, good: %s' % (eWaitResult,));
3878 try:
3879 eStatus = oCurProcess.status;
3880 except:
3881 fRc = reporter.errorXcpt();
3882 else:
3883 if eStatus != vboxcon.ProcessStatus_TimedOutKilled:
3884 fRc = reporter.error('Status of process 2 wrong; excepted %d, got %d'
3885 % (vboxcon.ProcessStatus_TimedOutKilled, eStatus));
3886 else:
3887 reporter.log('Status of process 2 is TimedOutKilled (%d) is it should be.'
3888 % (vboxcon.ProcessStatus_TimedOutKilled,));
3889 try:
3890 oCurProcess.terminate();
3891 except:
3892 reporter.logXcpt();
3893 oCurProcess = None;
3894
3895 #
3896 # Clean up the session.
3897 #
3898 try:
3899 oGuestSession.close();
3900 except:
3901 fRc = reporter.errorXcpt();
3902
3903 return (fRc, oTxsSession);
3904
3905 def testGuestCtrlDirCreate(self, oSession, oTxsSession, oTestVm):
3906 """
3907 Tests creation of guest directories.
3908 """
3909
3910 sScratch = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'testGuestCtrlDirCreate');
3911
3912 atTests = [
3913 # Invalid stuff.
3914 [ tdTestDirCreate(sDirectory = '' ), tdTestResultFailure() ],
3915 # More unusual stuff.
3916 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '.') ), tdTestResultFailure() ],
3917 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '..') ), tdTestResultFailure() ],
3918 [ tdTestDirCreate(sDirectory = '..' ), tdTestResultFailure() ],
3919 [ tdTestDirCreate(sDirectory = '../' ), tdTestResultFailure() ],
3920 [ tdTestDirCreate(sDirectory = '../../' ), tdTestResultFailure() ],
3921 [ tdTestDirCreate(sDirectory = '/' ), tdTestResultFailure() ],
3922 [ tdTestDirCreate(sDirectory = '/..' ), tdTestResultFailure() ],
3923 [ tdTestDirCreate(sDirectory = '/../' ), tdTestResultFailure() ],
3924 ];
3925 if oTestVm.isWindows() or oTestVm.isOS2():
3926 atTests.extend([
3927 [ tdTestDirCreate(sDirectory = 'C:\\' ), tdTestResultFailure() ],
3928 [ tdTestDirCreate(sDirectory = 'C:\\..' ), tdTestResultFailure() ],
3929 [ tdTestDirCreate(sDirectory = 'C:\\..\\' ), tdTestResultFailure() ],
3930 [ tdTestDirCreate(sDirectory = 'C:/' ), tdTestResultFailure() ],
3931 [ tdTestDirCreate(sDirectory = 'C:/.' ), tdTestResultFailure() ],
3932 [ tdTestDirCreate(sDirectory = 'C:/./' ), tdTestResultFailure() ],
3933 [ tdTestDirCreate(sDirectory = 'C:/..' ), tdTestResultFailure() ],
3934 [ tdTestDirCreate(sDirectory = 'C:/../' ), tdTestResultFailure() ],
3935 [ tdTestDirCreate(sDirectory = '\\\\uncrulez\\foo' ), tdTestResultFailure() ],
3936 ]);
3937 atTests.extend([
3938 # Existing directories and files.
3939 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemDir(oTestVm) ), tdTestResultFailure() ],
3940 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemShell(oTestVm) ), tdTestResultFailure() ],
3941 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemFileForReading(oTestVm) ), tdTestResultFailure() ],
3942 # Creating directories.
3943 [ tdTestDirCreate(sDirectory = sScratch ), tdTestResultSuccess() ],
3944 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3945 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3946 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3947 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3948 # Try format strings as directories.
3949 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo%sbar%sbaz%d' )), tdTestResultSuccess() ],
3950 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, '%f%%boo%%bar%RI32' )), tdTestResultSuccess() ],
3951 # Long random names.
3952 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(36, 28))),
3953 tdTestResultSuccess() ],
3954 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(140, 116))),
3955 tdTestResultSuccess() ],
3956 # Too long names. ASSUMES a guests has a 255 filename length limitation.
3957 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3958 tdTestResultFailure() ],
3959 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3960 tdTestResultFailure() ],
3961 # Missing directory in path.
3962 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo1', 'bar') ), tdTestResultFailure() ],
3963 ]);
3964
3965 fRc = True;
3966 for (i, tTest) in enumerate(atTests):
3967 oCurTest = tTest[0] # type: tdTestDirCreate
3968 oCurRes = tTest[1] # type: tdTestResult
3969 reporter.log('Testing #%d, sDirectory="%s" ...' % (i, limitString(oCurTest.sDirectory),));
3970
3971 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3972 if not fRc:
3973 break;
3974 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreate: Test #%d' % (i,));
3975 if fRc is False:
3976 return reporter.error('Test #%d failed: Could not create session' % (i,));
3977
3978 fRc = self.gctrlCreateDir(oCurTest, oCurRes, oCurGuestSession);
3979
3980 fRc = oCurTest.closeSession() and fRc;
3981 if fRc is False:
3982 fRc = reporter.error('Test #%d failed' % (i,));
3983
3984 return (fRc, oTxsSession);
3985
3986 def testGuestCtrlDirCreateTemp(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3987 """
3988 Tests creation of temporary directories.
3989 """
3990
3991 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3992 atTests = [
3993 # Invalid stuff (template must have one or more trailin 'X'es (upper case only), or a cluster of three or more).
3994 [ tdTestDirCreateTemp(sDirectory = ''), tdTestResultFailure() ],
3995 [ tdTestDirCreateTemp(sDirectory = sSystemDir, fMode = 1234), tdTestResultFailure() ],
3996 [ tdTestDirCreateTemp(sTemplate = 'xXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3997 [ tdTestDirCreateTemp(sTemplate = 'xxx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3998 [ tdTestDirCreateTemp(sTemplate = 'XXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3999 [ tdTestDirCreateTemp(sTemplate = 'bar', sDirectory = 'whatever', fMode = 0o700), tdTestResultFailure() ],
4000 [ tdTestDirCreateTemp(sTemplate = 'foo', sDirectory = 'it is not used', fMode = 0o700), tdTestResultFailure() ],
4001 [ tdTestDirCreateTemp(sTemplate = 'X,so', sDirectory = 'pointless test', fMode = 0o700), tdTestResultFailure() ],
4002 # Non-existing stuff.
4003 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX',
4004 sDirectory = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'non', 'existing')),
4005 tdTestResultFailure() ],
4006 # Working stuff:
4007 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
4008 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
4009 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
4010 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
4011 tdTestResultFailure() ],
4012 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
4013 tdTestResultFailure() ],
4014 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
4015 tdTestResultFailure() ],
4016 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
4017 tdTestResultFailure() ],
4018 ];
4019
4020 if self.oTstDrv.fpApiVer >= 7.0:
4021 # Weird mode set.
4022 atTests.extend([
4023 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o42333),
4024 tdTestResultFailure() ]
4025 ]);
4026 # Same as working stuff above, but with a different mode set.
4027 atTests.extend([
4028 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4029 tdTestResultFailure() ],
4030 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4031 tdTestResultFailure() ],
4032 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4033 tdTestResultFailure() ],
4034 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4035 tdTestResultFailure() ],
4036 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4037 tdTestResultFailure() ],
4038 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4039 tdTestResultFailure() ],
4040 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4041 tdTestResultFailure() ]
4042 ]);
4043 # Same as working stuff above, but with secure mode set.
4044 atTests.extend([
4045 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4046 tdTestResultFailure() ],
4047 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4048 tdTestResultFailure() ],
4049 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4050 tdTestResultFailure() ],
4051 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4052 tdTestResultFailure() ],
4053 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4054 fSecure = True),
4055 tdTestResultFailure() ],
4056 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4057 fSecure = True),
4058 tdTestResultFailure() ],
4059 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4060 fSecure = True),
4061 tdTestResultFailure() ]
4062 ]);
4063
4064 fRc = True;
4065 for (i, tTest) in enumerate(atTests):
4066 oCurTest = tTest[0] # type: tdTestDirCreateTemp
4067 oCurRes = tTest[1] # type: tdTestResult
4068 reporter.log('Testing #%d, sTemplate="%s", fMode=%#o, path="%s", secure="%s" ...' %
4069 (i, oCurTest.sTemplate, oCurTest.fMode, oCurTest.sDirectory, oCurTest.fSecure));
4070
4071 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4072 if not fRc:
4073 break;
4074 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreateTemp: Test #%d' % (i,));
4075 if fRc is False:
4076 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4077 break;
4078
4079 sDirTemp = '';
4080 try:
4081 sDirTemp = oCurGuestSession.directoryCreateTemp(oCurTest.sTemplate, oCurTest.fMode,
4082 oCurTest.sDirectory, oCurTest.fSecure);
4083 except:
4084 if oCurRes.fRc is True:
4085 fRc = reporter.errorXcpt('Creating temp directory "%s" failed:' % (oCurTest.sDirectory,));
4086 else:
4087 reporter.logXcpt('Creating temp directory "%s" failed expectedly, skipping:' % (oCurTest.sDirectory,));
4088 else:
4089 reporter.log2('Temporary directory is: "%s"' % (limitString(sDirTemp),));
4090 if not sDirTemp:
4091 fRc = reporter.error('Resulting directory is empty!');
4092 else:
4093 try:
4094 oFsObjInfo = oCurGuestSession.fsObjQueryInfo(sDirTemp, False);
4095 eType = oFsObjInfo.type;
4096 except:
4097 fRc = reporter.errorXcpt('sDirTemp="%s"' % (sDirTemp,));
4098 else:
4099 reporter.log2('%s: eType=%s (dir=%d)' % (limitString(sDirTemp), eType, vboxcon.FsObjType_Directory,));
4100 if eType != vboxcon.FsObjType_Directory:
4101 fRc = reporter.error('Temporary directory "%s" not created as a directory: eType=%d'
4102 % (sDirTemp, eType));
4103 fRc = oCurTest.closeSession() and fRc;
4104 return (fRc, oTxsSession);
4105
4106 def testGuestCtrlDirRead(self, oSession, oTxsSession, oTestVm):
4107 """
4108 Tests opening and reading (enumerating) guest directories.
4109 """
4110
4111 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
4112 atTests = [
4113 # Invalid stuff.
4114 [ tdTestDirRead(sDirectory = ''), tdTestResultDirRead() ],
4115 [ tdTestDirRead(sDirectory = sSystemDir, afFlags = [ 1234 ]), tdTestResultDirRead() ],
4116 [ tdTestDirRead(sDirectory = sSystemDir, sFilter = '*.foo'), tdTestResultDirRead() ],
4117 # Non-existing stuff.
4118 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'really-no-such-subdir')), tdTestResultDirRead() ],
4119 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'non', 'existing')), tdTestResultDirRead() ],
4120 ];
4121
4122 if oTestVm.isWindows() or oTestVm.isOS2():
4123 atTests.extend([
4124 # More unusual stuff.
4125 [ tdTestDirRead(sDirectory = 'z:\\'), tdTestResultDirRead() ],
4126 [ tdTestDirRead(sDirectory = '\\\\uncrulez\\foo'), tdTestResultDirRead() ],
4127 ]);
4128
4129 # Read the system directory (ASSUMES at least 5 files in it):
4130 # Windows 7+ has inaccessible system32/com/dmp directory that screws up this test, so skip it on windows:
4131 if not oTestVm.isWindows():
4132 atTests.append([ tdTestDirRead(sDirectory = sSystemDir),
4133 tdTestResultDirRead(fRc = True, cFiles = -5, cDirs = None) ]);
4134 ## @todo trailing slash
4135
4136 # Read from the test file set.
4137 atTests.extend([
4138 [ tdTestDirRead(sDirectory = self.oTestFiles.oEmptyDir.sPath),
4139 tdTestResultDirRead(fRc = True, cFiles = 0, cDirs = 0, cOthers = 0) ],
4140 [ tdTestDirRead(sDirectory = self.oTestFiles.oManyDir.sPath),
4141 tdTestResultDirRead(fRc = True, cFiles = len(self.oTestFiles.oManyDir.aoChildren), cDirs = 0, cOthers = 0) ],
4142 [ tdTestDirRead(sDirectory = self.oTestFiles.oTreeDir.sPath),
4143 tdTestResultDirRead(fRc = True, cFiles = self.oTestFiles.cTreeFiles, cDirs = self.oTestFiles.cTreeDirs,
4144 cOthers = self.oTestFiles.cTreeOthers) ],
4145 ]);
4146
4147
4148 fRc = True;
4149 for (i, tTest) in enumerate(atTests):
4150 oCurTest = tTest[0] # type: tdTestExec
4151 oCurRes = tTest[1] # type: tdTestResultDirRead
4152
4153 reporter.log('Testing #%d, dir="%s" ...' % (i, oCurTest.sDirectory));
4154 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4155 if not fRc:
4156 break;
4157 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: Test #%d' % (i,));
4158 if fRc is not True:
4159 break;
4160 fUseDirList = False;
4161 cEntriesPerRead = random.randrange(1, 32768);
4162 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4163 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4164 # Listing directories only is available for >= VBox 7.1.
4165 fUseDirList = random.choice( [True, False] );
4166 (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc,
4167 fUseDirList, cEntriesPerRead);
4168 fRc = oCurTest.closeSession() and fRc;
4169
4170 reporter.log2('Test #%d: Returned %d directories, %d files total' % (i, cDirs, cFiles));
4171 if fRc2 is oCurRes.fRc:
4172 if fRc2 is True:
4173 if oCurRes.cFiles is None:
4174 pass; # ignore
4175 elif oCurRes.cFiles >= 0 and cFiles != oCurRes.cFiles:
4176 fRc = reporter.error('Test #%d failed: Got %d files, expected %d' % (i, cFiles, oCurRes.cFiles));
4177 elif oCurRes.cFiles < 0 and cFiles < -oCurRes.cFiles:
4178 fRc = reporter.error('Test #%d failed: Got %d files, expected at least %d'
4179 % (i, cFiles, -oCurRes.cFiles));
4180 if oCurRes.cDirs is None:
4181 pass; # ignore
4182 elif oCurRes.cDirs >= 0 and cDirs != oCurRes.cDirs:
4183 fRc = reporter.error('Test #%d failed: Got %d directories, expected %d' % (i, cDirs, oCurRes.cDirs));
4184 elif oCurRes.cDirs < 0 and cDirs < -oCurRes.cDirs:
4185 fRc = reporter.error('Test #%d failed: Got %d directories, expected at least %d'
4186 % (i, cDirs, -oCurRes.cDirs));
4187 if oCurRes.cOthers is None:
4188 pass; # ignore
4189 elif oCurRes.cOthers >= 0 and cOthers != oCurRes.cOthers:
4190 fRc = reporter.error('Test #%d failed: Got %d other types, expected %d' % (i, cOthers, oCurRes.cOthers));
4191 elif oCurRes.cOthers < 0 and cOthers < -oCurRes.cOthers:
4192 fRc = reporter.error('Test #%d failed: Got %d other types, expected at least %d'
4193 % (i, cOthers, -oCurRes.cOthers));
4194
4195 else:
4196 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4197
4198
4199 #
4200 # Go over a few directories in the test file set and compare names,
4201 # types and sizes rather than just the counts like we did above.
4202 #
4203 if fRc is True:
4204 oCurTest = tdTestDirRead();
4205 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4206 if fRc:
4207 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: gctrlReadDirTree2');
4208 if fRc is True:
4209 for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
4210 reporter.log('Checking "%s" ...' % (oDir.sPath,));
4211 fUseDirList = False;
4212 cEntriesPerRead = random.randrange(1, 32768);
4213 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4214 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4215 # Listing directories only is available for >= VBox 7.1.
4216 fUseDirList = random.choice( [True, False] );
4217 fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir, fUseDirList, cEntriesPerRead) and fRc;
4218 fRc = oCurTest.closeSession() and fRc;
4219
4220 return (fRc, oTxsSession);
4221
4222
4223 def testGuestCtrlFileRemove(self, oSession, oTxsSession, oTestVm):
4224 """
4225 Tests removing guest files.
4226 """
4227
4228 #
4229 # Create a directory with a few files in it using TXS that we'll use for the initial tests.
4230 #
4231 asTestDirs = [
4232 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1'), # [0]
4233 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1'), # [1]
4234 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1', 'subsubdir-1'), # [2]
4235 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2'), # [3]
4236 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2'), # [4]
4237 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2', 'subsbudir-2'), # [5]
4238 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-3'), # [6]
4239 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-4'), # [7]
4240 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5'), # [8]
4241 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5', 'subdir-5'), # [9]
4242 ]
4243 asTestFiles = [
4244 oTestVm.pathJoin(asTestDirs[0], 'file-0'), # [0]
4245 oTestVm.pathJoin(asTestDirs[0], 'file-1'), # [1]
4246 oTestVm.pathJoin(asTestDirs[0], 'file-2'), # [2]
4247 oTestVm.pathJoin(asTestDirs[1], 'file-3'), # [3] - subdir-1
4248 oTestVm.pathJoin(asTestDirs[1], 'file-4'), # [4] - subdir-1
4249 oTestVm.pathJoin(asTestDirs[2], 'file-5'), # [5] - subsubdir-1
4250 oTestVm.pathJoin(asTestDirs[3], 'file-6'), # [6] - rmtestdir-2
4251 oTestVm.pathJoin(asTestDirs[4], 'file-7'), # [7] - subdir-2
4252 oTestVm.pathJoin(asTestDirs[5], 'file-8'), # [8] - subsubdir-2
4253 ];
4254 for sDir in asTestDirs:
4255 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
4256 return reporter.error('Failed to create test dir "%s"!' % (sDir,));
4257 for sFile in asTestFiles:
4258 if oTxsSession.syncUploadString(sFile, sFile, 0o666) is not True:
4259 return reporter.error('Failed to create test file "%s"!' % (sFile,));
4260
4261 #
4262 # Tear down the directories and files.
4263 #
4264 aoTests = [
4265 # Negative tests first:
4266 tdTestRemoveFile(asTestDirs[0], fRcExpect = False),
4267 tdTestRemoveDir(asTestDirs[0], fRcExpect = False),
4268 tdTestRemoveDir(asTestFiles[0], fRcExpect = False),
4269 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-file'), fRcExpect = False),
4270 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir'), fRcExpect = False),
4271 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-file'), fRcExpect = False),
4272 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-subdir'), fRcExpect = False),
4273 tdTestRemoveTree(asTestDirs[0], afFlags = [], fRcExpect = False), # Only removes empty dirs, this isn't empty.
4274 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fRcExpect = False), # ditto
4275 # Empty paths:
4276 tdTestRemoveFile('', fRcExpect = False),
4277 tdTestRemoveDir('', fRcExpect = False),
4278 tdTestRemoveTree('', fRcExpect = False),
4279 # Now actually remove stuff:
4280 tdTestRemoveDir(asTestDirs[7], fRcExpect = True),
4281 tdTestRemoveFile(asTestDirs[6], fRcExpect = False),
4282 tdTestRemoveDir(asTestDirs[6], fRcExpect = True),
4283 tdTestRemoveFile(asTestFiles[0], fRcExpect = True),
4284 tdTestRemoveFile(asTestFiles[0], fRcExpect = False),
4285 # 17:
4286 tdTestRemoveTree(asTestDirs[8], fRcExpect = True), # Removes empty subdirs and leaves the dir itself.
4287 tdTestRemoveDir(asTestDirs[8], fRcExpect = True),
4288 tdTestRemoveTree(asTestDirs[3], fRcExpect = False), # Have subdirs & files,
4289 tdTestRemoveTree(asTestDirs[3], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,], fRcExpect = True),
4290 tdTestRemoveDir(asTestDirs[3], fRcExpect = True),
4291 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4292 # No error if already delete (RTDirRemoveRecursive artifact).
4293 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4294 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,],
4295 fNotExist = True, fRcExpect = True),
4296 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fNotExist = True, fRcExpect = True),
4297 ];
4298
4299 #
4300 # Execution loop
4301 #
4302 fRc = True;
4303 for (i, oTest) in enumerate(aoTests): # int, tdTestRemoveBase
4304 reporter.log('Testing #%d, path="%s" %s ...' % (i, oTest.sPath, oTest.__class__.__name__));
4305 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4306 if not fRc:
4307 break;
4308 fRc, _ = oTest.createSession('testGuestCtrlFileRemove: Test #%d' % (i,));
4309 if fRc is False:
4310 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4311 break;
4312 fRc = oTest.execute(self) and fRc;
4313 fRc = oTest.closeSession() and fRc;
4314
4315 if fRc is True:
4316 oCurTest = tdTestDirRead();
4317 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4318 if fRc:
4319 fRc, oCurGuestSession = oCurTest.createSession('remove final');
4320 if fRc is True:
4321
4322 #
4323 # Delete all the files in the many subdir of the test set.
4324 #
4325 reporter.log('Deleting the file in "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
4326 for oFile in self.oTestFiles.oManyDir.aoChildren:
4327 reporter.log2('"%s"' % (limitString(oFile.sPath),));
4328 try:
4329 if self.oTstDrv.fpApiVer >= 5.0:
4330 oCurGuestSession.fsObjRemove(oFile.sPath);
4331 else:
4332 oCurGuestSession.fileRemove(oFile.sPath);
4333 except:
4334 fRc = reporter.errorXcpt('Removing "%s" failed' % (oFile.sPath,));
4335
4336 # Remove the directory itself to verify that we've removed all the files in it:
4337 reporter.log('Removing the directory "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
4338 try:
4339 oCurGuestSession.directoryRemove(self.oTestFiles.oManyDir.sPath);
4340 except:
4341 fRc = reporter.errorXcpt('Removing directory "%s" failed' % (self.oTestFiles.oManyDir.sPath,));
4342
4343 #
4344 # Recursively delete the entire test file tree from the root up.
4345 #
4346 # Note! On unix we cannot delete the root dir itself since it is residing
4347 # in /var/tmp where only the owner may delete it. Root is the owner.
4348 #
4349 if oTestVm.isWindows() or oTestVm.isOS2():
4350 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,];
4351 else:
4352 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,];
4353 try:
4354 oProgress = oCurGuestSession.directoryRemoveRecursive(self.oTestFiles.oRoot.sPath, afFlags);
4355 except:
4356 fRc = reporter.errorXcpt('Removing tree "%s" failed' % (self.oTestFiles.oRoot.sPath,));
4357 else:
4358 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv,
4359 "remove-tree-root: %s" % (self.oTestFiles.oRoot.sPath,));
4360 reporter.log2('waiting ...')
4361 oWrappedProgress.wait();
4362 reporter.log2('isSuccess=%s' % (oWrappedProgress.isSuccess(),));
4363 if not oWrappedProgress.isSuccess():
4364 fRc = oWrappedProgress.logResult();
4365
4366 fRc = oCurTest.closeSession() and fRc;
4367
4368 return (fRc, oTxsSession);
4369
4370
4371 def testGuestCtrlFileStat(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4372 """
4373 Tests querying file information through stat.
4374 """
4375
4376 # Basic stuff, existing stuff.
4377 aoTests = [
4378 tdTestSessionEx([
4379 tdStepStatDir('.'),
4380 tdStepStatDir('..'),
4381 tdStepStatDir(self.oTstDrv.getGuestTempDir(oTestVm)),
4382 tdStepStatDir(self.oTstDrv.getGuestSystemDir(oTestVm)),
4383 tdStepStatDirEx(self.oTestFiles.oRoot),
4384 tdStepStatDirEx(self.oTestFiles.oEmptyDir),
4385 tdStepStatDirEx(self.oTestFiles.oTreeDir),
4386 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4387 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4388 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4389 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4390 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4391 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4392 tdStepStatFile(self.oTstDrv.getGuestSystemFileForReading(oTestVm)),
4393 tdStepStatFile(self.oTstDrv.getGuestSystemShell(oTestVm)),
4394 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4395 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4396 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4397 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4398 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4399 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4400 ]),
4401 ];
4402
4403 # None existing stuff.
4404 sSysDir = self.oTstDrv.getGuestSystemDir(oTestVm);
4405 sSep = oTestVm.pathSep();
4406 aoTests += [
4407 tdTestSessionEx([
4408 tdStepStatFileNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory')),
4409 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory') + sSep),
4410 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', '.')),
4411 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory')),
4412 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory') + sSep),
4413 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory', '.')),
4414 #tdStepStatPathNotFound('N:\\'), # ASSUMES nothing mounted on N:!
4415 #tdStepStatPathNotFound('\\\\NoSuchUncServerName\\NoSuchShare'),
4416 ]),
4417 ];
4418 # Invalid parameter check.
4419 aoTests += [ tdTestSessionEx([ tdStepStat('', vbox.ComError.E_INVALIDARG), ]), ];
4420
4421 #
4422 # Execute the tests.
4423 #
4424 fRc, oTxsSession = tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession,
4425 oTestVm, 'FsStat');
4426 #
4427 # Test the full test file set.
4428 #
4429 if self.oTstDrv.fpApiVer < 5.0:
4430 return (fRc, oTxsSession);
4431
4432 oTest = tdTestGuestCtrlBase();
4433 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4434 if not fRc:
4435 return (False, oTxsSession);
4436 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4437 if fRc2 is not True:
4438 return (False, oTxsSession);
4439
4440 for oFsObj in self.oTestFiles.dPaths.values():
4441 reporter.log2('testGuestCtrlFileStat: %s sPath=%s'
4442 % ('file' if isinstance(oFsObj, testfileset.TestFile) else 'dir ', limitString(oFsObj.sPath),));
4443
4444 # Query the information:
4445 try:
4446 oFsInfo = oGuestSession.fsObjQueryInfo(oFsObj.sPath, False);
4447 except:
4448 fRc = reporter.errorXcpt('sPath=%s type=%s: fsObjQueryInfo trouble!' % (oFsObj.sPath, type(oFsObj),));
4449 continue;
4450 if oFsInfo is None:
4451 fRc = reporter.error('sPath=%s type=%s: No info object returned!' % (oFsObj.sPath, type(oFsObj),));
4452 continue;
4453
4454 # Check attributes:
4455 try:
4456 eType = oFsInfo.type;
4457 cbObject = oFsInfo.objectSize;
4458 except:
4459 fRc = reporter.errorXcpt('sPath=%s type=%s: attribute access trouble!' % (oFsObj.sPath, type(oFsObj),));
4460 continue;
4461
4462 if isinstance(oFsObj, testfileset.TestFile):
4463 if eType != vboxcon.FsObjType_File:
4464 fRc = reporter.error('sPath=%s type=file: eType=%s, expected %s!'
4465 % (oFsObj.sPath, eType, vboxcon.FsObjType_File));
4466 if cbObject != oFsObj.cbContent:
4467 fRc = reporter.error('sPath=%s type=file: cbObject=%s, expected %s!'
4468 % (oFsObj.sPath, cbObject, oFsObj.cbContent));
4469 fFileExists = True;
4470 fDirExists = False;
4471 elif isinstance(oFsObj, testfileset.TestDir):
4472 if eType != vboxcon.FsObjType_Directory:
4473 fRc = reporter.error('sPath=%s type=dir: eType=%s, expected %s!'
4474 % (oFsObj.sPath, eType, vboxcon.FsObjType_Directory));
4475 fFileExists = False;
4476 fDirExists = True;
4477 else:
4478 fRc = reporter.error('sPath=%s type=%s: Unexpected oFsObj type!' % (oFsObj.sPath, type(oFsObj),));
4479 continue;
4480
4481 # Check the directoryExists and fileExists results too.
4482 try:
4483 fExistsResult = oGuestSession.fileExists(oFsObj.sPath, False);
4484 except:
4485 fRc = reporter.errorXcpt('sPath=%s type=%s: fileExists trouble!' % (oFsObj.sPath, type(oFsObj),));
4486 else:
4487 if fExistsResult != fFileExists:
4488 fRc = reporter.error('sPath=%s type=%s: fileExists returned %s, expected %s!'
4489 % (oFsObj.sPath, type(oFsObj), fExistsResult, fFileExists));
4490 try:
4491 fExistsResult = oGuestSession.directoryExists(oFsObj.sPath, False);
4492 except:
4493 fRc = reporter.errorXcpt('sPath=%s type=%s: directoryExists trouble!' % (oFsObj.sPath, type(oFsObj),));
4494 else:
4495 if fExistsResult != fDirExists:
4496 fRc = reporter.error('sPath=%s type=%s: directoryExists returned %s, expected %s!'
4497 % (oFsObj.sPath, type(oFsObj), fExistsResult, fDirExists));
4498
4499 fRc = oTest.closeSession() and fRc;
4500 return (fRc, oTxsSession);
4501
4502 def testGuestCtrlFileOpen(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4503 """
4504 Tests opening guest files.
4505 """
4506 if self.oTstDrv.fpApiVer < 5.0:
4507 reporter.log('Skipping because of pre 5.0 API');
4508 return None;
4509
4510 #
4511 # Paths.
4512 #
4513 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
4514 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
4515 asFiles = [
4516 oTestVm.pathJoin(sTempDir, 'file-open-0'),
4517 oTestVm.pathJoin(sTempDir, 'file-open-1'),
4518 oTestVm.pathJoin(sTempDir, 'file-open-2'),
4519 oTestVm.pathJoin(sTempDir, 'file-open-3'),
4520 oTestVm.pathJoin(sTempDir, 'file-open-4'),
4521 ];
4522 asNonEmptyFiles = [
4523 oTestVm.pathJoin(sTempDir, 'file-open-10'),
4524 oTestVm.pathJoin(sTempDir, 'file-open-11'),
4525 oTestVm.pathJoin(sTempDir, 'file-open-12'),
4526 oTestVm.pathJoin(sTempDir, 'file-open-13'),
4527 ];
4528 sContent = 'abcdefghijklmnopqrstuvwxyz0123456789';
4529 for sFile in asNonEmptyFiles:
4530 if oTxsSession.syncUploadString(sContent, sFile, 0o666) is not True:
4531 return reporter.error('Failed to create "%s" via TXS' % (sFile,));
4532
4533 #
4534 # The tests.
4535 #
4536 atTests = [
4537 # Invalid stuff.
4538 [ tdTestFileOpen(sFile = ''), tdTestResultFailure() ],
4539 # Wrong open mode.
4540 [ tdTestFileOpen(sFile = sFileForReading, eAccessMode = -1), tdTestResultFailure() ],
4541 # Wrong disposition.
4542 [ tdTestFileOpen(sFile = sFileForReading, eAction = -1), tdTestResultFailure() ],
4543 # Non-existing file or path.
4544 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir')), tdTestResultFailure() ],
4545 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4546 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4547 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4548 eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4549 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4550 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4551 eAccessMode = vboxcon.FileAccessMode_ReadWrite,
4552 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4553 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-dir', 'no-such-file')), tdTestResultFailure() ],
4554 ];
4555 if self.oTstDrv.fpApiVer > 5.2: # Fixed since 6.0.
4556 atTests.extend([
4557 # Wrong type:
4558 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
4559 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestSystemDir(oTestVm)), tdTestResultFailure() ],
4560 ]);
4561 atTests.extend([
4562 # O_EXCL and such:
4563 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew,
4564 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
4565 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew), tdTestResultFailure() ],
4566 # Open a file.
4567 [ tdTestFileOpen(sFile = sFileForReading), tdTestResultSuccess() ],
4568 [ tdTestFileOpen(sFile = sFileForReading,
4569 eAction = vboxcon.FileOpenAction_OpenOrCreate), tdTestResultSuccess() ],
4570 # Create a new file.
4571 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
4572 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4573 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
4574 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
4575 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExisting,
4576 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4577 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4578 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4579 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenOrCreate,
4580 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4581 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExistingTruncated,
4582 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4583 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4584 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4585 # Open or create a new file.
4586 [ tdTestFileOpenCheckSize(sFile = asFiles[1], eAction = vboxcon.FileOpenAction_OpenOrCreate,
4587 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4588 # Create or replace a new file.
4589 [ tdTestFileOpenCheckSize(sFile = asFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4590 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4591 # Create and append to file (weird stuff).
4592 [ tdTestFileOpenCheckSize(sFile = asFiles[3], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4593 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4594 [ tdTestFileOpenCheckSize(sFile = asFiles[4], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4595 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4596 # Open the non-empty files in non-destructive modes.
4597 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent)), tdTestResultSuccess() ],
4598 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4599 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4600 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4601 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4602
4603 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
4604 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4605 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4606 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4607 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4608 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4609 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4610 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4611 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4612
4613 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
4614 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4615 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4616 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4617 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4618 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4619 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4620 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4621 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4622
4623 # Now the destructive stuff:
4624 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4625 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultSuccess() ],
4626 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4627 eAction = vboxcon.FileOpenAction_CreateOrReplace), tdTestResultSuccess() ],
4628 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4629 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4630 ]);
4631
4632 #
4633 # Do the testing.
4634 #
4635 fRc = True;
4636 for (i, tTest) in enumerate(atTests):
4637 oCurTest = tTest[0] # type: tdTestFileOpen
4638 oCurRes = tTest[1] # type: tdTestResult
4639
4640 reporter.log('Testing #%d: %s - sFile="%s", eAccessMode=%d, eAction=%d, (%s, %s, %s) ...'
4641 % (i, oCurTest.__class__.__name__, oCurTest.sFile, oCurTest.eAccessMode, oCurTest.eAction,
4642 oCurTest.eSharing, oCurTest.fCreationMode, oCurTest.afOpenFlags,));
4643
4644 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4645 if not fRc:
4646 break;
4647 fRc, _ = oCurTest.createSession('testGuestCtrlFileOpen: Test #%d' % (i,));
4648 if fRc is not True:
4649 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4650 break;
4651
4652 fRc2 = oCurTest.doSteps(oCurRes.fRc, self);
4653 if fRc2 != oCurRes.fRc:
4654 fRc = reporter.error('Test #%d result mismatch: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
4655
4656 fRc = oCurTest.closeSession() and fRc;
4657
4658 return (fRc, oTxsSession);
4659
4660
4661 def testGuestCtrlFileRead(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-branches,too-many-statements
4662 """
4663 Tests reading from guest files.
4664 """
4665 if self.oTstDrv.fpApiVer < 5.0:
4666 reporter.log('Skipping because of pre 5.0 API');
4667 return None;
4668
4669 #
4670 # Do everything in one session.
4671 #
4672 oTest = tdTestGuestCtrlBase();
4673 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4674 if not fRc:
4675 return (False, oTxsSession);
4676 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4677 if fRc2 is not True:
4678 return (False, oTxsSession);
4679
4680 #
4681 # Create a really big zero filled, up to 1 GiB, adding it to the list of
4682 # files from the set.
4683 #
4684 # Note! This code sucks a bit because we don't have a working setSize nor
4685 # any way to figure out how much free space there is in the guest.
4686 #
4687 aoExtraFiles = [];
4688 sBigName = self.oTestFiles.generateFilenameEx();
4689 sBigPath = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sBigName);
4690 fRc = True;
4691 try:
4692 oFile = oGuestSession.fileOpenEx(sBigPath, vboxcon.FileAccessMode_ReadWrite, vboxcon.FileOpenAction_CreateOrReplace,
4693 vboxcon.FileSharingMode_All, 0, []);
4694 except:
4695 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4696 else:
4697 # Does setSize work now?
4698 fUseFallback = True;
4699 try:
4700 oFile.setSize(0);
4701 oFile.setSize(64);
4702 fUseFallback = False;
4703 except:
4704 reporter.logXcpt();
4705
4706 # Grow the file till we hit trouble, typical VERR_DISK_FULL, then
4707 # reduce the file size if we have a working setSize.
4708 cbBigFile = 0;
4709 while cbBigFile < (1024 + 32)*1024*1024:
4710 if not fUseFallback:
4711 cbBigFile += 16*1024*1024;
4712 try:
4713 oFile.setSize(cbBigFile);
4714 except Exception:
4715 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4716 try:
4717 cbBigFile -= 16*1024*1024;
4718 oFile.setSize(cbBigFile);
4719 except:
4720 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4721 break;
4722 else:
4723 cbBigFile += 32*1024*1024;
4724 try:
4725 oFile.seek(cbBigFile, vboxcon.FileSeekOrigin_Begin);
4726 oFile.write(bytearray(1), 60*1000);
4727 except:
4728 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4729 break;
4730 try:
4731 cbBigFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4732 except:
4733 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4734 try:
4735 oFile.close();
4736 except:
4737 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4738 if fRc is True:
4739 reporter.log('Big file: %s bytes: %s' % (cbBigFile, sBigPath,));
4740 aoExtraFiles.append(testfileset.TestFileZeroFilled(None, sBigPath, cbBigFile));
4741 else:
4742 try:
4743 oGuestSession.fsObjRemove(sBigPath);
4744 except:
4745 reporter.errorXcpt('fsObjRemove(sBigName=%s)' % (sBigPath,));
4746
4747 #
4748 # Open and read all the files in the test file set.
4749 #
4750 for oTestFile in aoExtraFiles + self.oTestFiles.aoFiles: # type: testfileset.TestFile
4751 reporter.log2('Test file: %s bytes, "%s" ...' % (oTestFile.cbContent, limitString(oTestFile.sPath),));
4752
4753 #
4754 # Open it:
4755 #
4756 try:
4757 oFile = oGuestSession.fileOpenEx(oTestFile.sPath, vboxcon.FileAccessMode_ReadOnly,
4758 vboxcon.FileOpenAction_OpenExisting, vboxcon.FileSharingMode_All, 0, []);
4759 except:
4760 fRc = reporter.errorXcpt('sPath=%s' % (oTestFile.sPath, ));
4761 continue;
4762
4763 #
4764 # Read the file in different sized chunks:
4765 #
4766 if oTestFile.cbContent < 128:
4767 acbChunks = xrange(1,128);
4768 elif oTestFile.cbContent < 1024:
4769 acbChunks = (2048, 127, 63, 32, 29, 17, 16, 15, 9);
4770 elif oTestFile.cbContent < 8*1024*1024:
4771 acbChunks = (128*1024, 32*1024, 8191, 255);
4772 else:
4773 acbChunks = (768*1024, 128*1024);
4774
4775 reporter.log2('Chunked reads');
4776
4777 for cbChunk in acbChunks:
4778 # Read the whole file straight thru:
4779 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... cbChunk=%s' % (cbChunk,));
4780 offFile = 0;
4781 cReads = 0;
4782 while offFile <= oTestFile.cbContent:
4783 try:
4784 abRead = oFile.read(cbChunk, 30*1000);
4785 except:
4786 fRc = reporter.errorXcpt('%s: offFile=%s cbChunk=%s cbContent=%s'
4787 % (oTestFile.sPath, offFile, cbChunk, oTestFile.cbContent));
4788 break;
4789 cbRead = len(abRead);
4790 if cbRead == 0 and offFile == oTestFile.cbContent:
4791 break;
4792 if cbRead <= 0:
4793 fRc = reporter.error('%s @%s: cbRead=%s, cbContent=%s'
4794 % (oTestFile.sPath, offFile, cbRead, oTestFile.cbContent));
4795 break;
4796 if not oTestFile.equalMemory(abRead, offFile):
4797 fRc = reporter.error('%s: read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead));
4798 break;
4799 offFile += cbRead;
4800 cReads += 1;
4801 if cReads > 8192:
4802 break;
4803
4804 # Seek to start of file.
4805 try:
4806 offFile = oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4807 except:
4808 fRc = reporter.errorXcpt('%s: error seeking to start of file' % (oTestFile.sPath,));
4809 break;
4810 if offFile != 0:
4811 fRc = reporter.error('%s: seek to start of file returned %u, expected 0' % (oTestFile.sPath, offFile));
4812 break;
4813
4814 #
4815 # Random reads.
4816 #
4817 reporter.log2('Random reads (seek)');
4818 for _ in xrange(8):
4819 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4820 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4821 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s' % (offFile, cbToRead,));
4822
4823 try:
4824 offActual = oFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
4825 except:
4826 fRc = reporter.errorXcpt('%s: error seeking to %s' % (oTestFile.sPath, offFile));
4827 break;
4828 if offActual != offFile:
4829 fRc = reporter.error('%s: seek(%s,Begin) -> %s, expected %s'
4830 % (oTestFile.sPath, offFile, offActual, offFile));
4831 break;
4832
4833 try:
4834 abRead = oFile.read(cbToRead, 30*1000);
4835 except:
4836 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4837 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4838 cbRead = 0;
4839 else:
4840 cbRead = len(abRead);
4841 if not oTestFile.equalMemory(abRead, offFile):
4842 fRc = reporter.error('%s: random read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4843
4844 try:
4845 offActual = oFile.offset;
4846 except:
4847 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4848 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4849 else:
4850 if offActual != offFile + cbRead:
4851 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4852 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4853 try:
4854 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4855 except:
4856 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4857 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4858 else:
4859 if offActual != offFile + cbRead:
4860 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4861 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4862
4863 #
4864 # Random reads using readAt.
4865 #
4866 reporter.log2('Random reads (readAt)');
4867 for _ in xrange(12):
4868 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4869 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4870 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s (readAt)' % (offFile, cbToRead,));
4871
4872 try:
4873 abRead = oFile.readAt(offFile, cbToRead, 30*1000);
4874 except:
4875 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4876 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4877 cbRead = 0;
4878 else:
4879 cbRead = len(abRead);
4880 if not oTestFile.equalMemory(abRead, offFile):
4881 fRc = reporter.error('%s: random readAt mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4882
4883 try:
4884 offActual = oFile.offset;
4885 except:
4886 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4887 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4888 else:
4889 if offActual != offFile + cbRead:
4890 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4891 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4892
4893 try:
4894 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4895 except:
4896 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4897 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4898 else:
4899 if offActual != offFile + cbRead:
4900 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4901 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4902
4903 #
4904 # A few negative things.
4905 #
4906
4907 # Zero byte reads -> E_INVALIDARG.
4908 reporter.log2('Zero byte reads');
4909 try:
4910 abRead = oFile.read(0, 30*1000);
4911 except Exception as oXcpt:
4912 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4913 fRc = reporter.errorXcpt('read(0,30s) did not raise E_INVALIDARG as expected!');
4914 else:
4915 fRc = reporter.error('read(0,30s) did not fail!');
4916
4917 try:
4918 abRead = oFile.readAt(0, 0, 30*1000);
4919 except Exception as oXcpt:
4920 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4921 fRc = reporter.errorXcpt('readAt(0,0,30s) did not raise E_INVALIDARG as expected!');
4922 else:
4923 fRc = reporter.error('readAt(0,0,30s) did not fail!');
4924
4925 # See what happens when we read 1GiB. We should get a max of 1MiB back.
4926 ## @todo Document this behaviour in VirtualBox.xidl.
4927 reporter.log2('1GB reads');
4928 try:
4929 oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4930 except:
4931 fRc = reporter.error('seek(0)');
4932 try:
4933 abRead = oFile.read(1024*1024*1024, 30*1000);
4934 except:
4935 fRc = reporter.errorXcpt('read(1GiB,30s)');
4936 else:
4937 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4938 fRc = reporter.error('Expected read(1GiB,30s) to return %s bytes, got %s bytes instead'
4939 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4940
4941 try:
4942 abRead = oFile.readAt(0, 1024*1024*1024, 30*1000);
4943 except:
4944 fRc = reporter.errorXcpt('readAt(0,1GiB,30s)');
4945 else:
4946 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4947 reporter.error('Expected readAt(0, 1GiB,30s) to return %s bytes, got %s bytes instead'
4948 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4949
4950 #
4951 # Check stat info on the file as well as querySize.
4952 #
4953 if self.oTstDrv.fpApiVer > 5.2:
4954 try:
4955 oFsObjInfo = oFile.queryInfo();
4956 except:
4957 fRc = reporter.errorXcpt('%s: queryInfo()' % (oTestFile.sPath,));
4958 else:
4959 if oFsObjInfo is None:
4960 fRc = reporter.error('IGuestFile::queryInfo returned None');
4961 else:
4962 try:
4963 cbFile = oFsObjInfo.objectSize;
4964 except:
4965 fRc = reporter.errorXcpt();
4966 else:
4967 if cbFile != oTestFile.cbContent:
4968 fRc = reporter.error('%s: queryInfo returned incorrect file size: %s, expected %s'
4969 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4970
4971 try:
4972 cbFile = oFile.querySize();
4973 except:
4974 fRc = reporter.errorXcpt('%s: querySize()' % (oTestFile.sPath,));
4975 else:
4976 if cbFile != oTestFile.cbContent:
4977 fRc = reporter.error('%s: querySize returned incorrect file size: %s, expected %s'
4978 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4979
4980 #
4981 # Use seek to test the file size and do a few other end-relative seeks.
4982 #
4983 try:
4984 cbFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4985 except:
4986 fRc = reporter.errorXcpt('%s: seek(0,End)' % (oTestFile.sPath,));
4987 else:
4988 if cbFile != oTestFile.cbContent:
4989 fRc = reporter.error('%s: seek(0,End) returned incorrect file size: %s, expected %s'
4990 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4991 if oTestFile.cbContent > 0:
4992 for _ in xrange(5):
4993 offSeek = self.oTestFiles.oRandom.randrange(oTestFile.cbContent + 1);
4994 try:
4995 offFile = oFile.seek(-offSeek, vboxcon.FileSeekOrigin_End);
4996 except:
4997 fRc = reporter.errorXcpt('%s: seek(%s,End)' % (oTestFile.sPath, -offSeek,));
4998 else:
4999 if offFile != oTestFile.cbContent - offSeek:
5000 fRc = reporter.error('%s: seek(%s,End) returned incorrect offset: %s, expected %s (cbContent=%s)'
5001 % (oTestFile.sPath, -offSeek, offSeek, oTestFile.cbContent - offSeek,
5002 oTestFile.cbContent,));
5003
5004 #
5005 # Close it and we're done with this file.
5006 #
5007 try:
5008 oFile.close();
5009 except:
5010 fRc = reporter.errorXcpt('%s: error closing the file' % (oTestFile.sPath,));
5011
5012 #
5013 # Clean up.
5014 #
5015 for oTestFile in aoExtraFiles:
5016 try:
5017 oGuestSession.fsObjRemove(sBigPath);
5018 except:
5019 fRc = reporter.errorXcpt('fsObjRemove(%s)' % (sBigPath,));
5020
5021 fRc = oTest.closeSession() and fRc;
5022
5023 return (fRc, oTxsSession);
5024
5025
5026 def testGuestCtrlFileWrite(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5027 """
5028 Tests writing to guest files.
5029 """
5030 if self.oTstDrv.fpApiVer < 5.0:
5031 reporter.log('Skipping because of pre 5.0 API');
5032 return None;
5033
5034 #
5035 # The test file and its content.
5036 #
5037 sFile = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'gctrl-write-1');
5038 abContent = bytearray(0);
5039
5040 #
5041 # The tests.
5042 #
5043 def randBytes(cbHowMany):
5044 """ Returns an bytearray of random bytes. """
5045 return bytearray(self.oTestFiles.oRandom.getrandbits(8) for _ in xrange(cbHowMany));
5046
5047 aoTests = [
5048 # Write at end:
5049 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_CreateNew, abContent = abContent,
5050 atChunks = [(None, randBytes(1)), (None, randBytes(77)), (None, randBytes(98)),]),
5051 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1+77+98), # 176
5052 # Appending:
5053 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
5054 atChunks = [(None, randBytes(255)), (None, randBytes(33)),]),
5055 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 176 + 255+33), # 464
5056 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
5057 atChunks = [(10, randBytes(44)),]),
5058 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 464 + 44), # 508
5059 # Write within existing:
5060 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_OpenExisting, abContent = abContent,
5061 atChunks = [(0, randBytes(1)), (50, randBytes(77)), (255, randBytes(199)),]),
5062 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 508),
5063 # Writing around and over the end:
5064 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent,
5065 atChunks = [(500, randBytes(9)), (508, randBytes(15)), (512, randBytes(12)),]),
5066 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 512+12),
5067
5068 # writeAt appending:
5069 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5070 atChunks = [(0, randBytes(23)), (6, randBytes(1018)),]),
5071 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 6+1018), # 1024
5072 # writeAt within existing:
5073 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5074 atChunks = [(1000, randBytes(23)), (1, randBytes(990)),]),
5075 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1024),
5076 # writeAt around and over the end:
5077 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5078 atChunks = [(1024, randBytes(63)), (1080, randBytes(968)),]),
5079 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1080+968), # 2048
5080
5081 # writeAt beyond the end (gap is filled with zeros):
5082 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True, atChunks = [(3070, randBytes(2)),]),
5083 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 3072),
5084 # write beyond the end (gap is filled with zeros):
5085 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, atChunks = [(4090, randBytes(6)),]),
5086 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 4096),
5087 ];
5088
5089 for (i, oCurTest) in enumerate(aoTests):
5090 reporter.log('Testing #%d: %s ...' % (i, oCurTest.toString(),));
5091 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5092 if not fRc:
5093 break;
5094 fRc, _ = oCurTest.createSession('testGuestCtrlFileWrite: Test #%d' % (i,));
5095 if fRc is not True:
5096 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5097 break;
5098
5099 fRc2 = oCurTest.doSteps(True, self);
5100 if fRc2 is not True:
5101 fRc = reporter.error('Test #%d failed!' % (i,));
5102
5103 fRc = oCurTest.closeSession() and fRc;
5104
5105 #
5106 # Cleanup
5107 #
5108 if oTxsSession.syncRmFile(sFile) is not True:
5109 fRc = reporter.error('Failed to remove write-test file: %s' % (sFile, ));
5110
5111 return (fRc, oTxsSession);
5112
5113 @staticmethod
5114 def __generateFile(sName, cbFile):
5115 """ Helper for generating a file with a given size. """
5116 with open(sName, 'wb') as oFile:
5117 while cbFile > 0:
5118 cb = cbFile if cbFile < 256*1024 else 256*1024;
5119 oFile.write(bytearray(random.getrandbits(8) for _ in xrange(cb)));
5120 cbFile -= cb;
5121 return True;
5122
5123 def testGuestCtrlCopyTo(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5124 """
5125 Tests copying files from host to the guest.
5126 """
5127
5128 #
5129 # Paths and test files.
5130 #
5131 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, 'copyto');
5132 sScratchTestFilesHst = os.path.join(sScratchHst, self.oTestFiles.sSubDir);
5133 sScratchEmptyDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oEmptyDir.sName);
5134 sScratchNonEmptyDirHst = self.oTestFiles.chooseRandomDirFromTree().buildPath(sScratchHst, os.path.sep);
5135 sScratchTreeDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oTreeDir.sName);
5136
5137 sScratchGst = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'copyto');
5138 sScratchDstDir1Gst = oTestVm.pathJoin(sScratchGst, 'dstdir1');
5139 sScratchDstDir2Gst = oTestVm.pathJoin(sScratchGst, 'dstdir2');
5140 sScratchDstDir3Gst = oTestVm.pathJoin(sScratchGst, 'dstdir3');
5141 sScratchDstDir4Gst = oTestVm.pathJoin(sScratchGst, 'dstdir4');
5142 sScratchDotDotDirGst = oTestVm.pathJoin(sScratchGst, '..');
5143 #sScratchGstNotExist = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-file-or-directory');
5144 sScratchHstNotExist = os.path.join(self.oTstDrv.sScratchPath, 'no-such-file-or-directory');
5145 sScratchGstPathNotFound = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-directory', 'or-file');
5146 #sScratchHstPathNotFound = os.path.join(self.oTstDrv.sScratchPath, 'no-such-directory', 'or-file');
5147
5148 if oTestVm.isWindows() or oTestVm.isOS2():
5149 sScratchGstInvalid = "?*|<invalid-name>";
5150 else:
5151 sScratchGstInvalid = None;
5152 if utils.getHostOs() in ('win', 'os2'):
5153 sScratchHstInvalid = "?*|<invalid-name>";
5154 else:
5155 sScratchHstInvalid = None;
5156
5157 for sDir in (sScratchGst, sScratchDstDir1Gst, sScratchDstDir2Gst, sScratchDstDir3Gst, sScratchDstDir4Gst):
5158 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
5159 return reporter.error('TXS failed to create directory "%s"!' % (sDir,));
5160
5161 # Put the test file set under sScratchHst.
5162 if os.path.exists(sScratchHst):
5163 if base.wipeDirectory(sScratchHst) != 0:
5164 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
5165 else:
5166 try:
5167 os.mkdir(sScratchHst);
5168 except:
5169 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
5170 if self.oTestFiles.writeToDisk(sScratchHst) is not True:
5171 return reporter.error('Filed to write test files to "%s" on the host!' % (sScratchHst,));
5172
5173 # If for whatever reason the directory tree does not exist on the host, let us know.
5174 # Copying an non-existing tree *will* fail the tests which otherwise should succeed!
5175 assert os.path.exists(sScratchTreeDirHst);
5176
5177 # Generate a test file in 32MB to 64 MB range.
5178 sBigFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-random.data');
5179 cbBigFileHst = random.randrange(32*1024*1024, 64*1024*1024);
5180 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
5181 cbLeft = cbBigFileHst;
5182 try:
5183 self.__generateFile(sBigFileHst, cbBigFileHst);
5184 except:
5185 return reporter.errorXcpt('sBigFileHst=%s cbBigFileHst=%s cbLeft=%s' % (sBigFileHst, cbBigFileHst, cbLeft,));
5186 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
5187
5188 # Generate an empty file on the host that we can use to save space in the guest.
5189 sEmptyFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-empty.data');
5190 try:
5191 open(sEmptyFileHst, "wb").close(); # pylint: disable=consider-using-with
5192 except:
5193 return reporter.errorXcpt('sEmptyFileHst=%s' % (sEmptyFileHst,));
5194
5195 # os.path.join() is too clever for "..", so we just build up the path here ourselves.
5196 sScratchDotDotFileHst = sScratchHst + os.path.sep + '..' + os.path.sep + 'gctrl-empty.data';
5197
5198 #
5199 # Tests.
5200 #
5201 atTests = [
5202 # Nothing given:
5203 [ tdTestCopyToFile(), tdTestResultFailure() ],
5204 [ tdTestCopyToDir(), tdTestResultFailure() ],
5205 # Only source given:
5206 [ tdTestCopyToFile(sSrc = sBigFileHst), tdTestResultFailure() ],
5207 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst), tdTestResultFailure() ],
5208 # Only destination given:
5209 [ tdTestCopyToFile(sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')), tdTestResultFailure() ],
5210 [ tdTestCopyToDir( sDst = sScratchGst), tdTestResultFailure() ],
5211 # Both given, but invalid flags.
5212 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst, afFlags = [ 0x40000000, ] ), tdTestResultFailure() ],
5213 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGst, afFlags = [ 0x40000000, ] ),
5214 tdTestResultFailure() ],
5215 ];
5216 atTests.extend([
5217 # Non-existing source, but no destination:
5218 [ tdTestCopyToFile(sSrc = sScratchHstNotExist), tdTestResultFailure() ],
5219 [ tdTestCopyToDir( sSrc = sScratchHstNotExist), tdTestResultFailure() ],
5220 # Valid sources, but destination path not found:
5221 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
5222 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
5223 # Valid destination, but source file/dir not found:
5224 [ tdTestCopyToFile(sSrc = sScratchHstNotExist, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
5225 tdTestResultFailure() ],
5226 [ tdTestCopyToDir( sSrc = sScratchHstNotExist, sDst = sScratchGst), tdTestResultFailure() ],
5227 # Wrong type:
5228 [ tdTestCopyToFile(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
5229 tdTestResultFailure() ],
5230 [ tdTestCopyToDir( sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultFailure() ],
5231 ]);
5232 # Invalid characters in destination or source path:
5233 if sScratchGstInvalid is not None:
5234 atTests.extend([
5235 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
5236 tdTestResultFailure() ],
5237 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
5238 tdTestResultFailure() ],
5239 ]);
5240 if sScratchHstInvalid is not None:
5241 atTests.extend([
5242 [ tdTestCopyToFile(sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
5243 tdTestResultFailure() ],
5244 [ tdTestCopyToDir( sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
5245 tdTestResultFailure() ],
5246 ]);
5247
5248 #
5249 # Single file handling.
5250 #
5251 atTests.extend([
5252 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')),
5253 tdTestResultSuccess() ],
5254 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
5255 tdTestResultSuccess() ],
5256 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
5257 tdTestResultSuccess() ],
5258 ]);
5259 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
5260 atTests.extend([
5261 # Should succeed, as the file isn't there yet on the destination.
5262 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst + oTestVm.pathSep()), tdTestResultSuccess() ],
5263 # Overwrite the existing file.
5264 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst + oTestVm.pathSep()), tdTestResultSuccess() ],
5265 # Same file, but with a different name on the destination.
5266 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, os.path.split(sBigFileHst)[1])),
5267 tdTestResultSuccess() ], # Overwrite
5268 ]);
5269
5270 if oTestVm.isWindows():
5271 # Copy to a Windows alternative data stream (ADS).
5272 atTests.extend([
5273 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
5274 tdTestResultSuccess() ],
5275 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
5276 tdTestResultSuccess() ],
5277 ]);
5278
5279 #
5280 # Directory handling.
5281 #
5282 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
5283 atTests.extend([
5284 # Without a trailing slash added to the destination this should fail,
5285 # as the destination directory already exists.
5286 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst), tdTestResultFailure() ],
5287 # Same existing host directory, but this time with DirectoryCopyFlag_CopyIntoExisting set.
5288 # This should copy the contents of oEmptyDirGst to sScratchDstDir1Gst (empty, but anyway).
5289 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
5290 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5291 # Try again.
5292 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
5293 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5294 # With a trailing slash added to the destination, copy the empty guest directory
5295 # (should end up as sScratchDstDir2Gst/empty):
5296 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
5297 tdTestResultSuccess() ],
5298 # Repeat -- this time it should fail, as the destination directory already exists (and
5299 # DirectoryCopyFlag_CopyIntoExisting is not specified):
5300 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
5301 tdTestResultFailure() ],
5302 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work (again).
5303 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
5304 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5305 # Copy with a different destination name just for the heck of it:
5306 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchDstDir2Gst, 'empty2')),
5307 tdTestResultSuccess() ],
5308 ]);
5309 atTests.extend([
5310 # Now the same using a directory with files in it:
5311 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
5312 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5313 # Again.
5314 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
5315 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5316 ]);
5317 atTests.extend([
5318 # Copy the entire test tree:
5319 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep()),
5320 tdTestResultSuccess() ],
5321 # Again, should fail this time.
5322 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep()),
5323 tdTestResultFailure() ],
5324 # Works again, as DirectoryCopyFlag_CopyIntoExisting is specified.
5325 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep(),
5326 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5327 ]);
5328 #
5329 # Dotdot path handling.
5330 #
5331 if self.oTstDrv.fpApiVer >= 6.1:
5332 atTests.extend([
5333 # Test if copying stuff from a host dotdot ".." directory works.
5334 [ tdTestCopyToFile(sSrc = sScratchDotDotFileHst, sDst = sScratchDstDir1Gst + oTestVm.pathSep()),
5335 tdTestResultSuccess() ],
5336 # Test if copying stuff from the host to a guest's dotdot ".." directory works.
5337 # That should fail on destinations.
5338 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = sScratchDotDotDirGst), tdTestResultFailure() ],
5339 ]);
5340
5341 fRc = True;
5342 for (i, tTest) in enumerate(atTests):
5343 oCurTest = tTest[0]; # tdTestCopyTo
5344 oCurRes = tTest[1]; # tdTestResult
5345 reporter.log('Testing #%d, sSrc=%s, sDst=%s, afFlags=%s ...'
5346 % (i, limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags));
5347
5348 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5349 if not fRc:
5350 break;
5351 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyTo: Test #%d' % (i,));
5352 if fRc is not True:
5353 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5354 break;
5355
5356 fRc2 = False;
5357 if isinstance(oCurTest, tdTestCopyToFile):
5358 fRc2 = self.gctrlCopyFileTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
5359 else:
5360 fRc2 = self.gctrlCopyDirTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
5361 if fRc2 is not oCurRes.fRc:
5362 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
5363
5364 fRc = oCurTest.closeSession() and fRc;
5365
5366 return (fRc, oTxsSession);
5367
5368 def testGuestCtrlCopyFrom(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5369 """
5370 Tests copying files from guest to the host.
5371 """
5372
5373 reporter.log2('Entered');
5374
5375 #
5376 # Paths.
5377 #
5378 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, "testGctrlCopyFrom");
5379 sScratchDstDir1Hst = os.path.join(sScratchHst, "dstdir1");
5380 sScratchDstDir2Hst = os.path.join(sScratchHst, "dstdir2");
5381 sScratchDstDir3Hst = os.path.join(sScratchHst, "dstdir3");
5382 sScratchDstDir4Hst = os.path.join(sScratchHst, "dstdir4");
5383 # os.path.join() is too clever for "..", so we just build up the path here ourselves.
5384 sScratchDotDotDirHst = sScratchHst + os.path.sep + '..' + os.path.sep;
5385 oExistingFileGst = self.oTestFiles.chooseRandomFile();
5386 oNonEmptyDirGst = self.oTestFiles.chooseRandomDirFromTree(fNonEmpty = True);
5387 oTreeDirGst = self.oTestFiles.oTreeDir;
5388 oEmptyDirGst = self.oTestFiles.oEmptyDir;
5389
5390 if oTestVm.isWindows() or oTestVm.isOS2():
5391 sScratchGstInvalid = "?*|<invalid-name>";
5392 else:
5393 sScratchGstInvalid = None;
5394 if utils.getHostOs() in ('win', 'os2'):
5395 sScratchHstInvalid = "?*|<invalid-name>";
5396 else:
5397 sScratchHstInvalid = None;
5398
5399 sScratchDotDotDirGst = oTestVm.pathJoin(oEmptyDirGst.sPath, '..');
5400
5401 if os.path.exists(sScratchHst):
5402 if base.wipeDirectory(sScratchHst) != 0:
5403 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
5404 else:
5405 try:
5406 os.mkdir(sScratchHst);
5407 except:
5408 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
5409
5410 reporter.log2('Creating host sub dirs ...');
5411
5412 for sSubDir in (sScratchDstDir1Hst, sScratchDstDir2Hst, sScratchDstDir3Hst, sScratchDstDir4Hst):
5413 try:
5414 os.mkdir(sSubDir);
5415 except:
5416 return reporter.errorXcpt('os.mkdir(%s)' % (sSubDir, ));
5417
5418 reporter.log2('Defining tests ...');
5419
5420 #
5421 # Bad parameter tests.
5422 #
5423 atTests = [
5424 # Missing both source and destination:
5425 [ tdTestCopyFromFile(), tdTestResultFailure() ],
5426 [ tdTestCopyFromDir(), tdTestResultFailure() ],
5427 # Missing source.
5428 [ tdTestCopyFromFile(sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5429 [ tdTestCopyFromDir( sDst = sScratchHst), tdTestResultFailure() ],
5430 # Missing destination.
5431 [ tdTestCopyFromFile(oSrc = oExistingFileGst), tdTestResultFailure() ],
5432 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath), tdTestResultFailure() ],
5433 # Invalid flags:
5434 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somefile'), afFlags = [0x40000000]),
5435 tdTestResultFailure() ],
5436 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'somedir'), afFlags = [ 0x40000000] ),
5437 tdTestResultFailure() ],
5438 # Non-existing sources:
5439 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
5440 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5441 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
5442 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5443 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-file'),
5444 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5445 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-subdir'),
5446 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5447 # Non-existing destinations:
5448 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
5449 sDst = os.path.join(sScratchHst, 'no-such-directory', 'somefile') ), tdTestResultFailure() ],
5450 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'no-such-directory', 'somedir') ),
5451 tdTestResultFailure() ],
5452 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
5453 sDst = os.path.join(sScratchHst, 'no-such-directory-slash' + os.path.sep)),
5454 tdTestResultFailure() ],
5455 # Wrong source type:
5456 [ tdTestCopyFromFile(oSrc = oNonEmptyDirGst, sDst = os.path.join(sScratchHst, 'somefile') ), tdTestResultFailure() ],
5457 [ tdTestCopyFromDir(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somedir') ), tdTestResultFailure() ],
5458 ];
5459 # Bogus names:
5460 if sScratchHstInvalid:
5461 atTests.extend([
5462 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
5463 tdTestResultFailure() ],
5464 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
5465 tdTestResultFailure() ],
5466 ]);
5467 if sScratchGstInvalid:
5468 atTests.extend([
5469 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
5470 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5471 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
5472 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5473 ]);
5474
5475 #
5476 # Single file copying.
5477 #
5478 atTests.extend([
5479 # Should succeed, as the file isn't there yet on the destination.
5480 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), tdTestResultSuccess() ],
5481 # Overwrite the existing file.
5482 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), tdTestResultSuccess() ],
5483 # Same file, but with a different name on the destination.
5484 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile2')), tdTestResultSuccess() ],
5485 ]);
5486
5487 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
5488 # Copy into a directory.
5489 atTests.extend([
5490 # This should fail, as sScratchHst exists and is a directory.
5491 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst), tdTestResultFailure() ],
5492 # Same existing host directory, but this time with a trailing slash.
5493 # This should succeed, as the file isn't there yet on the destination.
5494 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
5495 # Overwrite the existing file.
5496 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
5497 ]);
5498
5499 #
5500 # Directory handling.
5501 #
5502 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
5503 atTests.extend([
5504 # Without a trailing slash added to the destination this should fail,
5505 # as the destination directory already exist.
5506 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst), tdTestResultFailure() ],
5507 # Same existing host directory, but this time with DirectoryCopyFlag_CopyIntoExisting set.
5508 # This should copy the contents of oEmptyDirGst to sScratchDstDir1Hst (empty, but anyway).
5509 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst,
5510 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5511 # Try again.
5512 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst,
5513 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5514 # With a trailing slash added to the destination, copy the empty guest directory
5515 # (should end up as sScratchHst/empty):
5516 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep), tdTestResultSuccess() ],
5517 # Repeat -- this time it should fail, as the destination directory already exists (and
5518 # DirectoryCopyFlag_CopyIntoExisting is not specified):
5519 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep), tdTestResultFailure() ],
5520 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work (again).
5521 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep,
5522 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5523 # Copy with a different destination name just for the heck of it:
5524 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = os.path.join(sScratchDstDir2Hst, 'empty2'),
5525 fIntoDst = True),
5526 tdTestResultSuccess() ],
5527 ]);
5528 atTests.extend([
5529 # Now the same using a directory with files in it:
5530 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir3Hst + os.path.sep), tdTestResultSuccess() ],
5531 # Again.
5532 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir3Hst, fIntoDst = True,
5533 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5534 ]);
5535 atTests.extend([
5536 # Copy the entire test tree:
5537 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep), tdTestResultSuccess() ],
5538 # Again, should fail this time.
5539 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep), tdTestResultFailure() ],
5540 # Works again, as DirectoryCopyFlag_CopyIntoExisting is specified.
5541 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep,
5542 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5543 ]);
5544 #
5545 # Dotdot path handling.
5546 #
5547 if self.oTstDrv.fpApiVer >= 6.1:
5548 atTests.extend([
5549 # Test if copying stuff from a guest dotdot ".." directory works.
5550 [ tdTestCopyFromDir(sSrc = sScratchDotDotDirGst, sDst = sScratchDstDir1Hst + os.path.sep,
5551 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]),
5552 tdTestResultFailure() ],
5553 # Test if copying stuff from the guest to a host's dotdot ".." directory works.
5554 # That should fail on destinations.
5555 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchDotDotDirHst), tdTestResultFailure() ],
5556 ]);
5557
5558 reporter.log2('Executing tests ...');
5559
5560 #
5561 # Execute the tests.
5562 #
5563 fRc = True;
5564 for (i, tTest) in enumerate(atTests):
5565 oCurTest = tTest[0]
5566 oCurRes = tTest[1] # type: tdTestResult
5567 if isinstance(oCurTest, tdTestCopyFrom):
5568 reporter.log('Testing #%d, %s: sSrc="%s", sDst="%s", afFlags="%s" ...'
5569 % (i, "directory" if isinstance(oCurTest, tdTestCopyFromDir) else "file",
5570 limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags,));
5571 else:
5572 reporter.log('Testing #%d, tdTestRemoveHostDir "%s" ...' % (i, oCurTest.sDir,));
5573 if isinstance(oCurTest, tdTestCopyFromDir) and self.oTstDrv.fpApiVer < 6.0:
5574 reporter.log('Skipping directoryCopyFromGuest test, not implemented in %s' % (self.oTstDrv.fpApiVer,));
5575 continue;
5576
5577 if isinstance(oCurTest, tdTestRemoveHostDir):
5578 fRc = oCurTest.execute(self.oTstDrv, oSession, oTxsSession, oTestVm, 'testing #%d' % (i,));
5579 else:
5580 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5581 if not fRc:
5582 break;
5583 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyFrom: Test #%d' % (i,));
5584 if fRc2 is not True:
5585 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5586 break;
5587
5588 if isinstance(oCurTest, tdTestCopyFromFile):
5589 fRc2 = self.gctrlCopyFileFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
5590 else:
5591 fRc2 = self.gctrlCopyDirFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
5592
5593 if fRc2 != oCurRes.fRc:
5594 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
5595
5596 fRc = oCurTest.closeSession() and fRc;
5597
5598 return (fRc, oTxsSession);
5599
5600 def testGuestCtrlUpdateAdditions(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5601 """
5602 Tests updating the Guest Additions inside the guest.
5603
5604 """
5605
5606 # Skip test for updating Guest Additions if we run on a too old (Windows) guest.
5607 ##
5608 ## @todo make it work everywhere!
5609 ##
5610 if oTestVm.sKind in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
5611 reporter.log("Skipping updating GAs on old windows vm (sKind=%s)" % (oTestVm.sKind,));
5612 return (None, oTxsSession);
5613 if oTestVm.isOS2():
5614 reporter.log("Skipping updating GAs on OS/2 guest");
5615 return (None, oTxsSession);
5616
5617 sVBoxValidationKitIso = self.oTstDrv.sVBoxValidationKitIso;
5618 if not os.path.isfile(sVBoxValidationKitIso):
5619 return reporter.log('Validation Kit .ISO not found at "%s"' % (sVBoxValidationKitIso,));
5620
5621 sScratch = os.path.join(self.oTstDrv.sScratchPath, "testGctrlUpdateAdditions");
5622 try:
5623 os.makedirs(sScratch);
5624 except OSError as e:
5625 if e.errno != errno.EEXIST:
5626 return reporter.error('Failed: Unable to create scratch directory \"%s\"' % (sScratch,));
5627 reporter.log('Scratch path is: %s' % (sScratch,));
5628
5629 atTests = [];
5630 if oTestVm.isWindows():
5631 atTests.extend([
5632 # Source is missing.
5633 [ tdTestUpdateAdditions(sSrc = ''), tdTestResultFailure() ],
5634
5635 # Wrong flags.
5636 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
5637 afFlags = [ 1234 ]), tdTestResultFailure() ],
5638
5639 # Non-existing .ISO.
5640 [ tdTestUpdateAdditions(sSrc = "non-existing.iso"), tdTestResultFailure() ],
5641
5642 # Wrong .ISO.
5643 [ tdTestUpdateAdditions(sSrc = sVBoxValidationKitIso), tdTestResultFailure() ],
5644
5645 # The real thing.
5646 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso()),
5647 tdTestResultSuccess() ],
5648 # Test the (optional) installer arguments. This will extract the
5649 # installer into our guest's scratch directory.
5650 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
5651 asArgs = [ '/extract', '/D=' + sScratch ]),
5652 tdTestResultSuccess() ]
5653 # Some debg ISO. Only enable locally.
5654 #[ tdTestUpdateAdditions(
5655 # sSrc = "V:\\Downloads\\VBoxGuestAdditions-r80354.iso"),
5656 # tdTestResultSuccess() ]
5657 ]);
5658 else:
5659 reporter.log('No OS-specific tests for non-Windows yet!');
5660
5661 fRc = True;
5662 for (i, tTest) in enumerate(atTests):
5663 oCurTest = tTest[0] # type: tdTestUpdateAdditions
5664 oCurRes = tTest[1] # type: tdTestResult
5665 reporter.log('Testing #%d, sSrc="%s", afFlags="%s" ...' % (i, oCurTest.sSrc, oCurTest.afFlags,));
5666
5667 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5668
5669 fRc, _ = oCurTest.createSession('Test #%d' % (i,));
5670 if fRc is not True:
5671 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5672 break;
5673
5674 try:
5675 oCurProgress = oCurTest.oGuest.updateGuestAdditions(oCurTest.sSrc, oCurTest.asArgs, oCurTest.afFlags);
5676 except:
5677 reporter.maybeErrXcpt(oCurRes.fRc, 'Updating Guest Additions exception for sSrc="%s", afFlags="%s":'
5678 % (oCurTest.sSrc, oCurTest.afFlags,));
5679 fRc = False;
5680 else:
5681 if oCurProgress is not None:
5682 oWrapperProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr,
5683 self.oTstDrv, "gctrlUpGA");
5684 oWrapperProgress.wait();
5685 assert oWrapperProgress.isCompleted();
5686 fRc = oWrapperProgress.isSuccess();
5687 if not fRc:
5688 oWrapperProgress.logResult(fIgnoreErrors = True);
5689 else:
5690 fRc = reporter.error('No progress object returned');
5691
5692 oCurTest.closeSession();
5693 if fRc is oCurRes.fRc:
5694 if fRc:
5695 ## @todo Verify if Guest Additions were really updated (build, revision, ...).
5696 ## @todo r=bird: Not possible since you're installing the same GAs as before...
5697 ## Maybe check creation dates on certain .sys/.dll/.exe files?
5698 pass;
5699 else:
5700 reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc, oCurRes.fRc));
5701
5702 return (True, oTxsSession); # Always return True here; errors are counted via the reporter.
5703
5704 def checkScreenShot(self, iWidth, iHeight, aRGBData): # pylint: disable=unused-argument
5705 """
5706 TBD: Implement basic validation of the captured screenshot content.
5707 """
5708 cPixels = iHeight * iWidth
5709
5710 if cPixels == 0:
5711 reporter.logXcpt("Empty screenshot");
5712 return False
5713
5714 # The simple algoritm below assumes that Windows OS desktop consists of a pixels that
5715 # are not too dark or bright but usually of blue tint.
5716 cDesktopPixels = 0
5717 cDesktopPixelsBlue = 0
5718 iThreshold = 20
5719 for i in range(0, cPixels, 4) :
5720 if sys.version_info[0] >= 3:
5721 iRed = aRGBData[i];
5722 iGreen = aRGBData[i + 1];
5723 iBlue = aRGBData[i + 2];
5724 else: # Python 2.7 treats a pixel data returned by takeScreenShotToArray as a string
5725 iRed = ord(aRGBData[i])
5726 iGreen = ord(aRGBData[i + 1])
5727 iBlue = ord(aRGBData[i + 2])
5728
5729 iBright = (3 * iRed + 6 * iGreen + iBlue) / 10
5730 if iThreshold < iBright < 255 - iThreshold :
5731 cDesktopPixels += 1;
5732 cDesktopPixelsBlue += int(iBlue > iRed and iBlue > iGreen);
5733
5734 fpRatioDesktop = float(cDesktopPixels) / float(cPixels);
5735 reporter.log2('Ratio of not too dark or bright pixels %.2f' % (fpRatioDesktop));
5736
5737 if fpRatioDesktop > 0.1:
5738 fpRatioBlue = float(cDesktopPixelsBlue) / float(cDesktopPixels);
5739 reporter.log2('Ratio of blue pixels %.2f ' % (fpRatioBlue));
5740 if fpRatioBlue > 0.5:
5741 return True
5742
5743 return True # Always return True until the parameters will be calibrated.
5744
5745 def testGuestCtrl3D(self, oSession, oTxsSession, oTestVm): # pylint: disable=unused-argument
5746 """
5747 Tests for VMSVGA device.
5748 """
5749
5750 if oTestVm.sKind not in ('Windows8_64', 'Windows10', 'Windows10_64', 'Windows11_64'):
5751 return (True, oTxsSession);
5752
5753 iScreenId = 0 # TBD: Use a loop to iterate and check all virtual displays
5754 try:
5755 if self.oTstDrv.fpApiVer >= 5.0:
5756 iWidth, iHeight, _, _, _, _ = oSession.o.console.display.getScreenResolution(iScreenId);
5757 else:
5758 iWidth, iHeight, _, _, _ = oSession.o.console.display.getScreenResolution(iScreenId);
5759
5760 aRGBData = oSession.o.console.display.takeScreenShotToArray(iScreenId, iWidth, iHeight,
5761 vboxcon.BitmapFormat_RGBA);
5762 except:
5763 reporter.logXcpt("Unable to take screenshot");
5764 return False
5765
5766 reporter.log2('Got screenshot (%s x %s) having %s bytes' % (iWidth, iHeight, len(aRGBData)));
5767 # @todo r=aeichner Where is this result incorporated in the test result?
5768 # It gets overwritten afterwards without being taken into account
5769 fRc = self.checkScreenShot(iWidth, iHeight, aRGBData);
5770
5771 fRc = fRc and self.oTstDrv.txsRunTest(oTxsSession, 'Checking DX11 feature level', 30 * 1000,
5772 '${CDROM}/${OS/ARCH}/ntDisplay${EXESUFF}', ('ntDisplay', ));
5773 fRc = True; # TBD: Fix for Unattended tests when the ValidationKit.iso is mounted as drive D:
5774 return (fRc, oTxsSession);
5775
5776class tdAddGuestCtrl(vbox.TestDriver): # pylint: disable=too-many-instance-attributes,too-many-public-methods
5777 """
5778 Guest control using VBoxService on the guest.
5779 """
5780
5781 def __init__(self):
5782 vbox.TestDriver.__init__(self);
5783 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
5784 self.asRsrcs = None;
5785 self.fQuick = False; # Don't skip lengthly tests by default.
5786 self.addSubTestDriver(SubTstDrvAddGuestCtrl(self));
5787
5788 #
5789 # Overridden methods.
5790 #
5791 def showUsage(self):
5792 """
5793 Shows the testdriver usage.
5794 """
5795 rc = vbox.TestDriver.showUsage(self);
5796 reporter.log('');
5797 reporter.log('tdAddGuestCtrl Options:');
5798 reporter.log(' --quick');
5799 reporter.log(' Same as --virt-modes hwvirt --cpu-counts 1.');
5800 return rc;
5801
5802 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
5803 """
5804 Parses the testdriver arguments from the command line.
5805 """
5806 if asArgs[iArg] == '--quick':
5807 self.parseOption(['--virt-modes', 'hwvirt'], 0);
5808 self.parseOption(['--cpu-counts', '1'], 0);
5809 self.fQuick = True;
5810 else:
5811 return vbox.TestDriver.parseOption(self, asArgs, iArg);
5812 return iArg + 1;
5813
5814 def actionConfig(self):
5815 if not self.importVBoxApi(): # So we can use the constant below.
5816 return False;
5817
5818 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT;
5819 sGaIso = self.getGuestAdditionsIso();
5820 return self.oTestVmSet.actionConfig(self, eNic0AttachType = eNic0AttachType, sDvdImage = sGaIso);
5821
5822 def actionExecute(self):
5823 return self.oTestVmSet.actionExecute(self, self.testOneCfg);
5824
5825 #
5826 # Test execution helpers.
5827 #
5828 def testOneCfg(self, oVM, oTestVm): # pylint: disable=too-many-statements
5829 """
5830 Runs the specified VM thru the tests.
5831
5832 Returns a success indicator on the general test execution. This is not
5833 the actual test result.
5834 """
5835
5836 self.logVmInfo(oVM);
5837
5838 fRc = True;
5839 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName, fCdWait = False);
5840 reporter.log("TxsSession: %s" % (oTxsSession,));
5841 if oSession is not None:
5842 fRc, oTxsSession = self.aoSubTstDrvs[0].testIt(oTestVm, oSession, oTxsSession);
5843 self.terminateVmBySession(oSession);
5844 else:
5845 fRc = False;
5846 return fRc;
5847
5848 def onExit(self, iRc):
5849 return vbox.TestDriver.onExit(self, iRc);
5850
5851 def gctrlReportError(self, progress):
5852 """
5853 Helper function to report an error of a
5854 given progress object.
5855 """
5856 if progress is None:
5857 reporter.log('No progress object to print error for');
5858 else:
5859 errInfo = progress.errorInfo;
5860 if errInfo:
5861 reporter.log('%s' % (errInfo.text,));
5862 return False;
5863
5864 def gctrlGetRemainingTime(self, msTimeout, msStart):
5865 """
5866 Helper function to return the remaining time (in ms)
5867 based from a timeout value and the start time (both in ms).
5868 """
5869 if msTimeout == 0:
5870 return 0xFFFFFFFE; # Wait forever.
5871 msElapsed = base.timestampMilli() - msStart;
5872 if msElapsed > msTimeout:
5873 return 0; # No time left.
5874 return msTimeout - msElapsed;
5875
5876 def testGuestCtrlManual(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements,unused-argument,unused-variable
5877 """
5878 For manually testing certain bits.
5879 """
5880
5881 reporter.log('Manual testing ...');
5882 fRc = True;
5883
5884 sUser = 'Administrator';
5885 sPassword = 'password';
5886
5887 oGuest = oSession.o.console.guest;
5888 oGuestSession = oGuest.createSession(sUser,
5889 sPassword,
5890 "", "Manual Test");
5891
5892 aWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
5893 _ = oGuestSession.waitForArray(aWaitFor, 30 * 1000);
5894
5895 #sCmd = self.getGuestSystemShell(oTestVm);
5896 #asArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
5897 #aEnv = [];
5898 #afFlags = [];
5899
5900 # Fix this once being used (again).
5901 #for _ in xrange(100):
5902 # oProc = self.processCreateWrapper(oGuestSession, sCmd, asArgs if self.fpApiVer >= 5.0 else asArgs[1:],
5903 # "", # Working directory.
5904 # aEnv, afFlags, 30 * 1000);
5905 #
5906 # aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
5907 # _ = oProc.waitForArray(aWaitFor, 30 * 1000);
5908
5909 oGuestSession.close();
5910 oGuestSession = None;
5911
5912 time.sleep(5);
5913
5914 oSession.o.console.PowerDown();
5915
5916 return (fRc, oTxsSession);
5917
5918if __name__ == '__main__':
5919 sys.exit(tdAddGuestCtrl().main(sys.argv));
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette