Skip to content

Commit

Permalink
feat(ref-imp): #781 - add some tests
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacJChen committed Sep 21, 2020
1 parent 3d218d4 commit 6662e9f
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 15 deletions.
11 changes: 9 additions & 2 deletions lib/core/versions/latest/CreateOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,21 @@ export default class CreateOperation implements OperationModel {
}

CreateOperation.validateSuffixData(operationObject.suffix_data);
const suffixData = {
deltaHash: operationObject.suffix_data.delta_hash,
recoveryCommitment: operationObject.suffix_data.recovery_commitment
}

// For compatibility with data pruning, we have to assume that `delta` may be unavailable,
// thus an operation with invalid `delta` needs to be processed as an operation with unavailable `delta`,
// so here we let `delta` be `undefined`.
let delta;
try {
Operation.validateDelta(operationObject.delta);
delta = operationObject.delta;
delta = {
patches: operationObject.delta.patches,
updateCommitment: operationObject.delta.update_commitment
};
} catch {
delta = undefined;
}
Expand All @@ -139,7 +146,7 @@ export default class CreateOperation implements OperationModel {

const encodedSuffixData = Encoder.encode(JsonCanonicalizer.canonicalizeAsBuffer(operationObject.suffix_data));
const encodedDelta = Encoder.encode(JsonCanonicalizer.canonicalizeAsBuffer(operationObject.delta));
return new CreateOperation(operationBuffer, didUniqueSuffix, encodedSuffixData, operationObject.suffix_data, encodedDelta, delta);
return new CreateOperation(operationBuffer, didUniqueSuffix, encodedSuffixData, suffixData, encodedDelta, delta);
}

/**
Expand Down
11 changes: 11 additions & 0 deletions lib/core/versions/latest/Multihash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ export default class Multihash {
return hash;
}

/**
* Canonicalize the given content, then double hashes the result using the latest supported hash algorithm, then encodes the multihash.
* Mainly used for testing purposes.
*/
public static canonicalizeThenHashThenEncode (content: object) {
const canonicalizedStringBuffer = JsonCanonicalizer.canonicalizeAsBuffer(content);

const multihashEncodedString = Multihash.hashThenEncode(canonicalizedStringBuffer, ProtocolParameters.hashAlgorithmInMultihashCode);
return multihashEncodedString;
}

/**
* Canonicalize the given content, then double hashes the result using the latest supported hash algorithm, then encodes the multihash.
* Mainly used for testing purposes.
Expand Down
15 changes: 5 additions & 10 deletions tests/core/Did.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,15 @@ describe('DID', async () => {

it('should create a long-form DID with suffix data and delta successfully.', async () => {
// Create a long-form DID string.
const createOperationData = await OperationGenerator.generateCreateOperation();

const generatedLongFormDidData = await OperationGenerator.generateLongFormDid();
const didMethodName = 'sidetree';
const didUniqueSuffix = createOperationData.createOperation.didUniqueSuffix;
const shortFormDid = `did:${didMethodName}:${didUniqueSuffix}`;
const encodedSuffixData = createOperationData.createOperation.encodedSuffixData;
const encodedDelta = createOperationData.createOperation.encodedDelta;
const longFormDid = `${shortFormDid}:${encodedSuffixData}.${encodedDelta}`;

const did = await Did.create(longFormDid, didMethodName);
const did = await Did.create(generatedLongFormDidData.longFormDid, didMethodName);
expect(did.isShortForm).toBeFalsy();
expect(did.didMethodName).toEqual(didMethodName);
expect(did.shortForm).toEqual(shortFormDid);
expect(did.uniqueSuffix).toEqual(didUniqueSuffix);
expect(did.createOperation).toEqual(createOperationData.createOperation);
expect(did.shortForm).toEqual(generatedLongFormDidData.shortFormDid);
expect(did.uniqueSuffix).toEqual(generatedLongFormDidData.didUniqueSuffix);
});

it('should create a testnet long-form DID successfully.', async () => {
Expand Down
17 changes: 15 additions & 2 deletions tests/core/RequestHandler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ describe('RequestHandler', () => {
validateDidReferencesInDidDocument(response.body.didDocument, did);
});

it('should return a resolved DID Document given a valid long-form DID.', async () => {
it('should return a resolved DID Document given a valid long-form DID with query param initial state format.', async () => {
// Create a long-form DID string.
const createOperationData = await OperationGenerator.generateCreateOperation();
const didMethodName = 'sidetree';
Expand All @@ -242,6 +242,19 @@ describe('RequestHandler', () => {
validateDidReferencesInDidDocument(response.body.didDocument, longFormDid);
});

it('should return a resolved DID Document given a valid long-form DID with JCS format.', async () => {
// Create a long-form DID string.
const longFormDid = (await OperationGenerator.generateLongFormDid()).longFormDid;

const response = await requestHandler.handleResolveRequest(longFormDid);
const httpStatus = Response.toHttpStatus(response.status);

expect(httpStatus).toEqual(200);
expect(response.body).toBeDefined();

validateDidReferencesInDidDocument(response.body.didDocument, longFormDid);
});

it('should return NotFound given an unknown DID.', async () => {
const response = await requestHandler.handleResolveRequest('did:sidetree:EiAgE-q5cRcn4JHh8ETJGKqaJv1z2OgjmN3N-APx0aAvHg');
const httpStatus = Response.toHttpStatus(response.status);
Expand All @@ -255,7 +268,7 @@ describe('RequestHandler', () => {
const httpStatus = Response.toHttpStatus(response.status);

expect(httpStatus).toEqual(400);
expect(response.body.code).toEqual(ErrorCode.DidInitialStateValueDoesNotContainTwoParts);
expect(response.body.code).toEqual(ErrorCode.EncoderValidateBase64UrlStringInputNotBase64UrlString);
});

it('should respond with HTTP 200 when DID deactivate operation request is successful.', async () => {
Expand Down
62 changes: 61 additions & 1 deletion tests/generators/OperationGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import * as crypto from 'crypto';
import AnchoredOperationModel from '../../lib/core/models/AnchoredOperationModel';
import AnchorFile from '../../lib/core/versions/latest/AnchorFile';
import CreateOperation from '../../lib/core/versions/latest/CreateOperation';
import DataGenerator from './DataGenerator';
import DeactivateOperation from '../../lib/core/versions/latest/DeactivateOperation';
import DocumentModel from '../../lib/core/versions/latest/models/DocumentModel';
import Encoder from '../../lib/core/versions/latest/Encoder';
import JsonCanonicalizer from '../../lib/core/versions/latest/util/JsonCanonicalizer';
import JwkEs256k from '../../lib/core/models/JwkEs256k';
import Jwk from '../../lib/core/versions/latest/util/Jwk';
import Jws from '../../lib/core/versions/latest/util/Jws';
Expand All @@ -17,7 +19,6 @@ import RecoverOperation from '../../lib/core/versions/latest/RecoverOperation';
import ServiceEndpointModel from '../../lib/core/versions/latest/models/ServiceEndpointModel';
import TransactionModel from '../../lib/common/models/TransactionModel';
import UpdateOperation from '../../lib/core/versions/latest/UpdateOperation';
import DataGenerator from './DataGenerator';

interface AnchoredCreateOperationGenerationInput {
transactionNumber: number;
Expand Down Expand Up @@ -117,6 +118,65 @@ export default class OperationGenerator {
};
}

/**
* generate a long form did
* @param recoveryPublicKey
* @param updatePublicKey
* @param otherPublicKeys
* @param serviceEndpoints
*/
public static async generateLongFormDid (
recoveryPublicKey?: JwkEs256k,
updatePublicKey?: JwkEs256k,
otherPublicKeys?: PublicKeyModel[],
serviceEndpoints?: ServiceEndpointModel[]) {

const document = {
public_keys: otherPublicKeys || [],
service_endpoints: serviceEndpoints || []
};

const patches = [{
action: 'replace',
document
}];

[recoveryPublicKey] = await Jwk.generateEs256kKeyPair();
[updatePublicKey] = await Jwk.generateEs256kKeyPair();

const delta = {
update_commitment: Multihash.canonicalizeThenDoubleHashThenEncode(updatePublicKey),
patches
};

const deltaHash = Multihash.canonicalizeThenHashThenEncode(delta);

const suffixData = {
delta_hash: deltaHash,
recovery_commitment: Multihash.canonicalizeThenDoubleHashThenEncode(recoveryPublicKey)
};

const didUniqueSuffix = CreateOperation['computeJcsDidUniqueSuffix'](suffixData);
const shortFormDid = `did:sidetree:${didUniqueSuffix}`;

// TODO: discuss if canonicalization is necessary.
const initialState = {
suffix_data: suffixData,
delta: delta
};

const canonicalizedInitialStateBuffer = JsonCanonicalizer.canonicalizeAsBuffer(initialState);
const encodedCanonicalizedInitialStateString = Encoder.encode(canonicalizedInitialStateBuffer);

const longFormDid = `${shortFormDid}:${encodedCanonicalizedInitialStateString}`;
return {
longFormDid,
shortFormDid,
didUniqueSuffix,

};
}

/**
* Generates a create operation.
*/
Expand Down

0 comments on commit 6662e9f

Please sign in to comment.