VirtualBox

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

Last change on this file since 106089 was 106061, checked in by vboxsync, 8 months ago

Copyright year updates by scm.

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