<commit_before>/*
 * Copyright 2010 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.messaging.remote.internal.inet

import org.gradle.api.Action
import org.gradle.internal.id.UUIDGenerator
import org.gradle.messaging.remote.internal.ConnectCompletion
import org.gradle.messaging.remote.internal.ConnectException
import org.gradle.messaging.remote.internal.DefaultMessageSerializer
import org.gradle.test.fixtures.concurrent.ConcurrentSpec

class TcpConnectorTest extends ConcurrentSpec {
    final def serializer = new DefaultMessageSerializer<String>(getClass().classLoader)
    final def idGenerator = new UUIDGenerator()
    final def addressFactory = new InetAddressFactory()
    final def outgoingConnector = new TcpOutgoingConnector()
    final def incomingConnector = new TcpIncomingConnector(executorFactory, addressFactory, idGenerator)

    def "client can connect to server"() {
        Action action = Mock()

        when:
        def acceptor = incomingConnector.accept(action, false)
        def connection = outgoingConnector.connect(acceptor.address).create(serializer)

        then:
        connection != null

        cleanup:
        acceptor?.requestStop()
    }

    def "client can connect to server using remote addresses"() {
        Action action = Mock()

        when:
        def acceptor = incomingConnector.accept(action, true)
        def connection = outgoingConnector.connect(acceptor.address).create(serializer)

        then:
        connection != null

        cleanup:
        acceptor?.requestStop()
    }

    def "server executes action when incoming connection received"() {
        Action action = Mock()

        when:
        def acceptor = incomingConnector.accept(action, false)
        outgoingConnector.connect(acceptor.address)
        thread.blockUntil.connected

        then:
        1 * action.execute(!null) >> { instant.connected }

        cleanup:
        acceptor?.requestStop()
    }

    def "client throws exception when cannot connect to server"() {
        def address = new MultiChoiceAddress("address", 12345, [InetAddress.getByName("localhost")])

        when:
        outgoingConnector.connect(address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${address}."
        e.cause instanceof java.net.ConnectException
    }

    def "the exception includes last failure when cannot connect"() {
        def address = new MultiChoiceAddress("address", 12345, [InetAddress.getByName("localhost"), InetAddress.getByName("127.0.0.1")])

        when:
        outgoingConnector.connect(address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${address}."
        e.cause instanceof java.net.ConnectException
    }

    def "client cannot connect when server has requested stop"() {
        when:
        def acceptor = incomingConnector.accept(Mock(Action), false)
        acceptor.requestStop()
        outgoingConnector.connect(acceptor.address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${acceptor.address}."
        e.cause instanceof java.net.ConnectException
    }

    def "server stops accepting connections when action fails"() {
        Action action = Mock()

        given:
        _ * action.execute(_) >> {
            throw new RuntimeException()
        }

        when:
        def acceptor = incomingConnector.accept(action, false)
        async {
            outgoingConnector.connect(acceptor.address)
        }
        outgoingConnector.connect(acceptor.address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${acceptor.address}."
        e.cause instanceof java.net.ConnectException

        cleanup:
        acceptor?.requestStop()
    }

    def "acceptor stop blocks until accept action has completed"() {
        Action action = Mock()

        given:
        1 * action.execute(_) >> {
            instant.connected
            thread.block()
            instant.actionFinished
        }

        when:
        def acceptor = incomingConnector.accept(action, false)
        outgoingConnector.connect(acceptor.address)
        thread.blockUntil.connected
        operation.stop {
            acceptor.stop()
        }

        then:
        operation.stop.end > instant.actionFinished

        cleanup:
        acceptor?.requestStop()
    }

    def "can receive message from peer after peer has closed connection"() {
        // This is a test to simulate the messaging that the daemon does on build completion, in order to validate some assumptions

        when:
        def acceptor = incomingConnector.accept({ ConnectCompletion event ->
            def connection = event.create(serializer)
            connection.dispatch("bye")
            connection.stop()
            instant.closed
        } as Action, false)

        def connection = outgoingConnector.connect(acceptor.address).create(serializer)
        thread.blockUntil.closed

        then:
        connection.receive() == "bye"
        connection.receive() == null

        cleanup:
        connection?.stop()
        acceptor?.stop()
    }
}
<commit_msg>Added test case to reproduce daemon failure on windows.<commit_after>/*
 * Copyright 2010 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.messaging.remote.internal.inet

import org.gradle.api.Action
import org.gradle.internal.id.UUIDGenerator
import org.gradle.internal.serialize.BaseSerializerFactory
import org.gradle.internal.serialize.Serializers
import org.gradle.messaging.remote.internal.ConnectCompletion
import org.gradle.messaging.remote.internal.ConnectException
import org.gradle.messaging.remote.internal.DefaultMessageSerializer
import org.gradle.messaging.remote.internal.KryoBackedMessageSerializer
import org.gradle.test.fixtures.concurrent.ConcurrentSpec
import spock.lang.Unroll

class TcpConnectorTest extends ConcurrentSpec {
    final def serializer = new DefaultMessageSerializer<String>(getClass().classLoader)
    final def idGenerator = new UUIDGenerator()
    final def addressFactory = new InetAddressFactory()
    final def outgoingConnector = new TcpOutgoingConnector()
    final def incomingConnector = new TcpIncomingConnector(executorFactory, addressFactory, idGenerator)

    def "client can connect to server"() {
        Action action = Mock()

        when:
        def acceptor = incomingConnector.accept(action, false)
        def connection = outgoingConnector.connect(acceptor.address).create(serializer)

        then:
        connection != null

        cleanup:
        acceptor?.requestStop()
    }

    def "client can connect to server using remote addresses"() {
        Action action = Mock()

        when:
        def acceptor = incomingConnector.accept(action, true)
        def connection = outgoingConnector.connect(acceptor.address).create(serializer)

        then:
        connection != null

        cleanup:
        acceptor?.requestStop()
    }

    def "server executes action when incoming connection received"() {
        Action action = Mock()

        when:
        def acceptor = incomingConnector.accept(action, false)
        outgoingConnector.connect(acceptor.address)
        thread.blockUntil.connected

        then:
        1 * action.execute(!null) >> { instant.connected }

        cleanup:
        acceptor?.requestStop()
    }

    def "client throws exception when cannot connect to server"() {
        def address = new MultiChoiceAddress("address", 12345, [InetAddress.getByName("localhost")])

        when:
        outgoingConnector.connect(address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${address}."
        e.cause instanceof java.net.ConnectException
    }

    def "the exception includes last failure when cannot connect"() {
        def address = new MultiChoiceAddress("address", 12345, [InetAddress.getByName("localhost"), InetAddress.getByName("127.0.0.1")])

        when:
        outgoingConnector.connect(address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${address}."
        e.cause instanceof java.net.ConnectException
    }

    def "client cannot connect when server has requested stop"() {
        when:
        def acceptor = incomingConnector.accept(Mock(Action), false)
        acceptor.requestStop()
        outgoingConnector.connect(acceptor.address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${acceptor.address}."
        e.cause instanceof java.net.ConnectException
    }

    def "server stops accepting connections when action fails"() {
        Action action = Mock()

        given:
        _ * action.execute(_) >> {
            throw new RuntimeException()
        }

        when:
        def acceptor = incomingConnector.accept(action, false)
        async {
            outgoingConnector.connect(acceptor.address)
        }
        outgoingConnector.connect(acceptor.address)

        then:
        ConnectException e = thrown()
        e.message.startsWith "Could not connect to server ${acceptor.address}."
        e.cause instanceof java.net.ConnectException

        cleanup:
        acceptor?.requestStop()
    }

    def "acceptor stop blocks until accept action has completed"() {
        Action action = Mock()

        given:
        1 * action.execute(_) >> {
            instant.connected
            thread.block()
            instant.actionFinished
        }

        when:
        def acceptor = incomingConnector.accept(action, false)
        outgoingConnector.connect(acceptor.address)
        thread.blockUntil.connected
        operation.stop {
            acceptor.stop()
        }

        then:
        operation.stop.end > instant.actionFinished

        cleanup:
        acceptor?.requestStop()
    }

    @Unroll
    def "can receive message from peer after peer has closed connection using #serializerName"() {
        // This is a test to simulate the messaging that the daemon does on build completion, in order to validate some assumptions

        when:
        def acceptor = incomingConnector.accept({ ConnectCompletion event ->
            def connection = event.create(messageSerializer)
            connection.dispatch("bye")
            connection.stop()
            instant.closed
        } as Action, false)

        def connection = outgoingConnector.connect(acceptor.address).create(messageSerializer)
        thread.blockUntil.closed

        then:
        connection.receive() == "bye"
        connection.receive() == null

        cleanup:
        connection?.stop()
        acceptor?.stop()

        where:
        messageSerializer | serializerName
        new DefaultMessageSerializer<String>(getClass().getClassLoader())                                      | "java"
        new KryoBackedMessageSerializer<String>(Serializers.stateful(BaseSerializerFactory.STRING_SERIALIZER)) | "kryo"
    }
}

{'fraction_non_alphanumeric': 0.08432458856118624, 'fraction_numerical': 0.004236597686165879, 'mean_word_length': 2.63273157738976, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5837242', 'n_tokens_mistral': 3108, 'n_tokens_neox': 3003, 'n_words': 886}