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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org
.apache
.hadoop
.hbase
.rest
;
20 import static org
.junit
.Assert
.assertEquals
;
21 import static org
.junit
.Assert
.assertFalse
;
22 import static org
.junit
.Assert
.assertNotNull
;
24 import java
.io
.ByteArrayInputStream
;
25 import java
.io
.IOException
;
26 import java
.io
.StringWriter
;
27 import java
.util
.Collection
;
28 import javax
.xml
.bind
.JAXBContext
;
29 import javax
.xml
.bind
.JAXBException
;
30 import org
.apache
.hadoop
.conf
.Configuration
;
31 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
32 import org
.apache
.hadoop
.hbase
.HBaseCommonTestingUtil
;
33 import org
.apache
.hadoop
.hbase
.HBaseTestingUtil
;
34 import org
.apache
.hadoop
.hbase
.TableName
;
35 import org
.apache
.hadoop
.hbase
.client
.Admin
;
36 import org
.apache
.hadoop
.hbase
.rest
.client
.Client
;
37 import org
.apache
.hadoop
.hbase
.rest
.client
.Cluster
;
38 import org
.apache
.hadoop
.hbase
.rest
.client
.Response
;
39 import org
.apache
.hadoop
.hbase
.rest
.model
.ColumnSchemaModel
;
40 import org
.apache
.hadoop
.hbase
.rest
.model
.TableSchemaModel
;
41 import org
.apache
.hadoop
.hbase
.rest
.model
.TestTableSchemaModel
;
42 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
43 import org
.apache
.hadoop
.hbase
.testclassification
.RestTests
;
44 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
45 import org
.apache
.http
.Header
;
46 import org
.apache
.http
.message
.BasicHeader
;
47 import org
.junit
.After
;
48 import org
.junit
.AfterClass
;
49 import org
.junit
.BeforeClass
;
50 import org
.junit
.ClassRule
;
51 import org
.junit
.Test
;
52 import org
.junit
.experimental
.categories
.Category
;
53 import org
.junit
.runner
.RunWith
;
54 import org
.junit
.runners
.Parameterized
;
56 @Category({RestTests
.class, MediumTests
.class})
57 @RunWith(Parameterized
.class)
58 public class TestSchemaResource
{
60 public static final HBaseClassTestRule CLASS_RULE
=
61 HBaseClassTestRule
.forClass(TestSchemaResource
.class);
63 private static String TABLE1
= "TestSchemaResource1";
64 private static String TABLE2
= "TestSchemaResource2";
66 private static final HBaseTestingUtil TEST_UTIL
= new HBaseTestingUtil();
67 private static final HBaseRESTTestingUtility REST_TEST_UTIL
=
68 new HBaseRESTTestingUtility();
69 private static Client client
;
70 private static JAXBContext context
;
71 private static Configuration conf
;
72 private static TestTableSchemaModel testTableSchemaModel
;
73 private static Header extraHdr
= null;
75 private static boolean csrfEnabled
= true;
77 @Parameterized.Parameters
78 public static Collection
<Object
[]> parameters() {
79 return HBaseCommonTestingUtil
.BOOLEAN_PARAMETERIZED
;
82 public TestSchemaResource(Boolean csrf
) {
87 public static void setUpBeforeClass() throws Exception
{
88 conf
= TEST_UTIL
.getConfiguration();
89 conf
.setBoolean(RESTServer
.REST_CSRF_ENABLED_KEY
, csrfEnabled
);
91 conf
.set(RESTServer
.REST_CSRF_BROWSER_USERAGENTS_REGEX_KEY
, ".*");
93 extraHdr
= new BasicHeader(RESTServer
.REST_CSRF_CUSTOM_HEADER_DEFAULT
, "");
94 TEST_UTIL
.startMiniCluster();
95 REST_TEST_UTIL
.startServletContainer(conf
);
96 client
= new Client(new Cluster().add("localhost",
97 REST_TEST_UTIL
.getServletPort()));
98 testTableSchemaModel
= new TestTableSchemaModel();
99 context
= JAXBContext
.newInstance(
100 ColumnSchemaModel
.class,
101 TableSchemaModel
.class);
105 public static void tearDownAfterClass() throws Exception
{
106 REST_TEST_UTIL
.shutdownServletContainer();
107 TEST_UTIL
.shutdownMiniCluster();
111 public void tearDown() throws Exception
{
112 Admin admin
= TEST_UTIL
.getAdmin();
114 for (String table
: new String
[] {TABLE1
, TABLE2
}) {
115 TableName t
= TableName
.valueOf(table
);
116 if (admin
.tableExists(t
)) {
117 admin
.disableTable(t
);
118 admin
.deleteTable(t
);
122 conf
.set("hbase.rest.readonly", "false");
125 private static byte[] toXML(TableSchemaModel model
) throws JAXBException
{
126 StringWriter writer
= new StringWriter();
127 context
.createMarshaller().marshal(model
, writer
);
128 return Bytes
.toBytes(writer
.toString());
131 private static TableSchemaModel
fromXML(byte[] content
)
132 throws JAXBException
{
133 return (TableSchemaModel
) context
.createUnmarshaller()
134 .unmarshal(new ByteArrayInputStream(content
));
138 public void testTableCreateAndDeleteXML() throws IOException
, JAXBException
{
139 String schemaPath
= "/" + TABLE1
+ "/schema";
140 TableSchemaModel model
;
143 Admin admin
= TEST_UTIL
.getAdmin();
144 assertFalse("Table " + TABLE1
+ " should not exist",
145 admin
.tableExists(TableName
.valueOf(TABLE1
)));
148 model
= testTableSchemaModel
.buildTestModel(TABLE1
);
149 testTableSchemaModel
.checkModel(model
, TABLE1
);
151 // test put operation is forbidden without custom header
152 response
= client
.put(schemaPath
, Constants
.MIMETYPE_XML
, toXML(model
));
153 assertEquals(400, response
.getCode());
156 response
= client
.put(schemaPath
, Constants
.MIMETYPE_XML
, toXML(model
), extraHdr
);
157 assertEquals("put failed with csrf " + (csrfEnabled ?
"enabled" : "disabled"),
158 201, response
.getCode());
160 // recall the same put operation but in read-only mode
161 conf
.set("hbase.rest.readonly", "true");
162 response
= client
.put(schemaPath
, Constants
.MIMETYPE_XML
, toXML(model
), extraHdr
);
163 assertEquals(403, response
.getCode());
165 // retrieve the schema and validate it
166 response
= client
.get(schemaPath
, Constants
.MIMETYPE_XML
);
167 assertEquals(200, response
.getCode());
168 assertEquals(Constants
.MIMETYPE_XML
, response
.getHeader("content-type"));
169 model
= fromXML(response
.getBody());
170 testTableSchemaModel
.checkModel(model
, TABLE1
);
172 // with json retrieve the schema and validate it
173 response
= client
.get(schemaPath
, Constants
.MIMETYPE_JSON
);
174 assertEquals(200, response
.getCode());
175 assertEquals(Constants
.MIMETYPE_JSON
, response
.getHeader("content-type"));
176 model
= testTableSchemaModel
.fromJSON(Bytes
.toString(response
.getBody()));
177 testTableSchemaModel
.checkModel(model
, TABLE1
);
180 // test delete schema operation is forbidden without custom header
181 response
= client
.delete(schemaPath
);
182 assertEquals(400, response
.getCode());
185 // test delete schema operation is forbidden in read-only mode
186 response
= client
.delete(schemaPath
, extraHdr
);
187 assertEquals(403, response
.getCode());
189 // return read-only setting back to default
190 conf
.set("hbase.rest.readonly", "false");
192 // delete the table and make sure HBase concurs
193 response
= client
.delete(schemaPath
, extraHdr
);
194 assertEquals(200, response
.getCode());
195 assertFalse(admin
.tableExists(TableName
.valueOf(TABLE1
)));
199 public void testTableCreateAndDeletePB() throws IOException
{
200 String schemaPath
= "/" + TABLE2
+ "/schema";
201 TableSchemaModel model
;
204 Admin admin
= TEST_UTIL
.getAdmin();
205 assertFalse(admin
.tableExists(TableName
.valueOf(TABLE2
)));
208 model
= testTableSchemaModel
.buildTestModel(TABLE2
);
209 testTableSchemaModel
.checkModel(model
, TABLE2
);
212 // test put operation is forbidden without custom header
213 response
= client
.put(schemaPath
, Constants
.MIMETYPE_PROTOBUF
, model
.createProtobufOutput());
214 assertEquals(400, response
.getCode());
216 response
= client
.put(schemaPath
, Constants
.MIMETYPE_PROTOBUF
,
217 model
.createProtobufOutput(), extraHdr
);
218 assertEquals("put failed with csrf " + (csrfEnabled ?
"enabled" : "disabled"),
219 201, response
.getCode());
221 // recall the same put operation but in read-only mode
222 conf
.set("hbase.rest.readonly", "true");
223 response
= client
.put(schemaPath
, Constants
.MIMETYPE_PROTOBUF
,
224 model
.createProtobufOutput(), extraHdr
);
225 assertNotNull(extraHdr
);
226 assertEquals(403, response
.getCode());
228 // retrieve the schema and validate it
229 response
= client
.get(schemaPath
, Constants
.MIMETYPE_PROTOBUF
);
230 assertEquals(200, response
.getCode());
231 assertEquals(Constants
.MIMETYPE_PROTOBUF
, response
.getHeader("content-type"));
232 model
= new TableSchemaModel();
233 model
.getObjectFromMessage(response
.getBody());
234 testTableSchemaModel
.checkModel(model
, TABLE2
);
236 // retrieve the schema and validate it with alternate pbuf type
237 response
= client
.get(schemaPath
, Constants
.MIMETYPE_PROTOBUF_IETF
);
238 assertEquals(200, response
.getCode());
239 assertEquals(Constants
.MIMETYPE_PROTOBUF_IETF
, response
.getHeader("content-type"));
240 model
= new TableSchemaModel();
241 model
.getObjectFromMessage(response
.getBody());
242 testTableSchemaModel
.checkModel(model
, TABLE2
);
245 // test delete schema operation is forbidden without custom header
246 response
= client
.delete(schemaPath
);
247 assertEquals(400, response
.getCode());
250 // test delete schema operation is forbidden in read-only mode
251 response
= client
.delete(schemaPath
, extraHdr
);
252 assertEquals(403, response
.getCode());
254 // return read-only setting back to default
255 conf
.set("hbase.rest.readonly", "false");
257 // delete the table and make sure HBase concurs
258 response
= client
.delete(schemaPath
, extraHdr
);
259 assertEquals(200, response
.getCode());
260 assertFalse(admin
.tableExists(TableName
.valueOf(TABLE2
)));