001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.rest;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022
023import java.io.ByteArrayInputStream;
024import java.io.IOException;
025import javax.xml.bind.JAXBContext;
026import javax.xml.bind.JAXBException;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.hbase.HBaseTestingUtil;
029import org.apache.hadoop.hbase.NamespaceDescriptor;
030import org.apache.hadoop.hbase.client.Admin;
031import org.apache.hadoop.hbase.rest.client.Client;
032import org.apache.hadoop.hbase.rest.client.Cluster;
033import org.apache.hadoop.hbase.rest.client.Response;
034import org.apache.hadoop.hbase.rest.model.NamespacesModel;
035import org.apache.hadoop.hbase.rest.model.TestNamespacesModel;
036import org.apache.hadoop.hbase.testclassification.MediumTests;
037import org.apache.hadoop.hbase.testclassification.RestTests;
038import org.apache.hadoop.hbase.util.Bytes;
039import org.junit.jupiter.api.AfterAll;
040import org.junit.jupiter.api.BeforeAll;
041import org.junit.jupiter.api.Tag;
042import org.junit.jupiter.api.Test;
043
044@Tag(RestTests.TAG)
045@Tag(MediumTests.TAG)
046public class TestNamespacesResource {
047
048  private static String NAMESPACE1 = "TestNamespacesInstanceResource1";
049  private static String NAMESPACE2 = "TestNamespacesInstanceResource2";
050
051  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
052  private static final HBaseRESTTestingUtility REST_TEST_UTIL = new HBaseRESTTestingUtility();
053  private static Client client;
054  private static JAXBContext context;
055  private static Configuration conf;
056  private static TestNamespacesModel testNamespacesModel;
057
058  @BeforeAll
059  public static void setUpBeforeClass() throws Exception {
060    conf = TEST_UTIL.getConfiguration();
061    TEST_UTIL.startMiniCluster();
062    REST_TEST_UTIL.startServletContainer(conf);
063    client = new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()));
064    testNamespacesModel = new TestNamespacesModel();
065    context = JAXBContext.newInstance(NamespacesModel.class);
066  }
067
068  @AfterAll
069  public static void tearDownAfterClass() throws Exception {
070    REST_TEST_UTIL.shutdownServletContainer();
071    TEST_UTIL.shutdownMiniCluster();
072  }
073
074  private static NamespacesModel fromXML(byte[] content) throws JAXBException {
075    return (NamespacesModel) context.createUnmarshaller()
076      .unmarshal(new ByteArrayInputStream(content));
077  }
078
079  private boolean doesNamespaceExist(Admin admin, String namespaceName) throws IOException {
080    NamespaceDescriptor[] nd = admin.listNamespaceDescriptors();
081    for (NamespaceDescriptor namespaceDescriptor : nd) {
082      if (namespaceDescriptor.getName().equals(namespaceName)) {
083        return true;
084      }
085    }
086    return false;
087  }
088
089  private void createNamespaceViaAdmin(Admin admin, String name) throws IOException {
090    NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(name);
091    NamespaceDescriptor nsd = builder.build();
092    admin.createNamespace(nsd);
093  }
094
095  @Test
096  public void testNamespaceListXMLandJSON() throws IOException, JAXBException {
097    String namespacePath = "/namespaces/";
098    NamespacesModel model;
099    Response response;
100
101    // Check that namespace does not yet exist via non-REST call.
102    Admin admin = TEST_UTIL.getAdmin();
103    assertFalse(doesNamespaceExist(admin, NAMESPACE1));
104    model = testNamespacesModel.buildTestModel();
105    testNamespacesModel.checkModel(model);
106
107    // Check that REST GET finds only default namespaces via XML and JSON responses.
108    response = client.get(namespacePath, Constants.MIMETYPE_XML);
109    assertEquals(200, response.getCode());
110    model = fromXML(response.getBody());
111    testNamespacesModel.checkModel(model, "hbase", "default");
112    response = client.get(namespacePath, Constants.MIMETYPE_JSON);
113    assertEquals(200, response.getCode());
114    model = testNamespacesModel.fromJSON(Bytes.toString(response.getBody()));
115    testNamespacesModel.checkModel(model, "hbase", "default");
116
117    // Create namespace and check that REST GET finds one additional namespace.
118    createNamespaceViaAdmin(admin, NAMESPACE1);
119    response = client.get(namespacePath, Constants.MIMETYPE_XML);
120    assertEquals(200, response.getCode());
121    model = fromXML(response.getBody());
122    testNamespacesModel.checkModel(model, NAMESPACE1, "hbase", "default");
123    response = client.get(namespacePath, Constants.MIMETYPE_JSON);
124    assertEquals(200, response.getCode());
125    model = testNamespacesModel.fromJSON(Bytes.toString(response.getBody()));
126    testNamespacesModel.checkModel(model, NAMESPACE1, "hbase", "default");
127
128    // Create another namespace and check that REST GET finds one additional namespace.
129    createNamespaceViaAdmin(admin, NAMESPACE2);
130    response = client.get(namespacePath, Constants.MIMETYPE_XML);
131    assertEquals(200, response.getCode());
132    model = fromXML(response.getBody());
133    testNamespacesModel.checkModel(model, NAMESPACE1, NAMESPACE2, "hbase", "default");
134    response = client.get(namespacePath, Constants.MIMETYPE_JSON);
135    assertEquals(200, response.getCode());
136    model = testNamespacesModel.fromJSON(Bytes.toString(response.getBody()));
137    testNamespacesModel.checkModel(model, NAMESPACE1, NAMESPACE2, "hbase", "default");
138
139    // Delete namespace and check that REST still finds correct namespaces.
140    admin.deleteNamespace(NAMESPACE1);
141    response = client.get(namespacePath, Constants.MIMETYPE_XML);
142    assertEquals(200, response.getCode());
143    model = fromXML(response.getBody());
144    testNamespacesModel.checkModel(model, NAMESPACE2, "hbase", "default");
145    response = client.get(namespacePath, Constants.MIMETYPE_JSON);
146    assertEquals(200, response.getCode());
147    model = testNamespacesModel.fromJSON(Bytes.toString(response.getBody()));
148    testNamespacesModel.checkModel(model, NAMESPACE2, "hbase", "default");
149
150    admin.deleteNamespace(NAMESPACE2);
151  }
152
153  @Test
154  public void testNamespaceListPBandDefault() throws IOException {
155    String schemaPath = "/namespaces/";
156    NamespacesModel model;
157    Response response;
158
159    // Check that namespace does not yet exist via non-REST call.
160    Admin admin = TEST_UTIL.getAdmin();
161    assertFalse(doesNamespaceExist(admin, NAMESPACE1));
162    model = testNamespacesModel.buildTestModel();
163    testNamespacesModel.checkModel(model);
164
165    // Check that REST GET finds only default namespaces via PB and default Accept header.
166    response = client.get(schemaPath, Constants.MIMETYPE_PROTOBUF);
167    assertEquals(200, response.getCode());
168    model.getObjectFromMessage(response.getBody());
169    testNamespacesModel.checkModel(model, "hbase", "default");
170    response = client.get(schemaPath);
171    assertEquals(200, response.getCode());
172
173    // Create namespace and check that REST GET finds one additional namespace.
174    createNamespaceViaAdmin(admin, NAMESPACE1);
175    response = client.get(schemaPath, Constants.MIMETYPE_PROTOBUF);
176    assertEquals(200, response.getCode());
177    model.getObjectFromMessage(response.getBody());
178    testNamespacesModel.checkModel(model, NAMESPACE1, "hbase", "default");
179    response = client.get(schemaPath);
180    assertEquals(200, response.getCode());
181
182    // Create another namespace and check that REST GET finds one additional namespace.
183    createNamespaceViaAdmin(admin, NAMESPACE2);
184    response = client.get(schemaPath, Constants.MIMETYPE_PROTOBUF);
185    assertEquals(200, response.getCode());
186    model.getObjectFromMessage(response.getBody());
187    testNamespacesModel.checkModel(model, NAMESPACE1, NAMESPACE2, "hbase", "default");
188    response = client.get(schemaPath);
189    assertEquals(200, response.getCode());
190
191    // Delete namespace and check that REST GET still finds correct namespaces.
192    admin.deleteNamespace(NAMESPACE1);
193    response = client.get(schemaPath, Constants.MIMETYPE_PROTOBUF);
194    assertEquals(200, response.getCode());
195    model.getObjectFromMessage(response.getBody());
196    testNamespacesModel.checkModel(model, NAMESPACE2, "hbase", "default");
197    response = client.get(schemaPath);
198    assertEquals(200, response.getCode());
199
200    admin.deleteNamespace(NAMESPACE2);
201  }
202}