mirror of
https://github.com/flutter/samples.git
synced 2026-03-22 04:17:50 +00:00
Add code sharing sample (#1444)
* code-sharing boilerplate * initial commit of code-sharing logic * documentation improvements * added code-sharing to samples.yaml * Updated counter UI to visually indicate communication with the server * added code_sharing to CI * CI changes to code_sharing * fixed test with DI * formatting * added shared module to CI * adds forgotten CI change
This commit is contained in:
9
code_sharing/server/.dockerignore
Normal file
9
code_sharing/server/.dockerignore
Normal file
@@ -0,0 +1,9 @@
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
build/
|
||||
.dart_tool/
|
||||
.git/
|
||||
.github/
|
||||
.gitignore
|
||||
.idea/
|
||||
.packages
|
||||
6
code_sharing/server/.gitignore
vendored
Normal file
6
code_sharing/server/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Files and directories created by pub.
|
||||
.dart_tool/
|
||||
.packages
|
||||
|
||||
# Conventional directory for build output.
|
||||
build/
|
||||
3
code_sharing/server/CHANGELOG.md
Normal file
3
code_sharing/server/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.0
|
||||
|
||||
- Initial version.
|
||||
20
code_sharing/server/Dockerfile
Normal file
20
code_sharing/server/Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
||||
# Use latest stable channel SDK.
|
||||
FROM dart:stable AS build
|
||||
|
||||
# Resolve app dependencies.
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN dart pub get
|
||||
|
||||
# AOT compile app.
|
||||
RUN dart compile exe bin/server.dart -o bin/server
|
||||
|
||||
# Build minimal serving image from AOT-compiled `/server`
|
||||
# and the pre-built AOT-runtime in the `/runtime/` directory of the base image.
|
||||
FROM scratch
|
||||
COPY --from=build /runtime/ /
|
||||
COPY --from=build /app/bin/server /app/bin/
|
||||
|
||||
# Start server.
|
||||
EXPOSE 8080
|
||||
CMD ["/app/bin/server"]
|
||||
49
code_sharing/server/README.md
Normal file
49
code_sharing/server/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
A server app built using [Shelf](https://pub.dev/packages/shelf),
|
||||
configured to enable running with [Docker](https://www.docker.com/).
|
||||
|
||||
This sample code handles HTTP GET requests to `/` and `/echo/<message>`
|
||||
|
||||
# Running the sample
|
||||
|
||||
## Running with the Dart SDK
|
||||
|
||||
You can run the example with the [Dart SDK](https://dart.dev/get-dart)
|
||||
like this:
|
||||
|
||||
```
|
||||
$ dart run bin/server.dart
|
||||
Server listening on port 8080
|
||||
```
|
||||
|
||||
And then from a second terminal:
|
||||
```
|
||||
$ curl http://0.0.0.0:8080
|
||||
Hello, World!
|
||||
$ curl http://0.0.0.0:8080/echo/I_love_Dart
|
||||
I_love_Dart
|
||||
```
|
||||
|
||||
## Running with Docker
|
||||
|
||||
If you have [Docker Desktop](https://www.docker.com/get-started) installed, you
|
||||
can build and run with the `docker` command:
|
||||
|
||||
```
|
||||
$ docker build . -t myserver
|
||||
$ docker run -it -p 8080:8080 myserver
|
||||
Server listening on port 8080
|
||||
```
|
||||
|
||||
And then from a second terminal:
|
||||
```
|
||||
$ curl http://0.0.0.0:8080
|
||||
Hello, World!
|
||||
$ curl http://0.0.0.0:8080/echo/I_love_Dart
|
||||
I_love_Dart
|
||||
```
|
||||
|
||||
You should see the logging printed in the first terminal:
|
||||
```
|
||||
2021-05-06T15:47:04.620417 0:00:00.000158 GET [200] /
|
||||
2021-05-06T15:47:08.392928 0:00:00.001216 GET [200] /echo/I_love_Dart
|
||||
```
|
||||
30
code_sharing/server/analysis_options.yaml
Normal file
30
code_sharing/server/analysis_options.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
# This file configures the static analysis results for your project (errors,
|
||||
# warnings, and lints).
|
||||
#
|
||||
# This enables the 'recommended' set of lints from `package:lints`.
|
||||
# This set helps identify many issues that may lead to problems when running
|
||||
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||
# style and format.
|
||||
#
|
||||
# If you want a smaller set of lints you can change this to specify
|
||||
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||
# (the recommended set includes the core lints).
|
||||
# The core lints are also what is used by pub.dev for scoring packages.
|
||||
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
# Uncomment the following section to specify additional rules.
|
||||
|
||||
# linter:
|
||||
# rules:
|
||||
# - camel_case_types
|
||||
|
||||
# analyzer:
|
||||
# exclude:
|
||||
# - path/to/excluded/files/**
|
||||
|
||||
# For more information about the core and recommended set of lints, see
|
||||
# https://dart.dev/go/core-lints
|
||||
|
||||
# For additional information about configuring this file, see
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
36
code_sharing/server/bin/server.dart
Normal file
36
code_sharing/server/bin/server.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:shared/shared.dart';
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf/shelf_io.dart';
|
||||
import 'package:shelf_router/shelf_router.dart';
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Configure routes.
|
||||
final _router = Router()
|
||||
..post('/', _incrementHandler)
|
||||
..get('/', _getValueHandler);
|
||||
|
||||
Future<Response> _incrementHandler(Request request) async {
|
||||
final incr = Increment.fromJson(json.decode(await request.readAsString()));
|
||||
count += incr.by;
|
||||
return Response.ok(json.encode(Count(count).toJson()));
|
||||
}
|
||||
|
||||
Response _getValueHandler(Request request) =>
|
||||
Response.ok(json.encode(Count(count).toJson()));
|
||||
|
||||
void main(List<String> args) async {
|
||||
// Use any available host or container IP (usually `0.0.0.0`).
|
||||
final ip = InternetAddress.anyIPv4;
|
||||
|
||||
// Configure a pipeline that logs requests.
|
||||
final handler = Pipeline().addMiddleware(logRequests()).addHandler(_router);
|
||||
|
||||
// For running in containers, we respect the PORT environment variable.
|
||||
final port = int.parse(Platform.environment['PORT'] ?? '8080');
|
||||
final server = await serve(handler, ip, port);
|
||||
print('Server listening on port ${server.port}');
|
||||
}
|
||||
19
code_sharing/server/pubspec.yaml
Normal file
19
code_sharing/server/pubspec.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
name: server
|
||||
description: A server app using the shelf package and Docker.
|
||||
version: 1.0.0
|
||||
publish_to: "none"
|
||||
|
||||
environment:
|
||||
sdk: ">=2.18.1 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
args: ^2.0.0
|
||||
shelf: ^1.1.0
|
||||
shelf_router: ^1.0.0
|
||||
shared:
|
||||
path: ./shared
|
||||
|
||||
dev_dependencies:
|
||||
http: ^0.13.0
|
||||
lints: ^2.0.0
|
||||
test: ^1.15.0
|
||||
10
code_sharing/server/shared/.gitignore
vendored
Normal file
10
code_sharing/server/shared/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Files and directories created by pub.
|
||||
.dart_tool/
|
||||
.packages
|
||||
|
||||
# Conventional directory for build outputs.
|
||||
build/
|
||||
|
||||
# Omit committing pubspec.lock for library packages; see
|
||||
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
pubspec.lock
|
||||
3
code_sharing/server/shared/CHANGELOG.md
Normal file
3
code_sharing/server/shared/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.0
|
||||
|
||||
- Initial version.
|
||||
39
code_sharing/server/shared/README.md
Normal file
39
code_sharing/server/shared/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
<!--
|
||||
This README describes the package. If you publish this package to pub.dev,
|
||||
this README's contents appear on the landing page for your package.
|
||||
|
||||
For information about how to write a good package README, see the guide for
|
||||
[writing package pages](https://dart.dev/guides/libraries/writing-package-pages).
|
||||
|
||||
For general information about developing packages, see the Dart guide for
|
||||
[creating packages](https://dart.dev/guides/libraries/create-library-packages)
|
||||
and the Flutter guide for
|
||||
[developing packages and plugins](https://flutter.dev/developing-packages).
|
||||
-->
|
||||
|
||||
TODO: Put a short description of the package here that helps potential users
|
||||
know whether this package might be useful for them.
|
||||
|
||||
## Features
|
||||
|
||||
TODO: List what your package can do. Maybe include images, gifs, or videos.
|
||||
|
||||
## Getting started
|
||||
|
||||
TODO: List prerequisites and provide or point to information on how to
|
||||
start using the package.
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
|
||||
```dart
|
||||
const like = 'sample';
|
||||
```
|
||||
|
||||
## Additional information
|
||||
|
||||
TODO: Tell users more about the package: where to find more information, how to
|
||||
contribute to the package, how to file issues, what response they can expect
|
||||
from the package authors, and more.
|
||||
29
code_sharing/server/shared/analysis_options.yaml
Normal file
29
code_sharing/server/shared/analysis_options.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
# This file configures the static analysis results for your project (errors,
|
||||
# warnings, and lints).
|
||||
#
|
||||
# This enables the 'recommended' set of lints from `package:lints`.
|
||||
# This set helps identify many issues that may lead to problems when running
|
||||
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||
# style and format.
|
||||
#
|
||||
# If you want a smaller set of lints you can change this to specify
|
||||
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||
# (the recommended set includes the core lints).
|
||||
# The core lints are also what is used by pub.dev for scoring packages.
|
||||
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
# Uncomment the following section to specify additional rules.
|
||||
|
||||
# linter:
|
||||
# rules:
|
||||
# - camel_case_types
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
- "**/*.g.dart"
|
||||
# For more information about the core and recommended set of lints, see
|
||||
# https://dart.dev/go/core-lints
|
||||
|
||||
# For additional information about configuring this file, see
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
4
code_sharing/server/shared/lib/shared.dart
Normal file
4
code_sharing/server/shared/lib/shared.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
/// Common data models required by our client and server.
|
||||
library shared;
|
||||
|
||||
export 'src/models.dart';
|
||||
19
code_sharing/server/shared/lib/src/models.dart
Normal file
19
code_sharing/server/shared/lib/src/models.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'models.freezed.dart';
|
||||
part 'models.g.dart';
|
||||
|
||||
@Freezed()
|
||||
class Increment with _$Increment {
|
||||
const factory Increment({required int by}) = _Increment;
|
||||
|
||||
factory Increment.fromJson(Map<String, dynamic> json) =>
|
||||
_$IncrementFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed()
|
||||
class Count with _$Count {
|
||||
const factory Count(int value) = _Count;
|
||||
|
||||
factory Count.fromJson(Map<String, dynamic> json) => _$CountFromJson(json);
|
||||
}
|
||||
271
code_sharing/server/shared/lib/src/models.freezed.dart
Normal file
271
code_sharing/server/shared/lib/src/models.freezed.dart
Normal file
@@ -0,0 +1,271 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
|
||||
|
||||
part of 'models.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
Increment _$IncrementFromJson(Map<String, dynamic> json) {
|
||||
return _Increment.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Increment {
|
||||
int get by => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$IncrementCopyWith<Increment> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $IncrementCopyWith<$Res> {
|
||||
factory $IncrementCopyWith(Increment value, $Res Function(Increment) then) =
|
||||
_$IncrementCopyWithImpl<$Res>;
|
||||
$Res call({int by});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$IncrementCopyWithImpl<$Res> implements $IncrementCopyWith<$Res> {
|
||||
_$IncrementCopyWithImpl(this._value, this._then);
|
||||
|
||||
final Increment _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function(Increment) _then;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? by = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
by: by == freezed
|
||||
? _value.by
|
||||
: by // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_IncrementCopyWith<$Res> implements $IncrementCopyWith<$Res> {
|
||||
factory _$$_IncrementCopyWith(
|
||||
_$_Increment value, $Res Function(_$_Increment) then) =
|
||||
__$$_IncrementCopyWithImpl<$Res>;
|
||||
@override
|
||||
$Res call({int by});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_IncrementCopyWithImpl<$Res> extends _$IncrementCopyWithImpl<$Res>
|
||||
implements _$$_IncrementCopyWith<$Res> {
|
||||
__$$_IncrementCopyWithImpl(
|
||||
_$_Increment _value, $Res Function(_$_Increment) _then)
|
||||
: super(_value, (v) => _then(v as _$_Increment));
|
||||
|
||||
@override
|
||||
_$_Increment get _value => super._value as _$_Increment;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? by = freezed,
|
||||
}) {
|
||||
return _then(_$_Increment(
|
||||
by: by == freezed
|
||||
? _value.by
|
||||
: by // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$_Increment implements _Increment {
|
||||
const _$_Increment({required this.by});
|
||||
|
||||
factory _$_Increment.fromJson(Map<String, dynamic> json) =>
|
||||
_$$_IncrementFromJson(json);
|
||||
|
||||
@override
|
||||
final int by;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Increment(by: $by)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_Increment &&
|
||||
const DeepCollectionEquality().equals(other.by, by));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(by));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
_$$_IncrementCopyWith<_$_Increment> get copyWith =>
|
||||
__$$_IncrementCopyWithImpl<_$_Increment>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$_IncrementToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Increment implements Increment {
|
||||
const factory _Increment({required final int by}) = _$_Increment;
|
||||
|
||||
factory _Increment.fromJson(Map<String, dynamic> json) =
|
||||
_$_Increment.fromJson;
|
||||
|
||||
@override
|
||||
int get by;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_IncrementCopyWith<_$_Increment> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
Count _$CountFromJson(Map<String, dynamic> json) {
|
||||
return _Count.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Count {
|
||||
int get value => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$CountCopyWith<Count> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $CountCopyWith<$Res> {
|
||||
factory $CountCopyWith(Count value, $Res Function(Count) then) =
|
||||
_$CountCopyWithImpl<$Res>;
|
||||
$Res call({int value});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$CountCopyWithImpl<$Res> implements $CountCopyWith<$Res> {
|
||||
_$CountCopyWithImpl(this._value, this._then);
|
||||
|
||||
final Count _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function(Count) _then;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? value = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
value: value == freezed
|
||||
? _value.value
|
||||
: value // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_CountCopyWith<$Res> implements $CountCopyWith<$Res> {
|
||||
factory _$$_CountCopyWith(_$_Count value, $Res Function(_$_Count) then) =
|
||||
__$$_CountCopyWithImpl<$Res>;
|
||||
@override
|
||||
$Res call({int value});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_CountCopyWithImpl<$Res> extends _$CountCopyWithImpl<$Res>
|
||||
implements _$$_CountCopyWith<$Res> {
|
||||
__$$_CountCopyWithImpl(_$_Count _value, $Res Function(_$_Count) _then)
|
||||
: super(_value, (v) => _then(v as _$_Count));
|
||||
|
||||
@override
|
||||
_$_Count get _value => super._value as _$_Count;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? value = freezed,
|
||||
}) {
|
||||
return _then(_$_Count(
|
||||
value == freezed
|
||||
? _value.value
|
||||
: value // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$_Count implements _Count {
|
||||
const _$_Count(this.value);
|
||||
|
||||
factory _$_Count.fromJson(Map<String, dynamic> json) =>
|
||||
_$$_CountFromJson(json);
|
||||
|
||||
@override
|
||||
final int value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Count(value: $value)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_Count &&
|
||||
const DeepCollectionEquality().equals(other.value, value));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(value));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
_$$_CountCopyWith<_$_Count> get copyWith =>
|
||||
__$$_CountCopyWithImpl<_$_Count>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$_CountToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Count implements Count {
|
||||
const factory _Count(final int value) = _$_Count;
|
||||
|
||||
factory _Count.fromJson(Map<String, dynamic> json) = _$_Count.fromJson;
|
||||
|
||||
@override
|
||||
int get value;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_CountCopyWith<_$_Count> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
24
code_sharing/server/shared/lib/src/models.g.dart
Normal file
24
code_sharing/server/shared/lib/src/models.g.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'models.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$_Increment _$$_IncrementFromJson(Map<String, dynamic> json) => _$_Increment(
|
||||
by: json['by'] as int,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$_IncrementToJson(_$_Increment instance) =>
|
||||
<String, dynamic>{
|
||||
'by': instance.by,
|
||||
};
|
||||
|
||||
_$_Count _$$_CountFromJson(Map<String, dynamic> json) => _$_Count(
|
||||
json['value'] as int,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$_CountToJson(_$_Count instance) => <String, dynamic>{
|
||||
'value': instance.value,
|
||||
};
|
||||
17
code_sharing/server/shared/pubspec.yaml
Normal file
17
code_sharing/server/shared/pubspec.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
name: shared
|
||||
description: Common data models required by our client and server
|
||||
version: 1.0.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.18.1 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
freezed_annotation: ^2.1.0
|
||||
json_annotation: ^4.7.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.2.1
|
||||
freezed: ^2.1.1
|
||||
json_serializable: ^6.4.0
|
||||
lints: ^2.0.0
|
||||
test: ^1.16.0
|
||||
17
code_sharing/server/shared/test/shared_test.dart
Normal file
17
code_sharing/server/shared/test/shared_test.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:shared/shared.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('Increment serialization', () {
|
||||
expect(Increment(by: 3).toJson(), <String, dynamic>{'by': 3});
|
||||
});
|
||||
test('Increment derialization', () {
|
||||
expect(Increment.fromJson(<String, dynamic>{'by': 5}), Increment(by: 5));
|
||||
});
|
||||
test('Count serialization', () {
|
||||
expect(Count(3).toJson(), <String, dynamic>{'value': 3});
|
||||
});
|
||||
test('Count derialization', () {
|
||||
expect(Count.fromJson(<String, dynamic>{'value': 5}), Count(5));
|
||||
});
|
||||
}
|
||||
40
code_sharing/server/test/server_test.dart
Normal file
40
code_sharing/server/test/server_test.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
// Manual test:
|
||||
// $ dart bin/server.dart
|
||||
// $ curl -X POST -d '{"by": 1}' -H "Content-Type: application/json" localhost:8080/
|
||||
|
||||
void main() {
|
||||
final port = '8080';
|
||||
final host = 'http://0.0.0.0:$port';
|
||||
late Process p;
|
||||
|
||||
setUp(() async {
|
||||
p = await Process.start(
|
||||
'dart',
|
||||
['run', 'bin/server.dart'],
|
||||
environment: {'PORT': port},
|
||||
);
|
||||
// Wait for server to start and print to stdout.
|
||||
await p.stdout.first;
|
||||
});
|
||||
|
||||
tearDown(() => p.kill());
|
||||
|
||||
test('Increment', () async {
|
||||
final response = await post(Uri.parse('$host/'), body: '{"by": 1}');
|
||||
expect(response.statusCode, 200);
|
||||
expect(response.body, '{"value":1}');
|
||||
});
|
||||
|
||||
test('Get', () async {
|
||||
final response = await get(Uri.parse('$host/'));
|
||||
expect(response.statusCode, 200);
|
||||
final resp = json.decode(response.body) as Map;
|
||||
expect(resp.containsKey('value'), true);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user