Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Lukas Wiest
unified-ticketing
Compare Revisions
0.0.0...0.1.0
Show whitespace changes
Inline
Side-by-side
src/main/java/de/hftstuttgart/unifiedticketing/exceptions/DeserializationException.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.exceptions
;
public
class
DeserializationException
extends
UnifiedticketingException
{
public
DeserializationException
()
{
super
();
}
public
DeserializationException
(
String
msg
)
{
super
(
msg
);
}
public
DeserializationException
(
String
msg
,
Throwable
cause
)
{
super
(
msg
,
cause
);
}
public
DeserializationException
(
Throwable
suppressed
)
{
super
(
suppressed
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/exceptions/HttpReqeustException.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.exceptions
;
public
class
HttpReqeustException
extends
UnifiedticketingException
{
public
HttpReqeustException
()
{
super
();
}
public
HttpReqeustException
(
String
msg
)
{
super
(
msg
);
}
public
HttpReqeustException
(
String
msg
,
Throwable
casue
)
{
super
(
msg
,
casue
);
}
public
HttpReqeustException
(
Throwable
suppressed
)
{
super
(
suppressed
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/exceptions/HttpResponseException.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.exceptions
;
public
class
HttpResponseException
extends
UnifiedticketingException
{
public
final
int
status
;
public
HttpResponseException
(
int
status
)
{
super
();
this
.
status
=
status
;
}
public
HttpResponseException
(
String
msg
,
int
status
)
{
super
(
msg
);
this
.
status
=
status
;
}
public
HttpResponseException
(
String
msg
,
Throwable
cause
,
int
status
)
{
super
(
msg
,
cause
);
this
.
status
=
status
;
}
public
HttpResponseException
(
Throwable
suppressed
,
int
status
)
{
super
(
suppressed
);
this
.
status
=
status
;
}
}
src/main/java/de/hftstuttgart/unifiedticketing/exceptions/SerializationException.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.exceptions
;
public
class
SerializationException
extends
UnifiedticketingException
{
public
SerializationException
()
{
super
();
}
public
SerializationException
(
String
msg
)
{
super
(
msg
);
}
public
SerializationException
(
String
msg
,
Throwable
cause
)
{
super
(
msg
,
cause
);
}
public
SerializationException
(
Throwable
suppressed
)
{
super
(
suppressed
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/exceptions/UnifiedticketingException.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.exceptions
;
public
class
UnifiedticketingException
extends
RuntimeException
{
public
UnifiedticketingException
()
{
super
();
}
public
UnifiedticketingException
(
String
msg
)
{
super
(
msg
);
}
public
UnifiedticketingException
(
String
msg
,
Throwable
cause
)
{
super
(
msg
,
cause
);
}
public
UnifiedticketingException
(
Throwable
suppressed
)
{
this
(
suppressed
.
getMessage
());
this
.
addSuppressed
(
suppressed
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/exceptions/UnsupportedFunctionException.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.exceptions
;
public
class
UnsupportedFunctionException
extends
UnifiedticketingException
{
public
UnsupportedFunctionException
()
{
super
();
}
public
UnsupportedFunctionException
(
String
msg
)
{
super
(
msg
);
}
public
UnsupportedFunctionException
(
String
msg
,
Throwable
cause
)
{
super
(
msg
,
cause
);
}
public
UnsupportedFunctionException
(
Throwable
suppressed
)
{
super
(
suppressed
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/gitlab/GitlabFilter.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.systems.gitlab
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.fasterxml.jackson.databind.DeserializationFeature
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
de.hftstuttgart.unifiedticketing.core.Filter
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.AssertionException
;
import
de.hftstuttgart.unifiedticketing.exceptions.DeserializationException
;
import
de.hftstuttgart.unifiedticketing.exceptions.HttpReqeustException
;
import
de.hftstuttgart.unifiedticketing.exceptions.HttpResponseException
;
import
okhttp3.*
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
public
class
GitlabFilter
extends
Filter
<
GitlabTicket
,
GitlabFilter
>
{
private
static
Logger
logger
=
Logging
.
getLogger
(
GitlabFilter
.
class
.
getName
());
protected
final
GitlabTicketSystem
parent
;
protected
GitlabFilter
(
GitlabTicketSystem
parent
)
{
this
.
parent
=
parent
;
}
protected
OkHttpClient
getHttpClient
()
{
return
new
OkHttpClient
();
}
/**
* this builds up a request with as much of the given constraints directed to the
* gitlab api. Everything not possible through the api will be filtered afterwards in java
* @return ticket list matching given constraints
*/
@Override
public
List
<
GitlabTicket
>
get
()
{
OkHttpClient
client
;
ObjectMapper
mapper
=
new
ObjectMapper
()
.
configure
(
DeserializationFeature
.
FAIL_ON_UNKNOWN_PROPERTIES
,
false
);
Request
.
Builder
requestBuilder
=
new
Request
.
Builder
()
.
url
(
String
.
format
(
"%s/issues"
,
parent
.
baseUrl
))
.
get
();
if
(
parent
.
apiKey
!=
null
)
{
requestBuilder
.
addHeader
(
"PRIVATE-TOKEN"
,
parent
.
apiKey
);
}
HttpUrl
.
Builder
urlBuilder
=
requestBuilder
.
build
().
url
().
newBuilder
();
for
(
Map
.
Entry
<
String
,
Object
>
mapEntry
:
setFilters
.
entrySet
())
{
String
f
=
mapEntry
.
getKey
();
Object
v
=
mapEntry
.
getValue
();
try
{
if
(
f
.
equals
(
FilterNames
.
ASSIGNEEID
.
name
()))
{
((
Set
<
String
>)
v
).
stream
()
.
findFirst
()
.
ifPresent
(
value
->
urlBuilder
.
addQueryParameter
(
"assignee_id"
,
value
));
}
else
if
(
f
.
equals
(
FilterNames
.
ASSIGNEENAME
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"assignee_username"
,
((
Set
<
String
>)
v
).
stream
()
.
reduce
((
u1
,
u2
)
->
u1
+
","
+
u2
)
.
orElse
(
""
));
}
else
if
(
f
.
equals
(
FilterNames
.
DESCRIPTION_CONTAIN
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"search"
,
(
String
)
v
);
}
else
if
(
f
.
equals
(
FilterNames
.
DESCRIPTION_MATCH
.
name
()))
{
logger
.
log
(
Level
.
FINE
,
"Regex matching only possible after request |"
+
" Filter: "
+
FilterNames
.
DESCRIPTION_MATCH
.
name
());
}
else
if
(
f
.
equals
(
FilterNames
.
IDS
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"iids"
,
((
Set
<
String
>)
v
).
stream
()
.
reduce
((
id1
,
id2
)
->
id1
+
","
+
id2
)
.
orElse
(
""
));
}
else
if
(
f
.
equals
(
FilterNames
.
LABELS
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"labels"
,
((
Set
<
String
>)
v
).
stream
()
.
reduce
((
l1
,
l2
)
->
l1
+
","
+
l2
)
.
orElse
(
""
));
}
else
if
(
f
.
equals
(
FilterNames
.
PAGE
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"page"
,
String
.
valueOf
(
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
PAGINATION
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"per_page"
,
String
.
valueOf
(
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
OPEN
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"state"
,
((
boolean
)
v
)
?
"opened"
:
"closed"
);
}
else
if
(
f
.
equals
(
FilterNames
.
TITLE_CONTAINS
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"search"
,
(
String
)
v
);
}
else
if
(
f
.
equals
(
FilterNames
.
TITLE_MATCH
.
name
()))
{
logger
.
log
(
Level
.
FINE
,
"Regex matching only possible after request |"
+
" Filter: "
+
FilterNames
.
TITLE_MATCH
.
name
());
}
else
{
logger
.
log
(
Level
.
WARNING
,
String
.
format
(
"unrecognized filter key: %s"
,
f
));
}
}
catch
(
ClassCastException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"Filter with key "
+
f
+
" unexpectedly had type "
+
v
.
getClass
().
getName
());
if
(!
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
{
throw
new
AssertionException
(
e
);
}
}
}
requestBuilder
.
url
(
urlBuilder
.
build
());
client
=
getHttpClient
();
Response
response
;
try
{
Request
request
=
requestBuilder
.
build
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"created request:\n%s"
,
(
this
.
parent
.
apiKey
!=
null
)
?
request
.
toString
().
replace
(
this
.
parent
.
apiKey
,
"SECRET"
)
:
request
.
toString
()
));
response
=
client
.
newCall
(
request
).
execute
();
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"get request FAILED with: %s"
,
e
.
getMessage
()));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpReqeustException
(
e
);
}
if
(
response
.
code
()
>=
400
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"request failed with response code %d"
,
response
.
code
()
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
String
.
format
(
"ticket query failed, error response code: %d"
,
response
.
code
()),
response
.
code
());
}
logger
.
log
(
Level
.
FINEST
,
"response received\n"
);
ResponseBody
responseBody
;
responseBody
=
response
.
body
();
if
(
responseBody
==
null
)
{
logger
.
log
(
Level
.
SEVERE
,
"query didn't deliver a body in response"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
"ticket query failed, no response body"
,
response
.
code
());
}
List
<
GitlabTicketResponse
>
tr
;
try
{
tr
=
mapper
.
readValue
(
responseBody
.
bytes
(),
new
TypeReference
<
List
<
GitlabTicketResponse
>>(){});
logger
.
log
(
Level
.
FINER
,
"parsed response body to ticketResponse list instance"
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"found %d items pre post-filter"
,
tr
.
size
()));
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"parsing query response FAILED with: %s"
,
e
.
getMessage
()));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
DeserializationException
(
e
);
}
logger
.
log
(
Level
.
FINER
,
"starting query post filter"
);
Stream
<
GitlabTicketResponse
>
ticketStream
=
tr
.
stream
();
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
setFilters
.
entrySet
())
{
String
f
=
entry
.
getKey
();
Object
v
=
entry
.
getValue
();
try
{
if
(
f
.
equals
(
FilterNames
.
DESCRIPTION_MATCH
.
name
()))
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
description
.
matches
((
String
)
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
TITLE_MATCH
.
name
()))
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
title
.
matches
((
String
)
v
));
}
}
catch
(
ClassCastException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"Filter with key "
+
f
+
" unexpectedly had type "
+
v
.
getClass
().
getName
());
}
}
logger
.
log
(
Level
.
FINER
,
"post-filter finished"
);
List
<
GitlabTicket
>
ret
=
ticketStream
.
map
(
t
->
GitlabTicket
.
fromTicketResponse
(
parent
,
t
))
.
collect
(
Collectors
.
toList
());
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"remaining items: %d"
,
ret
.
size
()));
return
ret
;
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/gitlab/GitlabTicket.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.systems.gitlab
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.DeserializationFeature
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.node.ArrayNode
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.Ticket
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.*
;
import
de.hftstuttgart.unifiedticketing.exceptions.*
;
import
okhttp3.*
;
import
java.io.IOException
;
import
java.util.HashSet
;
import
java.util.Objects
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.stream.Collectors
;
public
class
GitlabTicket
extends
Ticket
<
GitlabTicketSystem
,
GitlabTicket
>
{
private
static
Logger
logger
=
Logging
.
getLogger
(
GitlabTicket
.
class
.
getName
());
protected
GitlabTicket
(
GitlabTicketSystem
parent
)
{
super
(
parent
);
}
/**
* method to parse a library conform ticket instance from the JSON response of gitlab api
* @param parent ticket system instance to be placed as parent
* @param response api response
* @return library conform ticket instance
*/
protected
static
GitlabTicket
fromTicketResponse
(
GitlabTicketSystem
parent
,
GitlabTicketResponse
response
)
{
GitlabTicket
ret
=
new
GitlabTicket
(
parent
);
ret
.
description
=
response
.
description
;
ret
.
id
=
String
.
valueOf
(
response
.
iid
);
if
(
response
.
labels
!=
null
)
{
ret
.
labels
=
response
.
labels
;
}
ret
.
open
=
(
response
.
state
!=
null
)
?
!
response
.
state
.
equalsIgnoreCase
(
"closed"
)
:
true
;
ret
.
title
=
response
.
title
;
if
(
response
.
assignees
!=
null
)
{
ret
.
assignees
=
response
.
assignees
.
stream
()
.
map
(
a
->
new
GitlabTicketAssignee
(
a
.
id
,
a
.
name
,
a
.
username
))
.
collect
(
Collectors
.
toCollection
(
HashSet:
:
new
));
}
return
ret
;
}
/**
* adds assignee by it's user id
*
* @param userId gitlab user id parsable as integer
* @return this ticket
* @throws AssertionException if {@code userId} is not integer parsable
*/
@Override
public
GitlabTicket
addAssignee
(
String
userId
)
{
try
{
return
this
.
addAssignee
(
Integer
.
parseInt
(
userId
));
}
catch
(
NumberFormatException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"%s is not applicable for a Gitlab user id"
,
userId
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
this
;
else
throw
new
AssertionException
(
e
);
}
}
/**
* adds assignee by it's user id
*
* @param userId gitlab user id
* @return this ticket
*/
public
GitlabTicket
addAssignee
(
int
userId
)
{
this
.
assignees
.
add
(
new
GitlabTicketAssignee
(
userId
,
null
,
null
));
this
.
updatedFields
.
add
(
FieldNames
.
ASSIGNEES
.
name
());
return
this
;
}
/**
* removes assignee by it's user id
*
* @param userId gitlab user id parsable as integer
* @return this ticket
* @throws AssertionException if {@code userId} is not integer parsable
*/
@Override
public
GitlabTicket
removeAssignee
(
String
userId
)
{
int
id
;
try
{
return
this
.
removeAssignee
(
Integer
.
parseInt
(
userId
));
}
catch
(
NumberFormatException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"%s is not applicable for a Gitlab user id"
,
userId
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
this
;
else
throw
new
AssertionException
(
e
);
}
}
/**
* removes assignee by it's user id
*
* @param userId gitlab user id parsable as integer
* @return this ticket
*/
public
GitlabTicket
removeAssignee
(
int
userId
)
{
this
.
assignees
.
removeIf
(
a
->
Objects
.
equals
(
a
.
id
,
String
.
valueOf
(
userId
)));
this
.
updatedFields
.
add
(
FieldNames
.
ASSIGNEES
.
name
());
return
this
;
}
protected
OkHttpClient
getHttpClient
()
{
return
new
OkHttpClient
();
}
/**
* checks for changed fields and serializes them into a PUT request
* to update this ticket instance.
* @return newly received ticket data as new {@link GitlabTicket instance}
*/
@Override
public
GitlabTicket
save
()
{
if
(
updatedFields
.
size
()
==
0
)
{
logger
.
info
(
"No changed fields, no save required"
);
return
this
;
}
OkHttpClient
client
=
this
.
getHttpClient
();
ObjectMapper
mapper
=
new
ObjectMapper
()
.
configure
(
DeserializationFeature
.
FAIL_ON_UNKNOWN_PROPERTIES
,
false
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] preparing body for update request"
,
this
.
id
));
ObjectNode
body
=
mapper
.
createObjectNode
();
for
(
String
name
:
this
.
updatedFields
)
{
if
(
FieldNames
.
ASSIGNEES
.
name
().
equals
(
name
))
{
ArrayNode
ids
=
body
.
putArray
(
"assignee_ids"
);
try
{
this
.
assignees
.
forEach
(
a
->
ids
.
add
(
Integer
.
parseInt
(
a
.
id
)));
}
catch
(
NumberFormatException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"parsing assignee id failed on serialization"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
{
body
.
remove
(
"assignee_ids"
);
continue
;
}
else
{
throw
new
SerializationException
(
e
);
}
}
}
else
if
(
FieldNames
.
DESCRIPTION
.
name
().
equals
(
name
))
{
body
.
put
(
"description"
,
this
.
description
);
}
else
if
(
FieldNames
.
LABELS
.
name
().
equals
(
name
))
{
body
.
put
(
"labels"
,
this
.
labels
.
stream
().
reduce
((
l1
,
l2
)
->
l1
+
","
+
l2
).
orElse
(
""
));
}
else
if
(
FieldNames
.
OPEN
.
name
().
equals
(
name
))
{
body
.
put
(
"state_event"
,
(
this
.
open
)
?
"reopen"
:
"close"
);
}
else
if
(
FieldNames
.
TITLE
.
name
().
equals
(
name
))
{
body
.
put
(
"title"
,
this
.
title
);
}
else
{
logger
.
log
(
Level
.
WARNING
,
String
.
format
(
"[Ticket %s] unknown field %s will be ignored from update"
,
this
.
id
,
name
));
continue
;
}
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] %s added to update"
,
this
.
id
,
name
));
}
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] request body for update prepared"
,
this
.
id
));
Request
.
Builder
builder
=
new
Request
.
Builder
()
.
url
(
String
.
format
(
"%s/issues/%s"
,
this
.
parent
.
baseUrl
,
this
.
id
));
try
{
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] serializing update request body"
,
this
.
id
));
String
bodyJson
=
mapper
.
writeValueAsString
(
body
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] serialized JSON:\n%s"
,
this
.
id
,
bodyJson
));
builder
.
put
(
RequestBody
.
create
(
bodyJson
,
MediaType
.
get
(
"application/json"
)));
}
catch
(
JsonProcessingException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] serializing update request body FAILED!"
,
this
.
id
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
SerializationException
(
e
);
}
if
(
parent
.
apiKey
!=
null
)
{
builder
.
addHeader
(
"PRIVATE-TOKEN"
,
parent
.
apiKey
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] added token authentication header"
,
this
.
id
));
}
Response
response
;
try
{
Request
request
=
builder
.
build
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] created request:\n%s"
,
this
.
id
,
(
this
.
parent
.
apiKey
!=
null
)
?
request
.
toString
().
replace
(
this
.
parent
.
apiKey
,
"SECRET"
)
:
request
.
toString
()
));
response
=
client
.
newCall
(
request
).
execute
();
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] update request FAILED"
,
this
.
id
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpReqeustException
(
e
);
}
if
(
response
.
code
()
>=
400
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] update request failed with response code %d"
,
this
.
id
,
response
.
code
()
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
String
.
format
(
"ticket save failed, error response code: %d"
,
response
.
code
()),
response
.
code
());
}
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] response received"
,
this
.
id
));
ResponseBody
responseBody
;
responseBody
=
response
.
body
();
if
(
responseBody
==
null
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] update request didn't deliver a body in response"
,
this
.
id
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
"ticket save failed, no response body"
,
response
.
code
());
}
GitlabTicketResponse
ticketResponse
;
try
{
ticketResponse
=
mapper
.
readValue
(
responseBody
.
bytes
(),
GitlabTicketResponse
.
class
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] parsed response body to ticketResponse instance"
,
this
.
id
));
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"parsing update response FAILED with: %s"
,
e
.
getMessage
()));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
DeserializationException
(
e
);
}
this
.
updatedFields
.
clear
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] update mark state reset"
,
this
.
id
));
return
GitlabTicket
.
fromTicketResponse
(
this
.
parent
,
ticketResponse
);
}
/**
* compares a given Object to this one, including all data fields.
* The normal {@link #equals(Object)} method does only compare Ticket Type and id,
* but not the data fields like this one.
* @param o Object to compare to this
* @return true if the given object is equal in terms of type, id and content to this
*/
public
boolean
deepEquals
(
Object
o
)
{
if
(!
equals
(
o
))
return
false
;
GitlabTicket
t
=
(
GitlabTicket
)
o
;
return
Objects
.
equals
(
title
,
t
.
title
)
&&
Objects
.
equals
(
description
,
t
.
description
)
&&
Objects
.
equals
(
labels
,
t
.
labels
)
&&
Objects
.
equals
(
assignees
,
t
.
assignees
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/gitlab/GitlabTicketAssignee.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.systems.gitlab
;
import
de.hftstuttgart.unifiedticketing.core.TicketAssignee
;
public
class
GitlabTicketAssignee
extends
TicketAssignee
{
protected
GitlabTicketAssignee
(
int
id
,
String
fullName
,
String
username
)
{
super
(
null
,
String
.
valueOf
(
id
),
fullName
,
username
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/gitlab/GitlabTicketBuilder.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.systems.gitlab
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.DeserializationFeature
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.node.ArrayNode
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.TicketBuilder
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.*
;
import
de.hftstuttgart.unifiedticketing.exceptions.*
;
import
okhttp3.*
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.stream.Collectors
;
public
class
GitlabTicketBuilder
extends
TicketBuilder
<
GitlabTicketBuilder
,
GitlabTicket
,
GitlabTicketSystem
>
{
private
static
Logger
logger
=
Logging
.
getLogger
(
GitlabTicketBuilder
.
class
.
getName
());
protected
GitlabTicketBuilder
(
GitlabTicketSystem
parent
)
{
super
(
parent
);
}
@Override
public
GitlabTicketBuilder
assignees
(
String
...
identifiers
)
{
try
{
Arrays
.
stream
(
identifiers
)
.
forEach
(
Integer:
:
parseInt
);
}
catch
(
NumberFormatException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"not as integer parsable assignee id encountered!"
));
throw
new
AssertionException
(
e
);
}
return
super
.
assignees
(
identifiers
);
}
public
GitlabTicketBuilder
assignees
(
int
...
identifiers
)
{
return
super
.
assignees
(
Arrays
.
stream
(
identifiers
)
.
mapToObj
(
String:
:
valueOf
)
.
toArray
(
String
[]::
new
));
}
protected
OkHttpClient
getHttpClient
()
{
return
new
OkHttpClient
();
}
/**
* creates a new ticket with the collected data and retrieves a new ticket instance from
* the api response
* @return newly created Ticket as {@link GitlabTicket} instance
*/
@Override
public
GitlabTicket
create
()
{
logger
.
log
(
Level
.
FINEST
,
"starting Ticket creation from builder data"
);
ObjectMapper
mapper
=
new
ObjectMapper
()
.
configure
(
DeserializationFeature
.
FAIL_ON_UNKNOWN_PROPERTIES
,
false
);
ObjectNode
body
=
mapper
.
createObjectNode
();
if
(
this
.
title
==
null
)
{
logger
.
log
(
Level
.
SEVERE
,
"mandatory field title not set before building Ticket"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
AssertionException
(
"GitLab Tickets need at-least a title"
);
}
body
.
put
(
"title"
,
this
.
title
);
logger
.
log
(
Level
.
FINEST
,
"title set"
);
if
(
this
.
assignees
!=
null
)
{
ArrayNode
ids
=
body
.
putArray
(
"assignee_ids"
);
assignees
.
stream
()
.
mapToInt
(
Integer:
:
parseInt
)
.
forEach
(
ids:
:
add
);
logger
.
log
(
Level
.
FINEST
,
"assignees set"
);
}
if
(
this
.
description
!=
null
)
{
body
.
put
(
"description"
,
this
.
description
);
logger
.
log
(
Level
.
FINEST
,
"description set"
);
}
if
(
this
.
labels
!=
null
)
{
body
.
put
(
"labels"
,
this
.
labels
.
stream
()
.
reduce
((
l1
,
l2
)
->
l1
+
","
+
l2
)
.
orElse
(
""
));
logger
.
log
(
Level
.
FINEST
,
"labels set"
);
}
String
jsonBody
;
try
{
jsonBody
=
mapper
.
writeValueAsString
(
body
);
logger
.
log
(
Level
.
FINER
,
String
.
format
(
"body for new Ticket serialized as json:\n%s"
,
jsonBody
));
}
catch
(
JsonProcessingException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"json serialization FAILED"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
SerializationException
(
e
);
}
OkHttpClient
client
=
getHttpClient
();
Request
.
Builder
builder
=
new
Request
.
Builder
()
.
url
(
String
.
format
(
"%s/issues"
,
parent
.
baseUrl
));
builder
.
post
(
RequestBody
.
create
(
jsonBody
,
MediaType
.
get
(
"application/json"
)));
if
(
this
.
parent
.
apiKey
!=
null
)
{
builder
.
addHeader
(
"PRIVATE-TOKEN"
,
this
.
parent
.
apiKey
);
logger
.
log
(
Level
.
FINEST
,
"added token authentication header"
);
}
Response
response
;
try
{
Request
request
=
builder
.
build
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"created request:\n%s"
,
(
this
.
parent
.
apiKey
!=
null
)
?
request
.
toString
().
replace
(
this
.
parent
.
apiKey
,
"SECRET"
)
:
request
.
toString
()
));
response
=
client
.
newCall
(
request
).
execute
();
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"create request FAILED"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpReqeustException
(
e
);
}
if
(
response
.
code
()
>=
400
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"create request failed with response code %d"
,
response
.
code
()
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
String
.
format
(
"ticket creation failed, error response code %d"
,
response
.
code
()),
response
.
code
());
}
logger
.
log
(
Level
.
FINEST
,
"response received\n"
);
ResponseBody
responseBody
;
responseBody
=
response
.
body
();
if
(
responseBody
==
null
)
{
logger
.
log
(
Level
.
SEVERE
,
"create request didn't deliver a body in response"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
"ticket creation failed, no response body"
,
response
.
code
());
}
GitlabTicketResponse
ticketResponse
;
try
{
ticketResponse
=
mapper
.
readValue
(
responseBody
.
bytes
(),
GitlabTicketResponse
.
class
);
logger
.
log
(
Level
.
FINEST
,
"parsed response body to ticketResponse instance"
);
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"parsing update response FAILED with: %s"
,
e
.
getMessage
()));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
DeserializationException
(
e
);
}
return
GitlabTicket
.
fromTicketResponse
(
this
.
parent
,
ticketResponse
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/gitlab/GitlabTicketResponse.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.systems.gitlab
;
import
java.util.List
;
import
java.util.Set
;
public
class
GitlabTicketResponse
{
protected
GitlabTicketResponse
()
{
}
public
List
<
Assignee
>
assignees
;
public
String
description
;
public
int
iid
;
public
Set
<
String
>
labels
;
public
String
state
;
public
String
title
;
protected
static
class
Assignee
{
public
int
id
;
public
String
name
;
public
String
username
;
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/gitlab/GitlabTicketSystem.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.systems.gitlab
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.AssertionException
;
import
de.hftstuttgart.unifiedticketing.exceptions.UnifiedticketingException
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
public
class
GitlabTicketSystem
extends
TicketSystem
<
GitlabTicket
,
GitlabTicketSystem
,
GitlabTicketBuilder
,
GitlabFilter
>
{
private
static
Logger
logger
=
Logging
.
getLogger
(
TicketSystem
.
class
.
getName
());
/**
* creates a new instance of this class from an uri.<br/>
* <br/>
* <b>Attention:</b> This method should not be called from the enduser!<br/>
* Instead call the same method from {@link TicketSystem}.<br/>
* To call this method directly, the uri has to be shortend by the "unifiedticketing:gitlab:" part.
* @param uri gitlab specific part of full uri
* @return new gitlab ticket instance
*/
public
static
GitlabTicketSystem
fromUri
(
String
uri
)
{
Matcher
matcher
=
Pattern
.
compile
(
"^((http|https):\\/\\/)?(.*(:[0-9]+.*)?):([0-9]+)(:(.*))?$"
).
matcher
(
uri
);
if
(!
matcher
.
matches
())
{
logger
.
log
(
Level
.
SEVERE
,
"uri didn't match regex"
);
throw
new
AssertionException
(
"uri didn't match regex"
);
}
GitlabTicketSystemBuilder
builder
=
new
GitlabTicketSystemBuilder
();
if
(
matcher
.
group
(
2
)
!=
null
&&
matcher
.
group
(
2
).
length
()
>
0
)
{
if
(
matcher
.
group
(
2
).
equalsIgnoreCase
(
"http"
))
builder
.
withHttp
();
else
builder
.
withHttps
();
}
if
(
matcher
.
group
(
3
)
==
null
||
matcher
.
group
(
3
).
length
()
==
0
)
{
logger
.
log
(
Level
.
SEVERE
,
"no base url identified in uri"
);
throw
new
AssertionException
(
"no base url found"
);
}
builder
.
withBaseUrl
(
matcher
.
group
(
3
));
if
(
matcher
.
group
(
5
)
==
null
||
matcher
.
group
(
5
).
length
()
==
0
)
{
logger
.
log
(
Level
.
SEVERE
,
"no project id identified in uri"
);
throw
new
AssertionException
(
"no project id found"
);
}
builder
.
withProjectId
(
matcher
.
group
(
5
));
if
(
matcher
.
group
(
6
)
==
null
||
matcher
.
group
(
6
).
length
()
==
0
)
{
logger
.
log
(
Level
.
INFO
,
"no api key identified in uri, creating anonymous instance"
);
}
else
{
builder
.
withApiKey
(
matcher
.
group
(
7
));
}
return
builder
.
build
();
}
protected
GitlabTicketSystem
()
{
logger
.
log
(
Level
.
FINEST
,
"GitLab Ticketsystem created"
);
}
/**
* starts builder process for a new gitlab ticket
*/
@Override
public
GitlabTicketBuilder
createTicket
()
{
return
new
GitlabTicketBuilder
(
this
);
}
/**
* starts filter builder to define constraints and then request those tickets
*/
@Override
public
GitlabFilter
find
()
{
return
new
GitlabFilter
(
this
);
}
// @Override
// public List<GitlabTicket> getAllTickets()
// {
// logger.log(Level.FINER, "redirecting request to find method");
// return this.find()
// .get();
// }
/**
* This requests a dedicated ticket by it's id.
* It internally calls {@link #find()}, set's the id as filter
* and ensure to get exactly one element as answer.
* @param id ticket id to request
* @throws UnifiedticketingException if more or less than one element in the response
*/
@Override
public
GitlabTicket
getTicketById
(
String
id
)
{
logger
.
log
(
Level
.
FINER
,
"redirecting request to find method"
);
List
<
GitlabTicket
>
ret
=
this
.
find
()
.
withId
(
id
)
.
get
();
if
(
ret
==
null
)
return
null
;
else
if
(
ret
.
size
()
!=
1
)
throw
new
UnifiedticketingException
(
"more or less than 1 dedicated ticket found"
);
else
return
ret
.
get
(
0
);
}
@Override
public
boolean
hasAssigneeSupport
()
{
return
true
;
}
@Override
public
boolean
hasDefaultPagination
()
{
return
true
;
}
@Override
public
boolean
hasLabelSupport
()
{
return
true
;
}
@Override
public
boolean
hasPaginationSupport
()
{
return
true
;
}
@Override
public
boolean
hasReturnNullOnErrorSupport
()
{
return
true
;
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/gitlab/GitlabTicketSystemBuilder.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.systems.gitlab
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystemBuilder
;
import
de.hftstuttgart.unifiedticketing.exceptions.AssertionException
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
public
class
GitlabTicketSystemBuilder
extends
TicketSystemBuilder
<
GitlabTicketSystemBuilder
,
GitlabTicketSystem
>
{
private
static
Logger
logger
=
Logging
.
getLogger
(
GitlabTicketSystemBuilder
.
class
.
getName
());
protected
String
apiKey
;
protected
String
apiVersion
;
protected
int
projectId
;
protected
boolean
https
;
/**
* starts builder process for a {@link GitlabTicketSystem} instance
*/
public
GitlabTicketSystemBuilder
()
{
super
();
apiVersion
=
"v4"
;
projectId
=
-
1
;
https
=
true
;
logger
.
log
(
Level
.
FINEST
,
"Builder for Gitlab System instance started"
);
}
/**
* defines api-key to be used for requests<br/>
* <br/>
* if you don't specify an api-key, all requests will be without credentials
* @param apiKey your user specific
* @return this ticket system builder
*/
public
GitlabTicketSystemBuilder
withApiKey
(
String
apiKey
)
{
this
.
apiKey
=
apiKey
;
logger
.
log
(
Level
.
FINEST
,
"set api key"
);
return
this
;
}
/**
* set protocol to http (no transport security!)
* @return this ticket system builder
*/
public
GitlabTicketSystemBuilder
withHttp
()
{
this
.
https
=
false
;
logger
.
log
(
Level
.
FINEST
,
"set http"
);
return
this
;
}
/**
* set protocol to https (enabled transport security)<br/>
* this is the default
* @return this ticket system builder
*/
public
GitlabTicketSystemBuilder
withHttps
()
{
this
.
https
=
true
;
logger
.
log
(
Level
.
FINEST
,
"set https"
);
return
this
;
}
/**
* set project id the instance should work in
* @return this ticket system builder
*/
public
GitlabTicketSystemBuilder
withProjectId
(
int
projectId
)
{
this
.
projectId
=
projectId
;
logger
.
log
(
Level
.
FINEST
,
"set project id to "
+
this
.
projectId
);
return
this
;
}
/**
* set project id the instance should work in
* @return this ticket system builder
* @throws AssertionException if {@code projectId} is not parsable to as integer
*/
public
GitlabTicketSystemBuilder
withProjectId
(
String
projectId
)
{
try
{
return
this
.
withProjectId
(
Integer
.
parseInt
(
projectId
));
}
catch
(
NumberFormatException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"given String is not parsable to an integer projectId: %s"
,
projectId
));
throw
new
AssertionException
(
e
);
}
}
/**
* builds a new gitlab ticket system instance with the given information.<br/>
* <br/>
* The minimum builder methods needed, are {@link #withBaseUrl} and {@link #withProjectId}.
* @return new {@link GitlabTicketSystem} instance
* @throws AssertionException if {@link #withBaseUrl} or {@link #withProjectId} not called beforehand
*/
@Override
public
GitlabTicketSystem
build
()
{
if
(
baseUrl
==
null
||
projectId
==
-
1
)
{
logger
.
log
(
Level
.
SEVERE
,
"to build a GitlabTicketSystem instance at least a base url and projectId are needed!"
);
throw
new
AssertionException
(
"baseUrl or projectId are missing"
);
}
GitlabTicketSystem
system
=
new
GitlabTicketSystem
();
system
.
baseUrl
=
String
.
format
(
"%s://%s/api/%s/projects/%d"
,
(
this
.
https
)
?
"https"
:
"http"
,
this
.
baseUrl
,
this
.
apiVersion
,
this
.
projectId
);
system
.
apiKey
=
apiKey
;
logger
.
log
(
Level
.
FINEST
,
"created instance of "
+
system
.
getClass
().
getSimpleName
()
+
" with baseUrl "
+
system
.
baseUrl
);
return
system
;
}
}
src/test/java/de/hftstuttgart/unifiedticketing/core/FilterTest.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.core
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
import
static
org
.
mockito
.
Mockito
.*;
import
java.util.*
;
public
class
FilterTest
{
public
Filter
instance
;
@BeforeEach
public
void
initBeforeEach
()
{
instance
=
mock
(
Filter
.
class
,
withSettings
().
useConstructor
().
defaultAnswer
(
CALLS_REAL_METHODS
));
}
@Test
public
void
testWithSingleAssigneeId
()
{
String
value
=
"testId"
;
Set
<
String
>
expected
=
new
HashSet
<>();
expected
.
add
(
value
);
instance
.
withAssigneeId
(
value
);
assertEquals
(
expected
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEEID
.
name
()));
}
@Test
public
void
testWithMultipleAssigneeId
()
{
String
[]
values
=
new
String
[]{
"testId"
,
"anotherone"
,
"thirdId"
};
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
values
));
Object
valueBeforeFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEEID
.
name
());
instance
.
withAssigneeId
(
values
[
0
]);
Object
valueAfterFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEEID
.
name
());
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withAssigneeId
);
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withAssigneeId
);
Object
valueAfterAllAdds
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEEID
.
name
());
assertAll
(
()
->
assertNull
(
valueBeforeFirstAdd
),
// no initial instance present
()
->
assertNotNull
(
valueAfterFirstAdd
),
// after first add there has to be one
()
->
assertSame
(
valueAfterFirstAdd
,
valueAfterAllAdds
),
// check the collection stayed the same
()
->
assertEquals
(
expected
,
valueAfterAllAdds
)
// check the content is only in there once and complete
);
}
@Test
public
void
testWithSingleAssigneeName
()
{
String
value
=
"testName"
;
Set
<
String
>
expected
=
new
HashSet
<>();
expected
.
add
(
value
);
instance
.
withAssigneeName
(
value
);
assertEquals
(
expected
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEENAME
.
name
()));
}
@Test
public
void
testWithMultipleAssigneeName
()
{
String
[]
values
=
new
String
[]{
"testName"
,
"anotherone"
,
"thirdName"
};
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
values
));
Object
valueBeforeFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEENAME
.
name
());
instance
.
withAssigneeName
(
values
[
0
]);
Object
valueAfterFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEENAME
.
name
());
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withAssigneeName
);
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withAssigneeName
);
Object
valueAfterAllAdds
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
ASSIGNEENAME
.
name
());
assertAll
(
()
->
assertNull
(
valueBeforeFirstAdd
),
// no initial instance present
()
->
assertNotNull
(
valueAfterFirstAdd
),
// after first add there has to be one
()
->
assertSame
(
valueAfterFirstAdd
,
valueAfterAllAdds
),
// check the collection stayed the same
()
->
assertEquals
(
expected
,
valueAfterAllAdds
)
// check the content is only in there once and complete
);
}
@Test
public
void
testWithDescriptionContain
()
{
String
expected
=
"test description"
;
Object
valueBeforeFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
DESCRIPTION_CONTAIN
.
name
());
instance
.
withDescriptionContain
(
expected
);
Object
valueAfterAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
DESCRIPTION_CONTAIN
.
name
());
assertAll
(
()
->
assertNull
(
valueBeforeFirstAdd
),
// no initial instance present
()
->
assertEquals
(
expected
,
valueAfterAdd
)
// after add there has to be the set one
);
}
@Test
public
void
testWithDescriptionMatch
()
{
String
expected
=
"^some stupid regex number [0-9]+"
;
Object
valueBeforeFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
DESCRIPTION_MATCH
.
name
());
instance
.
withDescriptionMatch
(
expected
);
Object
valueAfterAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
DESCRIPTION_MATCH
.
name
());
assertAll
(
()
->
assertNull
(
valueBeforeFirstAdd
),
// no initial instance present
()
->
assertEquals
(
expected
,
valueAfterAdd
)
// after add there has to be the set one
);
}
@Test
public
void
testWithSingleTicketId
()
{
String
value
=
"testId"
;
Set
<
String
>
expected
=
new
HashSet
<>();
expected
.
add
(
value
);
instance
.
withId
(
value
);
assertEquals
(
expected
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
IDS
.
name
()));
}
@Test
public
void
testWithMultipleTicketIds
()
{
String
[]
values
=
new
String
[]{
"testId"
,
"anotherone"
,
"thirdId"
};
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
values
));
Object
valueBeforeFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
IDS
.
name
());
instance
.
withId
(
values
[
0
]);
Object
valueAfterFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
IDS
.
name
());
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withId
);
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withId
);
Object
valueAfterAllAdds
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
IDS
.
name
());
assertAll
(
()
->
assertNull
(
valueBeforeFirstAdd
),
// no initial instance present
()
->
assertNotNull
(
valueAfterFirstAdd
),
// after first add there has to be one
()
->
assertSame
(
valueAfterFirstAdd
,
valueAfterAllAdds
),
// check the collection stayed the same
()
->
assertEquals
(
expected
,
valueAfterAllAdds
)
// check the content is only in there once and complete
);
}
@Test
public
void
testIsOpen
()
{
instance
.
isOpen
()
.
isClosed
()
.
isOpen
();
assertEquals
(
Boolean
.
TRUE
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
OPEN
.
name
()));
}
@Test
public
void
testIsClosed
()
{
instance
.
isClosed
()
.
isOpen
()
.
isClosed
();
assertEquals
(
Boolean
.
FALSE
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
OPEN
.
name
()));
}
@Test
public
void
testWithSingleLabel
()
{
String
value
=
"test"
;
Set
<
String
>
expected
=
new
HashSet
<>();
expected
.
add
(
value
);
instance
.
withLabel
(
value
);
assertEquals
(
expected
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
LABELS
.
name
()));
}
@Test
public
void
testWithMultipleLabels
()
{
String
[]
values
=
new
String
[]{
"test"
,
"To Do"
,
"Bug"
,
"Feature"
,
"review"
};
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
values
));
Object
valueBeforeFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
LABELS
.
name
());
instance
.
withLabel
(
values
[
0
]);
Object
valueAfterFirstAdd
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
LABELS
.
name
());
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withLabel
);
Arrays
.
stream
(
values
).
forEach
(
instance:
:
withLabel
);
Object
valueAfterAllAdds
=
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
LABELS
.
name
());
assertAll
(
()
->
assertNull
(
valueBeforeFirstAdd
),
// no initial instance present
()
->
assertNotNull
(
valueAfterFirstAdd
),
// after first add there has to be one
()
->
assertSame
(
valueAfterFirstAdd
,
valueAfterAllAdds
),
// check the collection stayed the same
()
->
assertEquals
(
expected
,
valueAfterAllAdds
)
// check the content is only in there once and complete
);
}
@Test
public
void
testSetPage
()
{
int
value
=
2
;
instance
.
setPage
(
value
);
assertEquals
(
value
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
PAGE
.
name
()));
}
@Test
public
void
testSetPageSize
()
{
int
value
=
2
;
instance
.
setPageSize
(
value
);
assertEquals
(
value
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
PAGINATION
.
name
()));
}
@Test
public
void
testWithTitleContain
()
{
String
expected
=
"test title"
;
instance
.
withTitleContain
(
expected
);
assertEquals
(
expected
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
TITLE_CONTAINS
.
name
()));
}
@Test
public
void
testWithTitleMatch
()
{
String
expected
=
"^some stupid regex number [0-9]+"
;
instance
.
withTitleMatch
(
expected
);
assertEquals
(
expected
,
instance
.
setFilters
.
get
(
Filter
.
FilterNames
.
TITLE_MATCH
.
name
()));
}
@Test
public
void
testAddToSet
()
{
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
"test"
,
"another"
,
"something"
));
Map
<
String
,
Object
>
store
=
new
HashMap
<>();
expected
.
forEach
(
s
->
Filter
.
addToSet
(
Filter
.
FilterNames
.
LABELS
,
store
,
s
));
assertEquals
(
expected
,
store
.
get
(
Filter
.
FilterNames
.
LABELS
.
name
()));
}
@Test
public
void
testInitialValues
()
{
assertAll
(
()
->
assertNotNull
(
instance
.
setFilters
),
()
->
assertEquals
(
0
,
instance
.
setFilters
.
size
())
);
}
@Test
public
void
testFluentApi
()
{
Filter
before
=
instance
;
Filter
after
=
instance
.
setPage
(
1
)
.
setPageSize
(
1
)
.
withAssigneeId
(
"1"
)
.
withAssigneeName
(
"Max"
)
.
withDescriptionContain
(
"Muster"
)
.
withDescriptionMatch
(
"Mann"
)
.
withId
(
"ID"
)
.
withLabel
(
"blabber"
)
.
withTitleContain
(
"hell no"
)
.
withTitleMatch
(
"finally"
)
.
isOpen
()
.
isClosed
();
assertSame
(
before
,
after
);
}
}
src/test/java/de/hftstuttgart/unifiedticketing/core/RegisteredSystemsTest.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.core
;
import
de.hftstuttgart.unifiedticketing.systems.gitlab.GitlabTicketSystemBuilder
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
public
class
RegisteredSystemsTest
{
@Test
public
void
testGitlab
()
{
Class
expected
=
new
RegisteredSystems
().
gitlab
().
getClass
();
Class
actual
=
GitlabTicketSystemBuilder
.
class
;
assertEquals
(
expected
,
actual
);
}
}
src/test/java/de/hftstuttgart/unifiedticketing/core/TicketAssigneeTest.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.core
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
public
class
TicketAssigneeTest
{
@Test
public
void
testEquals
()
{
TicketAssignee
a1
=
new
TicketAssignee
(
null
,
"1"
,
null
,
null
);
TicketAssignee
a2
=
new
TicketAssignee
(
null
,
"1"
,
null
,
null
);
TicketAssignee
a3
=
new
TicketAssignee
(
null
,
"2"
,
null
,
null
);
assertEquals
(
a1
,
a2
);
assertNotEquals
(
a1
,
a3
);
}
}
src/test/java/de/hftstuttgart/unifiedticketing/core/TicketBuilderTest.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.core
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.Set
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
import
static
org
.
mockito
.
Mockito
.*;
public
class
TicketBuilderTest
{
public
TicketBuilder
instance
;
@BeforeEach
public
void
initBeforeEach
()
{
instance
=
mock
(
TicketBuilder
.
class
,
withSettings
().
useConstructor
(
mock
(
TicketSystem
.
class
)).
defaultAnswer
(
CALLS_REAL_METHODS
));
}
@Test
public
void
testInit
()
{
TicketSystem
ts
=
mock
(
TicketSystem
.
class
);
instance
=
mock
(
TicketBuilder
.
class
,
withSettings
().
useConstructor
(
ts
));
assertAll
(
()
->
assertSame
(
ts
,
instance
.
parent
),
()
->
assertNull
(
instance
.
description
),
()
->
assertNull
(
instance
.
labels
),
()
->
assertNull
(
instance
.
title
)
// seems not possible with mock
// () -> assertThrows(AssertionException.class, () -> new TicketBuilderTestImpl(null))
);
}
@Test
public
void
testDescription
()
{
String
expected
=
"some descriptive stuff"
;
instance
.
description
(
expected
);
assertEquals
(
expected
,
instance
.
description
);
}
@Test
public
void
testLabelsBySet
()
{
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
"unifiedticketing"
,
"bug"
,
"To Do"
));
instance
.
labels
(
expected
);
assertEquals
(
expected
,
instance
.
labels
);
}
@Test
public
void
testLabelsByArray
()
{
String
[]
input
=
new
String
[]{
"unifiedticketing"
,
"feature"
,
"review"
};
instance
.
labels
(
input
);
verify
(
instance
,
times
(
1
)).
labels
(
new
HashSet
<>(
Arrays
.
asList
(
input
)));
}
@Test
public
void
testTitle
()
{
String
expected
=
"outstanding title: yolo"
;
instance
.
title
(
expected
);
assertEquals
(
expected
,
instance
.
title
);
}
@Test
public
void
testFluentApi
()
{
TicketBuilder
before
=
instance
;
TicketBuilder
after
=
instance
.
description
(
"some"
)
.
labels
(
new
String
[]{
"random"
})
.
labels
(
new
HashSet
<>(
Collections
.
singleton
(
"values"
)))
.
title
(
"here"
);
assertSame
(
before
,
after
);
}
}
src/test/java/de/hftstuttgart/unifiedticketing/core/TicketSystemBuilderTest.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.core
;
import
de.hftstuttgart.unifiedticketing.exceptions.AssertionException
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
import
static
org
.
mockito
.
Mockito
.*;
public
class
TicketSystemBuilderTest
{
public
TicketSystemBuilder
instance
;
@BeforeEach
public
void
initBeforeEach
()
{
instance
=
mock
(
TicketSystemBuilder
.
class
,
withSettings
().
useConstructor
().
defaultAnswer
(
CALLS_REAL_METHODS
));
}
@Test
public
void
testWithBaseUrl
()
{
String
expected
=
"some.url.tld"
;
instance
.
withBaseUrl
(
expected
);
assertEquals
(
expected
,
instance
.
baseUrl
);
assertAll
(
()
->
assertThrows
(
AssertionException
.
class
,
()
->
instance
.
withBaseUrl
(
"http://urlwithprefix.com"
)),
()
->
assertThrows
(
AssertionException
.
class
,
()
->
instance
.
withBaseUrl
(
"https://urlwithprefix.com"
))
);
}
@Test
public
void
testFluentApi
()
{
TicketSystemBuilder
before
=
instance
;
TicketSystemBuilder
after
=
instance
.
withBaseUrl
(
"teststring"
);
assertSame
(
before
,
after
);
}
}
src/test/java/de/hftstuttgart/unifiedticketing/core/TicketSystemTest.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.core
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
import
static
org
.
mockito
.
Mockito
.*;
public
class
TicketSystemTest
{
public
TicketSystem
instance
;
@BeforeEach
public
void
initBeforeEach
()
{
instance
=
mock
(
TicketSystem
.
class
,
withSettings
().
useConstructor
().
defaultAnswer
(
CALLS_REAL_METHODS
));
}
@Test
public
void
testInit
()
{
assertAll
(
()
->
assertNull
(
instance
.
apiKey
),
()
->
assertNull
(
instance
.
baseUrl
),
()
->
assertNull
(
instance
.
password
),
()
->
assertNull
(
instance
.
username
)
);
}
@Test
public
void
testConfigBoolean
()
{
assertFalse
(
instance
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
instance
.
config
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
,
true
);
assertTrue
(
instance
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
instance
.
config
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
,
false
);
assertFalse
(
instance
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
}
@Test
public
void
testConfigValue
()
{
assertNull
(
instance
.
getConfigValue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
String
expected
=
"some string value"
;
instance
.
config
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
,
expected
);
assertFalse
(
instance
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
assertEquals
(
expected
,
instance
.
getConfigValue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
expected
=
"TRUE"
;
instance
.
config
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
,
expected
);
assertTrue
(
instance
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
instance
.
config
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
,
null
);
assertFalse
(
instance
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
assertEquals
(
null
,
instance
.
getConfigValue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
));
}
@Test
public
void
testGetTicketByIdByInt
()
{
int
input
=
5
;
instance
.
getTicketById
(
input
);
verify
(
instance
,
times
(
1
)).
getTicketById
(
String
.
valueOf
(
input
));
}
@Test
public
void
testFluentApi
()
{
TicketSystem
before
=
instance
;
TicketSystem
after
=
instance
.
config
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
,
true
)
.
config
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
,
"something"
);
assertSame
(
before
,
after
);
}
}
src/test/java/de/hftstuttgart/unifiedticketing/core/TicketTest.java
0 → 100644
View file @
32ea786f
package
de.hftstuttgart.unifiedticketing.core
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.extension.ExtendWith
;
import
org.mockito.junit.jupiter.MockitoExtension
;
import
static
org
.
mockito
.
Mockito
.*;
import
java.util.Arrays
;
import
java.util.HashSet
;
import
java.util.Set
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
@ExtendWith
(
MockitoExtension
.
class
)
public
class
TicketTest
{
private
Ticket
instance
;
@BeforeEach
public
void
initBeforeEach
()
{
instance
=
mock
(
Ticket
.
class
,
withSettings
().
useConstructor
(
mock
(
TicketSystem
.
class
)).
defaultAnswer
(
CALLS_REAL_METHODS
));
}
@Test
public
void
testInitialValues
()
{
TicketSystem
parent
=
mock
(
TicketSystem
.
class
);
instance
=
mock
(
Ticket
.
class
,
withSettings
().
useConstructor
(
parent
).
defaultAnswer
(
CALLS_REAL_METHODS
));
assertAll
(
()
->
assertNotNull
(
instance
.
assignees
),
()
->
assertEquals
(
HashSet
.
class
,
instance
.
assignees
.
getClass
()),
()
->
assertNull
(
instance
.
description
),
()
->
assertNull
(
instance
.
description
),
()
->
assertNull
(
instance
.
id
),
()
->
assertNotNull
(
instance
.
labels
),
()
->
assertEquals
(
HashSet
.
class
,
instance
.
labels
.
getClass
()),
()
->
assertTrue
(
instance
.
open
),
()
->
assertNull
(
instance
.
title
),
()
->
assertNotNull
(
instance
.
updatedFields
),
()
->
assertEquals
(
HashSet
.
class
,
instance
.
updatedFields
.
getClass
()),
()
->
assertSame
(
parent
,
instance
.
parent
)
// constructor exception check with mock of abstract class not possible I guess?
// () -> assertThrows(AssertionException.class,
// () -> mock(Ticket.class, withSettings().useConstructor((TicketSystem) null)))
);
}
@Test
public
void
testGetAssignees
()
{
assertEquals
(
instance
.
assignees
,
instance
.
getAssignees
());
}
@Test
public
void
testClearAssignees
()
{
Set
<
TicketAssignee
>
expected
=
instance
.
assignees
;
instance
.
clearAssignees
();
assertSame
(
expected
,
instance
.
assignees
);
}
@Test
public
void
testGetDescription
()
{
String
expected
=
"some descriptive text"
;
instance
.
description
=
expected
;
assertEquals
(
expected
,
instance
.
getDescription
());
}
@Test
public
void
testSetDescription
()
{
String
expected
=
"some other descriptive stuff"
;
instance
.
setDescription
(
expected
);
assertEquals
(
expected
,
instance
.
description
);
}
@Test
public
void
testGetId
()
{
String
expected
=
"T13"
;
instance
.
id
=
expected
;
assertEquals
(
expected
,
instance
.
getId
());
}
@Test
public
void
testAddLabel
()
{
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
"unifiedticketing"
,
"bug"
,
"feature"
));
expected
.
forEach
(
instance:
:
addLabel
);
assertEquals
(
expected
,
instance
.
labels
);
}
@Test
public
void
testGetLabels
()
{
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
"unifiedticketing"
,
"To Do"
,
"enhancement"
));
instance
.
labels
=
expected
;
assertEquals
(
expected
,
instance
.
getLabels
());
}
@Test
public
void
testSetLabelsByList
()
{
Set
<
String
>
expected
=
new
HashSet
<>(
Arrays
.
asList
(
"unifiedticketing"
,
"Doing"
,
"review"
));
instance
.
setLabels
(
expected
);
assertEquals
(
expected
,
instance
.
labels
);
}
@Test
public
void
testSetLabelsByArray
()
{
String
[]
expected
=
new
String
[]{
"unifiedticketing"
,
"abandoned"
,
"superseded"
};
instance
.
setLabels
(
expected
);
verify
(
instance
,
times
(
1
)).
setLabels
(
new
HashSet
<>(
Arrays
.
asList
(
expected
)));
}
@Test
public
void
testIsOpen
()
{
instance
.
open
=
true
;
assertTrue
(
instance
.
isOpen
());
instance
.
open
=
false
;
assertFalse
(
instance
.
isOpen
());
}
@Test
public
void
testOpen
()
{
instance
.
open
();
assertTrue
(
instance
.
open
);
}
@Test
public
void
testClose
()
{
instance
.
close
();
assertFalse
(
instance
.
open
);
}
@Test
public
void
testGetParent
()
{
assertSame
(
instance
.
parent
,
instance
.
getParent
());
}
@Test
public
void
testGetTitle
()
{
String
expected
=
"fancy title"
;
instance
.
title
=
expected
;
assertEquals
(
expected
,
instance
.
getTitle
());
}
@Test
public
void
testSetTitle
()
{
String
expected
=
"other title"
;
instance
.
setTitle
(
expected
);
assertEquals
(
expected
,
instance
.
title
);
}
}
Prev
1
2
3
Next