mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-12 13:39:10 +08:00
Compare commits
4 Commits
6531929124
...
07793d8aae
Author | SHA1 | Date | |
---|---|---|---|
|
07793d8aae | ||
|
4b9ed97f8f | ||
|
ff73529a75 | ||
|
706082c62f |
@@ -6,19 +6,14 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
|
|||||||
|
|
||||||
In the project directory, you can run:
|
In the project directory, you can run:
|
||||||
|
|
||||||
### `npm start`
|
### `npm run start`
|
||||||
|
|
||||||
Runs the app in the development mode.\
|
Runs the app in the development mode.\
|
||||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
Open [http://localhost:3003](http://localhost:3000) to view it in your browser.
|
||||||
|
|
||||||
The page will reload when you make changes.\
|
The page will reload when you make changes.\
|
||||||
You may also see any lint errors in the console.
|
You may also see any lint errors in the console.
|
||||||
|
|
||||||
### `npm test`
|
|
||||||
|
|
||||||
Launches the test runner in the interactive watch mode.\
|
|
||||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
|
||||||
|
|
||||||
### `npm run build`
|
### `npm run build`
|
||||||
|
|
||||||
Builds the app for production to the `build` folder.\
|
Builds the app for production to the `build` folder.\
|
||||||
|
@@ -77,12 +77,12 @@ const remoteApi = {
|
|||||||
listUsers: async (brokerAddress) => {
|
listUsers: async (brokerAddress) => {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/listUsers?${params.toString()}`));
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/acls.query?${params.toString()}`));
|
||||||
return await response.json();
|
return await response.json();
|
||||||
},
|
},
|
||||||
|
|
||||||
createUser: async (brokerAddress, userInfo) => {
|
createUser: async (brokerAddress, userInfo) => {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createUser'), {
|
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createUser.do'), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({brokerAddress, userInfo})
|
body: JSON.stringify({brokerAddress, userInfo})
|
||||||
@@ -91,7 +91,7 @@ const remoteApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateUser: async (brokerAddress, userInfo) => {
|
updateUser: async (brokerAddress, userInfo) => {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateUser'), {
|
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateUser.do'), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({brokerAddress, userInfo})
|
body: JSON.stringify({brokerAddress, userInfo})
|
||||||
@@ -103,7 +103,7 @@ const remoteApi = {
|
|||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||||
params.append('username', username);
|
params.append('username', username);
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteUser?${params.toString()}`), {
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteUser.do?${params.toString()}`), {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
@@ -114,12 +114,12 @@ const remoteApi = {
|
|||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||||
if (searchParam) params.append('searchParam', searchParam);
|
if (searchParam) params.append('searchParam', searchParam);
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/listAcls?${params.toString()}`));
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/acls.query?${params.toString()}`));
|
||||||
return await response.json();
|
return await response.json();
|
||||||
},
|
},
|
||||||
|
|
||||||
createAcl: async (brokerAddress, subject, policies) => {
|
createAcl: async (brokerAddress, subject, policies) => {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createAcl'), {
|
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createAcl.do'), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({brokerAddress, subject, policies})
|
body: JSON.stringify({brokerAddress, subject, policies})
|
||||||
@@ -128,7 +128,7 @@ const remoteApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateAcl: async (brokerAddress, subject, policies) => {
|
updateAcl: async (brokerAddress, subject, policies) => {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateAcl'), {
|
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateAcl.do'), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({brokerAddress, subject, policies})
|
body: JSON.stringify({brokerAddress, subject, policies})
|
||||||
@@ -141,7 +141,7 @@ const remoteApi = {
|
|||||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||||
params.append('subject', subject);
|
params.append('subject', subject);
|
||||||
if (resource) params.append('resource', resource);
|
if (resource) params.append('resource', resource);
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteAcl?${params.toString()}`), {
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteAcl.do?${params.toString()}`), {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
@@ -376,9 +376,9 @@ const remoteApi = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
queryConsumerGroupList: async (skipSysGroup = false) => {
|
queryConsumerGroupList: async (skipSysGroup, address) => {
|
||||||
try {
|
try {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/consumer/groupList.query?skipSysGroup=${skipSysGroup}`));
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/consumer/groupList.query?skipSysGroup=${skipSysGroup}&address=${address}`));
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Form, Input, Typography, Modal } from 'antd';
|
import {Form, Input, Typography} from 'antd';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {useLanguage} from '../i18n/LanguageContext'; // 根据实际路径调整
|
import {useLanguage} from '../i18n/LanguageContext'; // 根据实际路径调整
|
||||||
|
|
||||||
|
@@ -16,9 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal, Button, Typography, Descriptions, Tag, Spin, notification } from 'antd';
|
import {Button, Descriptions, Modal, notification, Spin, Tag, Typography} from 'antd';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { ExclamationCircleOutlined, SyncOutlined } from '@ant-design/icons';
|
import {SyncOutlined} from '@ant-design/icons';
|
||||||
import {useLanguage} from '../i18n/LanguageContext';
|
import {useLanguage} from '../i18n/LanguageContext';
|
||||||
import {remoteApi} from '../api/remoteApi/remoteApi'; // 确保这个路径正确
|
import {remoteApi} from '../api/remoteApi/remoteApi'; // 确保这个路径正确
|
||||||
|
|
||||||
@@ -96,10 +96,14 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
|
|||||||
{messageDetail ? ( // 确保 messageDetail 存在时才渲染内容
|
{messageDetail ? ( // 确保 messageDetail 存在时才渲染内容
|
||||||
<>
|
<>
|
||||||
{/* 消息信息部分 */}
|
{/* 消息信息部分 */}
|
||||||
<Descriptions title={<Text strong>{t.MESSAGE_INFO}</Text>} bordered column={2} size="small" style={{ marginBottom: 20 }}>
|
<Descriptions title={<Text strong>{t.MESSAGE_INFO}</Text>} bordered column={2} size="small"
|
||||||
<Descriptions.Item label="Topic" span={2}><Text copyable>{messageDetail.messageView.topic}</Text></Descriptions.Item>
|
style={{marginBottom: 20}}>
|
||||||
<Descriptions.Item label="Message ID" span={2}><Text copyable>{messageDetail.messageView.msgId}</Text></Descriptions.Item>
|
<Descriptions.Item label="Topic" span={2}><Text
|
||||||
<Descriptions.Item label="StoreHost">{messageDetail.messageView.storeHost}</Descriptions.Item>
|
copyable>{messageDetail.messageView.topic}</Text></Descriptions.Item>
|
||||||
|
<Descriptions.Item label="Message ID" span={2}><Text
|
||||||
|
copyable>{messageDetail.messageView.msgId}</Text></Descriptions.Item>
|
||||||
|
<Descriptions.Item
|
||||||
|
label="StoreHost">{messageDetail.messageView.storeHost}</Descriptions.Item>
|
||||||
<Descriptions.Item label="BornHost">{messageDetail.messageView.bornHost}</Descriptions.Item>
|
<Descriptions.Item label="BornHost">{messageDetail.messageView.bornHost}</Descriptions.Item>
|
||||||
<Descriptions.Item label="StoreTime">
|
<Descriptions.Item label="StoreTime">
|
||||||
{moment(messageDetail.messageView.storeTimestamp).format("YYYY-MM-DD HH:mm:ss")}
|
{moment(messageDetail.messageView.storeTimestamp).format("YYYY-MM-DD HH:mm:ss")}
|
||||||
@@ -108,26 +112,33 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
|
|||||||
{moment(messageDetail.messageView.bornTimestamp).format("YYYY-MM-DD HH:mm:ss")}
|
{moment(messageDetail.messageView.bornTimestamp).format("YYYY-MM-DD HH:mm:ss")}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="Queue ID">{messageDetail.messageView.queueId}</Descriptions.Item>
|
<Descriptions.Item label="Queue ID">{messageDetail.messageView.queueId}</Descriptions.Item>
|
||||||
<Descriptions.Item label="Queue Offset">{messageDetail.messageView.queueOffset}</Descriptions.Item>
|
<Descriptions.Item
|
||||||
<Descriptions.Item label="StoreSize">{messageDetail.messageView.storeSize} bytes</Descriptions.Item>
|
label="Queue Offset">{messageDetail.messageView.queueOffset}</Descriptions.Item>
|
||||||
<Descriptions.Item label="ReconsumeTimes">{messageDetail.messageView.reconsumeTimes}</Descriptions.Item>
|
<Descriptions.Item
|
||||||
|
label="StoreSize">{messageDetail.messageView.storeSize} bytes</Descriptions.Item>
|
||||||
|
<Descriptions.Item
|
||||||
|
label="ReconsumeTimes">{messageDetail.messageView.reconsumeTimes}</Descriptions.Item>
|
||||||
<Descriptions.Item label="BodyCRC">{messageDetail.messageView.bodyCRC}</Descriptions.Item>
|
<Descriptions.Item label="BodyCRC">{messageDetail.messageView.bodyCRC}</Descriptions.Item>
|
||||||
<Descriptions.Item label="SysFlag">{messageDetail.messageView.sysFlag}</Descriptions.Item>
|
<Descriptions.Item label="SysFlag">{messageDetail.messageView.sysFlag}</Descriptions.Item>
|
||||||
<Descriptions.Item label="Flag">{messageDetail.messageView.flag}</Descriptions.Item>
|
<Descriptions.Item label="Flag">{messageDetail.messageView.flag}</Descriptions.Item>
|
||||||
<Descriptions.Item label="PreparedTransactionOffset">{messageDetail.messageView.preparedTransactionOffset}</Descriptions.Item>
|
<Descriptions.Item
|
||||||
|
label="PreparedTransactionOffset">{messageDetail.messageView.preparedTransactionOffset}</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
|
|
||||||
{/* 消息属性部分 */}
|
{/* 消息属性部分 */}
|
||||||
{Object.keys(messageDetail.messageView.properties).length > 0 && (
|
{Object.keys(messageDetail.messageView.properties).length > 0 && (
|
||||||
<Descriptions title={<Text strong>{t.MESSAGE_PROPERTIES}</Text>} bordered column={1} size="small" style={{ marginBottom: 20 }}>
|
<Descriptions title={<Text strong>{t.MESSAGE_PROPERTIES}</Text>} bordered column={1}
|
||||||
|
size="small" style={{marginBottom: 20}}>
|
||||||
{Object.entries(messageDetail.messageView.properties).map(([key, value]) => (
|
{Object.entries(messageDetail.messageView.properties).map(([key, value]) => (
|
||||||
<Descriptions.Item label={key} key={key}><Text copyable>{value}</Text></Descriptions.Item>
|
<Descriptions.Item label={key} key={key}><Text
|
||||||
|
copyable>{value}</Text></Descriptions.Item>
|
||||||
))}
|
))}
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 消息体部分 */}
|
{/* 消息体部分 */}
|
||||||
<Descriptions title={<Text strong>{t.MESSAGE_BODY}</Text>} bordered column={1} size="small" style={{ marginBottom: 20 }}>
|
<Descriptions title={<Text strong>{t.MESSAGE_BODY}</Text>} bordered column={1} size="small"
|
||||||
|
style={{marginBottom: 20}}>
|
||||||
<Descriptions.Item>
|
<Descriptions.Item>
|
||||||
<Paragraph
|
<Paragraph
|
||||||
copyable
|
copyable
|
||||||
@@ -148,7 +159,8 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
|
|||||||
<Text strong>{t.MESSAGE_TRACKING}</Text>
|
<Text strong>{t.MESSAGE_TRACKING}</Text>
|
||||||
<div style={{marginTop: 10}}>
|
<div style={{marginTop: 10}}>
|
||||||
{messageDetail.messageTrackList.map((track, index) => (
|
{messageDetail.messageTrackList.map((track, index) => (
|
||||||
<Descriptions bordered column={1} size="small" key={index} style={{ marginBottom: 15 }}>
|
<Descriptions bordered column={1} size="small" key={index}
|
||||||
|
style={{marginBottom: 15}}>
|
||||||
<Descriptions.Item label={t.CONSUMER_GROUP}>
|
<Descriptions.Item label={t.CONSUMER_GROUP}>
|
||||||
{track.consumerGroup}
|
{track.consumerGroup}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
@@ -181,7 +193,10 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
|
|||||||
ellipsis={{
|
ellipsis={{
|
||||||
rows: 2, // 默认显示2行
|
rows: 2, // 默认显示2行
|
||||||
expandable: true,
|
expandable: true,
|
||||||
symbol: <Text style={{ color: '#1890ff', cursor: 'pointer' }}>{t.READ_MORE}</Text>, // 蓝色展开文本
|
symbol: <Text style={{
|
||||||
|
color: '#1890ff',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}>{t.READ_MORE}</Text>, // 蓝色展开文本
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{track.exceptionDesc}
|
{track.exceptionDesc}
|
||||||
@@ -198,7 +213,8 @@ const MessageDetailViewDialog = ({ visible, onCancel, messageId, topic, onResend
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
// 当 messageDetail 为 null 时,可以显示一个占位符或者不显示内容
|
// 当 messageDetail 为 null 时,可以显示一个占位符或者不显示内容
|
||||||
!loading && !error && <Paragraph style={{ textAlign: 'center' }}>{t.NO_MESSAGE_DETAIL_AVAILABLE}</Paragraph>
|
!loading && !error &&
|
||||||
|
<Paragraph style={{textAlign: 'center'}}>{t.NO_MESSAGE_DETAIL_AVAILABLE}</Paragraph>
|
||||||
)}
|
)}
|
||||||
</Spin>
|
</Spin>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useEffect, useRef} from 'react';
|
import React, {useEffect, useRef} from 'react';
|
||||||
import { Form, Input, Typography, Collapse, Table, Tag } from 'antd';
|
import {Collapse, Form, Input, Table, Tag, Typography} from 'antd';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {useLanguage} from '../i18n/LanguageContext';
|
import {useLanguage} from '../i18n/LanguageContext';
|
||||||
import Paragraph from "antd/es/skeleton/Paragraph";
|
import Paragraph from "antd/es/skeleton/Paragraph";
|
||||||
@@ -125,6 +125,7 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
|
|||||||
}
|
}
|
||||||
return `Cost Time: ${formatCostTimeStr(costTime)}<br/>`
|
return `Cost Time: ${formatCostTimeStr(costTime)}<br/>`
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTimeStamp(timestamp) {
|
function buildTimeStamp(timestamp) {
|
||||||
if (timestamp < 0) {
|
if (timestamp < 0) {
|
||||||
return 'N/A';
|
return 'N/A';
|
||||||
@@ -323,50 +324,130 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
|
|||||||
|
|
||||||
// ... (rest of your existing component code)
|
// ... (rest of your existing component code)
|
||||||
const transactionColumns = [
|
const transactionColumns = [
|
||||||
{ title: t.TIMESTAMP, dataIndex: 'beginTimestamp', key: 'beginTimestamp', align: 'center', render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss.SSS') },
|
{
|
||||||
{ title: t.TRANSACTION_STATE, dataIndex: 'transactionState', key: 'transactionState', align: 'center', render: (text) => <Tag color={text === 'COMMIT_MESSAGE' ? 'green' : (text === 'ROLLBACK_MESSAGE' ? 'red' : 'default')}>{text}</Tag> },
|
title: t.TIMESTAMP,
|
||||||
{ title: t.FROM_TRANSACTION_CHECK, dataIndex: 'fromTransactionCheck', key: 'fromTransactionCheck', align: 'center', render: (text) => (text ? <Tag color="blue">{t.YES}</Tag> : <Tag color="purple">{t.NO}</Tag>) },
|
dataIndex: 'beginTimestamp',
|
||||||
|
key: 'beginTimestamp',
|
||||||
|
align: 'center',
|
||||||
|
render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss.SSS')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t.TRANSACTION_STATE,
|
||||||
|
dataIndex: 'transactionState',
|
||||||
|
key: 'transactionState',
|
||||||
|
align: 'center',
|
||||||
|
render: (text) => <Tag
|
||||||
|
color={text === 'COMMIT_MESSAGE' ? 'green' : (text === 'ROLLBACK_MESSAGE' ? 'red' : 'default')}>{text}</Tag>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t.FROM_TRANSACTION_CHECK,
|
||||||
|
dataIndex: 'fromTransactionCheck',
|
||||||
|
key: 'fromTransactionCheck',
|
||||||
|
align: 'center',
|
||||||
|
render: (text) => (text ? <Tag color="blue">{t.YES}</Tag> : <Tag color="purple">{t.NO}</Tag>)
|
||||||
|
},
|
||||||
{title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center'},
|
{title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center'},
|
||||||
{title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center'},
|
{title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center'},
|
||||||
];
|
];
|
||||||
|
|
||||||
const consumeColumns = [
|
const consumeColumns = [
|
||||||
{ title: t.BEGIN_TIMESTAMP, dataIndex: 'beginTimestamp', key: 'beginTimestamp', align: 'center', render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS') },
|
{
|
||||||
{ title: t.END_TIMESTAMP, dataIndex: 'endTimestamp', key: 'endTimestamp', align: 'center', render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS') },
|
title: t.BEGIN_TIMESTAMP,
|
||||||
{ title: t.COST_TIME, dataIndex: 'costTime', key: 'costTime', align: 'center', render: (text) => text < 0 ? 'N/A' : `${text === 0 ? '<1' : text}ms` },
|
dataIndex: 'beginTimestamp',
|
||||||
{ title: t.STATUS, dataIndex: 'status', key: 'status', align: 'center', render: (text) => <Tag color={text === 'SUCCESS' ? 'green' : (text === 'FAILED' ? 'red' : 'default')}>{text}</Tag> },
|
key: 'beginTimestamp',
|
||||||
{ title: t.RETRY_TIMES, dataIndex: 'retryTimes', key: 'retryTimes', align: 'center', render: (text) => text < 0 ? 'N/A' : text },
|
align: 'center',
|
||||||
|
render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t.END_TIMESTAMP,
|
||||||
|
dataIndex: 'endTimestamp',
|
||||||
|
key: 'endTimestamp',
|
||||||
|
align: 'center',
|
||||||
|
render: (text) => text < 0 ? 'N/A' : moment(text).format('YYYY-MM-DD HH:mm:ss.SSS')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t.COST_TIME,
|
||||||
|
dataIndex: 'costTime',
|
||||||
|
key: 'costTime',
|
||||||
|
align: 'center',
|
||||||
|
render: (text) => text < 0 ? 'N/A' : `${text === 0 ? '<1' : text}ms`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t.STATUS,
|
||||||
|
dataIndex: 'status',
|
||||||
|
key: 'status',
|
||||||
|
align: 'center',
|
||||||
|
render: (text) => <Tag
|
||||||
|
color={text === 'SUCCESS' ? 'green' : (text === 'FAILED' ? 'red' : 'default')}>{text}</Tag>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t.RETRY_TIMES,
|
||||||
|
dataIndex: 'retryTimes',
|
||||||
|
key: 'retryTimes',
|
||||||
|
align: 'center',
|
||||||
|
render: (text) => text < 0 ? 'N/A' : text
|
||||||
|
},
|
||||||
{title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center'},
|
{title: t.CLIENT_HOST, dataIndex: 'clientHost', key: 'clientHost', align: 'center'},
|
||||||
{title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center'},
|
{title: t.STORE_HOST, dataIndex: 'storeHost', key: 'storeHost', align: 'center'},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{padding: '20px', backgroundColor: '#f0f2f5'}}>
|
<div style={{padding: '20px', backgroundColor: '#f0f2f5'}}>
|
||||||
<div style={{ marginBottom: '20px', borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)' }}>
|
<div style={{
|
||||||
|
marginBottom: '20px',
|
||||||
|
borderRadius: '8px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'
|
||||||
|
}}>
|
||||||
<Collapse defaultActiveKey={['messageTraceGraph']} expandIconPosition="right">
|
<Collapse defaultActiveKey={['messageTraceGraph']} expandIconPosition="right">
|
||||||
<Panel header={<Typography.Title level={3} style={{ margin: 0, color: '#333' }}>{t.MESSAGE_TRACE_GRAPH}</Typography.Title>} key="messageTraceGraph">
|
<Panel header={<Typography.Title level={3} style={{
|
||||||
<div ref={messageTraceGraphRef} style={{ height: 500, width: '100%', backgroundColor: '#fff', padding: '10px' }}>
|
margin: 0,
|
||||||
|
color: '#333'
|
||||||
|
}}>{t.MESSAGE_TRACE_GRAPH}</Typography.Title>} key="messageTraceGraph">
|
||||||
|
<div ref={messageTraceGraphRef}
|
||||||
|
style={{height: 500, width: '100%', backgroundColor: '#fff', padding: '10px'}}>
|
||||||
{/* ECharts message trace graph will be rendered here */}
|
{/* ECharts message trace graph will be rendered here */}
|
||||||
{(!producerNode && subscriptionNodeList.length === 0) && (
|
{(!producerNode && subscriptionNodeList.length === 0) && (
|
||||||
<Text type="secondary" style={{ display: 'block', textAlign: 'center', marginTop: '150px' }}>{t.TRACE_GRAPH_PLACEHOLDER}</Text>
|
<Text type="secondary" style={{
|
||||||
|
display: 'block',
|
||||||
|
textAlign: 'center',
|
||||||
|
marginTop: '150px'
|
||||||
|
}}>{t.TRACE_GRAPH_PLACEHOLDER}</Text>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginBottom: '20px', borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)' }}>
|
<div style={{
|
||||||
|
marginBottom: '20px',
|
||||||
|
borderRadius: '8px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'
|
||||||
|
}}>
|
||||||
<Collapse defaultActiveKey={['sendMessageTrace']} expandIconPosition="right">
|
<Collapse defaultActiveKey={['sendMessageTrace']} expandIconPosition="right">
|
||||||
<Panel header={<Typography.Title level={3} style={{ margin: 0, color: '#333' }}>{t.SEND_MESSAGE_TRACE}</Typography.Title>} key="sendMessageTrace">
|
<Panel header={<Typography.Title level={3} style={{
|
||||||
|
margin: 0,
|
||||||
|
color: '#333'
|
||||||
|
}}>{t.SEND_MESSAGE_TRACE}</Typography.Title>} key="sendMessageTrace">
|
||||||
{!producerNode ? (
|
{!producerNode ? (
|
||||||
<Paragraph style={{ padding: '16px', textAlign: 'center', color: '#666' }}>{t.NO_PRODUCER_TRACE_DATA}</Paragraph>
|
<Paragraph style={{
|
||||||
|
padding: '16px',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#666'
|
||||||
|
}}>{t.NO_PRODUCER_TRACE_DATA}</Paragraph>
|
||||||
) : (
|
) : (
|
||||||
<div style={{padding: '16px', backgroundColor: '#fff'}}>
|
<div style={{padding: '16px', backgroundColor: '#fff'}}>
|
||||||
<Typography.Title level={4} style={{marginBottom: '20px'}}>
|
<Typography.Title level={4} style={{marginBottom: '20px'}}>
|
||||||
{t.SEND_MESSAGE_INFO} : ( {t.MESSAGE_ID} <Text strong copyable>{producerNode.msgId}</Text> )
|
{t.SEND_MESSAGE_INFO} : ( {t.MESSAGE_ID} <Text strong
|
||||||
|
copyable>{producerNode.msgId}</Text> )
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
<Form layout="vertical" colon={false}>
|
<Form layout="vertical" colon={false}>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: '16px' }}>
|
<div style={{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
|
||||||
|
gap: '16px'
|
||||||
|
}}>
|
||||||
<Form.Item label={<Text strong>{t.TOPIC}</Text>}>
|
<Form.Item label={<Text strong>{t.TOPIC}</Text>}>
|
||||||
<Input value={producerNode.topic} readOnly/>
|
<Input value={producerNode.topic} readOnly/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -381,13 +462,19 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label={<Text strong>{t.BEGIN_TIMESTAMP}</Text>}>
|
<Form.Item label={<Text strong>{t.BEGIN_TIMESTAMP}</Text>}>
|
||||||
<Input value={moment(producerNode.traceNode.beginTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')} readOnly />
|
<Input
|
||||||
|
value={moment(producerNode.traceNode.beginTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')}
|
||||||
|
readOnly/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={<Text strong>{t.END_TIMESTAMP}</Text>}>
|
<Form.Item label={<Text strong>{t.END_TIMESTAMP}</Text>}>
|
||||||
<Input value={moment(producerNode.traceNode.endTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')} readOnly />
|
<Input
|
||||||
|
value={moment(producerNode.traceNode.endTimestamp).format('YYYY-MM-DD HH:mm:ss.SSS')}
|
||||||
|
readOnly/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={<Text strong>{t.COST_TIME}</Text>}>
|
<Form.Item label={<Text strong>{t.COST_TIME}</Text>}>
|
||||||
<Input value={`${producerNode.traceNode.costTime === 0 ? '<1' : producerNode.traceNode.costTime}ms`} readOnly />
|
<Input
|
||||||
|
value={`${producerNode.traceNode.costTime === 0 ? '<1' : producerNode.traceNode.costTime}ms`}
|
||||||
|
readOnly/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={<Text strong>{t.MSG_TYPE}</Text>}>
|
<Form.Item label={<Text strong>{t.MSG_TYPE}</Text>}>
|
||||||
<Input value={producerNode.traceNode.msgType} readOnly/>
|
<Input value={producerNode.traceNode.msgType} readOnly/>
|
||||||
@@ -410,7 +497,8 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
|
|||||||
|
|
||||||
{producerNode.transactionNodeList && producerNode.transactionNodeList.length > 0 && (
|
{producerNode.transactionNodeList && producerNode.transactionNodeList.length > 0 && (
|
||||||
<div style={{marginTop: '30px'}}>
|
<div style={{marginTop: '30px'}}>
|
||||||
<Typography.Title level={4} style={{ marginBottom: '15px' }}>{t.CHECK_TRANSACTION_INFO}:</Typography.Title>
|
<Typography.Title level={4}
|
||||||
|
style={{marginBottom: '15px'}}>{t.CHECK_TRANSACTION_INFO}:</Typography.Title>
|
||||||
<Table
|
<Table
|
||||||
columns={transactionColumns}
|
columns={transactionColumns}
|
||||||
dataSource={producerNode.transactionNodeList}
|
dataSource={producerNode.transactionNodeList}
|
||||||
@@ -430,9 +518,16 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
|
|||||||
|
|
||||||
<div style={{borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'}}>
|
<div style={{borderRadius: '8px', overflow: 'hidden', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)'}}>
|
||||||
<Collapse defaultActiveKey={['consumeMessageTrace']} expandIconPosition="right">
|
<Collapse defaultActiveKey={['consumeMessageTrace']} expandIconPosition="right">
|
||||||
<Panel header={<Typography.Title level={3} style={{ margin: 0, color: '#333' }}>{t.CONSUME_MESSAGE_TRACE}</Typography.Title>} key="consumeMessageTrace">
|
<Panel header={<Typography.Title level={3} style={{
|
||||||
|
margin: 0,
|
||||||
|
color: '#333'
|
||||||
|
}}>{t.CONSUME_MESSAGE_TRACE}</Typography.Title>} key="consumeMessageTrace">
|
||||||
{subscriptionNodeList.length === 0 ? (
|
{subscriptionNodeList.length === 0 ? (
|
||||||
<Paragraph style={{ padding: '16px', textAlign: 'center', color: '#666' }}>{t.NO_CONSUMER_TRACE_DATA}</Paragraph>
|
<Paragraph style={{
|
||||||
|
padding: '16px',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#666'
|
||||||
|
}}>{t.NO_CONSUMER_TRACE_DATA}</Paragraph>
|
||||||
) : (
|
) : (
|
||||||
<div style={{padding: '16px', backgroundColor: '#fff'}}>
|
<div style={{padding: '16px', backgroundColor: '#fff'}}>
|
||||||
{subscriptionNodeList.map(subscriptionNode => (
|
{subscriptionNodeList.map(subscriptionNode => (
|
||||||
@@ -443,7 +538,9 @@ const MessageTraceDetailViewDialog = ({ ngDialogData }) => {
|
|||||||
ghost
|
ghost
|
||||||
>
|
>
|
||||||
<Panel
|
<Panel
|
||||||
header={<Typography.Title level={4} style={{ margin: 0 }}>{t.SUBSCRIPTION_GROUP}: <Text strong>{subscriptionNode.subscriptionGroup}</Text></Typography.Title>}
|
header={<Typography.Title level={4}
|
||||||
|
style={{margin: 0}}>{t.SUBSCRIPTION_GROUP}: <Text
|
||||||
|
strong>{subscriptionNode.subscriptionGroup}</Text></Typography.Title>}
|
||||||
key={subscriptionNode.subscriptionGroup}
|
key={subscriptionNode.subscriptionGroup}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
|
@@ -16,8 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useEffect, useState} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import { Layout, Menu, Dropdown, Button, Drawer, Grid, Space } from 'antd';
|
import {Button, Drawer, Dropdown, Grid, Layout, Menu, Space} from 'antd';
|
||||||
import {GlobalOutlined, DownOutlined, UserOutlined, MenuOutlined, BgColorsOutlined} from '@ant-design/icons';
|
import {BgColorsOutlined, DownOutlined, GlobalOutlined, MenuOutlined, UserOutlined} from '@ant-design/icons';
|
||||||
import {useLocation, useNavigate} from 'react-router-dom';
|
import {useLocation, useNavigate} from 'react-router-dom';
|
||||||
import {useLanguage} from '../i18n/LanguageContext';
|
import {useLanguage} from '../i18n/LanguageContext';
|
||||||
import {useTheme} from "../store/context/ThemeContext";
|
import {useTheme} from "../store/context/ThemeContext";
|
||||||
@@ -102,7 +102,7 @@ const Navbar = ({ rmqVersion = true, showAcl = true}) => {
|
|||||||
{key: 'message', label: t.MESSAGE},
|
{key: 'message', label: t.MESSAGE},
|
||||||
{key: 'dlqMessage', label: t.DLQ_MESSAGE},
|
{key: 'dlqMessage', label: t.DLQ_MESSAGE},
|
||||||
{key: 'messageTrace', label: t.MESSAGETRACE},
|
{key: 'messageTrace', label: t.MESSAGETRACE},
|
||||||
...(showAcl ? [{ key: 'acl', label: t.WHITE_LIST }] : []),
|
...(showAcl ? [{key: 'acl', label: t.ACL_MANAGEMENT}] : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Determine if it's a small screen (e.g., less than md)
|
// Determine if it's a small screen (e.g., less than md)
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Input, Select, Tag, Space } from 'antd';
|
import {Input, Select, Space, Tag} from 'antd';
|
||||||
import {PlusOutlined} from '@ant-design/icons';
|
import {PlusOutlined} from '@ant-design/icons';
|
||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Input, Select} from 'antd';
|
import {Input, Select} from 'antd';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import { Modal, Table, Spin } from 'antd';
|
import {Modal, Spin, Table} from 'antd';
|
||||||
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
||||||
import {useLanguage} from '../../i18n/LanguageContext';
|
import {useLanguage} from '../../i18n/LanguageContext';
|
||||||
|
|
||||||
|
@@ -16,12 +16,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useEffect, useState} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import { Button, Descriptions, Form, Input, Select, Switch, message } from 'antd';
|
import {Button, Descriptions, Form, Input, message, Select, Switch} from 'antd';
|
||||||
import {remoteApi} from '../../api/remoteApi/remoteApi'; // 确保路径正确
|
import {remoteApi} from '../../api/remoteApi/remoteApi'; // 确保路径正确
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
const ConsumerConfigItem = ({ initialConfig, isAddConfig, group, brokerName, allBrokerList, allClusterNames,onCancel, onSuccess, t }) => {
|
const ConsumerConfigItem = ({
|
||||||
|
initialConfig,
|
||||||
|
isAddConfig,
|
||||||
|
group,
|
||||||
|
brokerName,
|
||||||
|
allBrokerList,
|
||||||
|
allClusterNames,
|
||||||
|
onCancel,
|
||||||
|
onSuccess,
|
||||||
|
t
|
||||||
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [currentBrokerName, setCurrentBrokerName] = useState(brokerName);
|
const [currentBrokerName, setCurrentBrokerName] = useState(brokerName);
|
||||||
|
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import { Modal, Table, Spin } from 'antd';
|
import {Modal, Spin, Table} from 'antd';
|
||||||
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
||||||
import {useLanguage} from '../../i18n/LanguageContext';
|
import {useLanguage} from '../../i18n/LanguageContext';
|
||||||
|
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import { Modal, Spin, Checkbox, Button, notification } from 'antd';
|
import {Button, Checkbox, Modal, notification, Spin} from 'antd';
|
||||||
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
||||||
import {useLanguage} from '../../i18n/LanguageContext';
|
import {useLanguage} from '../../i18n/LanguageContext';
|
||||||
|
|
||||||
|
@@ -63,7 +63,11 @@ const ConsumerViewDialog = ({ visible, onClose, topic, consumerData, consumerGro
|
|||||||
bordered
|
bordered
|
||||||
pagination={false}
|
pagination={false}
|
||||||
showHeader={false}
|
showHeader={false}
|
||||||
dataSource={[{ consumerGroup, diffTotal: consumeDetail.diffTotal, lastTimestamp: consumeDetail.lastTimestamp }]}
|
dataSource={[{
|
||||||
|
consumerGroup,
|
||||||
|
diffTotal: consumeDetail.diffTotal,
|
||||||
|
lastTimestamp: consumeDetail.lastTimestamp
|
||||||
|
}]}
|
||||||
columns={[
|
columns={[
|
||||||
{title: t.SUBSCRIPTION_GROUP, dataIndex: 'consumerGroup', key: 'consumerGroup'},
|
{title: t.SUBSCRIPTION_GROUP, dataIndex: 'consumerGroup', key: 'consumerGroup'},
|
||||||
{title: t.DELAY, dataIndex: 'diffTotal', key: 'diffTotal'},
|
{title: t.DELAY, dataIndex: 'diffTotal', key: 'diffTotal'},
|
||||||
|
@@ -30,7 +30,11 @@ const RouterViewDialog = ({ visible, onClose, topic, routeData, t }) => {
|
|||||||
key: 'brokerAddrs',
|
key: 'brokerAddrs',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Table
|
<Table
|
||||||
dataSource={Object.entries(record.brokerAddrs || []).map(([key, value]) => ({ key, idx: key, address: value }))}
|
dataSource={Object.entries(record.brokerAddrs || []).map(([key, value]) => ({
|
||||||
|
key,
|
||||||
|
idx: key,
|
||||||
|
address: value
|
||||||
|
}))}
|
||||||
columns={[
|
columns={[
|
||||||
{title: 'Index', dataIndex: 'idx', key: 'idx'},
|
{title: 'Index', dataIndex: 'idx', key: 'idx'},
|
||||||
{title: 'Address', dataIndex: 'address', key: 'address'},
|
{title: 'Address', dataIndex: 'address', key: 'address'},
|
||||||
|
@@ -61,5 +61,4 @@ const SendResultDialog = ({ visible, onClose, result, t }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default SendResultDialog;
|
export default SendResultDialog;
|
||||||
|
@@ -18,7 +18,14 @@
|
|||||||
import {Button, Form, message, Modal, Select} from "antd";
|
import {Button, Form, message, Modal, Select} from "antd";
|
||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
|
|
||||||
const SkipMessageAccumulateDialog = ({ visible, onClose, topic, allConsumerGroupList, handleSkipMessageAccumulate, t }) => {
|
const SkipMessageAccumulateDialog = ({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
topic,
|
||||||
|
allConsumerGroupList,
|
||||||
|
handleSkipMessageAccumulate,
|
||||||
|
t
|
||||||
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [selectedConsumerGroup, setSelectedConsumerGroup] = useState([]);
|
const [selectedConsumerGroup, setSelectedConsumerGroup] = useState([]);
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
// TopicSingleModifyForm.js
|
// TopicSingleModifyForm.js
|
||||||
import React, {useEffect} from "react";
|
import React, {useEffect} from "react";
|
||||||
import {Button, Form, Input, Select, Divider, Row, Col} from "antd";
|
import {Button, Col, Divider, Form, Input, Row, Select} from "antd";
|
||||||
|
|
||||||
const TopicSingleModifyForm = ({
|
const TopicSingleModifyForm = ({
|
||||||
initialData,
|
initialData,
|
||||||
@@ -68,7 +68,8 @@ const TopicSingleModifyForm = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{paddingBottom: 24}}>
|
<div style={{paddingBottom: 24}}>
|
||||||
{bIsUpdate && <Divider orientation="left">{`${t.TOPIC_CONFIG} - ${initialData.brokerNameList ? initialData.brokerNameList.join(', ') : t.UNKNOWN_BROKER}`}</Divider>}
|
{bIsUpdate && <Divider
|
||||||
|
orientation="left">{`${t.TOPIC_CONFIG} - ${initialData.brokerNameList ? initialData.brokerNameList.join(', ') : t.UNKNOWN_BROKER}`}</Divider>}
|
||||||
<Row justify="center"> {/* 使用 Row 居中内容 */}
|
<Row justify="center"> {/* 使用 Row 居中内容 */}
|
||||||
<Col span={16}> {/* 表单内容占据 12 栅格宽度,并自动居中 */}
|
<Col span={16}> {/* 表单内容占据 12 栅格宽度,并自动居中 */}
|
||||||
<Form
|
<Form
|
||||||
|
@@ -15,12 +15,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { createContext, useState, useContext } from 'react';
|
import React, {createContext, useContext, useState} from 'react';
|
||||||
import {translations} from '../i18n';
|
import {translations} from '../i18n';
|
||||||
|
|
||||||
const LanguageContext = createContext({
|
const LanguageContext = createContext({
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
setLang: () => {},
|
setLang: () => {
|
||||||
|
},
|
||||||
t: translations['en'], // 当前语言的文本资源
|
t: translations['en'], // 当前语言的文本资源
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -156,7 +156,6 @@ export const translations = {
|
|||||||
"NO_MATCH_RESULT": "没有查到符合条件的结果",
|
"NO_MATCH_RESULT": "没有查到符合条件的结果",
|
||||||
"BATCH_RESEND": "批量重发",
|
"BATCH_RESEND": "批量重发",
|
||||||
"BATCH_EXPORT": "批量导出",
|
"BATCH_EXPORT": "批量导出",
|
||||||
"WHITE_LIST":"白名单",
|
|
||||||
"ACCOUNT_INFO": "账户信息",
|
"ACCOUNT_INFO": "账户信息",
|
||||||
"IS_ADMIN": "是否管理员",
|
"IS_ADMIN": "是否管理员",
|
||||||
"DEFAULT_TOPIC_PERM": "topic默认权限",
|
"DEFAULT_TOPIC_PERM": "topic默认权限",
|
||||||
@@ -279,6 +278,12 @@ export const translations = {
|
|||||||
"ENTER_IP_HINT": "请输入 IP 地址,按回车键添加,支持 IPv4、IPv6 和 CIDR",
|
"ENTER_IP_HINT": "请输入 IP 地址,按回车键添加,支持 IPv4、IPv6 和 CIDR",
|
||||||
"PLEASE_ENTER_DECISION": "请输入决策!",
|
"PLEASE_ENTER_DECISION": "请输入决策!",
|
||||||
"MENU": "菜单",
|
"MENU": "菜单",
|
||||||
|
"SELECT_PROXY": "选择代理",
|
||||||
|
"ENABLE_PROXY": "启用代理",
|
||||||
|
"PROXY_DISABLED": "代理禁用",
|
||||||
|
"PROXY_ENABLED": "代理启用",
|
||||||
|
"BROKER_OVERVIEW": "Broker概览",
|
||||||
|
"TOTAL_MSG_RECEIVED_TODAY": "今天接收的总消息数",
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
"DEFAULT": "Default",
|
"DEFAULT": "Default",
|
||||||
@@ -325,7 +330,7 @@ export const translations = {
|
|||||||
"ADDRESS": "Address",
|
"ADDRESS": "Address",
|
||||||
"VERSION": "Version",
|
"VERSION": "Version",
|
||||||
"PRO_MSG_TPS": "Produce Message TPS",
|
"PRO_MSG_TPS": "Produce Message TPS",
|
||||||
"CUS_MSG_TPS": "Consume Message TPS",
|
"CUS_MSG_TPS": "Consumer Message TPS",
|
||||||
"YESTERDAY_PRO_COUNT": "Yesterday Produce Count",
|
"YESTERDAY_PRO_COUNT": "Yesterday Produce Count",
|
||||||
"YESTERDAY_CUS_COUNT": "Yesterday Consume Count",
|
"YESTERDAY_CUS_COUNT": "Yesterday Consume Count",
|
||||||
"TODAY_PRO_COUNT": "Today Produce Count",
|
"TODAY_PRO_COUNT": "Today Produce Count",
|
||||||
@@ -421,7 +426,6 @@ export const translations = {
|
|||||||
"NO_MATCH_RESULT": "no match result",
|
"NO_MATCH_RESULT": "no match result",
|
||||||
"BATCH_RESEND": "batchReSend",
|
"BATCH_RESEND": "batchReSend",
|
||||||
"BATCH_EXPORT": "batchExport",
|
"BATCH_EXPORT": "batchExport",
|
||||||
"WHITE_LIST":"White List",
|
|
||||||
"ACCOUNT_INFO": "Account Info",
|
"ACCOUNT_INFO": "Account Info",
|
||||||
"IS_ADMIN": "Is Admin",
|
"IS_ADMIN": "Is Admin",
|
||||||
"DEFAULT_TOPIC_PERM": "Default Topic Permission",
|
"DEFAULT_TOPIC_PERM": "Default Topic Permission",
|
||||||
@@ -536,6 +540,13 @@ export const translations = {
|
|||||||
"ENTER_IP_HINT": "Please enter IP address, press Enter to add. Supports IPv4, IPv6, and CIDR.",
|
"ENTER_IP_HINT": "Please enter IP address, press Enter to add. Supports IPv4, IPv6, and CIDR.",
|
||||||
"PLEASE_ENTER_DECISION": "Please enter decision!",
|
"PLEASE_ENTER_DECISION": "Please enter decision!",
|
||||||
"MENU": "Menu",
|
"MENU": "Menu",
|
||||||
|
"SELECT_PROXY": "Select Proxy",
|
||||||
|
"ENABLE_PROXY": "Enable Proxy",
|
||||||
|
"PROXY_DISABLED": "Proxy Disabled",
|
||||||
|
"PROXY_ENABLED": "Proxy Enabled",
|
||||||
|
"BROKER_OVERVIEW": "Broker Overview",
|
||||||
|
"TOTAL_MSG_RECEIVED_TODAY": "Total messages received today",
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,7 +27,6 @@ import store from './store';
|
|||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
root.render(
|
root.render(
|
||||||
|
|
||||||
<LanguageProvider>
|
<LanguageProvider>
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<AntdApp>
|
<AntdApp>
|
||||||
@@ -37,7 +36,6 @@ root.render(
|
|||||||
</AntdApp>
|
</AntdApp>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
</LanguageProvider>
|
</LanguageProvider>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
import React, {useCallback, useEffect, useState} from 'react';
|
||||||
import {Button, Checkbox, Input, message, notification, Spin, Table} from 'antd';
|
import {Button, Checkbox, Input, message, notification, Select, Spin, Switch, Table} from 'antd';
|
||||||
import {useLanguage} from '../../i18n/LanguageContext';
|
import {useLanguage} from '../../i18n/LanguageContext';
|
||||||
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
||||||
import ClientInfoModal from "../../components/consumer/ClientInfoModal";
|
import ClientInfoModal from "../../components/consumer/ClientInfoModal";
|
||||||
@@ -46,6 +46,27 @@ const ConsumerGroupList = () => {
|
|||||||
const [messageApi, msgContextHolder] = message.useMessage();
|
const [messageApi, msgContextHolder] = message.useMessage();
|
||||||
const [notificationApi, notificationContextHolder] = notification.useNotification();
|
const [notificationApi, notificationContextHolder] = notification.useNotification();
|
||||||
|
|
||||||
|
const [proxyEnabled, setProxyEnabled] = useState(() => {
|
||||||
|
try {
|
||||||
|
const storedValue = localStorage.getItem('proxyEnabled');
|
||||||
|
return storedValue ? JSON.parse(storedValue) : false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to read proxyEnabled from localStorage:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [selectedProxy, setSelectedProxy] = useState(() => {
|
||||||
|
try {
|
||||||
|
const storedValue = localStorage.getItem('selectedProxy');
|
||||||
|
return storedValue || undefined;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to read selectedProxy from localStorage:", error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [proxyOptions ,setProxyOptions]= useState([]);
|
||||||
const [paginationConf, setPaginationConf] = useState({
|
const [paginationConf, setPaginationConf] = useState({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -60,7 +81,12 @@ const ConsumerGroupList = () => {
|
|||||||
const loadConsumerGroups = useCallback(async (currentPage) => {
|
const loadConsumerGroups = useCallback(async (currentPage) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await remoteApi.queryConsumerGroupList(false);
|
var response;
|
||||||
|
if(!proxyEnabled){
|
||||||
|
response = await remoteApi.queryConsumerGroupList(false);
|
||||||
|
}else{
|
||||||
|
response = await remoteApi.queryConsumerGroupList(false, selectedProxy);
|
||||||
|
}
|
||||||
if (response.status === 0) {
|
if (response.status === 0) {
|
||||||
setAllConsumerGroupList(response.data);
|
setAllConsumerGroupList(response.data);
|
||||||
if (currentPage != null) {
|
if (currentPage != null) {
|
||||||
@@ -87,7 +113,6 @@ const ConsumerGroupList = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const filterList = useCallback((currentPage, data) => {
|
const filterList = useCallback((currentPage, data) => {
|
||||||
// 排序处理
|
|
||||||
let sortedData = [...data];
|
let sortedData = [...data];
|
||||||
if (sortConfig.sortKey) {
|
if (sortConfig.sortKey) {
|
||||||
sortedData.sort((a, b) => {
|
sortedData.sort((a, b) => {
|
||||||
@@ -153,6 +178,48 @@ const ConsumerGroupList = () => {
|
|||||||
filterList(paginationConf.current, sortedList);
|
filterList(paginationConf.current, sortedList);
|
||||||
}, [sortConfig, allConsumerGroupList, paginationConf.current]);
|
}, [sortConfig, allConsumerGroupList, paginationConf.current]);
|
||||||
|
|
||||||
|
const fetchProxyList = useCallback(async () => {
|
||||||
|
remoteApi.queryProxyHomePage((resp) => {
|
||||||
|
setLoading(false);
|
||||||
|
if (resp.status === 0) {
|
||||||
|
const {proxyAddrList, currentProxyAddr} = resp.data;
|
||||||
|
const options = proxyAddrList.map(proxyAddress => ({
|
||||||
|
label: proxyAddress,
|
||||||
|
value: proxyAddress,
|
||||||
|
}));
|
||||||
|
setProxyOptions(options || []);
|
||||||
|
setSelectedProxy(prevSelectedProxy => {
|
||||||
|
if (prevSelectedProxy) {
|
||||||
|
return prevSelectedProxy;
|
||||||
|
}
|
||||||
|
if (options.length > 0) {
|
||||||
|
return options[0].value;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notificationApi.error({message: resp.errMsg || t.FETCH_PROXY_LIST_FAILED, duration: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem('proxyEnabled', JSON.stringify(proxyEnabled));
|
||||||
|
}, [proxyEnabled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedProxy) {
|
||||||
|
localStorage.setItem('selectedProxy', selectedProxy);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem('selectedProxy');
|
||||||
|
}
|
||||||
|
}, [selectedProxy]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchProxyList();
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadConsumerGroups();
|
loadConsumerGroups();
|
||||||
}, [loadConsumerGroups]);
|
}, [loadConsumerGroups]);
|
||||||
@@ -391,14 +458,16 @@ const ConsumerGroupList = () => {
|
|||||||
{notificationContextHolder}
|
{notificationContextHolder}
|
||||||
<div style={{ padding: '20px' }}>
|
<div style={{ padding: '20px' }}>
|
||||||
<Spin spinning={loading} tip={t.LOADING}>
|
<Spin spinning={loading} tip={t.LOADING}>
|
||||||
<div style={{marginBottom: '20px'}}>
|
<div style={{ marginBottom: '20px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<div style={{display: 'flex', alignItems: 'center', gap: '15px'}}>
|
{/* 左侧:筛选和操作按钮 */}
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: '15px', flexWrap: 'wrap' }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<label style={{marginRight: '8px'}}>{t.SUBSCRIPTION_GROUP}:</label>
|
<label style={{ marginRight: '8px', whiteSpace: 'nowrap' }}>{t.SUBSCRIPTION_GROUP}:</label>
|
||||||
<Input
|
<Input
|
||||||
style={{ width: '200px' }}
|
style={{ width: '200px' }}
|
||||||
value={filterStr}
|
value={filterStr}
|
||||||
onChange={(e) => handleFilterInputChange(e.target.value)}
|
onChange={(e) => handleFilterInputChange(e.target.value)}
|
||||||
|
placeholder="输入订阅组名称"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Checkbox checked={filterNormal}
|
<Checkbox checked={filterNormal}
|
||||||
@@ -423,12 +492,35 @@ const ConsumerGroupList = () => {
|
|||||||
<Button type="primary" onClick={handleRefreshConsumerData}>
|
<Button type="primary" onClick={handleRefreshConsumerData}>
|
||||||
{t.REFRESH}
|
{t.REFRESH}
|
||||||
</Button>
|
</Button>
|
||||||
{/*<Switch*/}
|
</div>
|
||||||
{/* checked={intervalProcessSwitch}*/}
|
|
||||||
{/* onChange={(checked) => setIntervalProcessSwitch(checked)}*/}
|
{/* 右侧:代理选项 */}
|
||||||
{/* checkedChildren={t.AUTO_REFRESH}*/}
|
<div style={{ display: 'flex', alignItems: 'center', gap: '15px' }}>
|
||||||
{/* unCheckedChildren={t.AUTO_REFRESH}*/}
|
<label style={{ marginRight: '8px', whiteSpace: 'nowrap' }}>{t.SELECT_PROXY}:</label>
|
||||||
{/*/>*/}
|
<Select
|
||||||
|
style={{ width: '220px' }}
|
||||||
|
placeholder={t.SELECT_PROXY}
|
||||||
|
onChange={(value) => setSelectedProxy(value)}
|
||||||
|
value={selectedProxy}
|
||||||
|
options={proxyOptions}
|
||||||
|
disabled={!proxyEnabled}
|
||||||
|
allowClear
|
||||||
|
/>
|
||||||
|
<label style={{ marginRight: '8px', whiteSpace: 'nowrap' }}>{t.ENABLE_PROXY}:</label>
|
||||||
|
<Switch
|
||||||
|
checked={proxyEnabled}
|
||||||
|
onChange={(checked) => {
|
||||||
|
setProxyEnabled(checked);
|
||||||
|
if (!checked) {
|
||||||
|
setSelectedProxy(undefined);
|
||||||
|
messageApi.info(t.PROXY_DISABLED);
|
||||||
|
} else {
|
||||||
|
messageApi.info(t.PROXY_ENABLED);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
checkedChildren={t.ENABLED}
|
||||||
|
unCheckedChildren={t.DISABLED}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -443,6 +535,7 @@ const ConsumerGroupList = () => {
|
|||||||
/>
|
/>
|
||||||
</Spin>
|
</Spin>
|
||||||
|
|
||||||
|
{/* 模态框组件保持不变 */}
|
||||||
<ClientInfoModal
|
<ClientInfoModal
|
||||||
visible={showClientInfo}
|
visible={showClientInfo}
|
||||||
group={selectedGroup}
|
group={selectedGroup}
|
||||||
|
@@ -250,17 +250,18 @@ const DashboardPage = () => {
|
|||||||
const brokerAddrTable = resp.data.clusterInfo.brokerAddrTable; // Corrected to brokerAddrTable
|
const brokerAddrTable = resp.data.clusterInfo.brokerAddrTable; // Corrected to brokerAddrTable
|
||||||
const brokerDetail = resp.data.brokerServer;
|
const brokerDetail = resp.data.brokerServer;
|
||||||
const clusterMap = tools.generateBrokerMap(brokerDetail, clusterAddrTable, brokerAddrTable);
|
const clusterMap = tools.generateBrokerMap(brokerDetail, clusterAddrTable, brokerAddrTable);
|
||||||
|
console.log(brokerAddrTable)
|
||||||
let brokerArray = [];
|
let brokerArray = [];
|
||||||
Object.values(clusterMap).forEach(brokersInCluster => {
|
Object.values(clusterMap).forEach(brokersInCluster => {
|
||||||
brokerArray = brokerArray.concat(brokersInCluster);
|
brokerArray = brokerArray.concat(brokersInCluster);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update broker table data
|
const newData = brokerArray.map(broker => ({
|
||||||
setBrokerTableData(brokerArray.map(broker => ({
|
|
||||||
...broker,
|
...broker,
|
||||||
key: broker.brokerName // Ant Design Table needs a unique key
|
key: broker.brokerName,
|
||||||
})));
|
}));
|
||||||
|
console.log("即将设置的数据:", newData); // 先打印
|
||||||
|
setBrokerTableData(newData); // 再设置状态
|
||||||
|
|
||||||
brokerArray.sort((firstBroker, lastBroker) => {
|
brokerArray.sort((firstBroker, lastBroker) => {
|
||||||
const firstTotalMsg = parseFloat(firstBroker.msgGetTotalTodayNow || 0);
|
const firstTotalMsg = parseFloat(firstBroker.msgGetTotalTodayNow || 0);
|
||||||
@@ -347,7 +348,7 @@ const DashboardPage = () => {
|
|||||||
|
|
||||||
const brokerColumns = [
|
const brokerColumns = [
|
||||||
{title: t.BROKER_NAME, dataIndex: 'brokerName', key: 'brokerName'},
|
{title: t.BROKER_NAME, dataIndex: 'brokerName', key: 'brokerName'},
|
||||||
{title: t.BROKER_ADDR, dataIndex: 'brokerAddress', key: 'brokerAddress'},
|
{title: t.BROKER_ADDR, dataIndex: 'address', key: 'address'},
|
||||||
{
|
{
|
||||||
title: t.TOTAL_MSG_RECEIVED_TODAY,
|
title: t.TOTAL_MSG_RECEIVED_TODAY,
|
||||||
dataIndex: 'msgGetTotalTodayNow',
|
dataIndex: 'msgGetTotalTodayNow',
|
||||||
|
@@ -179,7 +179,6 @@ const DlqMessageQueryPage = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// console.log("根据Message ID查询DLQ消息:", { msgId: messageId, consumerGroup: selectedConsumerGroup });
|
|
||||||
try {
|
try {
|
||||||
const resp = await remoteApi.viewMessage(messageId, DLQ_GROUP_TOPIC_PREFIX + selectedConsumerGroup);
|
const resp = await remoteApi.viewMessage(messageId, DLQ_GROUP_TOPIC_PREFIX + selectedConsumerGroup);
|
||||||
if (resp.status === 0) {
|
if (resp.status === 0) {
|
||||||
@@ -323,7 +322,6 @@ const DlqMessageQueryPage = () => {
|
|||||||
msgId: message.properties.ORIGIN_MESSAGE_ID,
|
msgId: message.properties.ORIGIN_MESSAGE_ID,
|
||||||
consumerGroup: selectedConsumerGroup,
|
consumerGroup: selectedConsumerGroup,
|
||||||
}));
|
}));
|
||||||
// console.log(`批量重发DLQ消息到 ${selectedConsumerGroup}:`, messagesToResend);
|
|
||||||
try {
|
try {
|
||||||
const resp = await remoteApi.batchResendDlqMessage(messagesToResend);
|
const resp = await remoteApi.batchResendDlqMessage(messagesToResend);
|
||||||
if (resp.status === 0) {
|
if (resp.status === 0) {
|
||||||
@@ -355,7 +353,6 @@ const DlqMessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.BATCH_RESEND_FAILED,
|
description: t.BATCH_RESEND_FAILED,
|
||||||
});
|
});
|
||||||
console.error("批量重发失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Form, Input, Button, message, Typography } from 'antd';
|
import {Button, Form, Input, message, Typography} from 'antd';
|
||||||
import {remoteApi} from "../../api/remoteApi/remoteApi";
|
import {remoteApi} from "../../api/remoteApi/remoteApi";
|
||||||
|
|
||||||
const {Title} = Typography;
|
const {Title} = Typography;
|
||||||
|
@@ -146,7 +146,6 @@ const MessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.QUERY_FAILED,
|
description: t.QUERY_FAILED,
|
||||||
});
|
});
|
||||||
console.error("查询失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -182,7 +181,6 @@ const MessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.QUERY_FAILED,
|
description: t.QUERY_FAILED,
|
||||||
});
|
});
|
||||||
console.error("查询失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -241,7 +239,6 @@ const MessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.RESEND_FAILED,
|
description: t.RESEND_FAILED,
|
||||||
});
|
});
|
||||||
console.error("重发失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
// Optionally, you might want to refresh the message detail after resend
|
// Optionally, you might want to refresh the message detail after resend
|
||||||
@@ -455,7 +452,6 @@ const MessageQueryPage = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
{/* Message ID 查询结果通常直接弹窗显示,这里不需要表格 */}
|
|
||||||
</div>
|
</div>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import { Select, Button, Switch, Input, Typography, Space, message } from 'antd';
|
import {Button, Input, message, Select, Space, Switch, Typography} from 'antd';
|
||||||
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
||||||
|
|
||||||
const {Title} = Typography;
|
const {Title} = Typography;
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import { Modal, Button, Select, Input, Card, Row, Col, notification, Spin } from 'antd';
|
import {Button, Card, Col, Input, Modal, notification, Row, Select, Spin} from 'antd';
|
||||||
import {useLanguage} from '../../i18n/LanguageContext';
|
import {useLanguage} from '../../i18n/LanguageContext';
|
||||||
import {remoteApi} from "../../api/remoteApi/remoteApi";
|
import {remoteApi} from "../../api/remoteApi/remoteApi";
|
||||||
|
|
||||||
@@ -71,7 +71,10 @@ const ProxyManager = () => {
|
|||||||
|
|
||||||
const handleAddProxyAddr = () => {
|
const handleAddProxyAddr = () => {
|
||||||
if (!newProxyAddr.trim()) {
|
if (!newProxyAddr.trim()) {
|
||||||
notificationApi.warning({ message: t.INPUT_PROXY_ADDR_REQUIRED || "Please input a new proxy address.", duration: 2 });
|
notificationApi.warning({
|
||||||
|
message: t.INPUT_PROXY_ADDR_REQUIRED || "Please input a new proxy address.",
|
||||||
|
duration: 2
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -167,7 +170,8 @@ const ProxyManager = () => {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan="2" style={{ textAlign: 'center' }}>{t.NO_CONFIG_DATA || "No configuration data available."}</td>
|
<td colSpan="2"
|
||||||
|
style={{textAlign: 'center'}}>{t.NO_CONFIG_DATA || "No configuration data available."}</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@@ -173,7 +173,6 @@ const DeployHistoryList = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const filterList = (currentPage) => {
|
const filterList = (currentPage) => {
|
||||||
const lowExceptStr = filterStr.toLowerCase();
|
const lowExceptStr = filterStr.toLowerCase();
|
||||||
const canShowList = allTopicList.filter((topic, index) => {
|
const canShowList = allTopicList.filter((topic, index) => {
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import {useEffect} from 'react';
|
import {useEffect} from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
import { themes, defaultTheme } from '../../assets/styles/theme';
|
import {defaultTheme, themes} from '../../assets/styles/theme';
|
||||||
import {setTheme} from '../actions/themeActions';
|
import {setTheme} from '../actions/themeActions';
|
||||||
|
|
||||||
export const useTheme = () => {
|
export const useTheme = () => {
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { createStore,combineReducers } from 'redux';
|
import {combineReducers, createStore} from 'redux';
|
||||||
import themeReducer from './reducers/themeReducer';
|
import themeReducer from './reducers/themeReducer';
|
||||||
|
|
||||||
// 组合所有的 reducers
|
// 组合所有的 reducers
|
||||||
|
3
pom.xml
3
pom.xml
@@ -16,7 +16,8 @@
|
|||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.apache</groupId>
|
<groupId>org.apache</groupId>
|
||||||
|
@@ -91,6 +91,10 @@ public class RMQConfigure {
|
|||||||
@Getter
|
@Getter
|
||||||
private Integer clientCallbackExecutorThreads = 4;
|
private Integer clientCallbackExecutorThreads = 4;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private String authMode = "file";
|
||||||
|
|
||||||
public void setProxyAddrs(List<String> proxyAddrs) {
|
public void setProxyAddrs(List<String> proxyAddrs) {
|
||||||
this.proxyAddrs = proxyAddrs;
|
this.proxyAddrs = proxyAddrs;
|
||||||
if (CollectionUtils.isNotEmpty(proxyAddrs)) {
|
if (CollectionUtils.isNotEmpty(proxyAddrs)) {
|
||||||
@@ -112,10 +116,12 @@ public class RMQConfigure {
|
|||||||
logger.info("setNameSrvAddrByProperty nameSrvAddr={}", namesrvAddr);
|
logger.info("setNameSrvAddrByProperty nameSrvAddr={}", namesrvAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isACLEnabled() {
|
public boolean isACLEnabled() {
|
||||||
return !(StringUtils.isAnyBlank(this.accessKey, this.secretKey) ||
|
return !(StringUtils.isAnyBlank(this.accessKey, this.secretKey) ||
|
||||||
StringUtils.isAnyEmpty(this.accessKey, this.secretKey));
|
StringUtils.isAnyEmpty(this.accessKey, this.secretKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRocketMqDashboardDataPath() {
|
public String getRocketMqDashboardDataPath() {
|
||||||
return dataPath;
|
return dataPath;
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import org.apache.rocketmq.dashboard.model.request.UserUpdateRequest;
|
|||||||
import org.apache.rocketmq.dashboard.service.impl.AclServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.AclServiceImpl;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -31,24 +32,23 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@RestController
|
@Controller
|
||||||
@RequestMapping("/acl")
|
@RequestMapping("/acl")
|
||||||
public class AclController {
|
public class AclController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AclServiceImpl aclService;
|
private AclServiceImpl aclService;
|
||||||
|
|
||||||
@GetMapping("/listUsers")
|
@GetMapping("/users.query")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public List<UserInfo> listUsers(@RequestParam(required = false) String brokerAddress) {
|
public List<UserInfo> listUsers(@RequestParam(required = false) String brokerAddress) {
|
||||||
return aclService.listUsers(brokerAddress);
|
return aclService.listUsers(brokerAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/listAcls")
|
@GetMapping("/acls.query")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object listAcls(
|
public Object listAcls(
|
||||||
@RequestParam(required = false) String brokerAddress,
|
@RequestParam(required = false) String brokerAddress,
|
||||||
@@ -56,34 +56,34 @@ public class AclController {
|
|||||||
return aclService.listAcls(brokerAddress, searchParam);
|
return aclService.listAcls(brokerAddress, searchParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/createAcl")
|
@PostMapping("/createAcl.do")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object createAcl(@RequestBody PolicyRequest request) {
|
public Object createAcl(@RequestBody PolicyRequest request) {
|
||||||
aclService.createAcl(request);
|
aclService.createAcl(request);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/deleteUser")
|
@DeleteMapping("/deleteUser.do")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object deleteUser(@RequestParam(required = false) String brokerAddress, @RequestParam String username) {
|
public Object deleteUser(@RequestParam(required = false) String brokerAddress, @RequestParam String username) {
|
||||||
aclService.deleteUser(brokerAddress, username);
|
aclService.deleteUser(brokerAddress, username);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/updateUser", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
@RequestMapping(value = "/updateUser.do", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object updateUser(@RequestBody UserUpdateRequest request) {
|
public Object updateUser(@RequestBody UserUpdateRequest request) {
|
||||||
aclService.updateUser(request.getBrokerAddress(), request.getUserInfo());
|
aclService.updateUser(request.getBrokerAddress(), request.getUserInfo());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/createUser")
|
@PostMapping("/createUser.do")
|
||||||
public Object createUser(@RequestBody UserCreateRequest request) {
|
public Object createUser(@RequestBody UserCreateRequest request) {
|
||||||
aclService.createUser(request.getBrokerAddress(), request.getUserInfo());
|
aclService.createUser(request.getBrokerAddress(), request.getUserInfo());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/deleteAcl")
|
@DeleteMapping("/deleteAcl.do")
|
||||||
public Object deleteAcl(
|
public Object deleteAcl(
|
||||||
@RequestParam(required = false) String brokerAddress,
|
@RequestParam(required = false) String brokerAddress,
|
||||||
@RequestParam String subject,
|
@RequestParam String subject,
|
||||||
@@ -92,7 +92,7 @@ public class AclController {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/updateAcl", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
@RequestMapping(value = "/updateAcl.do", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object updateAcl(@RequestBody PolicyRequest request) {
|
public Object updateAcl(@RequestBody PolicyRequest request) {
|
||||||
aclService.updateAcl(request);
|
aclService.updateAcl(request);
|
||||||
|
@@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
public class ProxyController {
|
public class ProxyController {
|
||||||
@Resource
|
@Resource
|
||||||
private ProxyService proxyService;
|
private ProxyService proxyService;
|
||||||
|
|
||||||
@RequestMapping(value = "/homePage.query", method = RequestMethod.GET)
|
@RequestMapping(value = "/homePage.query", method = RequestMethod.GET)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object homePage() {
|
public Object homePage() {
|
||||||
|
@@ -72,7 +72,8 @@ public class TestController {
|
|||||||
|
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
@Override public void run() {
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -85,13 +86,11 @@ public class TestController {
|
|||||||
Thread.sleep(1000L);
|
Thread.sleep(1000L);
|
||||||
SendResult sendResult = producer.send(msg);
|
SendResult sendResult = producer.send(msg);
|
||||||
logger.info("sendMessage={}", JsonUtil.obj2String(sendResult));
|
logger.info("sendMessage={}", JsonUtil.obj2String(sendResult));
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
} catch (Exception ignore) {
|
||||||
catch (Exception ignore) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@WebFilter(urlPatterns = "/*", filterName = "httpBasicAuthorizedFilter")
|
@WebFilter(urlPatterns = "/*", filterName = "httpBasicAuthorizedFilter")
|
||||||
public class HttpBasicAuthorizedFilter implements Filter {
|
public class HttpBasicAuthorizedFilter implements Filter {
|
||||||
|
|
||||||
|
@@ -25,7 +25,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class MessageView {
|
public class MessageView {
|
||||||
|
|
||||||
/** from MessageExt **/
|
/**
|
||||||
|
* from MessageExt
|
||||||
|
**/
|
||||||
private int queueId;
|
private int queueId;
|
||||||
private int storeSize;
|
private int storeSize;
|
||||||
private long queueOffset;
|
private long queueOffset;
|
||||||
@@ -41,13 +43,17 @@ public class MessageView {
|
|||||||
private long preparedTransactionOffset;
|
private long preparedTransactionOffset;
|
||||||
/**from MessageExt**/
|
/**from MessageExt**/
|
||||||
|
|
||||||
/** from Message **/
|
/**
|
||||||
|
* from Message
|
||||||
|
**/
|
||||||
private String topic;
|
private String topic;
|
||||||
private int flag;
|
private int flag;
|
||||||
private Map<String, String> properties;
|
private Map<String, String> properties;
|
||||||
private String messageBody; // body
|
private String messageBody; // body
|
||||||
|
|
||||||
/** from Message **/
|
/**
|
||||||
|
* from Message
|
||||||
|
**/
|
||||||
|
|
||||||
public static MessageView fromMessageExt(MessageExt messageExt) {
|
public static MessageView fromMessageExt(MessageExt messageExt) {
|
||||||
MessageView messageView = new MessageView();
|
MessageView messageView = new MessageView();
|
||||||
|
@@ -19,8 +19,8 @@ package org.apache.rocketmq.dashboard.model;
|
|||||||
import org.hibernate.validator.constraints.Range;
|
import org.hibernate.validator.constraints.Range;
|
||||||
|
|
||||||
public class User {
|
public class User {
|
||||||
public static final int ORDINARY = 0;
|
public static final int SUPER = 0;
|
||||||
public static final int ADMIN = 1;
|
public static final int NORMAL = 1;
|
||||||
|
|
||||||
private long id;
|
private long id;
|
||||||
private String name;
|
private String name;
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.rocketmq.dashboard.model.request;
|
package org.apache.rocketmq.dashboard.model.request;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -24,7 +25,9 @@ public class TopicConfigInfo {
|
|||||||
private List<String> clusterNameList;
|
private List<String> clusterNameList;
|
||||||
private List<String> brokerNameList;
|
private List<String> brokerNameList;
|
||||||
|
|
||||||
/** topicConfig */
|
/**
|
||||||
|
* topicConfig
|
||||||
|
*/
|
||||||
private String topicName;
|
private String topicName;
|
||||||
private int writeQueueNums;
|
private int writeQueueNums;
|
||||||
private int readQueueNums;
|
private int readQueueNums;
|
||||||
@@ -32,6 +35,7 @@ public class TopicConfigInfo {
|
|||||||
private boolean order;
|
private boolean order;
|
||||||
|
|
||||||
private String messageType;
|
private String messageType;
|
||||||
|
|
||||||
public List<String> getClusterNameList() {
|
public List<String> getClusterNameList() {
|
||||||
return clusterNameList;
|
return clusterNameList;
|
||||||
}
|
}
|
||||||
@@ -40,8 +44,9 @@ public class TopicConfigInfo {
|
|||||||
this.clusterNameList = clusterNameList;
|
this.clusterNameList = clusterNameList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** topicConfig */
|
/**
|
||||||
|
* topicConfig
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
public List<String> getBrokerNameList() {
|
public List<String> getBrokerNameList() {
|
||||||
@@ -102,8 +107,6 @@ public class TopicConfigInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o)
|
||||||
|
@@ -17,9 +17,11 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.model.request;
|
package org.apache.rocketmq.dashboard.model.request;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
public class UserInfoParam {
|
public class UserInfoParam {
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
@@ -29,6 +29,7 @@ import java.util.Set;
|
|||||||
public abstract class AbstractCommonService {
|
public abstract class AbstractCommonService {
|
||||||
@Resource
|
@Resource
|
||||||
protected MQAdminExt mqAdminExt;
|
protected MQAdminExt mqAdminExt;
|
||||||
|
|
||||||
protected final Set<String> changeToBrokerNameSet(Map<String, Set<String>> clusterAddrTable,
|
protected final Set<String> changeToBrokerNameSet(Map<String, Set<String>> clusterAddrTable,
|
||||||
List<String> clusterNameList, List<String> brokerNameList) {
|
List<String> clusterNameList, List<String> brokerNameList) {
|
||||||
Set<String> finalBrokerNameList = Sets.newHashSet();
|
Set<String> finalBrokerNameList = Sets.newHashSet();
|
||||||
@@ -37,8 +38,7 @@ public abstract class AbstractCommonService {
|
|||||||
for (String clusterName : clusterNameList) {
|
for (String clusterName : clusterNameList) {
|
||||||
finalBrokerNameList.addAll(clusterAddrTable.get(clusterName));
|
finalBrokerNameList.addAll(clusterAddrTable.get(clusterName));
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@@ -39,8 +39,7 @@ public interface MessageService {
|
|||||||
/**
|
/**
|
||||||
* @param topic
|
* @param topic
|
||||||
* @param begin
|
* @param begin
|
||||||
* @param end
|
* @param end org.apache.rocketmq.tools.command.message.PrintMessageSubCommand
|
||||||
* org.apache.rocketmq.tools.command.message.PrintMessageSubCommand
|
|
||||||
*/
|
*/
|
||||||
List<MessageView> queryMessageByTopic(final String topic, final long begin,
|
List<MessageView> queryMessageByTopic(final String topic, final long begin,
|
||||||
final long end);
|
final long end);
|
||||||
@@ -54,6 +53,4 @@ public interface MessageService {
|
|||||||
MessagePage queryMessageByPage(MessageQuery query);
|
MessagePage queryMessageByPage(MessageQuery query);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -94,7 +94,8 @@ public class MQAdminExtImpl implements MQAdminExt {
|
|||||||
private Logger logger = LoggerFactory.getLogger(MQAdminExtImpl.class);
|
private Logger logger = LoggerFactory.getLogger(MQAdminExtImpl.class);
|
||||||
|
|
||||||
|
|
||||||
public MQAdminExtImpl() {}
|
public MQAdminExtImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -134,8 +135,7 @@ public class MQAdminExtImpl implements MQAdminExt {
|
|||||||
RemotingCommand response = null;
|
RemotingCommand response = null;
|
||||||
try {
|
try {
|
||||||
response = remotingClient.invokeSync(addr, request, 8000);
|
response = remotingClient.invokeSync(addr, request, 8000);
|
||||||
}
|
} catch (Exception err) {
|
||||||
catch (Exception err) {
|
|
||||||
Throwables.throwIfUnchecked(err);
|
Throwables.throwIfUnchecked(err);
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
@@ -566,17 +566,20 @@ public class MQAdminExtImpl implements MQAdminExt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4.0.0 added
|
// 4.0.0 added
|
||||||
@Override public void updateNameServerConfig(Properties properties,
|
@Override
|
||||||
|
public void updateNameServerConfig(Properties properties,
|
||||||
List<String> list) throws InterruptedException, RemotingConnectException, UnsupportedEncodingException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
|
List<String> list) throws InterruptedException, RemotingConnectException, UnsupportedEncodingException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public Map<String, Properties> getNameServerConfig(
|
@Override
|
||||||
|
public Map<String, Properties> getNameServerConfig(
|
||||||
List<String> list) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException, UnsupportedEncodingException {
|
List<String> list) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException, UnsupportedEncodingException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic,
|
@Override
|
||||||
|
public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic,
|
||||||
int queueId, long index, int count,
|
int queueId, long index, int count,
|
||||||
String consumerGroup) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
|
String consumerGroup) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
|
||||||
return null;
|
return null;
|
||||||
@@ -588,7 +591,8 @@ public class MQAdminExtImpl implements MQAdminExt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override public boolean resumeCheckHalfMessage(String topic,
|
@Override
|
||||||
|
public boolean resumeCheckHalfMessage(String topic,
|
||||||
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -58,7 +58,7 @@ public abstract class AbstractFileStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract void load(InputStream inputStream);
|
protected abstract void load(InputStream inputStream);
|
||||||
|
|
||||||
private void load() {
|
private void load() {
|
||||||
load(null);
|
load(null);
|
||||||
|
@@ -212,7 +212,6 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
|||||||
} else {
|
} else {
|
||||||
consumeInfo.setSubGroupType(subscriptionGroupTable.get(consumerGroup).isConsumeMessageOrderly() ? "FIFO" : "NORMAL");
|
consumeInfo.setSubGroupType(subscriptionGroupTable.get(consumerGroup).isConsumeMessageOrderly() ? "FIFO" : "NORMAL");
|
||||||
}
|
}
|
||||||
consumeInfo.setGroup(consumerGroup);
|
|
||||||
consumeInfo.setUpdateTime(new Date());
|
consumeInfo.setUpdateTime(new Date());
|
||||||
groupConsumeInfoList.add(consumeInfo);
|
groupConsumeInfoList.add(consumeInfo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -270,6 +269,7 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
|||||||
logger.warn("examineConsumeStats or examineConsumerConnectionInfo exception, "
|
logger.warn("examineConsumeStats or examineConsumerConnectionInfo exception, "
|
||||||
+ consumerGroup, e);
|
+ consumerGroup, e);
|
||||||
}
|
}
|
||||||
|
groupConsumeInfo.setGroup(consumerGroup);
|
||||||
return groupConsumeInfo;
|
return groupConsumeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -96,6 +96,7 @@ public class DashboardCollectServiceImpl implements DashboardCollectService {
|
|||||||
public LoadingCache<String, List<String>> getBrokerMap() {
|
public LoadingCache<String, List<String>> getBrokerMap() {
|
||||||
return brokerMap;
|
return brokerMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoadingCache<String, List<String>> getTopicMap() {
|
public LoadingCache<String, List<String>> getTopicMap() {
|
||||||
return topicMap;
|
return topicMap;
|
||||||
@@ -106,8 +107,7 @@ public class DashboardCollectServiceImpl implements DashboardCollectService {
|
|||||||
List<String> strings;
|
List<String> strings;
|
||||||
try {
|
try {
|
||||||
strings = Files.readLines(file, Charsets.UTF_8);
|
strings = Files.readLines(file, Charsets.UTF_8);
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch (IOException e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ public class DashboardServiceImpl implements DashboardService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DashboardCollectService dashboardCollectService;
|
private DashboardCollectService dashboardCollectService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param date format yyyy-MM-dd
|
* @param date format yyyy-MM-dd
|
||||||
*/
|
*/
|
||||||
|
@@ -17,13 +17,10 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.service.impl;
|
package org.apache.rocketmq.dashboard.service.impl;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
|
||||||
import org.apache.rocketmq.dashboard.service.LoginService;
|
import org.apache.rocketmq.dashboard.service.LoginService;
|
||||||
import org.apache.rocketmq.dashboard.service.UserService;
|
import org.apache.rocketmq.dashboard.service.strategy.UserContext;
|
||||||
import org.apache.rocketmq.dashboard.service.provider.UserInfoProvider;
|
|
||||||
import org.apache.rocketmq.dashboard.util.UserInfoContext;
|
import org.apache.rocketmq.dashboard.util.UserInfoContext;
|
||||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
@@ -33,34 +30,29 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class LoginServiceImpl implements LoginService {
|
public class LoginServiceImpl implements LoginService {
|
||||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RMQConfigure rmqConfigure;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
private UserContext userContext;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private UserInfoProvider userInfoProvider;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean login(HttpServletRequest request, HttpServletResponse response) {
|
public boolean login(HttpServletRequest request, HttpServletResponse response) {
|
||||||
String username = (String) WebUtil.getValueFromSession(request, WebUtil.USER_NAME);
|
String username = (String) WebUtil.getValueFromSession(request, WebUtil.USER_NAME);
|
||||||
if (username != null) {
|
if (username != null) {
|
||||||
UserInfo userInfo = userInfoProvider.getUserInfoByUsername(username);
|
UserInfo userInfo = userContext.queryByUsername(username);
|
||||||
if (userInfo == null) {
|
if (userInfo == null) {
|
||||||
auth(request, response);
|
auth(request, response);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
UserInfoContext.set(WebUtil.USER_NAME, userInfo);
|
UserInfoContext.set(WebUtil.USER_NAME, userInfo);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
auth(request, response);
|
auth(request, response);
|
||||||
return false;
|
return false;
|
||||||
@@ -69,11 +61,7 @@ public class LoginServiceImpl implements LoginService {
|
|||||||
protected void auth(HttpServletRequest request, HttpServletResponse response) {
|
protected void auth(HttpServletRequest request, HttpServletResponse response) {
|
||||||
try {
|
try {
|
||||||
String url = WebUtil.getUrl(request);
|
String url = WebUtil.getUrl(request);
|
||||||
try {
|
url = URLEncoder.encode(url, StandardCharsets.UTF_8);
|
||||||
url = URLEncoder.encode(url, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
logger.error("url encode:{}", url, e);
|
|
||||||
}
|
|
||||||
logger.debug("redirect url : {}", url);
|
logger.debug("redirect url : {}", url);
|
||||||
WebUtil.redirect(response, request, "/#/login?redirect=" + url);
|
WebUtil.redirect(response, request, "/#/login?redirect=" + url);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@@ -33,7 +33,6 @@ import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
|||||||
import org.apache.rocketmq.client.consumer.PullResult;
|
import org.apache.rocketmq.client.consumer.PullResult;
|
||||||
import org.apache.rocketmq.client.consumer.PullStatus;
|
import org.apache.rocketmq.client.consumer.PullStatus;
|
||||||
import org.apache.rocketmq.client.exception.MQClientException;
|
import org.apache.rocketmq.client.exception.MQClientException;
|
||||||
import org.apache.rocketmq.common.MixAll;
|
|
||||||
import org.apache.rocketmq.common.Pair;
|
import org.apache.rocketmq.common.Pair;
|
||||||
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
||||||
import org.apache.rocketmq.common.message.MessageExt;
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
@@ -74,6 +73,9 @@ import java.util.stream.Collectors;
|
|||||||
@Service
|
@Service
|
||||||
public class MessageServiceImpl implements MessageService {
|
public class MessageServiceImpl implements MessageService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AutoCloseConsumerWrapper autoCloseConsumerWrapper;
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
|
private Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
|
||||||
|
|
||||||
private static final Cache<String, List<QueueOffsetInfo>> CACHE = CacheBuilder.newBuilder()
|
private static final Cache<String, List<QueueOffsetInfo>> CACHE = CacheBuilder.newBuilder()
|
||||||
@@ -128,8 +130,8 @@ public class MessageServiceImpl implements MessageService {
|
|||||||
if (isEnableAcl) {
|
if (isEnableAcl) {
|
||||||
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
|
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
|
||||||
}
|
}
|
||||||
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
|
|
||||||
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
|
DefaultMQPullConsumer consumer = autoCloseConsumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
|
||||||
List<MessageView> messageViewList = Lists.newArrayList();
|
List<MessageView> messageViewList = Lists.newArrayList();
|
||||||
try {
|
try {
|
||||||
String subExpression = "*";
|
String subExpression = "*";
|
||||||
@@ -262,8 +264,8 @@ public class MessageServiceImpl implements MessageService {
|
|||||||
if (isEnableAcl) {
|
if (isEnableAcl) {
|
||||||
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
|
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
|
||||||
}
|
}
|
||||||
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
|
|
||||||
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
|
DefaultMQPullConsumer consumer = autoCloseConsumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
|
||||||
|
|
||||||
long total = 0;
|
long total = 0;
|
||||||
List<QueueOffsetInfo> queueOffsetInfos = new ArrayList<>();
|
List<QueueOffsetInfo> queueOffsetInfos = new ArrayList<>();
|
||||||
@@ -402,8 +404,8 @@ public class MessageServiceImpl implements MessageService {
|
|||||||
if (isEnableAcl) {
|
if (isEnableAcl) {
|
||||||
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
|
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
|
||||||
}
|
}
|
||||||
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
|
|
||||||
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
|
DefaultMQPullConsumer consumer = autoCloseConsumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
|
||||||
List<MessageView> messageViews = new ArrayList<>();
|
List<MessageView> messageViews = new ArrayList<>();
|
||||||
|
|
||||||
long offset = query.getPageNum() * query.getPageSize();
|
long offset = query.getPageNum() * query.getPageSize();
|
||||||
@@ -541,9 +543,9 @@ public class MessageServiceImpl implements MessageService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultMQPullConsumer buildDefaultMQPullConsumer(RPCHook rpcHook, boolean useTLS) {
|
// public DefaultMQPullConsumer buildDefaultMQPullConsumer(RPCHook rpcHook, boolean useTLS) {
|
||||||
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook);
|
// DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook);
|
||||||
consumer.setUseTLS(useTLS);
|
// consumer.setUseTLS(useTLS);
|
||||||
return consumer;
|
// return consumer;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@@ -81,8 +81,7 @@ public class MonitorServiceImpl implements MonitorService {
|
|||||||
private void writeDataJsonToFile(String path, String dataStr) {
|
private void writeDataJsonToFile(String path, String dataStr) {
|
||||||
try {
|
try {
|
||||||
MixAll.string2File(dataStr, path);
|
MixAll.string2File(dataStr, path);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@@ -33,8 +33,7 @@ public class ProducerServiceImpl implements ProducerService {
|
|||||||
public ProducerConnection getProducerConnection(String producerGroup, String topic) {
|
public ProducerConnection getProducerConnection(String producerGroup, String topic) {
|
||||||
try {
|
try {
|
||||||
return mqAdminExt.examineProducerConnectionInfo(producerGroup, topic);
|
return mqAdminExt.examineProducerConnectionInfo(producerGroup, topic);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@@ -17,29 +17,26 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.service.impl;
|
package org.apache.rocketmq.dashboard.service.impl;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.apache.rocketmq.auth.authentication.enums.UserType;
|
import org.apache.rocketmq.auth.authentication.enums.UserType;
|
||||||
import org.apache.rocketmq.dashboard.admin.UserMQAdminPoolManager;
|
import org.apache.rocketmq.dashboard.admin.UserMQAdminPoolManager;
|
||||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
|
||||||
import org.apache.rocketmq.dashboard.model.User;
|
import org.apache.rocketmq.dashboard.model.User;
|
||||||
import org.apache.rocketmq.dashboard.service.UserService;
|
import org.apache.rocketmq.dashboard.service.UserService;
|
||||||
import org.apache.rocketmq.dashboard.service.provider.UserInfoProvider;
|
import org.apache.rocketmq.dashboard.service.strategy.UserContext;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserServiceImpl implements UserService {
|
public class UserServiceImpl implements UserService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RMQConfigure configure;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserInfoProvider userInfoProvider;
|
private UserContext userContext;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserMQAdminPoolManager userMQAdminPoolManager;
|
private UserMQAdminPoolManager userMQAdminPoolManager;
|
||||||
@@ -47,7 +44,7 @@ public class UserServiceImpl implements UserService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User queryByName(String name) {
|
public User queryByName(String name) {
|
||||||
UserInfo userInfo = userInfoProvider.getUserInfoByUsername(name);
|
UserInfo userInfo = userContext.queryByUsername(name);
|
||||||
if (userInfo == null) {
|
if (userInfo == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.rocketmq.dashboard.service.strategy;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.apache.rocketmq.dashboard.service.ClusterInfoService;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||||
|
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AclUserStrategy implements UserStrategy {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AclUserStrategy.class);
|
||||||
|
|
||||||
|
private final MQAdminExt mqAdminExt;
|
||||||
|
|
||||||
|
private final ClusterInfoService clusterInfoService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserInfo getUserInfoByUsername(String username) {
|
||||||
|
ClusterInfo clusterInfo = clusterInfoService.get();
|
||||||
|
|
||||||
|
if (clusterInfo == null || clusterInfo.getBrokerAddrTable() == null || clusterInfo.getBrokerAddrTable().isEmpty()) {
|
||||||
|
log.warn("Cluster information is not available or has no broker addresses.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (BrokerData brokerLiveInfo : clusterInfo.getBrokerAddrTable().values()) {
|
||||||
|
if (brokerLiveInfo == null || brokerLiveInfo.getBrokerAddrs() == null || brokerLiveInfo.getBrokerAddrs().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String brokerAddr = brokerLiveInfo.getBrokerAddrs().get(0L); // Assuming 0L is the primary address
|
||||||
|
if (brokerAddr == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
UserInfo userInfo = mqAdminExt.getUser(brokerAddr, username);
|
||||||
|
if (userInfo != null) {
|
||||||
|
return userInfo;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to get user {} from broker {}. Trying next broker if available. Error: {}", username, brokerAddr, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* 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.rocketmq.dashboard.service.strategy;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||||
|
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||||
|
import org.apache.rocketmq.dashboard.model.User;
|
||||||
|
import org.apache.rocketmq.dashboard.service.impl.AbstractFileStore;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FileUserStrategy implements UserStrategy, InitializingBean {
|
||||||
|
@Resource
|
||||||
|
private RMQConfigure configure;
|
||||||
|
|
||||||
|
private FileBasedUserInfoStore fileBasedUserInfoStore;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
if (configure.isLoginRequired()) {
|
||||||
|
fileBasedUserInfoStore = new FileBasedUserInfoStore(configure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserInfo getUserInfoByUsername(String username) {
|
||||||
|
User user = fileBasedUserInfoStore.queryByUsernameAndPassword(username);
|
||||||
|
if (user != null) {
|
||||||
|
return UserInfo.of(user.getName(), user.getPassword(), user.getType() == 0 ? "normal" : "super");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FileBasedUserInfoStore extends AbstractFileStore {
|
||||||
|
private static final String FILE_NAME = "users.properties";
|
||||||
|
|
||||||
|
private static Map<String, User> userMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public FileBasedUserInfoStore(RMQConfigure configure) {
|
||||||
|
super(configure, FILE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(InputStream inputStream) {
|
||||||
|
Properties prop = new Properties();
|
||||||
|
try {
|
||||||
|
if (inputStream == null) {
|
||||||
|
prop.load(new FileReader(filePath));
|
||||||
|
} else {
|
||||||
|
prop.load(inputStream);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("load user.properties failed", e);
|
||||||
|
throw new ServiceException(0, String.format("Failed to load loginUserInfo property file: %s", filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, User> loadUserMap = new HashMap<>();
|
||||||
|
String[] arrs;
|
||||||
|
int role;
|
||||||
|
for (String key : prop.stringPropertyNames()) {
|
||||||
|
String v = prop.getProperty(key);
|
||||||
|
if (v == null)
|
||||||
|
continue;
|
||||||
|
arrs = v.split(",", 2);
|
||||||
|
if (arrs.length == 0) {
|
||||||
|
continue;
|
||||||
|
} else if (arrs.length == 1) {
|
||||||
|
role = 0;
|
||||||
|
} else {
|
||||||
|
role = Integer.parseInt(arrs[1].trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
loadUserMap.put(key, new User(key, arrs[0].trim(), role));
|
||||||
|
}
|
||||||
|
|
||||||
|
userMap.clear();
|
||||||
|
userMap.putAll(loadUserMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User queryByName(String name) {
|
||||||
|
return userMap.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User queryByUsernameAndPassword(@NotNull String username) {
|
||||||
|
User user = queryByName(username);
|
||||||
|
if (user != null) {
|
||||||
|
return user.cloneOne();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.rocketmq.dashboard.service.strategy;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UserContext {
|
||||||
|
private UserStrategy userStrategy;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Map<String, UserStrategy> userStrategies;
|
||||||
|
|
||||||
|
@Value("${rocketmq.config.authMode}")
|
||||||
|
private String authMode;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
switch (authMode.toLowerCase()) {
|
||||||
|
case "acl":
|
||||||
|
this.userStrategy = userStrategies.get("aclUserStrategy");
|
||||||
|
break;
|
||||||
|
case "file":
|
||||||
|
default:
|
||||||
|
this.userStrategy = userStrategies.get("fileUserStrategy");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo queryByUsername(String username) {
|
||||||
|
return userStrategy.getUserInfoByUsername(username);
|
||||||
|
}
|
||||||
|
}
|
@@ -15,11 +15,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.rocketmq.dashboard.admin;
|
package org.apache.rocketmq.dashboard.service.strategy;
|
||||||
|
|
||||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
|
|
||||||
@FunctionalInterface
|
public interface UserStrategy {
|
||||||
public interface MQAdminExtCallback<T> {
|
UserInfo getUserInfoByUsername(String username);
|
||||||
T doInMQAdminExt(MQAdminExt mqAdminExt) throws Exception;
|
|
||||||
}
|
}
|
@@ -23,6 +23,7 @@ import org.apache.rocketmq.common.MixAll;
|
|||||||
import org.apache.rocketmq.remoting.RPCHook;
|
import org.apache.rocketmq.remoting.RPCHook;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -32,9 +33,10 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
@Component
|
||||||
public class AutoCloseConsumerWrapper {
|
public class AutoCloseConsumerWrapper {
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(GlobalRestfulResponseBodyAdvice.class);
|
private final Logger logger = LoggerFactory.getLogger(AutoCloseConsumerWrapper.class);
|
||||||
|
|
||||||
private static final AtomicReference<DefaultMQPullConsumer> CONSUMER_REF = new AtomicReference<>();
|
private static final AtomicReference<DefaultMQPullConsumer> CONSUMER_REF = new AtomicReference<>();
|
||||||
private final AtomicBoolean isTaskScheduled = new AtomicBoolean(false);
|
private final AtomicBoolean isTaskScheduled = new AtomicBoolean(false);
|
||||||
@@ -77,7 +79,10 @@ public class AutoCloseConsumerWrapper {
|
|||||||
|
|
||||||
protected DefaultMQPullConsumer createNewConsumer(RPCHook rpcHook, Boolean useTLS) {
|
protected DefaultMQPullConsumer createNewConsumer(RPCHook rpcHook, Boolean useTLS) {
|
||||||
return new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook) {
|
return new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook) {
|
||||||
{ setUseTLS(useTLS); } };
|
{
|
||||||
|
setUseTLS(useTLS);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startIdleCheckTask() {
|
private void startIdleCheckTask() {
|
||||||
|
@@ -37,8 +37,7 @@ public class GlobalExceptionHandler {
|
|||||||
if (ex instanceof ServiceException) {
|
if (ex instanceof ServiceException) {
|
||||||
logger.error("Occur service exception: {}", ex.getMessage());
|
logger.error("Occur service exception: {}", ex.getMessage());
|
||||||
value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage());
|
value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
logger.error("op=global_exception_handler_print_error", ex);
|
logger.error("op=global_exception_handler_print_error", ex);
|
||||||
value = new JsonResult<Object>(-1, ex.getMessage() == null ? ex.toString() : ex.getMessage());
|
value = new JsonResult<Object>(-1, ex.getMessage() == null ? ex.toString() : ex.getMessage());
|
||||||
}
|
}
|
||||||
|
@@ -47,8 +47,7 @@ public class GlobalRestfulResponseBodyAdvice implements ResponseBodyAdvice<Objec
|
|||||||
JsonResult value;
|
JsonResult value;
|
||||||
if (obj instanceof JsonResult) {
|
if (obj instanceof JsonResult) {
|
||||||
value = (JsonResult) obj;
|
value = (JsonResult) obj;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
value = new JsonResult(obj);
|
value = new JsonResult(obj);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
@@ -87,8 +87,7 @@ public class DashboardCollectTask {
|
|||||||
CollectTaskRunnble collectTask = new CollectTaskRunnble(topic, mqAdminExt, dashboardCollectService);
|
CollectTaskRunnble collectTask = new CollectTaskRunnble(topic, mqAdminExt, dashboardCollectService);
|
||||||
collectExecutor.submit(collectTask);
|
collectExecutor.submit(collectTask);
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception err) {
|
||||||
catch (Exception err) {
|
|
||||||
Throwables.throwIfUnchecked(err);
|
Throwables.throwIfUnchecked(err);
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
@@ -100,7 +99,6 @@ public class DashboardCollectTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Scheduled(cron = "0 0/1 * * * ?")
|
@Scheduled(cron = "0 0/1 * * * ?")
|
||||||
public void collectBroker() {
|
public void collectBroker() {
|
||||||
if (!rmqConfigure.isEnableDashBoardCollect()) {
|
if (!rmqConfigure.isEnableDashBoardCollect()) {
|
||||||
@@ -139,8 +137,7 @@ public class DashboardCollectTask {
|
|||||||
dashboardCollectService.getBrokerMap().put(entry.getValue(), list);
|
dashboardCollectService.getBrokerMap().put(entry.getValue(), list);
|
||||||
}
|
}
|
||||||
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
|
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -152,12 +149,10 @@ public class DashboardCollectTask {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return mqAdminExt.fetchBrokerRuntimeStats(brokerAddr);
|
return mqAdminExt.fetchBrokerRuntimeStats(brokerAddr);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
} catch (InterruptedException e1) {
|
||||||
catch (InterruptedException e1) {
|
|
||||||
Throwables.throwIfUnchecked(e1);
|
Throwables.throwIfUnchecked(e1);
|
||||||
throw new RuntimeException(e1);
|
throw new RuntimeException(e1);
|
||||||
}
|
}
|
||||||
@@ -189,16 +184,14 @@ public class DashboardCollectTask {
|
|||||||
Map<String, List<String>> topicFileMap;
|
Map<String, List<String>> topicFileMap;
|
||||||
if (brokerFile.exists()) {
|
if (brokerFile.exists()) {
|
||||||
brokerFileMap = dashboardCollectService.jsonDataFile2map(brokerFile);
|
brokerFileMap = dashboardCollectService.jsonDataFile2map(brokerFile);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
brokerFileMap = Maps.newHashMap();
|
brokerFileMap = Maps.newHashMap();
|
||||||
Files.createParentDirs(brokerFile);
|
Files.createParentDirs(brokerFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topicFile.exists()) {
|
if (topicFile.exists()) {
|
||||||
topicFileMap = dashboardCollectService.jsonDataFile2map(topicFile);
|
topicFileMap = dashboardCollectService.jsonDataFile2map(topicFile);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
topicFileMap = Maps.newHashMap();
|
topicFileMap = Maps.newHashMap();
|
||||||
Files.createParentDirs(topicFile);
|
Files.createParentDirs(topicFile);
|
||||||
}
|
}
|
||||||
@@ -211,8 +204,7 @@ public class DashboardCollectTask {
|
|||||||
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
|
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
|
||||||
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
|
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
|
||||||
|
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch (IOException e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -224,8 +216,7 @@ public class DashboardCollectTask {
|
|||||||
Map<String, List<String>> resultMap = Maps.newHashMap();
|
Map<String, List<String>> resultMap = Maps.newHashMap();
|
||||||
if (fileMap.size() == 0) {
|
if (fileMap.size() == 0) {
|
||||||
resultMap = newMap;
|
resultMap = newMap;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (Map.Entry<String, List<String>> entry : fileMap.entrySet()) {
|
for (Map.Entry<String, List<String>> entry : fileMap.entrySet()) {
|
||||||
List<String> oldList = entry.getValue();
|
List<String> oldList = entry.getValue();
|
||||||
List<String> newList = newMap.get(entry.getKey());
|
List<String> newList = newMap.get(entry.getKey());
|
||||||
|
@@ -55,8 +55,7 @@ public class JsonUtil {
|
|||||||
public static void writeValue(Writer writer, Object obj) {
|
public static void writeValue(Writer writer, Object obj) {
|
||||||
try {
|
try {
|
||||||
objectMapper.writeValue(writer, obj);
|
objectMapper.writeValue(writer, obj);
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch (IOException e) {
|
|
||||||
Throwables.propagateIfPossible(e);
|
Throwables.propagateIfPossible(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,8 +67,7 @@ public class JsonUtil {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return src instanceof String ? (String) src : objectMapper.writeValueAsString(src);
|
return src instanceof String ? (String) src : objectMapper.writeValueAsString(src);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
logger.error("Parse Object to String error src=" + src, e);
|
logger.error("Parse Object to String error src=" + src, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -82,8 +80,7 @@ public class JsonUtil {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return src instanceof byte[] ? (byte[]) src : objectMapper.writeValueAsBytes(src);
|
return src instanceof byte[] ? (byte[]) src : objectMapper.writeValueAsBytes(src);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
logger.error("Parse Object to byte[] error", e);
|
logger.error("Parse Object to byte[] error", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -96,8 +93,7 @@ public class JsonUtil {
|
|||||||
str = escapesSpecialChar(str);
|
str = escapesSpecialChar(str);
|
||||||
try {
|
try {
|
||||||
return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
|
return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
logger.error("Parse String to Object error\nString: {}\nClass<T>: {}\nError: {}", str, clazz.getName(), e);
|
logger.error("Parse String to Object error\nString: {}\nClass<T>: {}\nError: {}", str, clazz.getName(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -109,8 +105,7 @@ public class JsonUtil {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return clazz.equals(byte[].class) ? (T) bytes : objectMapper.readValue(bytes, clazz);
|
return clazz.equals(byte[].class) ? (T) bytes : objectMapper.readValue(bytes, clazz);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
logger.error("Parse byte[] to Object error\nbyte[]: {}\nClass<T>: {}\nError: {}", bytes, clazz.getName(), e);
|
logger.error("Parse byte[] to Object error\nbyte[]: {}\nClass<T>: {}\nError: {}", bytes, clazz.getName(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -123,8 +118,7 @@ public class JsonUtil {
|
|||||||
str = escapesSpecialChar(str);
|
str = escapesSpecialChar(str);
|
||||||
try {
|
try {
|
||||||
return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
|
return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
logger.error("Parse String to Object error\nString: {}\nTypeReference<T>: {}\nError: {}", str,
|
logger.error("Parse String to Object error\nString: {}\nTypeReference<T>: {}\nError: {}", str,
|
||||||
typeReference.getType(), e);
|
typeReference.getType(), e);
|
||||||
return null;
|
return null;
|
||||||
@@ -138,8 +132,7 @@ public class JsonUtil {
|
|||||||
try {
|
try {
|
||||||
return (T) (typeReference.getType().equals(byte[].class) ? bytes : objectMapper.readValue(bytes,
|
return (T) (typeReference.getType().equals(byte[].class) ? bytes : objectMapper.readValue(bytes,
|
||||||
typeReference));
|
typeReference));
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
logger.error("Parse byte[] to Object error\nbyte[]: {}\nTypeReference<T>: {}\nError: {}", bytes,
|
logger.error("Parse byte[] to Object error\nbyte[]: {}\nTypeReference<T>: {}\nError: {}", bytes,
|
||||||
typeReference.getType(), e);
|
typeReference.getType(), e);
|
||||||
return null;
|
return null;
|
||||||
|
@@ -58,6 +58,12 @@ rocketmq:
|
|||||||
ticketKey: ticket
|
ticketKey: ticket
|
||||||
# must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
# must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
||||||
loginRequired: false
|
loginRequired: false
|
||||||
|
# Authentication mode for RocketMQ Dashboard
|
||||||
|
# Available options:
|
||||||
|
# - 'file': Use username/password stored in a file (requires 'auth.file.path')
|
||||||
|
# - 'acl': Use credentials from ACL system (requires 'acl.access.key' and 'acl.secret.key')
|
||||||
|
# Default: file
|
||||||
|
authMode: file
|
||||||
useTLS: false
|
useTLS: false
|
||||||
proxyAddr: 127.0.0.1:8080
|
proxyAddr: 127.0.0.1:8080
|
||||||
proxyAddrs:
|
proxyAddrs:
|
||||||
|
@@ -14,13 +14,10 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This file supports hot change, any change will be auto-reloaded without Dashboard restarting.
|
# This file supports hot change, any change will be auto-reloaded without Dashboard restarting.
|
||||||
# Format: a user per line, username=password[,N] #N is optional, 0 (Normal User); 1 (Admin)
|
# Format: a user per line, username=password[,N] #N is optional, 0 (Normal User); 1 (Admin)
|
||||||
|
|
||||||
# Define Admin
|
# Define Admin
|
||||||
admin=admin,1
|
super=admin,1
|
||||||
|
|
||||||
# Define Users
|
# Define Users
|
||||||
user1=user1
|
user1=user
|
||||||
user2=user2
|
user2=user
|
||||||
|
@@ -17,12 +17,20 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard;
|
package org.apache.rocketmq.dashboard;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
import java.util.ArrayList;
|
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||||
import java.util.List;
|
|
||||||
import org.mockito.internal.util.MockUtil;
|
import org.mockito.internal.util.MockUtil;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class BaseTest {
|
public class BaseTest {
|
||||||
/**
|
/**
|
||||||
* Inject the corresponding mock class automatically
|
* Inject the corresponding mock class automatically
|
||||||
@@ -69,4 +77,20 @@ public class BaseTest {
|
|||||||
ReflectionUtils.doWithFields(leafClass, fc);
|
ReflectionUtils.doWithFields(leafClass, fc);
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ClusterInfo getClusterInfo() {
|
||||||
|
ClusterInfo clusterInfo = new ClusterInfo();
|
||||||
|
Map<String, Set<String>> clusterAddrTable = new HashMap<>();
|
||||||
|
clusterAddrTable.put("DefaultCluster", new HashSet<>(Arrays.asList("broker-a")));
|
||||||
|
Map<String, BrokerData> brokerAddrTable = new HashMap<>();
|
||||||
|
BrokerData brokerData = new BrokerData();
|
||||||
|
brokerData.setBrokerName("broker-a");
|
||||||
|
HashMap<Long, String> brokerNameTable = new HashMap<>();
|
||||||
|
brokerNameTable.put(0L, "localhost:10911");
|
||||||
|
brokerData.setBrokerAddrs(brokerNameTable);
|
||||||
|
brokerAddrTable.put("broker-a", brokerData);
|
||||||
|
clusterInfo.setBrokerAddrTable(brokerAddrTable);
|
||||||
|
clusterInfo.setClusterAddrTable(clusterAddrTable);
|
||||||
|
return clusterInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,26 +17,45 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.admin;
|
package org.apache.rocketmq.dashboard.admin;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||||
import org.apache.rocketmq.dashboard.aspect.admin.MQAdminAspect;
|
import org.apache.rocketmq.dashboard.aspect.admin.MQAdminAspect;
|
||||||
|
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||||
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
|
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
|
||||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
public class MQAdminAspectTest {
|
public class MQAdminAspectTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RMQConfigure rmqConfigure;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
when(rmqConfigure.isLoginRequired()).thenReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAroundMQAdminMethod() throws Throwable {
|
public void testAroundMQAdminMethod() throws Throwable {
|
||||||
MQAdminAspect mqAdminAspect = new MQAdminAspect();
|
MQAdminAspect mqAdminAspect = new MQAdminAspect();
|
||||||
|
Field field = mqAdminAspect.getClass().getDeclaredField("rmqConfigure");
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(mqAdminAspect, rmqConfigure);
|
||||||
ProceedingJoinPoint joinPoint = mock(ProceedingJoinPoint.class);
|
ProceedingJoinPoint joinPoint = mock(ProceedingJoinPoint.class);
|
||||||
MethodSignature signature = mock(MethodSignature.class);
|
MethodSignature signature = mock(MethodSignature.class);
|
||||||
Method method = mock(Method.class);
|
Method method = mock(Method.class);
|
||||||
@@ -44,16 +63,39 @@ public class MQAdminAspectTest {
|
|||||||
when(joinPoint.getSignature()).thenReturn(signature);
|
when(joinPoint.getSignature()).thenReturn(signature);
|
||||||
|
|
||||||
GenericObjectPool<MQAdminExt> mqAdminExtPool = mock(GenericObjectPool.class);
|
GenericObjectPool<MQAdminExt> mqAdminExtPool = mock(GenericObjectPool.class);
|
||||||
|
// 1. Mock borrowObject() 行为:第一次抛异常,第二次返回 DefaultMQAdminExt
|
||||||
when(mqAdminExtPool.borrowObject())
|
when(mqAdminExtPool.borrowObject())
|
||||||
.thenThrow(new RuntimeException("borrowObject exception"))
|
.thenThrow(new RuntimeException("borrowObject exception"))
|
||||||
.thenReturn(new DefaultMQAdminExt());
|
.thenReturn(new DefaultMQAdminExt());
|
||||||
doNothing().doThrow(new RuntimeException("returnObject exception"))
|
|
||||||
|
// 2. Mock returnObject() 行为:第一次什么都不做,第二次抛异常
|
||||||
|
doNothing().when(mqAdminExtPool).returnObject(any());
|
||||||
|
doThrow(new RuntimeException("returnObject exception"))
|
||||||
.when(mqAdminExtPool).returnObject(any());
|
.when(mqAdminExtPool).returnObject(any());
|
||||||
Field field = mqAdminAspect.getClass().getDeclaredField("mqAdminExtPool");
|
|
||||||
|
// 3. 通过反射注入 Mock 对象
|
||||||
|
field = mqAdminAspect.getClass().getDeclaredField("mqAdminExtPool");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(mqAdminAspect, mqAdminExtPool);
|
field.set(mqAdminAspect, mqAdminExtPool);
|
||||||
// exception
|
|
||||||
|
// 4. 第一次调用 aroundMQAdminMethod,预期 borrowObject() 抛异常
|
||||||
|
try {
|
||||||
mqAdminAspect.aroundMQAdminMethod(joinPoint);
|
mqAdminAspect.aroundMQAdminMethod(joinPoint);
|
||||||
|
fail("Expected RuntimeException but no exception was thrown");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
assertEquals("borrowObject exception", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 第二次调用 aroundMQAdminMethod,预期 borrowObject() 成功,但 returnObject() 抛异常
|
||||||
|
try {
|
||||||
mqAdminAspect.aroundMQAdminMethod(joinPoint);
|
mqAdminAspect.aroundMQAdminMethod(joinPoint);
|
||||||
|
fail("Expected RuntimeException but no exception was thrown");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
assertEquals("returnObject exception", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 验证 borrowObject() 和 returnObject() 各调用了两次
|
||||||
|
verify(mqAdminExtPool, times(2)).borrowObject();
|
||||||
|
verify(mqAdminExtPool, times(1)).returnObject(any());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,27 +19,25 @@ package org.apache.rocketmq.dashboard.admin;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.apache.rocketmq.client.QueryResult;
|
import org.apache.rocketmq.client.QueryResult;
|
||||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||||
import org.apache.rocketmq.client.impl.MQAdminImpl;
|
import org.apache.rocketmq.client.impl.MQAdminImpl;
|
||||||
import org.apache.rocketmq.client.impl.MQClientAPIImpl;
|
import org.apache.rocketmq.client.impl.MQClientAPIImpl;
|
||||||
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
|
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
|
||||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
|
||||||
import org.apache.rocketmq.common.TopicConfig;
|
import org.apache.rocketmq.common.TopicConfig;
|
||||||
|
import org.apache.rocketmq.common.message.Message;
|
||||||
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
|
import org.apache.rocketmq.common.message.MessageQueue;
|
||||||
|
import org.apache.rocketmq.dashboard.service.client.MQAdminExtImpl;
|
||||||
|
import org.apache.rocketmq.dashboard.service.client.MQAdminInstance;
|
||||||
|
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||||
|
import org.apache.rocketmq.remoting.RemotingClient;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||||
import org.apache.rocketmq.common.message.MessageExt;
|
|
||||||
import org.apache.rocketmq.common.message.MessageQueue;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||||
@@ -55,12 +53,6 @@ import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
|
|||||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||||
import org.apache.rocketmq.dashboard.service.client.MQAdminExtImpl;
|
|
||||||
import org.apache.rocketmq.dashboard.service.client.MQAdminInstance;
|
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
|
||||||
import org.apache.rocketmq.remoting.RemotingClient;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
|
|
||||||
import org.apache.rocketmq.store.stats.BrokerStatsManager;
|
import org.apache.rocketmq.store.stats.BrokerStatsManager;
|
||||||
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
|
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
|
||||||
import org.apache.rocketmq.tools.admin.DefaultMQAdminExtImpl;
|
import org.apache.rocketmq.tools.admin.DefaultMQAdminExtImpl;
|
||||||
@@ -74,22 +66,25 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyMap;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||||
public class MQAdminExtImplTest {
|
public class MQAdminExtImplTest {
|
||||||
@@ -154,35 +149,6 @@ public class MQAdminExtImplTest {
|
|||||||
mqAdminExtImpl.createAndUpdateTopicConfig(brokerAddr, new TopicConfig());
|
mqAdminExtImpl.createAndUpdateTopicConfig(brokerAddr, new TopicConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDeletePlainAccessConfig() throws Exception {
|
|
||||||
assertNotNull(mqAdminExtImpl);
|
|
||||||
mqAdminExtImpl.deletePlainAccessConfig(brokerAddr, "rocketmq");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUpdateGlobalWhiteAddrConfig() throws Exception {
|
|
||||||
assertNotNull(mqAdminExtImpl);
|
|
||||||
mqAdminExtImpl.updateGlobalWhiteAddrConfig(brokerAddr, "192.168.*.*");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateAndUpdatePlainAccessConfig() throws Exception {
|
|
||||||
assertNotNull(mqAdminExtImpl);
|
|
||||||
mqAdminExtImpl.createAndUpdatePlainAccessConfig(brokerAddr, new PlainAccessConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExamineBrokerClusterAclVersionInfo() throws Exception {
|
|
||||||
assertNotNull(mqAdminExtImpl);
|
|
||||||
assertNull(mqAdminExtImpl.examineBrokerClusterAclVersionInfo(brokerAddr));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExamineBrokerClusterAclConfig() throws Exception {
|
|
||||||
assertNotNull(mqAdminExtImpl);
|
|
||||||
assertNull(mqAdminExtImpl.examineBrokerClusterAclConfig(brokerAddr));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQueryConsumerStatus() throws Exception {
|
public void testQueryConsumerStatus() throws Exception {
|
||||||
@@ -226,18 +192,15 @@ public class MQAdminExtImplTest {
|
|||||||
public void testExamineTopicConfig() throws Exception {
|
public void testExamineTopicConfig() throws Exception {
|
||||||
assertNotNull(mqAdminExtImpl);
|
assertNotNull(mqAdminExtImpl);
|
||||||
|
|
||||||
// Create valid TopicConfigSerializeWrapper with topic_test entry
|
// Create valid TopicConfigSerializeWrapper with topictest entry
|
||||||
TopicConfigSerializeWrapper wrapper = new TopicConfigSerializeWrapper();
|
|
||||||
ConcurrentMap<String, TopicConfig> topicConfigTable = new ConcurrentHashMap<>();
|
|
||||||
TopicConfig config = new TopicConfig();
|
TopicConfig config = new TopicConfig();
|
||||||
config.setTopicName("topic_test");
|
config.setTopicName("topic_test");
|
||||||
topicConfigTable.put("topic_test", config);
|
|
||||||
wrapper.setTopicConfigTable(topicConfigTable);
|
|
||||||
|
|
||||||
// Create successful response
|
// Create successful response
|
||||||
RemotingCommand successResponse = RemotingCommand.createResponseCommand(null);
|
RemotingCommand successResponse = RemotingCommand.createResponseCommand(null);
|
||||||
successResponse.setCode(ResponseCode.SUCCESS);
|
successResponse.setCode(ResponseCode.SUCCESS);
|
||||||
successResponse.setBody(RemotingSerializable.encode(wrapper));
|
successResponse.setBody(RemotingSerializable.encode(config));
|
||||||
|
|
||||||
// Mock the remote invocation
|
// Mock the remote invocation
|
||||||
when(remotingClient.invokeSync(eq(brokerAddr), any(RemotingCommand.class), anyLong()))
|
when(remotingClient.invokeSync(eq(brokerAddr), any(RemotingCommand.class), anyLong()))
|
||||||
@@ -249,6 +212,7 @@ public class MQAdminExtImplTest {
|
|||||||
Assert.assertEquals("topic_test", topicConfig.getTopicName());
|
Assert.assertEquals("topic_test", topicConfig.getTopicName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExamineTopicStats() throws Exception {
|
public void testExamineTopicStats() throws Exception {
|
||||||
assertNotNull(mqAdminExtImpl);
|
assertNotNull(mqAdminExtImpl);
|
||||||
@@ -257,7 +221,7 @@ public class MQAdminExtImplTest {
|
|||||||
}
|
}
|
||||||
TopicStatsTable topicStatsTable = mqAdminExtImpl.examineTopicStats("topic_test");
|
TopicStatsTable topicStatsTable = mqAdminExtImpl.examineTopicStats("topic_test");
|
||||||
Assert.assertNotNull(topicStatsTable);
|
Assert.assertNotNull(topicStatsTable);
|
||||||
Assert.assertEquals(topicStatsTable.getOffsetTable().size(), 1);
|
Assert.assertEquals(1, topicStatsTable.getOffsetTable().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -535,12 +499,10 @@ public class MQAdminExtImplTest {
|
|||||||
public void testConsumeMessageDirectly() throws Exception {
|
public void testConsumeMessageDirectly() throws Exception {
|
||||||
assertNotNull(mqAdminExtImpl);
|
assertNotNull(mqAdminExtImpl);
|
||||||
{
|
{
|
||||||
when(defaultMQAdminExt.consumeMessageDirectly(anyString(), anyString(), anyString())).thenReturn(new ConsumeMessageDirectlyResult());
|
|
||||||
when(defaultMQAdminExt.consumeMessageDirectly(anyString(), anyString(), anyString(), anyString())).thenReturn(new ConsumeMessageDirectlyResult());
|
when(defaultMQAdminExt.consumeMessageDirectly(anyString(), anyString(), anyString(), anyString())).thenReturn(new ConsumeMessageDirectlyResult());
|
||||||
}
|
}
|
||||||
ConsumeMessageDirectlyResult result1 = mqAdminExtImpl.consumeMessageDirectly("group_test", "", "7F000001ACC018B4AAC2116AF6500000");
|
|
||||||
ConsumeMessageDirectlyResult result2 = mqAdminExtImpl.consumeMessageDirectly("group_test", "", "topic_test", "7F000001ACC018B4AAC2116AF6500000");
|
ConsumeMessageDirectlyResult result2 = mqAdminExtImpl.consumeMessageDirectly("group_test", "", "topic_test", "7F000001ACC018B4AAC2116AF6500000");
|
||||||
Assert.assertNotNull(result1);
|
|
||||||
Assert.assertNotNull(result2);
|
Assert.assertNotNull(result2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,15 +578,6 @@ public class MQAdminExtImplTest {
|
|||||||
Assert.assertEquals(storeTime, 1628495765398L);
|
Assert.assertEquals(storeTime, 1628495765398L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testViewMessage() throws Exception {
|
|
||||||
assertNotNull(mqAdminExtImpl);
|
|
||||||
{
|
|
||||||
when(defaultMQAdminExt.viewMessage(anyString())).thenReturn(new MessageExt());
|
|
||||||
}
|
|
||||||
MessageExt messageExt = mqAdminExtImpl.viewMessage("7F000001ACC018B4AAC2116AF6500000");
|
|
||||||
Assert.assertNotNull(messageExt);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQueryMessage() throws Exception {
|
public void testQueryMessage() throws Exception {
|
||||||
@@ -666,15 +619,6 @@ public class MQAdminExtImplTest {
|
|||||||
Assert.assertNotNull(timeSpans);
|
Assert.assertNotNull(timeSpans);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testViewMessage2() throws Exception {
|
|
||||||
assertNotNull(mqAdminExtImpl);
|
|
||||||
{
|
|
||||||
when(MQAdminInstance.threadLocalMqClientInstance().getMQAdminImpl()).thenReturn(mock(MQAdminImpl.class));
|
|
||||||
when(defaultMQAdminExt.viewMessage(anyString())).thenThrow(new RuntimeException("viewMessage exception"));
|
|
||||||
}
|
|
||||||
mqAdminExtImpl.viewMessage("topic_test", "7F000001ACC018B4AAC2116AF6500000");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetBrokerConfig() throws Exception {
|
public void testGetBrokerConfig() throws Exception {
|
||||||
@@ -788,7 +732,6 @@ public class MQAdminExtImplTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testResumeCheckHalfMessage() throws Exception {
|
public void testResumeCheckHalfMessage() throws Exception {
|
||||||
assertNotNull(mqAdminExtImpl);
|
assertNotNull(mqAdminExtImpl);
|
||||||
Assert.assertFalse(mqAdminExtImpl.resumeCheckHalfMessage("7F000001ACC018B4AAC2116AF6500000"));
|
|
||||||
Assert.assertFalse(mqAdminExtImpl.resumeCheckHalfMessage("topic_test", "7F000001ACC018B4AAC2116AF6500000"));
|
Assert.assertFalse(mqAdminExtImpl.resumeCheckHalfMessage("topic_test", "7F000001ACC018B4AAC2116AF6500000"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,56 +18,41 @@
|
|||||||
package org.apache.rocketmq.dashboard.config;
|
package org.apache.rocketmq.dashboard.config;
|
||||||
|
|
||||||
import org.apache.rocketmq.dashboard.BaseTest;
|
import org.apache.rocketmq.dashboard.BaseTest;
|
||||||
import org.apache.rocketmq.dashboard.interceptor.AuthInterceptor;
|
|
||||||
import org.assertj.core.util.Lists;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.mockito.InjectMocks;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
||||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AuthWebMVCConfigurerAdapterTest extends BaseTest {
|
public class AuthWebMVCConfigurerAdapterTest extends BaseTest {
|
||||||
|
|
||||||
@InjectMocks
|
// @InjectMocks
|
||||||
private AuthWebMVCConfigurerAdapter authWebMVCConfigurerAdapter;
|
// private AuthWebMVCConfigurerAdapter authWebMVCConfigurerAdapter;
|
||||||
|
//
|
||||||
@Mock
|
// @Mock
|
||||||
private RMQConfigure configure;
|
// private RMQConfigure configure;
|
||||||
|
//
|
||||||
@Mock
|
// @Mock
|
||||||
private AuthInterceptor authInterceptor;
|
// private AuthInterceptor authInterceptor;
|
||||||
|
//
|
||||||
@Before
|
// @Before
|
||||||
public void init() throws Exception {
|
// public void init() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
// MockitoAnnotations.initMocks(this);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void addInterceptors() {
|
// public void addInterceptors() {
|
||||||
Mockito.when(configure.isLoginRequired()).thenReturn(true);
|
// Mockito.when(configure.isLoginRequired()).thenReturn(true);
|
||||||
InterceptorRegistry registry = new InterceptorRegistry();
|
// InterceptorRegistry registry = new InterceptorRegistry();
|
||||||
Assertions.assertDoesNotThrow(() -> authWebMVCConfigurerAdapter.addInterceptors(registry));
|
// Assertions.assertDoesNotThrow(() -> authWebMVCConfigurerAdapter.addInterceptors(registry));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void addArgumentResolvers() {
|
// public void addArgumentResolvers() {
|
||||||
List<HandlerMethodArgumentResolver> argumentResolvers = Lists.newArrayList();
|
// List<HandlerMethodArgumentResolver> argumentResolvers = Lists.newArrayList();
|
||||||
authWebMVCConfigurerAdapter.addArgumentResolvers(argumentResolvers);
|
// authWebMVCConfigurerAdapter.addArgumentResolvers(argumentResolvers);
|
||||||
Assertions.assertEquals(1, argumentResolvers.size());
|
// Assertions.assertEquals(1, argumentResolvers.size());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void addViewControllers() {
|
// public void addViewControllers() {
|
||||||
ViewControllerRegistry registry = new ViewControllerRegistry(new ClassPathXmlApplicationContext());
|
// ViewControllerRegistry registry = new ViewControllerRegistry(new ClassPathXmlApplicationContext());
|
||||||
Assertions.assertDoesNotThrow(() -> authWebMVCConfigurerAdapter.addViewControllers(registry));
|
// Assertions.assertDoesNotThrow(() -> authWebMVCConfigurerAdapter.addViewControllers(registry));
|
||||||
}
|
// }
|
||||||
}
|
}
|
@@ -16,11 +16,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.rocketmq.dashboard.config;
|
package org.apache.rocketmq.dashboard.config;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class CollectExecutorConfigTest {
|
public class CollectExecutorConfigTest {
|
||||||
|
|
||||||
|
@@ -18,13 +18,14 @@
|
|||||||
package org.apache.rocketmq.dashboard.config;
|
package org.apache.rocketmq.dashboard.config;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import java.io.File;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.boot.web.server.ErrorPage;
|
import org.springframework.boot.web.server.ErrorPage;
|
||||||
import org.springframework.boot.web.server.ErrorPageRegistrar;
|
import org.springframework.boot.web.server.ErrorPageRegistrar;
|
||||||
import org.springframework.boot.web.server.ErrorPageRegistry;
|
import org.springframework.boot.web.server.ErrorPageRegistry;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
public class RMQConfigureTest {
|
public class RMQConfigureTest {
|
||||||
|
|
||||||
private RMQConfigure rmqConfigure = new RMQConfigure();
|
private RMQConfigure rmqConfigure = new RMQConfigure();
|
||||||
@@ -41,6 +42,7 @@ public class RMQConfigureTest {
|
|||||||
rmqConfigure.setNamesrvAddr("127.0.0.1:9876");
|
rmqConfigure.setNamesrvAddr("127.0.0.1:9876");
|
||||||
rmqConfigure.setTimeoutMillis(3000L);
|
rmqConfigure.setTimeoutMillis(3000L);
|
||||||
rmqConfigure.setNamesrvAddrs(Lists.asList("127.0.0.1:9876", new String[]{"127.0.0.2:9876"}));
|
rmqConfigure.setNamesrvAddrs(Lists.asList("127.0.0.1:9876", new String[]{"127.0.0.2:9876"}));
|
||||||
|
rmqConfigure.setAuthMode("file");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -58,6 +60,7 @@ public class RMQConfigureTest {
|
|||||||
Assert.assertEquals(rmqConfigure.getNamesrvAddr(), "127.0.0.1:9876");
|
Assert.assertEquals(rmqConfigure.getNamesrvAddr(), "127.0.0.1:9876");
|
||||||
Assert.assertEquals(rmqConfigure.getNamesrvAddrs().size(), 2);
|
Assert.assertEquals(rmqConfigure.getNamesrvAddrs().size(), 2);
|
||||||
Assert.assertEquals(rmqConfigure.getTimeoutMillis().longValue(), 3000L);
|
Assert.assertEquals(rmqConfigure.getTimeoutMillis().longValue(), 3000L);
|
||||||
|
Assert.assertEquals(rmqConfigure.getAuthMode(), "file");
|
||||||
ErrorPageRegistrar registrar = rmqConfigure.errorPageRegistrar();
|
ErrorPageRegistrar registrar = rmqConfigure.errorPageRegistrar();
|
||||||
registrar.registerErrorPages(new ErrorPageRegistry() {
|
registrar.registerErrorPages(new ErrorPageRegistry() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -16,353 +16,228 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.rocketmq.dashboard.controller;
|
package org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.google.common.collect.Lists;
|
import org.apache.rocketmq.auth.authentication.enums.UserStatus;
|
||||||
import java.util.List;
|
import org.apache.rocketmq.auth.authentication.enums.UserType;
|
||||||
import org.apache.rocketmq.common.AclConfig;
|
import org.apache.rocketmq.auth.authorization.enums.Decision;
|
||||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
import org.apache.rocketmq.dashboard.model.Policy;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
import org.apache.rocketmq.dashboard.model.PolicyRequest;
|
||||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
import org.apache.rocketmq.dashboard.model.request.UserCreateRequest;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.UserInfoParam;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.UserUpdateRequest;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.AclServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.AclServiceImpl;
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.AclInfo;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Mock;
|
||||||
import org.springframework.http.MediaType;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import java.util.Arrays;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import java.util.List;
|
||||||
import static org.mockito.Mockito.doNothing;
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
||||||
|
|
||||||
public class AclControllerTest extends BaseControllerTest {
|
public class AclControllerTest extends BaseControllerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AclServiceImpl aclService;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private AclController aclController;
|
private AclController aclController;
|
||||||
|
|
||||||
@Spy
|
|
||||||
private AclServiceImpl aclService;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() throws Exception {
|
public void init() {
|
||||||
AclConfig aclConfig = MockObjectUtil.createAclConfig();
|
MockitoAnnotations.initMocks(this);
|
||||||
when(mqAdminExt.examineBrokerClusterAclConfig(anyString())).thenReturn(aclConfig);
|
mockMvc = MockMvcBuilders.standaloneSetup(aclController).setControllerAdvice(GlobalExceptionHandler.class).build();
|
||||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
}
|
||||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
|
||||||
doNothing().when(mqAdminExt).createAndUpdatePlainAccessConfig(anyString(), any(PlainAccessConfig.class));
|
|
||||||
doNothing().when(mqAdminExt).deletePlainAccessConfig(anyString(), anyString());
|
@Test
|
||||||
doNothing().when(mqAdminExt).updateGlobalWhiteAddrConfig(anyString(), anyString());
|
public void testListUsers() {
|
||||||
|
// Prepare test data
|
||||||
|
String brokerAddress = "localhost:10911";
|
||||||
|
List<UserInfo> expectedUsers = Arrays.asList(
|
||||||
|
UserInfo.of("user1", "password1", "super"),
|
||||||
|
UserInfo.of("user2", "password2", "super")
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock service behavior
|
||||||
|
when(aclService.listUsers(brokerAddress)).thenReturn(expectedUsers);
|
||||||
|
|
||||||
|
// Call controller method
|
||||||
|
List<UserInfo> result = aclController.listUsers(brokerAddress);
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
assertEquals(expectedUsers, result);
|
||||||
|
verify(aclService, times(1)).listUsers(brokerAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsEnableAcl() throws Exception {
|
public void testListUsersWithoutBrokerAddress() {
|
||||||
final String url = "/acl/enable.query";
|
// Prepare test data
|
||||||
// 1. disable acl.
|
List<UserInfo> expectedUsers = Arrays.asList(
|
||||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
UserInfo.of("user1", "password1", "super")
|
||||||
perform = mockMvc.perform(requestBuilder);
|
);
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.data").value(false));
|
|
||||||
|
|
||||||
// 2.enable acl.
|
// Mock service behavior
|
||||||
super.mockRmqConfigure();
|
when(aclService.listUsers(null)).thenReturn(expectedUsers);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
// Call controller method
|
||||||
perform.andExpect(status().isOk())
|
List<UserInfo> result = aclController.listUsers(null);
|
||||||
.andExpect(jsonPath("$.data").value(true));
|
// Verify
|
||||||
|
assertEquals(expectedUsers, result);
|
||||||
|
verify(aclService, times(1)).listUsers(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAclConfig() throws Exception {
|
public void testListAcls() {
|
||||||
final String url = "/acl/config.query";
|
// Prepare test data
|
||||||
|
String brokerAddress = "localhost:9092";
|
||||||
|
String searchParam = "user1";
|
||||||
|
Object expectedAcls = Arrays.asList(
|
||||||
|
AclInfo.of("user1", List.of("READ", "test"), List.of("TOPIC:test"), List.of("localhost:10911"), Decision.ALLOW.getName())
|
||||||
|
);
|
||||||
|
|
||||||
// 1. broker addr table is not empty.
|
// Mock service behavior
|
||||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
when(aclService.listAcls(brokerAddress, searchParam)).thenReturn(expectedAcls);
|
||||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
|
||||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.data").isMap())
|
|
||||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isNotEmpty())
|
|
||||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isNotEmpty())
|
|
||||||
.andExpect(jsonPath("$.data.plainAccessConfigs[0].secretKey").isNotEmpty());
|
|
||||||
|
|
||||||
// 2. broker addr table is empty.
|
// Call controller method
|
||||||
clusterInfo.getBrokerAddrTable().clear();
|
Object result = aclController.listAcls(brokerAddress, searchParam);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.data").isMap())
|
|
||||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isEmpty())
|
|
||||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isEmpty());
|
|
||||||
|
|
||||||
// 3. login required and user info is null.
|
// Verify
|
||||||
when(configure.isLoginRequired()).thenReturn(true);
|
assertEquals(expectedAcls, result);
|
||||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(MockObjectUtil.createClusterInfo());
|
verify(aclService, times(1)).listAcls(brokerAddress, searchParam);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.data").isMap())
|
|
||||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isNotEmpty())
|
|
||||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isNotEmpty())
|
|
||||||
.andExpect(jsonPath("$.data.plainAccessConfigs[0].secretKey").isEmpty());
|
|
||||||
// 4. login required, but user is not admin. emmmm, Mockito may can not mock static method.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddAclConfig() throws Exception {
|
public void testCreateAcl() {
|
||||||
final String url = "/acl/add.do";
|
// Prepare test data
|
||||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
PolicyRequest request = new PolicyRequest();
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
request.setBrokerAddress("localhost:9092");
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
request.setSubject("user1");
|
||||||
|
request.setPolicies(List.of(
|
||||||
|
new Policy()
|
||||||
|
));
|
||||||
|
|
||||||
// 1. access key is null.
|
// Call controller method
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
Object result = aclController.createAcl(request);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
|
||||||
.andExpect(jsonPath("$.errMsg").exists());
|
|
||||||
|
|
||||||
// 2. secret key is null.
|
// Verify
|
||||||
accessConfig.setAccessKey("test-access-key");
|
assertEquals(true, result);
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
verify(aclService, times(1)).createAcl(request);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
|
||||||
.andExpect(jsonPath("$.errMsg").exists());
|
|
||||||
|
|
||||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
|
||||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
|
||||||
|
|
||||||
// 3. add if the access key not exist.
|
|
||||||
accessConfig.setSecretKey("12345678");
|
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
|
|
||||||
// 4. add failed if the access key is existed.
|
|
||||||
accessConfig.setAccessKey("rocketmq2");
|
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
|
||||||
.andExpect(jsonPath("$.errMsg").exists());
|
|
||||||
|
|
||||||
// 5. add failed if there is no alive broker.
|
|
||||||
clusterInfo.getBrokerAddrTable().clear();
|
|
||||||
accessConfig.setAccessKey("test-access-key");
|
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
|
||||||
.andExpect(jsonPath("$.errMsg").exists());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteAclConfig() throws Exception {
|
public void testDeleteUser() {
|
||||||
final String url = "/acl/delete.do";
|
// Prepare test data
|
||||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
String brokerAddress = "localhost:9092";
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
String username = "user1";
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
|
|
||||||
// 1. access key is null.
|
// Call controller method
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
Object result = aclController.deleteUser(brokerAddress, username);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
|
||||||
.andExpect(jsonPath("$.errMsg").exists());
|
|
||||||
|
|
||||||
// 2. access key is not null.
|
// Verify
|
||||||
accessConfig.setAccessKey("rocketmq");
|
assertEquals(true, result);
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
verify(aclService, times(1)).deleteUser(brokerAddress, username);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateAclConfig() throws Exception {
|
public void testDeleteUserWithoutBrokerAddress() {
|
||||||
final String url = "/acl/update.do";
|
// Prepare test data
|
||||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
String username = "user1";
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
|
|
||||||
// 1. secret key is null.
|
// Call controller method
|
||||||
accessConfig.setAccessKey("rocketmq");
|
Object result = aclController.deleteUser(null, username);
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
|
||||||
.andExpect(jsonPath("$.errMsg").exists());
|
|
||||||
|
|
||||||
// 2. update.
|
// Verify
|
||||||
accessConfig.setSecretKey("abcdefghjkl");
|
assertEquals(true, result);
|
||||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
verify(aclService, times(1)).deleteUser(null, username);
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddAclTopicConfig() throws Exception {
|
public void testUpdateUser() {
|
||||||
final String url = "/acl/topic/add.do";
|
// Prepare test data
|
||||||
AclRequest request = new AclRequest();
|
UserUpdateRequest request = new UserUpdateRequest();
|
||||||
request.setConfig(createDefaultPlainAccessConfig());
|
request.setBrokerAddress("localhost:9092");
|
||||||
|
request.setUserInfo(new UserInfoParam("user1", "newPassword", UserStatus.ENABLE.getName(), UserType.SUPER.getName()));
|
||||||
|
|
||||||
// 1. if not exist.
|
// Call controller method
|
||||||
request.setTopicPerm("test_topic=PUB");
|
Object result = aclController.updateUser(request);
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
|
|
||||||
// 2. if exist.
|
// Verify
|
||||||
request.setTopicPerm("topicA=PUB");
|
assertEquals(true, result);
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
verify(aclService, times(1)).updateUser(request.getBrokerAddress(), request.getUserInfo());
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
|
|
||||||
// 3. if access key not exist.
|
|
||||||
request.getConfig().setAccessKey("test_access_key123");
|
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddAclGroupConfig() throws Exception {
|
public void testCreateUser() {
|
||||||
final String url = "/acl/group/add.do";
|
// Prepare test data
|
||||||
AclRequest request = new AclRequest();
|
UserCreateRequest request = new UserCreateRequest();
|
||||||
request.setConfig(createDefaultPlainAccessConfig());
|
request.setBrokerAddress("localhost:9092");
|
||||||
|
request.setUserInfo(new UserInfoParam("user1", "newPassword", UserStatus.ENABLE.getName(), UserType.SUPER.getName()));
|
||||||
|
|
||||||
// 1. if not exist.
|
// Call controller method
|
||||||
request.setGroupPerm("test_consumer=PUB|SUB");
|
Object result = aclController.createUser(request);
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
|
|
||||||
// 2. if exist.
|
// Verify
|
||||||
request.setGroupPerm("groupA=PUB|SUB");
|
assertEquals(true, result);
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
verify(aclService, times(1)).createUser(request.getBrokerAddress(), request.getUserInfo());
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
|
|
||||||
// 3. if access key not exist.
|
|
||||||
request.getConfig().setAccessKey("test_access_key123");
|
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletePermConfig() throws Exception {
|
public void testDeleteAcl() {
|
||||||
final String url = "/acl/perm/delete.do";
|
// Prepare test data
|
||||||
AclRequest request = new AclRequest();
|
String brokerAddress = "localhost:9092";
|
||||||
request.setConfig(createDefaultPlainAccessConfig());
|
String subject = "user1";
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
String resource = "TOPIC:test";
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
|
|
||||||
// if access key not exist.
|
// Call controller method
|
||||||
request.getConfig().setAccessKey("test_access_key123");
|
Object result = aclController.deleteAcl(brokerAddress, subject, resource);
|
||||||
requestBuilder.content(JSON.toJSONString(request));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
// Verify
|
||||||
perform.andExpect(status().isOk())
|
assertEquals(true, result);
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
verify(aclService, times(1)).deleteAcl(brokerAddress, subject, resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSyncConfig() throws Exception {
|
public void testDeleteAclWithoutBrokerAddressAndResource() {
|
||||||
final String url = "/acl/sync.do";
|
// Prepare test data
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
String subject = "user1";
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
requestBuilder.content(JSON.toJSONString(createDefaultPlainAccessConfig()));
|
// Call controller method
|
||||||
perform = mockMvc.perform(requestBuilder);
|
Object result = aclController.deleteAcl(null, subject, null);
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
// Verify
|
||||||
|
assertEquals(true, result);
|
||||||
|
verify(aclService, times(1)).deleteAcl(null, subject, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddWhiteList() throws Exception {
|
public void testUpdateAcl() {
|
||||||
final String url = "/acl/white/list/add.do";
|
// Prepare test data
|
||||||
List<String> whiteList = Lists.newArrayList("192.168.0.1");
|
PolicyRequest request = new PolicyRequest();
|
||||||
|
request.setBrokerAddress("localhost:9092");
|
||||||
|
request.setSubject("user1");
|
||||||
|
request.setPolicies(List.of(
|
||||||
|
new Policy()
|
||||||
|
));
|
||||||
|
|
||||||
// 1. if global white list is not null.
|
// Call controller method
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
Object result = aclController.updateAcl(request);
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
|
|
||||||
// 2. if global white list is null.
|
// Verify
|
||||||
AclConfig aclConfig = MockObjectUtil.createAclConfig();
|
assertEquals(true, result);
|
||||||
aclConfig.setGlobalWhiteAddrs(null);
|
verify(aclService, times(1)).updateAcl(request);
|
||||||
when(mqAdminExt.examineBrokerClusterAclConfig(anyString())).thenReturn(aclConfig);
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Override
|
||||||
public void testDeleteWhiteAddr() throws Exception {
|
protected Object getTestController() {
|
||||||
final String url = "/acl/white/list/delete.do";
|
|
||||||
requestBuilder = MockMvcRequestBuilders.delete(url);
|
|
||||||
requestBuilder.param("request", "localhost");
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSynchronizeWhiteList() throws Exception {
|
|
||||||
final String url = "/acl/white/list/sync.do";
|
|
||||||
List<String> whiteList = Lists.newArrayList();
|
|
||||||
|
|
||||||
// 1. if white list for syncing is empty.
|
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
|
||||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
|
||||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
|
||||||
.andExpect(jsonPath("$.errMsg").exists());
|
|
||||||
|
|
||||||
// 2. if white list for syncing is not empty.
|
|
||||||
whiteList.add("localhost");
|
|
||||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.status").value(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
|
||||||
return aclController;
|
return aclController;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlainAccessConfig createDefaultPlainAccessConfig() {
|
|
||||||
PlainAccessConfig config = new PlainAccessConfig();
|
|
||||||
config.setAdmin(false);
|
|
||||||
config.setAccessKey("rocketmq");
|
|
||||||
config.setSecretKey("123456789");
|
|
||||||
config.setDefaultGroupPerm("SUB");
|
|
||||||
config.setDefaultTopicPerm("DENY");
|
|
||||||
config.setTopicPerms(Lists.newArrayList("topicA=DENY", "topicB=PUB|SUB"));
|
|
||||||
config.setGroupPerms(Lists.newArrayList("groupA=DENY", "groupB=PUB|SUB"));
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -23,6 +23,8 @@ import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
|||||||
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
||||||
import org.apache.rocketmq.dashboard.support.GlobalRestfulResponseBodyAdvice;
|
import org.apache.rocketmq.dashboard.support.GlobalRestfulResponseBodyAdvice;
|
||||||
import org.apache.rocketmq.dashboard.util.MyPrintingResultHandler;
|
import org.apache.rocketmq.dashboard.util.MyPrintingResultHandler;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@@ -32,6 +34,12 @@ import org.springframework.test.web.servlet.ResultActions;
|
|||||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
@@ -16,17 +16,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.rocketmq.dashboard.controller;
|
package org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Properties;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
|
||||||
import org.apache.rocketmq.dashboard.service.impl.ClusterServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.ClusterServiceImpl;
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
@@ -19,44 +19,43 @@ package org.apache.rocketmq.dashboard.controller;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.apache.rocketmq.client.exception.MQClientException;
|
import org.apache.rocketmq.client.exception.MQClientException;
|
||||||
|
import org.apache.rocketmq.common.message.MessageQueue;
|
||||||
|
import org.apache.rocketmq.dashboard.model.QueueStatInfo;
|
||||||
|
import org.apache.rocketmq.dashboard.model.TopicConsumerInfo;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
|
||||||
|
import org.apache.rocketmq.dashboard.service.ClusterInfoService;
|
||||||
|
import org.apache.rocketmq.dashboard.service.impl.ConsumerServiceImpl;
|
||||||
|
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||||
import org.apache.rocketmq.common.message.MessageQueue;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
||||||
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
|
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
|
||||||
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
|
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
|
||||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||||
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
|
||||||
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
|
|
||||||
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
|
|
||||||
import org.apache.rocketmq.dashboard.service.impl.ConsumerServiceImpl;
|
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
|
||||||
import org.apache.rocketmq.dashboard.model.TopicConsumerInfo;
|
|
||||||
import org.apache.rocketmq.dashboard.model.QueueStatInfo;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.ArgumentMatchers.isNull;
|
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -71,12 +70,18 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
|||||||
@Spy
|
@Spy
|
||||||
private ConsumerServiceImpl consumerService;
|
private ConsumerServiceImpl consumerService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ClusterInfoService clusterInfoService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
|
// 2. mock ClusterInfo data
|
||||||
|
ClusterInfo mockClusterInfo = getClusterInfo();
|
||||||
|
when(clusterInfoService.get()).thenReturn(mockClusterInfo);
|
||||||
consumerService.afterPropertiesSet();
|
consumerService.afterPropertiesSet();
|
||||||
super.mockRmqConfigure();
|
super.mockRmqConfigure();
|
||||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
// ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
// when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||||
SubscriptionGroupWrapper wrapper = MockObjectUtil.createSubscriptionGroupWrapper();
|
SubscriptionGroupWrapper wrapper = MockObjectUtil.createSubscriptionGroupWrapper();
|
||||||
when(mqAdminExt.getAllSubscriptionGroup(anyString(), anyLong())).thenReturn(wrapper);
|
when(mqAdminExt.getAllSubscriptionGroup(anyString(), anyLong())).thenReturn(wrapper);
|
||||||
ConsumeStats stats = MockObjectUtil.createConsumeStats();
|
ConsumeStats stats = MockObjectUtil.createConsumeStats();
|
||||||
@@ -109,6 +114,7 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testGroupQuery() throws Exception {
|
public void testGroupQuery() throws Exception {
|
||||||
final String url = "/consumer/group.query";
|
final String url = "/consumer/group.query";
|
||||||
|
|
||||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||||
requestBuilder.param("consumerGroup", "group_test");
|
requestBuilder.param("consumerGroup", "group_test");
|
||||||
perform = mockMvc.perform(requestBuilder);
|
perform = mockMvc.perform(requestBuilder);
|
||||||
@@ -177,6 +183,10 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExamineSubscriptionGroupConfig() throws Exception {
|
public void testExamineSubscriptionGroupConfig() throws Exception {
|
||||||
|
ClusterInfo mockClusterInfo = getClusterInfo();
|
||||||
|
{
|
||||||
|
when(clusterInfoService.get()).thenReturn(mockClusterInfo);
|
||||||
|
}
|
||||||
final String url = "/consumer/examineSubscriptionGroupConfig.query";
|
final String url = "/consumer/examineSubscriptionGroupConfig.query";
|
||||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||||
requestBuilder.param("consumerGroup", "group_test");
|
requestBuilder.param("consumerGroup", "group_test");
|
||||||
@@ -188,7 +198,9 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testDelete() throws Exception {
|
public void testDelete() throws Exception {
|
||||||
final String url = "/consumer/deleteSubGroup.do";
|
final String url = "/consumer/deleteSubGroup.do";
|
||||||
|
ClusterInfo mockClusterInfo = getClusterInfo();
|
||||||
{
|
{
|
||||||
|
when(clusterInfoService.get()).thenReturn(mockClusterInfo);
|
||||||
doNothing().when(mqAdminExt).deleteSubscriptionGroup(any(), anyString());
|
doNothing().when(mqAdminExt).deleteSubscriptionGroup(any(), anyString());
|
||||||
doNothing().when(mqAdminExt).deleteTopicInBroker(any(), anyString());
|
doNothing().when(mqAdminExt).deleteTopicInBroker(any(), anyString());
|
||||||
doNothing().when(mqAdminExt).deleteTopicInNameServer(any(), anyString());
|
doNothing().when(mqAdminExt).deleteTopicInNameServer(any(), anyString());
|
||||||
@@ -214,7 +226,6 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
|||||||
requestBuilder.content(JSON.toJSONString(consumerConfigInfo));
|
requestBuilder.content(JSON.toJSONString(consumerConfigInfo));
|
||||||
perform = mockMvc.perform(requestBuilder);
|
perform = mockMvc.perform(requestBuilder);
|
||||||
performErrorExpect(perform);
|
performErrorExpect(perform);
|
||||||
|
|
||||||
{
|
{
|
||||||
doNothing().when(mqAdminExt).createAndUpdateSubscriptionGroupConfig(anyString(), any());
|
doNothing().when(mqAdminExt).createAndUpdateSubscriptionGroupConfig(anyString(), any());
|
||||||
}
|
}
|
||||||
@@ -233,6 +244,7 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
|||||||
.andExpect(jsonPath("$.data").value(true));
|
.andExpect(jsonPath("$.data").value(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQueryConsumerByTopic() throws Exception {
|
public void testQueryConsumerByTopic() throws Exception {
|
||||||
// Prepare test data
|
// Prepare test data
|
||||||
@@ -313,7 +325,8 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
|||||||
.andExpect(jsonPath("$.data.jstack").value("test"));
|
.andExpect(jsonPath("$.data.jstack").value("test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return consumerController;
|
return consumerController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,14 +18,6 @@ package org.apache.rocketmq.dashboard.controller;
|
|||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import java.io.File;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.apache.rocketmq.dashboard.service.impl.DashboardCollectServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.DashboardCollectServiceImpl;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.DashboardServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.DashboardServiceImpl;
|
||||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||||
@@ -36,6 +28,15 @@ import org.mockito.InjectMocks;
|
|||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasKey;
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@@ -18,13 +18,8 @@ package org.apache.rocketmq.dashboard.controller;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import java.util.List;
|
|
||||||
import org.apache.rocketmq.client.exception.MQClientException;
|
import org.apache.rocketmq.client.exception.MQClientException;
|
||||||
import org.apache.rocketmq.common.MixAll;
|
import org.apache.rocketmq.common.MixAll;
|
||||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.CMResult;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
|
||||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||||
@@ -32,6 +27,10 @@ import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
|||||||
import org.apache.rocketmq.dashboard.service.impl.DlqMessageServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.DlqMessageServiceImpl;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.MessageServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.MessageServiceImpl;
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.CMResult;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@@ -41,6 +40,8 @@ import org.springframework.data.domain.PageRequest;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -172,7 +173,8 @@ public class DlqMessageControllerTest extends BaseControllerTest {
|
|||||||
.andExpect(content().contentType("application/vnd.ms-excel;charset=utf-8"));
|
.andExpect(content().contentType("application/vnd.ms-excel;charset=utf-8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return dlqMessageController;
|
return dlqMessageController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,20 +16,26 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.rocketmq.dashboard.controller;
|
package org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import org.apache.rocketmq.dashboard.model.User;
|
import org.apache.rocketmq.dashboard.model.User;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.UserServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.UserServiceImpl;
|
||||||
|
import org.apache.rocketmq.dashboard.service.strategy.UserContext;
|
||||||
|
import org.apache.rocketmq.dashboard.service.strategy.UserStrategy;
|
||||||
|
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
||||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
@@ -38,19 +44,27 @@ public class LoginControllerTest extends BaseControllerTest {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private LoginController loginController;
|
private LoginController loginController;
|
||||||
|
|
||||||
@Spy
|
@Mock
|
||||||
private UserServiceImpl userService;
|
private UserServiceImpl userService;
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private UserContext userContext;
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private UserStrategy userStrategy;
|
||||||
|
|
||||||
private String contextPath = "/rocketmq-console";
|
private String contextPath = "/rocketmq-console";
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() {
|
public void init() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
super.mockRmqConfigure();
|
super.mockRmqConfigure();
|
||||||
when(configure.isLoginRequired()).thenReturn(true);
|
when(configure.isLoginRequired()).thenReturn(true);
|
||||||
when(configure.getRocketMqDashboardDataPath()).thenReturn("");
|
when(configure.getRocketMqDashboardDataPath()).thenReturn("");
|
||||||
Field contextPathField = ReflectionUtils.findField(LoginController.class, "contextPath");
|
Field contextPathField = ReflectionUtils.findField(LoginController.class, "contextPath");
|
||||||
ReflectionUtils.makeAccessible(contextPathField);
|
ReflectionUtils.makeAccessible(contextPathField);
|
||||||
ReflectionUtils.setField(contextPathField, loginController, contextPath);
|
ReflectionUtils.setField(contextPathField, loginController, contextPath);
|
||||||
|
mockMvc = MockMvcBuilders.standaloneSetup(loginController).setControllerAdvice(GlobalExceptionHandler.class).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -60,57 +74,56 @@ public class LoginControllerTest extends BaseControllerTest {
|
|||||||
requestBuilder.sessionAttr(WebUtil.USER_NAME, "admin");
|
requestBuilder.sessionAttr(WebUtil.USER_NAME, "admin");
|
||||||
perform = mockMvc.perform(requestBuilder);
|
perform = mockMvc.perform(requestBuilder);
|
||||||
perform.andExpect(status().isOk())
|
perform.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.data.logined").value(true))
|
.andExpect(jsonPath("$.logined").value(true))
|
||||||
.andExpect(jsonPath("$.data.loginRequired").value(true));
|
.andExpect(jsonPath("$.loginRequired").value(true));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLogin() throws Exception {
|
public void testLogin() throws Exception {
|
||||||
final String url = "/login/login.do";
|
final String url = "/login/login.do";
|
||||||
final String username = "admin";
|
final String username = "admin";
|
||||||
final String rightPwd = "admin";
|
final String rightPwd = "admin";
|
||||||
final String wrongPwd = "rocketmq";
|
final String wrongPwd = "rocketmq";
|
||||||
{
|
|
||||||
UserServiceImpl.FileBasedUserInfoStore store
|
// 模拟 userService.queryByName 方法返回一个用户
|
||||||
= new UserServiceImpl.FileBasedUserInfoStore(configure);
|
User user = new User("admin", "admin", 1);
|
||||||
User user = store.queryByName(username);
|
user.setPassword(rightPwd);
|
||||||
Assert.assertNotNull(user);
|
|
||||||
Assert.assertEquals(user.getPassword(), rightPwd);
|
|
||||||
ReflectionTestUtils.setField(userService, "fileBasedUserInfoStore", store);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1、login fail
|
// 1、login fail
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
perform = mockMvc.perform(post(url)
|
||||||
requestBuilder.param("username", username)
|
.param("username", username)
|
||||||
.param("password", wrongPwd);
|
.param("password", wrongPwd));
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
perform.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.data").doesNotExist())
|
.andExpect(jsonPath("$.data").doesNotExist())
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
.andExpect(jsonPath("$.status").value(-1))
|
||||||
.andExpect(jsonPath("$.errMsg").value("Bad username or password!"));
|
.andExpect(jsonPath("$.errMsg").value("Bad username or password!"));
|
||||||
|
|
||||||
// 2、login success
|
when(userService.queryByUsernameAndPassword(username, rightPwd)).thenReturn(user);
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
|
||||||
requestBuilder.param("username", username)
|
|
||||||
.param("password", rightPwd);
|
|
||||||
perform = mockMvc.perform(requestBuilder);
|
|
||||||
perform.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.data.contextPath").value(contextPath));
|
|
||||||
|
|
||||||
|
// 2、login success
|
||||||
|
perform = mockMvc.perform(post(url)
|
||||||
|
.param("username", username)
|
||||||
|
.param("password", rightPwd));
|
||||||
|
perform.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.contextPath").value(contextPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLogout() throws Exception {
|
public void testLogout() throws Exception {
|
||||||
final String url = "/login/logout.do";
|
final String url = "/login/logout.do";
|
||||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
requestBuilder = post(url);
|
||||||
requestBuilder.sessionAttr(WebUtil.USER_NAME, "root");
|
requestBuilder.sessionAttr(WebUtil.USER_NAME, "root");
|
||||||
perform = mockMvc.perform(requestBuilder);
|
perform = mockMvc.perform(requestBuilder);
|
||||||
perform.andExpect(status().isOk())
|
perform.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.data").value(contextPath));
|
.andExpect(jsonPath("$.data").value(contextPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return loginController;
|
return loginController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,11 +18,6 @@ package org.apache.rocketmq.dashboard.controller;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.apache.rocketmq.client.QueryResult;
|
import org.apache.rocketmq.client.QueryResult;
|
||||||
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
||||||
import org.apache.rocketmq.client.consumer.PullResult;
|
import org.apache.rocketmq.client.consumer.PullResult;
|
||||||
@@ -32,28 +27,33 @@ import org.apache.rocketmq.client.exception.MQClientException;
|
|||||||
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
||||||
import org.apache.rocketmq.common.message.MessageExt;
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
import org.apache.rocketmq.common.message.MessageQueue;
|
import org.apache.rocketmq.common.message.MessageQueue;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.CMResult;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
|
||||||
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
|
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
|
||||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.MessageServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.MessageServiceImpl;
|
||||||
|
import org.apache.rocketmq.dashboard.support.AutoCloseConsumerWrapper;
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||||
|
import org.apache.rocketmq.remoting.RPCHook;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.CMResult;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||||
import org.apache.rocketmq.tools.admin.api.TrackType;
|
import org.apache.rocketmq.tools.admin.api.TrackType;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
@@ -71,6 +71,9 @@ public class MessageControllerTest extends BaseControllerTest {
|
|||||||
|
|
||||||
private DefaultMQPullConsumer defaultMQPullConsumer;
|
private DefaultMQPullConsumer defaultMQPullConsumer;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AutoCloseConsumerWrapper autoCloseConsumerWrapper;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
super.mockRmqConfigure();
|
super.mockRmqConfigure();
|
||||||
@@ -89,7 +92,6 @@ public class MessageControllerTest extends BaseControllerTest {
|
|||||||
when(pullResult.getNextBeginOffset()).thenReturn(Long.MAX_VALUE);
|
when(pullResult.getNextBeginOffset()).thenReturn(Long.MAX_VALUE);
|
||||||
when(pullResult.getPullStatus()).thenReturn(PullStatus.FOUND);
|
when(pullResult.getPullStatus()).thenReturn(PullStatus.FOUND);
|
||||||
when(pullResult.getMsgFoundList()).thenReturn(wrappers);
|
when(pullResult.getMsgFoundList()).thenReturn(wrappers);
|
||||||
when(messageService.buildDefaultMQPullConsumer(any(), anyBoolean())).thenReturn(defaultMQPullConsumer);
|
|
||||||
|
|
||||||
// Ensure searchOffset returns values that make sense for the test times
|
// Ensure searchOffset returns values that make sense for the test times
|
||||||
when(defaultMQPullConsumer.searchOffset(any(MessageQueue.class), anyLong())).thenAnswer(invocation -> {
|
when(defaultMQPullConsumer.searchOffset(any(MessageQueue.class), anyLong())).thenAnswer(invocation -> {
|
||||||
@@ -115,6 +117,7 @@ public class MessageControllerTest extends BaseControllerTest {
|
|||||||
// Override the previous mock to ensure the test finds messages
|
// Override the previous mock to ensure the test finds messages
|
||||||
when(defaultMQPullConsumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
when(defaultMQPullConsumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
||||||
.thenReturn(pullResultWithMessages);
|
.thenReturn(pullResultWithMessages);
|
||||||
|
when(autoCloseConsumerWrapper.getConsumer(any(RPCHook.class), anyBoolean())).thenReturn(defaultMQPullConsumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +272,8 @@ public class MessageControllerTest extends BaseControllerTest {
|
|||||||
.andExpect(jsonPath("$.data.consumeResult").value(CMResult.CR_LATER.name()));
|
.andExpect(jsonPath("$.data.consumeResult").value(CMResult.CR_LATER.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return messageController;
|
return messageController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.rocketmq.dashboard.controller;
|
package org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.apache.rocketmq.client.QueryResult;
|
import org.apache.rocketmq.client.QueryResult;
|
||||||
import org.apache.rocketmq.client.exception.MQClientException;
|
import org.apache.rocketmq.client.exception.MQClientException;
|
||||||
import org.apache.rocketmq.client.trace.TraceType;
|
import org.apache.rocketmq.client.trace.TraceType;
|
||||||
@@ -33,6 +31,9 @@ import org.mockito.InjectMocks;
|
|||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
@@ -135,7 +136,8 @@ public class MessageTraceControllerTest extends BaseControllerTest {
|
|||||||
.andExpect(jsonPath("$.data.messageTraceViews", hasSize(4)));
|
.andExpect(jsonPath("$.data.messageTraceViews", hasSize(4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return messageTraceController;
|
return messageTraceController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,9 +17,6 @@
|
|||||||
package org.apache.rocketmq.dashboard.controller;
|
package org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import java.io.File;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import org.apache.rocketmq.common.MixAll;
|
import org.apache.rocketmq.common.MixAll;
|
||||||
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
|
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.MonitorServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.MonitorServiceImpl;
|
||||||
@@ -33,6 +30,10 @@ import org.mockito.Spy;
|
|||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
@@ -135,7 +136,8 @@ public class MonitorControllerTest extends BaseControllerTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return monitorController;
|
return monitorController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,8 @@ public class NamesvrControllerTest extends BaseControllerTest {
|
|||||||
Assert.assertEquals(namesrvAddr, "127.0.0.1:9876");
|
Assert.assertEquals(namesrvAddr, "127.0.0.1:9876");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return namesvrController;
|
return namesvrController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.controller;
|
package org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||||
import org.apache.rocketmq.dashboard.service.checker.RocketMqChecker;
|
import org.apache.rocketmq.dashboard.service.checker.RocketMqChecker;
|
||||||
import org.apache.rocketmq.dashboard.service.checker.impl.ClusterHealthCheckerImpl;
|
import org.apache.rocketmq.dashboard.service.checker.impl.ClusterHealthCheckerImpl;
|
||||||
@@ -34,6 +32,9 @@ import org.mockito.Spy;
|
|||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
@@ -17,28 +17,33 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.controller;
|
package org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import org.apache.rocketmq.client.exception.MQClientException;
|
import org.apache.rocketmq.client.exception.MQClientException;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
|
||||||
import org.apache.rocketmq.dashboard.interceptor.AuthInterceptor;
|
import org.apache.rocketmq.dashboard.interceptor.AuthInterceptor;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.LoginServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.LoginServiceImpl;
|
||||||
import org.apache.rocketmq.dashboard.service.impl.ProducerServiceImpl;
|
import org.apache.rocketmq.dashboard.service.impl.ProducerServiceImpl;
|
||||||
|
import org.apache.rocketmq.dashboard.service.strategy.UserContext;
|
||||||
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
||||||
import org.apache.rocketmq.dashboard.support.GlobalRestfulResponseBodyAdvice;
|
import org.apache.rocketmq.dashboard.support.GlobalRestfulResponseBodyAdvice;
|
||||||
import org.apache.rocketmq.dashboard.util.MyPrintingResultHandler;
|
import org.apache.rocketmq.dashboard.util.MyPrintingResultHandler;
|
||||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||||
import org.apache.rocketmq.remoting.protocol.LanguageCode;
|
import org.apache.rocketmq.remoting.protocol.LanguageCode;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
@@ -52,9 +57,17 @@ public class ProducerControllerTest extends BaseControllerTest {
|
|||||||
@Spy
|
@Spy
|
||||||
private ProducerServiceImpl producerService;
|
private ProducerServiceImpl producerService;
|
||||||
|
|
||||||
@Override protected MockMvc createMockMvc() {
|
@Spy
|
||||||
|
private LoginServiceImpl loginService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private UserContext userContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MockMvc createMockMvc() {
|
||||||
AuthInterceptor authInterceptor = new AuthInterceptor();
|
AuthInterceptor authInterceptor = new AuthInterceptor();
|
||||||
ReflectionTestUtils.setField(authInterceptor, "loginService", new LoginServiceImpl());
|
ReflectionTestUtils.setField(authInterceptor, "loginService", loginService);
|
||||||
|
ReflectionTestUtils.setField(loginService, "userContext", userContext);
|
||||||
MockMvc innerMockMvc = MockMvcBuilders.standaloneSetup(getTestController())
|
MockMvc innerMockMvc = MockMvcBuilders.standaloneSetup(getTestController())
|
||||||
.addInterceptors(authInterceptor)
|
.addInterceptors(authInterceptor)
|
||||||
.alwaysDo(MyPrintingResultHandler.me())
|
.alwaysDo(MyPrintingResultHandler.me())
|
||||||
@@ -88,6 +101,7 @@ public class ProducerControllerTest extends BaseControllerTest {
|
|||||||
conn.setVersion(LanguageCode.JAVA.getCode());
|
conn.setVersion(LanguageCode.JAVA.getCode());
|
||||||
connections.add(conn);
|
connections.add(conn);
|
||||||
producerConnection.setConnectionSet(connections);
|
producerConnection.setConnectionSet(connections);
|
||||||
|
when(userContext.queryByUsername(any(String.class))).thenReturn(UserInfo.of("admin", "admin", "super"));
|
||||||
when(mqAdminExt.examineProducerConnectionInfo(anyString(), anyString()))
|
when(mqAdminExt.examineProducerConnectionInfo(anyString(), anyString()))
|
||||||
.thenThrow(new MQClientException("Not found the producer group connection", null))
|
.thenThrow(new MQClientException("Not found the producer group connection", null))
|
||||||
.thenReturn(producerConnection);
|
.thenReturn(producerConnection);
|
||||||
|
@@ -19,49 +19,52 @@ package org.apache.rocketmq.dashboard.controller;
|
|||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.apache.rocketmq.client.impl.MQClientAPIImpl;
|
import org.apache.rocketmq.client.impl.MQClientAPIImpl;
|
||||||
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
|
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
|
||||||
import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;
|
import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;
|
||||||
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
||||||
import org.apache.rocketmq.client.producer.SendResult;
|
import org.apache.rocketmq.client.producer.SendResult;
|
||||||
import org.apache.rocketmq.client.producer.SendStatus;
|
import org.apache.rocketmq.client.producer.SendStatus;
|
||||||
|
import org.apache.rocketmq.common.MixAll;
|
||||||
import org.apache.rocketmq.common.TopicConfig;
|
import org.apache.rocketmq.common.TopicConfig;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
|
||||||
import org.apache.rocketmq.common.message.Message;
|
import org.apache.rocketmq.common.message.Message;
|
||||||
import org.apache.rocketmq.common.message.MessageQueue;
|
import org.apache.rocketmq.common.message.MessageQueue;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
||||||
|
import org.apache.rocketmq.dashboard.service.ClusterInfoService;
|
||||||
|
import org.apache.rocketmq.dashboard.service.ConsumerService;
|
||||||
|
import org.apache.rocketmq.dashboard.service.impl.TopicServiceImpl;
|
||||||
|
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||||
|
import org.apache.rocketmq.remoting.RPCHook;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.route.QueueData;
|
||||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
|
||||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
|
||||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
|
||||||
import org.apache.rocketmq.dashboard.service.impl.ConsumerServiceImpl;
|
|
||||||
import org.apache.rocketmq.dashboard.service.impl.TopicServiceImpl;
|
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
|
||||||
import org.apache.rocketmq.remoting.RPCHook;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@@ -77,14 +80,23 @@ public class TopicControllerTest extends BaseControllerTest {
|
|||||||
@Spy
|
@Spy
|
||||||
private TopicServiceImpl topicService;
|
private TopicServiceImpl topicService;
|
||||||
|
|
||||||
@Spy
|
@Mock
|
||||||
private ConsumerServiceImpl consumerService;
|
private ConsumerService consumerService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DefaultMQProducer producer;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ClusterInfoService clusterInfoService;
|
||||||
|
|
||||||
private String topicName = "topic_test";
|
private String topicName = "topic_test";
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() {
|
public void init() {
|
||||||
super.mockRmqConfigure();
|
super.mockRmqConfigure();
|
||||||
|
ClusterInfo mockClusterInfo = getClusterInfo();
|
||||||
|
when(clusterInfoService.get()).thenReturn(mockClusterInfo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -258,15 +270,35 @@ public class TopicControllerTest extends BaseControllerTest {
|
|||||||
public void testSendTopicMessage() throws Exception {
|
public void testSendTopicMessage() throws Exception {
|
||||||
final String url = "/topic/sendTopicMessage.do";
|
final String url = "/topic/sendTopicMessage.do";
|
||||||
{
|
{
|
||||||
DefaultMQProducer producer = mock(DefaultMQProducer.class);
|
|
||||||
doNothing().when(producer).start();
|
doNothing().when(producer).start();
|
||||||
doNothing().when(producer).shutdown();
|
doNothing().when(producer).shutdown();
|
||||||
|
TopicConfig topicConfig = new TopicConfig(topicName);
|
||||||
|
topicConfig.setReadQueueNums(4);
|
||||||
|
topicConfig.setWriteQueueNums(4);
|
||||||
|
topicConfig.setPerm(6);
|
||||||
|
topicConfig.setOrder(false);
|
||||||
|
TopicRouteData topicRouteData = new TopicRouteData();
|
||||||
|
BrokerData brokerData = new BrokerData();
|
||||||
|
brokerData.setBrokerName("broker-a");
|
||||||
|
brokerData.setCluster("DefaultCluster");
|
||||||
|
HashMap<Long, String> brokerAddrs = new HashMap<>();
|
||||||
|
brokerAddrs.put(0L, "127.0.0.1:9876");
|
||||||
|
brokerData.setBrokerAddrs(brokerAddrs);
|
||||||
|
topicRouteData.setBrokerDatas(List.of(brokerData));
|
||||||
|
topicRouteData.setQueueDatas(List.of(new QueueData()));
|
||||||
|
topicRouteData.getQueueDatas().get(0).setReadQueueNums(4);
|
||||||
|
topicRouteData.getQueueDatas().get(0).setWriteQueueNums(4);
|
||||||
|
topicRouteData.getQueueDatas().get(0).setPerm(6);
|
||||||
|
topicRouteData.getQueueDatas().get(0).setBrokerName("broker-a");
|
||||||
|
when(mqAdminExt.examineTopicRouteInfo(topicName)).thenReturn(topicRouteData);
|
||||||
|
when(topicService.examineTopicConfig(topicName,"broker-a")).thenReturn(topicConfig);
|
||||||
|
|
||||||
SendResult result = new SendResult(SendStatus.SEND_OK, "7F000001E41A2E5D6D978B82C20F003D",
|
SendResult result = new SendResult(SendStatus.SEND_OK, "7F000001E41A2E5D6D978B82C20F003D",
|
||||||
"0A8E83C300002A9F00000000000013D3", new MessageQueue(), 1000L);
|
"0A8E83C300002A9F00000000000013D3", new MessageQueue(), 1000L);
|
||||||
when(producer.send(any(Message.class))).thenReturn(result);
|
when(producer.send((Message) argThat(msg -> msg != null))).thenReturn(result);
|
||||||
doReturn(producer).when(topicService).buildDefaultMQProducer(anyString(), any(), anyBoolean());
|
doReturn(producer).when(topicService).buildDefaultMQProducer(any(String.class), any(RPCHook.class), anyBoolean());
|
||||||
}
|
}
|
||||||
Assert.assertNotNull(topicService.buildDefaultMQProducer("group_test", mock(RPCHook.class)));
|
Assert.assertNotNull(topicService.buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, mock(RPCHook.class),false));
|
||||||
SendTopicMessageRequest request = new SendTopicMessageRequest();
|
SendTopicMessageRequest request = new SendTopicMessageRequest();
|
||||||
request.setTopic(topicName);
|
request.setTopic(topicName);
|
||||||
request.setMessageBody("hello world");
|
request.setMessageBody("hello world");
|
||||||
@@ -275,8 +307,8 @@ public class TopicControllerTest extends BaseControllerTest {
|
|||||||
requestBuilder.content(JSON.toJSONString(request));
|
requestBuilder.content(JSON.toJSONString(request));
|
||||||
perform = mockMvc.perform(requestBuilder);
|
perform = mockMvc.perform(requestBuilder);
|
||||||
perform.andExpect(status().isOk())
|
perform.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.status").value(-1))
|
.andExpect(jsonPath("$.data.sendStatus").value(SendStatus.SEND_OK.name()))
|
||||||
.andExpect(jsonPath("$.errMsg").value(containsString("NullPointerException")));
|
.andExpect(jsonPath("$.data.msgId").value("7F000001E41A2E5D6D978B82C20F003D"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -358,7 +390,8 @@ public class TopicControllerTest extends BaseControllerTest {
|
|||||||
.andExpect(jsonPath("$.data.messageTypeList[2]").value("SYSTEM"));
|
.andExpect(jsonPath("$.data.messageTypeList[2]").value("SYSTEM"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected Object getTestController() {
|
@Override
|
||||||
|
protected Object getTestController() {
|
||||||
return topicController;
|
return topicController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,10 +18,6 @@ package org.apache.rocketmq.dashboard.permission;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.apache.rocketmq.dashboard.BaseTest;
|
import org.apache.rocketmq.dashboard.BaseTest;
|
||||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||||
import org.apache.rocketmq.dashboard.model.User;
|
import org.apache.rocketmq.dashboard.model.User;
|
||||||
@@ -43,6 +39,11 @@ import org.springframework.test.util.ReflectionTestUtils;
|
|||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@@ -19,21 +19,21 @@ package org.apache.rocketmq.dashboard.service.impl;
|
|||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
||||||
|
import org.apache.rocketmq.acl.common.SessionCredentials;
|
||||||
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
||||||
import org.apache.rocketmq.client.consumer.PullResult;
|
import org.apache.rocketmq.client.consumer.PullResult;
|
||||||
import org.apache.rocketmq.client.consumer.PullStatus;
|
import org.apache.rocketmq.client.consumer.PullStatus;
|
||||||
import org.apache.rocketmq.client.exception.MQClientException;
|
|
||||||
import org.apache.rocketmq.common.Pair;
|
import org.apache.rocketmq.common.Pair;
|
||||||
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
|
||||||
import org.apache.rocketmq.common.message.MessageExt;
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
import org.apache.rocketmq.common.message.MessageQueue;
|
import org.apache.rocketmq.common.message.MessageQueue;
|
||||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||||
|
import org.apache.rocketmq.dashboard.model.MessageQueryByPage;
|
||||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||||
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
|
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
|
||||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
import org.apache.rocketmq.dashboard.support.AutoCloseConsumerWrapper;
|
||||||
import org.apache.rocketmq.dashboard.model.MessageQueryByPage;
|
import org.apache.rocketmq.remoting.RPCHook;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||||
@@ -42,42 +42,24 @@ import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.PageImpl;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
|
||||||
import static org.mockito.Mockito.doThrow;
|
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||||
public class MessageServiceImplTest {
|
public class MessageServiceImplTest {
|
||||||
@@ -93,11 +75,15 @@ public class MessageServiceImplTest {
|
|||||||
private RMQConfigure configure;
|
private RMQConfigure configure;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private DefaultMQPullConsumer consumer;
|
private DefaultMQPullConsumer defaultMQPullConsumer;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AutoCloseConsumerWrapper autoCloseConsumerWrapper;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private Cache<String, MessagePage> messagePageCache;
|
private Cache<String, MessagePage> messagePageCache;
|
||||||
|
|
||||||
|
|
||||||
private static final String TOPIC = "testTopic";
|
private static final String TOPIC = "testTopic";
|
||||||
private static final String MSG_ID = "testMsgId";
|
private static final String MSG_ID = "testMsgId";
|
||||||
private static final String CONSUMER_GROUP = "testConsumerGroup";
|
private static final String CONSUMER_GROUP = "testConsumerGroup";
|
||||||
@@ -109,10 +95,10 @@ public class MessageServiceImplTest {
|
|||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
// Set up default mock responses
|
// Set up default mock responses
|
||||||
when(configure.getNamesrvAddr()).thenReturn("localhost:9876");
|
when(configure.getNamesrvAddr()).thenReturn("localhost:9876");
|
||||||
|
when(configure.getAccessKey()).thenReturn("12345678");
|
||||||
|
when(configure.getSecretKey()).thenReturn("rocketmq");
|
||||||
when(configure.isUseTLS()).thenReturn(false);
|
when(configure.isUseTLS()).thenReturn(false);
|
||||||
|
when(autoCloseConsumerWrapper.getConsumer(any(RPCHook.class), anyBoolean())).thenReturn(defaultMQPullConsumer);
|
||||||
// Mock the consumer creation to avoid actual RocketMQ calls
|
|
||||||
lenient().doReturn(consumer).when(messageService).buildDefaultMQPullConsumer(any(), anyBoolean());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -194,8 +180,9 @@ public class MessageServiceImplTest {
|
|||||||
Set<MessageQueue> messageQueues = new HashSet<>();
|
Set<MessageQueue> messageQueues = new HashSet<>();
|
||||||
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
|
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
|
||||||
messageQueues.add(new MessageQueue(TOPIC, "broker-2", 1));
|
messageQueues.add(new MessageQueue(TOPIC, "broker-2", 1));
|
||||||
when(consumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
|
System.out.println("Consumer from wrapper: " + autoCloseConsumerWrapper.getConsumer(new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey())), false));
|
||||||
|
when(defaultMQPullConsumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
|
||||||
|
System.out.println(defaultMQPullConsumer.fetchSubscribeMessageQueues(TOPIC));
|
||||||
// Setup pull results for both queues
|
// Setup pull results for both queues
|
||||||
PullResult pullResult1 = createPullResult(PullStatus.FOUND, Arrays.asList(
|
PullResult pullResult1 = createPullResult(PullStatus.FOUND, Arrays.asList(
|
||||||
createMessageExt("id1", TOPIC, "body1", 1500),
|
createMessageExt("id1", TOPIC, "body1", 1500),
|
||||||
@@ -210,7 +197,7 @@ public class MessageServiceImplTest {
|
|||||||
PullResult emptyResult = createPullResult(PullStatus.NO_NEW_MSG, Collections.emptyList(), 10, 10);
|
PullResult emptyResult = createPullResult(PullStatus.NO_NEW_MSG, Collections.emptyList(), 10, 10);
|
||||||
|
|
||||||
// First pull gets messages, second pull gets empty to terminate loop
|
// First pull gets messages, second pull gets empty to terminate loop
|
||||||
when(consumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
when(defaultMQPullConsumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
||||||
.thenReturn(pullResult1)
|
.thenReturn(pullResult1)
|
||||||
.thenReturn(emptyResult)
|
.thenReturn(emptyResult)
|
||||||
.thenReturn(pullResult2)
|
.thenReturn(pullResult2)
|
||||||
@@ -230,9 +217,8 @@ public class MessageServiceImplTest {
|
|||||||
assertEquals("id3", result.get(2).getMsgId()); // 1800
|
assertEquals("id3", result.get(2).getMsgId()); // 1800
|
||||||
assertEquals("id1", result.get(3).getMsgId()); // 1500
|
assertEquals("id1", result.get(3).getMsgId()); // 1500
|
||||||
|
|
||||||
verify(consumer, times(4)).pull(any(MessageQueue.class), eq("*"), anyLong(), anyInt());
|
verify(defaultMQPullConsumer, times(4)).pull(any(MessageQueue.class), eq("*"), anyLong(), anyInt());
|
||||||
verify(consumer).start();
|
|
||||||
verify(consumer).shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -240,7 +226,7 @@ public class MessageServiceImplTest {
|
|||||||
// Setup message queues
|
// Setup message queues
|
||||||
Set<MessageQueue> messageQueues = new HashSet<>();
|
Set<MessageQueue> messageQueues = new HashSet<>();
|
||||||
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
|
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
|
||||||
when(consumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
|
when(defaultMQPullConsumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
|
||||||
|
|
||||||
// Setup pull results - some messages are outside time range
|
// Setup pull results - some messages are outside time range
|
||||||
PullResult pullResult = createPullResult(PullStatus.FOUND, Arrays.asList(
|
PullResult pullResult = createPullResult(PullStatus.FOUND, Arrays.asList(
|
||||||
@@ -251,7 +237,7 @@ public class MessageServiceImplTest {
|
|||||||
|
|
||||||
PullResult emptyResult = createPullResult(PullStatus.NO_NEW_MSG, Collections.emptyList(), 10, 10);
|
PullResult emptyResult = createPullResult(PullStatus.NO_NEW_MSG, Collections.emptyList(), 10, 10);
|
||||||
|
|
||||||
when(consumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
when(defaultMQPullConsumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
||||||
.thenReturn(pullResult)
|
.thenReturn(pullResult)
|
||||||
.thenReturn(emptyResult);
|
.thenReturn(emptyResult);
|
||||||
|
|
||||||
@@ -270,7 +256,7 @@ public class MessageServiceImplTest {
|
|||||||
// Setup message queues
|
// Setup message queues
|
||||||
Set<MessageQueue> messageQueues = new HashSet<>();
|
Set<MessageQueue> messageQueues = new HashSet<>();
|
||||||
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
|
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
|
||||||
when(consumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
|
when(defaultMQPullConsumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
|
||||||
|
|
||||||
// Test all different pull statuses
|
// Test all different pull statuses
|
||||||
PullResult pullResult1 = createPullResult(PullStatus.FOUND,
|
PullResult pullResult1 = createPullResult(PullStatus.FOUND,
|
||||||
@@ -285,7 +271,7 @@ public class MessageServiceImplTest {
|
|||||||
PullResult pullResult4 = createPullResult(PullStatus.OFFSET_ILLEGAL,
|
PullResult pullResult4 = createPullResult(PullStatus.OFFSET_ILLEGAL,
|
||||||
Collections.emptyList(), 7, 8);
|
Collections.emptyList(), 7, 8);
|
||||||
|
|
||||||
when(consumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
when(defaultMQPullConsumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
|
||||||
.thenReturn(pullResult1)
|
.thenReturn(pullResult1)
|
||||||
.thenReturn(pullResult2)
|
.thenReturn(pullResult2)
|
||||||
.thenReturn(pullResult3)
|
.thenReturn(pullResult3)
|
||||||
@@ -447,22 +433,6 @@ public class MessageServiceImplTest {
|
|||||||
assertEquals(10, (qo1.getEndOffset() - 5L) + (qo2.getEndOffset() - 10L));
|
assertEquals(10, (qo1.getEndOffset() - 5L) + (qo2.getEndOffset() - 10L));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBuildDefaultMQPullConsumer() {
|
|
||||||
// Test with TLS enabled
|
|
||||||
DefaultMQPullConsumer tlsConsumer = messageService.buildDefaultMQPullConsumer(null, true);
|
|
||||||
assertNotNull(tlsConsumer);
|
|
||||||
|
|
||||||
// Test with TLS disabled
|
|
||||||
DefaultMQPullConsumer nonTlsConsumer = messageService.buildDefaultMQPullConsumer(null, false);
|
|
||||||
assertNotNull(nonTlsConsumer);
|
|
||||||
|
|
||||||
// Test with RPC hook
|
|
||||||
AclClientRPCHook rpcHook = mock(AclClientRPCHook.class);
|
|
||||||
DefaultMQPullConsumer hookConsumer = messageService.buildDefaultMQPullConsumer(rpcHook, false);
|
|
||||||
assertNotNull(hookConsumer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
|
|
||||||
private MessageExt createMessageExt(String msgId, String topic, String body, long storeTimestamp) {
|
private MessageExt createMessageExt(String msgId, String topic, String body, long storeTimestamp) {
|
||||||
|
@@ -17,15 +17,27 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.service.impl;
|
package org.apache.rocketmq.dashboard.service.impl;
|
||||||
|
|
||||||
|
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
||||||
|
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
||||||
|
import org.apache.rocketmq.client.producer.SendResult;
|
||||||
|
import org.apache.rocketmq.client.producer.SendStatus;
|
||||||
|
import org.apache.rocketmq.client.producer.TransactionMQProducer;
|
||||||
|
import org.apache.rocketmq.common.attribute.TopicMessageType;
|
||||||
|
import org.apache.rocketmq.common.message.Message;
|
||||||
|
import org.apache.rocketmq.dashboard.BaseTest;
|
||||||
|
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||||
|
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
import org.apache.rocketmq.dashboard.service.ClusterInfoService;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
@@ -36,38 +48,11 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.doReturn;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
|
||||||
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
|
||||||
import org.apache.rocketmq.client.producer.SendResult;
|
|
||||||
import org.apache.rocketmq.client.producer.SendStatus;
|
|
||||||
import org.apache.rocketmq.client.producer.TransactionMQProducer;
|
|
||||||
import org.apache.rocketmq.common.attribute.TopicMessageType;
|
|
||||||
import org.apache.rocketmq.common.message.Message;
|
|
||||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
|
||||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.ArgumentMatchers;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.ArgumentMatchers.isNull;
|
|
||||||
import static org.mockito.Mockito.doNothing;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class TopicServiceImplTest {
|
public class TopicServiceImplTest extends BaseTest {
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
@Spy
|
@Spy
|
||||||
@@ -79,59 +64,16 @@ public class TopicServiceImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private RMQConfigure configure;
|
private RMQConfigure configure;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ClusterInfoService clusterInfoService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
// Setup common mocks
|
|
||||||
when(configure.getNamesrvAddr()).thenReturn("localhost:9876");
|
when(configure.getNamesrvAddr()).thenReturn("localhost:9876");
|
||||||
|
|
||||||
// Use lenient() to prevent the unnecessary stubbing error
|
// Use lenient() to prevent the unnecessary stubbing error
|
||||||
lenient().when(configure.isUseTLS()).thenReturn(false);
|
lenient().when(configure.isUseTLS()).thenReturn(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExamineAllTopicType() throws Exception {
|
|
||||||
// Create mock TopicList with different types of topics
|
|
||||||
TopicList topicList = new TopicList();
|
|
||||||
Set<String> topicSet = new HashSet<>();
|
|
||||||
topicSet.add("normalTopic");
|
|
||||||
topicSet.add("%RETRY%someGroup");
|
|
||||||
topicSet.add("%DLQ%someGroup");
|
|
||||||
topicSet.add("%SYS%sysTopic");
|
|
||||||
topicList.setTopicList(topicSet);
|
|
||||||
|
|
||||||
// Mock fetchAllTopicList to return our test topics
|
|
||||||
doReturn(topicList).when(topicService).fetchAllTopicList(anyBoolean(), anyBoolean());
|
|
||||||
|
|
||||||
// Mock examineTopicConfig for the normal topic
|
|
||||||
TopicConfigInfo configInfo = new TopicConfigInfo();
|
|
||||||
configInfo.setMessageType("NORMAL");
|
|
||||||
List<TopicConfigInfo> topicConfigInfos = new ArrayList<>();
|
|
||||||
topicConfigInfos.add(configInfo);
|
|
||||||
doReturn(topicConfigInfos).when(topicService).examineTopicConfig(anyString());
|
|
||||||
|
|
||||||
// Call the method being tested
|
|
||||||
TopicTypeList result = topicService.examineAllTopicType();
|
|
||||||
|
|
||||||
// Verify the results
|
|
||||||
Assert.assertNotNull(result);
|
|
||||||
Assert.assertEquals(4, result.getTopicNameList().size());
|
|
||||||
Assert.assertEquals(4, result.getMessageTypeList().size());
|
|
||||||
|
|
||||||
// Verify that the topics contain the expected names and types
|
|
||||||
// Note: the actual order might be different due to sorting in the method
|
|
||||||
// So we're checking that all expected items are included
|
|
||||||
Assert.assertTrue(result.getTopicNameList().contains("normalTopic"));
|
|
||||||
Assert.assertTrue(result.getTopicNameList().contains("%RETRY%someGroup"));
|
|
||||||
Assert.assertTrue(result.getTopicNameList().contains("%DLQ%someGroup"));
|
|
||||||
Assert.assertTrue(result.getTopicNameList().contains("%SYS%sysTopic"));
|
|
||||||
|
|
||||||
// Verify message types
|
|
||||||
Assert.assertTrue(result.getMessageTypeList().contains("NORMAL"));
|
|
||||||
Assert.assertTrue(result.getMessageTypeList().contains("RETRY"));
|
|
||||||
Assert.assertTrue(result.getMessageTypeList().contains("DELAY"));
|
|
||||||
Assert.assertTrue(result.getMessageTypeList().contains("SYSTEM"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSendTopicMessageRequestNormal() throws Exception {
|
public void testSendTopicMessageRequestNormal() throws Exception {
|
||||||
// Prepare test data
|
// Prepare test data
|
||||||
|
@@ -21,6 +21,28 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
|||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import org.apache.rocketmq.common.MixAll;
|
||||||
|
import org.apache.rocketmq.dashboard.BaseTest;
|
||||||
|
import org.apache.rocketmq.dashboard.config.CollectExecutorConfig;
|
||||||
|
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||||
|
import org.apache.rocketmq.dashboard.service.impl.DashboardCollectServiceImpl;
|
||||||
|
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||||
|
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||||
|
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -32,27 +54,6 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.apache.rocketmq.common.MixAll;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
|
||||||
import org.apache.rocketmq.dashboard.BaseTest;
|
|
||||||
import org.apache.rocketmq.dashboard.config.CollectExecutorConfig;
|
|
||||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
|
||||||
import org.apache.rocketmq.dashboard.service.impl.DashboardCollectServiceImpl;
|
|
||||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
|
||||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
|
||||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.mockito.Spy;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@@ -18,8 +18,7 @@ package org.apache.rocketmq.dashboard.testbase;
|
|||||||
|
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import java.util.List;
|
import jakarta.annotation.Resource;
|
||||||
import javax.annotation.Resource;
|
|
||||||
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
|
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
|
||||||
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
|
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
|
||||||
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
|
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
|
||||||
@@ -29,16 +28,18 @@ import org.apache.rocketmq.client.producer.SendResult;
|
|||||||
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
|
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
|
||||||
import org.apache.rocketmq.common.message.Message;
|
import org.apache.rocketmq.common.message.Message;
|
||||||
import org.apache.rocketmq.common.message.MessageExt;
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
|
||||||
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
||||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||||
import org.apache.rocketmq.dashboard.service.ConsumerService;
|
import org.apache.rocketmq.dashboard.service.ConsumerService;
|
||||||
import org.apache.rocketmq.dashboard.service.TopicService;
|
import org.apache.rocketmq.dashboard.service.TopicService;
|
||||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@ComponentScan(basePackageClasses = {TestRocketMQServer.class})
|
@ComponentScan(basePackageClasses = {TestRocketMQServer.class})
|
||||||
public abstract class RocketMQConsoleTestBase {
|
public abstract class RocketMQConsoleTestBase {
|
||||||
private Logger consoleTestBaseLog = LoggerFactory.getLogger(RocketMQConsoleTestBase.class);
|
private Logger consoleTestBaseLog = LoggerFactory.getLogger(RocketMQConsoleTestBase.class);
|
||||||
@@ -65,13 +66,13 @@ public abstract class RocketMQConsoleTestBase {
|
|||||||
|
|
||||||
public static abstract class RetryTempLate<T> {
|
public static abstract class RetryTempLate<T> {
|
||||||
protected abstract T process() throws Exception;
|
protected abstract T process() throws Exception;
|
||||||
|
|
||||||
public T execute(int times, long waitTime) throws Exception {
|
public T execute(int times, long waitTime) throws Exception {
|
||||||
Exception exception = null;
|
Exception exception = null;
|
||||||
for (int i = 0; i < times; i++) {
|
for (int i = 0; i < times; i++) {
|
||||||
try {
|
try {
|
||||||
return process();
|
return process();
|
||||||
}
|
} catch (Exception ignore) {
|
||||||
catch (Exception ignore) {
|
|
||||||
exception = ignore;
|
exception = ignore;
|
||||||
if (waitTime > 0) {
|
if (waitTime > 0) {
|
||||||
Thread.sleep(waitTime);
|
Thread.sleep(waitTime);
|
||||||
@@ -84,14 +85,12 @@ public abstract class RocketMQConsoleTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected void startTestMQProducer() {
|
protected void startTestMQProducer() {
|
||||||
producer = new DefaultMQProducer(TEST_PRODUCER_GROUP);
|
producer = new DefaultMQProducer(TEST_PRODUCER_GROUP);
|
||||||
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
|
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
|
||||||
try {
|
try {
|
||||||
producer.start();
|
producer.start();
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -107,8 +106,7 @@ public abstract class RocketMQConsoleTestBase {
|
|||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
try {
|
try {
|
||||||
return producer.send(message);
|
return producer.send(message);
|
||||||
}
|
} catch (Exception ignore) {
|
||||||
catch (Exception ignore) {
|
|
||||||
Thread.sleep(500);
|
Thread.sleep(500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,8 +135,7 @@ public abstract class RocketMQConsoleTestBase {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
consumer.start();
|
consumer.start();
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
Throwables.throwIfUnchecked(e);
|
Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@@ -17,11 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.testbase;
|
package org.apache.rocketmq.dashboard.testbase;
|
||||||
|
|
||||||
import java.io.File;
|
import jakarta.annotation.PostConstruct;
|
||||||
import java.text.SimpleDateFormat;
|
import jakarta.annotation.PreDestroy;
|
||||||
import java.util.Date;
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
import org.apache.rocketmq.broker.BrokerController;
|
import org.apache.rocketmq.broker.BrokerController;
|
||||||
import org.apache.rocketmq.common.BrokerConfig;
|
import org.apache.rocketmq.common.BrokerConfig;
|
||||||
import org.apache.rocketmq.common.MixAll;
|
import org.apache.rocketmq.common.MixAll;
|
||||||
@@ -34,6 +31,10 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import static java.io.File.separator;
|
import static java.io.File.separator;
|
||||||
import static org.apache.rocketmq.dashboard.testbase.TestConstant.TEST_BROKER_NAME;
|
import static org.apache.rocketmq.dashboard.testbase.TestConstant.TEST_BROKER_NAME;
|
||||||
import static org.apache.rocketmq.dashboard.testbase.TestConstant.TEST_CLUSTER_NAME;
|
import static org.apache.rocketmq.dashboard.testbase.TestConstant.TEST_CLUSTER_NAME;
|
||||||
@@ -100,8 +101,7 @@ public class TestRocketMQServer {
|
|||||||
namesrvController.initialize();
|
namesrvController.initialize();
|
||||||
log.info("Success to start Name Server:{}", TestConstant.NAME_SERVER_ADDRESS);
|
log.info("Success to start Name Server:{}", TestConstant.NAME_SERVER_ADDRESS);
|
||||||
namesrvController.start();
|
namesrvController.start();
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
log.error("Failed to start Name Server", e);
|
log.error("Failed to start Name Server", e);
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
@@ -124,8 +124,7 @@ public class TestRocketMQServer {
|
|||||||
log.info("Broker Start name:{} address:{}", brokerConfig.getBrokerName(), brokerController.getBrokerAddr());
|
log.info("Broker Start name:{} address:{}", brokerConfig.getBrokerName(), brokerController.getBrokerAddr());
|
||||||
brokerController.start();
|
brokerController.start();
|
||||||
|
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
log.error("Failed to start Broker", e);
|
log.error("Failed to start Broker", e);
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
@@ -144,8 +143,7 @@ public class TestRocketMQServer {
|
|||||||
}
|
}
|
||||||
if (file.isFile()) {
|
if (file.isFile()) {
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
} else if (file.isDirectory()) {
|
||||||
else if (file.isDirectory()) {
|
|
||||||
File[] files = file.listFiles();
|
File[] files = file.listFiles();
|
||||||
for (File file1 : files) {
|
for (File file1 : files) {
|
||||||
deleteFile(file1);
|
deleteFile(file1);
|
||||||
|
@@ -18,17 +18,22 @@
|
|||||||
package org.apache.rocketmq.dashboard.util;
|
package org.apache.rocketmq.dashboard.util;
|
||||||
|
|
||||||
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
||||||
|
import org.apache.rocketmq.client.exception.MQClientException;
|
||||||
import org.apache.rocketmq.dashboard.support.AutoCloseConsumerWrapper;
|
import org.apache.rocketmq.dashboard.support.AutoCloseConsumerWrapper;
|
||||||
import org.apache.rocketmq.remoting.RPCHook;
|
import org.apache.rocketmq.remoting.RPCHook;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import org.apache.rocketmq.client.exception.MQClientException;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
import static org.mockito.Mockito.*;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class AutoCloseConsumerWrapperTests {
|
class AutoCloseConsumerWrapperTests {
|
||||||
@@ -66,7 +71,6 @@ class AutoCloseConsumerWrapperTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldCloseIdleConsumer() throws Exception {
|
void shouldCloseIdleConsumer() throws Exception {
|
||||||
TestableWrapper wrapper = new TestableWrapper();
|
TestableWrapper wrapper = new TestableWrapper();
|
||||||
|
@@ -16,34 +16,21 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.rocketmq.dashboard.util;
|
package org.apache.rocketmq.dashboard.util;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import org.apache.rocketmq.client.producer.LocalTransactionState;
|
import org.apache.rocketmq.client.producer.LocalTransactionState;
|
||||||
import org.apache.rocketmq.client.trace.TraceConstants;
|
import org.apache.rocketmq.client.trace.TraceConstants;
|
||||||
import org.apache.rocketmq.client.trace.TraceType;
|
import org.apache.rocketmq.client.trace.TraceType;
|
||||||
import org.apache.rocketmq.common.AclConfig;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.DataVersion;
|
|
||||||
import org.apache.rocketmq.common.MixAll;
|
import org.apache.rocketmq.common.MixAll;
|
||||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
|
||||||
import org.apache.rocketmq.common.TopicConfig;
|
import org.apache.rocketmq.common.TopicConfig;
|
||||||
|
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
|
||||||
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
|
import org.apache.rocketmq.common.message.MessageQueue;
|
||||||
|
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.DataVersion;
|
||||||
|
import org.apache.rocketmq.remoting.protocol.LanguageCode;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
|
import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.TopicOffset;
|
import org.apache.rocketmq.remoting.protocol.admin.TopicOffset;
|
||||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||||
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
|
|
||||||
import org.apache.rocketmq.common.message.MessageExt;
|
|
||||||
import org.apache.rocketmq.common.message.MessageQueue;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsItem;
|
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsItem;
|
||||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||||
@@ -61,9 +48,18 @@ import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
|||||||
import org.apache.rocketmq.remoting.protocol.route.QueueData;
|
import org.apache.rocketmq.remoting.protocol.route.QueueData;
|
||||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
|
||||||
import org.apache.rocketmq.remoting.protocol.LanguageCode;
|
import java.net.InetSocketAddress;
|
||||||
import org.checkerframework.checker.units.qual.A;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import static org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType.CONSUME_ACTIVELY;
|
import static org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType.CONSUME_ACTIVELY;
|
||||||
|
|
||||||
@@ -317,25 +313,5 @@ public class MockObjectUtil {
|
|||||||
return dlqMessages;
|
return dlqMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AclConfig createAclConfig() {
|
|
||||||
PlainAccessConfig adminConfig = new PlainAccessConfig();
|
|
||||||
adminConfig.setAdmin(true);
|
|
||||||
adminConfig.setAccessKey("rocketmq2");
|
|
||||||
adminConfig.setSecretKey("12345678");
|
|
||||||
|
|
||||||
PlainAccessConfig normalConfig = new PlainAccessConfig();
|
|
||||||
normalConfig.setAdmin(false);
|
|
||||||
normalConfig.setAccessKey("rocketmq");
|
|
||||||
normalConfig.setSecretKey("123456789");
|
|
||||||
normalConfig.setDefaultGroupPerm("SUB");
|
|
||||||
normalConfig.setDefaultTopicPerm("DENY");
|
|
||||||
normalConfig.setTopicPerms(Lists.newArrayList("topicA=DENY", "topicB=PUB|SUB"));
|
|
||||||
normalConfig.setGroupPerms(Lists.newArrayList("groupA=DENY", "groupB=PUB|SUB"));
|
|
||||||
|
|
||||||
|
|
||||||
AclConfig aclConfig = new AclConfig();
|
|
||||||
aclConfig.setPlainAccessConfigs(Lists.newArrayList(adminConfig, normalConfig));
|
|
||||||
aclConfig.setGlobalWhiteAddrs(Lists.newArrayList("localhost"));
|
|
||||||
return aclConfig;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.util;
|
package org.apache.rocketmq.dashboard.util;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import org.apache.rocketmq.client.trace.TraceConstants;
|
import org.apache.rocketmq.client.trace.TraceConstants;
|
||||||
import org.apache.rocketmq.client.trace.TraceContext;
|
import org.apache.rocketmq.client.trace.TraceContext;
|
||||||
import org.apache.rocketmq.common.UtilAll;
|
import org.apache.rocketmq.common.UtilAll;
|
||||||
@@ -25,6 +24,8 @@ import org.junit.Assert;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class MsgTraceDecodeUtilTest {
|
public class MsgTraceDecodeUtilTest {
|
||||||
private StringBuilder pubTraceDataBase;
|
private StringBuilder pubTraceDataBase;
|
||||||
private StringBuilder subTraceDataBase;
|
private StringBuilder subTraceDataBase;
|
||||||
|
@@ -17,13 +17,14 @@
|
|||||||
|
|
||||||
package org.apache.rocketmq.dashboard.util;
|
package org.apache.rocketmq.dashboard.util;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.test.web.servlet.result.PrintingResultHandler;
|
import org.springframework.test.web.servlet.result.PrintingResultHandler;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class MyPrintingResultHandler extends PrintingResultHandler {
|
public class MyPrintingResultHandler extends PrintingResultHandler {
|
||||||
public static MyPrintingResultHandler me() {
|
public static MyPrintingResultHandler me() {
|
||||||
return new MyPrintingResultHandler();
|
return new MyPrintingResultHandler();
|
||||||
|
@@ -18,10 +18,8 @@
|
|||||||
package org.apache.rocketmq.dashboard.web;
|
package org.apache.rocketmq.dashboard.web;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import java.util.Map;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||||
@@ -32,6 +30,8 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
|
Reference in New Issue
Block a user