Skip to content

Add Proof of Concept(POC) for Collection Runner and Performance Load Testing Features #817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/models/collection_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'package:apidash_core/apidash_core.dart';



class Collection {
final String id;
final String name;
final List<String> requests;


Collection({
required this.id,
required this.name,
this.requests = const [],
});

// Creates a new Collection instance with specific properties changed while preserving all other existing values
Collection copyWith({
String? id,
String? name,
List<String>? requests,
}) {
return Collection(
id: id ?? this.id,
name: name ?? this.name,
requests: requests ?? this.requests,
);
}
}
2 changes: 2 additions & 0 deletions lib/models/models.dart
Original file line number Diff line number Diff line change
@@ -2,3 +2,5 @@ export 'history_meta_model.dart';
export 'history_request_model.dart';
export 'request_model.dart';
export 'settings_model.dart';
export 'collection_model.dart';

29 changes: 29 additions & 0 deletions lib/models/performance_test_result.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'package:json_annotation/json_annotation.dart';

part 'performance_test_result.g.dart';

@JsonSerializable()
class PerformanceTestResult {
final int totalRequests;
final double requestsPerSecond;
final double avgResponseTime;
final double minResponseTime;
final double maxResponseTime;
final double errorRate;
final DateTime timestamp;

PerformanceTestResult({
required this.totalRequests,
required this.requestsPerSecond,
required this.avgResponseTime,
required this.minResponseTime,
required this.maxResponseTime,
required this.errorRate,
required this.timestamp,
});

factory PerformanceTestResult.fromJson(Map<String, dynamic> json) =>
_$PerformanceTestResultFromJson(json);

Map<String, dynamic> toJson() => _$PerformanceTestResultToJson(this);
}
31 changes: 31 additions & 0 deletions lib/models/performance_test_result.g.dart

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

4 changes: 4 additions & 0 deletions lib/models/request_model.dart
Original file line number Diff line number Diff line change
@@ -27,3 +27,7 @@ class RequestModel with _$RequestModel {
factory RequestModel.fromJson(Map<String, Object?> json) =>
_$RequestModelFromJson(json);
}




38 changes: 38 additions & 0 deletions lib/providers/collection_feature_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:apidash_core/apidash_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:apidash/consts.dart';
import '../screens/home_page/collection_pane.dart';
import 'providers.dart';
import '../models/models.dart';
import '../services/services.dart' show hiveHandler, HiveHandler;
import '../utils/utils.dart'
show getNewUuid, collectionToHAR, substituteHttpRequestModel;



// Existing providers that should be defined elsewhere in the app
final collectionsProvider = StateNotifierProvider<CollectionsNotifier, List<Collection>>((ref) {
return CollectionsNotifier();
});

class CollectionsNotifier extends StateNotifier<List<Collection>> {
CollectionsNotifier() : super([]);

void updateCollection(Collection updatedCollection) {
final index = state.indexWhere((c) => c.id == updatedCollection.id);
if (index >= 0) {
final newList = List<Collection>.from(state);
newList[index] = updatedCollection;
state = newList;
}
}

void addCollection(Collection collection) {
state = [...state, collection];
}

void removeCollection(String id) {
state = state.where((collection) => collection.id != id).toList();
}
}
75 changes: 58 additions & 17 deletions lib/providers/collection_providers.dart
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import 'package:apidash_core/apidash_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:apidash/consts.dart';
import '../screens/home_page/collection_pane.dart';
import 'providers.dart';
import '../models/models.dart';
import '../services/services.dart' show hiveHandler, HiveHandler;
@@ -10,6 +11,12 @@ import '../utils/utils.dart'

final selectedIdStateProvider = StateProvider<String?>((ref) => null);

final selectedCollectionIdProvider = StateProvider<String?>((ref) => null);
final filteredCollectionsProvider = Provider<List<Collection>>((ref) {
return ref.watch(collectionsProvider);
});


final selectedRequestModelProvider = StateProvider<RequestModel?>((ref) {
final selectedId = ref.watch(selectedIdStateProvider);
final collection = ref.watch(collectionStateNotifierProvider);
@@ -26,18 +33,48 @@ final requestSequenceProvider = StateProvider<List<String>>((ref) {
});

final StateNotifierProvider<CollectionStateNotifier, Map<String, RequestModel>?>
collectionStateNotifierProvider =
StateNotifierProvider((ref) => CollectionStateNotifier(
ref,
hiveHandler,
));
collectionStateNotifierProvider =
StateNotifierProvider((ref) => CollectionStateNotifier(
ref,
hiveHandler,
));

// this provider listens for changes in collection state and request sequence
final collectionRequestSyncProvider = Provider<void>((ref) {
final selectedCollectionId = ref.watch(selectedCollectionIdProvider);
final requestSequence = ref.watch(requestSequenceProvider);

// Only proceed if a collection is selected
if (selectedCollectionId != null && requestSequence.isNotEmpty) {
ref.listen(collectionStateNotifierProvider, (previous, current) {
if (previous != current) {
// Get the current collection
final collections = ref.read(collectionsProvider);
final collectionIndex = collections.indexWhere((c) => c.id == selectedCollectionId);

if (collectionIndex >= 0) {
// Update the collection with the current request sequence
// requestSequence is already List<String>, which matches what Collection.requests expects
final updatedCollection = collections[collectionIndex].copyWith(
requests: requestSequence
);

// Update the collection in the provider
ref.read(collectionsProvider.notifier).updateCollection(updatedCollection);
}
}
});
}
return null;
});


class CollectionStateNotifier
extends StateNotifier<Map<String, RequestModel>?> {
CollectionStateNotifier(
this.ref,
this.hiveHandler,
) : super(null) {
this.ref,
this.hiveHandler,
) : super(null) {
var status = loadData();
Future.microtask(() {
if (status) {
@@ -46,7 +83,7 @@ class CollectionStateNotifier
];
}
ref.read(selectedIdStateProvider.notifier).state =
ref.read(requestSequenceProvider)[0];
ref.read(requestSequenceProvider)[0];
});
}

@@ -78,12 +115,14 @@ class CollectionStateNotifier
.update((state) => [id, ...state]);
ref.read(selectedIdStateProvider.notifier).state = newRequestModel.id;
unsave();


}

void addRequestModel(
HttpRequestModel httpRequestModel, {
String? name,
}) {
HttpRequestModel httpRequestModel, {
String? name,
}) {
final id = getNewUuid();
final newRequestModel = RequestModel(
id: id,
@@ -204,6 +243,8 @@ class CollectionStateNotifier
unsave();
}



void update({
String? id,
HTTPVerb? method,
@@ -242,11 +283,11 @@ class CollectionStateNotifier
headers: headers ?? currentHttpRequestModel.headers,
params: params ?? currentHttpRequestModel.params,
isHeaderEnabledList:
isHeaderEnabledList ?? currentHttpRequestModel.isHeaderEnabledList,
isHeaderEnabledList ?? currentHttpRequestModel.isHeaderEnabledList,
isParamEnabledList:
isParamEnabledList ?? currentHttpRequestModel.isParamEnabledList,
isParamEnabledList ?? currentHttpRequestModel.isParamEnabledList,
bodyContentType:
bodyContentType ?? currentHttpRequestModel.bodyContentType,
bodyContentType ?? currentHttpRequestModel.bodyContentType,
body: body ?? currentHttpRequestModel.body,
query: query ?? currentHttpRequestModel.query,
formData: formData ?? currentHttpRequestModel.formData,
@@ -278,7 +319,7 @@ class CollectionStateNotifier

APIType apiType = requestModel!.apiType;
HttpRequestModel substitutedHttpRequestModel =
getSubstitutedHttpRequestModel(requestModel.httpRequestModel!);
getSubstitutedHttpRequestModel(requestModel.httpRequestModel!);

// set current model's isWorking to true and update state
var map = {...state!};
@@ -427,4 +468,4 @@ class CollectionStateNotifier
activeEnvId,
);
}
}
}
Loading