@if_docker_configured
    def test_links(self):
        expected_variables = frozenset({
            'ALIAS_PORT_80_TCP': 'tcp://localhost:8080',
            'ALIAS_PORT_80_TCP_PROTO': 'tcp',
            'ALIAS_PORT_80_TCP_ADDR': 'localhost',
            'ALIAS_PORT_80_TCP_PORT': '8080',
        }.items())

        volume_service = create_volume_service(self)

        docker_dir = FilePath(__file__).sibling('env-docker')
        image = DockerImageBuilder(test=self, source_dir=docker_dir)
        d = image.build()

        def image_built(image_name):
            application_name = random_name(self)

            docker_client = DockerClient()
            self.addCleanup(docker_client.remove, application_name)

            deployer = P2PNodeDeployer(
                u"localhost", volume_service, docker_client,
                make_memory_network(), node_uuid=uuid4())

            link = Link(alias=u"alias",
                        local_port=80,
                        remote_port=8080)

            dataset = Dataset(
                dataset_id=unicode(uuid4()),
                metadata=pmap({"name": application_name}))
            manifestation = Manifestation(dataset=dataset, primary=True)
            desired_state = Deployment(nodes=frozenset([
                Node(uuid=deployer.node_uuid,
                     applications=frozenset([Application(
                         name=application_name,
                         image=DockerImage.from_string(
                             image_name),
                         links=frozenset([link]),
                         volume=AttachedVolume(
                             manifestation=manifestation,
                             mountpoint=FilePath('/data'),
                         ),
                     )]),
                     manifestations={
                         manifestation.dataset_id: manifestation})]))

            return change_node_state(deployer, desired_state)

        d.addCallback(image_built)
        d.addCallback(lambda _: volume_service.enumerate())
        d.addCallback(lambda volumes:
                      list(volumes)[0].get_filesystem().get_path().child(
                          b'env'))

        def got_result_path(result_path):
            d = loop_until(reactor, result_path.exists)
            d.addCallback(lambda _: result_path)
            return d
        d.addCallback(got_result_path)

        def started(result_path):
            contents = result_path.getContent()

            assertContainsAll(
                haystack=contents,
                test_case=self,
                needles=['{}={}\n'.format(k, v)
                         for k, v in expected_variables])
        d.addCallback(started)
        return d
The links specified in an ``Application`` are passed to the
dataset/ETHPy150Open ClusterHQ/flocker/flocker/node/functional/test_deploy.py/DeployerTests.test_links