Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Dockerized Testing Toolkit
DTT Backend
Commits
657b50aa
Verified
Commit
657b50aa
authored
Dec 30, 2020
by
Lukas Wiest
🚂
Browse files
Merge branch '1-add-unified-ticketing'
closes
#1
parents
cf70796d
b30650fa
Changes
3
Hide whitespace changes
Inline
Side-by-side
pom.xml
View file @
657b50aa
...
...
@@ -63,6 +63,17 @@
<artifactId>
log4j-core
</artifactId>
<version>
2.11.2
</version>
</dependency>
<dependency>
<groupId>
de.hftstuttgart
</groupId>
<artifactId>
unified-ticketing
</artifactId>
<version>
0.2.0
</version>
</dependency>
<!-- somehow for unified-ticketing maven downloads a 3.x version, even though 4.9.0 is set on unified-ticketing pom -->
<dependency>
<groupId>
com.squareup.okhttp3
</groupId>
<artifactId>
okhttp
</artifactId>
<version>
4.9.0
</version>
</dependency>
</dependencies>
<build>
...
...
@@ -74,4 +85,11 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>
unified-ticketing
</id>
<url>
https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/154/packages/maven
</url>
</repository>
</repositories>
</project>
src/main/java/de/hftstuttgart/rest/v1/task/TaskUpload.java
View file @
657b50aa
...
...
@@ -9,6 +9,7 @@ import de.hftstuttgart.rest.v1.unittest.UnitTestUpload;
import
de.hftstuttgart.utils.DockerUtil
;
import
de.hftstuttgart.utils.FileUtil
;
import
de.hftstuttgart.utils.JGitUtil
;
import
de.hftstuttgart.utils.UnifiedTicketingUtil
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
org.springframework.core.env.Environment
;
...
...
@@ -201,6 +202,9 @@ public class TaskUpload {
LOG
.
debug
(
"convert to moodle understandable format"
);
LegacyMoodleResult
moodleResult
=
LegacyMoodleResult
.
convertToModdleResult
(
resultSummary
);
LOG
.
info
(
"check for provided Ticketsystem information"
);
UnifiedTicketingUtil
.
reportResults
(
taskFileRef
.
getInputStream
(),
resultSummary
);
LOG
.
info
(
"submission tested successfully"
);
return
moodleResult
;
}
...
...
src/main/java/de/hftstuttgart/utils/UnifiedTicketingUtil.java
0 → 100644
View file @
657b50aa
package
de.hftstuttgart.utils
;
import
de.hftstuttgart.models.ModocotResult
;
import
de.hftstuttgart.models.ModocotResultSummary
;
import
de.hftstuttgart.unifiedticketing.core.Filter
;
import
de.hftstuttgart.unifiedticketing.core.Ticket
;
import
de.hftstuttgart.unifiedticketing.core.TicketBuilder
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.UnifiedticketingException
;
import
org.apache.log4j.LogManager
;
import
org.apache.log4j.Logger
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.nio.charset.StandardCharsets
;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
public
class
UnifiedTicketingUtil
{
private
final
static
Logger
LOG
=
LogManager
.
getLogger
(
UnifiedTicketingUtil
.
class
);
private
final
static
String
MODOCOT_LABEL
=
"MoDoCoT created"
;
private
final
static
String
MODOCOT_TITLE
=
" | "
+
MODOCOT_LABEL
;
public
static
String
createTicketDescriptionFromResult
(
TicketSystem
ts
,
ModocotResult
result
,
boolean
compilationError
)
{
StringBuilder
sb
=
new
StringBuilder
();
// heading
if
(
compilationError
)
{
sb
.
append
(
String
.
format
(
"# %s is not compilable"
,
result
.
name
));
}
else
{
sb
.
append
(
String
.
format
(
"# Unittest for %s fails"
,
result
.
name
));
}
sb
.
append
(
"\n\n"
);
// meta data table
sb
.
append
(
"|||\n"
);
sb
.
append
(
"|:-|:-|\n"
);
if
(
compilationError
)
{
sb
.
append
(
String
.
format
(
"|File|`%s`|\n"
,
result
.
name
));
}
else
{
sb
.
append
(
String
.
format
(
"|Test|`%s`|\n"
,
result
.
name
));
}
sb
.
append
(
String
.
format
(
"|Reason|`%s`|\n"
,
result
.
failureReason
));
if
(
compilationError
)
{
sb
.
append
(
String
.
format
(
"|Line|`%s`|\n"
,
result
.
lineNumber
));
sb
.
append
(
String
.
format
(
"|Column|`%s`|\n"
,
result
.
columnNumber
));
sb
.
append
(
String
.
format
(
"|Position|`%s`|\n"
,
result
.
position
));
}
else
{
sb
.
append
(
String
.
format
(
"|Type|`%s`|\n"
,
result
.
failureType
));
}
sb
.
append
(
"\n\n"
);
// stacktrace
sb
.
append
(
"<details>\n\n"
);
sb
.
append
(
"<summary>show stacktrace</summary>\n\n"
);
sb
.
append
(
"```"
);
sb
.
append
(
result
.
stacktrace
);
sb
.
append
(
"\n```"
);
sb
.
append
(
"\n\n</details>\n"
);
return
sb
.
toString
();
}
public
static
String
createTicketTitleFromResult
(
TicketSystem
ts
,
ModocotResult
result
,
boolean
compilationError
)
{
StringBuilder
sb
=
new
StringBuilder
();
String
separator
=
" | "
;
if
(
compilationError
)
sb
.
append
(
"compilation fails"
);
else
sb
.
append
(
"test method fails"
);
sb
.
append
(
separator
);
sb
.
append
(
result
.
name
);
if
(!
compilationError
)
{
sb
.
append
(
separator
);
sb
.
append
(
result
.
failureReason
);
}
// if label-support is not present, place global identifier into title
if
(!
ts
.
hasLabelSupport
())
sb
.
append
(
MODOCOT_TITLE
);
sb
.
append
(
separator
);
sb
.
append
(
getHashForFailure
(
result
));
return
sb
.
toString
();
}
public
static
Ticket
createTicketFromResult
(
TicketSystem
ts
,
ModocotResult
result
,
boolean
compilationError
)
{
TicketBuilder
tb
=
ts
.
createTicket
()
.
title
(
createTicketTitleFromResult
(
ts
,
result
,
compilationError
))
.
description
(
createTicketDescriptionFromResult
(
ts
,
result
,
compilationError
));
if
(
ts
.
hasLabelSupport
())
tb
.
labels
(
Collections
.
singleton
(
MODOCOT_LABEL
));
return
tb
.
create
();
}
public
static
Set
<
Ticket
>
fetchExistingModocotTickets
(
TicketSystem
ts
)
{
Set
<
Ticket
>
ret
=
new
HashSet
<>();
Filter
f
=
ts
.
find
();
// depending on label support, identify MoDoCoT tickets by label or title containing string
if
(
ts
.
hasLabelSupport
())
{
LOG
.
debug
(
String
.
format
(
"ticketsystem has label support, using label %s to find modocot tickets"
,
MODOCOT_LABEL
));
f
.
withLabel
(
MODOCOT_LABEL
);
}
else
{
LOG
.
debug
(
String
.
format
(
"ticketsystem without labels, searching for ticket titles containing %s"
,
MODOCOT_TITLE
));
f
.
withTitleContain
(
MODOCOT_TITLE
);
}
LOG
.
debug
(
"prepare pagination cycling"
);
// set first page and page size for pagination
int
page
=
1
;
int
pageSize
=
10
;
f
.
setPageSize
(
pageSize
);
LOG
.
debug
(
String
.
format
(
"using pagination with %s elements per page"
,
pageSize
));
// declare list for received tickets
List
<
Ticket
>
received
;
// go into do-while to evaluate after receiving if another round is needed
do
{
LOG
.
debug
(
String
.
format
(
"calling page %s"
,
page
));
f
.
setPage
(
page
++);
received
=
f
.
get
();
ret
.
addAll
(
received
);
}
while
(
f
.
getLastReceivedItemCount
()
>=
pageSize
);
return
ret
;
}
public
static
String
getHashForFailure
(
ModocotResult
result
)
{
MessageDigest
digest
;
try
{
digest
=
MessageDigest
.
getInstance
(
"SHA-512"
);
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
UnifiedticketingException
(
e
);
}
byte
[]
data
=
digest
.
digest
(
result
.
name
.
getBytes
(
StandardCharsets
.
UTF_8
));
StringBuilder
hexString
=
new
StringBuilder
(
2
*
data
.
length
);
for
(
byte
character:
data
)
{
String
hex
=
Integer
.
toHexString
(
0xff
&
character
);
if
(
hex
.
length
()
==
1
)
{
hexString
.
append
(
'0'
);
}
hexString
.
append
(
hex
);
}
return
hexString
.
substring
(
hexString
.
length
()
-
9
,
hexString
.
length
()
-
1
);
}
public
static
void
processResult
(
TicketSystem
ts
,
Set
<
Ticket
>
tickets
,
ModocotResult
result
,
boolean
compilationError
)
{
LOG
.
debug
(
String
.
format
(
"retrieving hash for %s"
,
result
.
name
));
String
hash
=
getHashForFailure
(
result
);
// check if corresponding ticket exists yet, otherwise create new one
Ticket
ticket
=
tickets
.
stream
()
.
filter
(
t
->
t
.
getTitle
().
endsWith
(
hash
))
.
findFirst
()
.
orElse
(
null
);
if
(
ticket
!=
null
)
{
// if yet existing, remove from found list
LOG
.
debug
(
"found ticket with matching hash, removing from collection"
);
tickets
.
remove
(
ticket
);
LOG
.
debug
(
"updating ticket with new result"
);
updateTicketFromResult
(
ts
,
ticket
,
result
,
compilationError
);
}
else
{
LOG
.
debug
(
"no ticket found, creating new one"
);
createTicketFromResult
(
ts
,
result
,
compilationError
);
}
}
/**
* search file for unified-ticketing URI's and report to every set ticket system,
* not waiting for it to finish and catching an eventually interrupted thread.
*
* @param meta student uploaded file
* @param resultSummary summary from the testrunner container
*/
public
static
void
reportResults
(
InputStream
meta
,
ModocotResultSummary
resultSummary
)
{
try
{
reportResults
(
meta
,
resultSummary
,
false
);
}
catch
(
InterruptedException
e
)
{
LOG
.
error
(
String
.
format
(
"Unified-Ticketing got interrupted with: %s"
,
e
.
getMessage
()));
}
}
/**
* report all failures and compilation errors to all configured ticket systems.
* You can optionally wait for the ticket creation to finish, which is done in a separate thread.
*
* @param meta student uploaded file
* @param resultSummary summary from the testrunner container
* @param wait if we should block until the ticket creation has finished
* @throws InterruptedException
*/
public
static
void
reportResults
(
InputStream
meta
,
ModocotResultSummary
resultSummary
,
boolean
wait
)
throws
InterruptedException
{
LOG
.
debug
(
"preparing thread for ticket result submitting"
);
Thread
unifiedTicketingUtil
=
new
Thread
(()
->
{
// read student transmitted file
try
(
BufferedReader
br
=
new
BufferedReader
(
new
InputStreamReader
(
meta
)))
{
String
line
=
null
;
while
((
line
=
br
.
readLine
())
!=
null
)
{
TicketSystem
ts
=
null
;
// try each line as URI for a unified-ticketing instantiation
try
{
ts
=
TicketSystem
.
fromUri
(
line
);
LOG
.
info
(
String
.
format
(
"ticket system for reporting found: %s"
,
ts
.
baseUrl
));
}
catch
(
UnifiedticketingException
e
)
{
// ignore if line didn't match a unified-ticketing URI
}
// if a ticketsystem got instantiated, start the submission.
// If errors occur, log it this time.
try
{
if
(
ts
!=
null
)
reportToTicketsystem
(
ts
,
resultSummary
);
}
catch
(
UnifiedticketingException
e
)
{
LOG
.
warn
(
String
.
format
(
"reporting fails to ticketsystem %s failed with: "
,
ts
.
baseUrl
,
e
.
getMessage
()));
}
}
}
catch
(
IOException
e
)
{
LOG
.
error
(
String
.
format
(
"couldn't read config to find lines for ticket reporting: %s"
,
e
.
getMessage
()));
}
});
LOG
.
debug
(
"starting ticket submitting thread"
);
unifiedTicketingUtil
.
start
();
if
(
wait
)
{
LOG
.
debug
(
"wait for ticket submission completion"
);
unifiedTicketingUtil
.
join
();
}
else
{
LOG
.
debug
(
"tickets will be submitted in background"
);
}
}
public
static
void
reportToTicketsystem
(
TicketSystem
ts
,
ModocotResultSummary
resultSummary
)
{
// tickets existing yet
LOG
.
debug
(
"fetching existing tickets"
);
Set
<
Ticket
>
tickets
=
fetchExistingModocotTickets
(
ts
);
// for each fail or compile error
LOG
.
debug
(
"start failed tests reporting"
);
resultSummary
.
failures
.
forEach
(
f
->
processResult
(
ts
,
tickets
,
f
,
false
));
LOG
.
debug
(
"start compilation errors reporting"
);
resultSummary
.
compilationErrors
.
forEach
(
c
->
processResult
(
ts
,
tickets
,
c
,
true
));
LOG
.
debug
(
"closing all remaining tickets, no longer appeared"
);
tickets
.
forEach
(
ticket
->
ticket
.
close
().
save
());
}
public
static
Ticket
updateTicketFromResult
(
TicketSystem
ts
,
Ticket
ticket
,
ModocotResult
result
,
boolean
compilationError
)
{
ticket
.
open
()
.
setTitle
(
createTicketTitleFromResult
(
ts
,
result
,
compilationError
))
.
setDescription
(
createTicketDescriptionFromResult
(
ts
,
result
,
compilationError
));
if
(
ts
.
hasLabelSupport
())
ticket
.
addLabel
(
MODOCOT_LABEL
);
return
ticket
.
save
();
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment