content: /*
   * 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.bookkeeper.tools.cli.commands.cookie;
  
  import static java.nio.charset.StandardCharsets.UTF_8;
  import static org.junit.Assert.assertArrayEquals;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertTrue;
  import static org.mockito.Mockito.times;
  import static org.mockito.Mockito.verify;
  import static org.mockito.Mockito.when;
  
  import java.io.ByteArrayOutputStream;
  import java.io.File;
  import java.io.PrintStream;
  import java.nio.file.Files;
  import java.nio.file.Paths;
  import java.util.List;
  import org.apache.bookkeeper.bookie.Cookie;
  import org.apache.bookkeeper.tools.cli.helpers.CookieCommandTestBase;
  import org.apache.bookkeeper.tools.common.BKFlags;
  import org.junit.Rule;
  import org.junit.Test;
  import org.junit.rules.TemporaryFolder;
  
  /**
   * Unit test {@link GetCookieCommand}.
   */
  public class GenerateCookieCommandTest extends CookieCommandTestBase {
  
      @Rule
      public final TemporaryFolder testFolder = new TemporaryFolder();
  
      private final ByteArrayOutputStream output = new ByteArrayOutputStream();
      private final PrintStream console = new PrintStream(output);
  
      private boolean runCommand(String[] args) {
          GenerateCookieCommand getCmd = new GenerateCookieCommand(console);
          BKFlags bkFlags = new BKFlags();
          bkFlags.serviceUri = "zk://127.0.0.1";
          return getCmd.apply(bkFlags, args);
      }
  
      private String getConsoleOutput() {
          return new String(output.toByteArray(), UTF_8);
      }
  
      /**
       * Run a command without providing bookie id.
       */
      @Test
      public void testMissingBookieId() {
          assertFalse(runCommand(new String[] {}));
          String consoleOutput = getConsoleOutput();
          assertBookieIdMissing(consoleOutput);
      }
  
      /**
       * Run a command with invalid bookie id.
       */
      @Test
      public void testInvalidBookieId() {
          assertFalse(runCommand(new String[] {
              "-j", "/path/to/journal",
              "-l", "/path/to/ledgers",
              "-o", "/path/to/cookie-file",
              INVALID_BOOKIE_ID
          }));
          String consoleOutput = getConsoleOutput();
          assertInvalidBookieId(consoleOutput, INVALID_BOOKIE_ID);
      }
  
      /**
       * Run a command without journal dirs.
       */
      @Test
      public void testMissingJournalDir() {
          assertFalse(runCommand(new String[] { "-l", "/path/to/ledgers", "-o", "/path/to/cookie-file", BOOKIE_ID }));
          String consoleOutput = getConsoleOutput();
          assertOptionMissing(consoleOutput, "[-j | --journal-dirs]");
      }
  
      /**
       * Run a command without ledger dirs.
       */
      @Test
      public void testMissingLedgerDirs() {
          assertFalse(runCommand(new String[] { "-j", "/path/to/journal", "-o", "/path/to/cookie-file", BOOKIE_ID }));
          String consoleOutput = getConsoleOutput();
          assertOptionMissing(consoleOutput, "[-l | --ledger-dirs]");
      }
  
      /**
       * Run a command without output file.
       */
      @Test
      public void testMissingOutputFile() {
          assertFalse(runCommand(new String[] { "-j", "/path/to/journal", "-l", "/path/to/ledgers", BOOKIE_ID }));
          String consoleOutput = getConsoleOutput();
          assertOptionMissing(consoleOutput, "[-o | --output-file]");
      }
  
      /**
       * A successful run without instance id.
       */
      @Test
      public void testGenerateCookieWithoutInstanceId() throws Exception {
          File cookieFile = testFolder.newFile("cookie-without-instance-id");
          String journalDir = "/path/to/journal";
          String ledgersDir = "/path/to/ledgers";
          String instanceId = "test-instance-id";
  
          Cookie cookie = Cookie.newBuilder()
              .setBookieId(BOOKIE_ID)
              .setInstanceId(instanceId)
              .setJournalDirs(journalDir)
              .setLedgerDirs(Cookie.encodeDirPaths(ledgersDir.split(",")))
              .build();
  
          when(rm.getClusterInstanceId()).thenReturn(instanceId);
          assertTrue(
              getConsoleOutput(),
              runCommand(new String[] {
                  "-l", ledgersDir,
                  "-j", journalDir,
                  "-o", cookieFile.getPath(),
                  BOOKIE_ID
              }));
          String consoleOutput = getConsoleOutput();
          assertTrue(consoleOutput, consoleOutput.contains(
              "Successfully saved the generated cookie to " + cookieFile.getPath()
          ));
          verify(rm, times(1)).getClusterInstanceId();
  
          byte[] data = Files.readAllBytes(Paths.get(cookieFile.getPath()));
          assertArrayEquals(cookie.toString().getBytes(UTF_8), data);
      }
  
      /**
       * A successful run with instance id.
       */
      @Test
      public void testGenerateCookieWithInstanceId() throws Exception {
          File cookieFile = testFolder.newFile("cookie-with-instance-id");
          String journalDir = "/path/to/journal";
          String ledgersDir = "/path/to/ledgers";
          String instanceId = "test-instance-id";
  
          Cookie cookie = Cookie.newBuilder()
              .setBookieId(BOOKIE_ID)
              .setInstanceId(instanceId)
              .setJournalDirs(journalDir)
              .setLedgerDirs(Cookie.encodeDirPaths(ledgersDir.split(",")))
              .build();
  
          when(rm.getClusterInstanceId()).thenReturn(instanceId);
          assertTrue(
              getConsoleOutput(),
              runCommand(new String[] {
                  "-l", ledgersDir,
                  "-j", journalDir,
                  "-o", cookieFile.getPath(),
                  "-i", instanceId,
                  BOOKIE_ID
              }));
          String consoleOutput = getConsoleOutput();
          assertTrue(consoleOutput, consoleOutput.contains(
              "Successfully saved the generated cookie to " + cookieFile.getPath()
          ));
          verify(rm, times(0)).getClusterInstanceId();
  
          byte[] data = Files.readAllBytes(Paths.get(cookieFile.getPath()));
          assertArrayEquals(cookie.toString().getBytes(UTF_8), data);
      }
  
      /**
       * A successful run with encoding multiple ledgers while generating cookie.
       */
      @Test
      public void testGenerateCookieWithMultipleLedgerDirs() throws Exception {
          File cookieFile = testFolder.newFile("cookie-with-instance-id");
          String journalDir = "/path/to/journal";
          String ledgersDir = "/path/to/ledgers,/path/to/more/ledgers";
          String instanceId = "test-instance-id";
  
          when(rm.getClusterInstanceId()).thenReturn(instanceId);
          assertTrue(
                  getConsoleOutput(),
                  runCommand(new String[] {
                          "-l", ledgersDir,
                          "-j", journalDir,
                          "-o", cookieFile.getPath(),
                          "-i", instanceId,
                          BOOKIE_ID
                  }));
          String consoleOutput = getConsoleOutput();
          assertTrue(consoleOutput, consoleOutput.contains(
                  "Successfully saved the generated cookie to " + cookieFile.getPath()
          ));
          verify(rm, times(0)).getClusterInstanceId();
  
          List<String> cookieFields = Files.readAllLines(Paths.get(cookieFile.getPath()));
          for (String cookieField : cookieFields) {
              String[] fields = cookieField.split(" ");
              if (fields[0].equals("ledgerDirs:")) {
                  assertEquals(fields[1].charAt(1), '2');
              }
          }
      }
  
  }
  