/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.ranger.plugin.resourcematcher;

import static org.junit.Assert.*;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import org.apache.commons.lang.StringUtils;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.policyengine.RangerAccessResource;
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
import org.apache.ranger.plugin.policyresourcematcher.RangerDefaultPolicyResourceMatcher;
import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class TestDefaultPolicyResourceMatcherForPolicy {
	static Gson gsonBuilder;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		gsonBuilder = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z")
				.setPrettyPrinting()
				.registerTypeAdapter(RangerAccessResource.class, new TestDefaultPolicyResourceMatcherForPolicy.RangerResourceDeserializer())
				.create();
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testDefaultPolicyResourceMatcherForPolicy() throws Exception {
		String[] tests = { "/resourcematcher/test_defaultpolicyresourcematcher_for_policy.json",
				"/resourcematcher/test_defaultpolicyresourcematcher_for_hdfs_policy.json"};

		runTestsFromResourceFiles(tests);
	}

	private void runTestsFromResourceFiles(String[] resourceNames) throws Exception {
		for(String resourceName : resourceNames) {
			InputStream       inStream = this.getClass().getResourceAsStream(resourceName);
			InputStreamReader reader   = new InputStreamReader(inStream);

			runTests(reader);
		}
	}

	private void runTests(InputStreamReader reader) throws Exception {
		DefaultPolicyResourceMatcherTestCases testCases = gsonBuilder.fromJson(reader, DefaultPolicyResourceMatcherTestCases.class);

		for (DefaultPolicyResourceMatcherTestCases.TestCase testCase : testCases.testCases) {
			runTest(testCase, testCases.serviceDef);
		}
	}
		private void runTest(DefaultPolicyResourceMatcherTestCases.TestCase testCase, RangerServiceDef serviceDef) throws Exception {

		assertTrue("invalid input: " , testCase != null && testCase.tests != null);

		RangerDefaultPolicyResourceMatcher matcher = new RangerDefaultPolicyResourceMatcher();
		matcher.setServiceDef(serviceDef);
		matcher.setPolicyResources(testCase.policyResources);
		matcher.init();

		for(DefaultPolicyResourceMatcherTestCases.TestCase.OneTest oneTest : testCase.tests) {
			if(oneTest == null) {
				continue;
			}

			boolean expected = oneTest.result;
			RangerPolicyResourceMatcher.MatchScope scope;
			if (StringUtils.equalsIgnoreCase(oneTest.type, "selfOrDescendantMatch")) {
				scope = RangerPolicyResourceMatcher.MatchScope.SELF_OR_DESCENDANT;
			} else if (StringUtils.equalsIgnoreCase(oneTest.type, "descendantMatch")) {
				scope = RangerPolicyResourceMatcher.MatchScope.DESCENDANT;
			} else if (StringUtils.equalsIgnoreCase(oneTest.type, "exactMatch")) {
				scope = RangerPolicyResourceMatcher.MatchScope.SELF;
			} else if (StringUtils.equalsIgnoreCase(oneTest.type, "selfOrAncestorMatch")) {
				scope = RangerPolicyResourceMatcher.MatchScope.SELF_OR_ANCESTOR;
			} else if (StringUtils.equalsIgnoreCase(oneTest.type, "ancestorMatch")) {
				scope = RangerPolicyResourceMatcher.MatchScope.ANCESTOR;
			} else if (StringUtils.equalsIgnoreCase(oneTest.type, "anyMatch")) {
				scope = RangerPolicyResourceMatcher.MatchScope.SELF_OR_ANCESTOR_OR_DESCENDANT;
			} else {
				continue;
			}
			boolean result = matcher.isMatch(oneTest.policy, scope, oneTest.evalContext);

			assertEquals("match failed! " + ":" + testCase.name + ":" + oneTest.name + ":" + oneTest.type + ": policy=" + oneTest.policy, expected, result);
		}
	}

	private static class DefaultPolicyResourceMatcherTestCases {
		RangerServiceDef serviceDef;

		List<TestCase> testCases;

		class TestCase {
			public String name;
			Map<String, RangerPolicyResource> policyResources;
			public List<OneTest> tests;

			class OneTest {
				String name;
				String type;
				RangerPolicy policy;
				Map<String, Object> evalContext;
				boolean result;
			}
		}
	}

	private static class RangerResourceDeserializer implements JsonDeserializer<RangerAccessResource> {
		@Override
		public RangerAccessResource deserialize(JsonElement jsonObj, Type type,
												JsonDeserializationContext context) throws JsonParseException {
			return gsonBuilder.fromJson(jsonObj, RangerAccessResourceImpl.class);
		}
	}
}

@@ -979,16 +979,49 @@
 t.Type;%0A
+import java.nio.charset.Charset;%0A
 import j
@@ -3120,16 +3120,42 @@
 inStream
+, Charset.defaultCharset()
 );%0A%0A%09%09%09r
@@ -3514,17 +3514,16 @@
 %0A%09%09%7D%0A%09%7D%0A
-%09
 %09private
@@ -5404,16 +5404,23 @@
 ses;%0A%0A%09%09
+static 
 class Te
@@ -5431,23 +5431,16 @@
 se %7B%0A%09%09%09
-public 
 String n
@@ -5501,23 +5501,16 @@
 ces;%0A%09%09%09
-public 
 List%3COne
@@ -5526,16 +5526,23 @@
 ts;%0A%0A%09%09%09
+static 
 class On

Fix issues uncovered by static code analysis