Package cn.edu.zju.acm.onlinejudge.judgeservice

Source Code of cn.edu.zju.acm.onlinejudge.judgeservice.JudgingQueueUnitTest

/*
* Copyright 2007 Xu, Chuan <xuchuan@gmail.com>
*
* This file is part of ZOJ.
*
* ZOJ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either revision 3 of the License, or (at your option) any later revision.
*
* ZOJ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with ZOJ. if not, see
* <http://www.gnu.org/licenses/>.
*/

package cn.edu.zju.acm.onlinejudge.judgeservice;

import static org.hamcrest.core.IsNull.*;
import static org.hamcrest.core.Is.*;
import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

import cn.edu.zju.acm.onlinejudge.bean.Submission;

public class JudgingQueueUnitTest {
    private JudgingQueue queue;
    private Submission[] submissions;

    @Before
    public void setUp() {
        this.queue = new JudgingQueue();
        this.submissions = new Submission[10];
        for (int i = 0; i < this.submissions.length; ++i) {
            this.submissions[i] = new Submission();
            this.submissions[i].setId(i);
        }
    }

    @Test
    public void testEmptyQueue() {
        JudgingQueueIterator iter = this.queue.iterator();
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testPush() {
        this.queue.push(this.submissions[0]);
        JudgingQueueIterator iter = this.queue.iterator();
        assertThat(iter.next(), is(this.submissions[0]));
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testIteratorBeforePush() {
        JudgingQueueIterator iter = this.queue.iterator();
        this.queue.push(this.submissions[0]);
        assertThat(iter.next(), is(this.submissions[0]));
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testMultiplePush() {
        this.queue.push(this.submissions[0]);
        this.queue.push(this.submissions[1]);
        JudgingQueueIterator iter = this.queue.iterator();
        assertThat(iter.next(), is(this.submissions[0]));
        this.queue.push(this.submissions[2]);
        assertThat(iter.next(), is(this.submissions[1]));
        assertThat(iter.next(), is(this.submissions[2]));
        this.queue.push(this.submissions[3]);
        assertThat(iter.next(), is(this.submissions[3]));
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testRemoveBeforeIterator() {
        this.queue.push(this.submissions[0]);
        this.queue.remove(this.submissions[0]);
        JudgingQueueIterator iter = this.queue.iterator();
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testRemoveAfterIterator() {
        this.queue.push(this.submissions[0]);
        JudgingQueueIterator iter = this.queue.iterator();
        this.queue.remove(this.submissions[0]);
        assertThat(iter.next(), is(this.submissions[0]));
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testRemoveNotExisting() {
        this.queue.push(this.submissions[0]);
        this.queue.remove(this.submissions[1]);
        JudgingQueueIterator iter = this.queue.iterator();
        assertThat(iter.next(), is(this.submissions[0]));
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testMultipleIterator() {
        this.queue.push(this.submissions[0]);
        this.queue.push(this.submissions[1]);

        JudgingQueueIterator iter = this.queue.iterator();

        assertThat(iter.next(), is(this.submissions[0]));

        this.queue.push(this.submissions[2]);

        assertThat(iter.next(), is(this.submissions[1]));
        assertThat(iter.next(), is(this.submissions[2]));
        assertThat(iter.next(), nullValue());

        iter = this.queue.iterator();

        assertThat(iter.next(), is(this.submissions[0]));
        assertThat(iter.next(), is(this.submissions[1]));
        assertThat(iter.next(), is(this.submissions[2]));
        assertThat(iter.next(), nullValue());
    }

    @Test
    public void testMix() {
        this.queue.push(this.submissions[0]);
        this.queue.push(this.submissions[1]);

        JudgingQueueIterator iter1 = this.queue.iterator();

        assertThat(iter1.next(), is(this.submissions[0]));

        this.queue.remove(this.submissions[1]);

        JudgingQueueIterator iter2 = this.queue.iterator();

        this.queue.push(this.submissions[2]);

        assertThat(iter1.next(), is(this.submissions[1]));
        assertThat(iter2.next(), is(this.submissions[0]));
        assertThat(iter2.next(), is(this.submissions[1]));

        this.queue.remove(this.submissions[0]);

        JudgingQueueIterator iter3 = this.queue.iterator();

        assertThat(iter1.next(), is(this.submissions[2]));
        assertThat(iter2.next(), is(this.submissions[2]));
        assertThat(iter3.next(), is(this.submissions[2]));

        this.queue.push(this.submissions[3]);

        assertThat(iter1.next(), is(this.submissions[3]));
        assertThat(iter2.next(), is(this.submissions[3]));
        assertThat(iter3.next(), is(this.submissions[3]));
        assertThat(iter1.next(), nullValue());
        assertThat(iter2.next(), nullValue());
        assertThat(iter3.next(), nullValue());
    }

    /**
     * This test works in this way: We first save a global iterator, then create a set of judge threads which add and
     * remove submissions and another set of check threads which get iterators from the queue. We finally assert that
     * every submission sequence seen by a check thread is a sub-sequence of that returned by the global iterator saved
     * before. In order to be efficient, we do not save all submission sequence seen by check threads. Instead, we save the
     * hash code of submission ids, the first submission id and total number of submissions in the sequence.
     */
    @Test
    public void testMultipleThreads() {
        JudgingQueueIterator allIter = queue.iterator();
        final Thread[] judge = new Thread[50];
        final int maxIdPerJudgeThread = 1000;
        for (int i = 0; i < judge.length; ++i) {
            final int id = i;
            judge[i] = new Thread() {
                public void run() {
                    for (int i = 0; i < maxIdPerJudgeThread; ++i) {
                        Submission submission = new Submission();
                        submission.setId(id * maxIdPerJudgeThread + i);
                        queue.push(submission);
                        Thread.yield();
                        queue.remove(submission);
                    }
                }
            };
            judge[i].start();
        }
        Thread[] check = new Thread[100];
        final long[] start = new long[check.length];
        final int[] len = new int[check.length];
        final long[] hash = new long[check.length];
        for (int i = 0; i < check.length; ++i) {
            final int id = i;
            check[i] = new Thread() {
                public void run() {
                    hash[id] = len[id] = 0;
                    JudgingQueueIterator iter = queue.iterator();
                    for (int i = 0; i < 100; ++i) {
                        Submission submission = iter.next();
                        if (submission != null) {
                            start[id] = hash[id] = submission.getId();
                            break;
                        }
                        Thread.yield();
                    }
                    if (len[id] > 0) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {}
                        for (Submission submission = iter.next(); submission != null; submission = iter.next()) {
                            ++len[id];
                            hash[id] = hash[id] * 31 + submission.getId();
                        }
                    }
                }
            };
            check[i].start();
        }
        for (int i = 0; i < judge.length; ++i) {
            try {
                judge[i].join();
            } catch (InterruptedException e) {}
        }
        for (int i = 0; i < check.length; ++i) {
            try {
                check[i].join();
            } catch (InterruptedException e) {}
        }
        List<Long> h = new ArrayList<Long>();
        List<Long> base = new ArrayList<Long>();
        Map<Long, Integer> m = new HashMap<Long, Integer>();
        long[] last = new long[judge.length];
        for (int i = 0; i < last.length; ++i) {
            last[i] = -1;
        }
        h.add(0L);
        base.add(1L);
        for (Submission submission = allIter.next(); submission != null; submission = allIter.next()) {
            long id = submission.getId();
            m.put(id, h.size());
            h.add(h.get(h.size() - 1) * 31 + id);
            base.add(base.get(base.size() - 1) * 31);
            int a = (int) (id / maxIdPerJudgeThread);
            long b = id % maxIdPerJudgeThread;
            if (last[a] < 0) {
                last[a] = b;
            } else {
                assertThat(b, is(last[a] + 1));
                last[a] = b;
            }
        }
        for (int i = 0; i < check.length; ++i) {
            if (len[i] > 0) {
                int s = m.get(start[i]);
                assertThat(hash[i], is(h.get(s + len[i] - 1) - h.get(s - 1) * base.get(len[i])));
            }
        }
    }
}
TOP

Related Classes of cn.edu.zju.acm.onlinejudge.judgeservice.JudgingQueueUnitTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.