package com.sonymusic

import com.lesfurets.jenkins.unit.BasePipelineTest
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

import static org.junit.jupiter.api.Assertions.*

class WithSecretsTest extends BasePipelineTest {
    def withSecrets

    @BeforeEach
    void setUp() {
        super.setUp()
        withSecrets = loadScript("vars/withSecrets.groovy")
        helper.registerAllowedMethod('maskPasswords', [Map, Closure])
        helper.registerAllowedMethod('withAWS', [Map, Closure])
    }

    @Test
    void testCallWithNoSecrets() {
        assertThrows(AssertionError.class, {
            withSecrets.call([:], {})
        })
    }

    @Test
    void testCallWithSecretsNotAList() {
        assertThrows(AssertionError.class, {
            withSecrets.call(secrets: 'bad', {})
        })
    }

    @Test
    void testCallWithSecretsMissingId() {
        assertThrows(AssertionError.class, {
            withSecrets.call(secrets: [
                [environmentVariable: 'test']
            ], {})
        })
    }

    @Test
    void testCallWithSecretsMissingEnvironmentVariable() {
        assertThrows(AssertionError.class, {
            withSecrets.call(secrets: [
                [id: 'test']
            ], {})
        })
    }

    @Test
    void testCallWithAwsAccountIdButNoRole() {
        assertThrows(AssertionError.class, {
            withSecrets.call(awsAccountId: '123456789012', secrets: [
                [id: 'test', environmentVariable: 'TEST']
            ], {})
        })
    }

    @Test
    void testCallWithAwsRoleButNoAccountId() {
        assertThrows(AssertionError.class, {
            withSecrets.call(awsRole: 'test-role', secrets: [
                [id: 'test', environmentVariable: 'TEST']
            ], {})
        })
    }

    @Test
    void testCallSuccessWithNoRole() {
        // GIVEN
        helper.registerAllowedMethod('sh', [Map], { args ->
            return args.script.contains("--secret-id secret-1") ? 'VALUE1' : 'VALUE2'
        })
        def closureCalled = false

        // WHEN
        withSecrets(
            secrets: [
                [id: 'secret-1', environmentVariable: 'SECRET1'],
                [id: 'secret-2', environmentVariable: 'SECRET2']
            ],
        ) {
            closureCalled = true
        }

        // THEN

        // The provided closure was called
        assertTrue(closureCalled)

        // Secret values were set as environment variables
        def withEnvCall = helper.callStack.find { it.methodName == 'withEnv' }
        assertNotNull(withEnvCall)
        def expectedWithEnvArgs = ['SECRET1=VALUE1', 'SECRET2=VALUE2']
        assertEquals(expectedWithEnvArgs, withEnvCall.args[0].collect { it as String })

        // Secret values were masked
        def maskPasswordsCall = helper.callStack.find { it.methodName == 'maskPasswords' }
        assertNotNull(maskPasswordsCall)
        def expectedMaskPasswordArgs = [
            varPasswordPairs: [
                [password: 'VALUE1'],
                [password: 'VALUE2']
            ]
        ]
        assertEquals(expectedMaskPasswordArgs, maskPasswordsCall.args[0])

        // Role was NOT assumed
        assertNull(helper.callStack.find { it.methodName == 'withAWS' })
    }

    @Test
    void testCallWithAssumeRole() {
        // GIVEN
        binding.setVariable('env', [BUILD_TAG: 'build-tag'])
        helper.registerAllowedMethod('sh', [Map], { args ->
            return args.script.contains("--secret-id secret-1") ? 'VALUE1' : 'VALUE2'
        })
        def closureCalled = false

        // WHEN
        withSecrets(awsAccountId: '123456789012', awsRole: 'test-role',
            secrets: [
                [id: 'secret-1', environmentVariable: 'SECRET1'],
                [id: 'secret-2', environmentVariable: 'SECRET2']
            ],
        ) {
            closureCalled = true
        }

        // THEN

        // The provided closure was called
        assertTrue(closureCalled)

        // Secret values were set as environment variables
        def withEnvCall = helper.callStack.find { it.methodName == 'withEnv' }
        assertNotNull(withEnvCall)
        def expectedWithEnvArgs = ['SECRET1=VALUE1', 'SECRET2=VALUE2']
        assertEquals(expectedWithEnvArgs, withEnvCall.args[0].collect { it as String })

        // Secret values were masked
        def maskPasswordsCall = helper.callStack.find { it.methodName == 'maskPasswords' }
        assertNotNull(maskPasswordsCall)
        def expectedMaskPasswordArgs = [
            varPasswordPairs: [
                [password: 'VALUE1'],
                [password: 'VALUE2']
            ]
        ]
        assertEquals(expectedMaskPasswordArgs, maskPasswordsCall.args[0])

        // Role was assumed
        def withAWSCall = helper.callStack.find { it.methodName == 'withAWS' }
        assertNotNull(withAWSCall)
        assertEquals([
            roleAccount: '123456789012',
            role: 'test-role',
            roleSessionName: 'build-tag',
            useNode: true
        ], withAWSCall.args[0])
    }
}
