VirtualBox

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

Last change on this file since 103200 was 103200, checked in by vboxsync, 12 months ago

Validation Kit/tdAddGuestCtrl.py: Use the new VBoxGuestControlHelper binary to test in which Windows session guest processes are being started. Factored out the guest process execution code to a helper function so that it can be used also for VBoxGuestControlHelper. bugref:10586

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

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