org.gradle.internal.logging.console.ConsoleFunctionalTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.internal.logging.console
import org.gradle.api.logging.LogLevel
import org.gradle.internal.logging.events.EndOutputEvent
import org.gradle.internal.logging.events.OperationIdentifier
import org.gradle.internal.logging.events.ProgressCompleteEvent
import org.gradle.internal.logging.events.ProgressEvent
import org.gradle.internal.logging.events.ProgressStartEvent
import org.gradle.internal.logging.sink.OutputEventRenderer
import org.gradle.internal.nativeintegration.console.ConsoleMetaData
import org.gradle.internal.time.TrueTimeProvider
import org.gradle.test.fixtures.ConcurrentTestUtil
import org.gradle.util.RedirectStdOutAndErr
import org.junit.Rule
import spock.lang.Specification
class ConsoleFunctionalTest extends Specification {
@Rule public final RedirectStdOutAndErr outputs = new RedirectStdOutAndErr()
private final ConsoleStub console = new ConsoleStub()
private final ConsoleMetaData metaData = Mock(ConsoleMetaData)
private OutputEventRenderer renderer
public static final String IDLE = '> IDLE'
def setup() {
renderer = new OutputEventRenderer()
renderer.configure(LogLevel.INFO)
renderer.addConsole(console, true, true, metaData)
_ * metaData.getRows() >> 10
_ * metaData.getCols() >> 25
}
def "renders initial state"() {
when:
renderer.onOutput(startEvent(1, null, BuildStatusRenderer.BUILD_PROGRESS_CATEGORY, 'INITIALIZATION PHASE', '<---> 0% INITIALIZING'))
then:
ConcurrentTestUtil.poll(1) {
assert statusBar.display == '<---> 0% INITIALIZING'
assert progressArea.display == [IDLE, IDLE, IDLE, IDLE]
}
}
def "renders configuration progress"() {
when:
renderer.onOutput(startEvent(1, null, BuildStatusRenderer.BUILD_PROGRESS_CATEGORY, 'CONFIGURATION PHASE', '<---> 0% CONFIGURING'))
renderer.onOutput(startEvent(2, 1, 'category', 'Configuring root project', 'root project', null, 'root project'))
then:
ConcurrentTestUtil.poll(1) {
assert statusBar.display == '<---> 0% CONFIGURING'
assert progressArea.display == ['> root project', IDLE, IDLE, IDLE]
}
when:
renderer.onOutput(completeEvent(2, BuildStatusRenderer.BUILD_PROGRESS_CATEGORY))
renderer.onOutput(progressEvent(1, BuildStatusRenderer.BUILD_PROGRESS_CATEGORY, '<=--> 33% CONFIGURING'))
then:
ConcurrentTestUtil.poll(1) {
assert statusBar.display == '<=--> 33% CONFIGURING'
assert progressArea.display == [IDLE, IDLE, IDLE, IDLE]
}
}
def "removes operation display from progress area upon completion"() {
when:
renderer.onOutput(startEvent(2, ':foo'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> :foo', IDLE, IDLE, IDLE]
}
when:
renderer.onOutput(completeEvent(2, BuildStatusRenderer.BUILD_PROGRESS_CATEGORY))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == [IDLE, IDLE, IDLE, IDLE]
}
}
def "renders parallel execution progress"() {
when:
renderer.onOutput(startEvent(2, ':foo'))
renderer.onOutput(startEvent(3, ':bar'))
renderer.onOutput(startEvent(4, ':baz'))
renderer.onOutput(startEvent(5, ':quux'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> :foo', '> :bar', '> :baz', '> :quux']
}
}
def "renders child operation work inline"() {
when:
renderer.onOutput(startEvent(1, ':foo'))
renderer.onOutput(startEvent(2, 1, null, null, null, null, ':bar'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> :foo > :bar', IDLE, IDLE, IDLE]
}
}
def "trims progress display to console width"() {
given:
_ * metaData.getCols() >> 25
when:
renderer.onOutput(startEvent(1, 'abcdefghijklmnopqrstuvwxyz'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> abcdefghijklmnopqrstuv', IDLE, IDLE, IDLE]
}
}
def "progress display is removed upon build completion"() {
when:
renderer.onOutput(startEvent(1, null, BuildStatusRenderer.BUILD_PROGRESS_CATEGORY, 'EXECUTION PHASE', '<---> 0% EXECUTING'))
renderer.onOutput(startEvent(2, ':foo'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.visible
}
when:
renderer.onOutput(new EndOutputEvent())
then:
ConcurrentTestUtil.poll(1) {
assert !progressArea.visible
}
}
def "preserves position of operations in progress"() {
when:
renderer.onOutput(startEvent(1, ':wat'))
renderer.onOutput(startEvent(2, ':foo'))
renderer.onOutput(startEvent(3, ':bar'))
renderer.onOutput(startEvent(4, ':baz'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> :wat', '> :foo', '> :bar', '> :baz']
}
when:
renderer.onOutput(completeEvent(1, ':wat'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == [IDLE, '> :foo', '> :bar', '> :baz']
}
when:
renderer.onOutput(progressEvent(2, 'CATEGORY', '[35 / 50] :foo'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == [IDLE, '> [35 / 50] :foo', '> :bar', '> :baz']
}
when:
renderer.onOutput(startEvent(5, ':new'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> :new', '> [35 / 50] :foo', '> :bar', '> :baz']
}
}
def "progress display height remains fixed even if more work in progress than max height"() {
when:
renderer.onOutput(startEvent(1, ':wat'))
renderer.onOutput(startEvent(2, ':foo'))
renderer.onOutput(startEvent(3, ':bar'))
renderer.onOutput(startEvent(4, ':baz'))
renderer.onOutput(startEvent(5, ':nope'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> :wat', '> :foo', '> :bar', '> :baz']
}
when:
renderer.onOutput(completeEvent(1, ':wat'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> :nope', '> :foo', '> :bar', '> :baz']
}
}
def "multiple events for same operation are coalesced and rendered once"() {
when:
renderer.onOutput(startEvent(1, ':wat'))
renderer.onOutput(progressEvent(1, 'CATEGORY', '[1 / 7] :wat'))
renderer.onOutput(progressEvent(1, 'CATEGORY', '[2 / 7] :wat'))
renderer.onOutput(progressEvent(1, 'CATEGORY', '[3 / 7] :wat'))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> [3 / 7] :wat', IDLE, IDLE, IDLE]
}
}
def "operation that finishes immediately is not rendered"() {
when:
[startEvent(1, ':wat'), progressEvent(1, 'CATEGORY', ':wat'), completeEvent(1, 'CATEGORY', null, ':wat')].each {
renderer.onOutput(it)
}
then:
ConcurrentTestUtil.poll(1, 0.1) {
assert progressArea.display == [IDLE, IDLE, IDLE, IDLE]
}
}
def "progress display uses short description if status is empty"() {
when:
renderer.onOutput(startEvent(1, null, 'CATEGORY', 'DESCRIPTION', 'SHORT_DESCRIPTION', 'LOGGING_HEADER', ''))
then:
ConcurrentTestUtil.poll(1) {
assert progressArea.display == ['> SHORT_DESCRIPTION', IDLE, IDLE, IDLE]
}
}
ProgressStartEvent startEvent(Long id, Long parentId=null, category='CATEGORY', description='DESCRIPTION', shortDescription='SHORT_DESCRIPTION', loggingHeader='LOGGING_HEADER', status='STATUS') {
long timestamp = new TrueTimeProvider().currentTime
OperationIdentifier parent = parentId ? new OperationIdentifier(parentId) : null
new ProgressStartEvent(new OperationIdentifier(id), parent, timestamp, category, description, shortDescription, loggingHeader, status)
}
ProgressStartEvent startEvent(Long id, String status) {
new ProgressStartEvent(new OperationIdentifier(id), null, new TrueTimeProvider().currentTime, null, null, null, null, status)
}
ProgressEvent progressEvent(Long id, category='CATEGORY', status='STATUS') {
long timestamp = new TrueTimeProvider().currentTime
new ProgressEvent(new OperationIdentifier(id), timestamp, category, status)
}
ProgressCompleteEvent completeEvent(Long id, category='CATEGORY', description='DESCRIPTION', status='STATUS') {
long timestamp = new TrueTimeProvider().currentTime
new ProgressCompleteEvent(new OperationIdentifier(id), timestamp, category, description, status)
}
private ConsoleStub.TestableRedrawableLabel getStatusBar() {
console.statusBar as ConsoleStub.TestableRedrawableLabel
}
private ConsoleStub.TestableBuildProgressTextArea getProgressArea() {
console.buildProgressArea as ConsoleStub.TestableBuildProgressTextArea
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy