aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/core/end2end
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2017-04-18 13:39:18 -0700
committerGravatar Craig Tiller <ctiller@google.com>2017-04-18 13:39:18 -0700
commitcac4e178fda78564934c21ec2e77b5763dc3111a (patch)
tree175197d7ffac02cdc936e3844ace737103b6e928 /test/core/end2end
parent8b24229b7ca6b30b6c3eae64e20551386abc6ecb (diff)
parentc2d9f1e297b7a504412be85ec9840e59bfdb794e (diff)
Merge github.com:grpc/grpc into cpparena
Diffstat (limited to 'test/core/end2end')
-rw-r--r--test/core/end2end/BUILD79
-rw-r--r--test/core/end2end/fake_resolver.c211
-rw-r--r--test/core/end2end/fake_resolver.h34
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer.c3
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672bin0 -> 46 bytes
-rw-r--r--test/core/end2end/fuzzers/hpack.dictionary2
-rw-r--r--test/core/end2end/tests/load_reporting_hook.c22
7 files changed, 212 insertions, 139 deletions
diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD
index 0cef7aa01d..ffea1cc4e8 100644
--- a/test/core/end2end/BUILD
+++ b/test/core/end2end/BUILD
@@ -32,49 +32,66 @@ licenses(["notice"]) # 3-clause BSD
load(":generate_tests.bzl", "grpc_end2end_tests")
cc_library(
- name = 'cq_verifier',
- srcs = ['cq_verifier.c'],
- hdrs = ['cq_verifier.h'],
- deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util'],
- copts = ['-std=c99'],
- visibility = ["//test:__subpackages__"],
+ name = "cq_verifier",
+ srcs = ["cq_verifier.c"],
+ hdrs = ["cq_verifier.h"],
+ copts = ["-std=c99"],
+ visibility = ["//test:__subpackages__"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:grpc_test_util",
+ ],
)
cc_library(
- name = 'ssl_test_data',
- visibility = ["//test:__subpackages__"],
- hdrs = ['data/ssl_test_data.h'],
- copts = ['-std=c99'],
- srcs = [
- "data/client_certs.c",
- "data/server1_cert.c",
- "data/server1_key.c",
- "data/test_root_cert.c",
- ]
+ name = "ssl_test_data",
+ srcs = [
+ "data/client_certs.c",
+ "data/server1_cert.c",
+ "data/server1_key.c",
+ "data/test_root_cert.c",
+ ],
+ hdrs = ["data/ssl_test_data.h"],
+ copts = ["-std=c99"],
+ visibility = ["//test:__subpackages__"],
)
cc_library(
- name = 'fake_resolver',
- hdrs = ['fake_resolver.h'],
- srcs = ['fake_resolver.c'],
- copts = ['-std=c99'],
- deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+ name = "fake_resolver",
+ srcs = ["fake_resolver.c"],
+ hdrs = ["fake_resolver.h"],
+ copts = ["-std=c99"],
+ visibility = ["//test:__subpackages__"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:grpc_test_util",
+ ],
)
cc_library(
- name = 'http_proxy',
- hdrs = ['fixtures/http_proxy_fixture.h'],
- srcs = ['fixtures/http_proxy_fixture.c'],
- copts = ['-std=c99'],
- deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+ name = "http_proxy",
+ srcs = ["fixtures/http_proxy_fixture.c"],
+ hdrs = ["fixtures/http_proxy_fixture.h"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:grpc_test_util",
+ ],
)
cc_library(
- name = 'proxy',
- hdrs = ['fixtures/proxy.h'],
- srcs = ['fixtures/proxy.c'],
- copts = ['-std=c99'],
- deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+ name = "proxy",
+ srcs = ["fixtures/proxy.c"],
+ hdrs = ["fixtures/proxy.h"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:grpc_test_util",
+ ],
)
grpc_end2end_tests()
diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c
index 1c7dd1339c..6a71c20b80 100644
--- a/test/core/end2end/fake_resolver.c
+++ b/test/core/end2end/fake_resolver.c
@@ -32,6 +32,7 @@
// This is similar to the sockaddr resolver, except that it supports a
// bunch of query args that are useful for dependency injection in tests.
+#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -46,12 +47,18 @@
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
+#include "test/core/end2end/fake_resolver.h"
+
+#define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \
+ "grpc.fake_resolver.response_generator"
+
//
// fake_resolver
//
@@ -62,12 +69,11 @@ typedef struct {
// passed-in parameters
grpc_channel_args* channel_args;
- grpc_lb_addresses* addresses;
- // mutex guarding the rest of the state
- gpr_mu mu;
- // have we published?
- bool published;
+ // If not NULL, the next set of resolution results to be returned to
+ // grpc_resolver_next_locked()'s closure.
+ grpc_channel_args* next_results;
+
// pending next completion, or NULL
grpc_closure* next_completion;
// target result address for next completion
@@ -76,60 +82,137 @@ typedef struct {
static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) {
fake_resolver* r = (fake_resolver*)gr;
- gpr_mu_destroy(&r->mu);
+ grpc_channel_args_destroy(exec_ctx, r->next_results);
grpc_channel_args_destroy(exec_ctx, r->channel_args);
- grpc_lb_addresses_destroy(exec_ctx, r->addresses);
gpr_free(r);
}
-static void fake_resolver_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_resolver* resolver) {
+static void fake_resolver_shutdown_locked(grpc_exec_ctx* exec_ctx,
+ grpc_resolver* resolver) {
fake_resolver* r = (fake_resolver*)resolver;
- gpr_mu_lock(&r->mu);
if (r->next_completion != NULL) {
*r->target_result = NULL;
grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
r->next_completion = NULL;
}
- gpr_mu_unlock(&r->mu);
}
static void fake_resolver_maybe_finish_next_locked(grpc_exec_ctx* exec_ctx,
fake_resolver* r) {
- if (r->next_completion != NULL && !r->published) {
- r->published = true;
- grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses);
+ if (r->next_completion != NULL && r->next_results != NULL) {
*r->target_result =
- grpc_channel_args_copy_and_add(r->channel_args, &arg, 1);
+ grpc_channel_args_merge(r->channel_args, r->next_results);
+ grpc_channel_args_destroy(exec_ctx, r->next_results);
grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
r->next_completion = NULL;
+ r->next_results = NULL;
}
}
-static void fake_resolver_channel_saw_error(grpc_exec_ctx* exec_ctx,
- grpc_resolver* resolver) {
+static void fake_resolver_channel_saw_error_locked(grpc_exec_ctx* exec_ctx,
+ grpc_resolver* resolver) {
fake_resolver* r = (fake_resolver*)resolver;
- gpr_mu_lock(&r->mu);
- r->published = false;
fake_resolver_maybe_finish_next_locked(exec_ctx, r);
- gpr_mu_unlock(&r->mu);
}
-static void fake_resolver_next(grpc_exec_ctx* exec_ctx, grpc_resolver* resolver,
- grpc_channel_args** target_result,
- grpc_closure* on_complete) {
+static void fake_resolver_next_locked(grpc_exec_ctx* exec_ctx,
+ grpc_resolver* resolver,
+ grpc_channel_args** target_result,
+ grpc_closure* on_complete) {
fake_resolver* r = (fake_resolver*)resolver;
- gpr_mu_lock(&r->mu);
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_result = target_result;
fake_resolver_maybe_finish_next_locked(exec_ctx, r);
- gpr_mu_unlock(&r->mu);
}
static const grpc_resolver_vtable fake_resolver_vtable = {
- fake_resolver_destroy, fake_resolver_shutdown,
- fake_resolver_channel_saw_error, fake_resolver_next};
+ fake_resolver_destroy, fake_resolver_shutdown_locked,
+ fake_resolver_channel_saw_error_locked, fake_resolver_next_locked};
+
+struct grpc_fake_resolver_response_generator {
+ fake_resolver* resolver; // Set by the fake_resolver constructor to itself.
+ grpc_channel_args* next_response;
+ gpr_refcount refcount;
+};
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_create() {
+ grpc_fake_resolver_response_generator* generator =
+ gpr_zalloc(sizeof(*generator));
+ gpr_ref_init(&generator->refcount, 1);
+ return generator;
+}
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_ref(
+ grpc_fake_resolver_response_generator* generator) {
+ gpr_ref(&generator->refcount);
+ return generator;
+}
+
+void grpc_fake_resolver_response_generator_unref(
+ grpc_fake_resolver_response_generator* generator) {
+ if (gpr_unref(&generator->refcount)) {
+ gpr_free(generator);
+ }
+}
+
+static void set_response_cb(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ grpc_fake_resolver_response_generator* generator = arg;
+ fake_resolver* r = generator->resolver;
+ if (r->next_results != NULL) {
+ grpc_channel_args_destroy(exec_ctx, r->next_results);
+ }
+ r->next_results = generator->next_response;
+ fake_resolver_maybe_finish_next_locked(exec_ctx, r);
+}
+
+void grpc_fake_resolver_response_generator_set_response(
+ grpc_exec_ctx* exec_ctx, grpc_fake_resolver_response_generator* generator,
+ grpc_channel_args* next_response) {
+ GPR_ASSERT(generator->resolver != NULL);
+ generator->next_response = grpc_channel_args_copy(next_response);
+ grpc_closure_sched(
+ exec_ctx,
+ grpc_closure_create(
+ set_response_cb, generator,
+ grpc_combiner_scheduler(generator->resolver->base.combiner, false)),
+ GRPC_ERROR_NONE);
+}
+
+static void* response_generator_arg_copy(void* p) {
+ return grpc_fake_resolver_response_generator_ref(p);
+}
+
+static void response_generator_arg_destroy(grpc_exec_ctx* exec_ctx, void* p) {
+ grpc_fake_resolver_response_generator_unref(p);
+}
+
+static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
+
+static const grpc_arg_pointer_vtable response_generator_arg_vtable = {
+ response_generator_arg_copy, response_generator_arg_destroy,
+ response_generator_cmp};
+
+grpc_arg grpc_fake_resolver_response_generator_arg(
+ grpc_fake_resolver_response_generator* generator) {
+ grpc_arg arg;
+ arg.type = GRPC_ARG_POINTER;
+ arg.key = GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR;
+ arg.value.pointer.p = generator;
+ arg.value.pointer.vtable = &response_generator_arg_vtable;
+ return arg;
+}
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_get_response_generator(const grpc_channel_args* args) {
+ const grpc_arg* arg =
+ grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
+ if (arg == NULL || arg->type != GRPC_ARG_POINTER) return NULL;
+ return arg->value.pointer.p;
+}
//
// fake_resolver_factory
@@ -139,81 +222,15 @@ static void fake_resolver_factory_ref(grpc_resolver_factory* factory) {}
static void fake_resolver_factory_unref(grpc_resolver_factory* factory) {}
-static void do_nothing(void* ignored) {}
-
static grpc_resolver* fake_resolver_create(grpc_exec_ctx* exec_ctx,
grpc_resolver_factory* factory,
grpc_resolver_args* args) {
- if (0 != strcmp(args->uri->authority, "")) {
- gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
- args->uri->scheme);
- return NULL;
- }
- // Get lb_enabled arg. Anything other than "0" is interpreted as true.
- const char* lb_enabled_qpart =
- grpc_uri_get_query_arg(args->uri, "lb_enabled");
- const bool lb_enabled =
- lb_enabled_qpart != NULL && strcmp("0", lb_enabled_qpart) != 0;
-
- // Get the balancer's names.
- const char* balancer_names =
- grpc_uri_get_query_arg(args->uri, "balancer_names");
- grpc_slice_buffer balancer_names_parts;
- grpc_slice_buffer_init(&balancer_names_parts);
- if (balancer_names != NULL) {
- const grpc_slice balancer_names_slice =
- grpc_slice_from_copied_string(balancer_names);
- grpc_slice_split(balancer_names_slice, ",", &balancer_names_parts);
- grpc_slice_unref(balancer_names_slice);
- }
-
- // Construct addresses.
- grpc_slice path_slice =
- grpc_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
- grpc_slice_buffer path_parts;
- grpc_slice_buffer_init(&path_parts);
- grpc_slice_split(path_slice, ",", &path_parts);
- if (balancer_names_parts.count > 0 &&
- path_parts.count != balancer_names_parts.count) {
- gpr_log(GPR_ERROR,
- "Balancer names present but mismatched with number of addresses: "
- "%lu balancer names != %lu addresses",
- (unsigned long)balancer_names_parts.count,
- (unsigned long)path_parts.count);
- return NULL;
- }
- grpc_lb_addresses* addresses =
- grpc_lb_addresses_create(path_parts.count, NULL /* user_data_vtable */);
- bool errors_found = false;
- for (size_t i = 0; i < addresses->num_addresses; i++) {
- grpc_uri ith_uri = *args->uri;
- char* part_str = grpc_slice_to_c_string(path_parts.slices[i]);
- ith_uri.path = part_str;
- if (!parse_ipv4(&ith_uri, &addresses->addresses[i].address)) {
- errors_found = true;
- }
- gpr_free(part_str);
- if (errors_found) break;
- addresses->addresses[i].is_balancer = lb_enabled;
- addresses->addresses[i].balancer_name =
- balancer_names_parts.count > 0
- ? grpc_dump_slice(balancer_names_parts.slices[i], GPR_DUMP_ASCII)
- : NULL;
- }
- grpc_slice_buffer_destroy_internal(exec_ctx, &path_parts);
- grpc_slice_buffer_destroy_internal(exec_ctx, &balancer_names_parts);
- grpc_slice_unref(path_slice);
- if (errors_found) {
- grpc_lb_addresses_destroy(exec_ctx, addresses);
- return NULL;
- }
- // Instantiate resolver.
- fake_resolver* r = gpr_malloc(sizeof(fake_resolver));
- memset(r, 0, sizeof(*r));
+ fake_resolver* r = gpr_zalloc(sizeof(*r));
r->channel_args = grpc_channel_args_copy(args->args);
- r->addresses = addresses;
- gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &fake_resolver_vtable, args->combiner);
+ grpc_fake_resolver_response_generator* response_generator =
+ grpc_fake_resolver_get_response_generator(args->args);
+ if (response_generator != NULL) response_generator->resolver = r;
return &r->base;
}
diff --git a/test/core/end2end/fake_resolver.h b/test/core/end2end/fake_resolver.h
index 7a30347f30..447289adef 100644
--- a/test/core/end2end/fake_resolver.h
+++ b/test/core/end2end/fake_resolver.h
@@ -32,8 +32,42 @@
#ifndef GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H
#define GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/channel/channel_args.h"
+
#include "test/core/util/test_config.h"
void grpc_fake_resolver_init();
+// Instances of \a grpc_fake_resolver_response_generator are passed to the
+// fake resolver in a channel argument (see \a
+// grpc_fake_resolver_response_generator_arg) in order to inject and trigger
+// custom resolutions. See also \a
+// grpc_fake_resolver_response_generator_set_response.
+typedef struct grpc_fake_resolver_response_generator
+ grpc_fake_resolver_response_generator;
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_create();
+
+// Instruct the fake resolver associated with the \a response_generator instance
+// to trigger a new resolution for \a uri and \a args.
+void grpc_fake_resolver_response_generator_set_response(
+ grpc_exec_ctx* exec_ctx, grpc_fake_resolver_response_generator* generator,
+ grpc_channel_args* next_response);
+
+// Return a \a grpc_arg for a \a grpc_fake_resolver_response_generator instance.
+grpc_arg grpc_fake_resolver_response_generator_arg(
+ grpc_fake_resolver_response_generator* generator);
+// Return the \a grpc_fake_resolver_response_generator instance in \a args or
+// NULL.
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_get_response_generator(const grpc_channel_args* args);
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_ref(
+ grpc_fake_resolver_response_generator* generator);
+void grpc_fake_resolver_response_generator_unref(
+ grpc_fake_resolver_response_generator* generator);
+
#endif /* GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H */
diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index 7671609d3c..88a0e301da 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -932,6 +932,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
uint32_t propagation_mask = read_uint32(&inp);
grpc_slice method = read_string_like_slice(&inp);
+ if (GRPC_SLICE_LENGTH(method) == 0) {
+ ok = false;
+ }
grpc_slice host = read_string_like_slice(&inp);
gpr_timespec deadline =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672
new file mode 100644
index 0000000000..3fd5427b46
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672
Binary files differ
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index 4282c61214..2bb9de34c5 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -77,6 +77,7 @@
"\x08if-range"
"\x13if-unmodified-since"
"\x0Dlast-modified"
+"\x0Blb-cost-bin"
"\x04link"
"\x08location"
"\x0Cmax-forwards"
@@ -153,6 +154,7 @@
"\x00\x13if-unmodified-since\x00"
"\x00\x0Dlast-modified\x00"
"\x00\x08lb-token\x00"
+"\x00\x0Blb-cost-bin\x00"
"\x00\x04link\x00"
"\x00\x08location\x00"
"\x00\x0Cmax-forwards\x00"
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
index 15a69aa4d6..5f671405c2 100644
--- a/test/core/end2end/tests/load_reporting_hook.c
+++ b/test/core/end2end/tests/load_reporting_hook.c
@@ -129,8 +129,7 @@ static void end_test(grpc_end2end_test_fixture *f) {
static void request_response_with_payload(
grpc_end2end_test_config config, grpc_end2end_test_fixture f,
const char *method_name, const char *request_msg, const char *response_msg,
- grpc_metadata *initial_lr_metadata,
- grpc_load_reporting_cost_context *cost_ctx) {
+ grpc_metadata *initial_lr_metadata, grpc_metadata *trailing_lr_metadata) {
grpc_slice request_payload_slice = grpc_slice_from_static_string(request_msg);
grpc_slice response_payload_slice =
grpc_slice_from_static_string(response_msg);
@@ -243,8 +242,9 @@ static void request_response_with_payload(
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
- GPR_ASSERT(cost_ctx != NULL);
- grpc_call_set_load_reporting_cost_context(s, cost_ctx);
+ GPR_ASSERT(trailing_lr_metadata != NULL);
+ op->data.send_status_from_server.trailing_metadata_count = 1;
+ op->data.send_status_from_server.trailing_metadata = trailing_lr_metadata;
op->data.send_status_from_server.status = GRPC_STATUS_OK;
grpc_slice status_details = grpc_slice_from_static_string("xyz");
op->data.send_status_from_server.status_details = &status_details;
@@ -298,21 +298,21 @@ static void test_load_reporting_hook(grpc_end2end_test_config config) {
const char *response_msg = "... and the response from the server";
grpc_metadata initial_lr_metadata;
+ grpc_metadata trailing_lr_metadata;
initial_lr_metadata.key = GRPC_MDSTR_LB_TOKEN;
initial_lr_metadata.value = grpc_slice_from_static_string("client-token");
memset(&initial_lr_metadata.internal_data, 0,
sizeof(initial_lr_metadata.internal_data));
- grpc_load_reporting_cost_context *cost_ctx = gpr_malloc(sizeof(*cost_ctx));
- memset(cost_ctx, 0, sizeof(*cost_ctx));
- cost_ctx->values_count = 1;
- cost_ctx->values =
- gpr_malloc(sizeof(*cost_ctx->values) * cost_ctx->values_count);
- cost_ctx->values[0] = grpc_slice_from_static_string("cost-token");
+ trailing_lr_metadata.key = GRPC_MDSTR_LB_COST_BIN;
+ trailing_lr_metadata.value = grpc_slice_from_static_string("server-token");
+ memset(&trailing_lr_metadata.internal_data, 0,
+ sizeof(trailing_lr_metadata.internal_data));
request_response_with_payload(config, f, method_name, request_msg,
- response_msg, &initial_lr_metadata, cost_ctx);
+ response_msg, &initial_lr_metadata,
+ &trailing_lr_metadata);
end_test(&f);
{
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;