package nextflow.k8s

import nextflow.k8s.client.K8sClient
import nextflow.k8s.model.PodSpecBuilder
import spock.lang.Specification

class K8sNodeInitDeployerTest extends Specification {

    def setup() {
        PodSpecBuilder.VOLUMES.set(0)
    }

    def 'should not deploy pods when node init is disabled' () {
        given:
        def client = Mock(K8sClient)
        def config = new K8sConfig(nodeInit: [enabled: false])
        def deployer = new K8sNodeInitDeployer(client, config, 'run-foo')

        when:
        deployer.deploy()

        then:
        0 * client.nodeList()
        0 * client.podCreate(_)
    }

    def 'should deploy one init pod for each node' () {
        given:
        def client = Mock(K8sClient)
        def config = new K8sConfig(nodeInit: [
            enabled: true,
            image: 'ubuntu:latest',
            command: ['/bin/bash', '-c', 'echo init']
        ])
        def deployer = new K8sNodeInitDeployer(client, config, 'run-foo')

        when:
        deployer.deploy()

        then:
        1 * client.nodeList() >> [
            items: [
                [metadata: [name: 'node-a']],
                [metadata: [name: 'node-b']]
            ]
        ]

        then:
        1 * client.podCreate({ Map spec ->
            spec.kind == 'Pod'
            spec.metadata.name == 'nf-init-run-foo-node-a'
            spec.metadata.namespace == 'default'
            spec.spec.nodeName == 'node-a'
            spec.spec.restartPolicy == 'Never'

            def container = spec.spec.containers[0]
            container.name == 'nf-init-run-foo-node-a'
            container.image == 'ubuntu:latest'
            container.command == ['/bin/bash', '-c', 'echo init']
            container.securityContext.privileged == true

            spec.spec.volumes*.hostPath*.path as Set == ['/sys', '/dev', '/lib/modules'] as Set
            container.volumeMounts*.mountPath as Set == ['/sys', '/dev', '/lib/modules'] as Set
        })

        then:
        1 * client.podCreate({ Map spec ->
            spec.kind == 'Pod'
            spec.metadata.name == 'nf-init-run-foo-node-b'
            spec.spec.nodeName == 'node-b'

            def container = spec.spec.containers[0]
            container.name == 'nf-init-run-foo-node-b'
            container.image == 'ubuntu:latest'
            container.command == ['/bin/bash', '-c', 'echo init']
            container.securityContext.privileged == true
        })

        0 * client._
    }

    def 'should lowercase and truncate generated pod names' () {
        given:
        def client = Mock(K8sClient)
        def runName = 'run-name-with-a-very-long-identifier'
        def config = new K8sConfig(nodeInit: [
            enabled: true,
            image: 'ubuntu:latest',
            command: ['true']
        ])
        def deployer = new K8sNodeInitDeployer(client, config, runName)

        when:
        deployer.deploy()

        then:
        1 * client.nodeList() >> [
            items: [
                [metadata: [name: 'NODE-WITH-A-VERY-LONG-NAME-ABCDEFGHIJKLMNOPQRSTUVWXYZ']]
            ]
        ]

        then:
        1 * client.podCreate({ Map spec ->
            spec.metadata.name == 'nf-init-run-name-with-a-very-long-identifier-node-with-a-very-l'
            spec.metadata.name.size() == 63
            spec.metadata.name == spec.metadata.name.toLowerCase()
            spec.spec.nodeName == 'NODE-WITH-A-VERY-LONG-NAME-ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        })

        then:
        0 * client._
    }

    def 'should not cleanup pods when node init is disabled' () {
        given:
        def client = Mock(K8sClient)
        def config = new K8sConfig(nodeInit: [enabled: false, cleanup: true])
        def deployer = new K8sNodeInitDeployer(client, config, 'run-foo')

        when:
        deployer.cleanup()

        then:
        0 * client.nodeList()
        0 * client.podDelete(_)
    }

    def 'should not cleanup pods when cleanup is disabled' () {
        given:
        def client = Mock(K8sClient)
        def config = new K8sConfig(nodeInit: [enabled: true, cleanup: false])
        def deployer = new K8sNodeInitDeployer(client, config, 'run-foo')

        when:
        deployer.cleanup()

        then:
        0 * client.nodeList()
        0 * client.podDelete(_)
    }

    def 'should cleanup one init pod for each node' () {
        given:
        def client = Mock(K8sClient)
        def config = new K8sConfig(nodeInit: [enabled: true, cleanup: true])
        def deployer = new K8sNodeInitDeployer(client, config, 'run-foo')

        when:
        deployer.cleanup()

        then:
        1 * client.nodeList() >> [
            items: [
                [metadata: [name: 'node-a']],
                [metadata: [name: 'NODE-B']]
            ]
        ]

        then:
        1 * client.podDelete('nf-init-run-foo-node-a')
        1 * client.podDelete('nf-init-run-foo-node-b')
        0 * client._
    }
}
