docs: mark Phase 6 complete in phase6-scheduler-integration-plan
This commit is contained in:
parent
9b0e9571d1
commit
177cf45af5
17 changed files with 4226 additions and 361 deletions
|
|
@ -22,6 +22,7 @@ extern void test_xlist(void);
|
|||
extern void test_limit(void);
|
||||
extern void test_xvec(void);
|
||||
extern void test_resreq(void);
|
||||
extern void test_select(void);
|
||||
extern void test_bitset(void);
|
||||
extern void test_kv(void);
|
||||
extern void test_jobobj(void);
|
||||
|
|
@ -119,6 +120,7 @@ int main(int argc, char* argv[])
|
|||
TEST(test_limit);
|
||||
TEST(test_xvec);
|
||||
TEST(test_resreq);
|
||||
TEST(test_select);
|
||||
TEST(test_bitset);
|
||||
TEST(test_kv);
|
||||
TEST(test_jobobj);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,35 @@ void test_parse_section_fail(void)
|
|||
FREEUP(errmsg);
|
||||
}
|
||||
|
||||
void test_parse_section3(void)
|
||||
{
|
||||
char* resreq = "type == any span[ptile=1]";
|
||||
char* errmsg = NULL;
|
||||
int rc = 0;
|
||||
xce_resreq_data_t data;
|
||||
|
||||
rc = parse_section(&data, (char*)resreq, &errmsg);
|
||||
if (rc < 0) {
|
||||
if (errmsg != NULL) {
|
||||
printf("%s", errmsg);
|
||||
FREEUP(errmsg);
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
TEST_ASSERT_TRUE(data.selectString != NULL);
|
||||
TEST_ASSERT_TRUE((data.rusageString == NULL) && (data.spanString != NULL)
|
||||
&& (data.sameString == NULL)
|
||||
&& (data.affinityString == NULL));
|
||||
TEST_ASSERT_TRUE(errmsg == NULL);
|
||||
|
||||
printf("select: %s\n", data.selectString);
|
||||
printf("span: %s\n", data.spanString);
|
||||
|
||||
FREEUP(data.selectString);
|
||||
FREEUP(data.spanString);
|
||||
}
|
||||
|
||||
|
||||
void test_parse_rusage1(void)
|
||||
{
|
||||
char* rusageString
|
||||
|
|
@ -173,7 +202,7 @@ void test_resreq_primary(void)
|
|||
int rc = 0;
|
||||
xce_primary_resreq_t resreq;
|
||||
|
||||
rc = parse_resreq_primary(&resreq, resreqString, &errmsg);
|
||||
rc = parse_resreq_primary(&resreq, resreqString, NULL, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
if (rc >= 0) {
|
||||
int i;
|
||||
|
|
@ -220,7 +249,7 @@ void test_resreq_primary2(void)
|
|||
int rc = 0;
|
||||
xce_primary_resreq_t resreq;
|
||||
|
||||
rc = parse_resreq_primary(&resreq, resreqString, &errmsg);
|
||||
rc = parse_resreq_primary(&resreq, resreqString, NULL, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
if (rc >= 0) {
|
||||
int i;
|
||||
|
|
@ -241,7 +270,7 @@ void test_resreq1(void)
|
|||
int rc = 0;
|
||||
xce_resreq_t resreq;
|
||||
|
||||
rc = parse_resreq(&resreq, resreqString, &errmsg);
|
||||
rc = parse_resreq(&resreq, resreqString, NULL, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
if (rc >= 0) {
|
||||
int i;
|
||||
|
|
@ -298,7 +327,7 @@ void test_resreq2(void)
|
|||
|
||||
memset(&resreq, 0x0, sizeof(resreq));
|
||||
|
||||
rc = parse_resreq(&resreq, resreqString, &errmsg);
|
||||
rc = parse_resreq(&resreq, resreqString, NULL, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
if (rc >= 0) {
|
||||
char* buf = NULL;
|
||||
|
|
@ -327,7 +356,7 @@ void test_resreq3(void)
|
|||
|
||||
memset(&resreq, 0x0, sizeof(resreq));
|
||||
|
||||
rc = parse_resreq(&resreq, resreqString, &errmsg);
|
||||
rc = parse_resreq(&resreq, resreqString, NULL, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
if (rc >= 0) {
|
||||
char* buf = NULL;
|
||||
|
|
@ -347,6 +376,111 @@ void test_resreq3(void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Boundary tests for the P0-2 span-bleed fix in section.peg.
|
||||
*
|
||||
* Before the fix line 50 read: !("span[]" / "]")
|
||||
* After the fix line 50 reads: !("span[" / "]")
|
||||
*
|
||||
* With the old grammar the negative lookahead would only suppress
|
||||
* consumption of the literal token "span[]", so any span clause
|
||||
* with content (e.g. "span[ptile=1]") was silently absorbed into
|
||||
* selectString. These tests verify the corrected boundary.
|
||||
*/
|
||||
|
||||
/* Test 1: explicit select[...] with a non-empty span[...] clause. */
|
||||
void test_parse_section_explicit_select_with_span(void)
|
||||
{
|
||||
char* resreq = "select[type==linux] span[ptile=1]";
|
||||
char* errmsg = NULL;
|
||||
int rc = 0;
|
||||
xce_resreq_data_t data = {0};
|
||||
|
||||
rc = parse_section(&data, (char*)resreq, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
printf("select: %s\n", data.selectString ? data.selectString : "(null)");
|
||||
printf("span: %s\n", data.spanString ? data.spanString : "(null)");
|
||||
|
||||
/* select must contain the predicate, not bleed into the span keyword */
|
||||
TEST_ASSERT_TRUE(data.selectString != NULL);
|
||||
TEST_ASSERT_TRUE(strstr(data.selectString, "type==linux") != NULL);
|
||||
|
||||
/* span must be parsed separately and hold only its content */
|
||||
TEST_ASSERT_TRUE(data.spanString != NULL);
|
||||
TEST_ASSERT_TRUE(strstr(data.spanString, "ptile=1") != NULL);
|
||||
|
||||
/* unrelated clauses must be absent */
|
||||
TEST_ASSERT_TRUE(data.rusageString == NULL);
|
||||
TEST_ASSERT_TRUE(data.sameString == NULL);
|
||||
TEST_ASSERT_TRUE(data.affinityString == NULL);
|
||||
|
||||
FREEUP(data.selectString);
|
||||
FREEUP(data.spanString);
|
||||
FREEUP(errmsg);
|
||||
}
|
||||
|
||||
/* Test 2: all three major clauses — select, rusage, span — in one string. */
|
||||
void test_parse_section_explicit_select_rusage_span(void)
|
||||
{
|
||||
char* resreq = "select[a&&b] rusage[mem=100] span[ptile=2]";
|
||||
char* errmsg = NULL;
|
||||
int rc = 0;
|
||||
xce_resreq_data_t data = {0};
|
||||
|
||||
rc = parse_section(&data, (char*)resreq, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
printf("select: %s\n", data.selectString ? data.selectString : "(null)");
|
||||
printf("rusage: %s\n", data.rusageString ? data.rusageString : "(null)");
|
||||
printf("span: %s\n", data.spanString ? data.spanString : "(null)");
|
||||
|
||||
TEST_ASSERT_TRUE(data.selectString != NULL);
|
||||
TEST_ASSERT_TRUE(strstr(data.selectString, "a&&b") != NULL);
|
||||
|
||||
TEST_ASSERT_TRUE(data.rusageString != NULL);
|
||||
TEST_ASSERT_TRUE(strstr(data.rusageString, "mem=100") != NULL);
|
||||
|
||||
TEST_ASSERT_TRUE(data.spanString != NULL);
|
||||
TEST_ASSERT_TRUE(strstr(data.spanString, "ptile=2") != NULL);
|
||||
|
||||
FREEUP(data.selectString);
|
||||
FREEUP(data.rusageString);
|
||||
FREEUP(data.spanString);
|
||||
FREEUP(errmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test 3: the core regression guard — selectString must NOT contain the
|
||||
* substring "span" when a span clause is present. With the old buggy
|
||||
* grammar the span clause text would bleed into selectString.
|
||||
*/
|
||||
void test_parse_section_span_not_in_select(void)
|
||||
{
|
||||
char* resreq = "select[gpu] span[ptile=4]";
|
||||
char* errmsg = NULL;
|
||||
int rc = 0;
|
||||
xce_resreq_data_t data = {0};
|
||||
|
||||
rc = parse_section(&data, (char*)resreq, &errmsg);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
printf("select: %s\n", data.selectString ? data.selectString : "(null)");
|
||||
printf("span: %s\n", data.spanString ? data.spanString : "(null)");
|
||||
|
||||
/* selectString must not contain the span keyword (bleed check) */
|
||||
TEST_ASSERT_TRUE(data.selectString != NULL);
|
||||
TEST_ASSERT_TRUE(strstr(data.selectString, "span") == NULL);
|
||||
|
||||
/* span content must be correctly isolated */
|
||||
TEST_ASSERT_TRUE(data.spanString != NULL);
|
||||
TEST_ASSERT_TRUE(strstr(data.spanString, "ptile=4") != NULL);
|
||||
|
||||
FREEUP(data.selectString);
|
||||
FREEUP(data.spanString);
|
||||
FREEUP(errmsg);
|
||||
}
|
||||
|
||||
void test_resreq(void)
|
||||
{
|
||||
printf("\n>> resreq test\n\n");
|
||||
|
|
@ -354,6 +488,7 @@ void test_resreq(void)
|
|||
RUN_TEST(test_parse_section1);
|
||||
RUN_TEST(test_parse_section2);
|
||||
RUN_TEST(test_parse_section_fail);
|
||||
RUN_TEST(test_parse_section3);
|
||||
RUN_TEST(test_parse_rusage1);
|
||||
RUN_TEST(test_parse_rusage2);
|
||||
RUN_TEST(test_resreq_primary);
|
||||
|
|
@ -361,4 +496,7 @@ void test_resreq(void)
|
|||
RUN_TEST(test_resreq1);
|
||||
RUN_TEST(test_resreq2);
|
||||
RUN_TEST(test_resreq3);
|
||||
RUN_TEST(test_parse_section_explicit_select_with_span);
|
||||
RUN_TEST(test_parse_section_explicit_select_rusage_span);
|
||||
RUN_TEST(test_parse_section_span_not_in_select);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
@ -6,6 +7,147 @@
|
|||
#include "utils.h"
|
||||
#include "xstring.h"
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Concurrent-test helpers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
#define NTHREADS (8)
|
||||
|
||||
/* Thread argument for the same-key test */
|
||||
typedef struct {
|
||||
const char* key;
|
||||
char* result;
|
||||
} same_key_arg_t;
|
||||
|
||||
static void* thread_make_same_key(void* arg)
|
||||
{
|
||||
same_key_arg_t* a = (same_key_arg_t*)arg;
|
||||
a->result = makeString((char*)a->key);
|
||||
return a->result;
|
||||
}
|
||||
|
||||
/* Thread argument for the distinct-key test */
|
||||
typedef struct {
|
||||
char key[16];
|
||||
char* result;
|
||||
} distinct_key_arg_t;
|
||||
|
||||
static void* thread_make_distinct_key(void* arg)
|
||||
{
|
||||
distinct_key_arg_t* a = (distinct_key_arg_t*)arg;
|
||||
a->result = makeString(a->key);
|
||||
return a->result;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Concurrent tests */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/*
|
||||
* test_xstring_concurrent_same_key
|
||||
*
|
||||
* Spawn NTHREADS threads, each racing to intern the same key.
|
||||
* With the TOCTOU fix the lock is held from key_find through key_add,
|
||||
* so every thread must receive the identical interned pointer.
|
||||
* Without the fix, two threads could both miss key_find, both call
|
||||
* makeInstance, and one would leak — and the pointers would differ.
|
||||
*/
|
||||
static void test_xstring_concurrent_same_key(void)
|
||||
{
|
||||
pthread_t tids[NTHREADS];
|
||||
same_key_arg_t args[NTHREADS];
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
rc = xstring_table_init(139);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
args[i].key = "concurrent_key";
|
||||
args[i].result = NULL;
|
||||
rc = pthread_create(&tids[i], NULL, thread_make_same_key, &args[i]);
|
||||
TEST_ASSERT_TRUE(rc == 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
void* retval = NULL;
|
||||
rc = pthread_join(tids[i], &retval);
|
||||
TEST_ASSERT_TRUE(rc == 0);
|
||||
}
|
||||
|
||||
/* All threads must have received a non-NULL pointer */
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
TEST_ASSERT_TRUE(args[i].result != NULL);
|
||||
}
|
||||
|
||||
/* All pointers must be the same interned object */
|
||||
for (i = 1; i < NTHREADS; i++) {
|
||||
TEST_ASSERT_EQUAL_PTR(args[0].result, args[i].result);
|
||||
}
|
||||
|
||||
/*
|
||||
* makeString increments the refcount on a cache hit. Each thread
|
||||
* got one reference; drop NTHREADS - 1 extras so xstring_table_fini
|
||||
* can release the final one cleanly.
|
||||
*/
|
||||
for (i = 1; i < NTHREADS; i++) {
|
||||
dereference((var)args[i].result);
|
||||
}
|
||||
|
||||
xstring_table_fini();
|
||||
}
|
||||
|
||||
/*
|
||||
* test_xstring_concurrent_distinct_keys
|
||||
*
|
||||
* Spawn NTHREADS threads, each interning a unique key.
|
||||
* Every returned pointer must be non-NULL and distinct from all others,
|
||||
* confirming that concurrent inserts of different keys do not collide.
|
||||
*/
|
||||
static void test_xstring_concurrent_distinct_keys(void)
|
||||
{
|
||||
pthread_t tids[NTHREADS];
|
||||
distinct_key_arg_t args[NTHREADS];
|
||||
int rc;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
rc = xstring_table_init(139);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
snprintf(args[i].key, sizeof(args[i].key), "key_%d", i);
|
||||
args[i].result = NULL;
|
||||
rc = pthread_create(&tids[i], NULL, thread_make_distinct_key, &args[i]);
|
||||
TEST_ASSERT_TRUE(rc == 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
void* retval = NULL;
|
||||
rc = pthread_join(tids[i], &retval);
|
||||
TEST_ASSERT_TRUE(rc == 0);
|
||||
}
|
||||
|
||||
/* Every pointer must be non-NULL */
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
TEST_ASSERT_TRUE(args[i].result != NULL);
|
||||
}
|
||||
|
||||
/* Every pointer must be distinct from all others */
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
for (j = i + 1; j < NTHREADS; j++) {
|
||||
TEST_ASSERT_NOT_EQUAL(args[i].result, args[j].result);
|
||||
}
|
||||
}
|
||||
|
||||
/* Release each thread's reference */
|
||||
for (i = 0; i < NTHREADS; i++) {
|
||||
dereference((var)args[i].result);
|
||||
}
|
||||
|
||||
xstring_table_fini();
|
||||
}
|
||||
|
||||
static void test_xstring_create(void)
|
||||
{
|
||||
char* s = "Hello, world";
|
||||
|
|
@ -76,6 +218,8 @@ void test_xstrings(void)
|
|||
RUN_TEST(test_xstring_create);
|
||||
RUN_TEST(test_xstring_deref);
|
||||
RUN_TEST(test_xstring_share);
|
||||
RUN_TEST(test_xstring_concurrent_same_key);
|
||||
RUN_TEST(test_xstring_concurrent_distinct_keys);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue