Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release-2.14.0' into abernix/mig…
Browse files Browse the repository at this point in the history
…rate-engine-reporting-exts-to-plugin-api
  • Loading branch information
abernix committed May 12, 2020
2 parents 1144c7a + 546865d commit 3ccccad
Show file tree
Hide file tree
Showing 58 changed files with 632 additions and 518 deletions.
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ The version headers in this history reflect the versions of Apollo Server itself
_This change should be purely an implementation detail for a majority of users_. There are, however, some special considerations which are worth noting:

- The federated tracing plugin's `ftv1` response on `extensions` (which is present on the response from an implementing service to the gateway) is now placed on the `extensions` _after_ the `formatResponse` hook. Anyone leveraging the `extensions`.`ftv1` data from the `formatResponse` hook will find that it is no longer present at that phase.

- _Nothing yet! Stay tuned!_
- `apollo-tracing`: This package's internal integration with Apollo Server has been switched from using the soon-to-be-deprecated`graphql-extensions` API to using [the request pipeline plugin API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/). Behavior should remain otherwise the same. [PR #3991](https://github.com/apollographql/apollo-server/pull/3991)

### v2.13.0

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/apollo-cache-control/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-cache-control",
"version": "0.10.0",
"version": "0.10.1-alpha.0",
"description": "A GraphQL extension for cache control",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand All @@ -12,7 +12,7 @@
},
"dependencies": {
"apollo-server-env": "file:../apollo-server-env",
"graphql-extensions": "file:../graphql-extensions"
"apollo-server-plugin-base": "file:../apollo-server-plugin-base"
},
"peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
Expand Down

This file was deleted.

171 changes: 171 additions & 0 deletions packages/apollo-cache-control/src/__tests__/cacheControlPlugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { ResponsePath, GraphQLError } from 'graphql';
import { Headers } from 'apollo-server-env';
import {
CacheScope,
CacheControlExtensionOptions,
CacheHint,
__testing__,
plugin,
} from '../';
const { addHint, computeOverallCachePolicy } = __testing__;
import {
GraphQLRequestContextWillSendResponse,
GraphQLResponse,
} from 'apollo-server-plugin-base';
import pluginTestHarness from 'apollo-server-core/dist/utils/pluginTestHarness';

describe('plugin', () => {
describe('willSendResponse', () => {
function makePluginWithOptions({
pluginInitializationOptions,
overallCachePolicy,
errors = false,
}: {
pluginInitializationOptions?: CacheControlExtensionOptions;
overallCachePolicy?: Required<CacheHint>;
errors?: boolean;
} = Object.create(null)) {
const pluginInstance = plugin(pluginInitializationOptions);

return pluginTestHarness({
pluginInstance,
overallCachePolicy,
graphqlRequest: { query: 'does not matter' },
executor: () => {
const response: GraphQLResponse = {
http: {
headers: new Headers(),
},
data: { test: 'test' },
};

if (errors) {
response.errors = [new GraphQLError('Test Error')];
}

return response;
},
});
}

describe('HTTP cache-control header', () => {
const overallCachePolicy: Required<CacheHint> = {
maxAge: 300,
scope: CacheScope.Public,
};

it('is set when calculateHttpHeaders is set to true', async () => {
const requestContext = await makePluginWithOptions({
pluginInitializationOptions: {
calculateHttpHeaders: true,
},
overallCachePolicy,
});
expect(requestContext.response.http!.headers.get('Cache-Control')).toBe(
'max-age=300, public',
);
});

const shouldNotSetCacheControlHeader = (
requestContext: GraphQLRequestContextWillSendResponse<any>,
) => {
expect(
requestContext.response.http!.headers.get('Cache-Control'),
).toBeNull();
};

it('is not set when calculateHttpHeaders is set to false', async () => {
const requestContext = await makePluginWithOptions({
pluginInitializationOptions: {
calculateHttpHeaders: false,
},
overallCachePolicy,
});
shouldNotSetCacheControlHeader(requestContext);
});

it('is not set if response has errors', async () => {
const requestContext = await makePluginWithOptions({
pluginInitializationOptions: {
calculateHttpHeaders: false,
},
overallCachePolicy,
errors: true,
});
shouldNotSetCacheControlHeader(requestContext);
});

it('does not set cache-control header if there is no overall cache policy', async () => {
const requestContext = await makePluginWithOptions({
pluginInitializationOptions: {
calculateHttpHeaders: false,
},
overallCachePolicy: undefined,
errors: true,
});
shouldNotSetCacheControlHeader(requestContext);
});
});
});

describe('computeOverallCachePolicy', () => {
const responsePath: ResponsePath = {
key: 'test',
prev: undefined,
};
const responseSubPath: ResponsePath = {
key: 'subTest',
prev: responsePath,
};
const responseSubSubPath: ResponsePath = {
key: 'subSubTest',
prev: responseSubPath,
};

const hints = new Map();
afterEach(() => hints.clear());

it('returns undefined without cache hints', () => {
const cachePolicy = computeOverallCachePolicy(hints);
expect(cachePolicy).toBeUndefined();
});

it('returns lowest max age value', () => {
addHint(hints, responsePath, { maxAge: 10 });
addHint(hints, responseSubPath, { maxAge: 20 });

const cachePolicy = computeOverallCachePolicy(hints);
expect(cachePolicy).toHaveProperty('maxAge', 10);
});

it('returns undefined if any cache hint has a maxAge of 0', () => {
addHint(hints, responsePath, { maxAge: 120 });
addHint(hints, responseSubPath, { maxAge: 0 });
addHint(hints, responseSubSubPath, { maxAge: 20 });

const cachePolicy = computeOverallCachePolicy(hints);
expect(cachePolicy).toBeUndefined();
});

it('returns PUBLIC scope by default', () => {
addHint(hints, responsePath, { maxAge: 10 });

const cachePolicy = computeOverallCachePolicy(hints);
expect(cachePolicy).toHaveProperty('scope', CacheScope.Public);
});

it('returns PRIVATE scope if any cache hint has PRIVATE scope', () => {
addHint(hints, responsePath, {
maxAge: 10,
scope: CacheScope.Public,
});
addHint(hints, responseSubPath, {
maxAge: 10,
scope: CacheScope.Private,
});

const cachePolicy = computeOverallCachePolicy(hints);
expect(cachePolicy).toHaveProperty('scope', CacheScope.Private);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
import { GraphQLSchema, graphql } from 'graphql';

import {
enableGraphQLExtensions,
GraphQLExtensionStack,
} from 'graphql-extensions';
import {
CacheControlExtension,
CacheHint,
CacheControlExtensionOptions,
plugin,
} from '../';
import pluginTestHarness from 'apollo-server-core/dist/utils/pluginTestHarness';

export async function collectCacheControlHints(
schema: GraphQLSchema,
source: string,
options?: CacheControlExtensionOptions,
): Promise<CacheHint[]> {
enableGraphQLExtensions(schema);

// Because this test helper looks at the formatted extensions, we always want
// to include them.
const cacheControlExtension = new CacheControlExtension({
// to include them in the response rather than allow them to be stripped
// out.
const pluginInstance = plugin({
...options,
stripFormattedExtensions: false,
});

const response = await graphql({
const requestContext = await pluginTestHarness({
pluginInstance,
schema,
source,
contextValue: {
_extensionStack: new GraphQLExtensionStack([cacheControlExtension]),
graphqlRequest: {
query: source,
},
executor: async (requestContext) => {
return await graphql({
schema,
source: requestContext.request.query,
contextValue: requestContext.context,
});
}
});

expect(response.errors).toBeUndefined();
expect(requestContext.response.errors).toBeUndefined();

return cacheControlExtension.format()[1].hints;
return requestContext.response.extensions!.cacheControl.hints;
}

0 comments on commit 3ccccad

Please sign in to comment.