View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  import com.google.protobuf.RpcController;
24  import com.google.protobuf.ServiceException;
25  import java.io.File;
26  import java.io.IOException;
27  import java.nio.file.Files;
28  import java.nio.file.Path;
29  import java.nio.file.Paths;
30  import org.apache.commons.io.IOUtils;
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.client.Admin;
33  import org.apache.hadoop.hbase.client.Connection;
34  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ShellExecEndpoint.ShellExecRequest;
35  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ShellExecEndpoint.ShellExecResponse;
36  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ShellExecEndpoint.ShellExecService;
37  import org.apache.hadoop.hbase.ipc.HBaseRpcControllerImpl;
38  import org.apache.hadoop.hbase.testclassification.MediumTests;
39  import org.junit.AfterClass;
40  import org.junit.BeforeClass;
41  import org.junit.Test;
42  import org.junit.experimental.categories.Category;
43  
44  /**
45   * Test for the {@link ShellExecEndpointCoprocessor}.
46   */
47  @Category(MediumTests.class)
48  public class TestShellExecEndpointCoprocessor {
49  
50    private static IntegrationTestingUtility util;
51    private static Connection connection;
52  
53    @BeforeClass
54    public static void setUp() throws Exception {
55      // Set up the integration test util
56      if (util == null) {
57        util = new IntegrationTestingUtility(createConfiguration());
58        util.initializeCluster(3);
59        connection = util.getConnection();
60      }
61    }
62  
63  
64    @AfterClass
65    public static void teardown() throws Exception {
66      IOUtils.closeQuietly(connection);
67      // Clean everything up.
68      if (util != null) {
69        util.restoreCluster();
70        util = null;
71      }
72    }
73    @Test
74    public void testShellExecUnspecified() throws IOException, ServiceException {
75      testShellExecForeground(ShellExecRequest.newBuilder());
76    }
77  
78    @Test
79    public void testShellExecForeground() throws IOException, ServiceException {
80      testShellExecForeground(ShellExecRequest.newBuilder().setAwaitResponse(true));
81    }
82  
83    private void testShellExecForeground(final ShellExecRequest.Builder builder)
84        throws IOException, ServiceException {
85      final Admin admin = connection.getAdmin();
86  
87      final String command = "echo -n \"hello world\"";
88      builder.setCommand(command);
89      ShellExecService.BlockingInterface stub =
90          ShellExecService.newBlockingStub(admin.coprocessorService());
91      RpcController controller = new HBaseRpcControllerImpl();
92      ShellExecResponse resp = stub.shellExec(controller, builder.build());
93      assertEquals(0, resp.getExitCode());
94      assertEquals("hello world", resp.getStdout());
95    }
96  
97    @Test
98    public void testShellExecBackground() throws IOException, ServiceException {
99      Admin admin = connection.getAdmin();
100     final File testDataDir = ensureTestDataDirExists(util);
101     final File testFile = new File(testDataDir, "shell_exec_background.txt");
102     assertTrue(testFile.createNewFile());
103     assertEquals(0, testFile.length());
104 
105     final String command = "echo \"hello world\" >> " + testFile.getAbsolutePath();
106     final ShellExecRequest req = ShellExecRequest.newBuilder()
107       .setCommand(command)
108       .setAwaitResponse(false)
109       .build();
110 
111     ShellExecService.BlockingInterface stub =
112         ShellExecService.newBlockingStub(admin.coprocessorService());
113     RpcController controller = new HBaseRpcControllerImpl();
114     ShellExecResponse resp = stub.shellExec(controller, req);
115     assertFalse("the response from a background task should have no exit code", resp.hasExitCode());
116     assertFalse("the response from a background task should have no stdout", resp.hasStdout());
117     assertFalse("the response from a background task should have no stderr", resp.hasStderr());
118 
119     Waiter.waitFor(util.getConfiguration(), 5_000, new Waiter.Predicate<Exception>() {
120       @Override
121       public boolean evaluate() throws Exception {
122         return testFile.length() > 0;
123       }
124     });
125     final String content = new String(Files.readAllBytes(testFile.toPath())).trim();
126     assertEquals("hello world", content);
127   }
128 
129   private static File ensureTestDataDirExists(final HBaseTestingUtility testingUtility)
130       throws IOException {
131     final Path testDataDir = Paths.get(testingUtility.getDataTestDir().toString());
132     final File testDataDirFile = Files.createDirectories(testDataDir).toFile();
133     assertTrue(testDataDirFile.exists());
134     return testDataDirFile;
135   }
136 
137   private static Configuration createConfiguration() {
138     final Configuration conf = HBaseConfiguration.create();
139     conf.set("hbase.coprocessor.master.classes", ShellExecEndpointCoprocessor.class.getName());
140     return conf;
141   }
142 }