add http_get_cache

This commit is contained in:
2026-01-20 23:18:39 -08:00
parent 572c0789b7
commit 811e884481
168 changed files with 37335 additions and 0 deletions
@@ -0,0 +1,204 @@
import 'dart:convert';
import 'dart:io';
import 'package:http_get_cache/http_get_cache.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late HttpGetCacheDatabase db;
late SqliteHttpCacheStore store;
setUp(() async {
db = await initHttpGetCache(
cachePath: 'temp',
databasePath: 'temp'
);
store = SqliteHttpCacheStore(db);
});
tearDown(() async {
await db.close();
});
tearDownAll(() async {
await Directory(db.settings.cacheDir).delete(recursive: true);
// await Directory(db.settings.databaseDir).delete(recursive: true);
});
group('HttpGetCache', () {
test('check for no cache headers', () async {
final inner = TestHttpClient();
final client = HttpGetCache(inner, store);
var res = await client.get(Uri.http('example.com'));
expect(res.statusCode, 200);
expect(inner.calls, 1);
res = await client.get(Uri.http('example.com'));
expect(res.statusCode, 200);
expect(inner.calls, 2);
});
test('check if cache-control header is respected', () async {
final inner = TestHttpClient();
const target = 'http://example.com/cache-control';
inner.handle = (req) async {
return Response('', 200, headers: {
'Cache-Control': 'public, immutable',
});
};
final client = HttpGetCache(inner, store);
var res = await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'], 'public, immutable');
expect(inner.calls, 1);
res = await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'], 'public, immutable');
expect(inner.calls, 2);
});
test('check if max-age is respected', () async {
final inner = TestHttpClient();
const target = 'http://example.com/max-age';
const ma = 5;
inner.handle = (req) async {
return Response.bytes(utf8.encode('Success!'), 200, headers: {
'Cache-Control': 'max-age=$ma',
});
};
final client = HttpGetCache(inner, store);
var res = await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'], 'max-age=$ma');
expect(inner.calls, 1);
res = await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'], 'max-age=$ma');
expect(inner.calls, 1);
await Future.delayed(const Duration(seconds: ma + 1));
res = await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'], 'max-age=$ma');
expect(inner.calls, 2);
});
test('check if max-age + stale-while-revalidate is respected', () async {
final inner = TestHttpClient();
const target = 'http://example.com/max-age/stale-while-revalidate';
const ma = 3;
const swr = 5;
inner.handle = (req) async {
return Response.bytes(utf8.encode('Success!'), 200, headers: {
'Cache-Control': 'max-age=$ma, stale-while-revalidate=$swr',
});
};
final client = HttpGetCache(inner, store);
var res = await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'],
'max-age=$ma, stale-while-revalidate=$swr');
expect(inner.calls, 1);
res = await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'],
'max-age=$ma, stale-while-revalidate=$swr');
expect(inner.calls, 1);
await Future.delayed(const Duration(seconds: ma));
await client.stream(Request('GET', Uri.parse(target))).first;
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'],
'max-age=$ma, stale-while-revalidate=$swr');
expect(inner.calls, 1);
await Future.delayed(const Duration(seconds: swr + 1));
await client.get(Uri.parse(target));
expect(res.statusCode, 200);
expect(res.headers['Cache-Control'],
'max-age=$ma, stale-while-revalidate=$swr');
expect(inner.calls, 2);
});
test('stale-if-error', () async {
final inner = TestHttpClient();
const ma = 3;
const sie = 5;
const target = 'http://example.com/error-check';
int count = 0;
bool error = false;
inner.handle = (req) async {
if (error) return Response('', 500);
if (req.method == 'GET') count++;
return Response.bytes(utf8.encode('count: $count'), 200, headers: {
'Cache-Control': 'max-age=$ma, stale-if-error=$sie',
});
};
final client = HttpGetCache(inner, store);
final url = Uri.parse(target);
var res = await client.get(url);
expect(res.statusCode, 200);
expect(res.body, 'count: 1');
error = true;
await Future.delayed(const Duration(seconds: ma + 1));
res = await client.get(url);
expect(res.statusCode, 200);
expect(res.body, 'count: 1');
await Future.delayed(const Duration(seconds: sie + 1));
res = await client.get(url);
expect(res.statusCode, 500);
});
});
}
class TestHttpClient extends BaseClient {
TestHttpClient();
int calls = 0;
Future<Response> Function(BaseRequest request) handle = (req) async {
return Response('', 200);
};
@override
Future<StreamedResponse> send(BaseRequest request) async {
final res = await handle(request);
if (request.method == 'GET') calls++;
return StreamedResponse(
Stream.value(res.bodyBytes),
res.statusCode,
headers: res.headers,
request: request,
isRedirect: res.isRedirect,
persistentConnection: res.persistentConnection,
reasonPhrase: res.reasonPhrase,
contentLength: res.contentLength,
);
}
}