VirtualBox

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

Last change on this file was 109301, checked in by vboxsync, 31 hours ago

tests/additions/tdAddGuestCtrl.py: Simplified Guest Additions revision checks.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 289.8 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# pylint: disable=too-many-lines
4# $Id: tdAddGuestCtrl.py 109301 2025-05-16 12:39:49Z 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: 109301 $"
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
1782 #
1783 # Enable VBoxService verbose logging.
1784 #
1785 reporter.log('Enabling verbose VBoxService logging: %s' % (fEnableVerboseLogging));
1786 if fEnableVerboseLogging:
1787 if oTxsSession.syncMkDirPath(self.oDebug.sGstVBoxServiceLogPath, 0o777) is not True:
1788 return reporter.error('Failed to create directory "%s"!' % (self.oDebug.sGstVBoxServiceLogPath,));
1789 reporter.log('VBoxService logs will be stored in "%s"' % (self.oDebug.sGstVBoxServiceLogPath,));
1790
1791 fRestartVBoxService = False;
1792
1793 if oTestVm.isWindows():
1794 asArgs = [ sRegEditorExePath ] + asRegEditorArgs;
1795 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging (via registry)',
1796 30 * 1000,
1797 sRegEditorExePath, asRegEditorArgs);
1798 elif oTestVm.isLinux():
1799 # Need to use some stupid trickery here to locate the sed binary,
1800 # as this might differ on various Linux hosts, sigh. We also could use 'which' or some sort on the guest.
1801 # Note: Sorted by likeliness.
1802 asSedPaths = [
1803 '/bin/sed',
1804 '/usr/bin/sed',
1805 '/usr/local/bin/sed'
1806 ];
1807 fRc, sPathSed = self.locateGstBinary(oTxsSession, asSedPaths);
1808 if fRc:
1809 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging', 30 * 1000,
1810 sPathSed,
1811 (sPathSed, '-i', '-e', 's/'
1812 '\\$2 \\$3'
1813 '/'
1814 '\\$2 \\$3 -vvvv --logfile \\/var\\/tmp\\/VBoxService\\/VBoxService.log'
1815 '/g',
1816 '/sbin/rcvboxadd-service'));
1817 else:
1818 reporter.log('Verbose logging for VBoxService not supported for this guest yet');
1819
1820 if fRestartVBoxService:
1821 # Wait for VBoxService to start up properly so, we can shut it down again and restart.
1822 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1823 vboxcon.AdditionsFacilityStatus_Active);
1824 if not fRc:
1825 reporter.log('VBoxService didn\'t startup in time');
1826 return False;
1827
1828 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1829 self.oTstDrv.sleep(5);
1830 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1831
1832 # Wait for VBoxService to start up in any case.
1833 reporter.testStart('Waiting for VBoxService to get started');
1834 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1835 vboxcon.AdditionsFacilityStatus_Active);
1836 reporter.testDone();
1837 if not fRc:
1838 return False;
1839
1840 #
1841 # Generate and upload some random files and dirs to the guest.
1842 # Note! Make sure we don't run into too-long-path issues when using
1843 # the test files on the host if.
1844 #
1845 cchGst = len(self.oTstDrv.getGuestTempDir(oTestVm)) + 1 + len('addgst-1') + 1;
1846 cchHst = len(self.oTstDrv.sScratchPath) + 1 + len('copyto/addgst-1') + 1;
1847 cchMaxPath = 230;
1848 if cchHst > cchGst:
1849 cchMaxPath -= cchHst - cchGst;
1850 reporter.log('cchMaxPath=%s (cchHst=%s, cchGst=%s)' % (cchMaxPath, cchHst, cchGst,));
1851 self.oTestFiles = vboxtestfileset.TestFileSet(oTestVm,
1852 self.oTstDrv.getGuestTempDir(oTestVm), 'addgst-1',
1853 # Make sure that we use a lowest common denominator across all supported
1854 # platforms, to make testing the randomly generated file paths work
1855 # reliably.
1856 cchMaxPath = cchMaxPath, asCompatibleWith = [ ('cross') ]);
1857 return self.oTestFiles.upload(oTxsSession, self.oTstDrv);
1858
1859
1860 #
1861 # gctrlXxxx stuff.
1862 #
1863
1864 def gctrlCopyFileFrom(self, oGuestSession, oTest, fExpected):
1865 """
1866 Helper function to copy a single file from the guest to the host.
1867 """
1868
1869 # As we pass-in randomly generated file names, the source sometimes can be empty, which
1870 # in turn will result in a (correct) error by the API. Simply skip this function then.
1871 if not oTest.sSrc:
1872 reporter.log2('Skipping guest file "%s"' % (limitString(oTest.sSrc)));
1873 return fExpected;
1874
1875 #
1876 # Do the copying.
1877 #
1878 reporter.log2('Copying guest file "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1879 try:
1880 if self.oTstDrv.fpApiVer >= 5.0:
1881 oCurProgress = oGuestSession.fileCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1882 else:
1883 oCurProgress = oGuestSession.copyFrom(oTest.sSrc, oTest.sDst, oTest.afFlags);
1884 except:
1885 reporter.maybeErrXcpt(fExpected, 'Copy from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1886 return False;
1887 if oCurProgress is None:
1888 return reporter.error('No progress object returned');
1889 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlFileCopyFrom");
1890 oProgress.wait();
1891 if not oProgress.isSuccess():
1892 oProgress.logResult(fIgnoreErrors = not fExpected);
1893 return False;
1894
1895 #
1896 # Check the result if we can.
1897 #
1898 if oTest.oSrc:
1899 assert isinstance(oTest.oSrc, testfileset.TestFile);
1900 sDst = oTest.sDst;
1901 if os.path.isdir(sDst):
1902 sDst = os.path.join(sDst, oTest.oSrc.sName);
1903 try:
1904 oFile = open(sDst, 'rb'); # pylint: disable=consider-using-with
1905 except:
1906 # Don't report expected non-existing paths / files as an error.
1907 return reporter.maybeErrXcpt(fExpected, 'open(%s) failed during verfication (file / path not found)' % (sDst,));
1908 fEqual = oTest.oSrc.equalFile(oFile);
1909 oFile.close();
1910 if not fEqual:
1911 return reporter.error('Content differs for "%s"' % (sDst,));
1912
1913 return True;
1914
1915 def __compareTestDir(self, oDir, sHostPath): # type: (testfileset.TestDir, str) -> bool
1916 """
1917 Recursively compare the content of oDir and sHostPath.
1918
1919 Returns True on success, False + error logging on failure.
1920
1921 Note! This ASSUMES that nothing else was copied to sHostPath!
1922 """
1923 #
1924 # First check out all the entries and files in the directory.
1925 #
1926 dLeftUpper = dict(oDir.dChildrenUpper);
1927 try:
1928 asEntries = os.listdir(sHostPath);
1929 except:
1930 return reporter.errorXcpt('os.listdir(%s) failed' % (sHostPath,));
1931
1932 fRc = True;
1933 for sEntry in asEntries:
1934 sEntryUpper = sEntry.upper();
1935 if sEntryUpper not in dLeftUpper:
1936 fRc = reporter.error('Unexpected entry "%s" in "%s"' % (sEntry, sHostPath,));
1937 else:
1938 oFsObj = dLeftUpper[sEntryUpper];
1939 del dLeftUpper[sEntryUpper];
1940
1941 if isinstance(oFsObj, testfileset.TestFile):
1942 sFilePath = os.path.join(sHostPath, oFsObj.sName);
1943 try:
1944 oFile = open(sFilePath, 'rb'); # pylint: disable=consider-using-with
1945 except:
1946 fRc = reporter.errorXcpt('open(%s) failed during verfication' % (sFilePath,));
1947 else:
1948 fEqual = oFsObj.equalFile(oFile);
1949 oFile.close();
1950 if not fEqual:
1951 fRc = reporter.error('Content differs for "%s"' % (sFilePath,));
1952
1953 # List missing entries:
1954 for sKey in dLeftUpper:
1955 oEntry = dLeftUpper[sKey];
1956 fRc = reporter.error('%s: Missing %s "%s" (src path: %s)'
1957 % (sHostPath, oEntry.sName,
1958 'file' if isinstance(oEntry, testfileset.TestFile) else 'directory', oEntry.sPath));
1959
1960 #
1961 # Recurse into subdirectories.
1962 #
1963 for oFsObj in oDir.aoChildren:
1964 if isinstance(oFsObj, testfileset.TestDir):
1965 fRc = self.__compareTestDir(oFsObj, os.path.join(sHostPath, oFsObj.sName)) and fRc;
1966 return fRc;
1967
1968 def gctrlCopyDirFrom(self, oGuestSession, oTest, fExpected):
1969 """
1970 Helper function to copy a directory from the guest to the host.
1971 """
1972
1973 # As we pass-in randomly generated directories, the source sometimes can be empty, which
1974 # in turn will result in a (correct) error by the API. Simply skip this function then.
1975 if not oTest.sSrc:
1976 reporter.log2('Skipping guest dir "%s"' % (limitString(oTest.sSrc)));
1977 return fExpected;
1978
1979 #
1980 # Do the copying.
1981 #
1982 reporter.log2('Copying guest dir "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1983 try:
1984 if self.oTstDrv.fpApiVer >= 7.0:
1985 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
1986 if not oTest.afFlags:
1987 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
1988 elif vboxcon.DirectoryCopyFlag_Recursive not in oTest.afFlags:
1989 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
1990 ## @todo Ditto.
1991 if not oTest.afFlags:
1992 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_FollowLinks, ];
1993 elif vboxcon.DirectoryCopyFlag_FollowLinks not in oTest.afFlags:
1994 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
1995 oCurProgress = oGuestSession.directoryCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1996 except:
1997 reporter.maybeErrXcpt(fExpected, 'Copy dir from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1998 return False;
1999 if oCurProgress is None:
2000 return reporter.error('No progress object returned');
2001
2002 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlDirCopyFrom");
2003 oProgress.wait();
2004 if not oProgress.isSuccess():
2005 oProgress.logResult(fIgnoreErrors = not fExpected);
2006 return False;
2007
2008 #
2009 # Check the result if we can.
2010 #
2011 if oTest.oSrc:
2012 assert isinstance(oTest.oSrc, testfileset.TestDir);
2013 sDst = oTest.sDst;
2014 if oTest.fIntoDst:
2015 return self.__compareTestDir(oTest.oSrc, os.path.join(sDst, oTest.oSrc.sName));
2016 oDummy = testfileset.TestDir(None, 'dummy');
2017 oDummy.aoChildren = [oTest.oSrc,]
2018 oDummy.dChildrenUpper = { oTest.oSrc.sName.upper(): oTest.oSrc, };
2019 return self.__compareTestDir(oDummy, sDst);
2020 return True;
2021
2022 def gctrlCopyFileTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
2023 """
2024 Helper function to copy a single file from the host to the guest.
2025
2026 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
2027 """
2028 reporter.log2('Copying host file "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
2029 try:
2030 if self.oTstDrv.fpApiVer >= 5.0:
2031 oCurProgress = oGuestSession.fileCopyToGuest(sSrc, sDst, afFlags);
2032 else:
2033 oCurProgress = oGuestSession.copyTo(sSrc, sDst, afFlags);
2034 except:
2035 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
2036 return False;
2037
2038 if oCurProgress is None:
2039 return reporter.error('No progress object returned');
2040 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
2041
2042 try:
2043 oProgress.wait();
2044 if not oProgress.isSuccess():
2045 oProgress.logResult(fIgnoreErrors = not fIsError);
2046 return False;
2047 except:
2048 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
2049 return False;
2050 return True;
2051
2052 def gctrlCopyDirTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
2053 """
2054 Helper function to copy a directory (tree) from the host to the guest.
2055
2056 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
2057 """
2058 reporter.log2('Copying host directory "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
2059 try:
2060 if self.oTstDrv.fpApiVer >= 7.0:
2061 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
2062 if not afFlags:
2063 afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
2064 elif vboxcon.DirectoryCopyFlag_Recursive not in afFlags:
2065 afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
2066 ## @todo Ditto.
2067 if not afFlags:
2068 afFlags = [vboxcon.DirectoryCopyFlag_FollowLinks,];
2069 elif vboxcon.DirectoryCopyFlag_FollowLinks not in afFlags:
2070 afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
2071 oCurProgress = oGuestSession.directoryCopyToGuest(sSrc, sDst, afFlags);
2072 except:
2073 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
2074 return False;
2075
2076 if oCurProgress is None:
2077 return reporter.error('No progress object returned');
2078 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
2079
2080 try:
2081 oProgress.wait();
2082 if not oProgress.isSuccess():
2083 oProgress.logResult(fIgnoreErrors = not fIsError);
2084 return False;
2085 except:
2086 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
2087 return False;
2088 return True;
2089
2090 def gctrlCreateDir(self, oTest, oRes, oGuestSession):
2091 """
2092 Helper function to create a guest directory specified in the current test.
2093 """
2094 reporter.log2('Creating directory "%s"' % (limitString(oTest.sDirectory),));
2095 try:
2096 oGuestSession.directoryCreate(oTest.sDirectory, oTest.fMode, oTest.afFlags);
2097 except:
2098 reporter.maybeErrXcpt(oRes.fRc, 'Failed to create "%s" fMode=%o afFlags=%s'
2099 % (oTest.sDirectory, oTest.fMode, oTest.afFlags,));
2100 return not oRes.fRc;
2101 if oRes.fRc is not True:
2102 return reporter.error('Did not expect to create directory "%s"!' % (oTest.sDirectory,));
2103
2104 # Check if the directory now exists.
2105 try:
2106 if self.oTstDrv.fpApiVer >= 5.0:
2107 fDirExists = oGuestSession.directoryExists(oTest.sDirectory, False);
2108 else:
2109 fDirExists = oGuestSession.directoryExists(oTest.sDirectory);
2110 except:
2111 return reporter.errorXcpt('directoryExists failed on "%s"!' % (oTest.sDirectory,));
2112 if not fDirExists:
2113 return reporter.errorXcpt('directoryExists returned False on "%s" after directoryCreate succeeded!'
2114 % (oTest.sDirectory,));
2115 return True;
2116
2117 def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, fUseDirList = False, cEntriesPerRead = 0, sSubDir = None):
2118 """
2119 Helper function to recursively read a guest directory tree specified in the current test.
2120 """
2121 sDir = oTest.sDirectory;
2122 sFilter = oTest.sFilter;
2123 afFlags = oTest.afFlags;
2124 oTestVm = oTest.oCreds.oTestVm;
2125 sCurDir = oTestVm.pathJoin(sDir, sSubDir) if sSubDir else sDir;
2126
2127 fRc = True; # Be optimistic.
2128 cDirs = 0; # Number of directories read.
2129 cFiles = 0; # Number of files read.
2130 cOthers = 0; # Other files.
2131
2132 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2133 aFsObjInfo = [];
2134
2135 # Open the directory:
2136 reporter.log2('Directory="%s", filter="%s", afFlags="%s", fUseDirList=%s, cEntriesPerRead=%d'
2137 % (limitString(sCurDir), sFilter, afFlags, fUseDirList, cEntriesPerRead));
2138 try:
2139 oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
2140 except:
2141 reporter.maybeErrXcpt(fIsError, 'sCurDir=%s sFilter=%s afFlags=%s' % (sCurDir, sFilter, afFlags,))
2142 return (False, 0, 0, 0);
2143
2144 # Read the directory.
2145 fDone = False;
2146 while fRc is True:
2147 reporter.log3('Reading next batch ...');
2148 aFsObjInfo = [];
2149 try:
2150 if not fUseDirList:
2151 aFsObjInfo.append(oCurDir.read());
2152 else:
2153 if not cEntriesToRead:
2154 cEntriesToRead = random.randrange(1, 32768);
2155 aFsObjInfo = oCurDir.list(cEntriesToRead);
2156 except Exception as oXcpt:
2157 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2158 if fUseDirList:
2159 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % (sCurDir, cEntriesToRead));
2160 else:
2161 if self.oTstDrv.fpApiVer > 5.2:
2162 reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
2163 else:
2164 # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
2165 reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
2166 fRc = False;
2167 else:
2168 reporter.log2('\tNo more directory entries for "%s"' % (limitString(sCurDir),));
2169 fDone = True;
2170 break;
2171
2172 if fDone or not fRc: # Abort reading?
2173 break;
2174
2175 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2176 for oFsObjInfo in aFsObjInfo:
2177 try:
2178 sName = oFsObjInfo.name;
2179 eType = oFsObjInfo.type;
2180 except:
2181 fRc = reporter.errorXcpt();
2182 break;
2183
2184 if sName in ('.', '..', ):
2185 if eType != vboxcon.FsObjType_Directory:
2186 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2187 % (sName, eType, vboxcon.FsObjType_Directory));
2188 elif eType == vboxcon.FsObjType_Directory:
2189 reporter.log2(' Directory "%s"' % limitString(oFsObjInfo.name));
2190 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
2191 fUseDirList, cEntriesPerRead,
2192 oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
2193 fRc = aSubResult[0];
2194 cDirs += aSubResult[1] + 1;
2195 cFiles += aSubResult[2];
2196 cOthers += aSubResult[3];
2197 elif eType is vboxcon.FsObjType_File:
2198 reporter.log4(' File "%s"' % oFsObjInfo.name);
2199 cFiles += 1;
2200 elif eType is vboxcon.FsObjType_Symlink:
2201 reporter.log4(' Symlink "%s" -- not tested yet' % oFsObjInfo.name);
2202 cOthers += 1;
2203 elif oTestVm.isWindows() \
2204 or oTestVm.isOS2() \
2205 or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
2206 vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
2207 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
2208 (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
2209 else:
2210 cOthers += 1;
2211
2212 # Close the directory
2213 try:
2214 oCurDir.close();
2215 except:
2216 fRc = reporter.errorXcpt('sCurDir=%s' % (sCurDir));
2217
2218 return (fRc, cDirs, cFiles, cOthers);
2219
2220 def gctrlReadDirTree2(self, oGuestSession, oDir, fUseDirList = False, cEntriesPerRead = 0):
2221 # type: (testfileset.TestDir) -> bool
2222 """
2223 Helper function to recursively read a guest directory tree specified in the current test.
2224 """
2225
2226 #
2227 # Process the directory.
2228 #
2229
2230 # Open the directory:
2231 try:
2232 oCurDir = oGuestSession.directoryOpen(oDir.sPath, '', None);
2233 except:
2234 return reporter.errorXcpt('sPath=%s' % (oDir.sPath,));
2235
2236 # Read the directory.
2237 dLeftUpper = dict(oDir.dChildrenUpper);
2238 cDot = 0;
2239 cDotDot = 0;
2240 fRc = True;
2241 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2242 aFsObjInfo = [];
2243 while True:
2244 reporter.log3('Reading next batch ...');
2245 aFsObjInfo = [];
2246 try:
2247 if not fUseDirList:
2248 aFsObjInfo.append(oCurDir.read());
2249 else:
2250 if not cEntriesToRead:
2251 cEntriesToRead = random.randrange(1, 32768);
2252 aFsObjInfo = oCurDir.list(cEntriesToRead);
2253 except Exception as oXcpt:
2254 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2255 if fUseDirList:
2256 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % \
2257 (oDir.sPath, cEntriesToRead));
2258 else:
2259 fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath));
2260 else:
2261 reporter.log2('\tNo more directory entries for "%s"' % (limitString(oDir.sPath),));
2262 break;
2263
2264 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2265 for oFsObjInfo in aFsObjInfo:
2266 try:
2267 sName = oFsObjInfo.name;
2268 eType = oFsObjInfo.type;
2269 cbFile = oFsObjInfo.objectSize;
2270 ## @todo check further attributes.
2271 except:
2272 fRc = reporter.errorXcpt();
2273 break;
2274
2275 # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
2276 if sName in ('.', '..', ):
2277 if eType != vboxcon.FsObjType_Directory:
2278 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2279 % (sName, eType, vboxcon.FsObjType_Directory));
2280 if sName == '.': cDot += 1;
2281 else: cDotDot += 1;
2282 else:
2283 # Find the child and remove it from the dictionary.
2284 sNameUpper = sName.upper();
2285 oFsObj = dLeftUpper.get(sNameUpper);
2286 if oFsObj is None:
2287 fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
2288 % (sName, oDir.sPath, eType, cbFile,));
2289 else:
2290 del dLeftUpper[sNameUpper];
2291
2292 # Check type
2293 if isinstance(oFsObj, testfileset.TestDir):
2294 if eType != vboxcon.FsObjType_Directory:
2295 fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
2296 % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
2297 elif isinstance(oFsObj, testfileset.TestFile):
2298 if eType != vboxcon.FsObjType_File:
2299 fRc = reporter.error('%s: expected file (%d), got eType=%d!'
2300 % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
2301 else:
2302 fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
2303
2304 # Check the name.
2305 if oFsObj.sName != sName:
2306 fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % \
2307 (oFsObj.sPath, oFsObj.sName, sName,));
2308
2309 # Check the size if a file.
2310 if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
2311 fRc = reporter.error('%s: expected size %s, got %s instead!' % \
2312 (oFsObj.sPath, oFsObj.cbContent, cbFile,));
2313
2314 ## @todo check timestamps and attributes.
2315
2316 # Close the directory
2317 try:
2318 oCurDir.close();
2319 except:
2320 fRc = reporter.errorXcpt('oDir.sPath=%s' % (oDir.sPath,));
2321
2322 # Any files left over?
2323 for sKey in dLeftUpper:
2324 oFsObj = dLeftUpper[sKey];
2325 fRc = reporter.error('%s: Was not returned! (%s)' % (oFsObj.sPath, type(oFsObj),));
2326
2327 # Check the dot and dot-dot counts.
2328 if cDot != 1:
2329 fRc = reporter.error('%s: Found %s "." entries, expected exactly 1!' % (oDir.sPath, cDot,));
2330 if cDotDot != 1:
2331 fRc = reporter.error('%s: Found %s ".." entries, expected exactly 1!' % (oDir.sPath, cDotDot,));
2332
2333 #
2334 # Recurse into subdirectories using info from oDir.
2335 #
2336 for oFsObj in oDir.aoChildren:
2337 if isinstance(oFsObj, testfileset.TestDir):
2338 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj, fUseDirList, cEntriesPerRead) and fRc;
2339
2340 return fRc;
2341
2342 def gctrlExecDoTest(self, i, oTest, oRes, oGuestSession):
2343 """
2344 Wrapper function around gctrlExecute to provide more sanity checking
2345 when needed in actual execution tests.
2346 """
2347 reporter.log('Testing #%d, cmd="%s" ...' % (i, oTest.sCmd));
2348 fRcExec = self.gctrlExecute(oTest, oGuestSession, oRes.fRc);
2349 if fRcExec == oRes.fRc:
2350 fRc = True;
2351 if fRcExec is True:
2352 # Compare exit status / code on successful process execution.
2353 if oTest.uExitStatus != oRes.uExitStatus \
2354 or oTest.iExitCode != oRes.iExitCode:
2355 fRc = reporter.error('Test #%d (%s) failed: Got exit status + code %d,%d, expected %d,%d'
2356 % (i, oTest.asArgs, oTest.uExitStatus, oTest.iExitCode,
2357 oRes.uExitStatus, oRes.iExitCode));
2358
2359 # Compare test / result buffers on successful process execution.
2360 if oTest.sBuf is not None and oRes.sBuf is not None:
2361 if not utils.areBytesEqual(oTest.sBuf, oRes.sBuf):
2362 fRc = reporter.error('Test #%d (%s) failed: Got buffer\n%s (%d bytes), expected\n%s (%d bytes)'
2363 % (i, oTest.asArgs,
2364 map(hex, map(ord, oTest.sBuf)), len(oTest.sBuf),
2365 map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf)));
2366 reporter.log2('Test #%d passed: Buffers match (%d bytes)' % (i, len(oRes.sBuf)));
2367 elif oRes.sBuf and not oTest.sBuf:
2368 fRc = reporter.error('Test #%d (%s) failed: Got no buffer data, expected\n%s (%dbytes)' %
2369 (i, oTest.asArgs, map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf),));
2370
2371 if oRes.cbStdOut is not None and oRes.cbStdOut != oTest.cbStdOut:
2372 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stdout data, expected %d'
2373 % (i, oTest.asArgs, oTest.cbStdOut, oRes.cbStdOut));
2374 if oRes.cbStdErr is not None and oRes.cbStdErr != oTest.cbStdErr:
2375 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stderr data, expected %d'
2376 % (i, oTest.asArgs, oTest.cbStdErr, oRes.cbStdErr));
2377 else:
2378 fRc = reporter.error('Test #%d (%s) failed: Got %s, expected %s' % (i, oTest.asArgs, fRcExec, oRes.fRc));
2379 return fRc;
2380
2381 def processCreateWrapper(self, oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS):
2382 """
2383 Wrapepr function to deal with different flavors of the IGuestProcess::processCreate call,
2384 depending on the API version.
2385
2386 Returns oProcess object on success, None on failure.
2387 """
2388 oProcess = None;
2389
2390 reporter.log2('Executing sCmd=%s, cCwd=%s, afFlags=%s, timeoutMS=%d, asArgs=%s, asEnv=%s'
2391 % (sCmd, sCwd, afFlags, timeoutMS, limitString(asArgs), limitString(aEnv),));
2392
2393 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485:
2394 # 7.1 adds a current working directory parameter.
2395 oProcess = oGuestSession.processCreate(sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS);
2396 else:
2397 oProcess = oGuestSession.processCreate(sCmd,
2398 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2399 aEnv, afFlags, timeoutMS);
2400 return oProcess;
2401
2402 def processExecute(self, oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS, fIsError = True):
2403 """
2404 Executes a process on the guest and deals with input/output + waiting flags.
2405
2406 Returns tuple (success, exit status, exit code, stdout len, stderr len, stdout / stderr output).
2407 """
2408
2409 #
2410 # Start the process:
2411 #
2412 try:
2413 oProcess = self.processCreateWrapper(oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS);
2414 except:
2415 reporter.maybeErrXcpt(fIsError, 'type=%s, asArgs=%s' % (type(asArgs), asArgs,));
2416 return (False, vboxcon.ProcessStatus_Undefined, 0, 0, 0, '');
2417 if oProcess is None:
2418 reporter.error('oProcess is None! (%s)' % (asArgs,));
2419 return (False, vboxcon.ProcessStatus_Undefined, 0, 0, 0, '');
2420
2421 fRc = True;
2422 uExitStatus = vboxcon.ProcessStatus_Undefined;
2423 iExitCode = -1;
2424 cbStdOut = 0;
2425 cbStdErr = 0;
2426 sBufOut = '';
2427
2428 #time.sleep(5); # try this if you want to see races here.
2429
2430 # Wait for the process to start properly:
2431 reporter.log2('Process start requested, waiting for start (%dms) ...' % (timeoutMS,));
2432 iPid = -1;
2433 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Start, ];
2434 try:
2435 eWaitResult = oProcess.waitForArray(aeWaitFor, timeoutMS);
2436 except:
2437 reporter.maybeErrXcpt(fIsError, 'waitforArray failed for asArgs=%s' % (asArgs,));
2438 fRc = False;
2439 else:
2440 try:
2441 eStatus = oProcess.status;
2442 iPid = oProcess.PID;
2443 except:
2444 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2445 else:
2446 reporter.log2('Wait result returned: %d, current process status is: %d' % (eWaitResult, eStatus,));
2447
2448 #
2449 # Wait for the process to run to completion if necessary.
2450 #
2451 # Note! The above eWaitResult return value can be ignored as it will
2452 # (mostly) reflect the process status anyway.
2453 #
2454 if eStatus == vboxcon.ProcessStatus_Started:
2455
2456 # What to wait for:
2457 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, ];
2458 if vboxcon.ProcessCreateFlag_WaitForStdOut in afFlags:
2459 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdOut);
2460 if vboxcon.ProcessCreateFlag_WaitForStdErr in afFlags:
2461 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdErr);
2462 ## @todo Add vboxcon.ProcessWaitForFlag_StdIn.
2463
2464 reporter.log2('Process (PID %d) started, waiting for termination (%dms), aeWaitFor=%s ...'
2465 % (iPid, timeoutMS, aeWaitFor));
2466 acbFdOut = [0,0,0];
2467 while True:
2468 try:
2469 eWaitResult = oProcess.waitForArray(aeWaitFor, timeoutMS);
2470 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2471 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2472 try: oProcess.close();
2473 except: pass;
2474 break;
2475 except:
2476 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2477 break;
2478 #reporter.log2('Wait returned: %d' % (eWaitResult,));
2479
2480 # Process output:
2481 for eFdResult, iFd, sFdNm in [ (vboxcon.ProcessWaitResult_StdOut, 1, 'stdout'),
2482 (vboxcon.ProcessWaitResult_StdErr, 2, 'stderr'), ]:
2483 if eWaitResult in (eFdResult, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2484 try:
2485 abBuf = oProcess.read(iFd, 64 * 1024, timeoutMS);
2486 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2487 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2488 try: oProcess.close();
2489 except: pass;
2490 except:
2491 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (asArgs,));
2492 else:
2493 if abBuf:
2494 reporter.log2('Process (PID %d) got %d bytes of %s data (type: %s)'
2495 % (iPid, len(abBuf), sFdNm, type(abBuf)));
2496 if reporter.getVerbosity() >= 4:
2497 sBufOut = '';
2498 if sys.version_info >= (2, 7):
2499 if isinstance(abBuf, memoryview): ## @todo Why is this happening?
2500 abBuf = abBuf.tobytes();
2501 sBufOut = abBuf.decode("utf-8");
2502 if sys.version_info <= (2, 7):
2503 if isinstance(abBuf, buffer): # (for 3.0+) pylint: disable=undefined-variable
2504 sBufOut = str(abBuf);
2505 for sLine in sBufOut.splitlines():
2506 reporter.log4('%s: %s' % (sFdNm, sLine));
2507 acbFdOut[iFd] += len(abBuf);
2508 sBufOut = abBuf; ## @todo Figure out how to uniform + append!
2509
2510 ## Process input (todo):
2511 #if eWaitResult in (vboxcon.ProcessWaitResult_StdIn, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2512 # reporter.log2('Process (PID %d) needs stdin data' % (iPid,));
2513
2514 # Termination or error?
2515 if eWaitResult in (vboxcon.ProcessWaitResult_Terminate,
2516 vboxcon.ProcessWaitResult_Error,
2517 vboxcon.ProcessWaitResult_Timeout,):
2518 try: eStatus = oProcess.status;
2519 except: fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2520 reporter.log2('Process (PID %d) reported terminate/error/timeout: %d, status: %d'
2521 % (iPid, eWaitResult, eStatus,));
2522 break;
2523
2524 # End of the wait loop.
2525 _, cbStdOut, cbStdErr = acbFdOut;
2526
2527 try: eStatus = oProcess.status;
2528 except: fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2529 reporter.log2('Final process status (PID %d) is: %d' % (iPid, eStatus));
2530 reporter.log2('Process (PID %d) %d stdout, %d stderr' % (iPid, cbStdOut, cbStdErr));
2531
2532 #
2533 # Get the final status and exit code of the process.
2534 #
2535 try:
2536 uExitStatus = oProcess.status;
2537 iExitCode = oProcess.exitCode;
2538 except:
2539 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2540 reporter.log2('Process (PID %d) has exit code: %d; status: %d ' % (iPid, iExitCode, uExitStatus));
2541 return (fRc, uExitStatus, iExitCode, cbStdOut, cbStdErr, sBufOut);
2542
2543 def gctrlExecute(self, oTest, oGuestSession, fIsError): # pylint: disable=too-many-statements
2544 """
2545 Helper function to execute a program on a guest, specified in the current test.
2546
2547 Note! This weirdo returns results (process exitcode and status) in oTest.
2548 """
2549 fRc = True; # Be optimistic.
2550
2551 # Reset the weird result stuff:
2552 oTest.cbStdOut = 0;
2553 oTest.cbStdErr = 0;
2554 oTest.sBuf = '';
2555 oTest.uExitStatus = 0;
2556 oTest.iExitCode = 0;
2557
2558 ## @todo Compare execution timeouts!
2559 #tsStart = base.timestampMilli();
2560
2561 try:
2562 reporter.log2('Using session user=%s, sDomain=%s, name=%s, timeout=%d'
2563 % (oGuestSession.user, oGuestSession.domain, oGuestSession.name, oGuestSession.timeout,));
2564 except:
2565 return reporter.errorXcpt();
2566
2567 fRc, oTest.uExitStatus, oTest.iExitCode, oTest.cbStdOut, oTest.cbStdErr, oTest.sBuf = \
2568 self.processExecute(oGuestSession, oTest.sCmd, oTest.asArgs, oTest.sCwd, \
2569 oTest.aEnv, oTest.afFlags, oTest.timeoutMS, fIsError);
2570
2571 return fRc;
2572
2573 def executeGstCtlHelper(self, oTxsSession, oGuestSession, asArgs, asEnv = None, sCwd = '', timeoutMS = 30 * 1000):
2574 """
2575 Wrapper to invoke the Guest Control Helper on the guest.
2576
2577 Returns tuple (success, exit status, exit code, stdout len, stderr len, stdout / stderr output).
2578 """
2579 fRc = True;
2580 eExitStatus = vboxcon.ProcessStatus_Undefined;
2581 iExitCode = -1;
2582 cbStdOut = 0;
2583 cbStdErr = 0;
2584 sBuf = '';
2585
2586 if not self.sGstCtlHelperExe:
2587 fRc, self.sGstCtlHelperExe = self.locateGstBinary(oTxsSession, self.asGstCtlHelperPaths);
2588 if fRc:
2589 reporter.log('Using VBoxGuestControlHelper on guest at \"%s\"' % (self.sGstCtlHelperExe));
2590
2591 if fRc \
2592 and self.sGstCtlHelperExe:
2593 try:
2594 asArgs2 = [ self.sGstCtlHelperExe ]; # Always set argv0.
2595 asArgs2.extend(asArgs); # Add the arguments passed-in.
2596 if not asEnv:
2597 asEnv = [];
2598 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, \
2599 vboxcon.ProcessWaitForFlag_StdOut, \
2600 vboxcon.ProcessWaitForFlag_StdErr ];
2601
2602 fRc, eExitStatus, iExitCode, cbStdOut, cbStdErr, sBuf = \
2603 self.processExecute(oGuestSession, self.sGstCtlHelperExe, asArgs2, sCwd, \
2604 asEnv, aeWaitFor, timeoutMS);
2605 if eExitStatus != vboxcon.ProcessStatus_TerminatedNormally:
2606 reporter.log('VBoxGuestControlHelper failed to run; got exit status %d' % (eExitStatus,));
2607 fRc = False;
2608 except:
2609 fRc = reporter.errorXcpt();
2610
2611 return (fRc, eExitStatus, iExitCode, cbStdOut, cbStdErr, sBuf);
2612
2613 def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2614 """
2615 Tests the guest session environment changes.
2616 """
2617 aoTests = [
2618 # Check basic operations.
2619 tdTestSessionEx([ # Initial environment is empty.
2620 tdStepSessionCheckEnv(),
2621 # Check clearing empty env.
2622 tdStepSessionClearEnv(),
2623 tdStepSessionCheckEnv(),
2624 # Check set.
2625 tdStepSessionSetEnv('FOO', 'BAR'),
2626 tdStepSessionCheckEnv(['FOO=BAR',]),
2627 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2628 tdStepSessionClearEnv(),
2629 tdStepSessionCheckEnv(),
2630 # Check unset.
2631 tdStepSessionUnsetEnv('BAR'),
2632 tdStepSessionCheckEnv(['BAR']),
2633 tdStepSessionClearEnv(),
2634 tdStepSessionCheckEnv(),
2635 # Set + unset.
2636 tdStepSessionSetEnv('FOO', 'BAR'),
2637 tdStepSessionCheckEnv(['FOO=BAR',]),
2638 tdStepSessionUnsetEnv('FOO'),
2639 tdStepSessionCheckEnv(['FOO']),
2640 # Bulk environment changes (via attrib) (shall replace existing 'FOO').
2641 tdStepSessionBulkEnv( ['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2642 tdStepSessionCheckEnv(['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2643 ]),
2644 tdTestSessionEx([ # Check that setting the same value several times works.
2645 tdStepSessionSetEnv('FOO','BAR'),
2646 tdStepSessionCheckEnv([ 'FOO=BAR',]),
2647 tdStepSessionSetEnv('FOO','BAR2'),
2648 tdStepSessionCheckEnv([ 'FOO=BAR2',]),
2649 tdStepSessionSetEnv('FOO','BAR3'),
2650 tdStepSessionCheckEnv([ 'FOO=BAR3',]),
2651 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2652 # Add a little unsetting to the mix.
2653 tdStepSessionSetEnv('BAR', 'BEAR'),
2654 tdStepSessionCheckEnv([ 'FOO=BAR3', 'BAR=BEAR',]),
2655 tdStepSessionUnsetEnv('FOO'),
2656 tdStepSessionCheckEnv([ 'FOO', 'BAR=BEAR',]),
2657 tdStepSessionSetEnv('FOO','BAR4'),
2658 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR',]),
2659 # The environment is case sensitive.
2660 tdStepSessionSetEnv('foo','BAR5'),
2661 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo=BAR5']),
2662 tdStepSessionUnsetEnv('foo'),
2663 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo']),
2664 ]),
2665 tdTestSessionEx([ # Bulk settings merges stuff, last entry standing.
2666 tdStepSessionBulkEnv(['FOO=bar', 'foo=bar', 'FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2667 tdStepSessionCheckEnv(['FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2668 tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2669 tdStepSessionBulkEnv(['2=1+1', 'FOO=doofus2', ]),
2670 tdStepSessionCheckEnv(['2=1+1', 'FOO=doofus2' ]),
2671 ]),
2672 # Invalid variable names.
2673 tdTestSessionEx([
2674 tdStepSessionSetEnv('', 'FOO', vbox.ComError.E_INVALIDARG),
2675 tdStepSessionCheckEnv(),
2676 tdStepRequireMinimumApiVer(5.0), # 4.3 is too relaxed checking input!
2677 tdStepSessionBulkEnv(['', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2678 tdStepSessionCheckEnv(),
2679 tdStepSessionSetEnv('FOO=', 'BAR', vbox.ComError.E_INVALIDARG),
2680 tdStepSessionCheckEnv(),
2681 ]),
2682 # A bit more weird keys/values.
2683 tdTestSessionEx([ tdStepSessionSetEnv('$$$', ''),
2684 tdStepSessionCheckEnv([ '$$$=',]), ]),
2685 tdTestSessionEx([ tdStepSessionSetEnv('$$$', '%%%'),
2686 tdStepSessionCheckEnv([ '$$$=%%%',]),
2687 ]),
2688 tdTestSessionEx([ tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2689 tdStepSessionSetEnv(u'ß$%ß&', ''),
2690 tdStepSessionCheckEnv([ u'ß$%ß&=',]),
2691 ]),
2692 # Misc stuff.
2693 tdTestSessionEx([ tdStepSessionSetEnv('FOO', ''),
2694 tdStepSessionCheckEnv(['FOO=',]),
2695 ]),
2696 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2697 tdStepSessionCheckEnv(['FOO=BAR',])
2698 ],),
2699 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2700 tdStepSessionSetEnv('BAR', 'BAZ'),
2701 tdStepSessionCheckEnv([ 'FOO=BAR', 'BAR=BAZ',]),
2702 ]),
2703 ];
2704 # Leading '=' in the name is okay for windows guests in 6.1 and later (for driver letter CWDs).
2705 if (self.oTstDrv.fpApiVer < 6.1 and self.oTstDrv.fpApiVer >= 5.0) or not oTestVm.isWindows():
2706 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=', '===', vbox.ComError.E_INVALIDARG),
2707 tdStepSessionCheckEnv(),
2708 tdStepSessionSetEnv('=FOO', 'BAR', vbox.ComError.E_INVALIDARG),
2709 tdStepSessionCheckEnv(),
2710 tdStepSessionBulkEnv(['=', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2711 tdStepSessionCheckEnv(),
2712 tdStepSessionBulkEnv(['=FOO', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2713 tdStepSessionCheckEnv(),
2714 tdStepSessionBulkEnv(['=D:=D:/tmp', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2715 tdStepSessionCheckEnv(),
2716 tdStepSessionSetEnv('=D:', 'D:/temp', vbox.ComError.E_INVALIDARG),
2717 tdStepSessionCheckEnv(),
2718 ]));
2719 elif self.oTstDrv.fpApiVer >= 6.1 and oTestVm.isWindows():
2720 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=D:', 'D:/tmp'),
2721 tdStepSessionCheckEnv(['=D:=D:/tmp',]),
2722 tdStepSessionBulkEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2723 tdStepSessionCheckEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2724 tdStepSessionUnsetEnv('=D:'),
2725 tdStepSessionCheckEnv(['=D:', '=FOO', 'foo=bar']),
2726 ]));
2727
2728 return tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession, oTestVm, 'SessionEnv');
2729
2730 def testGuestCtrlSessionSimple(self, oSession, oTxsSession, oTestVm):
2731 """
2732 Tests simple session-based API calls.
2733 """
2734
2735 reporter.log('Testing simple session-based API calls ...');
2736
2737 # Start a valid session.
2738 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2739 try:
2740 oCreds = tdCtxCreds();
2741 oCreds.applyDefaultsIfNotSet(oTestVm);
2742 oGuest = oSession.o.console.guest;
2743 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionSimple");
2744 oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2745 except:
2746 reporter.logXcpt('Starting session for session-based API calls failed');
2747 return False;
2748
2749 fRc = True;
2750
2751 # Note: Starting with r161502 this should be fixed.
2752 # Session 0 separation started with Windows Vista, so skip everything older.
2753 if self.oTstDrv.uRevision >= 161502 \
2754 and oTestVm.isWindows() \
2755 and oTestVm.sKind not in ('WindowsNT3x', 'WindowsNT4', 'Windows2000', 'WindowsXP'):
2756 reporter.testStart('Windows guest processes in session >= 1');
2757 # Test in which Windows session Guest Control processes are being started.
2758 # We don't want them to be started in session 0, as this would prevent desktop interaction and other stuff.
2759 fRc, eExitStatus, iExitCode, _, _, _ = \
2760 self.executeGstCtlHelper(oTxsSession, oGuestSession, [ "show", "win-session-id" ]);
2761 if fRc \
2762 and eExitStatus == vboxcon.ProcessStatus_TerminatedNormally:
2763 if iExitCode >= 1000: # We report 1000 + <session ID> as exit code.
2764 uSessionId = iExitCode - 1000;
2765 if uSessionId >= 1:
2766 reporter.log('Guest processes start in session %d, good' % (uSessionId));
2767 else:
2768 reporter.error('Guest processes start in session 0, expected session >= 1');
2769 else:
2770 reporter.error('Guest Control Helper returned error %d (exit code)' % (iExitCode));
2771 reporter.testDone();
2772
2773 # User home.
2774 if self.oTstDrv.fpApiVer >= 7.0:
2775 reporter.log('Getting user\'s home directory ...');
2776 try:
2777 reporter.log('User home directory: %s' % (oGuestSession.userHome));
2778 except:
2779 fRc = reporter.logXcpt('Getting user home directory failed');
2780
2781 # User documents.
2782 if self.oTstDrv.fpApiVer >= 7.0:
2783 reporter.log('Getting user\'s documents directory ...');
2784 try:
2785 reporter.log('User documents directory: %s' % (oGuestSession.userDocuments));
2786 except:
2787 fRc = reporter.logXcpt('Getting user documents directory failed');
2788
2789 # Mount points. Only available for Guest Additions >= 7.1.
2790 if self.oTstDrv.fpApiVer >= 7.1:
2791 reporter.log('Getting mount points ...');
2792 try:
2793 aMountpoints = oGuestSession.getMountPoints();
2794 reporter.log('Got %ld mount points' % len(aMountpoints))
2795 for mountPoint in aMountpoints:
2796 reporter.log('Mountpoint: %s' % (mountPoint));
2797 except:
2798 fRc = reporter.logXcpt('Getting mount points failed');
2799
2800 # Close the session.
2801 try:
2802 oGuestSession.close();
2803 except:
2804 fRc = reporter.errorXcpt('Closing guest session failed');
2805
2806 return fRc;
2807
2808 def testGuestCtrlSession(self, oSession, oTxsSession, oTestVm):
2809 """
2810 Tests the guest session handling.
2811 """
2812
2813 #
2814 # Tests:
2815 #
2816 atTests = [
2817 # Invalid parameters.
2818 [ tdTestSession(sUser = ''), tdTestResultSession() ],
2819 # User account without a passwort - forbidden.
2820 [ tdTestSession(sPassword = "" ), tdTestResultSession() ],
2821 # Various wrong credentials.
2822 # Note! Only windows cares about sDomain, the other guests ignores it.
2823 # Note! On Guest Additions < 4.3 this always succeeds because these don't
2824 # support creating dedicated sessions. Instead, guest process creation
2825 # then will fail. See note below.
2826 [ tdTestSession(sPassword = 'bar'), tdTestResultSession() ],
2827 [ tdTestSession(sUser = 'foo', sPassword = 'bar'), tdTestResultSession() ],
2828 [ tdTestSession(sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2829 [ tdTestSession(sUser = 'foo', sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2830 ];
2831 if oTestVm.isWindows(): # domain is ignored elsewhere.
2832 atTests.append([ tdTestSession(sDomain = 'boo'), tdTestResultSession() ]);
2833
2834 # Finally, correct credentials.
2835 atTests.append([ tdTestSession(), tdTestResultSession(fRc = True, cNumSessions = 1) ]);
2836
2837 #
2838 # Run the tests.
2839 #
2840 fRc = True;
2841 for (i, tTest) in enumerate(atTests):
2842 oCurTest = tTest[0] # type: tdTestSession
2843 oCurRes = tTest[1] # type: tdTestResult
2844
2845 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2846 if not fRc:
2847 break;
2848 reporter.log('Testing #%d, user="%s", sPassword="%s", sDomain="%s" ...'
2849 % (i, oCurTest.oCreds.sUser, oCurTest.oCreds.sPassword, oCurTest.oCreds.sDomain));
2850 sCurGuestSessionName = 'testGuestCtrlSession: Test #%d' % (i,);
2851 fRc2, oCurGuestSession = oCurTest.createSession(sCurGuestSessionName, fIsError = oCurRes.fRc);
2852
2853 # See note about < 4.3 Guest Additions above.
2854 uProtocolVersion = 2;
2855 if oCurGuestSession is not None:
2856 try:
2857 uProtocolVersion = oCurGuestSession.protocolVersion;
2858 except:
2859 fRc = reporter.errorXcpt('Test #%d' % (i,));
2860
2861 if uProtocolVersion >= 2 and fRc2 is not oCurRes.fRc:
2862 fRc = reporter.error('Test #%d failed: Session creation failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
2863
2864 if fRc2 and oCurGuestSession is None:
2865 fRc = reporter.error('Test #%d failed: no session object' % (i,));
2866 fRc2 = False;
2867
2868 if fRc2:
2869 if uProtocolVersion >= 2: # For Guest Additions < 4.3 getSessionCount() always will return 1.
2870 cCurSessions = oCurTest.getSessionCount(self.oTstDrv.oVBoxMgr);
2871 if cCurSessions != oCurRes.cNumSessions:
2872 fRc = reporter.error('Test #%d failed: Session count does not match: Got %d, expected %d'
2873 % (i, cCurSessions, oCurRes.cNumSessions));
2874 try:
2875 sObjName = oCurGuestSession.name;
2876 except:
2877 fRc = reporter.errorXcpt('Test #%d' % (i,));
2878 else:
2879 if sObjName != sCurGuestSessionName:
2880 fRc = reporter.error('Test #%d failed: Session name does not match: Got "%s", expected "%s"'
2881 % (i, sObjName, sCurGuestSessionName));
2882 fRc2 = oCurTest.closeSession();
2883 if fRc2 is False:
2884 fRc = reporter.error('Test #%d failed: Session could not be closed' % (i,));
2885
2886 if fRc is False:
2887 return (False, oTxsSession);
2888
2889 #
2890 # Multiple sessions.
2891 #
2892 cMaxGuestSessions = 31; # Maximum number of concurrent guest session allowed.
2893 # Actually, this is 32, but we don't test session 0.
2894 aoMultiSessions = {};
2895 reporter.log2('Opening multiple guest tsessions at once ...');
2896 for i in xrange(cMaxGuestSessions + 1):
2897 aoMultiSessions[i] = tdTestSession(sSessionName = 'MultiSession #%d' % (i,));
2898 fRc = aoMultiSessions[i].setEnvironment(oSession, oTxsSession, oTestVm);
2899 if not fRc:
2900 break;
2901
2902 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2903 reporter.log2('MultiSession test #%d count is %d' % (i, cCurSessions));
2904 if cCurSessions != i:
2905 return (reporter.error('MultiSession count is %d, expected %d' % (cCurSessions, i)), oTxsSession);
2906 fRc2, _ = aoMultiSessions[i].createSession('MultiSession #%d' % (i,), i < cMaxGuestSessions);
2907 if fRc2 is not True:
2908 if i < cMaxGuestSessions:
2909 return (reporter.error('MultiSession #%d test failed' % (i,)), oTxsSession);
2910 reporter.log('MultiSession #%d exceeded concurrent guest session count, good' % (i,));
2911 break;
2912
2913 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2914 if cCurSessions is not cMaxGuestSessions:
2915 return (reporter.error('Final session count %d, expected %d ' % (cCurSessions, cMaxGuestSessions,)), oTxsSession);
2916
2917 reporter.log2('Closing MultiSessions ...');
2918 for i in xrange(cMaxGuestSessions):
2919 # Close this session:
2920 oClosedGuestSession = aoMultiSessions[i].oGuestSession;
2921 fRc2 = aoMultiSessions[i].closeSession();
2922 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr)
2923 reporter.log2('MultiSession #%d count is %d' % (i, cCurSessions,));
2924 if fRc2 is False:
2925 fRc = reporter.error('Closing MultiSession #%d failed' % (i,));
2926 elif cCurSessions != cMaxGuestSessions - (i + 1):
2927 fRc = reporter.error('Expected %d session after closing #%d, got %d instead'
2928 % (cMaxGuestSessions - (i + 1), cCurSessions, i,));
2929 assert aoMultiSessions[i].oGuestSession is None or not fRc2;
2930 ## @todo any way to check that the session is closed other than the 'sessions' attribute?
2931
2932 # Try check that none of the remaining sessions got closed.
2933 try:
2934 aoGuestSessions = self.oTstDrv.oVBoxMgr.getArray(atTests[0][0].oGuest, 'sessions');
2935 except:
2936 return (reporter.errorXcpt('i=%d/%d' % (i, cMaxGuestSessions,)), oTxsSession);
2937 if oClosedGuestSession in aoGuestSessions:
2938 fRc = reporter.error('i=%d/%d: %s should not be in %s'
2939 % (i, cMaxGuestSessions, oClosedGuestSession, aoGuestSessions));
2940 if i + 1 < cMaxGuestSessions: # Not sure what xrange(2,2) does...
2941 for j in xrange(i + 1, cMaxGuestSessions):
2942 if aoMultiSessions[j].oGuestSession not in aoGuestSessions:
2943 fRc = reporter.error('i=%d/j=%d/%d: %s should be in %s'
2944 % (i, j, cMaxGuestSessions, aoMultiSessions[j].oGuestSession, aoGuestSessions));
2945 ## @todo any way to check that they work?
2946
2947 ## @todo Test session timeouts.
2948
2949 fRc2 = self.testGuestCtrlSessionSimple(oSession, oTxsSession, oTestVm);
2950 if fRc:
2951 fRc = fRc2;
2952
2953 return (fRc, oTxsSession);
2954
2955 def testGuestCtrlSessionFileRefs(self, oSession, oTxsSession, oTestVm):
2956 """
2957 Tests the guest session file reference handling.
2958 """
2959
2960 # Find a file to play around with:
2961 sFile = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2962
2963 # Use credential defaults.
2964 oCreds = tdCtxCreds();
2965 oCreds.applyDefaultsIfNotSet(oTestVm);
2966
2967 # Number of stale guest files to create.
2968 cStaleFiles = 10;
2969
2970 #
2971 # Start a session.
2972 #
2973 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2974 try:
2975 oGuest = oSession.o.console.guest;
2976 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionFileRefs");
2977 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2978 except:
2979 return (reporter.errorXcpt(), oTxsSession);
2980
2981 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2982 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2983 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2984 reporter.log('Session successfully started');
2985
2986 #
2987 # Open guest files and "forget" them (stale entries).
2988 # For them we don't have any references anymore intentionally.
2989 #
2990 reporter.log2('Opening stale files');
2991 fRc = True;
2992 for i in xrange(0, cStaleFiles):
2993 try:
2994 if self.oTstDrv.fpApiVer >= 5.0:
2995 oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly, vboxcon.FileOpenAction_OpenExisting, 0);
2996 else:
2997 oGuestSession.fileOpen(sFile, "r", "oe", 0);
2998 # Note: Use a timeout in the call above for not letting the stale processes
2999 # hanging around forever. This can happen if the installed Guest Additions
3000 # do not support terminating guest processes.
3001 except:
3002 fRc = reporter.errorXcpt('Opening stale file #%d failed:' % (i,));
3003 break;
3004
3005 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3006 except: fRc = reporter.errorXcpt();
3007 else:
3008 if cFiles != cStaleFiles:
3009 fRc = reporter.error('Got %d stale files, expected %d' % (cFiles, cStaleFiles));
3010
3011 if fRc is True:
3012 #
3013 # Open non-stale files and close them again.
3014 #
3015 reporter.log2('Opening non-stale files');
3016 aoFiles = [];
3017 for i in xrange(0, cStaleFiles):
3018 try:
3019 if self.oTstDrv.fpApiVer >= 5.0:
3020 oCurFile = oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly,
3021 vboxcon.FileOpenAction_OpenExisting, 0);
3022 else:
3023 oCurFile = oGuestSession.fileOpen(sFile, "r", "oe", 0);
3024 aoFiles.append(oCurFile);
3025 except:
3026 fRc = reporter.errorXcpt('Opening non-stale file #%d failed:' % (i,));
3027 break;
3028
3029 # Check the count.
3030 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3031 except: fRc = reporter.errorXcpt();
3032 else:
3033 if cFiles != cStaleFiles * 2:
3034 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles * 2));
3035
3036 # Close them.
3037 reporter.log2('Closing all non-stale files again ...');
3038 for i, oFile in enumerate(aoFiles):
3039 try:
3040 oFile.close();
3041 except:
3042 fRc = reporter.errorXcpt('Closing non-stale file #%d failed:' % (i,));
3043
3044 # Check the count again.
3045 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3046 except: fRc = reporter.errorXcpt();
3047 # Here we count the stale files (that is, files we don't have a reference
3048 # anymore for) and the opened and then closed non-stale files (that we still keep
3049 # a reference in aoFiles[] for).
3050 if cFiles != cStaleFiles:
3051 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles));
3052
3053 #
3054 # Check that all (referenced) non-stale files are now in the "closed" state.
3055 #
3056 reporter.log2('Checking statuses of all non-stale files ...');
3057 for i, oFile in enumerate(aoFiles):
3058 try:
3059 eFileStatus = aoFiles[i].status;
3060 except:
3061 fRc = reporter.errorXcpt('Checking status of file #%d failed:' % (i,));
3062 else:
3063 if eFileStatus != vboxcon.FileStatus_Closed:
3064 fRc = reporter.error('Non-stale file #%d has status %d, expected %d'
3065 % (i, eFileStatus, vboxcon.FileStatus_Closed));
3066
3067 if fRc is True:
3068 reporter.log2('All non-stale files closed');
3069
3070 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3071 except: fRc = reporter.errorXcpt();
3072 else: reporter.log2('Final guest session file count: %d' % (cFiles,));
3073
3074 #
3075 # Now try to close the session and see what happens.
3076 # Note! Session closing is why we've been doing all the 'if fRc is True' stuff above rather than returning.
3077 #
3078 reporter.log2('Closing guest session ...');
3079 try:
3080 oGuestSession.close();
3081 except:
3082 fRc = reporter.errorXcpt('Testing for stale processes failed:');
3083
3084 return (fRc, oTxsSession);
3085
3086 #def testGuestCtrlSessionDirRefs(self, oSession, oTxsSession, oTestVm):
3087 # """
3088 # Tests the guest session directory reference handling.
3089 # """
3090
3091 # fRc = True;
3092 # return (fRc, oTxsSession);
3093
3094 def testGuestCtrlSessionProcRefs(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
3095 """
3096 Tests the guest session process reference handling.
3097 """
3098
3099 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3100 asArgs = [sShell,];
3101
3102 # Use credential defaults.
3103 oCreds = tdCtxCreds();
3104 oCreds.applyDefaultsIfNotSet(oTestVm);
3105
3106 # Number of guest processes per group to create.
3107 cProcsPerGroup = 10;
3108
3109 #
3110 # Start a session.
3111 #
3112 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3113 try:
3114 oGuest = oSession.o.console.guest;
3115 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionProcRefs");
3116 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3117 except:
3118 return (reporter.errorXcpt(), oTxsSession);
3119
3120 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3121 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3122 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3123 reporter.log('Session successfully started');
3124
3125 #
3126 # Fire off forever-running processes and "forget" them (stale entries).
3127 # For them we don't have any references anymore intentionally.
3128 #
3129 reporter.log('Starting stale processes...');
3130 fRc = True;
3131 for i in xrange(0, cProcsPerGroup):
3132 try:
3133 reporter.log2('Starting stale process #%d...' % (i));
3134 self.processCreateWrapper(oGuestSession, sShell, asArgs, "", # Working directory.
3135 [], # Environment changes.
3136 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], 30 * 1000);
3137 # Note: Not keeping a process reference from the created process above is intentional and part of the test!
3138
3139 # Note: Use a timeout in the call above for not letting the stale processes
3140 # hanging around forever. This can happen if the installed Guest Additions
3141 # do not support terminating guest processes.
3142 except:
3143 fRc = reporter.errorXcpt('Creating stale process #%d failed:' % (i,));
3144 break;
3145
3146 if fRc:
3147 reporter.log2('Starting stale processes successful');
3148 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3149 except: fRc = reporter.errorXcpt();
3150 else:
3151 reporter.log2('Proccess count is: %d' % (cProcs));
3152 if cProcs != cProcsPerGroup:
3153 fRc = reporter.error('Got %d stale processes, expected %d (stale)' % (cProcs, cProcsPerGroup));
3154
3155 if fRc:
3156 #
3157 # Fire off non-stale processes and wait for termination.
3158 #
3159 if oTestVm.isWindows() or oTestVm.isOS2():
3160 asArgs = [ sShell, '/C', 'dir', '/S', self.oTstDrv.getGuestSystemDir(oTestVm), ];
3161 else:
3162 asArgs = [ sShell, '-c', 'ls -la ' + self.oTstDrv.getGuestSystemDir(oTestVm), ];
3163 reporter.log('Starting non-stale processes...');
3164 aoProcs = [];
3165 for i in xrange(0, cProcsPerGroup):
3166 try:
3167 reporter.log2('Starting non-stale process #%d...' % (i));
3168 oCurProc = self.processCreateWrapper(oGuestSession, sShell, asArgs,
3169 "", # Working directory.
3170 [], [], 0); # Infinite timeout.
3171 aoProcs.append(oCurProc);
3172 except:
3173 fRc = reporter.errorXcpt('Creating non-stale process #%d failed:' % (i,));
3174 break;
3175
3176 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3177 except: fRc = reporter.errorXcpt();
3178 else:
3179 reporter.log2('Proccess count is: %d' % (cProcs));
3180
3181 reporter.log('Waiting for non-stale processes to terminate...');
3182 for i, oProcess in enumerate(aoProcs):
3183 try:
3184 reporter.log('Waiting for non-stale process #%d...' % (i));
3185 eWaitResult = oProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 30 * 1000);
3186 eProcessStatus = oProcess.status;
3187 except:
3188 fRc = reporter.errorXcpt('Waiting for non-stale process #%d failed:' % (i,));
3189 else:
3190 if eProcessStatus != vboxcon.ProcessStatus_TerminatedNormally:
3191 fRc = reporter.error('Waiting for non-stale processes #%d resulted in status %d, expected %d (wr=%d)'
3192 % (i, eProcessStatus, vboxcon.ProcessStatus_TerminatedNormally, eWaitResult));
3193 if fRc:
3194 reporter.log('All non-stale processes ended successfully');
3195
3196 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3197 except: fRc = reporter.errorXcpt();
3198 else:
3199 reporter.log2('Proccess count is: %d' % (cProcs));
3200
3201 # Here we count the stale processes (that is, processes we don't have a reference
3202 # anymore for) and the started + ended non-stale processes (that we still keep
3203 # a reference in aoProcesses[] for).
3204 cProcsExpected = cProcsPerGroup * 2;
3205 if cProcs != cProcsExpected:
3206 fRc = reporter.error('Got %d total processes, expected %d (stale vs. non-stale)' \
3207 % (cProcs, cProcsExpected));
3208 #
3209 # Fire off non-stale blocking processes which are terminated via terminate().
3210 #
3211 if oTestVm.isWindows() or oTestVm.isOS2():
3212 sCmd = sShell;
3213 asArgs = [ sCmd, '/C', 'pause'];
3214 else:
3215 sCmd = '/usr/bin/yes';
3216 asArgs = [ sCmd ];
3217 reporter.log('Starting blocking processes...');
3218 aoProcs = [];
3219 for i in xrange(0, cProcsPerGroup):
3220 try:
3221 reporter.log2('Starting blocking process #%d...' % (i));
3222 oCurProc = self.processCreateWrapper(oGuestSession, sCmd, asArgs,
3223 "", # Working directory.
3224 [], [], 30 * 1000);
3225
3226 # Note: Use a timeout in the call above for not letting the stale processes
3227 # hanging around forever. This can happen if the installed Guest Additions
3228 # do not support terminating guest processes.
3229 try:
3230 reporter.log('Waiting for blocking process #%d getting started...' % (i));
3231 eWaitResult = oCurProc.waitForArray([ vboxcon.ProcessWaitForFlag_Start, ], 30 * 1000);
3232 eProcessStatus = oCurProc.status;
3233 except:
3234 fRc = reporter.errorXcpt('Waiting for blocking process #%d failed:' % (i,));
3235 else:
3236 if eProcessStatus != vboxcon.ProcessStatus_Started:
3237 fRc = reporter.error('Waiting for blocking processes #%d resulted in status %d, expected %d (wr=%d)'
3238 % (i, eProcessStatus, vboxcon.ProcessStatus_Started, eWaitResult));
3239 aoProcs.append(oCurProc);
3240 except:
3241 fRc = reporter.errorXcpt('Creating blocking process #%d failed:' % (i,));
3242 break;
3243
3244 if fRc:
3245 reporter.log2('Starting blocking processes successful');
3246
3247 reporter.log2('Terminating blocking processes...');
3248 for i, oProcess in enumerate(aoProcs):
3249 try:
3250 reporter.log('Terminating blocking process #%d...' % (i));
3251 oProcess.terminate();
3252 except: # Termination might not be supported, just skip and log it.
3253 reporter.logXcpt('Termination of blocking process #%d failed, skipped:' % (i,));
3254 if self.oTstDrv.fpApiVer >= 6.1: # Termination is supported since 5.2 or so.
3255 fRc = False;
3256 if fRc:
3257 reporter.log('All blocking processes were terminated successfully');
3258
3259 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3260 except: fRc = reporter.errorXcpt();
3261 else:
3262 # There still should be 20 processes because we just terminated the 10 blocking ones above.
3263 cProcsExpected = cProcsPerGroup * 2;
3264 if cProcs != cProcsExpected:
3265 fRc = reporter.error('Got %d total processes, expected %d (final)' % (cProcs, cProcsExpected));
3266 reporter.log2('Final guest session processes count: %d' % (cProcs,));
3267
3268 if not fRc:
3269 aoProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3270 for i, oProc in enumerate(aoProcs):
3271 try:
3272 aoArgs = self.oTstDrv.oVBoxMgr.getArray(oProc, 'arguments');
3273 reporter.log('Process %d (\'%s\') still around, status is %d' \
3274 % (i, ' '.join([str(x) for x in aoArgs]), oProc.status));
3275 except:
3276 reporter.errorXcpt('Process lookup failed:');
3277 #
3278 # Now try to close the session and see what happens.
3279 #
3280 reporter.log('Closing guest session ...');
3281 try:
3282 oGuestSession.close();
3283 except:
3284 fRc = reporter.errorXcpt('Closing session for testing process references failed:');
3285
3286 return (fRc, oTxsSession);
3287
3288 def testGuestCtrlExec(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
3289 """
3290 Tests the basic execution feature.
3291 """
3292
3293 # Paths:
3294 sVBoxControl = None; # Only available on supported Windows guests.
3295 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3296 sShellOpt = '/C' if oTestVm.isWindows() or oTestVm.isOS2() else '-c';
3297 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3298 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
3299 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
3300 if oTestVm.isWindows() or oTestVm.isOS2():
3301 sImageOut = self.oTstDrv.getGuestSystemShell(oTestVm);
3302 if oTestVm.isWindows():
3303 sVBoxControl = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm), 'VBoxControl.exe');
3304 else:
3305 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3306 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/ls", fIgnoreErrors = True):
3307 sImageOut = "/bin/ls";
3308 else:
3309 sImageOut = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'ls');
3310 if oTestVm.isLinux(): ## @todo check solaris and darwin.
3311 sVBoxControl = "/usr/bin/VBoxControl"; # Symlink
3312
3313 # Use credential defaults.
3314 oCreds = tdCtxCreds();
3315 oCreds.applyDefaultsIfNotSet(oTestVm);
3316
3317 atInvalid = [
3318 # Invalid parameters.
3319 [ tdTestExec(), tdTestResultExec() ],
3320 # Non-existent / invalid image.
3321 [ tdTestExec(sCmd = "non-existent"), tdTestResultExec() ],
3322 [ tdTestExec(sCmd = "non-existent2"), tdTestResultExec() ],
3323 # Use an invalid format string.
3324 [ tdTestExec(sCmd = "%$%%%&"), tdTestResultExec() ],
3325 # More stuff.
3326 [ tdTestExec(sCmd = u"ƒ‰‹ˆ÷‹¸"), tdTestResultExec() ],
3327 [ tdTestExec(sCmd = "???://!!!"), tdTestResultExec() ],
3328 [ tdTestExec(sCmd = "<>!\\"), tdTestResultExec() ],
3329 # Enable as soon as ERROR_BAD_DEVICE is implemented.
3330 #[ tdTestExec(sCmd = "CON", tdTestResultExec() ],
3331 ];
3332
3333 atExec = [];
3334 if oTestVm.isWindows() or oTestVm.isOS2():
3335 if oTestVm.sKind == 'WindowsNT4':
3336 # For whatever reason NT4 SP6 (tst-nt4sp6) returns exit code 2 for existing *and* non-existing files.
3337 # I've manually checked that on the VM itself, so this is *not* a bug in the Guest Control code.
3338 # So we have to tweak the expected exit codes here in order to make the following tests pass.
3339 iExitCodeForExistingFiles = 2
3340 iExitCodeForNonExistingFiles = 2
3341 else:
3342 iExitCodeForExistingFiles = 0
3343 iExitCodeForNonExistingFiles = 1
3344 atExec += [
3345 # Basic execution.
3346 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3347 tdTestResultExec(fRc = True) ],
3348 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sFileForReading ]),
3349 tdTestResultExec(fRc = True, iExitCode = iExitCodeForExistingFiles) ],
3350 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir + '\\nonexist.dll' ]),
3351 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3352 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ]),
3353 tdTestResultExec(fRc = True, iExitCode = 1) ],
3354 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3355 tdTestResultExec(fRc = True, iExitCode = 1) ],
3356 # StdOut.
3357 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3358 tdTestResultExec(fRc = True) ],
3359 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ]),
3360 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3361 # StdErr.
3362 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3363 tdTestResultExec(fRc = True) ],
3364 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ]),
3365 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3366 # StdOut + StdErr.
3367 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3368 tdTestResultExec(fRc = True) ],
3369 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ]),
3370 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3371 ];
3372
3373 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3374 atExec.extend([
3375 # Current working directory set (VBox >= 7.1).
3376 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3377 tdTestResultExec(fRc = True) ]
3378 ]);
3379
3380 # atExec.extend([
3381 # FIXME: Failing tests.
3382 # Environment variables.
3383 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3384 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3385 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3386 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3387 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3388 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3389 # aEnv = [ 'TEST_FOO=BAR' ],
3390 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3391 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3392 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3393 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3394 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3395 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3396
3397 ## @todo Create some files (or get files) we know the output size of to validate output length!
3398 ## @todo Add task which gets killed at some random time while letting the guest output something.
3399 #];
3400 else:
3401 atExec += [
3402 # Basic execution.
3403 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '-R', sSystemDir ]),
3404 tdTestResultExec(fRc = True) ],
3405 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sFileForReading ]),
3406 tdTestResultExec(fRc = True) ],
3407 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '--wrong-parameter' ]),
3408 tdTestResultExec(fRc = True, iExitCode = 2) ],
3409 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/non/existent' ]),
3410 tdTestResultExec(fRc = True, iExitCode = 2) ],
3411 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3412 tdTestResultExec(fRc = True, iExitCode = 127) ],
3413 # StdOut.
3414 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3415 tdTestResultExec(fRc = True) ],
3416 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdout-non-existing' ]),
3417 tdTestResultExec(fRc = True, iExitCode = 2) ],
3418 # StdErr.
3419 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3420 tdTestResultExec(fRc = True) ],
3421 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stderr-non-existing' ]),
3422 tdTestResultExec(fRc = True, iExitCode = 2) ],
3423 # StdOut + StdErr.
3424 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3425 tdTestResultExec(fRc = True) ],
3426 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdouterr-non-existing' ]),
3427 tdTestResultExec(fRc = True, iExitCode = 2) ],
3428 ];
3429
3430 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3431 atExec.extend([
3432 # Current working directory set (VBox >= 7.1).
3433 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '-R', sSystemDir ]),
3434 tdTestResultExec(fRc = True) ]
3435 ]);
3436
3437 # atExec.extend([
3438 # FIXME: Failing tests.
3439 # Environment variables.
3440 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3441 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3442 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3443 #
3444 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3445 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3446 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3447 # aEnv = [ 'TEST_FOO=BAR' ],
3448 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3449 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3450 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3451 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3452 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3453 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3454
3455 ## @todo Create some files (or get files) we know the output size of to validate output length!
3456 ## @todo Add task which gets killed at some random time while letting the guest output something.
3457 #];
3458
3459 #
3460 #for iExitCode in xrange(0, 127):
3461 # atExec.append([ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'exit %s' % iExitCode ]),
3462 # tdTestResultExec(fRc = True, iExitCode = iExitCode) ]);
3463
3464 if sVBoxControl \
3465 and self.oTstDrv.fpApiVer >= 6.0: # Investigate with this doesn't work on (<) 5.2.
3466 # Paths with spaces on windows.
3467 atExec.append([ tdTestExec(sCmd = sVBoxControl, asArgs = [ sVBoxControl, 'version' ],
3468 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3469 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3470 tdTestResultExec(fRc = True) ]);
3471
3472 # Test very long arguments. Be careful when tweaking this to not break the tests.
3473 # Regarding paths:
3474 # - We have RTPATH_BIG_MAX (64K)
3475 # - MSDN says 32K for CreateFileW()
3476 # - On Windows, each path component must not be longer than MAX_PATH (260), see
3477 # https://docs.microsoft.com/en-us/windows/win32/fileio/filesystem-functionality-comparison#limits
3478 #
3479 # Old(er) Windows OSes tend to crash in cmd.exe, so skip this on these OSes.
3480 if self.oTstDrv.fpApiVer >= 6.1 \
3481 and oTestVm.sKind not in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
3482 sEndMarker = '--end-marker';
3483 if oTestVm.isWindows() \
3484 or oTestVm.isOS2():
3485 sCmd = sShell;
3486 else:
3487 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3488 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/echo", fIgnoreErrors = True):
3489 sCmd = "/bin/echo";
3490 else:
3491 sCmd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'echo');
3492
3493 for _ in xrange(0, 16):
3494 if oTestVm.isWindows() \
3495 or oTestVm.isOS2():
3496 asArgs = [ sShell, sShellOpt, "echo" ];
3497 else:
3498 asArgs = [ sCmd ];
3499
3500 # Append a random number of arguments with random length.
3501 for _ in xrange(0, self.oTestFiles.oRandom.randrange(1, 64)):
3502 asArgs.append(''.join(random.choice(string.ascii_lowercase)
3503 for _ in range(self.oTestFiles.oRandom.randrange(1, 196))));
3504
3505 asArgs.append(sEndMarker);
3506
3507 reporter.log2('asArgs=%s (%d args), type=%s' % (limitString(asArgs), len(asArgs), type(asArgs)));
3508
3509 ## @todo Check limits; on Ubuntu with 256KB IPRT returns VERR_NOT_IMPLEMENTED.
3510 # Use a higher timeout (15 min) than usual for these long checks.
3511 atExec.append([ tdTestExec(sCmd = sCmd, asArgs = asArgs,
3512 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3513 vboxcon.ProcessCreateFlag_WaitForStdErr ],
3514 timeoutMS = 15 * 60 * 1000),
3515 tdTestResultExec(fRc = True) ]);
3516
3517 # Build up the final test array for the first batch.
3518 atTests = atInvalid + atExec;
3519
3520 #
3521 # First batch: One session per guest process.
3522 #
3523 reporter.log('One session per guest process ...');
3524 fRc = True;
3525 for (i, tTest) in enumerate(atTests):
3526 oCurTest = tTest[0] # type: tdTestExec
3527 oCurRes = tTest[1] # type: tdTestResultExec
3528 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3529 if not fRc:
3530 break;
3531 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlExec: Test #%d' % (i,));
3532 if fRc2 is not True:
3533 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3534 break;
3535 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession) and fRc;
3536 fRc = oCurTest.closeSession() and fRc;
3537
3538 reporter.log('Execution of all tests done, checking for stale sessions');
3539
3540 # No sessions left?
3541 try:
3542 aSessions = self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions');
3543 except:
3544 fRc = reporter.errorXcpt();
3545 else:
3546 cSessions = len(aSessions);
3547 if cSessions != 0:
3548 fRc = reporter.error('Found %d stale session(s), expected 0:' % (cSessions,));
3549 for (i, aSession) in enumerate(aSessions):
3550 try: reporter.log(' Stale session #%d ("%s")' % (aSession.id, aSession.name));
3551 except: reporter.errorXcpt();
3552
3553 if fRc is not True:
3554 return (fRc, oTxsSession);
3555
3556 reporter.log('Now using one guest session for all tests ...');
3557
3558 #
3559 # Second batch: One session for *all* guest processes.
3560 #
3561
3562 # Create session.
3563 reporter.log('Creating session for all tests ...');
3564 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
3565 try:
3566 oGuest = oSession.o.console.guest;
3567 oCurGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain,
3568 'testGuestCtrlExec: One session for all tests');
3569 except:
3570 return (reporter.errorXcpt(), oTxsSession);
3571
3572 try:
3573 eWaitResult = oCurGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3574 except:
3575 fRc = reporter.errorXcpt('Waiting for guest session to start failed:');
3576 else:
3577 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3578 fRc = reporter.error('Session did not start successfully, returned wait result: %d' % (eWaitResult,));
3579 else:
3580 reporter.log('Session successfully started');
3581
3582 # Do the tests within this session.
3583 for (i, tTest) in enumerate(atTests):
3584 oCurTest = tTest[0] # type: tdTestExec
3585 oCurRes = tTest[1] # type: tdTestResultExec
3586
3587 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3588 if not fRc:
3589 break;
3590 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession);
3591 if fRc is False:
3592 break;
3593
3594 # Close the session.
3595 reporter.log2('Closing guest session ...');
3596 try:
3597 oCurGuestSession.close();
3598 oCurGuestSession = None;
3599 except:
3600 fRc = reporter.errorXcpt('Closing guest session failed:');
3601
3602 # No sessions left?
3603 reporter.log('Execution of all tests done, checking for stale sessions again');
3604 try: cSessions = len(self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions'));
3605 except: fRc = reporter.errorXcpt();
3606 else:
3607 if cSessions != 0:
3608 fRc = reporter.error('Found %d stale session(s), expected 0' % (cSessions,));
3609 return (fRc, oTxsSession);
3610
3611 def threadForTestGuestCtrlSessionReboot(self, oGuestProcess):
3612 """
3613 Thread routine which waits for the stale guest process getting terminated (or some error)
3614 while the main test routine reboots the guest. It then compares the expected guest process result
3615 and logs an error if appropriate.
3616 """
3617 reporter.log('Waiting for process to get terminated at reboot ...');
3618 try:
3619 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate ], 5 * 60 * 1000);
3620 except:
3621 return reporter.errorXcpt('waitForArray failed');
3622 try:
3623 eStatus = oGuestProcess.status
3624 except:
3625 return reporter.errorXcpt('failed to get status (wait result %d)' % (eWaitResult,));
3626
3627 if eWaitResult == vboxcon.ProcessWaitResult_Terminate and eStatus == vboxcon.ProcessStatus_Down:
3628 reporter.log('Stale process was correctly terminated (status: down)');
3629 return True;
3630
3631 return reporter.error('Process wait across reboot failed: eWaitResult=%d, expected %d; eStatus=%d, expected %d'
3632 % (eWaitResult, vboxcon.ProcessWaitResult_Terminate, eStatus, vboxcon.ProcessStatus_Down,));
3633
3634 def testGuestCtrlSessionReboot(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3635 """
3636 Tests guest object notifications when a guest gets rebooted / shutdown.
3637
3638 These notifications gets sent from the guest sessions in order to make API clients
3639 aware of guest session changes.
3640
3641 To test that we create a stale guest process and trigger a reboot of the guest.
3642 """
3643
3644 ## @todo backport fixes to 6.0 and maybe 5.2
3645 if self.oTstDrv.fpApiVer <= 6.0:
3646 reporter.log('Skipping: Required fixes not yet backported!');
3647 return None;
3648
3649 # Use credential defaults.
3650 oCreds = tdCtxCreds();
3651 oCreds.applyDefaultsIfNotSet(oTestVm);
3652
3653 fRebooted = False;
3654 fRc = True;
3655
3656 #
3657 # Start a session.
3658 #
3659 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3660 try:
3661 oGuest = oSession.o.console.guest;
3662 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionReboot");
3663 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3664 except:
3665 return (reporter.errorXcpt(), oTxsSession);
3666
3667 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3668 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3669 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3670 reporter.log('Session successfully started');
3671
3672 #
3673 # Create a process.
3674 #
3675 # That process will also be used later to see if the session cleanup worked upon reboot.
3676 #
3677 sImage = self.oTstDrv.getGuestSystemShell(oTestVm);
3678 asArgs = [ sImage, ];
3679 aEnv = [];
3680 afFlags = [];
3681 try:
3682 oGuestProcess = self.processCreateWrapper(oGuestSession, sImage, asArgs,
3683 "", # Working directory.
3684 aEnv, afFlags, 30 * 1000);
3685 except:
3686 fRc = reporter.error('Failed to start shell process (%s)' % (sImage,));
3687 else:
3688 try:
3689 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3690 except:
3691 fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3692 else:
3693 # Check the result and state:
3694 try: eStatus = oGuestProcess.status;
3695 except: fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3696 else:
3697 reporter.log2('Starting process wait result returned: %d; Process status is: %d' % (eWaitResult, eStatus,));
3698 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3699 fRc = reporter.error('wait for ProcessWaitForFlag_Start failed: %d, expected %d (Start)'
3700 % (eWaitResult, vboxcon.ProcessWaitResult_Start,));
3701 elif eStatus != vboxcon.ProcessStatus_Started:
3702 fRc = reporter.error('Unexpected process status after startup: %d, wanted %d (Started)'
3703 % (eStatus, vboxcon.ProcessStatus_Started,));
3704 else:
3705 # Create a thread that waits on the process to terminate
3706 reporter.log('Creating reboot thread ...');
3707 oThreadReboot = threading.Thread(target = self.threadForTestGuestCtrlSessionReboot,
3708 args = (oGuestProcess,),
3709 name = 'threadForTestGuestCtrlSessionReboot');
3710 oThreadReboot.setDaemon(True); # pylint: disable=deprecated-method
3711 oThreadReboot.start();
3712
3713 # Do the reboot.
3714 reporter.log('Rebooting guest and reconnecting TXS ...');
3715 (oSession, oTxsSession) = self.oTstDrv.txsRebootAndReconnectViaTcp(oSession, oTxsSession,
3716 cMsTimeout = 3 * 60000);
3717 if oSession \
3718 and oTxsSession:
3719 # Set reboot flag (needed later for session closing).
3720 fRebooted = True;
3721 else:
3722 reporter.error('Rebooting via TXS failed');
3723 try: oGuestProcess.terminate();
3724 except: reporter.logXcpt();
3725 fRc = False;
3726
3727 reporter.log('Waiting for thread to finish ...');
3728 oThreadReboot.join();
3729
3730 # Check that the guest session now still has the formerly guest process object created above,
3731 # but with the "down" status now (because of guest reboot).
3732 try:
3733 aoGuestProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3734 if len(aoGuestProcs) == 1:
3735 enmProcSts = aoGuestProcs[0].status;
3736 if enmProcSts != vboxcon.ProcessStatus_Down:
3737 fRc = reporter.error('Old guest process (before reboot) has status %d, expected %s' \
3738 % (enmProcSts, vboxcon.ProcessStatus_Down));
3739 else:
3740 fRc = reporter.error('Old guest session (before reboot) has %d processes registered, expected 1' \
3741 % (len(aoGuestProcs)));
3742 except:
3743 fRc = reporter.errorXcpt();
3744 #
3745 # Try make sure we don't leave with a stale process on failure.
3746 #
3747 try: oGuestProcess.terminate();
3748 except: reporter.logXcpt();
3749
3750 #
3751 # Close the session.
3752 #
3753 reporter.log2('Closing guest session ...');
3754 try:
3755 oGuestSession.close();
3756 except:
3757 # Closing the guest session will fail when the guest reboot has been triggered,
3758 # as the session object will be cleared on a guest reboot.
3759 if fRebooted:
3760 reporter.logXcpt('Closing guest session failed, good (guest rebooted)');
3761 else: # ... otherwise this (still) should succeed. Report so if it doesn't.
3762 reporter.errorXcpt('Closing guest session failed');
3763
3764 return (fRc, oTxsSession);
3765
3766 def testGuestCtrlExecTimeout(self, oSession, oTxsSession, oTestVm):
3767 """
3768 Tests handling of timeouts of started guest processes.
3769 """
3770
3771 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3772
3773 # Use credential defaults.
3774 oCreds = tdCtxCreds();
3775 oCreds.applyDefaultsIfNotSet(oTestVm);
3776
3777 #
3778 # Create a session.
3779 #
3780 try:
3781 oGuest = oSession.o.console.guest;
3782 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlExecTimeout");
3783 eWaitResult = oGuestSession.waitForArray([ vboxcon.GuestSessionWaitForFlag_Start, ], 30 * 1000);
3784 except:
3785 return (reporter.errorXcpt(), oTxsSession);
3786
3787 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3788 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3789 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3790 reporter.log('Session successfully started');
3791
3792 #
3793 # Create a process which never terminates and should timeout when
3794 # waiting for termination.
3795 #
3796 fRc = True;
3797 try:
3798 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [ sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3799 "", # Working directory.
3800 [], [], 30 * 1000);
3801 except:
3802 fRc = reporter.errorXcpt();
3803 else:
3804 reporter.log('Waiting for process 1 being started ...');
3805 try:
3806 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3807 except:
3808 fRc = reporter.errorXcpt();
3809 else:
3810 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3811 fRc = reporter.error('Waiting for process 1 to start failed, got status %d' % (eWaitResult,));
3812 else:
3813 for msWait in (1, 32, 2000,):
3814 reporter.log('Waiting for process 1 to time out within %sms ...' % (msWait,));
3815 try:
3816 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], msWait);
3817 except:
3818 fRc = reporter.errorXcpt();
3819 break;
3820 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3821 fRc = reporter.error('Waiting for process 1 did not time out in %sms as expected: %d'
3822 % (msWait, eWaitResult,));
3823 break;
3824 reporter.log('Waiting for process 1 timed out in %u ms, good' % (msWait,));
3825
3826 try:
3827 oCurProcess.terminate();
3828 except:
3829 reporter.errorXcpt();
3830 oCurProcess = None;
3831
3832 #
3833 # Create another process that doesn't terminate, but which will be killed by VBoxService
3834 # because it ran out of execution time (3 seconds).
3835 #
3836 try:
3837 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3838 "", # Working directory.
3839 [], [], 3 * 1000);
3840 except:
3841 fRc = reporter.errorXcpt();
3842 else:
3843 reporter.log('Waiting for process 2 being started ...');
3844 try:
3845 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3846 except:
3847 fRc = reporter.errorXcpt();
3848 else:
3849 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3850 fRc = reporter.error('Waiting for process 2 to start failed, got status %d' % (eWaitResult,));
3851 else:
3852 reporter.log('Waiting for process 2 to get killed for running out of execution time ...');
3853 try:
3854 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 15 * 1000);
3855 except:
3856 fRc = reporter.errorXcpt();
3857 else:
3858 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3859 fRc = reporter.error('Waiting for process 2 did not time out when it should, got wait result %d'
3860 % (eWaitResult,));
3861 else:
3862 reporter.log('Waiting for process 2 did not time out, good: %s' % (eWaitResult,));
3863 try:
3864 eStatus = oCurProcess.status;
3865 except:
3866 fRc = reporter.errorXcpt();
3867 else:
3868 if eStatus != vboxcon.ProcessStatus_TimedOutKilled:
3869 fRc = reporter.error('Status of process 2 wrong; excepted %d, got %d'
3870 % (vboxcon.ProcessStatus_TimedOutKilled, eStatus));
3871 else:
3872 reporter.log('Status of process 2 is TimedOutKilled (%d) is it should be.'
3873 % (vboxcon.ProcessStatus_TimedOutKilled,));
3874 try:
3875 oCurProcess.terminate();
3876 except:
3877 reporter.logXcpt();
3878 oCurProcess = None;
3879
3880 #
3881 # Clean up the session.
3882 #
3883 try:
3884 oGuestSession.close();
3885 except:
3886 fRc = reporter.errorXcpt();
3887
3888 return (fRc, oTxsSession);
3889
3890 def testGuestCtrlDirCreate(self, oSession, oTxsSession, oTestVm):
3891 """
3892 Tests creation of guest directories.
3893 """
3894
3895 sScratch = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'testGuestCtrlDirCreate');
3896
3897 atTests = [
3898 # Invalid stuff.
3899 [ tdTestDirCreate(sDirectory = '' ), tdTestResultFailure() ],
3900 # More unusual stuff.
3901 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '.') ), tdTestResultFailure() ],
3902 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '..') ), tdTestResultFailure() ],
3903 [ tdTestDirCreate(sDirectory = '..' ), tdTestResultFailure() ],
3904 [ tdTestDirCreate(sDirectory = '../' ), tdTestResultFailure() ],
3905 [ tdTestDirCreate(sDirectory = '../../' ), tdTestResultFailure() ],
3906 [ tdTestDirCreate(sDirectory = '/' ), tdTestResultFailure() ],
3907 [ tdTestDirCreate(sDirectory = '/..' ), tdTestResultFailure() ],
3908 [ tdTestDirCreate(sDirectory = '/../' ), tdTestResultFailure() ],
3909 ];
3910 if oTestVm.isWindows() or oTestVm.isOS2():
3911 atTests.extend([
3912 [ tdTestDirCreate(sDirectory = 'C:\\' ), tdTestResultFailure() ],
3913 [ tdTestDirCreate(sDirectory = 'C:\\..' ), tdTestResultFailure() ],
3914 [ tdTestDirCreate(sDirectory = 'C:\\..\\' ), tdTestResultFailure() ],
3915 [ tdTestDirCreate(sDirectory = 'C:/' ), tdTestResultFailure() ],
3916 [ tdTestDirCreate(sDirectory = 'C:/.' ), tdTestResultFailure() ],
3917 [ tdTestDirCreate(sDirectory = 'C:/./' ), tdTestResultFailure() ],
3918 [ tdTestDirCreate(sDirectory = 'C:/..' ), tdTestResultFailure() ],
3919 [ tdTestDirCreate(sDirectory = 'C:/../' ), tdTestResultFailure() ],
3920 [ tdTestDirCreate(sDirectory = '\\\\uncrulez\\foo' ), tdTestResultFailure() ],
3921 ]);
3922 atTests.extend([
3923 # Existing directories and files.
3924 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemDir(oTestVm) ), tdTestResultFailure() ],
3925 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemShell(oTestVm) ), tdTestResultFailure() ],
3926 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemFileForReading(oTestVm) ), tdTestResultFailure() ],
3927 # Creating directories.
3928 [ tdTestDirCreate(sDirectory = sScratch ), tdTestResultSuccess() ],
3929 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3930 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3931 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3932 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3933 # Try format strings as directories.
3934 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo%sbar%sbaz%d' )), tdTestResultSuccess() ],
3935 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, '%f%%boo%%bar%RI32' )), tdTestResultSuccess() ],
3936 # Long random names.
3937 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(36, 28))),
3938 tdTestResultSuccess() ],
3939 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(140, 116))),
3940 tdTestResultSuccess() ],
3941 # Too long names. ASSUMES a guests has a 255 filename length limitation.
3942 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3943 tdTestResultFailure() ],
3944 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3945 tdTestResultFailure() ],
3946 # Missing directory in path.
3947 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo1', 'bar') ), tdTestResultFailure() ],
3948 ]);
3949
3950 fRc = True;
3951 for (i, tTest) in enumerate(atTests):
3952 oCurTest = tTest[0] # type: tdTestDirCreate
3953 oCurRes = tTest[1] # type: tdTestResult
3954 reporter.log('Testing #%d, sDirectory="%s" ...' % (i, limitString(oCurTest.sDirectory),));
3955
3956 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3957 if not fRc:
3958 break;
3959 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreate: Test #%d' % (i,));
3960 if fRc is False:
3961 return reporter.error('Test #%d failed: Could not create session' % (i,));
3962
3963 fRc = self.gctrlCreateDir(oCurTest, oCurRes, oCurGuestSession);
3964
3965 fRc = oCurTest.closeSession() and fRc;
3966 if fRc is False:
3967 fRc = reporter.error('Test #%d failed' % (i,));
3968
3969 return (fRc, oTxsSession);
3970
3971 def testGuestCtrlDirCreateTemp(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3972 """
3973 Tests creation of temporary directories.
3974 """
3975
3976 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3977 atTests = [
3978 # Invalid stuff (template must have one or more trailin 'X'es (upper case only), or a cluster of three or more).
3979 [ tdTestDirCreateTemp(sDirectory = ''), tdTestResultFailure() ],
3980 [ tdTestDirCreateTemp(sDirectory = sSystemDir, fMode = 1234), tdTestResultFailure() ],
3981 [ tdTestDirCreateTemp(sTemplate = 'xXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3982 [ tdTestDirCreateTemp(sTemplate = 'xxx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3983 [ tdTestDirCreateTemp(sTemplate = 'XXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3984 [ tdTestDirCreateTemp(sTemplate = 'bar', sDirectory = 'whatever', fMode = 0o700), tdTestResultFailure() ],
3985 [ tdTestDirCreateTemp(sTemplate = 'foo', sDirectory = 'it is not used', fMode = 0o700), tdTestResultFailure() ],
3986 [ tdTestDirCreateTemp(sTemplate = 'X,so', sDirectory = 'pointless test', fMode = 0o700), tdTestResultFailure() ],
3987 # Non-existing stuff.
3988 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX',
3989 sDirectory = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'non', 'existing')),
3990 tdTestResultFailure() ],
3991 # Working stuff:
3992 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3993 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3994 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3995 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3996 tdTestResultFailure() ],
3997 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3998 tdTestResultFailure() ],
3999 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
4000 tdTestResultFailure() ],
4001 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
4002 tdTestResultFailure() ],
4003 ];
4004
4005 if self.oTstDrv.fpApiVer >= 7.0:
4006 # Weird mode set.
4007 atTests.extend([
4008 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o42333),
4009 tdTestResultFailure() ]
4010 ]);
4011 # Same as working stuff above, but with a different mode set.
4012 atTests.extend([
4013 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4014 tdTestResultFailure() ],
4015 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4016 tdTestResultFailure() ],
4017 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4018 tdTestResultFailure() ],
4019 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4020 tdTestResultFailure() ],
4021 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4022 tdTestResultFailure() ],
4023 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4024 tdTestResultFailure() ],
4025 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
4026 tdTestResultFailure() ]
4027 ]);
4028 # Same as working stuff above, but with secure mode set.
4029 atTests.extend([
4030 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4031 tdTestResultFailure() ],
4032 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4033 tdTestResultFailure() ],
4034 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4035 tdTestResultFailure() ],
4036 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4037 tdTestResultFailure() ],
4038 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4039 fSecure = True),
4040 tdTestResultFailure() ],
4041 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4042 fSecure = True),
4043 tdTestResultFailure() ],
4044 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4045 fSecure = True),
4046 tdTestResultFailure() ]
4047 ]);
4048
4049 fRc = True;
4050 for (i, tTest) in enumerate(atTests):
4051 oCurTest = tTest[0] # type: tdTestDirCreateTemp
4052 oCurRes = tTest[1] # type: tdTestResult
4053 reporter.log('Testing #%d, sTemplate="%s", fMode=%#o, path="%s", secure="%s" ...' %
4054 (i, oCurTest.sTemplate, oCurTest.fMode, oCurTest.sDirectory, oCurTest.fSecure));
4055
4056 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4057 if not fRc:
4058 break;
4059 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreateTemp: Test #%d' % (i,));
4060 if fRc is False:
4061 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4062 break;
4063
4064 sDirTemp = '';
4065 try:
4066 sDirTemp = oCurGuestSession.directoryCreateTemp(oCurTest.sTemplate, oCurTest.fMode,
4067 oCurTest.sDirectory, oCurTest.fSecure);
4068 except:
4069 if oCurRes.fRc is True:
4070 fRc = reporter.errorXcpt('Creating temp directory "%s" failed:' % (oCurTest.sDirectory,));
4071 else:
4072 reporter.logXcpt('Creating temp directory "%s" failed expectedly, skipping:' % (oCurTest.sDirectory,));
4073 else:
4074 reporter.log2('Temporary directory is: "%s"' % (limitString(sDirTemp),));
4075 if not sDirTemp:
4076 fRc = reporter.error('Resulting directory is empty!');
4077 else:
4078 try:
4079 oFsObjInfo = oCurGuestSession.fsObjQueryInfo(sDirTemp, False);
4080 eType = oFsObjInfo.type;
4081 except:
4082 fRc = reporter.errorXcpt('sDirTemp="%s"' % (sDirTemp,));
4083 else:
4084 reporter.log2('%s: eType=%s (dir=%d)' % (limitString(sDirTemp), eType, vboxcon.FsObjType_Directory,));
4085 if eType != vboxcon.FsObjType_Directory:
4086 fRc = reporter.error('Temporary directory "%s" not created as a directory: eType=%d'
4087 % (sDirTemp, eType));
4088 fRc = oCurTest.closeSession() and fRc;
4089 return (fRc, oTxsSession);
4090
4091 def testGuestCtrlDirRead(self, oSession, oTxsSession, oTestVm):
4092 """
4093 Tests opening and reading (enumerating) guest directories.
4094 """
4095
4096 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
4097 atTests = [
4098 # Invalid stuff.
4099 [ tdTestDirRead(sDirectory = ''), tdTestResultDirRead() ],
4100 [ tdTestDirRead(sDirectory = sSystemDir, afFlags = [ 1234 ]), tdTestResultDirRead() ],
4101 [ tdTestDirRead(sDirectory = sSystemDir, sFilter = '*.foo'), tdTestResultDirRead() ],
4102 # Non-existing stuff.
4103 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'really-no-such-subdir')), tdTestResultDirRead() ],
4104 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'non', 'existing')), tdTestResultDirRead() ],
4105 ];
4106
4107 if oTestVm.isWindows() or oTestVm.isOS2():
4108 atTests.extend([
4109 # More unusual stuff.
4110 [ tdTestDirRead(sDirectory = 'z:\\'), tdTestResultDirRead() ],
4111 [ tdTestDirRead(sDirectory = '\\\\uncrulez\\foo'), tdTestResultDirRead() ],
4112 ]);
4113
4114 # Read the system directory (ASSUMES at least 5 files in it):
4115 # Windows 7+ has inaccessible system32/com/dmp directory that screws up this test, so skip it on windows:
4116 if not oTestVm.isWindows():
4117 atTests.append([ tdTestDirRead(sDirectory = sSystemDir),
4118 tdTestResultDirRead(fRc = True, cFiles = -5, cDirs = None) ]);
4119 ## @todo trailing slash
4120
4121 # Read from the test file set.
4122 atTests.extend([
4123 [ tdTestDirRead(sDirectory = self.oTestFiles.oEmptyDir.sPath),
4124 tdTestResultDirRead(fRc = True, cFiles = 0, cDirs = 0, cOthers = 0) ],
4125 [ tdTestDirRead(sDirectory = self.oTestFiles.oManyDir.sPath),
4126 tdTestResultDirRead(fRc = True, cFiles = len(self.oTestFiles.oManyDir.aoChildren), cDirs = 0, cOthers = 0) ],
4127 [ tdTestDirRead(sDirectory = self.oTestFiles.oTreeDir.sPath),
4128 tdTestResultDirRead(fRc = True, cFiles = self.oTestFiles.cTreeFiles, cDirs = self.oTestFiles.cTreeDirs,
4129 cOthers = self.oTestFiles.cTreeOthers) ],
4130 ]);
4131
4132
4133 fRc = True;
4134 for (i, tTest) in enumerate(atTests):
4135 oCurTest = tTest[0] # type: tdTestExec
4136 oCurRes = tTest[1] # type: tdTestResultDirRead
4137
4138 reporter.log('Testing #%d, dir="%s" ...' % (i, oCurTest.sDirectory));
4139 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4140 if not fRc:
4141 break;
4142 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: Test #%d' % (i,));
4143 if fRc is not True:
4144 break;
4145 fUseDirList = False;
4146 cEntriesPerRead = random.randrange(1, 32768);
4147 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4148 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4149 # Listing directories only is available for >= VBox 7.1.
4150 fUseDirList = random.choice( [True, False] );
4151 (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc,
4152 fUseDirList, cEntriesPerRead);
4153 fRc = oCurTest.closeSession() and fRc;
4154
4155 reporter.log2('Test #%d: Returned %d directories, %d files total' % (i, cDirs, cFiles));
4156 if fRc2 is oCurRes.fRc:
4157 if fRc2 is True:
4158 if oCurRes.cFiles is None:
4159 pass; # ignore
4160 elif oCurRes.cFiles >= 0 and cFiles != oCurRes.cFiles:
4161 fRc = reporter.error('Test #%d failed: Got %d files, expected %d' % (i, cFiles, oCurRes.cFiles));
4162 elif oCurRes.cFiles < 0 and cFiles < -oCurRes.cFiles:
4163 fRc = reporter.error('Test #%d failed: Got %d files, expected at least %d'
4164 % (i, cFiles, -oCurRes.cFiles));
4165 if oCurRes.cDirs is None:
4166 pass; # ignore
4167 elif oCurRes.cDirs >= 0 and cDirs != oCurRes.cDirs:
4168 fRc = reporter.error('Test #%d failed: Got %d directories, expected %d' % (i, cDirs, oCurRes.cDirs));
4169 elif oCurRes.cDirs < 0 and cDirs < -oCurRes.cDirs:
4170 fRc = reporter.error('Test #%d failed: Got %d directories, expected at least %d'
4171 % (i, cDirs, -oCurRes.cDirs));
4172 if oCurRes.cOthers is None:
4173 pass; # ignore
4174 elif oCurRes.cOthers >= 0 and cOthers != oCurRes.cOthers:
4175 fRc = reporter.error('Test #%d failed: Got %d other types, expected %d' % (i, cOthers, oCurRes.cOthers));
4176 elif oCurRes.cOthers < 0 and cOthers < -oCurRes.cOthers:
4177 fRc = reporter.error('Test #%d failed: Got %d other types, expected at least %d'
4178 % (i, cOthers, -oCurRes.cOthers));
4179
4180 else:
4181 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4182
4183
4184 #
4185 # Go over a few directories in the test file set and compare names,
4186 # types and sizes rather than just the counts like we did above.
4187 #
4188 if fRc is True:
4189 oCurTest = tdTestDirRead();
4190 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4191 if fRc:
4192 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: gctrlReadDirTree2');
4193 if fRc is True:
4194 for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
4195 reporter.log('Checking "%s" ...' % (oDir.sPath,));
4196 fUseDirList = False;
4197 cEntriesPerRead = random.randrange(1, 32768);
4198 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4199 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4200 # Listing directories only is available for >= VBox 7.1.
4201 fUseDirList = random.choice( [True, False] );
4202 fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir, fUseDirList, cEntriesPerRead) and fRc;
4203 fRc = oCurTest.closeSession() and fRc;
4204
4205 return (fRc, oTxsSession);
4206
4207
4208 def testGuestCtrlFileRemove(self, oSession, oTxsSession, oTestVm):
4209 """
4210 Tests removing guest files.
4211 """
4212
4213 #
4214 # Create a directory with a few files in it using TXS that we'll use for the initial tests.
4215 #
4216 asTestDirs = [
4217 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1'), # [0]
4218 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1'), # [1]
4219 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1', 'subsubdir-1'), # [2]
4220 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2'), # [3]
4221 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2'), # [4]
4222 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2', 'subsbudir-2'), # [5]
4223 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-3'), # [6]
4224 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-4'), # [7]
4225 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5'), # [8]
4226 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5', 'subdir-5'), # [9]
4227 ]
4228 asTestFiles = [
4229 oTestVm.pathJoin(asTestDirs[0], 'file-0'), # [0]
4230 oTestVm.pathJoin(asTestDirs[0], 'file-1'), # [1]
4231 oTestVm.pathJoin(asTestDirs[0], 'file-2'), # [2]
4232 oTestVm.pathJoin(asTestDirs[1], 'file-3'), # [3] - subdir-1
4233 oTestVm.pathJoin(asTestDirs[1], 'file-4'), # [4] - subdir-1
4234 oTestVm.pathJoin(asTestDirs[2], 'file-5'), # [5] - subsubdir-1
4235 oTestVm.pathJoin(asTestDirs[3], 'file-6'), # [6] - rmtestdir-2
4236 oTestVm.pathJoin(asTestDirs[4], 'file-7'), # [7] - subdir-2
4237 oTestVm.pathJoin(asTestDirs[5], 'file-8'), # [8] - subsubdir-2
4238 ];
4239 for sDir in asTestDirs:
4240 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
4241 return reporter.error('Failed to create test dir "%s"!' % (sDir,));
4242 for sFile in asTestFiles:
4243 if oTxsSession.syncUploadString(sFile, sFile, 0o666) is not True:
4244 return reporter.error('Failed to create test file "%s"!' % (sFile,));
4245
4246 #
4247 # Tear down the directories and files.
4248 #
4249 aoTests = [
4250 # Negative tests first:
4251 tdTestRemoveFile(asTestDirs[0], fRcExpect = False),
4252 tdTestRemoveDir(asTestDirs[0], fRcExpect = False),
4253 tdTestRemoveDir(asTestFiles[0], fRcExpect = False),
4254 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-file'), fRcExpect = False),
4255 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir'), fRcExpect = False),
4256 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-file'), fRcExpect = False),
4257 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-subdir'), fRcExpect = False),
4258 tdTestRemoveTree(asTestDirs[0], afFlags = [], fRcExpect = False), # Only removes empty dirs, this isn't empty.
4259 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fRcExpect = False), # ditto
4260 # Empty paths:
4261 tdTestRemoveFile('', fRcExpect = False),
4262 tdTestRemoveDir('', fRcExpect = False),
4263 tdTestRemoveTree('', fRcExpect = False),
4264 # Now actually remove stuff:
4265 tdTestRemoveDir(asTestDirs[7], fRcExpect = True),
4266 tdTestRemoveFile(asTestDirs[6], fRcExpect = False),
4267 tdTestRemoveDir(asTestDirs[6], fRcExpect = True),
4268 tdTestRemoveFile(asTestFiles[0], fRcExpect = True),
4269 tdTestRemoveFile(asTestFiles[0], fRcExpect = False),
4270 # 17:
4271 tdTestRemoveTree(asTestDirs[8], fRcExpect = True), # Removes empty subdirs and leaves the dir itself.
4272 tdTestRemoveDir(asTestDirs[8], fRcExpect = True),
4273 tdTestRemoveTree(asTestDirs[3], fRcExpect = False), # Have subdirs & files,
4274 tdTestRemoveTree(asTestDirs[3], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,], fRcExpect = True),
4275 tdTestRemoveDir(asTestDirs[3], fRcExpect = True),
4276 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4277 # No error if already delete (RTDirRemoveRecursive artifact).
4278 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4279 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,],
4280 fNotExist = True, fRcExpect = True),
4281 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fNotExist = True, fRcExpect = True),
4282 ];
4283
4284 #
4285 # Execution loop
4286 #
4287 fRc = True;
4288 for (i, oTest) in enumerate(aoTests): # int, tdTestRemoveBase
4289 reporter.log('Testing #%d, path="%s" %s ...' % (i, oTest.sPath, oTest.__class__.__name__));
4290 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4291 if not fRc:
4292 break;
4293 fRc, _ = oTest.createSession('testGuestCtrlFileRemove: Test #%d' % (i,));
4294 if fRc is False:
4295 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4296 break;
4297 fRc = oTest.execute(self) and fRc;
4298 fRc = oTest.closeSession() and fRc;
4299
4300 if fRc is True:
4301 oCurTest = tdTestDirRead();
4302 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4303 if fRc:
4304 fRc, oCurGuestSession = oCurTest.createSession('remove final');
4305 if fRc is True:
4306
4307 #
4308 # Delete all the files in the many subdir of the test set.
4309 #
4310 reporter.log('Deleting the file in "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
4311 for oFile in self.oTestFiles.oManyDir.aoChildren:
4312 reporter.log2('"%s"' % (limitString(oFile.sPath),));
4313 try:
4314 if self.oTstDrv.fpApiVer >= 5.0:
4315 oCurGuestSession.fsObjRemove(oFile.sPath);
4316 else:
4317 oCurGuestSession.fileRemove(oFile.sPath);
4318 except:
4319 fRc = reporter.errorXcpt('Removing "%s" failed' % (oFile.sPath,));
4320
4321 # Remove the directory itself to verify that we've removed all the files in it:
4322 reporter.log('Removing the directory "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
4323 try:
4324 oCurGuestSession.directoryRemove(self.oTestFiles.oManyDir.sPath);
4325 except:
4326 fRc = reporter.errorXcpt('Removing directory "%s" failed' % (self.oTestFiles.oManyDir.sPath,));
4327
4328 #
4329 # Recursively delete the entire test file tree from the root up.
4330 #
4331 # Note! On unix we cannot delete the root dir itself since it is residing
4332 # in /var/tmp where only the owner may delete it. Root is the owner.
4333 #
4334 if oTestVm.isWindows() or oTestVm.isOS2():
4335 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,];
4336 else:
4337 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,];
4338 try:
4339 oProgress = oCurGuestSession.directoryRemoveRecursive(self.oTestFiles.oRoot.sPath, afFlags);
4340 except:
4341 fRc = reporter.errorXcpt('Removing tree "%s" failed' % (self.oTestFiles.oRoot.sPath,));
4342 else:
4343 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv,
4344 "remove-tree-root: %s" % (self.oTestFiles.oRoot.sPath,));
4345 reporter.log2('waiting ...')
4346 oWrappedProgress.wait();
4347 reporter.log2('isSuccess=%s' % (oWrappedProgress.isSuccess(),));
4348 if not oWrappedProgress.isSuccess():
4349 fRc = oWrappedProgress.logResult();
4350
4351 fRc = oCurTest.closeSession() and fRc;
4352
4353 return (fRc, oTxsSession);
4354
4355
4356 def testGuestCtrlFileStat(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4357 """
4358 Tests querying file information through stat.
4359 """
4360
4361 # Basic stuff, existing stuff.
4362 aoTests = [
4363 tdTestSessionEx([
4364 tdStepStatDir('.'),
4365 tdStepStatDir('..'),
4366 tdStepStatDir(self.oTstDrv.getGuestTempDir(oTestVm)),
4367 tdStepStatDir(self.oTstDrv.getGuestSystemDir(oTestVm)),
4368 tdStepStatDirEx(self.oTestFiles.oRoot),
4369 tdStepStatDirEx(self.oTestFiles.oEmptyDir),
4370 tdStepStatDirEx(self.oTestFiles.oTreeDir),
4371 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4372 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4373 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4374 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4375 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4376 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4377 tdStepStatFile(self.oTstDrv.getGuestSystemFileForReading(oTestVm)),
4378 tdStepStatFile(self.oTstDrv.getGuestSystemShell(oTestVm)),
4379 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4380 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4381 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4382 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4383 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4384 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4385 ]),
4386 ];
4387
4388 # None existing stuff.
4389 sSysDir = self.oTstDrv.getGuestSystemDir(oTestVm);
4390 sSep = oTestVm.pathSep();
4391 aoTests += [
4392 tdTestSessionEx([
4393 tdStepStatFileNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory')),
4394 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory') + sSep),
4395 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', '.')),
4396 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory')),
4397 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory') + sSep),
4398 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory', '.')),
4399 #tdStepStatPathNotFound('N:\\'), # ASSUMES nothing mounted on N:!
4400 #tdStepStatPathNotFound('\\\\NoSuchUncServerName\\NoSuchShare'),
4401 ]),
4402 ];
4403 # Invalid parameter check.
4404 aoTests += [ tdTestSessionEx([ tdStepStat('', vbox.ComError.E_INVALIDARG), ]), ];
4405
4406 #
4407 # Execute the tests.
4408 #
4409 fRc, oTxsSession = tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession,
4410 oTestVm, 'FsStat');
4411 #
4412 # Test the full test file set.
4413 #
4414 if self.oTstDrv.fpApiVer < 5.0:
4415 return (fRc, oTxsSession);
4416
4417 oTest = tdTestGuestCtrlBase();
4418 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4419 if not fRc:
4420 return (False, oTxsSession);
4421 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4422 if fRc2 is not True:
4423 return (False, oTxsSession);
4424
4425 for oFsObj in self.oTestFiles.dPaths.values():
4426 reporter.log2('testGuestCtrlFileStat: %s sPath=%s'
4427 % ('file' if isinstance(oFsObj, testfileset.TestFile) else 'dir ', limitString(oFsObj.sPath),));
4428
4429 # Query the information:
4430 try:
4431 oFsInfo = oGuestSession.fsObjQueryInfo(oFsObj.sPath, False);
4432 except:
4433 fRc = reporter.errorXcpt('sPath=%s type=%s: fsObjQueryInfo trouble!' % (oFsObj.sPath, type(oFsObj),));
4434 continue;
4435 if oFsInfo is None:
4436 fRc = reporter.error('sPath=%s type=%s: No info object returned!' % (oFsObj.sPath, type(oFsObj),));
4437 continue;
4438
4439 # Check attributes:
4440 try:
4441 eType = oFsInfo.type;
4442 cbObject = oFsInfo.objectSize;
4443 except:
4444 fRc = reporter.errorXcpt('sPath=%s type=%s: attribute access trouble!' % (oFsObj.sPath, type(oFsObj),));
4445 continue;
4446
4447 if isinstance(oFsObj, testfileset.TestFile):
4448 if eType != vboxcon.FsObjType_File:
4449 fRc = reporter.error('sPath=%s type=file: eType=%s, expected %s!'
4450 % (oFsObj.sPath, eType, vboxcon.FsObjType_File));
4451 if cbObject != oFsObj.cbContent:
4452 fRc = reporter.error('sPath=%s type=file: cbObject=%s, expected %s!'
4453 % (oFsObj.sPath, cbObject, oFsObj.cbContent));
4454 fFileExists = True;
4455 fDirExists = False;
4456 elif isinstance(oFsObj, testfileset.TestDir):
4457 if eType != vboxcon.FsObjType_Directory:
4458 fRc = reporter.error('sPath=%s type=dir: eType=%s, expected %s!'
4459 % (oFsObj.sPath, eType, vboxcon.FsObjType_Directory));
4460 fFileExists = False;
4461 fDirExists = True;
4462 else:
4463 fRc = reporter.error('sPath=%s type=%s: Unexpected oFsObj type!' % (oFsObj.sPath, type(oFsObj),));
4464 continue;
4465
4466 # Check the directoryExists and fileExists results too.
4467 try:
4468 fExistsResult = oGuestSession.fileExists(oFsObj.sPath, False);
4469 except:
4470 fRc = reporter.errorXcpt('sPath=%s type=%s: fileExists trouble!' % (oFsObj.sPath, type(oFsObj),));
4471 else:
4472 if fExistsResult != fFileExists:
4473 fRc = reporter.error('sPath=%s type=%s: fileExists returned %s, expected %s!'
4474 % (oFsObj.sPath, type(oFsObj), fExistsResult, fFileExists));
4475 try:
4476 fExistsResult = oGuestSession.directoryExists(oFsObj.sPath, False);
4477 except:
4478 fRc = reporter.errorXcpt('sPath=%s type=%s: directoryExists trouble!' % (oFsObj.sPath, type(oFsObj),));
4479 else:
4480 if fExistsResult != fDirExists:
4481 fRc = reporter.error('sPath=%s type=%s: directoryExists returned %s, expected %s!'
4482 % (oFsObj.sPath, type(oFsObj), fExistsResult, fDirExists));
4483
4484 fRc = oTest.closeSession() and fRc;
4485 return (fRc, oTxsSession);
4486
4487 def testGuestCtrlFileOpen(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4488 """
4489 Tests opening guest files.
4490 """
4491 if self.oTstDrv.fpApiVer < 5.0:
4492 reporter.log('Skipping because of pre 5.0 API');
4493 return None;
4494
4495 #
4496 # Paths.
4497 #
4498 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
4499 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
4500 asFiles = [
4501 oTestVm.pathJoin(sTempDir, 'file-open-0'),
4502 oTestVm.pathJoin(sTempDir, 'file-open-1'),
4503 oTestVm.pathJoin(sTempDir, 'file-open-2'),
4504 oTestVm.pathJoin(sTempDir, 'file-open-3'),
4505 oTestVm.pathJoin(sTempDir, 'file-open-4'),
4506 ];
4507 asNonEmptyFiles = [
4508 oTestVm.pathJoin(sTempDir, 'file-open-10'),
4509 oTestVm.pathJoin(sTempDir, 'file-open-11'),
4510 oTestVm.pathJoin(sTempDir, 'file-open-12'),
4511 oTestVm.pathJoin(sTempDir, 'file-open-13'),
4512 ];
4513 sContent = 'abcdefghijklmnopqrstuvwxyz0123456789';
4514 for sFile in asNonEmptyFiles:
4515 if oTxsSession.syncUploadString(sContent, sFile, 0o666) is not True:
4516 return reporter.error('Failed to create "%s" via TXS' % (sFile,));
4517
4518 #
4519 # The tests.
4520 #
4521 atTests = [
4522 # Invalid stuff.
4523 [ tdTestFileOpen(sFile = ''), tdTestResultFailure() ],
4524 # Wrong open mode.
4525 [ tdTestFileOpen(sFile = sFileForReading, eAccessMode = -1), tdTestResultFailure() ],
4526 # Wrong disposition.
4527 [ tdTestFileOpen(sFile = sFileForReading, eAction = -1), tdTestResultFailure() ],
4528 # Non-existing file or path.
4529 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir')), tdTestResultFailure() ],
4530 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4531 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4532 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4533 eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4534 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4535 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4536 eAccessMode = vboxcon.FileAccessMode_ReadWrite,
4537 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4538 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-dir', 'no-such-file')), tdTestResultFailure() ],
4539 ];
4540 if self.oTstDrv.fpApiVer > 5.2: # Fixed since 6.0.
4541 atTests.extend([
4542 # Wrong type:
4543 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
4544 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestSystemDir(oTestVm)), tdTestResultFailure() ],
4545 ]);
4546 atTests.extend([
4547 # O_EXCL and such:
4548 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew,
4549 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
4550 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew), tdTestResultFailure() ],
4551 # Open a file.
4552 [ tdTestFileOpen(sFile = sFileForReading), tdTestResultSuccess() ],
4553 [ tdTestFileOpen(sFile = sFileForReading,
4554 eAction = vboxcon.FileOpenAction_OpenOrCreate), tdTestResultSuccess() ],
4555 # Create a new file.
4556 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
4557 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4558 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
4559 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
4560 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExisting,
4561 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4562 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4563 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4564 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenOrCreate,
4565 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4566 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExistingTruncated,
4567 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4568 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4569 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4570 # Open or create a new file.
4571 [ tdTestFileOpenCheckSize(sFile = asFiles[1], eAction = vboxcon.FileOpenAction_OpenOrCreate,
4572 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4573 # Create or replace a new file.
4574 [ tdTestFileOpenCheckSize(sFile = asFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4575 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4576 # Create and append to file (weird stuff).
4577 [ tdTestFileOpenCheckSize(sFile = asFiles[3], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4578 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4579 [ tdTestFileOpenCheckSize(sFile = asFiles[4], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4580 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4581 # Open the non-empty files in non-destructive modes.
4582 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent)), tdTestResultSuccess() ],
4583 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4584 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4585 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4586 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4587
4588 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
4589 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4590 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4591 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4592 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4593 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4594 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4595 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4596 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4597
4598 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
4599 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4600 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4601 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4602 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4603 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4604 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4605 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4606 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4607
4608 # Now the destructive stuff:
4609 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4610 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultSuccess() ],
4611 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4612 eAction = vboxcon.FileOpenAction_CreateOrReplace), tdTestResultSuccess() ],
4613 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4614 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4615 ]);
4616
4617 #
4618 # Do the testing.
4619 #
4620 fRc = True;
4621 for (i, tTest) in enumerate(atTests):
4622 oCurTest = tTest[0] # type: tdTestFileOpen
4623 oCurRes = tTest[1] # type: tdTestResult
4624
4625 reporter.log('Testing #%d: %s - sFile="%s", eAccessMode=%d, eAction=%d, (%s, %s, %s) ...'
4626 % (i, oCurTest.__class__.__name__, oCurTest.sFile, oCurTest.eAccessMode, oCurTest.eAction,
4627 oCurTest.eSharing, oCurTest.fCreationMode, oCurTest.afOpenFlags,));
4628
4629 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4630 if not fRc:
4631 break;
4632 fRc, _ = oCurTest.createSession('testGuestCtrlFileOpen: Test #%d' % (i,));
4633 if fRc is not True:
4634 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4635 break;
4636
4637 fRc2 = oCurTest.doSteps(oCurRes.fRc, self);
4638 if fRc2 != oCurRes.fRc:
4639 fRc = reporter.error('Test #%d result mismatch: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
4640
4641 fRc = oCurTest.closeSession() and fRc;
4642
4643 return (fRc, oTxsSession);
4644
4645
4646 def testGuestCtrlFileRead(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-branches,too-many-statements
4647 """
4648 Tests reading from guest files.
4649 """
4650 if self.oTstDrv.fpApiVer < 5.0:
4651 reporter.log('Skipping because of pre 5.0 API');
4652 return None;
4653
4654 #
4655 # Do everything in one session.
4656 #
4657 oTest = tdTestGuestCtrlBase();
4658 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4659 if not fRc:
4660 return (False, oTxsSession);
4661 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4662 if fRc2 is not True:
4663 return (False, oTxsSession);
4664
4665 #
4666 # Create a really big zero filled, up to 1 GiB, adding it to the list of
4667 # files from the set.
4668 #
4669 # Note! This code sucks a bit because we don't have a working setSize nor
4670 # any way to figure out how much free space there is in the guest.
4671 #
4672 aoExtraFiles = [];
4673 sBigName = self.oTestFiles.generateFilenameEx();
4674 sBigPath = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sBigName);
4675 fRc = True;
4676 try:
4677 oFile = oGuestSession.fileOpenEx(sBigPath, vboxcon.FileAccessMode_ReadWrite, vboxcon.FileOpenAction_CreateOrReplace,
4678 vboxcon.FileSharingMode_All, 0, []);
4679 except:
4680 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4681 else:
4682 # Does setSize work now?
4683 fUseFallback = True;
4684 try:
4685 oFile.setSize(0);
4686 oFile.setSize(64);
4687 fUseFallback = False;
4688 except:
4689 reporter.logXcpt();
4690
4691 # Grow the file till we hit trouble, typical VERR_DISK_FULL, then
4692 # reduce the file size if we have a working setSize.
4693 cbBigFile = 0;
4694 while cbBigFile < (1024 + 32)*1024*1024:
4695 if not fUseFallback:
4696 cbBigFile += 16*1024*1024;
4697 try:
4698 oFile.setSize(cbBigFile);
4699 except Exception:
4700 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4701 try:
4702 cbBigFile -= 16*1024*1024;
4703 oFile.setSize(cbBigFile);
4704 except:
4705 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4706 break;
4707 else:
4708 cbBigFile += 32*1024*1024;
4709 try:
4710 oFile.seek(cbBigFile, vboxcon.FileSeekOrigin_Begin);
4711 oFile.write(bytearray(1), 60*1000);
4712 except:
4713 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4714 break;
4715 try:
4716 cbBigFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4717 except:
4718 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4719 try:
4720 oFile.close();
4721 except:
4722 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4723 if fRc is True:
4724 reporter.log('Big file: %s bytes: %s' % (cbBigFile, sBigPath,));
4725 aoExtraFiles.append(testfileset.TestFileZeroFilled(None, sBigPath, cbBigFile));
4726 else:
4727 try:
4728 oGuestSession.fsObjRemove(sBigPath);
4729 except:
4730 reporter.errorXcpt('fsObjRemove(sBigName=%s)' % (sBigPath,));
4731
4732 #
4733 # Open and read all the files in the test file set.
4734 #
4735 for oTestFile in aoExtraFiles + self.oTestFiles.aoFiles: # type: testfileset.TestFile
4736 reporter.log2('Test file: %s bytes, "%s" ...' % (oTestFile.cbContent, limitString(oTestFile.sPath),));
4737
4738 #
4739 # Open it:
4740 #
4741 try:
4742 oFile = oGuestSession.fileOpenEx(oTestFile.sPath, vboxcon.FileAccessMode_ReadOnly,
4743 vboxcon.FileOpenAction_OpenExisting, vboxcon.FileSharingMode_All, 0, []);
4744 except:
4745 fRc = reporter.errorXcpt('sPath=%s' % (oTestFile.sPath, ));
4746 continue;
4747
4748 #
4749 # Read the file in different sized chunks:
4750 #
4751 if oTestFile.cbContent < 128:
4752 acbChunks = xrange(1,128);
4753 elif oTestFile.cbContent < 1024:
4754 acbChunks = (2048, 127, 63, 32, 29, 17, 16, 15, 9);
4755 elif oTestFile.cbContent < 8*1024*1024:
4756 acbChunks = (128*1024, 32*1024, 8191, 255);
4757 else:
4758 acbChunks = (768*1024, 128*1024);
4759
4760 reporter.log2('Chunked reads');
4761
4762 for cbChunk in acbChunks:
4763 # Read the whole file straight thru:
4764 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... cbChunk=%s' % (cbChunk,));
4765 offFile = 0;
4766 cReads = 0;
4767 while offFile <= oTestFile.cbContent:
4768 try:
4769 abRead = oFile.read(cbChunk, 30*1000);
4770 except:
4771 fRc = reporter.errorXcpt('%s: offFile=%s cbChunk=%s cbContent=%s'
4772 % (oTestFile.sPath, offFile, cbChunk, oTestFile.cbContent));
4773 break;
4774 cbRead = len(abRead);
4775 if cbRead == 0 and offFile == oTestFile.cbContent:
4776 break;
4777 if cbRead <= 0:
4778 fRc = reporter.error('%s @%s: cbRead=%s, cbContent=%s'
4779 % (oTestFile.sPath, offFile, cbRead, oTestFile.cbContent));
4780 break;
4781 if not oTestFile.equalMemory(abRead, offFile):
4782 fRc = reporter.error('%s: read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead));
4783 break;
4784 offFile += cbRead;
4785 cReads += 1;
4786 if cReads > 8192:
4787 break;
4788
4789 # Seek to start of file.
4790 try:
4791 offFile = oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4792 except:
4793 fRc = reporter.errorXcpt('%s: error seeking to start of file' % (oTestFile.sPath,));
4794 break;
4795 if offFile != 0:
4796 fRc = reporter.error('%s: seek to start of file returned %u, expected 0' % (oTestFile.sPath, offFile));
4797 break;
4798
4799 #
4800 # Random reads.
4801 #
4802 reporter.log2('Random reads (seek)');
4803 for _ in xrange(8):
4804 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4805 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4806 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s' % (offFile, cbToRead,));
4807
4808 try:
4809 offActual = oFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
4810 except:
4811 fRc = reporter.errorXcpt('%s: error seeking to %s' % (oTestFile.sPath, offFile));
4812 break;
4813 if offActual != offFile:
4814 fRc = reporter.error('%s: seek(%s,Begin) -> %s, expected %s'
4815 % (oTestFile.sPath, offFile, offActual, offFile));
4816 break;
4817
4818 try:
4819 abRead = oFile.read(cbToRead, 30*1000);
4820 except:
4821 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4822 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4823 cbRead = 0;
4824 else:
4825 cbRead = len(abRead);
4826 if not oTestFile.equalMemory(abRead, offFile):
4827 fRc = reporter.error('%s: random read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4828
4829 try:
4830 offActual = oFile.offset;
4831 except:
4832 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4833 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4834 else:
4835 if offActual != offFile + cbRead:
4836 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4837 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4838 try:
4839 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4840 except:
4841 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4842 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4843 else:
4844 if offActual != offFile + cbRead:
4845 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4846 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4847
4848 #
4849 # Random reads using readAt.
4850 #
4851 reporter.log2('Random reads (readAt)');
4852 for _ in xrange(12):
4853 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4854 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4855 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s (readAt)' % (offFile, cbToRead,));
4856
4857 try:
4858 abRead = oFile.readAt(offFile, cbToRead, 30*1000);
4859 except:
4860 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4861 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4862 cbRead = 0;
4863 else:
4864 cbRead = len(abRead);
4865 if not oTestFile.equalMemory(abRead, offFile):
4866 fRc = reporter.error('%s: random readAt mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4867
4868 try:
4869 offActual = oFile.offset;
4870 except:
4871 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4872 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4873 else:
4874 if offActual != offFile + cbRead:
4875 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4876 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4877
4878 try:
4879 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4880 except:
4881 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4882 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4883 else:
4884 if offActual != offFile + cbRead:
4885 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4886 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4887
4888 #
4889 # A few negative things.
4890 #
4891
4892 # Zero byte reads -> E_INVALIDARG.
4893 reporter.log2('Zero byte reads');
4894 try:
4895 abRead = oFile.read(0, 30*1000);
4896 except Exception as oXcpt:
4897 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4898 fRc = reporter.errorXcpt('read(0,30s) did not raise E_INVALIDARG as expected!');
4899 else:
4900 fRc = reporter.error('read(0,30s) did not fail!');
4901
4902 try:
4903 abRead = oFile.readAt(0, 0, 30*1000);
4904 except Exception as oXcpt:
4905 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4906 fRc = reporter.errorXcpt('readAt(0,0,30s) did not raise E_INVALIDARG as expected!');
4907 else:
4908 fRc = reporter.error('readAt(0,0,30s) did not fail!');
4909
4910 # See what happens when we read 1GiB. We should get a max of 1MiB back.
4911 ## @todo Document this behaviour in VirtualBox.xidl.
4912 reporter.log2('1GB reads');
4913 try:
4914 oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4915 except:
4916 fRc = reporter.error('seek(0)');
4917 try:
4918 abRead = oFile.read(1024*1024*1024, 30*1000);
4919 except:
4920 fRc = reporter.errorXcpt('read(1GiB,30s)');
4921 else:
4922 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4923 fRc = reporter.error('Expected read(1GiB,30s) to return %s bytes, got %s bytes instead'
4924 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4925
4926 try:
4927 abRead = oFile.readAt(0, 1024*1024*1024, 30*1000);
4928 except:
4929 fRc = reporter.errorXcpt('readAt(0,1GiB,30s)');
4930 else:
4931 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4932 reporter.error('Expected readAt(0, 1GiB,30s) to return %s bytes, got %s bytes instead'
4933 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4934
4935 #
4936 # Check stat info on the file as well as querySize.
4937 #
4938 if self.oTstDrv.fpApiVer > 5.2:
4939 try:
4940 oFsObjInfo = oFile.queryInfo();
4941 except:
4942 fRc = reporter.errorXcpt('%s: queryInfo()' % (oTestFile.sPath,));
4943 else:
4944 if oFsObjInfo is None:
4945 fRc = reporter.error('IGuestFile::queryInfo returned None');
4946 else:
4947 try:
4948 cbFile = oFsObjInfo.objectSize;
4949 except:
4950 fRc = reporter.errorXcpt();
4951 else:
4952 if cbFile != oTestFile.cbContent:
4953 fRc = reporter.error('%s: queryInfo returned incorrect file size: %s, expected %s'
4954 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4955
4956 try:
4957 cbFile = oFile.querySize();
4958 except:
4959 fRc = reporter.errorXcpt('%s: querySize()' % (oTestFile.sPath,));
4960 else:
4961 if cbFile != oTestFile.cbContent:
4962 fRc = reporter.error('%s: querySize returned incorrect file size: %s, expected %s'
4963 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4964
4965 #
4966 # Use seek to test the file size and do a few other end-relative seeks.
4967 #
4968 try:
4969 cbFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4970 except:
4971 fRc = reporter.errorXcpt('%s: seek(0,End)' % (oTestFile.sPath,));
4972 else:
4973 if cbFile != oTestFile.cbContent:
4974 fRc = reporter.error('%s: seek(0,End) returned incorrect file size: %s, expected %s'
4975 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4976 if oTestFile.cbContent > 0:
4977 for _ in xrange(5):
4978 offSeek = self.oTestFiles.oRandom.randrange(oTestFile.cbContent + 1);
4979 try:
4980 offFile = oFile.seek(-offSeek, vboxcon.FileSeekOrigin_End);
4981 except:
4982 fRc = reporter.errorXcpt('%s: seek(%s,End)' % (oTestFile.sPath, -offSeek,));
4983 else:
4984 if offFile != oTestFile.cbContent - offSeek:
4985 fRc = reporter.error('%s: seek(%s,End) returned incorrect offset: %s, expected %s (cbContent=%s)'
4986 % (oTestFile.sPath, -offSeek, offSeek, oTestFile.cbContent - offSeek,
4987 oTestFile.cbContent,));
4988
4989 #
4990 # Close it and we're done with this file.
4991 #
4992 try:
4993 oFile.close();
4994 except:
4995 fRc = reporter.errorXcpt('%s: error closing the file' % (oTestFile.sPath,));
4996
4997 #
4998 # Clean up.
4999 #
5000 for oTestFile in aoExtraFiles:
5001 try:
5002 oGuestSession.fsObjRemove(sBigPath);
5003 except:
5004 fRc = reporter.errorXcpt('fsObjRemove(%s)' % (sBigPath,));
5005
5006 fRc = oTest.closeSession() and fRc;
5007
5008 return (fRc, oTxsSession);
5009
5010
5011 def testGuestCtrlFileWrite(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5012 """
5013 Tests writing to guest files.
5014 """
5015 if self.oTstDrv.fpApiVer < 5.0:
5016 reporter.log('Skipping because of pre 5.0 API');
5017 return None;
5018
5019 #
5020 # The test file and its content.
5021 #
5022 sFile = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'gctrl-write-1');
5023 abContent = bytearray(0);
5024
5025 #
5026 # The tests.
5027 #
5028 def randBytes(cbHowMany):
5029 """ Returns an bytearray of random bytes. """
5030 return bytearray(self.oTestFiles.oRandom.getrandbits(8) for _ in xrange(cbHowMany));
5031
5032 aoTests = [
5033 # Write at end:
5034 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_CreateNew, abContent = abContent,
5035 atChunks = [(None, randBytes(1)), (None, randBytes(77)), (None, randBytes(98)),]),
5036 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1+77+98), # 176
5037 # Appending:
5038 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
5039 atChunks = [(None, randBytes(255)), (None, randBytes(33)),]),
5040 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 176 + 255+33), # 464
5041 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
5042 atChunks = [(10, randBytes(44)),]),
5043 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 464 + 44), # 508
5044 # Write within existing:
5045 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_OpenExisting, abContent = abContent,
5046 atChunks = [(0, randBytes(1)), (50, randBytes(77)), (255, randBytes(199)),]),
5047 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 508),
5048 # Writing around and over the end:
5049 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent,
5050 atChunks = [(500, randBytes(9)), (508, randBytes(15)), (512, randBytes(12)),]),
5051 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 512+12),
5052
5053 # writeAt appending:
5054 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5055 atChunks = [(0, randBytes(23)), (6, randBytes(1018)),]),
5056 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 6+1018), # 1024
5057 # writeAt within existing:
5058 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5059 atChunks = [(1000, randBytes(23)), (1, randBytes(990)),]),
5060 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1024),
5061 # writeAt around and over the end:
5062 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5063 atChunks = [(1024, randBytes(63)), (1080, randBytes(968)),]),
5064 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1080+968), # 2048
5065
5066 # writeAt beyond the end (gap is filled with zeros):
5067 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True, atChunks = [(3070, randBytes(2)),]),
5068 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 3072),
5069 # write beyond the end (gap is filled with zeros):
5070 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, atChunks = [(4090, randBytes(6)),]),
5071 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 4096),
5072 ];
5073
5074 for (i, oCurTest) in enumerate(aoTests):
5075 reporter.log('Testing #%d: %s ...' % (i, oCurTest.toString(),));
5076 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5077 if not fRc:
5078 break;
5079 fRc, _ = oCurTest.createSession('testGuestCtrlFileWrite: Test #%d' % (i,));
5080 if fRc is not True:
5081 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5082 break;
5083
5084 fRc2 = oCurTest.doSteps(True, self);
5085 if fRc2 is not True:
5086 fRc = reporter.error('Test #%d failed!' % (i,));
5087
5088 fRc = oCurTest.closeSession() and fRc;
5089
5090 #
5091 # Cleanup
5092 #
5093 if oTxsSession.syncRmFile(sFile) is not True:
5094 fRc = reporter.error('Failed to remove write-test file: %s' % (sFile, ));
5095
5096 return (fRc, oTxsSession);
5097
5098 @staticmethod
5099 def __generateFile(sName, cbFile):
5100 """ Helper for generating a file with a given size. """
5101 with open(sName, 'wb') as oFile:
5102 while cbFile > 0:
5103 cb = cbFile if cbFile < 256*1024 else 256*1024;
5104 oFile.write(bytearray(random.getrandbits(8) for _ in xrange(cb)));
5105 cbFile -= cb;
5106 return True;
5107
5108 def testGuestCtrlCopyTo(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5109 """
5110 Tests copying files from host to the guest.
5111 """
5112
5113 #
5114 # Paths and test files.
5115 #
5116 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, 'copyto');
5117 sScratchTestFilesHst = os.path.join(sScratchHst, self.oTestFiles.sSubDir);
5118 sScratchEmptyDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oEmptyDir.sName);
5119 sScratchNonEmptyDirHst = self.oTestFiles.chooseRandomDirFromTree().buildPath(sScratchHst, os.path.sep);
5120 sScratchTreeDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oTreeDir.sName);
5121
5122 sScratchGst = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'copyto');
5123 sScratchDstDir1Gst = oTestVm.pathJoin(sScratchGst, 'dstdir1');
5124 sScratchDstDir2Gst = oTestVm.pathJoin(sScratchGst, 'dstdir2');
5125 sScratchDstDir3Gst = oTestVm.pathJoin(sScratchGst, 'dstdir3');
5126 sScratchDstDir4Gst = oTestVm.pathJoin(sScratchGst, 'dstdir4');
5127 sScratchDotDotDirGst = oTestVm.pathJoin(sScratchGst, '..');
5128 #sScratchGstNotExist = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-file-or-directory');
5129 sScratchHstNotExist = os.path.join(self.oTstDrv.sScratchPath, 'no-such-file-or-directory');
5130 sScratchGstPathNotFound = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-directory', 'or-file');
5131 #sScratchHstPathNotFound = os.path.join(self.oTstDrv.sScratchPath, 'no-such-directory', 'or-file');
5132
5133 if oTestVm.isWindows() or oTestVm.isOS2():
5134 sScratchGstInvalid = "?*|<invalid-name>";
5135 else:
5136 sScratchGstInvalid = None;
5137 if utils.getHostOs() in ('win', 'os2'):
5138 sScratchHstInvalid = "?*|<invalid-name>";
5139 else:
5140 sScratchHstInvalid = None;
5141
5142 for sDir in (sScratchGst, sScratchDstDir1Gst, sScratchDstDir2Gst, sScratchDstDir3Gst, sScratchDstDir4Gst):
5143 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
5144 return reporter.error('TXS failed to create directory "%s"!' % (sDir,));
5145
5146 # Put the test file set under sScratchHst.
5147 if os.path.exists(sScratchHst):
5148 if base.wipeDirectory(sScratchHst) != 0:
5149 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
5150 else:
5151 try:
5152 os.mkdir(sScratchHst);
5153 except:
5154 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
5155 if self.oTestFiles.writeToDisk(sScratchHst) is not True:
5156 return reporter.error('Filed to write test files to "%s" on the host!' % (sScratchHst,));
5157
5158 # If for whatever reason the directory tree does not exist on the host, let us know.
5159 # Copying an non-existing tree *will* fail the tests which otherwise should succeed!
5160 assert os.path.exists(sScratchTreeDirHst);
5161
5162 # Generate a test file in 32MB to 64 MB range.
5163 sBigFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-random.data');
5164 cbBigFileHst = random.randrange(32*1024*1024, 64*1024*1024);
5165 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
5166 cbLeft = cbBigFileHst;
5167 try:
5168 self.__generateFile(sBigFileHst, cbBigFileHst);
5169 except:
5170 return reporter.errorXcpt('sBigFileHst=%s cbBigFileHst=%s cbLeft=%s' % (sBigFileHst, cbBigFileHst, cbLeft,));
5171 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
5172
5173 # Generate an empty file on the host that we can use to save space in the guest.
5174 sEmptyFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-empty.data');
5175 try:
5176 open(sEmptyFileHst, "wb").close(); # pylint: disable=consider-using-with
5177 except:
5178 return reporter.errorXcpt('sEmptyFileHst=%s' % (sEmptyFileHst,));
5179
5180 # os.path.join() is too clever for "..", so we just build up the path here ourselves.
5181 sScratchDotDotFileHst = sScratchHst + os.path.sep + '..' + os.path.sep + 'gctrl-empty.data';
5182
5183 #
5184 # Tests.
5185 #
5186 atTests = [
5187 # Nothing given:
5188 [ tdTestCopyToFile(), tdTestResultFailure() ],
5189 [ tdTestCopyToDir(), tdTestResultFailure() ],
5190 # Only source given:
5191 [ tdTestCopyToFile(sSrc = sBigFileHst), tdTestResultFailure() ],
5192 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst), tdTestResultFailure() ],
5193 # Only destination given:
5194 [ tdTestCopyToFile(sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')), tdTestResultFailure() ],
5195 [ tdTestCopyToDir( sDst = sScratchGst), tdTestResultFailure() ],
5196 # Both given, but invalid flags.
5197 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst, afFlags = [ 0x40000000, ] ), tdTestResultFailure() ],
5198 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGst, afFlags = [ 0x40000000, ] ),
5199 tdTestResultFailure() ],
5200 ];
5201 atTests.extend([
5202 # Non-existing source, but no destination:
5203 [ tdTestCopyToFile(sSrc = sScratchHstNotExist), tdTestResultFailure() ],
5204 [ tdTestCopyToDir( sSrc = sScratchHstNotExist), tdTestResultFailure() ],
5205 # Valid sources, but destination path not found:
5206 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
5207 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
5208 # Valid destination, but source file/dir not found:
5209 [ tdTestCopyToFile(sSrc = sScratchHstNotExist, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
5210 tdTestResultFailure() ],
5211 [ tdTestCopyToDir( sSrc = sScratchHstNotExist, sDst = sScratchGst), tdTestResultFailure() ],
5212 # Wrong type:
5213 [ tdTestCopyToFile(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
5214 tdTestResultFailure() ],
5215 [ tdTestCopyToDir( sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultFailure() ],
5216 ]);
5217 # Invalid characters in destination or source path:
5218 if sScratchGstInvalid is not None:
5219 atTests.extend([
5220 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
5221 tdTestResultFailure() ],
5222 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
5223 tdTestResultFailure() ],
5224 ]);
5225 if sScratchHstInvalid is not None:
5226 atTests.extend([
5227 [ tdTestCopyToFile(sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
5228 tdTestResultFailure() ],
5229 [ tdTestCopyToDir( sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
5230 tdTestResultFailure() ],
5231 ]);
5232
5233 #
5234 # Single file handling.
5235 #
5236 atTests.extend([
5237 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')),
5238 tdTestResultSuccess() ],
5239 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
5240 tdTestResultSuccess() ],
5241 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
5242 tdTestResultSuccess() ],
5243 ]);
5244 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
5245 atTests.extend([
5246 # Should succeed, as the file isn't there yet on the destination.
5247 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst + oTestVm.pathSep()), tdTestResultSuccess() ],
5248 # Overwrite the existing file.
5249 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst + oTestVm.pathSep()), tdTestResultSuccess() ],
5250 # Same file, but with a different name on the destination.
5251 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, os.path.split(sBigFileHst)[1])),
5252 tdTestResultSuccess() ], # Overwrite
5253 ]);
5254
5255 if oTestVm.isWindows():
5256 # Copy to a Windows alternative data stream (ADS).
5257 atTests.extend([
5258 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
5259 tdTestResultSuccess() ],
5260 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
5261 tdTestResultSuccess() ],
5262 ]);
5263
5264 #
5265 # Directory handling.
5266 #
5267 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
5268 atTests.extend([
5269 # Without a trailing slash added to the destination this should fail,
5270 # as the destination directory already exists.
5271 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst), tdTestResultFailure() ],
5272 # Same existing host directory, but this time with DirectoryCopyFlag_CopyIntoExisting set.
5273 # This should copy the contents of oEmptyDirGst to sScratchDstDir1Gst (empty, but anyway).
5274 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
5275 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5276 # Try again.
5277 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
5278 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5279 # With a trailing slash added to the destination, copy the empty guest directory
5280 # (should end up as sScratchDstDir2Gst/empty):
5281 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
5282 tdTestResultSuccess() ],
5283 # Repeat -- this time it should fail, as the destination directory already exists (and
5284 # DirectoryCopyFlag_CopyIntoExisting is not specified):
5285 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
5286 tdTestResultFailure() ],
5287 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work (again).
5288 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
5289 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5290 # Copy with a different destination name just for the heck of it:
5291 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchDstDir2Gst, 'empty2')),
5292 tdTestResultSuccess() ],
5293 ]);
5294 atTests.extend([
5295 # Now the same using a directory with files in it:
5296 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
5297 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5298 # Again.
5299 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
5300 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5301 ]);
5302 atTests.extend([
5303 # Copy the entire test tree:
5304 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep()),
5305 tdTestResultSuccess() ],
5306 # Again, should fail this time.
5307 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep()),
5308 tdTestResultFailure() ],
5309 # Works again, as DirectoryCopyFlag_CopyIntoExisting is specified.
5310 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep(),
5311 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5312 ]);
5313 #
5314 # Dotdot path handling.
5315 #
5316 if self.oTstDrv.fpApiVer >= 6.1:
5317 atTests.extend([
5318 # Test if copying stuff from a host dotdot ".." directory works.
5319 [ tdTestCopyToFile(sSrc = sScratchDotDotFileHst, sDst = sScratchDstDir1Gst + oTestVm.pathSep()),
5320 tdTestResultSuccess() ],
5321 # Test if copying stuff from the host to a guest's dotdot ".." directory works.
5322 # That should fail on destinations.
5323 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = sScratchDotDotDirGst), tdTestResultFailure() ],
5324 ]);
5325
5326 fRc = True;
5327 for (i, tTest) in enumerate(atTests):
5328 oCurTest = tTest[0]; # tdTestCopyTo
5329 oCurRes = tTest[1]; # tdTestResult
5330 reporter.log('Testing #%d, sSrc=%s, sDst=%s, afFlags=%s ...'
5331 % (i, limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags));
5332
5333 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5334 if not fRc:
5335 break;
5336 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyTo: Test #%d' % (i,));
5337 if fRc is not True:
5338 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5339 break;
5340
5341 fRc2 = False;
5342 if isinstance(oCurTest, tdTestCopyToFile):
5343 fRc2 = self.gctrlCopyFileTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
5344 else:
5345 fRc2 = self.gctrlCopyDirTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
5346 if fRc2 is not oCurRes.fRc:
5347 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
5348
5349 fRc = oCurTest.closeSession() and fRc;
5350
5351 return (fRc, oTxsSession);
5352
5353 def testGuestCtrlCopyFrom(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5354 """
5355 Tests copying files from guest to the host.
5356 """
5357
5358 reporter.log2('Entered');
5359
5360 #
5361 # Paths.
5362 #
5363 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, "testGctrlCopyFrom");
5364 sScratchDstDir1Hst = os.path.join(sScratchHst, "dstdir1");
5365 sScratchDstDir2Hst = os.path.join(sScratchHst, "dstdir2");
5366 sScratchDstDir3Hst = os.path.join(sScratchHst, "dstdir3");
5367 sScratchDstDir4Hst = os.path.join(sScratchHst, "dstdir4");
5368 # os.path.join() is too clever for "..", so we just build up the path here ourselves.
5369 sScratchDotDotDirHst = sScratchHst + os.path.sep + '..' + os.path.sep;
5370 oExistingFileGst = self.oTestFiles.chooseRandomFile();
5371 oNonEmptyDirGst = self.oTestFiles.chooseRandomDirFromTree(fNonEmpty = True);
5372 oTreeDirGst = self.oTestFiles.oTreeDir;
5373 oEmptyDirGst = self.oTestFiles.oEmptyDir;
5374
5375 if oTestVm.isWindows() or oTestVm.isOS2():
5376 sScratchGstInvalid = "?*|<invalid-name>";
5377 else:
5378 sScratchGstInvalid = None;
5379 if utils.getHostOs() in ('win', 'os2'):
5380 sScratchHstInvalid = "?*|<invalid-name>";
5381 else:
5382 sScratchHstInvalid = None;
5383
5384 sScratchDotDotDirGst = oTestVm.pathJoin(oEmptyDirGst.sPath, '..');
5385
5386 if os.path.exists(sScratchHst):
5387 if base.wipeDirectory(sScratchHst) != 0:
5388 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
5389 else:
5390 try:
5391 os.mkdir(sScratchHst);
5392 except:
5393 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
5394
5395 reporter.log2('Creating host sub dirs ...');
5396
5397 for sSubDir in (sScratchDstDir1Hst, sScratchDstDir2Hst, sScratchDstDir3Hst, sScratchDstDir4Hst):
5398 try:
5399 os.mkdir(sSubDir);
5400 except:
5401 return reporter.errorXcpt('os.mkdir(%s)' % (sSubDir, ));
5402
5403 reporter.log2('Defining tests ...');
5404
5405 #
5406 # Bad parameter tests.
5407 #
5408 atTests = [
5409 # Missing both source and destination:
5410 [ tdTestCopyFromFile(), tdTestResultFailure() ],
5411 [ tdTestCopyFromDir(), tdTestResultFailure() ],
5412 # Missing source.
5413 [ tdTestCopyFromFile(sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5414 [ tdTestCopyFromDir( sDst = sScratchHst), tdTestResultFailure() ],
5415 # Missing destination.
5416 [ tdTestCopyFromFile(oSrc = oExistingFileGst), tdTestResultFailure() ],
5417 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath), tdTestResultFailure() ],
5418 # Invalid flags:
5419 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somefile'), afFlags = [0x40000000]),
5420 tdTestResultFailure() ],
5421 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'somedir'), afFlags = [ 0x40000000] ),
5422 tdTestResultFailure() ],
5423 # Non-existing sources:
5424 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
5425 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5426 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
5427 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5428 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-file'),
5429 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5430 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-subdir'),
5431 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5432 # Non-existing destinations:
5433 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
5434 sDst = os.path.join(sScratchHst, 'no-such-directory', 'somefile') ), tdTestResultFailure() ],
5435 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'no-such-directory', 'somedir') ),
5436 tdTestResultFailure() ],
5437 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
5438 sDst = os.path.join(sScratchHst, 'no-such-directory-slash' + os.path.sep)),
5439 tdTestResultFailure() ],
5440 # Wrong source type:
5441 [ tdTestCopyFromFile(oSrc = oNonEmptyDirGst, sDst = os.path.join(sScratchHst, 'somefile') ), tdTestResultFailure() ],
5442 [ tdTestCopyFromDir(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somedir') ), tdTestResultFailure() ],
5443 ];
5444 # Bogus names:
5445 if sScratchHstInvalid:
5446 atTests.extend([
5447 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
5448 tdTestResultFailure() ],
5449 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
5450 tdTestResultFailure() ],
5451 ]);
5452 if sScratchGstInvalid:
5453 atTests.extend([
5454 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
5455 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5456 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
5457 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5458 ]);
5459
5460 #
5461 # Single file copying.
5462 #
5463 atTests.extend([
5464 # Should succeed, as the file isn't there yet on the destination.
5465 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), tdTestResultSuccess() ],
5466 # Overwrite the existing file.
5467 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), tdTestResultSuccess() ],
5468 # Same file, but with a different name on the destination.
5469 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile2')), tdTestResultSuccess() ],
5470 ]);
5471
5472 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
5473 # Copy into a directory.
5474 atTests.extend([
5475 # This should fail, as sScratchHst exists and is a directory.
5476 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst), tdTestResultFailure() ],
5477 # Same existing host directory, but this time with a trailing slash.
5478 # This should succeed, as the file isn't there yet on the destination.
5479 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
5480 # Overwrite the existing file.
5481 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
5482 ]);
5483
5484 #
5485 # Directory handling.
5486 #
5487 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
5488 atTests.extend([
5489 # Without a trailing slash added to the destination this should fail,
5490 # as the destination directory already exist.
5491 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst), tdTestResultFailure() ],
5492 # Same existing host directory, but this time with DirectoryCopyFlag_CopyIntoExisting set.
5493 # This should copy the contents of oEmptyDirGst to sScratchDstDir1Hst (empty, but anyway).
5494 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst,
5495 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5496 # Try again.
5497 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst,
5498 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5499 # With a trailing slash added to the destination, copy the empty guest directory
5500 # (should end up as sScratchHst/empty):
5501 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep), tdTestResultSuccess() ],
5502 # Repeat -- this time it should fail, as the destination directory already exists (and
5503 # DirectoryCopyFlag_CopyIntoExisting is not specified):
5504 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep), tdTestResultFailure() ],
5505 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work (again).
5506 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep,
5507 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5508 # Copy with a different destination name just for the heck of it:
5509 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = os.path.join(sScratchDstDir2Hst, 'empty2'),
5510 fIntoDst = True),
5511 tdTestResultSuccess() ],
5512 ]);
5513 atTests.extend([
5514 # Now the same using a directory with files in it:
5515 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir3Hst + os.path.sep), tdTestResultSuccess() ],
5516 # Again.
5517 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir3Hst, fIntoDst = True,
5518 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5519 ]);
5520 atTests.extend([
5521 # Copy the entire test tree:
5522 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep), tdTestResultSuccess() ],
5523 # Again, should fail this time.
5524 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep), tdTestResultFailure() ],
5525 # Works again, as DirectoryCopyFlag_CopyIntoExisting is specified.
5526 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep,
5527 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5528 ]);
5529 #
5530 # Dotdot path handling.
5531 #
5532 if self.oTstDrv.fpApiVer >= 6.1:
5533 atTests.extend([
5534 # Test if copying stuff from a guest dotdot ".." directory works.
5535 [ tdTestCopyFromDir(sSrc = sScratchDotDotDirGst, sDst = sScratchDstDir1Hst + os.path.sep,
5536 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]),
5537 tdTestResultFailure() ],
5538 # Test if copying stuff from the guest to a host's dotdot ".." directory works.
5539 # That should fail on destinations.
5540 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchDotDotDirHst), tdTestResultFailure() ],
5541 ]);
5542
5543 reporter.log2('Executing tests ...');
5544
5545 #
5546 # Execute the tests.
5547 #
5548 fRc = True;
5549 for (i, tTest) in enumerate(atTests):
5550 oCurTest = tTest[0]
5551 oCurRes = tTest[1] # type: tdTestResult
5552 if isinstance(oCurTest, tdTestCopyFrom):
5553 reporter.log('Testing #%d, %s: sSrc="%s", sDst="%s", afFlags="%s" ...'
5554 % (i, "directory" if isinstance(oCurTest, tdTestCopyFromDir) else "file",
5555 limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags,));
5556 else:
5557 reporter.log('Testing #%d, tdTestRemoveHostDir "%s" ...' % (i, oCurTest.sDir,));
5558 if isinstance(oCurTest, tdTestCopyFromDir) and self.oTstDrv.fpApiVer < 6.0:
5559 reporter.log('Skipping directoryCopyFromGuest test, not implemented in %s' % (self.oTstDrv.fpApiVer,));
5560 continue;
5561
5562 if isinstance(oCurTest, tdTestRemoveHostDir):
5563 fRc = oCurTest.execute(self.oTstDrv, oSession, oTxsSession, oTestVm, 'testing #%d' % (i,));
5564 else:
5565 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5566 if not fRc:
5567 break;
5568 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyFrom: Test #%d' % (i,));
5569 if fRc2 is not True:
5570 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5571 break;
5572
5573 if isinstance(oCurTest, tdTestCopyFromFile):
5574 fRc2 = self.gctrlCopyFileFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
5575 else:
5576 fRc2 = self.gctrlCopyDirFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
5577
5578 if fRc2 != oCurRes.fRc:
5579 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
5580
5581 fRc = oCurTest.closeSession() and fRc;
5582
5583 return (fRc, oTxsSession);
5584
5585 def testGuestCtrlUpdateAdditions(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5586 """
5587 Tests updating the Guest Additions inside the guest.
5588
5589 """
5590
5591 # Skip test for updating Guest Additions if we run on a too old (Windows) guest.
5592 ##
5593 ## @todo make it work everywhere!
5594 ##
5595 if oTestVm.sKind in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
5596 reporter.log("Skipping updating GAs on old windows vm (sKind=%s)" % (oTestVm.sKind,));
5597 return (None, oTxsSession);
5598 if oTestVm.isOS2():
5599 reporter.log("Skipping updating GAs on OS/2 guest");
5600 return (None, oTxsSession);
5601
5602 sVBoxValidationKitIso = self.oTstDrv.sVBoxValidationKitIso;
5603 if not os.path.isfile(sVBoxValidationKitIso):
5604 return reporter.log('Validation Kit .ISO not found at "%s"' % (sVBoxValidationKitIso,));
5605
5606 sScratch = os.path.join(self.oTstDrv.sScratchPath, "testGctrlUpdateAdditions");
5607 try:
5608 os.makedirs(sScratch);
5609 except OSError as e:
5610 if e.errno != errno.EEXIST:
5611 return reporter.error('Failed: Unable to create scratch directory \"%s\"' % (sScratch,));
5612 reporter.log('Scratch path is: %s' % (sScratch,));
5613
5614 atTests = [];
5615 if oTestVm.isWindows():
5616 atTests.extend([
5617 # Source is missing.
5618 [ tdTestUpdateAdditions(sSrc = ''), tdTestResultFailure() ],
5619
5620 # Wrong flags.
5621 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
5622 afFlags = [ 1234 ]), tdTestResultFailure() ],
5623
5624 # Non-existing .ISO.
5625 [ tdTestUpdateAdditions(sSrc = "non-existing.iso"), tdTestResultFailure() ],
5626
5627 # Wrong .ISO.
5628 [ tdTestUpdateAdditions(sSrc = sVBoxValidationKitIso), tdTestResultFailure() ],
5629
5630 # The real thing.
5631 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso()),
5632 tdTestResultSuccess() ],
5633 # Test the (optional) installer arguments. This will extract the
5634 # installer into our guest's scratch directory.
5635 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
5636 asArgs = [ '/extract', '/D=' + sScratch ]),
5637 tdTestResultSuccess() ]
5638 # Some debg ISO. Only enable locally.
5639 #[ tdTestUpdateAdditions(
5640 # sSrc = "V:\\Downloads\\VBoxGuestAdditions-r80354.iso"),
5641 # tdTestResultSuccess() ]
5642 ]);
5643 else:
5644 reporter.log('No OS-specific tests for non-Windows yet!');
5645
5646 fRc = True;
5647 for (i, tTest) in enumerate(atTests):
5648 oCurTest = tTest[0] # type: tdTestUpdateAdditions
5649 oCurRes = tTest[1] # type: tdTestResult
5650 reporter.log('Testing #%d, sSrc="%s", afFlags="%s" ...' % (i, oCurTest.sSrc, oCurTest.afFlags,));
5651
5652 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5653
5654 fRc, _ = oCurTest.createSession('Test #%d' % (i,));
5655 if fRc is not True:
5656 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5657 break;
5658
5659 try:
5660 oCurProgress = oCurTest.oGuest.updateGuestAdditions(oCurTest.sSrc, oCurTest.asArgs, oCurTest.afFlags);
5661 except:
5662 reporter.maybeErrXcpt(oCurRes.fRc, 'Updating Guest Additions exception for sSrc="%s", afFlags="%s":'
5663 % (oCurTest.sSrc, oCurTest.afFlags,));
5664 fRc = False;
5665 else:
5666 if oCurProgress is not None:
5667 oWrapperProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr,
5668 self.oTstDrv, "gctrlUpGA");
5669 oWrapperProgress.wait();
5670 assert oWrapperProgress.isCompleted();
5671 fRc = oWrapperProgress.isSuccess();
5672 if not fRc:
5673 oWrapperProgress.logResult(fIgnoreErrors = True);
5674 else:
5675 fRc = reporter.error('No progress object returned');
5676
5677 oCurTest.closeSession();
5678 if fRc is oCurRes.fRc:
5679 if fRc:
5680 ## @todo Verify if Guest Additions were really updated (build, revision, ...).
5681 ## @todo r=bird: Not possible since you're installing the same GAs as before...
5682 ## Maybe check creation dates on certain .sys/.dll/.exe files?
5683 pass;
5684 else:
5685 reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc, oCurRes.fRc));
5686
5687 return (True, oTxsSession); # Always return True here; errors are counted via the reporter.
5688
5689 def checkScreenShot(self, iWidth, iHeight, aRGBData): # pylint: disable=unused-argument
5690 """
5691 TBD: Implement basic validation of the captured screenshot content.
5692 """
5693 cPixels = iHeight * iWidth
5694
5695 if cPixels == 0:
5696 reporter.logXcpt("Empty screenshot");
5697 return False
5698
5699 # The simple algoritm below assumes that Windows OS desktop consists of a pixels that
5700 # are not too dark or bright but usually of blue tint.
5701 cDesktopPixels = 0
5702 cDesktopPixelsBlue = 0
5703 iThreshold = 20
5704 for i in range(0, cPixels, 4) :
5705 if sys.version_info[0] >= 3:
5706 iRed = aRGBData[i];
5707 iGreen = aRGBData[i + 1];
5708 iBlue = aRGBData[i + 2];
5709 else: # Python 2.7 treats a pixel data returned by takeScreenShotToArray as a string
5710 iRed = ord(aRGBData[i])
5711 iGreen = ord(aRGBData[i + 1])
5712 iBlue = ord(aRGBData[i + 2])
5713
5714 iBright = (3 * iRed + 6 * iGreen + iBlue) / 10
5715 if iThreshold < iBright < 255 - iThreshold :
5716 cDesktopPixels += 1;
5717 cDesktopPixelsBlue += int(iBlue > iRed and iBlue > iGreen);
5718
5719 fpRatioDesktop = float(cDesktopPixels) / float(cPixels);
5720 reporter.log2('Ratio of not too dark or bright pixels %.2f' % (fpRatioDesktop));
5721
5722 if fpRatioDesktop > 0.1:
5723 fpRatioBlue = float(cDesktopPixelsBlue) / float(cDesktopPixels);
5724 reporter.log2('Ratio of blue pixels %.2f ' % (fpRatioBlue));
5725 if fpRatioBlue > 0.5:
5726 return True
5727
5728 return True # Always return True until the parameters will be calibrated.
5729
5730 def testGuestCtrl3D(self, oSession, oTxsSession, oTestVm): # pylint: disable=unused-argument
5731 """
5732 Tests for VMSVGA device.
5733 """
5734
5735 if oTestVm.sKind not in ('Windows8_64', 'Windows10', 'Windows10_64', 'Windows11_64'):
5736 return (True, oTxsSession);
5737
5738 iScreenId = 0 # TBD: Use a loop to iterate and check all virtual displays
5739 try:
5740 if self.oTstDrv.fpApiVer >= 5.0:
5741 iWidth, iHeight, _, _, _, _ = oSession.o.console.display.getScreenResolution(iScreenId);
5742 else:
5743 iWidth, iHeight, _, _, _ = oSession.o.console.display.getScreenResolution(iScreenId);
5744
5745 aRGBData = oSession.o.console.display.takeScreenShotToArray(iScreenId, iWidth, iHeight,
5746 vboxcon.BitmapFormat_RGBA);
5747 except:
5748 reporter.logXcpt("Unable to take screenshot");
5749 return False
5750
5751 reporter.log2('Got screenshot (%s x %s) having %s bytes' % (iWidth, iHeight, len(aRGBData)));
5752 # @todo r=aeichner Where is this result incorporated in the test result?
5753 # It gets overwritten afterwards without being taken into account
5754 fRc = self.checkScreenShot(iWidth, iHeight, aRGBData);
5755
5756 fRc = fRc and self.oTstDrv.txsRunTest(oTxsSession, 'Checking DX11 feature level', 30 * 1000,
5757 '${CDROM}/${OS/ARCH}/ntDisplay${EXESUFF}', ('ntDisplay', ));
5758 fRc = True; # TBD: Fix for Unattended tests when the ValidationKit.iso is mounted as drive D:
5759 return (fRc, oTxsSession);
5760
5761class tdAddGuestCtrl(vbox.TestDriver): # pylint: disable=too-many-instance-attributes,too-many-public-methods
5762 """
5763 Guest control using VBoxService on the guest.
5764 """
5765
5766 def __init__(self):
5767 vbox.TestDriver.__init__(self);
5768 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
5769 self.asRsrcs = None;
5770 self.fQuick = False; # Don't skip lengthly tests by default.
5771 self.addSubTestDriver(SubTstDrvAddGuestCtrl(self));
5772
5773 #
5774 # Overridden methods.
5775 #
5776 def showUsage(self):
5777 """
5778 Shows the testdriver usage.
5779 """
5780 rc = vbox.TestDriver.showUsage(self);
5781 reporter.log('');
5782 reporter.log('tdAddGuestCtrl Options:');
5783 reporter.log(' --quick');
5784 reporter.log(' Same as --virt-modes hwvirt --cpu-counts 1.');
5785 return rc;
5786
5787 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
5788 """
5789 Parses the testdriver arguments from the command line.
5790 """
5791 if asArgs[iArg] == '--quick':
5792 self.parseOption(['--virt-modes', 'hwvirt'], 0);
5793 self.parseOption(['--cpu-counts', '1'], 0);
5794 self.fQuick = True;
5795 else:
5796 return vbox.TestDriver.parseOption(self, asArgs, iArg);
5797 return iArg + 1;
5798
5799 def actionConfig(self):
5800 if not self.importVBoxApi(): # So we can use the constant below.
5801 return False;
5802
5803 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT;
5804 sGaIso = self.getGuestAdditionsIso();
5805 return self.oTestVmSet.actionConfig(self, eNic0AttachType = eNic0AttachType, sDvdImage = sGaIso);
5806
5807 def actionExecute(self):
5808 return self.oTestVmSet.actionExecute(self, self.testOneCfg);
5809
5810 #
5811 # Test execution helpers.
5812 #
5813 def testOneCfg(self, oVM, oTestVm): # pylint: disable=too-many-statements
5814 """
5815 Runs the specified VM thru the tests.
5816
5817 Returns a success indicator on the general test execution. This is not
5818 the actual test result.
5819 """
5820
5821 self.logVmInfo(oVM);
5822
5823 fRc = True;
5824 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName, fCdWait = False);
5825 reporter.log("TxsSession: %s" % (oTxsSession,));
5826 if oSession is not None:
5827 fRc, oTxsSession = self.aoSubTstDrvs[0].testIt(oTestVm, oSession, oTxsSession);
5828 self.terminateVmBySession(oSession);
5829 else:
5830 fRc = False;
5831 return fRc;
5832
5833 def onExit(self, iRc):
5834 return vbox.TestDriver.onExit(self, iRc);
5835
5836 def gctrlReportError(self, progress):
5837 """
5838 Helper function to report an error of a
5839 given progress object.
5840 """
5841 if progress is None:
5842 reporter.log('No progress object to print error for');
5843 else:
5844 errInfo = progress.errorInfo;
5845 if errInfo:
5846 reporter.log('%s' % (errInfo.text,));
5847 return False;
5848
5849 def gctrlGetRemainingTime(self, msTimeout, msStart):
5850 """
5851 Helper function to return the remaining time (in ms)
5852 based from a timeout value and the start time (both in ms).
5853 """
5854 if msTimeout == 0:
5855 return 0xFFFFFFFE; # Wait forever.
5856 msElapsed = base.timestampMilli() - msStart;
5857 if msElapsed > msTimeout:
5858 return 0; # No time left.
5859 return msTimeout - msElapsed;
5860
5861 def testGuestCtrlManual(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements,unused-argument,unused-variable
5862 """
5863 For manually testing certain bits.
5864 """
5865
5866 reporter.log('Manual testing ...');
5867 fRc = True;
5868
5869 sUser = 'Administrator';
5870 sPassword = 'password';
5871
5872 oGuest = oSession.o.console.guest;
5873 oGuestSession = oGuest.createSession(sUser,
5874 sPassword,
5875 "", "Manual Test");
5876
5877 aWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
5878 _ = oGuestSession.waitForArray(aWaitFor, 30 * 1000);
5879
5880 #sCmd = self.getGuestSystemShell(oTestVm);
5881 #asArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
5882 #aEnv = [];
5883 #afFlags = [];
5884
5885 # Fix this once being used (again).
5886 #for _ in xrange(100):
5887 # oProc = self.processCreateWrapper(oGuestSession, sCmd, asArgs if self.fpApiVer >= 5.0 else asArgs[1:],
5888 # "", # Working directory.
5889 # aEnv, afFlags, 30 * 1000);
5890 #
5891 # aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
5892 # _ = oProc.waitForArray(aWaitFor, 30 * 1000);
5893
5894 oGuestSession.close();
5895 oGuestSession = None;
5896
5897 time.sleep(5);
5898
5899 oSession.o.console.PowerDown();
5900
5901 return (fRc, oTxsSession);
5902
5903if __name__ == '__main__':
5904 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