text:
============================================================
Detection of user-initiated shutdown from inside an instance
============================================================

.. contents:: :depth: 2

This is a design document detailing the implementation of a way for Ganeti to
detect whether a machine marked as up but not running was shutdown gracefully
by the user from inside the machine itself.

Current state and shortcomings
==============================

Ganeti keeps track of the desired status of instances in order to be able to
take proper actions (e.g.: reboot) on the ones that happen to crash.
Currently, the only way to properly shut down a machine is through Ganeti's own
commands, that will mark an instance as ``ADMIN_down``.
If a user shuts down an instance from inside, through the proper command of the
operating system it is running, the instance will be shutdown gracefully, but
Ganeti is not aware of that: the desired status of the instance will still be
marked as ``running``, so when the watcher realises that the instance is down,
it will restart it. This behaviour is usually not what the user expects.

Proposed changes
================

We propose to modify Ganeti in such a way that it will detect when an instance
was shutdown because of an explicit user request. When such a situation is
detected, instead of presenting an error as it happens now, either the state
of the instance will be set to ADMIN_down, or the instance will be
automatically rebooted, depending on a instance-specific configuration value.
The default behavior in case no such parameter is found will be to follow
the apparent will of the user, and setting to ADMIN_down an instance that
was shut down correctly from inside.

This design document applies to the Xen backend of Ganeti, because it uses
features specific of such hypervisor. Initial analysis suggests that a similar
approach might be used for KVM as well, so this design document will be later
extended to add more details about it.

Implementation
==============

Xen knows why a domain is being shut down (a crash or an explicit shutdown
or poweroff request), but such information is not usually readily available
externally, because all such cases lead to the virtual machine being destroyed
immediately after the event is detected.

Still, Xen allows the instance configuration file to define what action to be
taken in all those cases through the ``on_poweroff``, ``on_shutdown`` and
``on_crash`` variables. By setting them to ``preserve``, Xen will avoid
destroying the domains automatically.

When the domain is not destroyed, it can be viewed by using ``xm list`` (or ``xl
list`` in newer Xen versions), and the ``State`` field of the output will
provide useful information.

If the state is ``----c-`` it means the instance has crashed.

If the state is ``---s--`` it means the instance was properly shutdown.

If the instance was properly shutdown and it is still marked as ``running`` by
Ganeti, it means that it was shutdown from inside by the user, and the ganeti
status of the instance needs to be changed to ``ADMIN_down``.

This will be done at regular intervals by the group watcher, just before
deciding which instances to reboot.

On top of that, at the same times, the watcher will also need to issue ``xm
destroy`` commands for all the domains that are in crashed or shutdown state,
since this will not be done automatically by Xen anymore because of the
``preserve`` setting in their config files.

This behavior will be limited to the domains shut down from inside, because it
will actually keep the resources of the domain busy until the watcher will do
the cleaning job (that, with the default setting, is up to every 5 minutes).
Still, this is considered acceptable, because it is not frequent for a domain
to be shut down this way. The cleanup function will be also run
automatically just before performing any job that requires resources to be
available (such as when creating a new instance), in order to ensure that the
new resource allocation happens starting from a clean state. Functionalities
that only query the state of instances will not run the cleanup function.

The cleanup operation includes both node-specific operations (the actual
destruction of the stopped domains) and configuration changes, to be performed
on the master node (marking as offline an instance that was shut down
internally). The watcher, on the master node, will fetch the list of instances
that have been shutdown from inside (recognizable by their ``oper_state``
as described below). It will then submit a series of ``InstanceShutdown`` jobs
that will mark such instances as ``ADMIN_down`` and clean them up (after
the functionality of ``InstanceShutdown`` will have been extended as specified
in the rest of this design document).

LUs performing operations other than an explicit cleanup will have to be
modified to perform the cleanup as well, either by submitting a job to perform
the cleanup (to be completed before actually performing the task at hand) or by
explicitly performing the cleanup themselves through the RPC calls.

Other required changes
++++++++++++++++++++++

The implementation of this design document will require some commands to be
changed in order to cope with the new shutdown procedure.

With the default shutdown action in Xen set to ``preserve``, the Ganeti
command for shutting down instances would leave them in a shutdown but
preserved state. Therefore, it will have to be changed in such a way to
immediately perform the cleanup of the instance after verifying its correct
shutdown. Also, it will correctly deal with instances that have been shutdown
from inside but are still active according to Ganeti, by detecting this
situation, destroying the instance and carrying out the rest of the Ganeti
shutdown procedure as usual.

The ``gnt-instance list`` command will need to be able to handle the situation
where an instance was shutdown internally but not yet cleaned up.
The ``admin_state`` field will maintain the current meaning unchanged. The
``oper_state`` field will get a new possible state, ``S``, meaning that the
instance was shutdown internally.

The ``gnt-instance info`` command ``State`` field, in such case, will show a
message stating that the instance was supposed to be run but was shut down
internally.

.. vim: set textwidth=72 :
.. Local Variables:
.. mode: rst
.. fill-column: 72
.. End:


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>
类 com.baidu.mapapi.search.MKPoiInfo 的使用
</TITLE>

<META NAME="date" CONTENT="2013-11-25">

<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">

      概述
      软件包
      类
    使用
      树
      已过时
      索引
      帮助

 上一个
 下一个

  框架
 无框架

  所有类

类 com.baidu.mapapi.search.MKPoiInfo
的使用

使用 MKPoiInfo 的软件包

com.baidu.mapapi.map
地图操作方法,覆盖物相关方法

com.baidu.mapapi.search
信息查询类和搜索结果通知接口

com.baidu.mapapi.map 中 MKPoiInfo 的使用

返回 MKPoiInfo 的 com.baidu.mapapi.map 中的方法

 MKPoiInfo
PoiOverlay.getPoi(int index)

类型变量类型为 MKPoiInfo 的 com.baidu.mapapi.map 中的方法参数

 void
PoiOverlay.setData(java.util.ArrayList<MKPoiInfo> data)

          设置poi 数据

com.baidu.mapapi.search 中 MKPoiInfo 的使用

类型参数类型为 MKPoiInfo 的 com.baidu.mapapi.search 中的字段

 java.util.ArrayList<MKPoiInfo>
MKRouteAddrResult.mEndPoiList

          终点地址选择列表,当途经点有歧义时填充。

 java.util.ArrayList<MKPoiInfo>
MKRouteAddrResult.mStartPoiList

          起点地址选择列表,当途经点有歧义时填充。

 java.util.ArrayList<java.util.ArrayList<MKPoiInfo>>
MKRouteAddrResult.mWpPoiList

          途经点地址选择列表,当途经点有歧义时填充。

 java.util.ArrayList<MKPoiInfo>
MKAddrInfo.poiList

          地址周边Poi信息,只有在type为MK_REVERSEGEOCODE时才有效

返回 MKPoiInfo 的 com.baidu.mapapi.search 中的方法

 MKPoiInfo
MKLine.getGetOffStop()

          获取下车的站点

 MKPoiInfo
MKLine.getGetOnStop()

          获取上车的站点

 MKPoiInfo
MKPoiResult.getPoi(int index)

          获取第index个poi信息

返回变量类型为 MKPoiInfo 的类型的 com.baidu.mapapi.search 中的方法

 java.util.ArrayList<MKPoiInfo>
MKPoiResult.getAllPoi()

      概述
      软件包
      类
    使用
      树
      已过时
      索引
      帮助

 上一个
 下一个

  框架
 无框架

  所有类

redpajama_set_name: RedPajamaGithub


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>PlausibleInstruments: Source/PLInstrument.h Source File</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">

Main Page

Modules

Classes

Files

Source/PLInstrument.h

00001
00027
00028 #import "PLInstrumentTime.h"
00029 #import "PLInstrumentResult.h"
00030 #import "PLInstrumentCase.h"
00031
00032 #import "PLInstrumentResultHandler.h"
00033 #import "PLInstrumentRunner.h"
00034
00035 #import "PLInstrumentConsoleResultHandler.h"
00036

<address style="text-align: right;">Generated on Wed Dec 31 18:55:32 2008 for PlausibleInstruments by

 1.5.5 </address>


text:
package alluxio.job.move;

import com.google.common.base.Objects;

import java.io.Serializable;

/**
 * A command telling a worker to move a file.
 */
public final class MoveCommand implements Serializable {
  private static final long serialVersionUID = -4287491133291080690L;

  private final String mSource;
  private final String mDestination;

  /**
   * @param source the source file to move
   * @param destination the destination file to move it to
   */
  public MoveCommand(String source, String destination) {
    mSource = source;
    mDestination = destination;
  }

  /**
   * @return the source
   */
  public String getSource() {
    return mSource;
  }

  /**
   * @return the destination
   */
  public String getDestination() {
    return mDestination;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof MoveCommand)) {
      return false;
    }
    MoveCommand that = (MoveCommand) o;
    return Objects.equal(mSource, that.mSource)
        && Objects.equal(mDestination, that.mDestination);
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(mSource, mDestination);
  }

  @Override
  public String toString() {
    return Objects.toStringHelper(this)
        .add("source", mSource)
        .add("destination", mDestination)
        .toString();
  }
}


text:
  Moirey-Flabas-Crépion est
       un village
       localisé dans le département de Meuse en Lorraine. On dénombrait 131 habitants en 2008.

Si vous pensez emmenager à Moirey-Flabas-Crépion, vous pourrez aisément trouver une maison à acheter.

Le nombre d'habitations, à Moirey-Flabas-Crépion, se décomposait en 2011 en deux appartements et 57 maisons soit
 un marché plutôt équilibré.

À proximité de Moirey-Flabas-Crépion sont localisées les villes de
Wavrille localisée à 2 km, 46 habitants,
Azannes-et-Soumazannes à 5 km, 174 habitants,
Romagne-sous-les-Côtes à 5 km, 111 habitants,
Étraye située à 3 km, 56 habitants,
Damvillers située à 3 km, 653 habitants,
Chaumont-devant-Damvillers localisée à 1 km, 39 habitants,
 entre autres. De plus, Moirey-Flabas-Crépion est située à seulement 16 km de Verdun.


text:
<?php

namespace Budget\Repository;

use Doctrine\ORM\Tools\Pagination\Paginator;

class UserRepository extends AbstractRepository
{
    public function findBy(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null)
	{

		$order_property = (isset($orderBy['property'])) ? 'main.'.$orderBy['property'] : 'main.id';
		$order_direction = (isset($orderBy['direction']) && $orderBy['direction'] == 'DESC') ? 'DESC' : 'ASC';

		$qb = $this->_em->createQueryBuilder();
		$qb	->select('main, c')
			->from('Budget\Entity\User', 'main')
			->leftJoin('main.companies', 'c')
//			->where($this->_getWherePart($criteria))
			->orderBy($order_property, $order_direction)
			->setFirstResult($offset)
			->setMaxResults($limit);

		$this->_setWherePart($criteria, $qb);

		$query = $qb->getQuery();

		$paginator = new Paginator($query, $fetchJoinCollection = true);

		return array(
			'result' => $paginator,
			'total' => $paginator->count()
		);
	}
}


text:
(function (window) {
  'use strict';

  function Controller(model, view) {
    var self = this;

    self.model = model;
    self.view = view;

    self.view.bind('add', function (name) {
      self.add(name);
    });

    self.view.bind('remove', function (id) {
      self.remove(id);
    });

    self.view.bind('clear', function () {
      self.clear();
    });

    self.view.bind('churn', function () {
      self.churn();
    });
  }

  Controller.prototype.add = function (name) {
    var trimmedName = name.trim();

    if (trimmedName) {
      var id = this.model.create(name);
      this.view.add(id, name);
    }
  }

  Controller.prototype.remove = function (id) {
    this.model.remove(id);
    this.view.remove(id);
  }

  Controller.prototype.clear = function () {
    this.model.removeAll();
    this.view.clear();
  }

  Controller.prototype.churn = function () {
    var randomVictim = this.model.getRandom();
    this.view.displayChoice(randomVictim);
    this.clear();
  }

  window.app = window.app || {};
  window.app.Controller = Controller;
})(window);


text:
<?php

namespace Phalcon\Test\Annotations\Adapter;

use UnitTester;
use ReflectionMethod;
use ReflectionProperty;
use Codeception\TestCase\Test;
use Phalcon\Annotations\Adapter\Aerospike;
use Phalcon\Cache\Backend\Aerospike as CacheBackend;

class AerospikeTest extends Test
{
    /**
     * UnitTester Object
     * @var UnitTester
     */
    protected $tester;

    /**
     * executed before each test
     */
    protected function _before()
    {
        if (!extension_loaded('aerospike')) {
            $this->markTestSkipped('The Aerospike module is not available.');
        }
    }

    public function testHasAerospikeProperty()
    {
        $this->assertClassHasAttribute('aerospike', Aerospike::class);
    }

    public function testHasNamespaceProperty()
    {
        $this->assertClassHasAttribute('namespace', Aerospike::class);
    }

    public function testHasSetProperty()
    {
        $this->assertClassHasAttribute('set', Aerospike::class);
    }

    /**
     * @dataProvider providerReadWrite
     * @param string $key
     * @param mixed $data
     */
    public function testShouldReadAndWriteToAerospikeWithoutPrefix($key, $data)
    {
        $object = new Aerospike(['hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]]]);
        $object->write($key, $data);

        $this->assertEquals($data, $object->read($key));
    }

    /**
     * @dataProvider providerReadWrite
     * @param string $key
     * @param mixed $data
     */
    public function testShouldReadAndWriteToAerospikeWithPrefix($key, $data)
    {
        $object = new Aerospike(['hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]], 'prefix' => 'test_']);
        $object->write($key, $data);

        $this->assertEquals($data, $object->read($key));
    }

    public function testShouldGetCacheBackendThroughGetter()
    {
        $object = new Aerospike(['hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]]]);

        $reflectedMethod = new ReflectionMethod(get_class($object), 'getCacheBackend');
        $reflectedMethod->setAccessible(true);
        $this->assertInstanceOf(CacheBackend::class, $reflectedMethod->invoke($object));
    }

    public function testShouldGetCacheBackendThroughReflectionSetter()
    {
        $object = new Aerospike(['hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]]]);
        $mock = $this->getMock(CacheBackend::class, [], [], '', false);

        $reflectedProperty = new ReflectionProperty(get_class($object), 'aerospike');
        $reflectedProperty->setAccessible(true);
        $reflectedProperty->setValue($object, $mock);

        $reflectedMethod = new ReflectionMethod(get_class($object), 'getCacheBackend');
        $reflectedMethod->setAccessible(true);
        $this->assertInstanceOf(CacheBackend::class, $reflectedMethod->invoke($object));
    }

    /**
     * @dataProvider providerKey
     * @param mixed $key
     */
    public function testShouldPrepareKey($key)
    {
        $object = new Aerospike(['hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]]]);
        $reflectedMethod = new ReflectionMethod(get_class($object), 'prepareKey');
        $reflectedMethod->setAccessible(true);

        $this->assertEquals($key, $reflectedMethod->invoke($object, $key));
    }

    /**
     * @dataProvider providerConstructor
     * @param array $options
     * @param array $expected
     */
    public function testShouldCreateRedisAdapterInstanceAndSetOptions($options, $expected)
    {
        $object = new Aerospike($options);
        $reflectedProperty = new ReflectionProperty(get_class($object), 'options');
        $reflectedProperty->setAccessible(true);

        $this->assertEquals($expected, $reflectedProperty->getValue($object));
    }

    /**
     * @dataProvider providerInvalidConstructor
     * @param array $options
     * @param string  $exceptionName
     * @param string $exceptionMessage
     */
    public function testShouldCatchExceptionWhenInvalidParamsPassed($options, $exceptionName, $exceptionMessage)
    {
        $this->setExpectedException($exceptionName, $exceptionMessage);

        new Aerospike($options);
    }

    public function providerReadWrite()
    {
        // This key is needed in order not to break your real data
        $key = hash('sha256', json_encode([__CLASS__, __METHOD__, __FILE__, __LINE__]));

        return [
            'string' => [$key . '_test1', 'data1'],
            'object' => [$key . '_test1', (object) ['key' => 'value']],
            'array'  => [$key . '_test1', ['key' => 'value']],
            'null'   => [$key . '_test1', null],
            'int'    => [$key . '_test1', 9223372036854775807],
            'float'  => [$key . '_test1', 3.14],
            'class'  => [$key . '_test1', new \stdClass()],
        ];
    }

    public function providerKey()
    {
        return [
            ['key1'],
            [1],
            ['_key1']
        ];
    }

    public function providerInvalidConstructor()
    {
        return [
            [
                [],
                'Phalcon\Annotations\Exception',
                'No hosts given in options'
            ],
            [
                ['hosts' => null],
                'Phalcon\Annotations\Exception',
                'No hosts given in options'
            ],
            [
                ['hosts' => []],
                'Phalcon\Annotations\Exception',
                'No hosts given in options'
            ],
            [
                ['hosts' => [[]]],
                'Phalcon\Cache\Exception',
                'Aerospike failed to connect [-2]: Unable to find host parameter'
            ]
        ];
    }

    public function providerConstructor()
    {
        return [
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 23
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 23,
                    'prefix' => '',
                    'persistent' => false,
                    'options' => []
                ]
            ],
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 23,
                    'options' => [
                        1 => 1250,
                        3  => 1500
                    ]
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 23,
                    'prefix' => '',
                    'persistent' => false,
                    'options' => [
                        1 => 1250,
                        3 => 1500
                    ]
                ]
            ],
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 23,
                    'persistent' => true
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 23,
                    'prefix' => '',
                    'persistent' => true,
                    'options' => [],
                ]
            ],
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'prefix' => 'test_'
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 8600,
                    'prefix' => 'test_',
                    'persistent' => false,
                    'options' => [],
                ]
            ],
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'randomValue' => 'test_'
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'randomValue' => 'test_',
                    'lifetime' => 8600,
                    'prefix' => '',
                    'persistent' => false,
                    'options' => [],
                ]
            ],
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    123 => 'test_'
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    123 => 'test_',
                    'lifetime' => 8600,
                    'prefix' => '',
                    'persistent' => false,
                    'options' => [],
                ]
            ],
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 24,
                    'prefix' => 'test_',
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 24,
                    'prefix' => 'test_',
                    'persistent' => false,
                    'options' => [],
                ]
            ],
            [
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                ],
                [
                    'hosts' => [['addr' => TEST_AS_HOST, 'port' => TEST_AS_PORT]],
                    'lifetime' => 8600,
                    'prefix' => '',
                    'persistent' => false,
                    'options' => [],
                ]
            ],

        ];
    }
}


text:
package kornell.core.entity;

import java.util.Date;

public interface EnrollmentProgress {
    Integer getProgress();
    void setProgress(Integer progress);

    EnrollmentProgressDescription getDescription();
    void setDescription(EnrollmentProgressDescription description);

    Date getCertifiedAt();
    void setCertifiedAt(Date certifiedAt);
}


text:
#include "LedDeviceWS281x.h"
#include <utils/SysInfo.h>

// Constants
namespace {
const bool verbose = false;
} //End of constants

LedDeviceWS281x::LedDeviceWS281x(const QJsonObject &deviceConfig)
	: LedDevice(deviceConfig)
{
}

LedDeviceWS281x::~LedDeviceWS281x()
{
}

LedDevice* LedDeviceWS281x::construct(const QJsonObject &deviceConfig)
{
	return new LedDeviceWS281x(deviceConfig);
}

bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
{
	QString errortext;

	bool isInitOK = false;

	// Initialise sub-class
	if ( LedDevice::init(deviceConfig) )
	{
		QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");

		_whiteAlgorithm	= RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
		if (_whiteAlgorithm == RGBW::WhiteAlgorithm::INVALID)
		{
			errortext = QString ("unknown whiteAlgorithm: %1").arg(whiteAlgorithm);
			isInitOK = false;
		}
		else
		{
			_channel = deviceConfig["pwmchannel"].toInt(0);
			if (_channel != 0 && _channel != 1)
			{
				errortext = "WS281x: invalid PWM channel; must be 0 or 1.";
				isInitOK = false;
			}
			else
			{
				memset(&_led_string, 0, sizeof(_led_string));
				_led_string.freq   = deviceConfig["freq"].toInt(800000UL);
				_led_string.dmanum = deviceConfig["dma"].toInt(5);
				_led_string.channel[_channel].gpionum    = deviceConfig["gpio"].toInt(18);
				_led_string.channel[_channel].count      = deviceConfig["leds"].toInt(256);
				_led_string.channel[_channel].invert     = deviceConfig["invert"].toInt(0);
				_led_string.channel[_channel].strip_type = (deviceConfig["rgbw"].toBool(false) ? SK6812_STRIP_GRBW : WS2811_STRIP_RGB);
				_led_string.channel[_channel].brightness = 255;

				_led_string.channel[!_channel].gpionum = 0;
				_led_string.channel[!_channel].invert = _led_string.channel[_channel].invert;
				_led_string.channel[!_channel].count = 0;
				_led_string.channel[!_channel].brightness = 0;
				_led_string.channel[!_channel].strip_type = WS2811_STRIP_RGB;

				Debug( _log, "ws281x strip type : %d", _led_string.channel[_channel].strip_type );

				isInitOK = true;
			}
		}
	}

	if ( !isInitOK)
	{
		this->setInError(errortext);
	}
	return isInitOK;
}

int LedDeviceWS281x::open()
{
	int retval = -1;
	_isDeviceReady = false;

	if (!SysInfo::isUserAdmin())
	{
		QString errortext = QString ("Hyperion must run with \"root\" privileges for this device. Current user is: \"%1\"").arg(SysInfo::userName());
		this->setInError( errortext );
	}
	else
	{
		// Try to open the LedDevice
		ws2811_return_t rc = ws2811_init(&_led_string);
		if ( rc != WS2811_SUCCESS )
		{
			QString errortext = QString ("Failed to open. Error message: %1").arg( ws2811_get_return_t_str(rc) );
			this->setInError( errortext );
		}
		else
		{
			// Everything is OK, device is ready
			_isDeviceReady = true;
			retval = 0;
		}
	}
	return retval;
}

int LedDeviceWS281x::close()
{
	int retval = 0;
	_isDeviceReady = false;

	// LedDevice specific closing activities
	if ( isInitialised() )
	{
		ws2811_fini(&_led_string);
	}

	return retval;
}

// Send new values down the LED chain
int LedDeviceWS281x::write(const std::vector<ColorRgb> &ledValues)
{
	int idx = 0;
	for (const ColorRgb& color : ledValues)
	{
		if (idx >= _led_string.channel[_channel].count)
		{
			break;
		}

		_temp_rgbw.red = color.red;
		_temp_rgbw.green = color.green;
		_temp_rgbw.blue = color.blue;
		_temp_rgbw.white = 0;

		if (_led_string.channel[_channel].strip_type == SK6812_STRIP_GRBW)
		{
			Rgb_to_Rgbw(color, &_temp_rgbw, _whiteAlgorithm);
		}

		_led_string.channel[_channel].leds[idx++] =
			((uint32_t)_temp_rgbw.white << 24) + ((uint32_t)_temp_rgbw.red << 16) + ((uint32_t)_temp_rgbw.green << 8) + _temp_rgbw.blue;

	}
	while (idx < _led_string.channel[_channel].count)
	{
		_led_string.channel[_channel].leds[idx++] = 0;
	}

	return ws2811_render(&_led_string) ? -1 : 0;
}

QJsonObject LedDeviceWS281x::discover(const QJsonObject& /*params*/)
{
	QJsonObject devicesDiscovered;
	devicesDiscovered.insert("ledDeviceType", _activeDeviceType);

	QJsonArray deviceList;

	if (SysInfo::isUserAdmin())
	{
		//Indicate the general availability of the device, if hyperion is run under root
		deviceList << QJsonObject ({{"found",true}});
		devicesDiscovered.insert("devices", deviceList);
	}

	DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());

	return devicesDiscovered;
}


text:
// Copyright 2018 Istio 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 v1alpha3

import (
	"fmt"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"

	xdsapi "github.com/envoyproxy/go-control-plane/envoy/api/v2"
	listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
	tcp_proxy "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/tcp_proxy/v2"
	"github.com/envoyproxy/go-control-plane/pkg/conversion"
	xdsutil "github.com/envoyproxy/go-control-plane/pkg/wellknown"
	"github.com/gogo/protobuf/types"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"

	networking "istio.io/api/networking/v1alpha3"

	"istio.io/istio/pilot/pkg/features"
	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pilot/pkg/networking/core/v1alpha3/fakes"
	"istio.io/istio/pilot/pkg/networking/plugin"
	"istio.io/istio/pilot/pkg/serviceregistry"
	"istio.io/istio/pkg/config/host"
	"istio.io/istio/pkg/config/labels"
	"istio.io/istio/pkg/config/mesh"
	"istio.io/istio/pkg/config/protocol"
	"istio.io/istio/pkg/config/schemas"
)

const (
	wildcardIP = "0.0.0.0"
)

var (
	tnow  = time.Now()
	tzero = time.Time{}
	proxy = model.Proxy{
		Type:        model.SidecarProxy,
		IPAddresses: []string{"1.1.1.1"},
		ID:          "v0.default",
		DNSDomain:   "default.example.org",
		Metadata: &model.NodeMetadata{
			ConfigNamespace: "not-default",
			IstioVersion:    "1.1",
		},
		IstioVersion:    &model.IstioVersion{Major: 1, Minor: 3},
		ConfigNamespace: "not-default",
	}
	proxyHTTP10 = model.Proxy{
		Type:        model.SidecarProxy,
		IPAddresses: []string{"1.1.1.1"},
		ID:          "v0.default",
		DNSDomain:   "default.example.org",
		Metadata: &model.NodeMetadata{
			ConfigNamespace: "not-default",
			IstioVersion:    "1.1",
			HTTP10:          "1",
		},
		ConfigNamespace: "not-default",
	}
	proxy13 = model.Proxy{
		Type:        model.SidecarProxy,
		IPAddresses: []string{"1.1.1.1"},
		ID:          "v0.default",
		DNSDomain:   "default.example.org",
		Metadata: &model.NodeMetadata{
			ConfigNamespace: "not-default",
			IstioVersion:    "1.3",
		},
		ConfigNamespace: "not-default",
	}
	proxy13HTTP10 = model.Proxy{
		Type:        model.SidecarProxy,
		IPAddresses: []string{"1.1.1.1"},
		ID:          "v0.default",
		DNSDomain:   "default.example.org",
		Metadata: &model.NodeMetadata{
			ConfigNamespace: "not-default",
			IstioVersion:    "1.3",
			HTTP10:          "1",
		},
		IstioVersion:    &model.IstioVersion{Major: 1, Minor: 3},
		ConfigNamespace: "not-default",
	}
	proxy13Gateway = model.Proxy{
		Type:        model.Router,
		IPAddresses: []string{"1.1.1.1"},
		ID:          "v0.default",
		DNSDomain:   "default.example.org",
		Metadata: &model.NodeMetadata{
			ConfigNamespace: "not-default",
			IstioVersion:    "1.3",
		},
		ConfigNamespace: "not-default",
		WorkloadLabels:  labels.Collection{{"istio": "ingressgateway"}},
	}
	proxyInstances = []*model.ServiceInstance{
		{
			Service: &model.Service{
				Hostname:     "v0.default.example.org",
				Address:      "9.9.9.9",
				CreationTime: tnow,
				Attributes: model.ServiceAttributes{
					Namespace: "not-default",
				},
			},
			Labels: nil,
		},
	}
	virtualServiceSpec = &networking.VirtualService{
		Hosts:    []string{"test.com"},
		Gateways: []string{"mesh"},
		Tcp: []*networking.TCPRoute{
			{
				Match: []*networking.L4MatchAttributes{
					{
						DestinationSubnets: []string{"10.10.0.0/24"},
						Port:               8080,
					},
				},
				Route: []*networking.RouteDestination{
					{
						Destination: &networking.Destination{
							Host: "test.org",
							Port: &networking.PortSelector{
								Number: 80,
							},
						},
						Weight: 100,
					},
				},
			},
		},
	}
)

func TestInboundListenerConfigProxyV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForInbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForInbound.Name) }()

	for _, p := range []*model.Proxy{&proxy13, &proxy13HTTP10} {
		testInboundListenerConfigV13(t, p,
			buildService("test1.com", wildcardIP, protocol.HTTP, tnow.Add(1*time.Second)),
			buildService("test2.com", wildcardIP, "unknown", tnow),
			buildService("test3.com", wildcardIP, protocol.HTTP, tnow.Add(2*time.Second)))
		testInboundListenerConfigWithoutServiceV13(t, p)
		testInboundListenerConfigWithSidecarV13(t, p,
			buildService("test.com", wildcardIP, protocol.HTTP, tnow))
		testInboundListenerConfigWithSidecarWithoutServicesV13(t, p)
	}
}

func TestOutboundListenerConflict_HTTPWithCurrentUnknownV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForOutbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForOutbound.Name) }()

	// The oldest service port is unknown.  We should encounter conflicts when attempting to add the HTTP ports. Purposely
	// storing the services out of time order to test that it's being sorted properly.
	testOutboundListenerConflictV13(t,
		buildService("test1.com", wildcardIP, protocol.HTTP, tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, "unknown", tnow),
		buildService("test3.com", wildcardIP, protocol.HTTP, tnow.Add(2*time.Second)))
}

func TestOutboundListenerConflict_WellKnowPortsV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForOutbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForOutbound.Name) }()

	// The oldest service port is unknown.  We should encounter conflicts when attempting to add the HTTP ports. Purposely
	// storing the services out of time order to test that it's being sorted properly.
	testOutboundListenerConflictV13(t,
		buildServiceWithPort("test1.com", 3306, protocol.HTTP, tnow.Add(1*time.Second)),
		buildServiceWithPort("test2.com", 3306, protocol.MySQL, tnow))
	testOutboundListenerConflictV13(t,
		buildServiceWithPort("test1.com", 9999, protocol.HTTP, tnow.Add(1*time.Second)),
		buildServiceWithPort("test2.com", 9999, protocol.MySQL, tnow))
}

func TestOutboundListenerConflict_TCPWithCurrentUnknownV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForOutbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForOutbound.Name) }()

	// The oldest service port is unknown.  We should encounter conflicts when attempting to add the HTTP ports. Purposely
	// storing the services out of time order to test that it's being sorted properly.
	testOutboundListenerConflictV13(t,
		buildService("test1.com", wildcardIP, protocol.TCP, tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, "unknown", tnow),
		buildService("test3.com", wildcardIP, protocol.TCP, tnow.Add(2*time.Second)))
}

func TestOutboundListenerConflict_UnknownWithCurrentTCPV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForOutbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForOutbound.Name) }()

	// The oldest service port is TCP.  We should encounter conflicts when attempting to add the HTTP ports. Purposely
	// storing the services out of time order to test that it's being sorted properly.
	testOutboundListenerConflictV13(t,
		buildService("test1.com", wildcardIP, "unknown", tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, protocol.TCP, tnow),
		buildService("test3.com", wildcardIP, "unknown", tnow.Add(2*time.Second)))
}

func TestOutboundListenerConflict_UnknownWithCurrentHTTPV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForOutbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForOutbound.Name) }()

	// The oldest service port is TCP.  We should encounter conflicts when attempting to add the HTTP ports. Purposely
	// storing the services out of time order to test that it's being sorted properly.
	testOutboundListenerConflictV13(t,
		buildService("test1.com", wildcardIP, "unknown", tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, protocol.HTTP, tnow),
		buildService("test3.com", wildcardIP, "unknown", tnow.Add(2*time.Second)))
}

func TestOutboundListenerRouteV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForOutbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForOutbound.Name) }()

	testOutboundListenerRouteV13(t,
		buildService("test1.com", "1.2.3.4", "unknown", tnow.Add(1*time.Second)),
		buildService("test2.com", "2.3.4.5", protocol.HTTP, tnow),
		buildService("test3.com", "3.4.5.6", "unknown", tnow.Add(2*time.Second)))
}

func TestOutboundListenerConfig_WithSidecarV13(t *testing.T) {
	_ = os.Setenv(features.EnableProtocolSniffingForOutbound.Name, "true")
	defer func() { _ = os.Unsetenv(features.EnableProtocolSniffingForOutbound.Name) }()

	// Add a service and verify it's config
	services := []*model.Service{
		buildService("test1.com", wildcardIP, protocol.HTTP, tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, protocol.TCP, tnow),
		buildService("test3.com", wildcardIP, "unknown", tnow.Add(2*time.Second))}
	testOutboundListenerConfigWithSidecarV13(t, services...)
}

func TestOutboundListenerConflict_HTTPWithCurrentTCP(t *testing.T) {
	// The oldest service port is TCP.  We should encounter conflicts when attempting to add the HTTP ports. Purposely
	// storing the services out of time order to test that it's being sorted properly.
	testOutboundListenerConflict(t,
		buildService("test1.com", wildcardIP, protocol.HTTP, tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, protocol.TCP, tnow),
		buildService("test3.com", wildcardIP, protocol.HTTP, tnow.Add(2*time.Second)))
}

func TestOutboundListenerConflict_TCPWithCurrentHTTP(t *testing.T) {
	// The oldest service port is HTTP.  We should encounter conflicts when attempting to add the TCP ports. Purposely
	// storing the services out of time order to test that it's being sorted properly.
	testOutboundListenerConflict(t,
		buildService("test1.com", wildcardIP, protocol.TCP, tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, protocol.HTTP, tnow),
		buildService("test3.com", wildcardIP, protocol.TCP, tnow.Add(2*time.Second)))
}

func TestOutboundListenerConflict_Unordered(t *testing.T) {
	// Ensure that the order is preserved when all the times match. The first service in the list wins.
	testOutboundListenerConflict(t,
		buildService("test1.com", wildcardIP, protocol.HTTP, tzero),
		buildService("test2.com", wildcardIP, protocol.TCP, tzero),
		buildService("test3.com", wildcardIP, protocol.TCP, tzero))
}

func TestOutboundListenerConflict_HTTPoverHTTPS(t *testing.T) {
	cases := []struct {
		name             string
		service          *model.Service
		expectedListener []string
	}{
		{
			"http on 443",
			buildServiceWithPort("test1.com", CanonicalHTTPSPort, protocol.HTTP, tnow.Add(1*time.Second)),
			[]string{},
		},
		{
			"http on 80",
			buildServiceWithPort("test1.com", CanonicalHTTPSPort, protocol.HTTP, tnow.Add(1*time.Second)),
			[]string{},
		},
		{
			"https on 443",
			buildServiceWithPort("test1.com", CanonicalHTTPSPort, protocol.HTTPS, tnow.Add(1*time.Second)),
			[]string{"0.0.0.0_443"},
		},
		{
			"tcp on 443",
			buildServiceWithPort("test1.com", CanonicalHTTPSPort, protocol.TCP, tnow.Add(1*time.Second)),
			[]string{"0.0.0.0_443"},
		},
	}
	for _, tt := range cases {
		t.Run(tt.name, func(t *testing.T) {
			p := &fakePlugin{}
			listeners := buildOutboundListeners(p, &proxy, nil, nil, tt.service)
			got := []string{}
			for _, l := range listeners {
				got = append(got, l.Name)
			}
			if !reflect.DeepEqual(got, tt.expectedListener) {
				t.Fatalf("expected listener %v got %v", tt.expectedListener, got)
			}
		})
	}
}

func TestOutboundListenerConflict_TCPWithCurrentTCP(t *testing.T) {
	services := []*model.Service{
		buildService("test1.com", "1.2.3.4", protocol.TCP, tnow.Add(1*time.Second)),
		buildService("test2.com", "1.2.3.4", protocol.TCP, tnow),
		buildService("test3.com", "1.2.3.4", protocol.TCP, tnow.Add(2*time.Second)),
	}
	p := &fakePlugin{}
	listeners := buildOutboundListeners(p, &proxy, nil, nil, services...)
	if len(listeners) != 1 {
		t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
	}
	// The filter chains should all be merged into one.
	if len(listeners[0].FilterChains) != 1 {
		t.Fatalf("expected %d filter chains, found %d", 1, len(listeners[0].FilterChains))
	}
	verifyOutboundTCPListenerHostname(t, listeners[0], "test2.com")

	oldestService := getOldestService(services...)
	oldestProtocol := oldestService.Ports[0].Protocol
	if oldestProtocol != protocol.HTTP && isHTTPListener(listeners[0]) {
		t.Fatal("expected TCP listener, found HTTP")
	} else if oldestProtocol == protocol.HTTP && !isHTTPListener(listeners[0]) {
		t.Fatal("expected HTTP listener, found TCP")
	}

	if p.outboundListenerParams[0].Service != oldestService {
		t.Fatalf("listener conflict failed to preserve listener for the oldest service")
	}
}

func TestOutboundListenerTCPWithVS(t *testing.T) {
	_ = os.Setenv("PILOT_ENABLE_FALLTHROUGH_ROUTE", "false")

	defer func() { _ = os.Unsetenv("PILOT_ENABLE_FALLTHROUGH_ROUTE") }()

	tests := []struct {
		name           string
		CIDR           string
		expectedChains []string
	}{
		{
			name:           "same CIDR",
			CIDR:           "10.10.0.0/24",
			expectedChains: []string{"10.10.0.0"},
		},
		{
			name:           "different CIDR",
			CIDR:           "10.10.10.0/24",
			expectedChains: []string{"10.10.0.0", "10.10.10.0"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if features.RestrictPodIPTrafficLoops.Get() {
				// Expect a filter chain on the node IP
				tt.expectedChains = append([]string{"1.1.1.1"}, tt.expectedChains...)
			}
			services := []*model.Service{
				buildService("test.com", tt.CIDR, protocol.TCP, tnow),
			}

			p := &fakePlugin{}
			virtualService := model.Config{
				ConfigMeta: model.ConfigMeta{
					Type:      schemas.VirtualService.Type,
					Version:   schemas.VirtualService.Version,
					Name:      "test_vs",
					Namespace: "default",
				},
				Spec: virtualServiceSpec,
			}
			listeners := buildOutboundListeners(p, &proxy, nil, &virtualService, services...)

			if len(listeners) != 1 {
				t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
			}
			var chains []string
			for _, fc := range listeners[0].FilterChains {
				for _, cidr := range fc.FilterChainMatch.PrefixRanges {
					chains = append(chains, cidr.AddressPrefix)
				}
			}
			// There should not be multiple filter chains with same CIDR match
			if !reflect.DeepEqual(chains, tt.expectedChains) {
				t.Fatalf("expected filter chains %v, found %v", tt.expectedChains, chains)
			}
		})
	}
}

func TestOutboundListenerForHeadlessServices(t *testing.T) {
	_ = os.Setenv("PILOT_ENABLE_FALLTHROUGH_ROUTE", "false")

	defer func() { _ = os.Unsetenv("PILOT_ENABLE_FALLTHROUGH_ROUTE") }()

	svc := buildServiceWithPort("test.com", 9999, protocol.TCP, tnow)
	svc.Attributes.ServiceRegistry = string(serviceregistry.KubernetesRegistry)
	svc.Resolution = model.Passthrough
	services := []*model.Service{svc}

	p := &fakePlugin{}
	tests := []struct {
		name                      string
		instances                 []*model.ServiceInstance
		numListenersOnServicePort int
	}{
		{
			name: "gen a listener per instance",
			instances: []*model.ServiceInstance{
				// This instance is the proxy itself, will not gen a outbound listener for it.
				buildServiceInstance(services[0], "1.1.1.1"),
				buildServiceInstance(services[0], "10.10.10.10"),
				buildServiceInstance(services[0], "11.11.11.11"),
				buildServiceInstance(services[0], "12.11.11.11"),
			},
			numListenersOnServicePort: 3,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			configgen := NewConfigGenerator([]plugin.Plugin{p})

			env := buildListenerEnv(services)
			serviceDiscovery := new(fakes.ServiceDiscovery)
			serviceDiscovery.ServicesReturns(services, nil)
			serviceDiscovery.InstancesByPortReturns(tt.instances, nil)
			env.ServiceDiscovery = serviceDiscovery
			if err := env.PushContext.InitContext(&env, nil, nil); err != nil {
				t.Errorf("Failed to initialize push context: %v", err)
			}

			proxy.SidecarScope = model.DefaultSidecarScopeForNamespace(env.PushContext, "not-default")
			proxy.ServiceInstances = proxyInstances

			listeners := configgen.buildSidecarOutboundListeners(&env, &proxy, env.PushContext)
			listenersToCheck := make([]*xdsapi.Listener, 0)
			for _, l := range listeners {
				if l.Address.GetSocketAddress().GetPortValue() == 9999 {
					listenersToCheck = append(listenersToCheck, l)
				}
			}

			if len(listenersToCheck) != tt.numListenersOnServicePort {
				t.Errorf("Expected %d listeners on service port 9999, got %d", tt.numListenersOnServicePort, len(listenersToCheck))
			}
		})
	}
}

func TestInboundListenerConfig_HTTP(t *testing.T) {
	for _, p := range []*model.Proxy{&proxy, &proxyHTTP10} {
		// Add a service and verify it's config
		testInboundListenerConfig(t, p,
			buildService("test.com", wildcardIP, protocol.HTTP, tnow))
		testInboundListenerConfigWithoutServices(t, p)
		testInboundListenerConfigWithSidecar(t, p,
			buildService("test.com", wildcardIP, protocol.HTTP, tnow))
		testInboundListenerConfigWithSidecarWithoutServices(t, p)
	}
}

func TestOutboundListenerConfig_WithSidecar(t *testing.T) {
	// Add a service and verify it's config
	services := []*model.Service{
		buildService("test1.com", wildcardIP, protocol.HTTP, tnow.Add(1*time.Second)),
		buildService("test2.com", wildcardIP, protocol.TCP, tnow),
		buildService("test3.com", wildcardIP, protocol.HTTP, tnow.Add(2*time.Second))}
	testOutboundListenerConfigWithSidecar(t, services...)
	testOutboundListenerConfigWithSidecarWithCaptureModeNone(t, services...)
	testOutboundListenerConfigWithSidecarWithUseRemoteAddress(t, services...)
}

func TestGetActualWildcardAndLocalHost(t *testing.T) {
	tests := []struct {
		name     string
		proxy    *model.Proxy
		expected [2]string
	}{
		{
			name: "ipv4 only",
			proxy: &model.Proxy{
				IPAddresses: []string{"1.1.1.1", "127.0.0.1", "2.2.2.2"},
			},
			expected: [2]string{WildcardAddress, LocalhostAddress},
		},
		{
			name: "ipv6 only",
			proxy: &model.Proxy{
				IPAddresses: []string{"1111:2222::1", "::1", "2222:3333::1"},
			},
			expected: [2]string{WildcardIPv6Address, LocalhostIPv6Address},
		},
		{
			name: "mixed ipv4 and ipv6",
			proxy: &model.Proxy{
				IPAddresses: []string{"1111:2222::1", "::1", "127.0.0.1", "2.2.2.2", "2222:3333::1"},
			},
			expected: [2]string{WildcardAddress, LocalhostAddress},
		},
	}
	for _, tt := range tests {
		wm, lh := getActualWildcardAndLocalHost(tt.proxy)
		if wm != tt.expected[0] && lh != tt.expected[1] {
			t.Errorf("Test %s failed, expected: %s / %s got: %s / %s", tt.name, tt.expected[0], tt.expected[1], wm, lh)
		}
	}
}

func testOutboundListenerConflict(t *testing.T, services ...*model.Service) {
	t.Helper()

	oldestService := getOldestService(services...)

	p := &fakePlugin{}
	listeners := buildOutboundListeners(p, &proxy, nil, nil, services...)
	if len(listeners) != 1 {
		t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
	}

	oldestProtocol := oldestService.Ports[0].Protocol
	if oldestProtocol != protocol.HTTP && isHTTPListener(listeners[0]) {
		t.Fatal("expected TCP listener, found HTTP")
	} else if oldestProtocol == protocol.HTTP && !isHTTPListener(listeners[0]) {
		t.Fatal("expected HTTP listener, found TCP")
	}

	if len(p.outboundListenerParams) != 1 {
		t.Fatalf("expected %d listener params, found %d", 1, len(p.outboundListenerParams))
	}

	if p.outboundListenerParams[0].Service != oldestService {
		t.Fatalf("listener conflict failed to preserve listener for the oldest service")
	}
}

func testOutboundListenerRouteV13(t *testing.T, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	listeners := buildOutboundListeners(p, &proxy13, nil, nil, services...)
	if len(listeners) != 3 {
		t.Fatalf("expected %d listeners, found %d", 3, len(listeners))
	}

	l := findListenerByAddress(listeners, wildcardIP)
	if l == nil {
		t.Fatalf("expect listener %s", "0.0.0.0_8080")
	}

	f := l.FilterChains[1].Filters[0]
	cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
	rds := cfg.Fields["rds"].GetStructValue().Fields["route_config_name"].GetStringValue()
	if rds != "8080" {
		t.Fatalf("expect routes %s, found %s", "8080", rds)
	}

	l = findListenerByAddress(listeners, "1.2.3.4")
	if l == nil {
		t.Fatalf("expect listener %s", "1.2.3.4_8080")
	}
	f = l.FilterChains[1].Filters[0]
	cfg, _ = conversion.MessageToStruct(f.GetTypedConfig())
	rds = cfg.Fields["rds"].GetStructValue().Fields["route_config_name"].GetStringValue()
	if rds != "test1.com:8080" {
		t.Fatalf("expect routes %s, found %s", "test1.com:8080", rds)
	}

	l = findListenerByAddress(listeners, "3.4.5.6")
	if l == nil {
		t.Fatalf("expect listener %s", "3.4.5.6_8080")
	}
	f = l.FilterChains[1].Filters[0]
	cfg, _ = conversion.MessageToStruct(f.GetTypedConfig())
	rds = cfg.Fields["rds"].GetStructValue().Fields["route_config_name"].GetStringValue()
	if rds != "test3.com:8080" {
		t.Fatalf("expect routes %s, found %s", "test3.com:8080", rds)
	}
}

func testOutboundListenerConflictV13(t *testing.T, services ...*model.Service) {
	t.Helper()
	oldestService := getOldestService(services...)
	p := &fakePlugin{}
	listeners := buildOutboundListeners(p, &proxy13, nil, nil, services...)
	if len(listeners) != 1 {
		t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
	}

	oldestProtocol := oldestService.Ports[0].Protocol
	if oldestProtocol == protocol.MySQL {
		if len(listeners[0].FilterChains) != 2 {
			t.Fatalf("expectd %d filter chains, found %d", 2, len(listeners[0].FilterChains))
		} else if !isTCPFilterChain(listeners[0].FilterChains[1]) {
			t.Fatalf("expected tcp filter chain, found %s", listeners[0].FilterChains[1].Filters[0].Name)
		}
	} else if oldestProtocol != protocol.HTTP && oldestProtocol != protocol.TCP {
		if len(listeners[0].FilterChains) != 3 {
			t.Fatalf("expectd %d filter chains, found %d", 3, len(listeners[0].FilterChains))
		} else {
			if !isHTTPFilterChain(listeners[0].FilterChains[2]) {
				t.Fatalf("expected http filter chain, found %s", listeners[0].FilterChains[1].Filters[0].Name)
			}

			if !isTCPFilterChain(listeners[0].FilterChains[1]) {
				t.Fatalf("expected tcp filter chain, found %s", listeners[0].FilterChains[2].Filters[0].Name)
			}
		}

		verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[2], model.TrafficDirectionOutbound)
		if len(listeners[0].ListenerFilters) != 2 ||
			listeners[0].ListenerFilters[0].Name != "envoy.listener.tls_inspector" ||
			listeners[0].ListenerFilters[1].Name != "envoy.listener.http_inspector" {
			t.Fatalf("expected %d listener filter, found %d", 2, len(listeners[0].ListenerFilters))
		}

		f := listeners[0].FilterChains[2].Filters[0]
		cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
		rds := cfg.Fields["rds"].GetStructValue().Fields["route_config_name"].GetStringValue()
		expect := fmt.Sprintf("%d", oldestService.Ports[0].Port)
		if rds != expect {
			t.Fatalf("expect routes %s, found %s", expect, rds)
		}
	} else {
		if len(listeners[0].FilterChains) != 3 {
			t.Fatalf("expectd %d filter chains, found %d", 3, len(listeners[0].FilterChains))
		}

		if !isTCPFilterChain(listeners[0].FilterChains[1]) {
			t.Fatalf("expected tcp filter chain, found %s", listeners[0].FilterChains[2].Filters[0].Name)
		}

		if !isHTTPFilterChain(listeners[0].FilterChains[2]) {
			t.Fatalf("expected http filter chain, found %s", listeners[0].FilterChains[1].Filters[0].Name)
		}

		verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[2], model.TrafficDirectionOutbound)
		if len(listeners[0].ListenerFilters) != 2 ||
			listeners[0].ListenerFilters[0].Name != "envoy.listener.tls_inspector" ||
			listeners[0].ListenerFilters[1].Name != "envoy.listener.http_inspector" {
			t.Fatalf("expected %d listener filter, found %d", 2, len(listeners[0].ListenerFilters))
		}
	}
}

func testInboundListenerConfigV13(t *testing.T, proxy *model.Proxy, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	listeners := buildInboundListeners(p, proxy, nil, services...)
	if len(listeners) != 1 {
		t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
	}

	if len(listeners[0].FilterChains) != 4 ||
		!isHTTPFilterChain(listeners[0].FilterChains[0]) ||
		!isHTTPFilterChain(listeners[0].FilterChains[1]) ||
		!isTCPFilterChain(listeners[0].FilterChains[2]) ||
		!isTCPFilterChain(listeners[0].FilterChains[3]) {
		t.Fatalf("expectd %d filter chains, %d http filter chains and %d tcp filter chain", 4, 2, 2)
	}

	verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[0], model.TrafficDirectionInbound)
	verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[1], model.TrafficDirectionInbound)
}

func testInboundListenerConfigWithSidecarV13(t *testing.T, proxy *model.Proxy, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Ingress: []*networking.IstioIngressListener{
				{
					Port: &networking.Port{
						Number:   8080,
						Protocol: "unknown",
						Name:     "uds",
					},
					Bind:            "1.1.1.1",
					DefaultEndpoint: "127.0.0.1:80",
				},
			},
		},
	}
	listeners := buildInboundListeners(p, proxy, sidecarConfig, services...)
	if len(listeners) != 1 {
		t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
	}

	if len(listeners[0].FilterChains) != 4 ||
		!isHTTPFilterChain(listeners[0].FilterChains[0]) ||
		!isHTTPFilterChain(listeners[0].FilterChains[1]) ||
		!isTCPFilterChain(listeners[0].FilterChains[2]) ||
		!isTCPFilterChain(listeners[0].FilterChains[3]) {
		t.Fatalf("expectd %d filter chains, %d http filter chains and %d tcp filter chain", 4, 2, 2)
	}

	verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[0], model.TrafficDirectionInbound)
	verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[1], model.TrafficDirectionInbound)
}

func testInboundListenerConfigWithSidecarWithoutServicesV13(t *testing.T, proxy *model.Proxy) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo-without-service",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Ingress: []*networking.IstioIngressListener{
				{
					Port: &networking.Port{
						Number:   8080,
						Protocol: "unknown",
						Name:     "uds",
					},
					Bind:            "1.1.1.1",
					DefaultEndpoint: "127.0.0.1:80",
				},
			},
		},
	}
	listeners := buildInboundListeners(p, proxy, sidecarConfig)
	if expected := 1; len(listeners) != expected {
		t.Fatalf("expected %d listeners, found %d", expected, len(listeners))
	}

	if len(listeners[0].FilterChains) != 4 ||
		!isHTTPFilterChain(listeners[0].FilterChains[0]) ||
		!isHTTPFilterChain(listeners[0].FilterChains[1]) ||
		!isTCPFilterChain(listeners[0].FilterChains[2]) ||
		!isTCPFilterChain(listeners[0].FilterChains[3]) {
		t.Fatalf("expectd %d filter chains, %d http filter chains and %d tcp filter chain", 4, 2, 2)
	}

	verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[0], model.TrafficDirectionInbound)
	verifyHTTPFilterChainMatch(t, listeners[0].FilterChains[1], model.TrafficDirectionInbound)
}

func testInboundListenerConfigWithoutServiceV13(t *testing.T, proxy *model.Proxy) {
	t.Helper()
	p := &fakePlugin{}
	listeners := buildInboundListeners(p, proxy, nil)
	if expected := 0; len(listeners) != expected {
		t.Fatalf("expected %d listeners, found %d", expected, len(listeners))
	}
}

func verifyHTTPFilterChainMatch(t *testing.T, fc *listener.FilterChain, direction model.TrafficDirection) {
	t.Helper()
	if direction == model.TrafficDirectionInbound &&
		(len(fc.FilterChainMatch.ApplicationProtocols) != 2 ||
			fc.FilterChainMatch.ApplicationProtocols[0] != "http/1.0" ||
			fc.FilterChainMatch.ApplicationProtocols[1] != "http/1.1") {
		t.Fatalf("expected %d application protocols, [http/1.0, http/1.1]", 2)
	}

	if direction == model.TrafficDirectionOutbound &&
		(len(fc.FilterChainMatch.ApplicationProtocols) != 3 ||
			fc.FilterChainMatch.ApplicationProtocols[0] != "http/1.0" ||
			fc.FilterChainMatch.ApplicationProtocols[1] != "http/1.1" ||
			fc.FilterChainMatch.ApplicationProtocols[2] != "h2") {
		t.Fatalf("expected %d application protocols, [http/1.0, http/1.1, h2]", 3)
	}
}

func isHTTPFilterChain(fc *listener.FilterChain) bool {
	return len(fc.Filters) > 0 && fc.Filters[0].Name == "envoy.http_connection_manager"
}

func isTCPFilterChain(fc *listener.FilterChain) bool {
	return len(fc.Filters) > 0 && fc.Filters[0].Name == "envoy.tcp_proxy"
}

func testOutboundListenerConfigWithSidecarV13(t *testing.T, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Egress: []*networking.IstioEgressListener{
				{
					Port: &networking.Port{
						Number:   9000,
						Protocol: "HTTP",
						Name:     "uds",
					},
					Bind:  "1.1.1.1",
					Hosts: []string{"*/*"},
				},
				{
					Port: &networking.Port{
						Number:   3306,
						Protocol: string(protocol.MySQL),
						Name:     "MySQL",
					},
					Bind:  "8.8.8.8",
					Hosts: []string{"*/*"},
				},
				{
					Port: &networking.Port{
						Number:   8888,
						Protocol: "unknown",
						Name:     "unknown",
					},
					Bind:  "2.2.2.2",
					Hosts: []string{"*/*"},
				},
				{
					Hosts: []string{"*/*"},
				},
			},
		},
	}

	// enable mysql filter that is used here
	_ = os.Setenv(features.EnableMysqlFilter.Name, "true")

	defer func() { _ = os.Unsetenv(features.EnableMysqlFilter.Name) }()

	listeners := buildOutboundListeners(p, &proxy13, sidecarConfig, nil, services...)
	if len(listeners) != 4 {
		t.Fatalf("expected %d listeners, found %d", 4, len(listeners))
	}

	l := findListenerByPort(listeners, 8080)
	if len(l.FilterChains) != 4 {
		t.Fatalf("expectd %d filter chains, found %d", 4, len(l.FilterChains))
	} else {
		if !isHTTPFilterChain(l.FilterChains[3]) {
			t.Fatalf("expected http filter chain, found %s", l.FilterChains[3].Filters[0].Name)
		}

		if !isTCPFilterChain(l.FilterChains[1]) {
			t.Fatalf("expected tcp filter chain, found %s", l.FilterChains[1].Filters[0].Name)
		}

		verifyHTTPFilterChainMatch(t, l.FilterChains[3], model.TrafficDirectionOutbound)

		if len(l.ListenerFilters) != 2 ||
			l.ListenerFilters[0].Name != "envoy.listener.tls_inspector" ||
			l.ListenerFilters[1].Name != "envoy.listener.http_inspector" {
			t.Fatalf("expected %d listener filter, found %d", 2, len(l.ListenerFilters))
		}
	}

	if l := findListenerByPort(listeners, 3306); !isMysqlListener(l) {
		t.Fatalf("expected MySQL listener on port 3306, found %v", l)
	}

	if l := findListenerByPort(listeners, 9000); !isHTTPListener(l) {
		t.Fatalf("expected HTTP listener on port 9000, found TCP\n%v", l)
	}

	l = findListenerByPort(listeners, 8888)
	if len(l.FilterChains) != 2 {
		t.Fatalf("expectd %d filter chains, found %d", 2, len(l.FilterChains))
	} else {
		if !isHTTPFilterChain(l.FilterChains[1]) {
			t.Fatalf("expected http filter chain, found %s", l.FilterChains[0].Filters[0].Name)
		}

		if !isTCPFilterChain(l.FilterChains[0]) {
			t.Fatalf("expected tcp filter chain, found %s", l.FilterChains[1].Filters[0].Name)
		}
	}

	verifyHTTPFilterChainMatch(t, l.FilterChains[1], model.TrafficDirectionOutbound)
	if len(l.ListenerFilters) != 2 ||
		l.ListenerFilters[0].Name != "envoy.listener.tls_inspector" ||
		l.ListenerFilters[1].Name != "envoy.listener.http_inspector" {
		t.Fatalf("expected %d listener filter, found %d", 2, len(l.ListenerFilters))
	}
}

func testInboundListenerConfig(t *testing.T, proxy *model.Proxy, services ...*model.Service) {
	t.Helper()
	oldestService := getOldestService(services...)
	p := &fakePlugin{}
	listeners := buildInboundListeners(p, proxy, nil, services...)
	if len(listeners) != 1 {
		t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
	}
	oldestProtocol := oldestService.Ports[0].Protocol
	if oldestProtocol != protocol.HTTP && isHTTPListener(listeners[0]) {
		t.Fatal("expected TCP listener, found HTTP")
	} else if oldestProtocol == protocol.HTTP && !isHTTPListener(listeners[0]) {
		t.Fatal("expected HTTP listener, found TCP")
	}
	verifyInboundHTTPListenerServerName(t, listeners[0])
	verifyInboundHTTPListenerStatPrefix(t, listeners[0])
	if isHTTPListener(listeners[0]) {
		verifyInboundHTTPListenerCertDetails(t, listeners[0])
		verifyInboundHTTPListenerNormalizePath(t, listeners[0])
	}
	for _, l := range listeners {
		verifyInboundHTTP10(t, isNodeHTTP10(proxy), l)
	}

	verifyInboundEnvoyListenerNumber(t, listeners[0])
}

func testInboundListenerConfigWithoutServices(t *testing.T, proxy *model.Proxy) {
	t.Helper()
	p := &fakePlugin{}
	listeners := buildInboundListeners(p, proxy, nil)
	if expected := 0; len(listeners) != expected {
		t.Fatalf("expected %d listeners, found %d", expected, len(listeners))
	}
}

func testInboundListenerConfigWithSidecar(t *testing.T, proxy *model.Proxy, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Ingress: []*networking.IstioIngressListener{
				{
					Port: &networking.Port{
						Number:   8080,
						Protocol: "HTTP",
						Name:     "uds",
					},
					Bind:            "1.1.1.1",
					DefaultEndpoint: "127.0.0.1:80",
				},
			},
		},
	}
	listeners := buildInboundListeners(p, proxy, sidecarConfig, services...)
	if len(listeners) != 1 {
		t.Fatalf("expected %d listeners, found %d", 1, len(listeners))
	}

	if !isHTTPListener(listeners[0]) {
		t.Fatal("expected HTTP listener, found TCP")
	}
	for _, l := range listeners {
		verifyInboundHTTP10(t, isNodeHTTP10(proxy), l)
	}
}

func testInboundListenerConfigWithSidecarWithoutServices(t *testing.T, proxy *model.Proxy) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo-without-service",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Ingress: []*networking.IstioIngressListener{
				{
					Port: &networking.Port{
						Number:   8080,
						Protocol: "HTTP",
						Name:     "uds",
					},
					Bind:            "1.1.1.1",
					DefaultEndpoint: "127.0.0.1:80",
				},
			},
		},
	}
	listeners := buildInboundListeners(p, proxy, sidecarConfig)
	if expected := 1; len(listeners) != expected {
		t.Fatalf("expected %d listeners, found %d", expected, len(listeners))
	}
	if !isHTTPListener(listeners[0]) {
		t.Fatal("expected HTTP listener, found TCP")
	}
	for _, l := range listeners {
		verifyInboundHTTP10(t, isNodeHTTP10(proxy), l)
	}
}

func testOutboundListenerConfigWithSidecar(t *testing.T, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Egress: []*networking.IstioEgressListener{
				{
					Port: &networking.Port{
						Number:   9000,
						Protocol: "HTTP",
						Name:     "uds",
					},
					Bind:  "1.1.1.1",
					Hosts: []string{"*/*"},
				},
				{
					Port: &networking.Port{
						Number:   3306,
						Protocol: string(protocol.MySQL),
						Name:     "MySQL",
					},
					Bind:  "8.8.8.8",
					Hosts: []string{"*/*"},
				},
				{
					Hosts: []string{"*/*"},
				},
			},
		},
	}

	// enable mysql filter that is used here
	_ = os.Setenv(features.EnableMysqlFilter.Name, "true")

	defer func() { _ = os.Unsetenv(features.EnableMysqlFilter.Name) }()

	listeners := buildOutboundListeners(p, &proxy, sidecarConfig, nil, services...)
	if len(listeners) != 3 {
		t.Fatalf("expected %d listeners, found %d", 3, len(listeners))
	}

	if l := findListenerByPort(listeners, 8080); isHTTPListener(l) {
		t.Fatalf("expected TCP listener on port 8080, found HTTP: %v", l)
	}

	if l := findListenerByPort(listeners, 3306); !isMysqlListener(l) {
		t.Fatalf("expected MySQL listener on port 3306, found %v", l)
	}

	if l := findListenerByPort(listeners, 9000); !isHTTPListener(l) {
		t.Fatalf("expected HTTP listener on port 9000, found TCP\n%v", l)
	} else {
		f := l.FilterChains[0].Filters[0]
		cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
		if !strings.HasPrefix(cfg.Fields["stat_prefix"].GetStringValue(), "outbound_") {
			t.Fatalf("expected stat prefix to have outbound, %s", cfg.Fields["stat_prefix"].GetStringValue())
		}
		if useRemoteAddress, exists := cfg.Fields["use_remote_address"]; exists {
			if exists && useRemoteAddress.GetBoolValue() {
				t.Fatalf("expected useRemoteAddress false, found true %v", l)
			}
		}
	}
}

func testOutboundListenerConfigWithSidecarWithUseRemoteAddress(t *testing.T, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Egress: []*networking.IstioEgressListener{
				{
					Port: &networking.Port{
						Number:   9000,
						Protocol: "HTTP",
						Name:     "uds",
					},
					Bind:  "1.1.1.1",
					Hosts: []string{"*/*"},
				},
			},
		},
	}

	// enable use remote address to true
	_ = os.Setenv(features.UseRemoteAddress.Name, "true")

	defer func() { _ = os.Unsetenv(features.UseRemoteAddress.Name) }()

	listeners := buildOutboundListeners(p, &proxy, sidecarConfig, nil, services...)

	if l := findListenerByPort(listeners, 9000); !isHTTPListener(l) {
		t.Fatalf("expected HTTP listener on port 9000, found TCP\n%v", l)
	} else {
		f := l.FilterChains[0].Filters[0]
		cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
		if useRemoteAddress, exists := cfg.Fields["use_remote_address"]; exists {
			if !exists || !useRemoteAddress.GetBoolValue() {
				t.Fatalf("expected useRemoteAddress true, found false %v", l)
			}
		}
	}
}

func testOutboundListenerConfigWithSidecarWithCaptureModeNone(t *testing.T, services ...*model.Service) {
	t.Helper()
	p := &fakePlugin{}
	sidecarConfig := &model.Config{
		ConfigMeta: model.ConfigMeta{
			Name:      "foo",
			Namespace: "not-default",
		},
		Spec: &networking.Sidecar{
			Egress: []*networking.IstioEgressListener{
				{
					// Bind + Port
					CaptureMode: networking.CaptureMode_NONE,
					Port: &networking.Port{
						Number:   9090,
						Protocol: "HTTP",
						Name:     "grpc",
					},
					Bind:  "127.1.1.2",
					Hosts: []string{"*/*"},
				},
				{
					// Bind Only
					CaptureMode: networking.CaptureMode_NONE,
					Bind:        "127.1.1.2",
					Hosts:       []string{"*/*"},
				},
				{
					// Port Only
					CaptureMode: networking.CaptureMode_NONE,
					Port: &networking.Port{
						Number:   9090,
						Protocol: "HTTP",
						Name:     "grpc",
					},
					Hosts: []string{"*/*"},
				},
				{
					// None
					CaptureMode: networking.CaptureMode_NONE,
					Hosts:       []string{"*/*"},
				},
			},
		},
	}
	listeners := buildOutboundListeners(p, &proxy, sidecarConfig, nil, services...)
	if len(listeners) != 4 {
		t.Fatalf("expected %d listeners, found %d", 4, len(listeners))
	}

	expectedListeners := map[string]string{
		"127.1.1.2_9090": "HTTP",
		"127.1.1.2_8080": "TCP",
		"127.0.0.1_9090": "HTTP",
		"127.0.0.1_8080": "TCP",
	}

	for _, l := range listeners {
		listenerName := l.Name
		expectedListenerType := expectedListeners[listenerName]
		if expectedListenerType == "" {
			t.Fatalf("listener %s not expected", listenerName)
		}
		if expectedListenerType == "TCP" && isHTTPListener(l) {
			t.Fatalf("expected TCP listener %s, but found HTTP", listenerName)
		}
		if expectedListenerType == "HTTP" && !isHTTPListener(l) {
			t.Fatalf("expected HTTP listener %s, but found TCP", listenerName)
		}
	}
}

func TestOutboundListenerAccessLogs(t *testing.T) {
	t.Helper()
	p := &fakePlugin{}
	listeners := buildAllListeners(p, nil)
	for _, l := range listeners {
		if l.Name == "virtual" {
			fc := &tcp_proxy.TcpProxy{}
			if err := getFilterConfig(l.FilterChains[0].Filters[0], fc); err != nil {
				t.Fatalf("failed to get TCP Proxy config: %s", err)
			}
			if fc.AccessLog == nil {
				t.Fatal("expected access log configuration")
			}
		}
	}
}

func TestHttpProxyListener(t *testing.T) {
	p := &fakePlugin{}
	configgen := NewConfigGenerator([]plugin.Plugin{p})

	env := buildListenerEnv(nil)
	if err := env.PushContext.InitContext(&env, nil, nil); err != nil {
		t.Fatalf("error in initializing push context: %s", err)
	}

	proxy.ServiceInstances = nil
	env.Mesh.ProxyHttpPort = 15007
	proxy.SidecarScope = model.DefaultSidecarScopeForNamespace(env.PushContext, "not-default")
	httpProxy := configgen.buildHTTPProxy(&env, &proxy, env.PushContext, nil)
	f := httpProxy.FilterChains[0].Filters[0]
	cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())

	if httpProxy.Address.GetSocketAddress().GetPortValue() != 15007 {
		t.Fatalf("expected http proxy is not listening on %d, but on port %d", env.Mesh.ProxyHttpPort,
			httpProxy.Address.GetSocketAddress().GetPortValue())
	}
	if !strings.HasPrefix(cfg.Fields["stat_prefix"].GetStringValue(), "outbound_") {
		t.Fatalf("expected http proxy stat prefix to have outbound, %s", cfg.Fields["stat_prefix"].GetStringValue())
	}
}

func verifyOutboundTCPListenerHostname(t *testing.T, l *xdsapi.Listener, hostname host.Name) {
	t.Helper()
	if len(l.FilterChains) != 1 {
		t.Fatalf("expected %d filter chains, found %d", 1, len(l.FilterChains))
	}
	fc := l.FilterChains[0]
	if len(fc.Filters) != 1 {
		t.Fatalf("expected %d filters, found %d", 1, len(fc.Filters))
	}
	f := fc.Filters[0]
	expectedStatPrefix := fmt.Sprintf("outbound|8080||%s", hostname)
	cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
	statPrefix := cfg.Fields["stat_prefix"].GetStringValue()
	if statPrefix != expectedStatPrefix {
		t.Fatalf("expected listener to contain stat_prefix %s, found %s", expectedStatPrefix, statPrefix)
	}
}

func verifyInboundHTTPListenerServerName(t *testing.T, l *xdsapi.Listener) {
	t.Helper()
	if len(l.FilterChains) != 2 {
		t.Fatalf("expected %d filter chains, found %d", 2, len(l.FilterChains))
	}
	fc := l.FilterChains[0]
	if len(fc.Filters) != 1 {
		t.Fatalf("expected %d filters, found %d", 1, len(fc.Filters))
	}
	f := fc.Filters[0]
	expectedServerName := "istio-envoy"
	cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
	serverName := cfg.Fields["server_name"].GetStringValue()
	if serverName != expectedServerName {
		t.Fatalf("expected listener to contain server_name %s, found %s", expectedServerName, serverName)
	}
}

func verifyInboundHTTPListenerStatPrefix(t *testing.T, l *xdsapi.Listener) {
	t.Helper()
	if len(l.FilterChains) != 2 {
		t.Fatalf("expected %d filter chains, found %d", 2, len(l.FilterChains))
	}
	fc := l.FilterChains[0]
	if len(fc.Filters) != 1 {
		t.Fatalf("expected %d filters, found %d", 1, len(fc.Filters))
	}
	f := fc.Filters[0]
	cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
	if !strings.HasPrefix(cfg.Fields["stat_prefix"].GetStringValue(), "inbound_") {
		t.Fatalf("expected stat prefix to have %s , found %s", "inbound", cfg.Fields["stat_prefix"].GetStringValue())
	}

}

func verifyInboundEnvoyListenerNumber(t *testing.T, l *xdsapi.Listener) {
	t.Helper()
	if len(l.FilterChains) != 2 {
		t.Fatalf("expected %d filter chains, found %d", 2, len(l.FilterChains))
	}

	for _, fc := range l.FilterChains {
		if len(fc.Filters) != 1 {
			t.Fatalf("expected %d filters, found %d", 1, len(fc.Filters))
		}

		f := fc.Filters[0]
		cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
		hf := cfg.Fields["http_filters"].GetListValue()
		if len(hf.Values) != 4 {
			t.Fatalf("expected %d http filters, found %d", 4, len(hf.Values))
		}
		envoyLua := hf.Values[0].GetStructValue().Fields["name"].GetStringValue()
		envoyCors := hf.Values[1].GetStructValue().Fields["name"].GetStringValue()
		if envoyLua != "envoy.lua" || envoyCors != "envoy.cors" {
			t.Fatalf("expected %q %q http filter, found %q %q", "envoy.lua", "envoy.cors", envoyLua, envoyCors)
		}
	}
}

func verifyInboundHTTPListenerCertDetails(t *testing.T, l *xdsapi.Listener) {
	t.Helper()
	if len(l.FilterChains) != 2 {
		t.Fatalf("expected %d filter chains, found %d", 2, len(l.FilterChains))
	}
	fc := l.FilterChains[0]
	if len(fc.Filters) != 1 {
		t.Fatalf("expected %d filters, found %d", 1, len(fc.Filters))
	}
	f := fc.Filters[0]
	cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
	forwardDetails, expected := cfg.Fields["forward_client_cert_details"].GetStringValue(), "APPEND_FORWARD"
	if forwardDetails != expected {
		t.Fatalf("expected listener to contain forward_client_cert_details %s, found %s", expected, forwardDetails)
	}
	setDetails := cfg.Fields["set_current_client_cert_details"].GetStructValue()
	subject := setDetails.Fields["subject"].GetBoolValue()
	dns := setDetails.Fields["dns"].GetBoolValue()
	uri := setDetails.Fields["uri"].GetBoolValue()
	if !subject || !dns || !uri {
		t.Fatalf("expected listener to contain set_current_client_cert_details (subject: true, dns: true, uri: true), "+
			"found (subject: %t, dns: %t, uri %t)", subject, dns, uri)
	}
}

func verifyInboundHTTPListenerNormalizePath(t *testing.T, l *xdsapi.Listener) {
	t.Helper()
	if len(l.FilterChains) != 2 {
		t.Fatalf("expected 2 filter chains, found %d", len(l.FilterChains))
	}
	fc := l.FilterChains[0]
	if len(fc.Filters) != 1 {
		t.Fatalf("expected 1 filter, found %d", len(fc.Filters))
	}
	f := fc.Filters[0]
	cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
	actual := cfg.Fields["normalize_path"].GetBoolValue()
	if actual != true {
		t.Errorf("expected HTTP listener with normalize_path set to true, found false")
	}
}

func verifyInboundHTTP10(t *testing.T, http10Expected bool, l *xdsapi.Listener) {
	t.Helper()
	for _, fc := range l.FilterChains {
		for _, f := range fc.Filters {
			if f.Name == "envoy.http_connection_manager" {
				cfg, _ := conversion.MessageToStruct(f.GetTypedConfig())
				httpProtocolOptionsField := cfg.Fields["http_protocol_options"]
				if http10Expected && httpProtocolOptionsField == nil {
					t.Error("expected http_protocol_options for http_connection_manager, found nil")
					return
				}
				if !http10Expected && httpProtocolOptionsField == nil {
					continue
				}
				httpProtocolOptions := httpProtocolOptionsField.GetStructValue()
				acceptHTTP10Field := httpProtocolOptions.Fields["accept_http_10"]
				if http10Expected && acceptHTTP10Field == nil {
					t.Error("expected http protocol option accept_http_10, found nil")
					return
				}
				if http10Expected && acceptHTTP10Field.GetBoolValue() != http10Expected {
					t.Errorf("expected accepting HTTP 1.0: %v, found: %v", http10Expected, acceptHTTP10Field.GetBoolValue())
				}
			}
		}
	}
}

func getOldestService(services ...*model.Service) *model.Service {
	var oldestService *model.Service
	for _, s := range services {
		if oldestService == nil || s.CreationTime.Before(oldestService.CreationTime) {
			oldestService = s
		}
	}
	return oldestService
}

func buildAllListeners(p plugin.Plugin, sidecarConfig *model.Config, services ...*model.Service) []*xdsapi.Listener {
	configgen := NewConfigGenerator([]plugin.Plugin{p})

	env := buildListenerEnv(services)

	if err := env.PushContext.InitContext(&env, nil, nil); err != nil {
		return nil
	}

	proxy.ServiceInstances = nil
	if sidecarConfig == nil {
		proxy.SidecarScope = model.DefaultSidecarScopeForNamespace(env.PushContext, "not-default")
	} else {
		proxy.SidecarScope = model.ConvertToSidecarScope(env.PushContext, sidecarConfig, sidecarConfig.Namespace)
	}
	builder := NewListenerBuilder(&proxy)
	return configgen.buildSidecarListeners(&env, &proxy, env.PushContext, builder).getListeners()
}

func getFilterConfig(filter *listener.Filter, out proto.Message) error {
	switch c := filter.ConfigType.(type) {
	case *listener.Filter_Config:
		if err := conversion.StructToMessage(c.Config, out); err != nil {
			return err
		}
	case *listener.Filter_TypedConfig:
		if err := ptypes.UnmarshalAny(c.TypedConfig, out); err != nil {
			return err
		}
	}
	return nil
}

func buildOutboundListeners(p plugin.Plugin, proxy *model.Proxy, sidecarConfig *model.Config,
	virtualService *model.Config, services ...*model.Service) []*xdsapi.Listener {
	configgen := NewConfigGenerator([]plugin.Plugin{p})

	var env model.Environment
	if virtualService != nil {
		env = buildListenerEnvWithVirtualServices(services, []*model.Config{virtualService})
	} else {
		env = buildListenerEnv(services)
	}

	if err := env.PushContext.InitContext(&env, nil, nil); err != nil {
		return nil
	}

	proxy.IstioVersion = model.ParseIstioVersion(proxy.Metadata.IstioVersion)
	if sidecarConfig == nil {
		proxy.SidecarScope = model.DefaultSidecarScopeForNamespace(env.PushContext, "not-default")
	} else {
		proxy.SidecarScope = model.ConvertToSidecarScope(env.PushContext, sidecarConfig, sidecarConfig.Namespace)
	}
	proxy.ServiceInstances = proxyInstances

	return configgen.buildSidecarOutboundListeners(&env, proxy, env.PushContext)
}

func buildInboundListeners(p plugin.Plugin, proxy *model.Proxy, sidecarConfig *model.Config, services ...*model.Service) []*xdsapi.Listener {
	configgen := NewConfigGenerator([]plugin.Plugin{p})
	env := buildListenerEnv(services)
	if err := env.PushContext.InitContext(&env, nil, nil); err != nil {
		return nil
	}
	instances := make([]*model.ServiceInstance, len(services))
	for i, s := range services {
		instances[i] = &model.ServiceInstance{
			Service:  s,
			Endpoint: buildEndpoint(s),
		}
	}

	proxy.IstioVersion = model.ParseIstioVersion(proxy.Metadata.IstioVersion)
	proxy.ServiceInstances = instances
	if sidecarConfig == nil {
		proxy.SidecarScope = model.DefaultSidecarScopeForNamespace(env.PushContext, "not-default")
	} else {
		proxy.SidecarScope = model.ConvertToSidecarScope(env.PushContext, sidecarConfig, sidecarConfig.Namespace)
	}
	return configgen.buildSidecarInboundListeners(&env, proxy, env.PushContext)
}

type fakePlugin struct {
	outboundListenerParams []*plugin.InputParams
}

var _ plugin.Plugin = (*fakePlugin)(nil)

func (p *fakePlugin) OnOutboundListener(in *plugin.InputParams, mutable *plugin.MutableObjects) error {
	p.outboundListenerParams = append(p.outboundListenerParams, in)
	return nil
}

func (p *fakePlugin) OnInboundListener(in *plugin.InputParams, mutable *plugin.MutableObjects) error {
	return nil
}

func (p *fakePlugin) OnVirtualListener(in *plugin.InputParams, mutable *plugin.MutableObjects) error {
	return nil
}

func (p *fakePlugin) OnOutboundCluster(in *plugin.InputParams, cluster *xdsapi.Cluster) {
}

func (p *fakePlugin) OnInboundCluster(in *plugin.InputParams, cluster *xdsapi.Cluster) {
}

func (p *fakePlugin) OnOutboundRouteConfiguration(in *plugin.InputParams, routeConfiguration *xdsapi.RouteConfiguration) {
}

func (p *fakePlugin) OnInboundRouteConfiguration(in *plugin.InputParams, routeConfiguration *xdsapi.RouteConfiguration) {
}

func (p *fakePlugin) OnInboundFilterChains(in *plugin.InputParams) []plugin.FilterChain {
	return []plugin.FilterChain{{}, {}}
}

func isHTTPListener(listener *xdsapi.Listener) bool {
	if listener == nil {
		return false
	}

	for _, fc := range listener.FilterChains {
		if fc.Filters[0].Name == "envoy.http_connection_manager" {
			return true
		}
	}
	return false
}

func isMysqlListener(listener *xdsapi.Listener) bool {
	if len(listener.FilterChains) > 0 && len(listener.FilterChains[0].Filters) > 0 {
		return listener.FilterChains[0].Filters[0].Name == xdsutil.MySQLProxy
	}
	return false
}

func isNodeHTTP10(proxy *model.Proxy) bool {
	return proxy.Metadata.HTTP10 == "1"
}

func findListenerByPort(listeners []*xdsapi.Listener, port uint32) *xdsapi.Listener {
	for _, l := range listeners {
		if port == l.Address.GetSocketAddress().GetPortValue() {
			return l
		}
	}

	return nil
}

func findListenerByAddress(listeners []*xdsapi.Listener, address string) *xdsapi.Listener {
	for _, l := range listeners {
		if address == l.Address.GetSocketAddress().Address {
			return l
		}
	}

	return nil
}

func buildService(hostname string, ip string, protocol protocol.Instance, creationTime time.Time) *model.Service {
	return &model.Service{
		CreationTime: creationTime,
		Hostname:     host.Name(hostname),
		Address:      ip,
		ClusterVIPs:  make(map[string]string),
		Ports: model.PortList{
			&model.Port{
				Name:     "default",
				Port:     8080,
				Protocol: protocol,
			},
		},
		Resolution: model.Passthrough,
		Attributes: model.ServiceAttributes{
			Namespace: "default",
		},
	}
}

func buildServiceWithPort(hostname string, port int, protocol protocol.Instance, creationTime time.Time) *model.Service {
	return &model.Service{
		CreationTime: creationTime,
		Hostname:     host.Name(hostname),
		Address:      wildcardIP,
		ClusterVIPs:  make(map[string]string),
		Ports: model.PortList{
			&model.Port{
				Name:     "default",
				Port:     port,
				Protocol: protocol,
			},
		},
		Resolution: model.Passthrough,
		Attributes: model.ServiceAttributes{
			Namespace: "default",
		},
	}
}

func buildEndpoint(service *model.Service) model.NetworkEndpoint {
	return model.NetworkEndpoint{
		ServicePort: service.Ports[0],
		Port:        8080,
	}
}

func buildServiceInstance(service *model.Service, instanceIP string) *model.ServiceInstance {
	return &model.ServiceInstance{
		Endpoint: model.NetworkEndpoint{
			Address: instanceIP,
		},
		Service: service,
	}
}

func buildListenerEnv(services []*model.Service) model.Environment {
	return buildListenerEnvWithVirtualServices(services, nil)
}

func buildListenerEnvWithVirtualServices(services []*model.Service, virtualServices []*model.Config) model.Environment {
	serviceDiscovery := new(fakes.ServiceDiscovery)
	serviceDiscovery.ServicesReturns(services, nil)

	configStore := &fakes.IstioConfigStore{
		EnvoyFilterStub: func(workloadLabels labels.Collection) *model.Config {
			return &model.Config{
				ConfigMeta: model.ConfigMeta{
					Name:      "test-envoyfilter",
					Namespace: "not-default",
				},
				Spec: &networking.EnvoyFilter{
					Filters: []*networking.EnvoyFilter_Filter{
						{
							InsertPosition: &networking.EnvoyFilter_InsertPosition{
								Index: networking.EnvoyFilter_InsertPosition_FIRST,
							},
							FilterType:   networking.EnvoyFilter_Filter_HTTP,
							FilterName:   "envoy.lua",
							FilterConfig: &types.Struct{},
						},
					},
				},
			}
		},
		ListStub: func(typ, namespace string) (configs []model.Config, e error) {
			if typ == "virtual-service" {
				result := make([]model.Config, len(virtualServices))
				for i := range virtualServices {
					result[i] = *virtualServices[i]
				}
				return result, nil
			}
			return nil, nil

		},
	}

	m := mesh.DefaultMeshConfig()
	m.EnableEnvoyAccessLogService = true
	env := model.Environment{
		PushContext:      model.NewPushContext(),
		ServiceDiscovery: serviceDiscovery,
		IstioConfigStore: configStore,
		Mesh:             &m,
	}

	return env
}


text:
package javax.faces.component.behavior;

import java.util.Collection;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

/**
 * @since 2.0
 */
public abstract class ClientBehaviorContext
{

    public static ClientBehaviorContext createClientBehaviorContext(FacesContext context,
                                                                    UIComponent component,
                                                                    String eventName,
                                                                    String sourceId,
                                                                    Collection<Parameter> parameters)
    {
        // This method is weird... Creating a dummy impl class seems stupid, yet I don't see any other way...
        if(context == null)
        {
            throw new NullPointerException("context argument must not be null");
        }
        if(component == null)
        {
            throw new NullPointerException("component argument must not be null");
        }
        if(eventName == null)
        {
            throw new NullPointerException("eventName argument must not be null");
        }

        return new ClientBehaviorContextImpl(context,component,eventName,sourceId, parameters);
    }

    public abstract UIComponent getComponent();

    public abstract String getEventName();

    public abstract FacesContext getFacesContext();

    public abstract Collection<Parameter> getParameters();

    public abstract String getSourceId();

    /**
     * @since 2.0
     */
    public static class Parameter
    {
        private String _name;
        private Object _value;

        public Parameter(String name, Object value)
        {
            if (name == null)
            {
                throw new NullPointerException("name");
            }

            _name = name;
            _value = value;
        }

        public String getName()
        {
            return _name;
        }

        public Object getValue()
        {
            return _value;
        }
    }

    private static final class ClientBehaviorContextImpl extends ClientBehaviorContext
    {
        private FacesContext _facesContext;
        private UIComponent _component;
        private String _eventName;
        private String _sourceId;
        private Collection<ClientBehaviorContext.Parameter> _parameters;

        public ClientBehaviorContextImpl(FacesContext context, UIComponent component, String eventName,
                String sourceId, Collection<ClientBehaviorContext.Parameter> parameters)
        {
            _facesContext = context;
            _component = component;
            _eventName = eventName;
            _sourceId = sourceId;
            _parameters = parameters;
        }

        @Override
        public UIComponent getComponent()
        {
            return _component;
        }

        @Override
        public String getEventName()
        {
            return _eventName;
        }

        @Override
        public FacesContext getFacesContext()
        {
            return _facesContext;
        }

        @Override
        public Collection<Parameter> getParameters()
        {
            return _parameters;
        }

        @Override
        public String getSourceId()
        {
            return _sourceId;
        }
    }
}


text:
package com.bnorm.infinite.file;

import com.bnorm.infinite.Action;
import com.bnorm.infinite.ActionType;

/**
 * Functional interface that represents how to convert a string into a state entrance or exit Action.
 *
 * @param <S> the class type of the states.
 * @param <E> the class type of the events.
 * @param <C> the class type of the context.
 * @author Brian Norman
 * @since 1.2.0
 */
@FunctionalInterface
public interface StringStateActionFactory<S, E, C> {

    /**
     * A string state action factory that always returns a no action.  Since this string state action factory always
     * returns the type safe {@link Action#noAction()}, it can be cast to any required state machine types.
     */
    static StringStateActionFactory<?, ?, ?> NO_ACTION_FACTORY = (s, t, a) -> Action.noAction();

    /**
     * Returns the {@link StringStateActionFactory#NO_ACTION_FACTORY} factory cast to the required parameter types.
     *
     * @param <S> the class type of the states.
     * @param <E> the class type of the events.
     * @param <C> the class type of the context.
     * @return a type safe {@link StringStateActionFactory#NO_ACTION_FACTORY} factory.
     */
    static <S, E, C> StringStateActionFactory<S, E, C> noActionFactory() {
        @SuppressWarnings("unchecked")
        StringStateActionFactory<S, E, C> noActionFactory = (StringStateActionFactory<S, E, C>) NO_ACTION_FACTORY;
        return noActionFactory;
    }

    /**
     * Creates a new action given the specified action string, action type, and state to which it should be added.  How
     * to interpret these parameters is completely up to the implementing class.
     *
     * @param state the state to which the action should be added.
     * @param type the action type.
     * @param action the string that should be converted to an action.
     * @return a new action converted from the action string.
     */
    Action<S, E, C> create(S state, ActionType type, String action);
}


text:
<?php

include(dirname(__FILE__).'/../../bootstrap/functional.php');

// create a new test browser
$browser = new sfTestBrowser();
$browser->initialize();

$browser->
  get('/fx-cmisc/index')->
  isStatusCode(200)->
  isRequestParameter('module', 'fx-cmisc')->
  isRequestParameter('action', 'index')->
  checkResponseElement('body', '!/This is a temporary page/')
;