content: /*
   * Copyright 2012-2013 Cooma Team.
   *
   * 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 com.alibaba.cooma;
  
  import com.alibaba.cooma.ext1.SimpleExt;
  import com.alibaba.cooma.ext1.impl.SimpleExtImpl1;
  import com.alibaba.cooma.ext1.impl.SimpleExtImpl2;
  import com.alibaba.cooma.ext2.NoDefaultExt;
  import com.alibaba.cooma.ext3.WrappedExt;
  import com.alibaba.cooma.ext3.impl.Ext3Impl1;
  import com.alibaba.cooma.ext3.impl.Ext3Impl2;
  import com.alibaba.cooma.ext3.impl.Ext3Wrapper1;
  import com.alibaba.cooma.ext3.impl.Ext3Wrapper2;
  import com.alibaba.cooma.ext4.WithAttributeExt;
  import com.alibaba.cooma.ext6.InjectExt;
  import com.alibaba.cooma.ext6.impl.Ext6Impl2;
  import com.alibaba.cooma.ext7.InitErrorExt;
  import com.alibaba.cooma.ext8.InvalidNameExt;
  import com.alibaba.cooma.ext8.InvalidNameExt2;
  import com.alibaba.cooma.ext5.ImplNoDefaultConstructorExt;
  import com.alibaba.util.Utils;
  import org.junit.Test;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Set;
  
  import static org.hamcrest.CoreMatchers.allOf;
  import static org.hamcrest.CoreMatchers.anyOf;
  import static org.hamcrest.CoreMatchers.instanceOf;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertNotSame;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertThat;
  import static org.junit.Assert.assertTrue;
  import static org.junit.Assert.fail;
  import static org.junit.matchers.JUnitMatchers.containsString;
  
  /**
   * @author Jerry Lee(oldratlee AT gmail DOT com)
   */
  public class ExtensionLoaderTest {
      @Test
      public void test_getExtensionLoader_Null() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(null);
              fail();
          } catch (IllegalArgumentException expected) {
              assertThat(expected.getMessage(),
                      containsString("Extension type == null"));
          }
      }
  
      @Test
      public void test_getExtensionLoader_NotInterface() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(ExtensionLoaderTest.class);
              fail();
          } catch (IllegalArgumentException expected) {
              assertThat(expected.getMessage(),
                      containsString("type(com.alibaba.cooma.ExtensionLoaderTest) is not interface"));
          }
      }
  
      @Test
      public void test_getExtensionLoader_NotSpiAnnotation() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(NoExtensionExt.class);
              fail();
          } catch (IllegalArgumentException expected) {
              assertThat(expected.getMessage(),
                      allOf(containsString(NoExtensionExt.class.getName()),
                              containsString("is not a extension"),
                              containsString("WITHOUT @Extension Annotation")));
          }
      }
  
      @Test
      public void test_getDefault() throws Exception {
          SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultExtension();
          assertThat(ext, instanceOf(SimpleExtImpl1.class));
  
          String name = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultExtensionName();
          assertEquals("impl1", name);
      }
  
      @Test
      public void test_getDefault_NULL() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(NoDefaultExt.class).getDefaultExtension();
          } catch (IllegalStateException expected) {
              assertThat(expected.getMessage(), containsString("No default extension on extension com.alibaba.cooma.ext2.NoDefaultExt"));
          }
  
  
          String name = ExtensionLoader.getExtensionLoader(NoDefaultExt.class).getDefaultExtensionName();
          assertNull(name);
      }
  
      @Test
      public void test_getExtension() throws Exception {
          assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension("impl1") instanceof SimpleExtImpl1);
          assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension("impl2") instanceof SimpleExtImpl2);
      }
  
      @Test
      public void test_getExtension_DifferentInstance() throws Exception {
          ExtensionLoader<SimpleExt> extensionLoader = ExtensionLoader.getExtensionLoader(SimpleExt.class);
          assertNotSame(extensionLoader.getExtension("impl1"), extensionLoader.getExtension("impl1"));
      }
  
      @Test
      public void test_getExtension_WithWrapper_notAutoLoad() throws Exception {
          //
          WrappedExt impl1 = ExtensionLoader.getExtensionLoader(WrappedExt.class).getExtension("impl1", new ArrayList<String>());
          assertThat(impl1, instanceOf(Ext3Impl1.class));
  
          WrappedExt impl2 = ExtensionLoader.getExtensionLoader(WrappedExt.class).getExtension("impl2", new ArrayList<String>());
          assertThat(impl2, instanceOf(Ext3Impl2.class));
  
          int echoCount1 = Ext3Wrapper1.echoCount.get();
          int echoCount2 = Ext3Wrapper2.echoCount.get();
          int yellCount1 = Ext3Wrapper1.yellCount.get();
          int yellCount2 = Ext3Wrapper2.yellCount.get();
  
          Map<String, String> config = Utils.kv2Map("protocol", "p1", "host", "1.2.3.4", "port", "1010", "path", "path1");
  
          assertEquals("Ext3Impl1-echo", impl1.echo(config, "ha"));
          assertEquals(echoCount1, Ext3Wrapper1.echoCount.get());
          assertEquals(echoCount2, Ext3Wrapper2.echoCount.get());
          assertEquals(yellCount1, Ext3Wrapper1.yellCount.get());
          assertEquals(yellCount2, Ext3Wrapper2.yellCount.get());
  
          assertEquals("Ext3Impl2-yell", impl2.yell(config, "ha"));
          assertEquals(echoCount1, Ext3Wrapper1.echoCount.get());
          assertEquals(echoCount2, Ext3Wrapper2.echoCount.get());
          assertEquals(yellCount1, Ext3Wrapper1.yellCount.get());
          assertEquals(yellCount2, Ext3Wrapper2.yellCount.get());
      }
  
      @Test
      public void test_getExtension_WithWrapper() throws Exception {
          WrappedExt impl1 = ExtensionLoader.getExtensionLoader(WrappedExt.class).getExtension("impl1", Arrays.asList("wrapper1", "wrapper2"));
          assertThat(impl1, anyOf(instanceOf(Ext3Wrapper1.class), instanceOf(Ext3Wrapper2.class)));
  
          WrappedExt impl2 = ExtensionLoader.getExtensionLoader(WrappedExt.class).getExtension("impl2", Arrays.asList("wrapper1", "wrapper2"));
          assertThat(impl2, anyOf(instanceOf(Ext3Wrapper1.class), instanceOf(Ext3Wrapper2.class)));
  
          int echoCount1 = Ext3Wrapper1.echoCount.get();
          int echoCount2 = Ext3Wrapper2.echoCount.get();
          int yellCount1 = Ext3Wrapper1.yellCount.get();
          int yellCount2 = Ext3Wrapper2.yellCount.get();
  
          Map<String, String> config = Utils.kv2Map("protocol", "p1", "host", "1.2.3.4", "port", "1010", "path", "path1");
  
          assertEquals("Ext3Impl1-echo", impl1.echo(config, "ha"));
          assertEquals(echoCount1 + 1, Ext3Wrapper1.echoCount.get());
          assertEquals(echoCount2 + 1, Ext3Wrapper2.echoCount.get());
          assertEquals(yellCount1, Ext3Wrapper1.yellCount.get());
          assertEquals(yellCount2, Ext3Wrapper2.yellCount.get());
  
          assertEquals("Ext3Impl2-yell", impl2.yell(config, "ha"));
          assertEquals(echoCount1 + 1, Ext3Wrapper1.echoCount.get());
          assertEquals(echoCount2 + 1, Ext3Wrapper2.echoCount.get());
          assertEquals(yellCount1 + 1, Ext3Wrapper1.yellCount.get());
          assertEquals(yellCount2 + 1, Ext3Wrapper2.yellCount.get());
      }
  
      @Test
      public void test_getExtension_ExceptionNoExtension() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension("NotExisted");
              fail();
          } catch (IllegalStateException expected) {
              assertThat(expected.getMessage(), containsString("No such extension com.alibaba.cooma.ext1.SimpleExt by name NotExisted"));
          }
      }
  
      @Test
      public void test_getExtension_ExceptionNoExtension_NameOnWrapperNoEffective() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(WrappedExt.class).getExtension("wrapper1");
              fail();
          } catch (IllegalStateException expected) {
              assertThat(expected.getMessage(), containsString("No such extension com.alibaba.cooma.ext3.WrappedExt by name wrapper1"));
          }
      }
  
      @Test
      public void test_getExtension_ExceptionNullArg() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension((String) null);
              fail();
          } catch (IllegalArgumentException expected) {
              assertThat(expected.getMessage(), containsString("Extension name == null"));
          }
      }
  
      @Test
      public void test_hasExtension() throws Exception {
          assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).hasExtension("impl1"));
          assertFalse(ExtensionLoader.getExtensionLoader(SimpleExt.class).hasExtension("impl1,impl2"));
          assertFalse(ExtensionLoader.getExtensionLoader(SimpleExt.class).hasExtension("xxx"));
  
          try {
              ExtensionLoader.getExtensionLoader(SimpleExt.class).hasExtension(null);
              fail();
          } catch (IllegalArgumentException expected) {
              assertThat(expected.getMessage(), containsString("Extension name == null"));
          }
      }
  
      @Test
      public void test_hasDefaultExtension() throws Exception {
          assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).hasDefaultExtension());
          assertFalse(ExtensionLoader.getExtensionLoader(NoDefaultExt.class).hasDefaultExtension());
      }
  
      @Test
      public void test_hasExtension_wrapperIsNotExt() throws Exception {
          ExtensionLoader<WrappedExt> extensionLoader = ExtensionLoader.getExtensionLoader(WrappedExt.class);
  
          assertTrue(extensionLoader.hasExtension("impl1"));
          assertFalse(extensionLoader.hasExtension("impl1,impl2"));
          assertFalse(extensionLoader.hasExtension("xxx"));
  
          assertFalse(extensionLoader.hasExtension("wrapper1"));
  
          try {
              extensionLoader.hasExtension(null);
              fail();
          } catch (IllegalArgumentException expected) {
              assertThat(expected.getMessage(), containsString("Extension name == null"));
          }
      }
  
      @Test
      public void test_getSupportedExtensions() throws Exception {
          Set<String> extensions = ExtensionLoader.getExtensionLoader(SimpleExt.class).getSupportedExtensions();
  
          Set<String> expected = new HashSet<String>();
          expected.add("impl1");
          expected.add("impl2");
          expected.add("impl3");
  
          assertEquals(expected, extensions);
      }
  
      @Test
      public void test_getSupportedExtensions_wrapperIsNotExt() throws Exception {
          Set<String> extensions = ExtensionLoader.getExtensionLoader(WrappedExt.class).getSupportedExtensions();
  
          Set<String> expected = new HashSet<String>();
          expected.add("impl1");
          expected.add("impl2");
  
          assertEquals(expected, extensions);
      }
  
      @Test
      public void test_getExtensionAttribute_all() throws Exception {
          ExtensionLoader<WithAttributeExt> extensionLoader = ExtensionLoader.getExtensionLoader(WithAttributeExt.class);
  
          Map<String, Map<String, String>> extensionAttribute = extensionLoader.getExtensionAttribute();
  
          Map<String, Map<String, String>> expected = new HashMap<String, Map<String, String>>();
          expected.put("impl1", Utils.kv2Map("k1", "v1", "k2", "", "k3", "v3", "k4", "", "k5", "v5"));
          expected.put("impl2", new HashMap<String, String>());
          expected.put("impl3", Utils.kv2Map("key1", "value1", "key2", "value2", "key3", ""));
  
          assertEquals(expected, extensionAttribute);
      }
  
      @Test
      public void test_getExtensionAttribute_one() throws Exception {
          ExtensionLoader<WithAttributeExt> extensionLoader = ExtensionLoader.getExtensionLoader(WithAttributeExt.class);
          Map<String, String> extensionAttribute = extensionLoader.getExtensionAttribute("impl1");
          assertEquals(Utils.kv2Map("k1", "v1", "k2", "", "k3", "v3", "k4", "", "k5", "v5"), extensionAttribute);
      }
  
      @Test
      public void test_getExtensionAttribute_oneNotExisted() throws Exception {
          ExtensionLoader<WithAttributeExt> extensionLoader = ExtensionLoader.getExtensionLoader(WithAttributeExt.class);
  
          try {
              Map<String, String> extensionAttribute = extensionLoader.getExtensionAttribute("NotExisted");
              fail();
          } catch (IllegalStateException expected) {
              assertThat(expected.getMessage(), containsString("No such extension com.alibaba.cooma.ext4.WithAttributeExt by name NotExisted"));
          }
      }
  
      @Test
      public void test_getAdaptiveInstance_InjectNotExtFail() throws Exception {
          InjectExt ext = ExtensionLoader.getExtensionLoader(InjectExt.class).getExtension("impl2");
  
          Ext6Impl2 impl = (Ext6Impl2) ext;
          assertNull(impl.getList());
      }
  
      @Test
      public void test_InitError() throws Exception {
          ExtensionLoader<InitErrorExt> loader = ExtensionLoader.getExtensionLoader(InitErrorExt.class);
  
          loader.getExtension("ok");
  
          try {
              loader.getExtension("error");
              fail();
          } catch (IllegalStateException expected) {
              assertThat(expected.getMessage(), containsString("Failed to load config line(error=com.alibaba.cooma.ext7.impl.Ext7InitErrorImpl)"));
              assertThat(expected.getMessage(), containsString("com.alibaba.cooma.ext7.InitErrorExt) for extension(com.alibaba.cooma.ext7.InitErrorExt)"));
              assertThat(expected.getCause().getCause(), instanceOf(ExceptionInInitializerError.class));
          }
      }
  
      @Test
      public void test_InvalidExtName() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(InvalidNameExt.class);
              fail();
          } catch (IllegalStateException expected) {
              assertThat(expected.getMessage(),
                      containsString("default name(invalid-name&) of extension com.alibaba.cooma.ext8.InvalidNameExt is invalid"));
          }
      }
  
      // 新增测试 a-Z 中的 ] [ 等非法符号，见 Issue #56
      @Test
      public void test_InvalidExtName2() throws Exception {
          try {
              ExtensionLoader.getExtensionLoader(InvalidNameExt2.class);
              fail();
          } catch (IllegalStateException expected) {
              assertThat(expected.getMessage(),
                      containsString("default name(invalidName]) of extension com.alibaba.cooma.ext8.InvalidNameExt2 is invalid"));
          }
      }
  
      @Test
      public void test_ImplNoDefaultConstructor() throws Exception {
          ExtensionLoader<ImplNoDefaultConstructorExt> extensionLoader = ExtensionLoader.getExtensionLoader(ImplNoDefaultConstructorExt.class);
          assertEquals(new HashSet<String>(Arrays.asList("impl2")), extensionLoader.getSupportedExtensions());
      }
  
      @Test
      public void test_parseExtAttribute() throws Exception {
          assertEquals(Utils.kv2Map("k1", "v1", "k2", "v2"), ExtensionLoader.parseExtAttribute("k1=v1,k2=v2"));
          assertEquals(Utils.kv2Map("k1", "v1", "k2", "v2", "k3", ""), ExtensionLoader.parseExtAttribute("  k1   =v1,   k2=    v2  , k3    "));
          assertEquals(Utils.kv2Map("k1", ""), ExtensionLoader.parseExtAttribute("k1"));
      }
  }
  