/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch 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.elasticsearch.bootstrap;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
import org.apache.lucene.util.Constants;
import org.elasticsearch.common.SuppressLoggerChecks;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.test.ESTestCase;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Path;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class MaxMapCountCheckTests extends ESTestCase {

    public void testGetMaxMapCountOnLinux() {
        if (Constants.LINUX) {
            final BootstrapCheck.MaxMapCountCheck check = new BootstrapCheck.MaxMapCountCheck();
            assertThat(check.getMaxMapCount(), greaterThan(0L));
        }
    }

    @SuppressLoggerChecks(reason = "mock usage")
    public void testGetMaxMapCount() throws IOException {
        final long procSysVmMaxMapCount = randomIntBetween(1, Integer.MAX_VALUE);
        final BufferedReader reader = mock(BufferedReader.class);
        when(reader.readLine()).thenReturn(Long.toString(procSysVmMaxMapCount));
        final Path procSysVmMaxMapCountPath = PathUtils.get("/proc/sys/vm/max_map_count");
        BootstrapCheck.MaxMapCountCheck check = new BootstrapCheck.MaxMapCountCheck() {
            @Override
            BufferedReader getBufferedReader(Path path) throws IOException {
                assertEquals(path, procSysVmMaxMapCountPath);
                return reader;
            }
        };

        assertThat(check.getMaxMapCount(), equalTo(procSysVmMaxMapCount));
        verify(reader).close();

        reset(reader);
        final IOException ioException = new IOException("fatal");
        when(reader.readLine()).thenThrow(ioException);
        final Logger logger = mock(Logger.class);
        assertThat(check.getMaxMapCount(logger), equalTo(-1L));
        verify(logger).warn(
            (Supplier<?>) () -> new ParameterizedMessage(
                "I/O exception while trying to read [{}]", procSysVmMaxMapCountPath), ioException);
        verify(reader).close();

        reset(reader);
        reset(logger);
        when(reader.readLine()).thenReturn("eof");
        assertThat(check.getMaxMapCount(logger), equalTo(-1L));
        verify(logger).warn(eq(
            (Supplier<?>) () -> new ParameterizedMessage(
                "unable to parse vm.max_map_count [{}]", "eof")), any(NumberFormatException.class));
        verify(reader).close();
    }

    public void testMaxMapCountCheckRead() throws IOException {
        final String rawProcSysVmMaxMapCount = Long.toString(randomIntBetween(1, Integer.MAX_VALUE));
        final BufferedReader reader = mock(BufferedReader.class);
        when(reader.readLine()).thenReturn(rawProcSysVmMaxMapCount);
        final BootstrapCheck.MaxMapCountCheck check = new BootstrapCheck.MaxMapCountCheck();
        assertThat(check.readProcSysVmMaxMapCount(reader), equalTo(rawProcSysVmMaxMapCount));
    }

    public void testMaxMapCountCheckParse() {
        final long procSysVmMaxMapCount = randomIntBetween(1, Integer.MAX_VALUE);
        final BootstrapCheck.MaxMapCountCheck check = new BootstrapCheck.MaxMapCountCheck();
        assertThat(check.parseProcSysVmMaxMapCount(Long.toString(procSysVmMaxMapCount)), equalTo(procSysVmMaxMapCount));
    }

}

@@ -1152,16 +1152,81 @@
 estCase;
+%0Aimport org.hamcrest.Matcher;%0Aimport org.mockito.ArgumentMatcher;
 %0A%0Aimport
@@ -1444,16 +1444,60 @@
 rs.any;%0A
+import static org.mockito.Matchers.argThat;%0A
 import s
@@ -3136,83 +3136,32 @@
 arn(
-%0A            (Supplier%3C?%3E) () -%3E new ParameterizedMessage(%0A                
+argThat(argumentMatcher(
 %22I/O
@@ -3197,41 +3197,43 @@
 ad %5B
-%7B%7D%5D%22, procSysVmMaxMapCountPath), 
+/proc/sys/vm/max_map_count%5D%22)), eq(
 ioEx
@@ -3232,32 +3232,33 @@
  eq(ioException)
+)
 ;%0A        verify
@@ -3469,86 +3469,32 @@
 arn(
-eq(%0A            (Supplier%3C?%3E) () -%3E new ParameterizedMessage(%0A                
+argThat(argumentMatcher(
 %22una
@@ -3528,18 +3528,12 @@
 nt %5B
-%7B%7D%5D%22, %22
 eof
+%5D
 %22)),
@@ -3599,32 +3599,515 @@
 close();%0A    %7D%0A%0A
+    private ArgumentMatcher%3CSupplier%3C?%3E%3E argumentMatcher(final String message) %7B%0A        return new ArgumentMatcher%3CSupplier%3C?%3E%3E() %7B%0A            @Override%0A            public boolean matches(Object o) %7B%0A                final Supplier%3C?%3E supplier = (Supplier%3C?%3E)o;%0A                final ParameterizedMessage parameterizedMessage = (ParameterizedMessage) supplier.get();%0A                return parameterizedMessage.getFormattedMessage().equals(message);%0A            %7D%0A        %7D;%0A    %7D%0A%0A
     public void 

Fix failing max map count check test