/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * 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 io.cdap.cdap.common.lang;

import io.cdap.cdap.api.app.Application;
import java.io.IOException;
import javax.ws.rs.PUT;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.VersionInfo;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;

/**
 */
public class FilterClassLoaderTest {

  @Test(expected = ClassNotFoundException.class)
  public void testSystemInternalsHidden() throws ClassNotFoundException {
    FilterClassLoader classLoader = FilterClassLoader.create(this.getClass().getClassLoader());
    classLoader.loadClass(FilterClassLoader.class.getName());
  }

  @Test
  public void testAPIVisible() throws ClassNotFoundException {
    FilterClassLoader classLoader = FilterClassLoader.create(this.getClass().getClassLoader());
    Assert.assertSame(Application.class, classLoader.loadClass(Application.class.getName()));

    // Dependencies of API classes should also be visible
    Assert.assertSame(Logger.class, classLoader.loadClass(Logger.class.getName()));

    // JAX-RS classes should also be visible
    Assert.assertSame(PUT.class, classLoader.loadClass(PUT.class.getName()));
  }

  @Test
  public void testBootstrapResourcesVisible() throws IOException {
    FilterClassLoader classLoader = FilterClassLoader.create(this.getClass().getClassLoader());
    Assert.assertNotNull(classLoader.getResource("java/lang/String.class"));
  }

  @Test
  public void testExtensionResourcesVisible() throws ClassNotFoundException {
    // isn't really a way to guarantee what classes are in the extensions directory.
    // so we'll just check that if the system classloader can load it, the filter classloader should be able to load it.
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    Object o;
    try {
      o = systemClassLoader.loadClass("com.sun.nio.zipfs.ZipInfo");
    } catch (ClassNotFoundException e) {
      // class isn't in extensions, this test will be a no-op
      return;
    }
    FilterClassLoader classLoader = FilterClassLoader.create(this.getClass().getClassLoader());
    Assert.assertEquals(o.getClass(), classLoader.loadClass("com.sun.nio.zipfs.ZipInfo").getClass());
  }

  @Test
  public void testHadoopResourcesVisible() throws ClassNotFoundException {
    FilterClassLoader classLoader = FilterClassLoader.create(this.getClass().getClassLoader());
    ClassLoader oldClassLoader = ClassLoaders.setContextClassLoader(classLoader);
    try {
      // VersionInfo will based on the context class loader to find the "common-version-info.properties" file.
      // If it is missing/failed to locate that, getVersion() will returns "Unknown".
      Assert.assertNotEquals("Unknown", VersionInfo.getVersion());
    } finally {
      ClassLoaders.setContextClassLoader(oldClassLoader);
    }

    // Load standard Hadoop class. It should pass. The class loader of the loaded class should be the same
    // as the system Configuration class.
    Assert.assertSame(Configuration.class, classLoader.loadClass(Configuration.class.getName()));
  }
}
