zoukankan      html  css  js  c++  java
  • 白板点阵数据传输测试初探

    近期公司上线了一个功能,就是在虚拟教室中添加了一个白板的展示框,此白板可以由老师通过配套的笔(硬件)进行绘制图形,有一些简单的功能,学生可以同步白板信息,也可以在老师授权的情况下进行绘制。

    答题需求就是这些,技术上的细节整理如下:

    白板传输接口文档

    这个文档是本人自己整理的,主要讲清楚白板数据传输接口的测试脚本实现过程遇到的问题。

    接口逻辑

    • 用户登录,获取token
    • 使用用户token和个人信息连接Socket
    • 使用token和个人信息注册连接
    • 加入某个房间(roomId)
    • 发送Socket消息(白板消息,后面介绍)

    数据来源

    白板原始数据为点坐标,通过SDK(自研)进行数据的处理,得到二进制数据,再通过base64转码成字符串。长度约为几十。

    业务处理

    共有三种不同的请求消息结构,分别为

    • 落笔
    • 移动
    • 起笔

    每次发送数据量为5个坐标点,发送数据中有UUID格式的笔画ID,用户ID(字符格式)。在落笔消息中需要添加颜色数据(10进制数字,来源为RGB颜色转成10进制即可)

    起笔和落笔可不足5个坐标点。

    坐标分布

    pad正常放置桌面(横向),白板左上角为原点(0,0),右下方坐标为(1200,760),全部在第一象限。

    测试方案

    首先我用了一个point的类用于报错某一个点的坐标信息,颜色信息在起笔过程中传输。

    package com.okayqa.board.base;
    
    public class Point {
    
        public short x;         // 将此值除以 10 才是点的 x 坐标
    
        public short y;         // 将此值除以 10 才是点的 x 坐标
    
        public short width;     // 将此值除以 100 才是点的宽度
    
        private Point(int x, int y, int width) {
            this.x = (short) (x * 10);
            this.y = (short) (y * 10);
            this.width = (short) (width * 100);
        }
    
        private Point(int x, int y) {
            this(x, y, 3);
        }
    
        public static Point getPoint(int x, int y) {
            if (x < 0 || x > 1199 || y < 0 || y > 760) return new Point(1, 1);
            return new Point(x, y);
        }
    
        public static Point getPoint(int x, int y, int width) {
            if (x < 0 || x > 1199 || y < 0 || y > 760) return new Point(1, 1, width);
            return new Point(x, y, width);
        }
    
    
        /**
         * 偏移方法
         *
         * @param offsetX 实际坐标点偏移量 x
         * @param offsetY 实际坐标点偏移量 y
         * @return
         */
        public Point move(int offsetX, int offsetY) {
            return getPoint(this.x / 10 + offsetX * 10, this.y / 10 + offsetY * 10);
        }
    
        @Override
        public String toString() {
            return "Point{ " + x + ", " + y + '}';
        }
    
    
    }
    
    

    然后用了一个BoardBase类封装了一些基础方法,主要是生成一些BoardUser中使用的静态方法,获取UUID和设定的几种图形的点集合。

    MessageHandler类是SDK自带的,这里继承一下只是为了方便调用其方法。

    package com.okayqa.board.base;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.UUID;
    
    import static com.okayqa.board.base.Point.getPoint;
    
    /**
     * 白板测试:wiki:http://rap2.ailearn.ink/repository/editor?id=30&mod=69&itf=187
     */
    public class BoardBase extends MessageHandler {
    
        private static Logger logger = LoggerFactory.getLogger(BoardBase.class);
    
        public static List<Point> getFive(int x, int y) {
            if (x < 0 || x > 1199 || y < 0 || y > 760) return getFive(0, 0);
            List<Point> ps = new ArrayList<>();
            ps.add(getPoint(x, y));
            ps.add(getPoint(x + 1, y));
            ps.add(getPoint(x + 1, y + 1));
            ps.add(getPoint(x + 2, y + 1));
            ps.add(getPoint(x + 2, y + 2));
            return ps;
        }
    
    
        /**
         * 获取一个UUID的strokeID
         *
         * @return
         */
        public static String getStrokeId() {
            String s = DEFAULT_STRING + UUID.randomUUID().toString();
            logger.info("生成了笔画ID: {}", s);
            return s;
        }
    
        /**
         * 获取随机颜色值
         *
         * @return
         */
        public static int getColor() {
            return getRandomInt(16777215);
        }
    
        /**
         * 画一个方形
         *
         * @param xx 中心点x坐标
         * @param yy 中心点y坐标
         * @param x  横长度/2
         * @param y  竖长度/2
         * @return
         */
        public static List<Point> square(int xx, int yy, int x, int y) {
            List<Point> ps = new ArrayList<>();
            Point lefttop = getPoint(xx - x, yy - y);
            Point righttop = getPoint(xx + x, yy - y);
            Point leftbottom = getPoint(xx - x, yy + y);
            Point rightbottom = getPoint(xx + x, yy + y);
            ps.addAll(line(lefttop, righttop));
            ps.addAll(line(righttop, rightbottom));
            ps.addAll(line(rightbottom, leftbottom));
            ps.addAll(line(leftbottom, lefttop));
            return ps;
        }
    
        /**
         * 画直线
         *
         * @param start 起点
         * @param end   终点
         * @return
         */
        public static List<Point> line(Point start, Point end) {
            List<Point> ps = new ArrayList<>();
            int xlength = end.x - start.x;
            int ylength = end.y - start.y;
            ps.add(start);
            for (int i = 1; i < xlength; i++) {
                int xx = start.x + i;
                int yy = start.y + (ylength / xlength) * i;
                ps.add(getPoint(xx, yy));
            }
            ps.add(end);
            return ps;
        }
    
        /**
         * 画圆形
         *
         * @param x 圆心坐标x
         * @param y 圆心坐标y
         * @param r 半径
         * @return
         */
        public static List<Point> circle(int x, int y, int r) {
            List<Point> ps = new ArrayList<>();
            double diff = Math.PI / 60;
            for (int i = 0; i < 121; i++) {
                double xx = r * (Math.cos(i * diff)) + x;
                double yy = r * (Math.sin(i * diff)) + y;
                ps.add(getPoint((int) xx, (int) yy));
            }
            return ps;
        }
    
        /**
         * 画心形图案的方法
         *
         * @param x 圆心坐标x
         * @param y 圆心坐标y
         * @param r 半径
         * @return
         */
        public static List<Point> heart(int x, int y, int r) {
            //画心形的方法
            List<Point> heart = new ArrayList<>();
            double d = Math.PI / 60;
            for (int i = 0; i < 121; i++) {
                double xx = r * (2 * Math.cos(i * d) - Math.cos(2 * i * d));
                double yy = r * (2 * Math.sin(i * d) - Math.sin(2 * i * d));
                heart.add(getPoint((int) yy + x, (int) xx + y));
            }
            return heart;
        }
    
    
    }
    
    

    下面是BoardUser类,由于这个类主要是用来生成各种用于Socket接口传输的数据的,所以没有实现ibase接口,也没有进行登录等操作,只有一个author来标记是不同的作者,因为author这个参数在转码的过程中用到了。

    package com.okayqa.board.function
    
    import com.fun.utils.DecodeEncode
    import com.okayqa.board.base.BoardBase
    import com.okayqa.board.base.Document
    import com.okayqa.board.base.Point
    import com.okayqa.board.base.WriteType
    import org.msgpack.core.MessagePack
    import org.slf4j.Logger
    import org.slf4j.LoggerFactory
    
    import java.util.stream.Collectors
    
    class BoardUser extends BoardBase {
    
        private static Logger logger = LoggerFactory.getLogger(BoardUser.class)
    
        /**
         * 作者
         */
        String author
    
        /**
         * 版本
         */
        byte version = Document.BOARD_VERSION_INITIAL;
    
        /**
         * 最后一次点阵集合
         */
        List<Point> ps;
    
        BoardUser(String author) {
            this.author = author
        }
    
        public String writeStart(List<Point> ps, String strokeId, byte page = 0) {
            write(ps, strokeId, page, WriteType.START)
        }
    
    
        public String writeEnd(List<Point> ps, String strokeId, byte page = 0) {
            write(ps, strokeId, page, WriteType.END)
        }
    
        public String writeMove(List<Point> ps, String strokeId, byte page = 0) {
            write(ps, strokeId, page, WriteType.MOVE)
        }
    
        public String clearPage(byte page = 0) {
            def packer = MessagePack.newDefaultBufferPacker()
            writeClearPage(Document.CURRENT_BOARD_VERSION, author, page, packer);
            DecodeEncode.base64Encode(packer.toByteArray())
        }
    
        /**
         * 创建不同的笔画类型
         * @param ps
         * @param strokeId
         * @param page
         * @param type
         * @return
         */
        private String write(List<Point> ps, String strokeId, byte page = 0, WriteType type) {
            def packer = MessagePack.newDefaultBufferPacker()
            switch (type) {
                case WriteType.START:
                    writeStartWrite(version, author, page, strokeId, getColor(), ps, packer)
                    break;
                case WriteType.MOVE:
                    writeContinueWrite(version, author, page, strokeId, ps, packer)
                    break
                case WriteType.END:
                    writeEndWrite(version, author, page, strokeId, ps, packer)
                    break
                default:
                    break
            }
            DecodeEncode.base64Encode(packer.toByteArray());
        }
    
        public List<String> initGraph(String strokeId = getStrokeId(), byte page = 0) {
            List<String> mgss = new ArrayList<>()
            if (ps == null || ps.isEmpty()) return mgss
            for (int i = 0; i < ps.size(); i += 5) {
                def five = ps[i..(i + 6 > ps.size() ? ps.size() - 1 : i + 4)]
                if (mgss.isEmpty()) {
                    mgss << writeStart(five, strokeId, page)
                    continue
                }
                if (!mgss.isEmpty() && i + 6 > ps.size()) {
                    mgss << writeEnd(five, strokeId, page)
                    continue
                }
                mgss << writeMove(five, strokeId, page)
            }
            mgss
        }
    
    
        /**
         * 画方形
         * @return
         */
        public List<String> writeSquare() {
            ps = square(500, 300, 200, 100)
            initGraph()
        }
    
        /**
         * 画圆形
         * @return
         */
        public List<String> writeCircle() {
            ps = circle(500, 300, 250)
            initGraph()
        }
    
        /**
         * 画心形
         * @return
         */
        public List<String> writeHeart() {
            ps = heart(500, 300, 200)
            initGraph()
        }
    
        /**
         * 图形漂移
         * @param offsetX
         * @param offsetY
         * @return
         */
        public List<String> move(int offsetX, int offsetY) {
            ps = ps.stream().map { it.move(offsetX, offsetY) }.collect(Collectors.toList())
            initGraph()
        }
    
    
    }
    
    

    测试Demo

    下面是测试方法:

        public static void main(String[] args) throws IOException {
            BoardUser boardUser = new BoardUser(Users.getTeaUser(0));
            List<String> list = boardUser.writeCircle();
            range(list.size()).forEach(x -> output(list.get(x)));
        }
    

    控制台输出:

    INFO-> 当前用户:fv,IP:10.60.193.37,工作目录:/Users/fv/Documents/workspace/okay_test/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> 生成了笔画ID: FunTester88f7b499-843d-406e-86f8-889c00119220
    INFO-> AQKrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjDOAInvmZXNHUzNC7jNASzNHULNDDrNASzNHTjNDLzNASzNHSTNDT7NASzNHRDNDbbNASw=
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRzyzQ44zQEszRzKzQ66zQEszRyizQ8yzQEszRxwzQ+qzQEszRw0zRAizQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRv4zRCazQEszRuyzREIzQEszRtszRFszQEszRsczRHazQEszRrCzRI+zQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRpozRKYzQEszRoOzRLyzQEszRmqzRNMzQEszRk8zROczQEszRjYzRPizQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRhqzRQozQEszRfyzRRkzQEszRd6zRSgzQEszRcCzRTSzQEszRaKzRT6zQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRYIzRUizQEszRWGzRVAzQEszRUOzRVUzQEszRSMzRVozQEszRQKzRVyzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzROIzRV8zQEszRL8zRVyzQEszRJ6zRVozQEszRH4zRVUzQEszRGAzRVAzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRD+zRUizQEszRB8zRT6zQEszRAEzRTSzQEszQ+MzRSgzQEszQ8UzRRkzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQ6mzRQozQEszQ4uzRPizQEszQ3KzROczQEszQ1czRNMzQEszQz4zRLyzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQyezRKYzQEszQxEzRI+zQEszQvqzRHazQEszQuazRFszQEszQtUzREIzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQsOzRCazQEszQrSzRAizQEszQqWzQ+qzQEszQpkzQ8yzQEszQo8zQ66zQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQoUzQ44zQEszQn2zQ22zQEszQnizQ0+zQEszQnOzQy8zQEszQnEzQw6zQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQnEzQu4zQEszQnEzQsszQEszQnOzQqqzQEszQnizQoozQEszQn2zQmwzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQoUzQkuzQEszQo8zQiszQEszQpkzQg0zQEszQqWzQe8zQEszQrSzQdEzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQsOzQbWzQEszQtUzQZezQEszQuazQX6zQEszQvqzQWMzQEszQxEzQUozQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQyezQTOzQEszQz4zQR0zQEszQ1czQQazQEszQ3KzQPKzQEszQ4uzQOEzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQ6czQM+zQEszQ8UzQMCzQEszQ+MzQLGzQEszRAEzQKUzQEszRB8zQJszQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRD+zQJEzQEszRGAzQImzQEszRH4zQISzQEszRJ6zQH+zQEszRL8zQH0zQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRN+zQH0zQEszRQKzQH0zQEszRSMzQH+zQEszRUOzQISzQEszRWGzQImzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRYIzQJEzQEszRaKzQJszQEszRcCzQKUzQEszRd6zQLGzQEszRfyzQMCzQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRhgzQM+zQEszRjYzQOEzQEszRk8zQPKzQEszRmqzQQazQEszRoOzQR0zQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRpozQTOzQEszRrCzQUozQEszRsczQWMzQEszRtszQX6zQEszRuyzQZezQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRv4zQbMzQEszRw0zQdEzQEszRxwzQe8zQEszRyizQg0zQEszRzKzQiszQEs
    INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRzyzQkuzQEszR0QzQmwzQEszR0kzQoozQEszR04zQqqzQEszR1CzQsszQEs
    INFO-> AQSrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCRzR1MzQuuzQEs
    
    Process finished with exit code 0
    
    

    完美!

    接下来会分享一下Socket接口的中如何进行白板接口测试,敬请期待!


    FunTester腾讯云年度作者,优秀讲师 | 腾讯云+社区权威认证,非著名测试开发,欢迎关注。

    点击阅读原文,查看公众号历史文章

  • 相关阅读:
    [转载]RTSP in Stagefright
    FFMPEG for WMA Build Script
    Merge AACExtractor from ICS to Froyo
    查看部署在Heroku上的项目信息
    About AudioSystem Mute
    C++标准转换运算符reinterpret_cast
    纯CSS动态效果的画廊
    基于正则表达式匹配的C++语法高亮度显示
    C++标准转换运算符static_cast
    C++标准转换运算符const_cast
  • 原文地址:https://www.cnblogs.com/FunTester/p/14382095.html
Copyright © 2011-2022 走看看