RegressionTests__VMCrashTestCase.st
author Claus Gittinger <cg@exept.de>
Tue, 09 Jul 2019 18:53:03 +0200
changeset 2327 bf482d49aeaf
parent 1447 2351db93aa5b
child 1500 d406a10b2965
permissions -rw-r--r--
#QUALITY by exept class: RegressionTests::StringTests added: #test82c_expanding

"{ Encoding: utf8 }"

"{ Package: 'stx:goodies/regression' }"

"{ NameSpace: RegressionTests }"

TestCase subclass:#VMCrashTestCase
	instanceVariableNames:''
	classVariableNames:'EXIT_CODE_SUCCESS EXIT_CODE_FAILURE EXIT_CODE_ERROR'
	poolDictionaries:''
	category:'tests-Regression-Abstract'
!

!VMCrashTestCase class methodsFor:'documentation'!

documentation
"
    A specialized abstract test case class for writing
    VM crash tests. The test is run in separate process
    if it eventually crashes the VM, it won't take whole test
    suite with it.

    Each test case *must* be annotated by one <spawn:> annotation,
    argument must be either `true` of `false`. If `true` then the
    test is run in a freshly started VM. If `false`, test is run
    in the same VM.

    As this is meant as a base class for regression tests that used to
    kill the VM, normally you should annotate tests with <spawn: true>

    [author:]
	Jan Vrany <jan.vrany@fit.cvut.cz>

    [instance variables:]

    [class variables:]

    [see also:]

"
! !

!VMCrashTestCase class methodsFor:'initialization'!

initialize
    "Invoked at system start or when the class is dynamically loaded."

    "/ please change as required (and remove this comment)

    EXIT_CODE_SUCCESS := 0.
    EXIT_CODE_FAILURE := 1.
    EXIT_CODE_ERROR := 2.

    "Modified: / 05-09-2014 / 18:17:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VMCrashTestCase class methodsFor:'testing'!

isAbstract
    ^ self == RegressionTests::VMCrashTestCase
! !

!VMCrashTestCase methodsFor:'accessing'!

timeout
    "Returns a default timeout (sec) for the test.
     If nil is returned, no timeout enforced.

    Note that the timeout is set only when running under
    report runner, interactive tools does not use it"

    | method |
    method := self class lookupMethodFor: testSelector.
    method annotationsAt:#timeout: do:[:annotation|
	 ^annotation arguments first
    ].
    ^60"sec - default timeout"

    "Created: / 08-09-2014 / 13:00:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VMCrashTestCase methodsFor:'running'!

runCase
    "Perform the testcase.

     If testcase is annotated by <spawn: false> the test is run in the
     very same VM. If <spawn: true>, a new VM is started and the testcase
     in run in that new VM"

    | tempDir testcaseFile exe args script environment outputFile output pid blocker status spawn |

    spawn := (self class lookupMethodFor: testSelector) annotationAt: #spawn:.
    spawn isNil ifTrue:[
	self error: 'No <spawn:> annotation'.
    ].
    (spawn argumentAt: 1) == false ifTrue:[
	^ super runCase.
    ] ifFalse:[
	(spawn argumentAt: 1) ~~ true ifTrue:[
	    self error: 'Argument to <spawn:> must be either `true` or `false`'.
	]
    ].

    [
	tempDir := Filename newTemporary.
	tempDir makeDirectory.
	testcaseFile := tempDir / ((Smalltalk fileNameForClass: self class) , '.st').
	self class fileOutAs: testcaseFile.

	script := 'Smalltalk packagePath: %1.
		   Smalltalk loadPackage:%2.
		   Smalltalk fileIn: %3.
		   (%4 selector: %5) runCaseInternal.'
		    bindWith: Smalltalk packagePath asArray storeString
			with: self class package storeString
			with: testcaseFile pathName storeString
			with: self class name
			with: testSelector storeString.

	exe := OperatingSystem pathOfSTXExecutable.
	args := { exe . '--abortOnSEGV' . '--execute' . ( tempDir / 'run.st' ) pathName }.

	OperatingSystem isMSWINDOWSlike ifTrue:[
	    args := String streamContents:[:s|
		args
		    do:[:each | s nextPut:$"; nextPutAll: each; nextPut: $"]
		    separatedBy: [ s space ]
	    ]
	].

	outputFile := tempDir / 'output.txt'.
	output := outputFile writeStream.

	"/ Now, spit out some helper files that for debugging.
	( tempDir / 'run.st' ) writingFileDo:[ :f |
	    f nextPutAll: script.
	].
	environment := OperatingSystem isUNIXlike
			ifTrue:[OperatingSystem getEnvironment copy]
			ifFalse:[environment := Dictionary new].
	blocker := Semaphore new.

	Processor monitor:[
	     pid := OperatingSystem exec: exe withArguments:args
		environment:environment
		fileDescriptors:{0 . output fileDescriptor  . output fileDescriptor  }
		fork:true
		newPgrp:false
		inDirectory: Filename currentDirectory pathName
	] action: [ :s |
	    status := s.
	    blocker signal.
	].

	output close.

	pid isNil ifTrue:[
	    self error: 'Failed to spawn test'.
	    ^ self.
	].

	blocker wait.

	status code == EXIT_CODE_FAILURE ifTrue:[
	    (outputFile notNil and:[ outputFile exists ]) ifTrue:[
		Stdout nextPutAll: '== TEST FAILED: '; nextPutAll: testSelector; nextPutLine:' =='.
		outputFile readingFileDo:[:s|
		    [ s atEnd ] whileFalse:[
			Stdout nextPutLine: s nextLine.
		    ].
		].
	    ].
	    self assert: false description: 'Assertion failed, see log'.
	].
	(status code == EXIT_CODE_ERROR or:[status status == #signal]) ifTrue:[
	    (outputFile notNil and:[ outputFile exists ]) ifTrue:[
		Stdout nextPutAll: '== TEST ERROR: '; nextPutAll: testSelector; nextPutLine:' =='.
		outputFile readingFileDo:[:s|
		    [ s atEnd ] whileFalse:[
			Stdout nextPutLine: s nextLine.
		    ].
		].
	    ].
	    self error: 'Error occured'.
	].
    ] ensure:[
	(tempDir notNil and:[tempDir exists]) ifTrue:[
	    [
		tempDir recursiveRemove.
	    ] on: Error do:[:ex |
		OperatingSystem isMSWINDOWSlike ifFalse:[
		    ex reject.
		].
	    ]
	].
    ].

    "
    VMCrashTestCase run:#test_infrastructure
    "

    "Created: / 04-09-2014 / 18:13:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 19-09-2014 / 16:43:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

runCaseInternal
    [
	super runCase.
	Stdout cr;
	    nextPutAll: 'PASSED'; cr.
    ] on: TestResult failure do:[:failure |
	Stdout cr;
	    nextPutAll: 'FAILURE: '; nextPutAll: failure description; cr.
	Smalltalk exit: EXIT_CODE_FAILURE.
    ] on: TestResult exError do:[:error |
	Stdout cr;
	    nextPutAll: 'ERROR: '; nextPutAll: error description; cr.
	Smalltalk exit: EXIT_CODE_ERROR.
    ].

    "Created: / 04-09-2014 / 17:41:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 05-09-2014 / 18:37:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VMCrashTestCase methodsFor:'tests - infrastructure'!

test_infrastructure
    "
    VMCrashTestCase run:#test_infrastructure
    "
    <spawn: false>

    | result |

    result := self class run: #tst_pass.
    self assert: result passedCount = 1.
    self assert: result failureCount = 0.
    self assert: result errorCount = 0.

    result := self class run: #tst_fail.
    self assert: result passedCount = 0.
    self assert: result failureCount = 1.
    self assert: result errorCount = 0.

    result := self class run: #tst_error.
    self assert: result passedCount = 0.
    self assert: result failureCount = 0.
    self assert: result errorCount = 1.

    "
    VMCrashTestCase run: #tst_crash.
    "
    result := self class run: #tst_crash.
    self assert: result passedCount = 0.
    self assert: result failureCount = 0.
    self assert: result errorCount = 1.

    "Created: / 05-09-2014 / 18:22:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 08-09-2014 / 12:26:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

tst_crash

    <spawn: true>

    | bytes |

    Stdout nextPutLine: 'Going to crash now!!'.

    bytes := ExternalBytes address: 16r10 size: 100.
    bytes byteAt: 1 put: 10.

    "Created: / 05-09-2014 / 18:24:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 16-09-2014 / 20:30:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

tst_error
    <spawn: true>
    self error:'Error'

    "Created: / 05-09-2014 / 18:20:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 08-09-2014 / 12:26:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

tst_fail
    <spawn: true>
    self assert: false.

    "Created: / 05-09-2014 / 18:20:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 08-09-2014 / 12:26:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

tst_pass
    <spawn: true>

    "Created: / 05-09-2014 / 18:20:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 08-09-2014 / 12:26:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VMCrashTestCase class methodsFor:'documentation'!

version
    ^ '$Header$'
!

version_CVS
    ^ '$Header$'
! !


VMCrashTestCase initialize!