Skip to content

Commit

Permalink
Merge pull request #59 from ytka/feat-disconnect
Browse files Browse the repository at this point in the history
  • Loading branch information
1natsu172 authored Aug 9, 2021
2 parents face07b + e15ce08 commit 1aabe4d
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 3 deletions.
47 changes: 47 additions & 0 deletions __tests__/bluevery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,53 @@ describe('bluevery: commands APIs', () => {
});
});

describe('disconnect', () => {
const disconnectFn = jest.fn();
const core = (jest.fn().mockImplementation(() => ({
listeners: {publicListeners: {}},
init: jest.fn(),
disconnect: disconnectFn,
})) as unknown) as typeof BlueveryCore;

beforeEach(async () => {
jest.clearAllMocks();
bluevery = new Bluevery({
BlueveryCore: core,
BlueveryState,
blueveryListeners: new BlueveryListeners(),
store: proxy({bluevery: createInitialState()}),
});
await bluevery.init();
});

describe('disconnect: check calls', () => {
beforeEach(async () => {
await bluevery.disconnect({
disconnectParams: ['1'],
});
});

test('should call core#connect', async () => {
expect(disconnectFn).toBeCalled();
});
});

describe('disconnect: negative pattern', () => {
test('should throw if not found core method', async () => {
bluevery = new Bluevery({
BlueveryCore: core,
BlueveryState,
blueveryListeners: new BlueveryListeners(),
store: proxy({bluevery: createInitialState()}),
});
const ret = bluevery.disconnect({
disconnectParams: ['1'],
});
await expect(ret).rejects.toThrow('this.core?.disconnect is undefined');
});
});
});

describe('receiveCharacteristicValue', () => {
const connectFn = jest.fn();
const mockedOnCallBeforeStartNotification = jest.fn(async () => {});
Expand Down
144 changes: 144 additions & 0 deletions __tests__/blueveryCore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,150 @@ describe('BlueveryCore', () => {
});
});

describe('disconect', () => {
beforeEach(() => {
blueveryCore = new BlueveryCore({
store: proxy({bluevery: createInitialState()}),

blueveryListeners: new BlueveryListeners(),
BlueveryState,
initialState: createInitialState({
scannedPeripherals: {
['1']: dummyPeripheralInfo('1'),
},
}),
});
});

test('disconnect: should return false if requireCheckBeforeBleProcess failed', async () => {
spiedRequireCheckBeforeBleProcess.mockImplementationOnce(() => false);
const ret = await blueveryCore.disconnect({
disconnectParams: ['1'],
disconnectOptions: {
timeoutOptions: {timeoutMilliseconds: 1000},
},
});

expect(ret).toBe(false);
});

test('disconnect: shoube be early return if not connected the peripheral', async () => {
// @ts-expect-error mocked at jest.setup.js
BleManager.isPeripheralConnected.mockImplementationOnce(() => false);
const ret = await blueveryCore.disconnect({
disconnectParams: ['1'],
disconnectOptions: {
timeoutOptions: {timeoutMilliseconds: 1000},
},
});

expect(ret).toBe(false);
});

test('disconnect: should be change disconnect of state the managing peripheral', async () => {
mockPlatform('android', 10);
const spyState = jest.fn();
blueveryCore = new BlueveryCore({
store: proxy({bluevery: createInitialState()}),

blueveryListeners: new BlueveryListeners(),
BlueveryState,
initialState: createInitialState({
scannedPeripherals: {['1']: dummyPeripheralInfo('1')},
managingPeripherals: {
['1']: {...dummyPeripheralInfo('1'), connect: 'connected'},
},
}),
onChangeStateHandler: (state) => {
spyState(state.managingPeripherals['1']);
},
});
// check initial status
expect(blueveryCore.getState().managingPeripherals['1'].connect).toBe(
'connected',
);
//BleManager.disconnect.mockImplementationOnce(async () => {});
// @ts-expect-error -- mocked at jest.setup.js
BleManager.isPeripheralConnected.mockImplementationOnce(() => true);

await blueveryCore.disconnect({
disconnectParams: ['1'],
disconnectOptions: {
timeoutOptions: {timeoutMilliseconds: 1000},
},
});
expect(spyState.mock.calls.length).toBe(1);
expect(spyState.mock.calls[0][0].connect).toBe('disconnected');
expect(blueveryCore.getState().managingPeripherals['1'].connect).toBe(
'disconnected',
);
});

test('disconnect: should be throw error and state change to failed', async () => {
// @ts-expect-error -- mocked at jest.setup.js
BleManager.disconnect.mockImplementationOnce(async () => {
throw new Error('fixture error');
});
//BleManager.disconnect.mockImplementationOnce(async () => {});
// @ts-expect-error -- mocked at jest.setup.js
BleManager.isPeripheralConnected.mockImplementationOnce(() => true);

const spyState = jest.fn();
blueveryCore = new BlueveryCore({
store: proxy({bluevery: createInitialState()}),

blueveryListeners: new BlueveryListeners(),
BlueveryState,
initialState: createInitialState({
scannedPeripherals: {['1']: dummyPeripheralInfo('1')},
managingPeripherals: {
['1']: {...dummyPeripheralInfo('1'), connect: 'connected'},
},
}),
onChangeStateHandler: (state) => {
spyState(state.managingPeripherals['1']);
},
});

const disconnect = blueveryCore.disconnect({
disconnectParams: ['1'],
disconnectOptions: {
timeoutOptions: {timeoutMilliseconds: 1000},
},
});

await expect(disconnect).rejects.toThrow('fixture error');
expect(spyState.mock.calls.length).toBe(0);
});

test('disconnect: should be throw if not found peripheral in scannedPeripherals', async () => {
blueveryCore = new BlueveryCore({
store: proxy({bluevery: createInitialState()}),

blueveryListeners: new BlueveryListeners(),
BlueveryState,
initialState: createInitialState({
scannedPeripherals: {},
managingPeripherals: {
['2']: {...dummyPeripheralInfo('2'), connect: 'connected'},
},
}),
onChangeStateHandler: () => undefined,
});
//BleManager.disconnect.mockImplementationOnce(async () => {});
// @ts-expect-error -- mocked at jest.setup.js
BleManager.isPeripheralConnected.mockImplementationOnce(() => true);

const disconnecting = blueveryCore.disconnect({
disconnectParams: ['2'],
disconnectOptions: {
timeoutOptions: {timeoutMilliseconds: 1000},
},
});
await expect(disconnecting).rejects.toThrow();
});
});

describe('retrieveServices', () => {
const spyRetrieveServicesState = jest.fn();
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ export const useAND_UC_352BLE: (props: Props) => BleController = ({
],
retrieveServicesParams: [peripheralInfo.id],
});
//await bluevery.disconnect(peripheralInfo.id);
},
scanParams: {
scanOptions: {
Expand Down Expand Up @@ -155,7 +154,7 @@ export const useAND_UC_352BLE: (props: Props) => BleController = ({
],
retrieveServicesParams: [peripheralInfo.id],
});
console.log(`reade value: end write value`);
console.log(`end write value`);
const value = await bluevery.readValue({
readValueParams: [
peripheralInfo.id,
Expand All @@ -164,7 +163,9 @@ export const useAND_UC_352BLE: (props: Props) => BleController = ({
],
retrieveServicesParams: [peripheralInfo.id],
});
console.log(`reade value: ${JSON.stringify(value)}`);
console.log(`end reade value: ${JSON.stringify(value)}`);
console.log('disconnect');
await bluevery.disconnect({disconnectParams: [peripheralInfo.id]});
} catch (error) {
onError(error);
}
Expand Down
1 change: 1 addition & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jest.mock('react-native-ble-manager', () => {
});
}),
connect: jest.fn(),
disconnect: jest.fn(),
retrieveServices: jest.fn(),
createBond: jest.fn(),
startNotification: jest.fn(),
Expand Down
25 changes: 25 additions & 0 deletions src/bluevery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,31 @@ export class Bluevery {
debugBluevery('connect: end');
}

async disconnect({
disconnectParams,
disconnectOptions,
}: {
disconnectParams: BleManagerParams['disconnect'];
disconnectOptions?: BlueveryMethodOptions['disconnect'];
}) {
debugBluevery('disconnect: start');

const _disconnectOptions = createBlueveryCoreMethodOption(
'disconnect',
disconnectOptions,
);

if (this.core?.disconnect === undefined) {
throw new Error('this.core?.disconnect is undefined');
}

await this.core?.disconnect({
disconnectParams,
disconnectOptions: _disconnectOptions,
});
debugBluevery('disconnect: end');
}

/**
* NOTE: connect, bondingはconnectメソッドで必要で、connectメソッド側でオプションのデフォルト値は吸収しているのでこのメソッドで設定しないのは意図的。
*/
Expand Down
54 changes: 54 additions & 0 deletions src/blueveryCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,60 @@ export class BlueveryCore {
debugBlueveryCore('connect: connect process end');
}

async disconnect({
disconnectParams,
disconnectOptions,
}: {
disconnectParams: BleManagerParams['disconnect'];
disconnectOptions: BlueveryCoreMethodOptions['disconnect'];
}) {
debugBlueveryCore('disconnect: start', disconnectParams);
const [targetPeripheralId] = disconnectParams;

const isPassedRequireCheck = await this.requireCheckBeforeBleProcess();
debugBlueveryCore('disconnect: isPassedRequireCheck', isPassedRequireCheck);
if (isPassedRequireCheck === false) {
return false;
}

const isAlreadyConnected = await BleManager.isPeripheralConnected(
targetPeripheralId,
[],
);
debugBlueveryCore('disconnect: isAlreadyConnected', isAlreadyConnected);
if (!isAlreadyConnected) {
return false;
}

// FIXME: selector化したい
const peripheral = this.getState().scannedPeripherals[targetPeripheralId];
if (!peripheral) {
throw new Error(
`${targetPeripheralId} is not found in scannedPeripherals`,
);
}

const _disconnect = toBetterPromise(
toThrowErrorIfRejected(BleManager.disconnect),
disconnectOptions,
);

try {
debugBlueveryCore('disconnect: disconnect process start');
await _disconnect(...disconnectParams).then(() => {
debugBlueveryCore('disconnect: disconnect success');
this.state.setManagingPeripheralDisconnected(targetPeripheralId);
});
} catch (error) {
debugBlueveryCore(
'disconnect: An error has occurred in the disconnect process',
error,
);
throw error;
}
debugBlueveryCore('disconnect: disconnect process end');
}

/**
* @description retrieveServices must have timeout
*/
Expand Down
3 changes: 3 additions & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export interface BlueveryCoreMethodOptions {
connect: ToBetterOptionsWithMustTimeout & {
omoiyariTime: number;
};
disconnect: ToBetterOptions & {};

// Note: retrieveServicesがpendingのままになるときがあるので、タイムアウトするようにする
retrieveServices: ToBetterOptionsWithMustTimeout & {
omoiyariTime: number;
Expand All @@ -118,6 +120,7 @@ export interface BlueveryCoreMethodOptions {
export interface BlueveryMethodOptions {
scan: Partial<BlueveryCoreMethodOptions['scan']>;
connect: Partial<BlueveryCoreMethodOptions['connect']>;
disconnect: Partial<BlueveryCoreMethodOptions['disconnect']>;
retrieveServices: Partial<BlueveryCoreMethodOptions['retrieveServices']>;
createBond: Partial<BlueveryCoreMethodOptions['createBond']>;
read: Partial<BlueveryCoreMethodOptions['read']>;
Expand Down
4 changes: 4 additions & 0 deletions src/utils/createBlueveryCoreMethodOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export const defaultBlueveryCoreMethodOptions: BlueveryCoreMethodOptions = {
timeoutOptions: {timeoutMilliseconds: 8000},
omoiyariTime: DEFAULT_OMOIYARI_TIME,
},
disconnect: {
retryOptions: {factor: 1, retries: 4},
timeoutOptions: {timeoutMilliseconds: 8000},
},
createBond: {
retryOptions: {factor: 1, retries: 4},
timeoutOptions: {timeoutMilliseconds: 10000},
Expand Down

0 comments on commit 1aabe4d

Please sign in to comment.