VirtualBox

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

Last change on this file since 84563 was 84563, checked in by vboxsync, 5 years ago

Validation Kit/tdAddGuestCtrl.py: Implemented limitString() for limiting string output length; especially useful for logging very long (random) test data.

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