Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions packages/base/src/locale/zh-CN/dmsDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export default {
name: '数据源名称',
describe: '数据源描述',
type: '数据源类型',
connectionMode: '连接模式',
connectionModeStandalone: '单实例',
connectionModeCluster: 'Cluster',
ip: '数据源地址',
ipTips: '数据源IP或域名',
port: '数据源端口',
Expand Down Expand Up @@ -104,6 +107,28 @@ export default {
lineNumberLimit: '回滚行数限制',
lineNumberLimitTips: '当预计影响行数超过指定值则不回滚',
dataSourceConnectError: '数据源连通性测试失败',
mongoTopology: 'MongoDB 形态',
mongoTopologyTips:
'按 MongoDB 部署拓扑选择(Standalone / Replica set / Sharded cluster);选错会导致测连失败。',
mongoTopologySingle: '单机',
mongoTopologyReplicaSet: '副本集',
mongoTopologyShard: '分片集群',
mongoSingleTips:
'填写单个 standalone 实例地址与端口;无需副本集名称与成员地址',
mongoReplicaSetTips:
'在「副本集成员地址」填写多个 host:port;基础地址取首个成员;需填副本集名称',
mongoShardTips:
'只填单个 mongos 地址与端口;勿填 configsvr、shard 数据节点或副本集多成员',
mongoAuthSource: '认证数据库',
mongoAuthSourceTips: 'MongoDB 认证库名,通常为 admin',
mongoReplicaSet: '副本集名称',
mongoReplicaSetNameTips: '仅副本集形态需要填写',
mongoSeedHosts: '副本集成员地址',
mongoSeedHostsTips: '多个成员使用英文逗号或换行分隔',
mongoSeedHostsPlaceholder:
'例如:192.0.2.10:27017,192.0.2.11:27017,192.0.2.12:27017',
mongoSeedHostsRule:
'请填写 host:port 格式的成员地址,多个成员用英文逗号或换行分隔',
returnModify: '返回修改',
continueSubmit: '继续提交'
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -803,26 +803,30 @@ exports[`page/DataSource/AddDataSource render add database snap 1`] = `
<div
class="ant-form-item-control-input-content"
>
<button
aria-checked="true"
class="ant-switch basic-switch-wrapper audit-confirm-switch css-g6dhbn ant-switch-checked"
role="switch"
type="button"
<span
class="audit-confirm-switch-trigger"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
<button
aria-checked="true"
class="ant-switch basic-switch-wrapper audit-confirm-switch css-g6dhbn ant-switch-checked"
role="switch"
type="button"
>
<span
class="ant-switch-inner-checked"
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner-unchecked"
/>
</span>
</button>
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
/>
<span
class="ant-switch-inner-unchecked"
/>
</span>
</button>
</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -1170,6 +1174,22 @@ exports[`page/DataSource/AddDataSource render add database snap 1`] = `

exports[`page/DataSource/AddDataSource render conenctable modal when current service can not connect 1`] = `
<body>
<textarea
aria-hidden="true"
style="letter-spacing:normal;line-height:1.5714285714285714;padding-top:4px;padding-bottom:4px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';font-weight:;font-size:14px;font-variant:;text-rendering:auto;text-transform:none;width:100%;text-indent:0;padding-left:11px;padding-right:11px;border-width:1px;box-sizing:border-box;word-break:;white-space:pre-wrap;
min-height:0 !important;
max-height:none !important;
height:0 !important;
visibility:hidden !important;
overflow:hidden !important;
position:absolute !important;
z-index:-1000 !important;
top:0 !important;
right:0 !important;
pointer-events: none !important;
"
tab-index="-1"
/>
<div>
<section
class="css-doq0dk"
Expand Down Expand Up @@ -2054,26 +2074,30 @@ exports[`page/DataSource/AddDataSource render conenctable modal when current ser
<div
class="ant-form-item-control-input-content"
>
<button
aria-checked="false"
class="ant-switch basic-switch-wrapper audit-confirm-switch css-g6dhbn"
role="switch"
type="button"
<span
class="audit-confirm-switch-trigger"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
<button
aria-checked="false"
class="ant-switch basic-switch-wrapper audit-confirm-switch css-g6dhbn"
role="switch"
type="button"
>
<span
class="ant-switch-inner-checked"
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner-unchecked"
/>
</span>
</button>
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
/>
<span
class="ant-switch-inner-unchecked"
/>
</span>
</button>
</span>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,39 @@ describe('page/DataSource/AddDataSource', () => {
return baseSuperRender(<AddDataSource />);
};

const mockMongoDriverOption = () => {
baseMockApi.global.getListDBServiceDriverOption().mockImplementation(() =>
createSpySuccessResponse({
data: [
{
db_type: 'MongoDB',
logo_path: 'logo_path_mock',
params: [
{
description: 'MongoDB authentication database',
name: 'auth_source',
type: 'string',
value: 'admin'
},
{
description: 'Replica set name',
name: 'replica_set',
type: 'string',
value: ''
},
{
description: 'MongoDB seed hosts',
name: 'seed_hosts',
type: 'string',
value: ''
}
]
}
]
})
);
};

beforeEach(() => {
jest.useFakeTimers();
(useNavigate as jest.Mock).mockImplementation(() => navigateSpy);
Expand Down Expand Up @@ -237,6 +270,157 @@ describe('page/DataSource/AddDataSource', () => {
expect(screen.getByText('添加数据源')).toBeInTheDocument();
});

it.each([
{
topology: '单机',
name: 'mongo-single-source',
host: '192.0.2.10',
port: '27017',
expectedParams: [
{ name: 'auth_source', value: 'admin' },
{ name: 'replica_set', value: '' },
{ name: 'topology', value: 'single' }
]
},
{
topology: '副本集',
name: 'mongo-replica-source',
host: '192.0.2.10',
port: '27017',
replicaSet: 'rs0',
seedHosts: '192.0.2.10:27017,27018,27019',
expectedParams: [
{ name: 'auth_source', value: 'admin' },
{ name: 'replica_set', value: 'rs0' },
{
name: 'seed_hosts',
value: '192.0.2.10:27017,192.0.2.10:27018,192.0.2.10:27019'
},
{ name: 'topology', value: 'replicaSet' }
]
},
{
topology: '分片集群',
name: 'mongo-shard-source',
host: '192.0.2.20',
port: '27017',
expectedParams: [
{ name: 'auth_source', value: 'admin' },
{ name: 'replica_set', value: '' },
{ name: 'topology', value: 'shard' }
]
}
])(
'submits MongoDB $topology to v2 create API with expected params',
async ({
topology,
name,
host,
port,
replicaSet,
seedHosts,
expectedParams
}) => {
mockMongoDriverOption();
const { baseElement } = customRender();
await act(async () => jest.advanceTimersByTime(9300));

fireEvent.change(getBySelector('#name', baseElement), {
target: { value: name }
});
await act(async () => jest.advanceTimersByTime(300));

fireEvent.mouseDown(getBySelector('#type', baseElement));
await act(async () => jest.advanceTimersByTime(300));
fireEvent.click(getBySelector('span[title="MongoDB"]', baseElement));
await act(async () => jest.advanceTimersByTime(3000));

if (topology !== '单机') {
fireEvent.mouseDown(getBySelector('#mongoTopology', baseElement));
await act(async () => jest.advanceTimersByTime(300));
fireEvent.click(screen.getByText(topology));
await act(async () => jest.advanceTimersByTime(300));
}

fireEvent.change(getBySelector('#ip', baseElement), {
target: { value: host }
});
fireEvent.change(getBySelector('#port', baseElement), {
target: { value: port }
});
fireEvent.change(getBySelector('#user', baseElement), {
target: { value: 'mongo' }
});
fireEvent.change(getBySelector('#password', baseElement), {
target: { value: 'Mongo@123' }
});
fireEvent.change(getBySelector('#params_auth_source', baseElement), {
target: { value: 'admin' }
});

if (replicaSet) {
fireEvent.change(getBySelector('#params_replica_set', baseElement), {
target: { value: replicaSet }
});
}
if (seedHosts) {
fireEvent.change(getBySelector('#params_seed_hosts', baseElement), {
target: { value: seedHosts }
});
fireEvent.blur(getBySelector('#params_seed_hosts', baseElement));
} else {
expect(
baseElement.querySelector('#params_seed_hosts')
).not.toBeInTheDocument();
}
await act(async () => jest.advanceTimersByTime(300));

fireEvent.click(getBySelector('.editable-select-trigger', baseElement));
await act(async () => jest.advanceTimersByTime(0));
fireEvent.click(getAllBySelector('.ant-dropdown-menu-item')[0]);
await act(async () => jest.advanceTimersByTime(0));

await act(async () => {
fireEvent.click(screen.getByText('提 交'));
});
expect(checkDbServiceIsConnectableSpy).toHaveBeenCalledTimes(1);
await act(async () => jest.advanceTimersByTime(3000));

expect(requestAddDBServiceSpy).toHaveBeenCalledWith({
db_service: {
additional_params: expectedParams,
db_type: 'MongoDB',
desc: undefined,
environment_tag_uid: '1',
host,
maintenance_times: [],
name,
password: 'Mongo@123',
port,
sqle_config: {
audit_enabled: undefined,
data_export_rule_template_id: undefined,
data_export_rule_template_name: undefined,
rule_template_id: undefined,
rule_template_name: undefined,
sql_query_config: {
allow_query_when_less_than_audit_level: undefined,
audit_enabled: undefined,
maintenance_times: [],
rule_template_id: undefined,
rule_template_name: undefined,
workflow_exec_enabled: undefined
}
},
user: 'mongo',
enable_backup: undefined,
backup_max_rows: undefined
},
project_uid: projectID
});
}
);

it('render conenctable modal when current service can not connect', async () => {
checkDbServiceIsConnectableSpy.mockImplementation(() =>
createSpySuccessResponse({
Expand Down
Loading
Loading